From e44df02c8ee5e03d74ec8b5844164576711cffcc Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Sat, 6 Nov 2021 21:26:22 +0200 Subject: [PATCH 001/356] soc: qcom: Add soc information for SDM845 Add SOC information like Chip ID, macros and dummy socinfo definitions for SDM845 SoC. Signed-off-by: Pavel Dubrova --- drivers/soc/qcom/socinfo.c | 7 +++++++ include/soc/qcom/socinfo.h | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index d1b52f7e548a..df794df11d29 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -341,6 +341,9 @@ static struct msm_soc_info cpu_of_id[] = { /* SDM660 ID */ [317] = {MSM_CPU_SDM660, "SDM660"}, + /* SDM845 ID */ + [321] = {MSM_CPU_SDM845, "SDM845"}, + /* sm8150 ID */ [339] = {MSM_CPU_SM8150, "SM8150"}, @@ -1546,6 +1549,10 @@ static void * __init setup_dummy_socinfo(void) dummy_socinfo.id = 317; strlcpy(dummy_socinfo.build_id, "sdm660 - ", sizeof(dummy_socinfo.build_id)); + } else if (early_machine_is_sdm845()) { + dummy_socinfo.id = 321; + strlcpy(dummy_socinfo.build_id, "sdm845 - ", + sizeof(dummy_socinfo.build_id)); } else if (early_machine_is_sm8150()) { dummy_socinfo.id = 339; strlcpy(dummy_socinfo.build_id, "sm8150 - ", diff --git a/include/soc/qcom/socinfo.h b/include/soc/qcom/socinfo.h index 70aa770f6da7..b858ec606b78 100644 --- a/include/soc/qcom/socinfo.h +++ b/include/soc/qcom/socinfo.h @@ -151,6 +151,8 @@ enum socinfo_parttype { of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sdmmagpie") #define early_machine_is_sdm660() \ of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sdm660") +#define early_machine_is_sdm845() \ + of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,sdm845") #define early_machine_is_bengal_iot() \ of_flat_dt_is_compatible(of_get_flat_dt_root(), "qcom,bengal-iot") #define early_machine_is_bengalp_iot() \ @@ -210,6 +212,7 @@ enum socinfo_parttype { #define early_machine_is_sdxprairie() 0 #define early_machine_is_sdmmagpie() 0 #define early_machine_is_sdm660() 0 +#define early_machine_is_sdm845() 0 #define early_machine_is_bengal_iot() 0 #define early_machine_is_bengalp_iot() 0 #define early_machine_is_msm8937() 0 @@ -241,6 +244,7 @@ enum msm_cpu { MSM_CPU_8084, MSM_CPU_8996, MSM_CPU_SDM660, + MSM_CPU_SDM845, MSM_CPU_SM8150, MSM_CPU_SA8150, MSM_CPU_KONA, From 21dfb39642cd2438fb87251101ada13f56749090 Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Sat, 6 Nov 2021 21:17:58 +0200 Subject: [PATCH 002/356] soc: qcom: qsee_ipc_irq: Add bindings for SDM845 Add compatible string for SDM845. Signed-off-by: Pavel Dubrova --- drivers/soc/qcom/qsee_ipc_irq.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/soc/qcom/qsee_ipc_irq.c b/drivers/soc/qcom/qsee_ipc_irq.c index 4db221999139..79b3dcbe5403 100644 --- a/drivers/soc/qcom/qsee_ipc_irq.c +++ b/drivers/soc/qcom/qsee_ipc_irq.c @@ -331,6 +331,7 @@ static const struct qsee_irq_data qsee_irq_data_init[] = { }; static const struct of_device_id qsee_irq_of_match[] = { + { .compatible = "qcom,sdm845-qsee-irq", .data = &qsee_irq_data_init}, { .compatible = "qcom,sm8150-qsee-irq", .data = &qsee_irq_data_init}, { .compatible = "qcom,kona-qsee-irq", .data = &qsee_irq_data_init}, {}, From 24fc12aea0170a420a6e3340eaacaa5d514227f7 Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Sat, 6 Nov 2021 21:16:45 +0200 Subject: [PATCH 003/356] mailbox: apcs-ipc: Add spcs bindings for SDM845 Add compatible string for the spcs region for SDM845. Signed-off-by: Pavel Dubrova --- drivers/mailbox/qcom-apcs-ipc-mailbox.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mailbox/qcom-apcs-ipc-mailbox.c b/drivers/mailbox/qcom-apcs-ipc-mailbox.c index f3deddf176bc..eb0b38f15204 100644 --- a/drivers/mailbox/qcom-apcs-ipc-mailbox.c +++ b/drivers/mailbox/qcom-apcs-ipc-mailbox.c @@ -134,6 +134,7 @@ static const struct of_device_id qcom_apcs_ipc_of_match[] = { { .compatible = "qcom,msm8998-apcs-hmss-global", .data = (void *)8 }, { .compatible = "qcom,sdm845-apss-shared", .data = (void *)12 }, { .compatible = "qcom,sm8150-apcs-hmss-global", .data = (void *) 12 }, + { .compatible = "qcom,sdm845-spcs-global", .data = (void *)0 }, { .compatible = "qcom,sm8150-spcs-global", .data = (void *)0 }, { .compatible = "qcom,kona-spcs-global", .data = (void *)0 }, { .compatible = "qcom,bengal-apcs-hmss-global", .data = (void *)8 }, From 60c10564f77c6a6f4c69225eda38f22a8758fa7e Mon Sep 17 00:00:00 2001 From: MrArtemSid Date: Mon, 25 Dec 2023 01:55:35 +0400 Subject: [PATCH 004/356] arm64: dts: qcom-sdm845: Import from LA.UM.10.3.c25-00400-sdm845.0 state: https://git.codelinaro.org/clo/la/kernel/msm-4.9/-/tree/LA.UM.10.3.c25-00400-sdm845.0/arch/arm64/boot/dts/qcom?ref_type=tags --- arch/arm64/Kconfig.platforms | 10 + .../dsi-panel-nt35597-dualmipi-wqxga-cmd.dtsi | 112 + ...si-panel-nt35597-dualmipi-wqxga-video.dtsi | 111 + ...dsi-panel-nt35597-truly-dsc-wqxga-cmd.dtsi | 247 + ...i-panel-nt35597-truly-dsc-wqxga-video.dtsi | 233 + ...anel-nt35597-truly-dualmipi-wqxga-cmd.dtsi | 231 + ...el-nt35597-truly-dualmipi-wqxga-video.dtsi | 213 + ...panel-nt36850-truly-dualmipi-wqhd-cmd.dtsi | 87 + .../dsi-panel-r63417-truly-1080p-cmd.dtsi | 104 + ...anel-s6e3ha3-amoled-dualmipi-wqhd-cmd.dtsi | 141 + .../dts/qcom/dsi-panel-sharp-1080p-cmd.dtsi | 86 + .../dts/qcom/dsi-panel-sharp-dsc-4k-cmd.dtsi | 103 + .../qcom/dsi-panel-sharp-dsc-4k-video.dtsi | 96 + .../dsi-panel-sharp-dualmipi-1080p-120hz.dtsi | 633 ++ .../boot/dts/qcom/dsi-panel-sim-cmd.dtsi | 219 + .../dts/qcom/dsi-panel-sim-dsc375-cmd.dtsi | 286 + .../dts/qcom/dsi-panel-sim-dualmipi-cmd.dtsi | 121 + .../dsi-panel-sim-dualmipi-dsc375-cmd.dtsi | 281 + .../qcom/dsi-panel-sim-dualmipi-video.dtsi | 61 + .../boot/dts/qcom/dsi-panel-sim-video.dtsi | 69 + .../dsi-panel-test-dualmipi-oled-cmd.dtsi | 50 + .../fg-gen3-batterydata-ascent-3450mah.dtsi | 90 + .../fg-gen3-batterydata-demo-6000mah.dtsi | 78 + .../fg-gen3-batterydata-itech-3000mah.dtsi | 81 + .../boot/dts/qcom/msm-arm-smmu-sdm845.dtsi | 364 + arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi | 596 ++ arch/arm64/boot/dts/qcom/msm-gdsc-sdm845.dtsi | 237 + arch/arm64/boot/dts/qcom/msm-rdbg.dtsi | 106 + arch/arm64/boot/dts/qcom/msm-wsa881x.dtsi | 45 + arch/arm64/boot/dts/qcom/pm8005.dtsi | 106 +- arch/arm64/boot/dts/qcom/pm8998.dtsi | 275 +- arch/arm64/boot/dts/qcom/pmi8998.dtsi | 898 +++ .../boot/dts/qcom/sdm845-670-usb-common.dtsi | 608 ++ .../boot/dts/qcom/sdm845-audio-overlay.dtsi | 185 + arch/arm64/boot/dts/qcom/sdm845-audio.dtsi | 115 + arch/arm64/boot/dts/qcom/sdm845-bus.dtsi | 1984 ++++++ .../dts/qcom/sdm845-camera-sensor-mtp.dtsi | 465 ++ arch/arm64/boot/dts/qcom/sdm845-camera.dtsi | 1097 +++ .../arm64/boot/dts/qcom/sdm845-coresight.dtsi | 2457 +++++++ arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi | 390 + arch/arm64/boot/dts/qcom/sdm845-ion.dtsi | 59 + .../boot/dts/qcom/sdm845-mtp-overlay.dts | 31 + arch/arm64/boot/dts/qcom/sdm845-mtp.dts | 70 +- arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi | 549 ++ arch/arm64/boot/dts/qcom/sdm845-pcie.dtsi | 552 ++ .../boot/dts/qcom/sdm845-pinctrl-overlay.dtsi | 63 + arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi | 3664 ++++++++++ arch/arm64/boot/dts/qcom/sdm845-pm.dtsi | 154 + .../boot/dts/qcom/sdm845-pmic-overlay.dtsi | 51 + arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi | 797 +++ .../arm64/boot/dts/qcom/sdm845-regulator.dtsi | 820 +++ .../boot/dts/qcom/sdm845-sde-display.dtsi | 935 +++ arch/arm64/boot/dts/qcom/sdm845-sde-pll.dtsi | 113 + arch/arm64/boot/dts/qcom/sdm845-sde.dtsi | 642 ++ arch/arm64/boot/dts/qcom/sdm845-smp2p.dtsi | 345 + .../arm64/boot/dts/qcom/sdm845-v2-camera.dtsi | 497 ++ .../boot/dts/qcom/sdm845-v2-mtp-overlay.dts | 31 + arch/arm64/boot/dts/qcom/sdm845-v2-mtp.dts | 25 + .../boot/dts/qcom/sdm845-v2.1-mtp-overlay.dts | 31 + arch/arm64/boot/dts/qcom/sdm845-v2.1-mtp.dts | 111 + arch/arm64/boot/dts/qcom/sdm845-v2.1.dts | 22 + arch/arm64/boot/dts/qcom/sdm845-v2.1.dtsi | 31 + arch/arm64/boot/dts/qcom/sdm845-v2.dts | 21 + arch/arm64/boot/dts/qcom/sdm845-v2.dtsi | 679 ++ arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi | 129 + arch/arm64/boot/dts/qcom/sdm845-wcd.dtsi | 167 + arch/arm64/boot/dts/qcom/sdm845.dts | 21 + arch/arm64/boot/dts/qcom/sdm845.dtsi | 6298 ++++++++++++++--- arch/arm64/boot/dts/qcom/skeleton64.dtsi | 1 - arch/arm64/boot/dts/qcom/smb1355.dtsi | 107 + 70 files changed, 29633 insertions(+), 1054 deletions(-) create mode 100644 arch/arm64/boot/dts/qcom/dsi-panel-nt35597-dualmipi-wqxga-cmd.dtsi create mode 100644 arch/arm64/boot/dts/qcom/dsi-panel-nt35597-dualmipi-wqxga-video.dtsi create mode 100644 arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-cmd.dtsi create mode 100644 arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi create mode 100644 arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi create mode 100644 arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi create mode 100644 arch/arm64/boot/dts/qcom/dsi-panel-nt36850-truly-dualmipi-wqhd-cmd.dtsi create mode 100644 arch/arm64/boot/dts/qcom/dsi-panel-r63417-truly-1080p-cmd.dtsi create mode 100644 arch/arm64/boot/dts/qcom/dsi-panel-s6e3ha3-amoled-dualmipi-wqhd-cmd.dtsi create mode 100644 arch/arm64/boot/dts/qcom/dsi-panel-sharp-1080p-cmd.dtsi create mode 100644 arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-cmd.dtsi create mode 100644 arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-video.dtsi create mode 100644 arch/arm64/boot/dts/qcom/dsi-panel-sharp-dualmipi-1080p-120hz.dtsi create mode 100644 arch/arm64/boot/dts/qcom/dsi-panel-sim-cmd.dtsi create mode 100644 arch/arm64/boot/dts/qcom/dsi-panel-sim-dsc375-cmd.dtsi create mode 100644 arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-cmd.dtsi create mode 100644 arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-dsc375-cmd.dtsi create mode 100644 arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-video.dtsi create mode 100644 arch/arm64/boot/dts/qcom/dsi-panel-sim-video.dtsi create mode 100644 arch/arm64/boot/dts/qcom/dsi-panel-test-dualmipi-oled-cmd.dtsi create mode 100644 arch/arm64/boot/dts/qcom/fg-gen3-batterydata-ascent-3450mah.dtsi create mode 100644 arch/arm64/boot/dts/qcom/fg-gen3-batterydata-demo-6000mah.dtsi create mode 100644 arch/arm64/boot/dts/qcom/fg-gen3-batterydata-itech-3000mah.dtsi create mode 100644 arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi create mode 100644 arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi create mode 100644 arch/arm64/boot/dts/qcom/msm-gdsc-sdm845.dtsi create mode 100644 arch/arm64/boot/dts/qcom/msm-rdbg.dtsi create mode 100644 arch/arm64/boot/dts/qcom/msm-wsa881x.dtsi create mode 100644 arch/arm64/boot/dts/qcom/pmi8998.dtsi create mode 100644 arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi create mode 100644 arch/arm64/boot/dts/qcom/sdm845-audio-overlay.dtsi create mode 100644 arch/arm64/boot/dts/qcom/sdm845-audio.dtsi create mode 100644 arch/arm64/boot/dts/qcom/sdm845-bus.dtsi create mode 100644 arch/arm64/boot/dts/qcom/sdm845-camera-sensor-mtp.dtsi create mode 100644 arch/arm64/boot/dts/qcom/sdm845-camera.dtsi create mode 100644 arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi create mode 100644 arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi create mode 100644 arch/arm64/boot/dts/qcom/sdm845-ion.dtsi create mode 100644 arch/arm64/boot/dts/qcom/sdm845-mtp-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi create mode 100644 arch/arm64/boot/dts/qcom/sdm845-pcie.dtsi create mode 100644 arch/arm64/boot/dts/qcom/sdm845-pinctrl-overlay.dtsi create mode 100644 arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi create mode 100644 arch/arm64/boot/dts/qcom/sdm845-pm.dtsi create mode 100644 arch/arm64/boot/dts/qcom/sdm845-pmic-overlay.dtsi create mode 100644 arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi create mode 100644 arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi create mode 100644 arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi create mode 100644 arch/arm64/boot/dts/qcom/sdm845-sde-pll.dtsi create mode 100644 arch/arm64/boot/dts/qcom/sdm845-sde.dtsi create mode 100644 arch/arm64/boot/dts/qcom/sdm845-smp2p.dtsi create mode 100644 arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi create mode 100644 arch/arm64/boot/dts/qcom/sdm845-v2-mtp-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/sdm845-v2-mtp.dts create mode 100644 arch/arm64/boot/dts/qcom/sdm845-v2.1-mtp-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/sdm845-v2.1-mtp.dts create mode 100644 arch/arm64/boot/dts/qcom/sdm845-v2.1.dts create mode 100644 arch/arm64/boot/dts/qcom/sdm845-v2.1.dtsi create mode 100644 arch/arm64/boot/dts/qcom/sdm845-v2.dts create mode 100644 arch/arm64/boot/dts/qcom/sdm845-v2.dtsi create mode 100644 arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi create mode 100644 arch/arm64/boot/dts/qcom/sdm845-wcd.dtsi create mode 100644 arch/arm64/boot/dts/qcom/sdm845.dts create mode 100644 arch/arm64/boot/dts/qcom/smb1355.dtsi diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms index 6dcf2da859a5..b525f4161d5f 100644 --- a/arch/arm64/Kconfig.platforms +++ b/arch/arm64/Kconfig.platforms @@ -230,6 +230,16 @@ config ARCH_SDM660 This enables support for the SDM660 chipset. If you do not wish to build a kernel that runs on this chipset, say 'N' here. +config ARCH_SDM845 + bool "Enable Support for Qualcomm Technologies Inc. SDM845" + depends on ARCH_QCOM + select COMMON_CLK + select COMMON_CLK_QCOM + select QCOM_GDSC + help + This enables support for the SDM845 chipset. If you do not + wish to build a kernel that runs on this chipset, say 'N' here. + config ARCH_REALTEK bool "Realtek Platforms" help diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-dualmipi-wqxga-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-dualmipi-wqxga-cmd.dtsi new file mode 100644 index 000000000000..78f933ad23c2 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-dualmipi-wqxga-cmd.dtsi @@ -0,0 +1,112 @@ +/* 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_dual_nt35597_cmd: qcom,mdss_dsi_nt35597_wqxga_cmd{ + qcom,mdss-dsi-panel-name = + "Dual nt35597 cmd mode dsi panel without DSC"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + qcom,mdss-dsi-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-t-clk-post = <0x0d>; + qcom,mdss-dsi-t-clk-pre = <0x2d>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,ulps-enabled; + + qcom,mdss-dsi-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-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 10 + 15 01 00 00 10 00 02 fb 01 + 15 01 00 00 10 00 02 ba 03 + 15 01 00 00 10 00 02 e5 01 + 15 01 00 00 10 00 02 35 00 + 15 01 00 00 10 00 02 bb 10 + 15 01 00 00 10 00 02 b0 03 + 15 01 00 00 10 00 02 ff e0 + 15 01 00 00 10 00 02 fb 01 + 15 01 00 00 10 00 02 6b 3d + 15 01 00 00 10 00 02 6c 3d + 15 01 00 00 10 00 02 6d 3d + 15 01 00 00 10 00 02 6e 3d + 15 01 00 00 10 00 02 6f 3d + 15 01 00 00 10 00 02 35 02 + 15 01 00 00 10 00 02 36 72 + 15 01 00 00 10 00 02 37 10 + 15 01 00 00 10 00 02 08 c0 + 15 01 00 00 10 00 02 ff 24 + 15 01 00 00 10 00 02 fb 01 + 15 01 00 00 10 00 02 c6 06 + 15 01 00 00 10 00 02 ff 10 + 05 01 00 00 a0 00 02 11 00 + 05 01 00 00 a0 00 02 29 00]; + + qcom,mdss-dsi-off-command = [05 01 00 00 0a 00 + 02 28 00 05 01 00 00 3c 00 02 10 00]; + + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-timings = [cd 32 22 00 60 + 64 26 34 29 03 04 00]; + + qcom,config-select = + <&dsi_dual_nt35597_cmd_config0>; + + dsi_dual_nt35597_cmd_config0: config0 { + qcom,split-mode = "dualctl-split"; + }; + + dsi_dual_nt35597_cmd_config1: config1 { + qcom,split-mode = "pingpong-split"; + }; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-dualmipi-wqxga-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-dualmipi-wqxga-video.dtsi new file mode 100644 index 000000000000..9cd5815e7529 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-dualmipi-wqxga-video.dtsi @@ -0,0 +1,111 @@ +/* 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_dual_nt35597_video: qcom,mdss_dsi_nt35597_wqxga_video { + qcom,mdss-dsi-panel-name = + "Dual nt35597 video mode dsi panel without DSC"; + qcom,mdss-dsi-panel-type = "dsi_video_mode"; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-underflow-color = <0x3ff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <14500 15500 32000 + 17000 15500 30000 8000 3000>; + qcom,mdss-dsi-panel-peak-brightness = <4200000>; + qcom,mdss-dsi-panel-blackness-level = <3230>; + qcom,mdss-dsi-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,cmd-sync-wait-broadcast; + qcom,mdss-dsi-t-clk-post = <0x0d>; + qcom,mdss-dsi-t-clk-pre = <0x2d>; + qcom,mdss-dsi-min-refresh-rate = <55>; + qcom,mdss-dsi-max-refresh-rate = <60>; + qcom,mdss-dsi-pan-enable-dynamic-fps; + qcom,mdss-dsi-pan-fps-update = + "dfps_immediate_porch_mode_vfp"; + + qcom,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 = + [15 01 00 00 00 00 02 ff 10 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 ba 03 + 15 01 00 00 00 00 02 e5 01 + 15 01 00 00 00 00 02 35 00 + 15 01 00 00 00 00 02 bb 03 + 15 01 00 00 00 00 02 b0 03 + 39 01 00 00 00 00 06 3b 03 + 08 08 64 9a + 15 01 00 00 00 00 02 ff e0 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 6b 3d + 15 01 00 00 00 00 02 6c 3d + 15 01 00 00 00 00 02 6d 3d + 15 01 00 00 00 00 02 6e 3d + 15 01 00 00 00 00 02 6f 3d + 15 01 00 00 00 00 02 35 02 + 15 01 00 00 00 00 02 36 72 + 15 01 00 00 00 00 02 37 10 + 15 01 00 00 00 00 02 08 c0 + 15 01 00 00 00 00 02 ff 10 + 05 01 00 00 78 00 02 11 00 + 05 01 00 00 32 00 02 29 00]; + qcom,mdss-dsi-off-command = [05 01 00 00 + 0a 00 02 28 00 05 01 00 00 3c 00 + 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-panel-timings = [e2 36 24 00 66 + 6a 28 38 2a 03 04 00]; + + qcom,config-select = + <&dsi_dual_nt35597_video_config0>; + + dsi_dual_nt35597_video_config0: + config0 { + qcom,split-mode = + "dualctl-split"; + }; + + dsi_dual_nt35597_video_config1: + config1 { + qcom,split-mode = + "pingpong-split"; + }; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-cmd.dtsi new file mode 100644 index 000000000000..0e60a0c1f22e --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-cmd.dtsi @@ -0,0 +1,247 @@ +/* Copyright (c) 2016-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_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,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 11 + 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/qcom/dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi new file mode 100644 index 000000000000..b2a541d9384e --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi @@ -0,0 +1,233 @@ +/* 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. + */ + +&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,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 11 + 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/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi new file mode 100644 index 000000000000..1a8ce910fc2a --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi @@ -0,0 +1,231 @@ +/* Copyright (c) 2016-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_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,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 11 + 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 + /* NVT SDC */ + 15 01 00 00 00 00 02 C0 00 + /* GRAM Slide Parameter */ + 29 01 00 00 00 00 0C C9 01 01 70 + 00 0A 06 67 04 C5 12 18 + /* 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/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi new file mode 100644 index 000000000000..95e0e5ae1db8 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi @@ -0,0 +1,213 @@ +/* Copyright (c) 2016-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_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,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 11 + 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/qcom/dsi-panel-nt36850-truly-dualmipi-wqhd-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-nt36850-truly-dualmipi-wqhd-cmd.dtsi new file mode 100644 index 000000000000..ca28261a82a7 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dsi-panel-nt36850-truly-dualmipi-wqhd-cmd.dtsi @@ -0,0 +1,87 @@ +/* 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. + */ + +&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,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/qcom/dsi-panel-r63417-truly-1080p-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-r63417-truly-1080p-cmd.dtsi new file mode 100644 index 000000000000..29aab25ec15e --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dsi-panel-r63417-truly-1080p-cmd.dtsi @@ -0,0 +1,104 @@ +/* Copyright (c) 2015-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. + */ + +&mdss_mdp { + dsi_r63417_truly_1080_cmd: qcom,mdss_dsi_r63417_truly_1080p_cmd { + qcom,mdss-dsi-panel-name = + "r63417 truly 1080p cmd mode 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-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-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-t-clk-post = <0x02>; + qcom,mdss-dsi-t-clk-pre = <0x2d>; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; + qcom,mdss-dsi-post-init-delay = <1>; + qcom,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 = <96>; + qcom,mdss-dsi-h-back-porch = <64>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <16>; + qcom,mdss-dsi-v-front-porch = <4>; + qcom,mdss-dsi-v-pulse-width = <1>; + qcom,mdss-dsi-h-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 = + [23 01 00 00 00 00 02 d6 01 + 15 01 00 00 00 00 02 35 00 + 15 01 00 00 00 00 02 51 ff + 15 01 00 00 00 00 02 53 2c + 15 01 00 00 00 00 02 55 00 + 05 01 00 00 78 00 02 11 00 + 23 01 00 00 00 00 02 b0 04 + 29 01 00 00 00 00 07 b3 04 00 00 00 00 00 + 29 01 00 00 00 00 03 b6 3a d3 + 29 01 00 00 00 00 03 c0 00 00 + 29 01 00 00 00 00 23 c1 84 60 10 eb ff 6f ce ff ff 17 02 + 58 73 ae b1 20 c6 ff ff 1f f3 ff 5f 10 10 10 10 + 00 02 01 22 22 00 01 + 29 01 00 00 00 00 08 c2 31 f7 80 06 08 00 00 + 29 01 00 00 00 00 17 c4 70 00 00 00 00 04 00 00 00 0c 06 + 00 00 00 00 00 04 00 00 00 0c 06 + 29 01 00 00 00 00 29 c6 78 69 00 69 00 69 00 00 00 00 00 + 69 00 69 00 69 10 19 07 00 78 00 69 00 69 00 69 + 00 00 00 00 00 69 00 69 00 69 10 19 07 + 29 01 00 00 00 00 0a cb 31 fc 3f 8c 00 00 00 00 c0 + 23 01 00 00 00 00 02 cc 0b + 29 01 00 00 00 00 0b d0 11 81 bb 1e 1e 4c 19 19 0c 00 + 29 01 00 00 00 00 1a d3 1b 33 bb bb b3 33 33 33 00 01 00 + a0 d8 a0 0d 4e 4e 33 3b 22 72 07 3d bf 33 + 29 01 00 00 00 00 08 d5 06 00 00 01 51 01 32 + 29 01 00 00 00 00 1f c7 01 0a 11 18 26 33 3e 50 38 42 52 + 60 67 6e 77 01 0a 11 18 26 33 3e 50 38 42 52 60 + 67 6e 77 + 29 01 00 00 14 00 14 c8 01 00 00 00 00 fc 00 00 00 00 + 00 fc 00 00 00 00 00 fc 00 + 05 01 00 00 14 00 02 29 00]; + qcom,mdss-dsi-off-command = [05 01 00 00 14 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-timings = + [e6 38 26 00 68 6e 2a 3c 44 03 04 00]; + }; + }; + }; +}; + diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-s6e3ha3-amoled-dualmipi-wqhd-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-s6e3ha3-amoled-dualmipi-wqhd-cmd.dtsi new file mode 100644 index 000000000000..834a08fd4625 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dsi-panel-s6e3ha3-amoled-dualmipi-wqhd-cmd.dtsi @@ -0,0 +1,141 @@ +/* Copyright (c) 2016-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_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/qcom/dsi-panel-sharp-1080p-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sharp-1080p-cmd.dtsi new file mode 100644 index 000000000000..aebc8b924182 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dsi-panel-sharp-1080p-cmd.dtsi @@ -0,0 +1,86 @@ +/* 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_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,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/qcom/dsi-panel-sharp-dsc-4k-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-cmd.dtsi new file mode 100644 index 000000000000..86c8836ca518 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-cmd.dtsi @@ -0,0 +1,103 @@ +/* Copyright (c) 2016-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_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,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 200>, <0 200>, <1 200>; + 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/qcom/dsi-panel-sharp-dsc-4k-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-video.dtsi new file mode 100644 index 000000000000..66beead39bed --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-video.dtsi @@ -0,0 +1,96 @@ +/* Copyright (c) 2016-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_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,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 200>, <0 200>, <1 200>; + 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/qcom/dsi-panel-sharp-dualmipi-1080p-120hz.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dualmipi-1080p-120hz.dtsi new file mode 100644 index 000000000000..6dc621ed8922 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dualmipi-1080p-120hz.dtsi @@ -0,0 +1,633 @@ +/* Copyright (c) 2014-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_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,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/qcom/dsi-panel-sim-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sim-cmd.dtsi new file mode 100644 index 000000000000..45ac04219915 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dsi-panel-sim-cmd.dtsi @@ -0,0 +1,219 @@ +/* Copyright (c) 2014-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_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,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-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,ulps-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-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@1{ + 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@2{ + 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/qcom/dsi-panel-sim-dsc375-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sim-dsc375-cmd.dtsi new file mode 100644 index 000000000000..ceb68568fa9f --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dsi-panel-sim-dsc375-cmd.dtsi @@ -0,0 +1,286 @@ +/* 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_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,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/qcom/dsi-panel-sim-dualmipi-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-cmd.dtsi new file mode 100644 index 000000000000..9a4e318ba756 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-cmd.dtsi @@ -0,0 +1,121 @@ +/* Copyright (c) 2014-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_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,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 = <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"; + }; + timing@1{ + 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-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 = + [/* 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"; + }; + 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"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-dsc375-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-dsc375-cmd.dtsi new file mode 100644 index 000000000000..5d977e7cb675 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-dsc375-cmd.dtsi @@ -0,0 +1,281 @@ +/* Copyright (c) 2016-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_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,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; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-video.dtsi new file mode 100644 index 000000000000..dbfedb92865a --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-video.dtsi @@ -0,0 +1,61 @@ +/* Copyright (c) 2014-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_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,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-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"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-sim-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sim-video.dtsi new file mode 100644 index 000000000000..40bedd0e462c --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dsi-panel-sim-video.dtsi @@ -0,0 +1,69 @@ +/* Copyright (c) 2012-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_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,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/qcom/dsi-panel-test-dualmipi-oled-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-test-dualmipi-oled-cmd.dtsi new file mode 100644 index 000000000000..3a5d272903b1 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dsi-panel-test-dualmipi-oled-cmd.dtsi @@ -0,0 +1,50 @@ +/* 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. + */ + +&mdss_mdp { + dsi_dual_test_cmd: qcom,mdss_dsi_test_oled_cmd { + qcom,mdss-dsi-panel-name = + "Dual test cmd mode DSI amoled non-DSC 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,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 2>, <0 2>, <1 2>; + 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-hfp-power-mode; + qcom,mdss-dsi-hbp-power-mode; + qcom,mdss-dsi-hsa-power-mode; + qcom,mdss-dsi-display-timings { + timing@0{ + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-ascent-3450mah.dtsi b/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-ascent-3450mah.dtsi new file mode 100644 index 000000000000..a57ea7c9e3e0 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-ascent-3450mah.dtsi @@ -0,0 +1,90 @@ +/* Copyright (c) 2016-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. + */ + +qcom,ascent_3450mah { + /* Ascent_wConn_Aging_3450mAh_averaged_MasterSlave_Jul11th2017 */ + qcom,max-voltage-uv = <4350000>; + qcom,fg-cc-cv-threshold-mv = <4340>; + qcom,fastchg-current-ma = <3450>; + qcom,batt-id-kohm = <60>; + qcom,jeita-fcc-ranges = <0 100 1725000 + 101 400 3450000 + 401 450 2760000>; + qcom,jeita-fv-ranges = <0 100 4250000 + 101 400 4350000 + 401 450 4250000>; + qcom,step-chg-ranges = <3600000 4200000 3450000 + 4201000 4300000 2760000 + 4301000 4350000 2070000>; + qcom,battery-beta = <3435>; + qcom,battery-type = "ascent_3450mah_averaged_masterslave_oct30th2017"; + qcom,checksum = <0xAAE2>; + qcom,gui-version = "PMI8998GUI - 2.0.0.58"; + qcom,fg-profile-data = [ + 8F 1F 94 05 + 73 0A 4A 06 + 27 1D 21 EA + 16 0A 3A 0C + 07 18 97 22 + A5 3C EC 4A + 5C 00 00 00 + 10 00 00 00 + 00 00 43 C5 + 92 BC 89 BB + 11 00 08 00 + 69 DA AD 07 + 4B FD 19 FA + 7E 01 49 13 + EB F3 78 3B + 24 06 09 20 + 27 00 14 00 + 7E 1F F2 05 + 19 0A AB 06 + 6C 1D B9 07 + 1A 12 FF 1D + 6F 18 EB 22 + B9 45 6F 52 + 55 00 00 00 + 0E 00 00 00 + 00 00 33 CC + 72 CA B3 C4 + 0F 00 00 00 + 93 00 AD 07 + 8D FD F6 00 + 6F E3 44 0B + AB FC F9 1B + C3 33 CC FF + 07 10 00 00 + A4 0D 99 45 + 0F 00 40 00 + A4 01 0A FA + FF 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + ]; +}; diff --git a/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-demo-6000mah.dtsi b/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-demo-6000mah.dtsi new file mode 100644 index 000000000000..1e8cd16567b8 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-demo-6000mah.dtsi @@ -0,0 +1,78 @@ +/* Copyright (c) 2016-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. + */ + +qcom,demo_6000mah { + qcom,max-voltage-uv = <4350000>; + qcom,fg-cc-cv-threshold-mv = <4340>; + qcom,fastchg-current-ma = <6000>; + qcom,batt-id-kohm = <75>; + qcom,battery-beta = <3435>; + qcom,battery-type = "Demo_battery_6000mah"; + qcom,fg-profile-data = [ + 2C 1F 3F FC + E9 03 A1 FD + 58 1D FD F5 + 27 12 2C 14 + 3F 18 FF 22 + 9B 45 A3 52 + 55 00 00 00 + 0E 00 00 00 + 00 00 1C AC + F7 CD 71 B5 + 1A 00 0C 00 + 3C EB 54 E4 + EC 05 7F FA + 76 05 F5 02 + CA F3 82 3A + 2A 09 40 40 + 07 00 05 00 + 58 1F 42 06 + 85 03 35 F4 + 4D 1D 37 F2 + 23 0A 79 15 + B7 18 32 23 + 26 45 72 53 + 55 00 00 00 + 0D 00 00 00 + 00 00 13 CC + 03 00 98 BD + 16 00 00 00 + 3C EB 54 E4 + 9F FC A3 F3 + 0F FC DF FA + FF E5 A9 23 + CB 33 08 33 + 07 10 00 00 + 81 0D 99 45 + 16 00 19 00 + 75 01 0A FA + FF 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + ]; +}; diff --git a/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-itech-3000mah.dtsi b/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-itech-3000mah.dtsi new file mode 100644 index 000000000000..3888047b9f8c --- /dev/null +++ b/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-itech-3000mah.dtsi @@ -0,0 +1,81 @@ +/* Copyright (c) 2016-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. + */ + +qcom,itech_3000mah { + /* #Itech_B00826LF_3000mAh_ver1660_averaged_MasterSlave_Jan10th2017*/ + qcom,max-voltage-uv = <4350000>; + qcom,fg-cc-cv-threshold-mv = <4340>; + qcom,fastchg-current-ma = <2000>; + qcom,batt-id-kohm = <100>; + qcom,battery-beta = <3435>; + qcom,battery-type = "itech_b00826lf_3000mah_ver1660_jan10th2017"; + qcom,checksum = <0xFB8F>; + qcom,gui-version = "PMI8998GUI - 2.0.0.54"; + qcom,fg-profile-data = [ + A4 1F 6E 05 + 9C 0A 2B FC + 32 1D 23 E5 + 60 0B 1B 15 + AD 17 8C 22 + EA 3C 89 4A + 5B 00 00 00 + 12 00 00 00 + 00 00 62 C2 + 0C CD D8 C2 + 19 00 08 00 + 85 EA C7 EC + E2 05 2F 01 + 9B F5 12 12 + 5E 05 88 3B + 22 06 09 20 + 27 00 14 00 + 7D 1F DD 05 + 3F 0A E5 FC + 72 1D E3 F5 + 6F 12 C0 1D + 88 18 FB 22 + 8D 45 C6 52 + 54 00 00 00 + 0F 00 00 00 + 00 00 BD CD + 55 C2 5D C5 + 14 00 00 00 + 7E 00 C7 EC + 60 06 BB 00 + 59 06 61 03 + D9 FC 75 1B + B3 33 CC FF + 07 10 00 00 + 3E 0B 99 45 + 14 00 40 00 + AE 01 0A FA + FF 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + ]; +}; diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi new file mode 100644 index 000000000000..0ac9c2a1dc3f --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi @@ -0,0 +1,364 @@ +/* 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. + */ + +#include +#include + +&soc { + kgsl_smmu: arm,smmu-kgsl@5040000 { + status = "ok"; + compatible = "qcom,smmu-v2"; + reg = <0x5040000 0x10000>; + #iommu-cells = <1>; + qcom,dynamic; + qcom,use-3-lvl-tables; + qcom,disable-atos; + #global-interrupts = <2>; + qcom,regulator-names = "vdd"; + vdd-supply = <&gpu_cx_gdsc>; + interrupts = , + , + , + , + , + , + , + , + , + ; + clock-names = "gcc_gpu_memnoc_gfx_clk"; + clocks = <&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>; + 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@0x15000000 { + compatible = "qcom,qsmmu-v500"; + reg = <0x15000000 0x80000>, + <0x150c2000 0x20>; + reg-names = "base", "tcu-base"; + #iommu-cells = <2>; + qcom,skip-init; + qcom,use-3-lvl-tables; + qcom,no-asid-retention; + qcom,disable-atos; + #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>; + + anoc_1_tbu: anoc_1_tbu@0x150c5000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x150c5000 0x1000>, + <0x150c2200 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x0 0x400>; + qcom,regulator-names = "vdd"; + vdd-supply = <&hlos1_vote_aggre_noc_mmu_tbu1_gdsc>; + 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@0x150c9000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x150c9000 0x1000>, + <0x150c2208 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x400 0x400>; + qcom,regulator-names = "vdd"; + vdd-supply = <&hlos1_vote_aggre_noc_mmu_tbu2_gdsc>; + 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@0x150cd000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x150cd000 0x1000>, + <0x150c2210 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@0x150d1000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x150d1000 0x1000>, + <0x150c2218 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>; + }; + + mnoc_sf_0_tbu: mnoc_sf_0_tbu@0x150d5000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x150d5000 0x1000>, + <0x150c2220 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x1000 0x400>; + 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>; + }; + + compute_dsp_tbu: compute_dsp_tbu@0x150d9000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x150d9000 0x1000>, + <0x150c2228 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x1400 0x400>; + /* No GDSC */ + 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@0x150dd000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x150dd000 0x1000>, + <0x150c2230 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x1800 0x400>; + qcom,regulator-names = "vdd"; + vdd-supply = <&hlos1_vote_aggre_noc_mmu_audio_tbu_gdsc>; + 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@0x150e1000 { + compatible = "qcom,qsmmuv500-tbu"; + reg = <0x150e1000 0x1000>, + <0x150c2238 0x8>; + reg-names = "base", "status-reg"; + qcom,stream-id-range = <0x1c00 0x400>; + qcom,regulator-names = "vdd"; + vdd-supply = <&hlos1_vote_aggre_noc_mmu_pcie_tbu_gdsc>; + 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>; + }; + }; + + kgsl_iommu_test_device { + status = "disabled"; + compatible = "iommu-debug-test"; + /* + * 0x7 isn't a valid sid, but should pass the sid sanity check. + * We just need _something_ here to get this node recognized by + * the SMMU driver. Our test uses ATOS, which doesn't use SIDs + * anyways, so using a dummy value is ok. + */ + iommus = <&kgsl_smmu 0x7>; + }; + + apps_iommu_test_device { + compatible = "iommu-debug-test"; + /* + * This SID belongs to TSIF. We can't use a fake SID for + * the apps_smmu device. + */ + iommus = <&apps_smmu 0x20 0>; + }; + + apps_iommu_coherent_test_device { + compatible = "iommu-debug-test"; + /* + * This SID belongs to TSIF. We can't use a fake SID for + * the apps_smmu device. + */ + iommus = <&apps_smmu 0x20 0>; + dma-coherent; + }; +}; + +&apps_smmu { + qcom,actlr = <0x0880 0x8 0x103>, + <0x0881 0x8 0x103>, + <0x0c80 0x8 0x103>, + <0x0c81 0x8 0x103>, + <0x1090 0x0 0x103>, + <0x1091 0x0 0x103>, + <0x10a0 0x8 0x103>, + <0x10b0 0x0 0x103>, + <0x10a1 0x8 0x103>, + <0x10a3 0x8 0x103>, + <0x10a4 0x8 0x103>, + <0x10b4 0x0 0x103>, + <0x10a5 0x8 0x103>; + qcom,mmu500-errata-1 = <0x800 0x3ff>, + <0xc00 0x3ff>; +}; diff --git a/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi b/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi new file mode 100644 index 000000000000..bb05a2e86926 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi @@ -0,0 +1,596 @@ +/* + * Copyright (c) 2016-2020, 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. + */ + +&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"; + }; + + 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 = <24608>; + }; + + loopback: qcom,msm-pcm-loopback { + compatible = "qcom,msm-pcm-loopback"; + }; + + 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 = <6>; + qcom,msm-mi2s-rx-lines = <0>; + qcom,msm-mi2s-tx-lines = <3>; + }; + }; + + lsm: qcom,msm-lsm-client { + compatible = "qcom,msm-lsm-client"; + }; + + qcom,msm-dai-q6 { + compatible = "qcom,msm-dai-q6"; + sb_0_rx: qcom,msm-dai-q6-sb-0-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16384>; + }; + + sb_0_tx: qcom,msm-dai-q6-sb-0-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16385>; + }; + + sb_1_rx: qcom,msm-dai-q6-sb-1-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16386>; + }; + + sb_1_tx: qcom,msm-dai-q6-sb-1-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16387>; + }; + + sb_2_rx: qcom,msm-dai-q6-sb-2-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16388>; + }; + + sb_2_tx: qcom,msm-dai-q6-sb-2-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16389>; + }; + + + sb_3_rx: qcom,msm-dai-q6-sb-3-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16390>; + }; + + sb_3_tx: qcom,msm-dai-q6-sb-3-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16391>; + }; + + sb_4_rx: qcom,msm-dai-q6-sb-4-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16392>; + }; + + sb_4_tx: qcom,msm-dai-q6-sb-4-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16393>; + }; + + sb_5_tx: qcom,msm-dai-q6-sb-5-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16395>; + }; + + sb_5_rx: qcom,msm-dai-q6-sb-5-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16394>; + }; + + sb_6_rx: qcom,msm-dai-q6-sb-6-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16396>; + }; + + sb_7_rx: qcom,msm-dai-q6-sb-7-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16398>; + }; + + sb_7_tx: qcom,msm-dai-q6-sb-7-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16399>; + }; + + sb_8_rx: qcom,msm-dai-q6-sb-8-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16400>; + }; + + sb_8_tx: qcom,msm-dai-q6-sb-8-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <16401>; + }; + + 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>; + }; + + afe_loopback_tx: qcom,msm-dai-q6-afe-loopback-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <24577>; + }; + + 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"; + }; + + 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>; + }; + + hdmi_dba: qcom,msm-hdmi-dba-codec-rx { + compatible = "qcom,msm-hdmi-dba-codec-rx"; + qcom,dba-bridge-chip = "adv7533"; + }; + + msm_audio_ion: qcom,msm-audio-ion { + compatible = "qcom,msm-audio-ion"; + qcom,smmu-version = <2>; + qcom,smmu-enabled; + iommus = <&apps_smmu 0x1821 0x0>; + }; + + qcom,msm-adsp-loader { + status = "ok"; + compatible = "qcom,adsp-loader"; + qcom,adsp-state = <0>; + }; + + qcom,msm-dai-tdm-pri-rx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37120>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36864>; + qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; + dai_pri_tdm_rx_0: qcom,msm-dai-q6-tdm-pri-rx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36864>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + qcom,msm-dai-tdm-pri-tx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37121>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36865>; + qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; + dai_pri_tdm_tx_0: qcom,msm-dai-q6-tdm-pri-tx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36865>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + qcom,msm-dai-tdm-sec-rx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37136>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36880>; + qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; + dai_sec_tdm_rx_0: qcom,msm-dai-q6-tdm-sec-rx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36880>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + qcom,msm-dai-tdm-sec-tx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37137>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36881>; + qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; + dai_sec_tdm_tx_0: qcom,msm-dai-q6-tdm-sec-tx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36881>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + qcom,msm-dai-tdm-tert-rx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37152>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36896>; + qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; + dai_tert_tdm_rx_0: qcom,msm-dai-q6-tdm-tert-rx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36896>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + qcom,msm-dai-tdm-tert-tx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37153>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36897 >; + qcom,msm-cpudai-tdm-clk-rate = <1536000>; + qcom,msm-cpudai-tdm-clk-internal = <1>; + qcom,msm-cpudai-tdm-sync-mode = <1>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <1>; + qcom,msm-cpudai-tdm-data-delay = <1>; + dai_tert_tdm_tx_0: qcom,msm-dai-q6-tdm-tert-tx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36897 >; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + msm_dai_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>; + }; + }; + + 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>; + }; + }; + + 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>; + }; + }; + + 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>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/msm-gdsc-sdm845.dtsi b/arch/arm64/boot/dts/qcom/msm-gdsc-sdm845.dtsi new file mode 100644 index 000000000000..b43c87633365 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm-gdsc-sdm845.dtsi @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2016-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. + */ + +&soc { + /* GDSCs in Global CC */ + pcie_0_gdsc: qcom,gdsc@0x16b004 { + compatible = "qcom,gdsc"; + regulator-name = "pcie_0_gdsc"; + reg = <0x16b004 0x4>; + qcom,poll-cfg-gdscr; + status = "disabled"; + }; + + pcie_1_gdsc: qcom,gdsc@0x18d004 { + compatible = "qcom,gdsc"; + regulator-name = "pcie_1_gdsc"; + reg = <0x18d004 0x4>; + qcom,poll-cfg-gdscr; + status = "disabled"; + }; + + ufs_card_gdsc: qcom,gdsc@0x175004 { + compatible = "qcom,gdsc"; + regulator-name = "ufs_card_gdsc"; + reg = <0x175004 0x4>; + qcom,poll-cfg-gdscr; + status = "disabled"; + }; + + ufs_phy_gdsc: qcom,gdsc@0x177004 { + compatible = "qcom,gdsc"; + regulator-name = "ufs_phy_gdsc"; + reg = <0x177004 0x4>; + qcom,poll-cfg-gdscr; + status = "disabled"; + }; + + usb30_prim_gdsc: qcom,gdsc@0x10f004 { + compatible = "qcom,gdsc"; + regulator-name = "usb30_prim_gdsc"; + reg = <0x10f004 0x4>; + qcom,poll-cfg-gdscr; + status = "disabled"; + }; + + usb30_sec_gdsc: qcom,gdsc@0x110004 { + compatible = "qcom,gdsc"; + regulator-name = "usb30_sec_gdsc"; + reg = <0x110004 0x4>; + qcom,poll-cfg-gdscr; + status = "disabled"; + }; + + hlos1_vote_aggre_noc_mmu_audio_tbu_gdsc: qcom,gdsc@0x17d030 { + compatible = "qcom,gdsc"; + regulator-name = "hlos1_vote_aggre_noc_mmu_audio_tbu_gdsc"; + reg = <0x17d030 0x4>; + qcom,no-status-check-on-disable; + qcom,gds-timeout = <500>; + status = "disabled"; + }; + + hlos1_vote_aggre_noc_mmu_pcie_tbu_gdsc: qcom,gdsc@0x17d03c { + compatible = "qcom,gdsc"; + regulator-name = "hlos1_vote_aggre_noc_mmu_pcie_tbu_gdsc"; + reg = <0x17d03c 0x4>; + qcom,no-status-check-on-disable; + qcom,gds-timeout = <500>; + status = "disabled"; + }; + + hlos1_vote_aggre_noc_mmu_tbu1_gdsc: qcom,gdsc@0x17d034 { + compatible = "qcom,gdsc"; + regulator-name = "hlos1_vote_aggre_noc_mmu_tbu1_gdsc"; + reg = <0x17d034 0x4>; + qcom,no-status-check-on-disable; + qcom,gds-timeout = <500>; + status = "disabled"; + }; + + hlos1_vote_aggre_noc_mmu_tbu2_gdsc: qcom,gdsc@0x17d038 { + compatible = "qcom,gdsc"; + regulator-name = "hlos1_vote_aggre_noc_mmu_tbu2_gdsc"; + reg = <0x17d038 0x4>; + qcom,no-status-check-on-disable; + qcom,gds-timeout = <500>; + status = "disabled"; + }; + + hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc: qcom,gdsc@0x17d040 { + compatible = "qcom,gdsc"; + regulator-name = "hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc"; + reg = <0x17d040 0x4>; + qcom,no-status-check-on-disable; + qcom,gds-timeout = <500>; + status = "disabled"; + }; + + hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc: qcom,gdsc@0x17d048 { + compatible = "qcom,gdsc"; + regulator-name = "hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc"; + reg = <0x17d048 0x4>; + qcom,no-status-check-on-disable; + qcom,gds-timeout = <500>; + status = "disabled"; + }; + + hlos1_vote_mmnoc_mmu_tbu_sf_gdsc: qcom,gdsc@0x17d044 { + compatible = "qcom,gdsc"; + regulator-name = "hlos1_vote_mmnoc_mmu_tbu_sf_gdsc"; + reg = <0x17d044 0x4>; + qcom,no-status-check-on-disable; + qcom,gds-timeout = <500>; + status = "disabled"; + }; + + /* GDSCs in Camera CC */ + bps_gdsc: qcom,gdsc@0xad06004 { + compatible = "qcom,gdsc"; + regulator-name = "bps_gdsc"; + reg = <0xad06004 0x4>; + qcom,poll-cfg-gdscr; + status = "disabled"; + }; + + ife_0_gdsc: qcom,gdsc@0xad09004 { + compatible = "qcom,gdsc"; + regulator-name = "ife_0_gdsc"; + reg = <0xad09004 0x4>; + qcom,poll-cfg-gdscr; + status = "disabled"; + }; + + ife_1_gdsc: qcom,gdsc@0xad0a004 { + compatible = "qcom,gdsc"; + regulator-name = "ife_1_gdsc"; + reg = <0xad0a004 0x4>; + qcom,poll-cfg-gdscr; + status = "disabled"; + }; + + ipe_0_gdsc: qcom,gdsc@0xad07004 { + compatible = "qcom,gdsc"; + regulator-name = "ipe_0_gdsc"; + reg = <0xad07004 0x4>; + qcom,poll-cfg-gdscr; + status = "disabled"; + }; + + ipe_1_gdsc: qcom,gdsc@0xad08004 { + compatible = "qcom,gdsc"; + regulator-name = "ipe_1_gdsc"; + reg = <0xad08004 0x4>; + qcom,poll-cfg-gdscr; + status = "disabled"; + }; + + titan_top_gdsc: qcom,gdsc@0xad0b134 { + compatible = "qcom,gdsc"; + regulator-name = "titan_top_gdsc"; + reg = <0xad0b134 0x4>; + qcom,poll-cfg-gdscr; + status = "disabled"; + }; + + /* GDSCs in Display CC */ + mdss_core_gdsc: qcom,gdsc@0xaf03000 { + compatible = "qcom,gdsc"; + regulator-name = "mdss_core_gdsc"; + reg = <0xaf03000 0x4>; + qcom,poll-cfg-gdscr; + qcom,support-hw-trigger; + status = "disabled"; + proxy-supply = <&mdss_core_gdsc>; + qcom,proxy-consumer-enable; + }; + + /* GDSCs in Graphics CC */ + gpu_cx_hw_ctrl: syscon@0x5091540 { + compatible = "syscon"; + reg = <0x5091540 0x4>; + }; + + gpu_cx_gdsc: qcom,gdsc@0x509106c { + compatible = "qcom,gdsc"; + regulator-name = "gpu_cx_gdsc"; + reg = <0x509106c 0x4>; + 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@0x509100c { + compatible = "qcom,gdsc"; + regulator-name = "gpu_gx_gdsc"; + reg = <0x509100c 0x4>; + qcom,poll-cfg-gdscr; + status = "disabled"; + }; + + /* GDSCs in Video CC */ + vcodec0_gdsc: qcom,gdsc@0xab00874 { + compatible = "qcom,gdsc"; + regulator-name = "vcodec0_gdsc"; + reg = <0xab00874 0x4>; + qcom,poll-cfg-gdscr; + status = "disabled"; + }; + + vcodec1_gdsc: qcom,gdsc@0xab008b4 { + compatible = "qcom,gdsc"; + regulator-name = "vcodec1_gdsc"; + reg = <0xab008b4 0x4>; + qcom,poll-cfg-gdscr; + status = "disabled"; + }; + + venus_gdsc: qcom,gdsc@0xab00814 { + compatible = "qcom,gdsc"; + regulator-name = "venus_gdsc"; + reg = <0xab00814 0x4>; + qcom,poll-cfg-gdscr; + status = "disabled"; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/msm-rdbg.dtsi b/arch/arm64/boot/dts/qcom/msm-rdbg.dtsi new file mode 100644 index 000000000000..d9d1be428c71 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm-rdbg.dtsi @@ -0,0 +1,106 @@ +/* Copyright (c) 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. + */ + +&soc { + smp2pgpio_rdbg_2_in: qcom,smp2pgpio-rdbg-2-in { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "rdbg"; + qcom,remote-pid = <2>; + qcom,is-inbound; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio_client_rdbg_2_in { + compatible = "qcom,smp2pgpio_client_rdbg_2_in"; + gpios = <&smp2pgpio_rdbg_2_in 0 0>; + }; + + smp2pgpio_rdbg_2_out: qcom,smp2pgpio-rdbg-2-out { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "rdbg"; + qcom,remote-pid = <2>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio_client_rdbg_2_out { + compatible = "qcom,smp2pgpio_client_rdbg_2_out"; + gpios = <&smp2pgpio_rdbg_2_out 0 0>; + }; + + smp2pgpio_rdbg_1_in: qcom,smp2pgpio-rdbg-1-in { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "rdbg"; + qcom,remote-pid = <1>; + qcom,is-inbound; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio_client_rdbg_1_in { + compatible = "qcom,smp2pgpio_client_rdbg_1_in"; + gpios = <&smp2pgpio_rdbg_1_in 0 0>; + }; + + smp2pgpio_rdbg_1_out: qcom,smp2pgpio-rdbg-1-out { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "rdbg"; + qcom,remote-pid = <1>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio_client_rdbg_1_out { + compatible = "qcom,smp2pgpio_client_rdbg_1_out"; + gpios = <&smp2pgpio_rdbg_1_out 0 0>; + }; + + smp2pgpio_rdbg_5_in: qcom,smp2pgpio-rdbg-5-in { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "rdbg"; + qcom,remote-pid = <5>; + qcom,is-inbound; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio_client_rdbg_5_in { + compatible = "qcom,smp2pgpio_client_rdbg_5_in"; + gpios = <&smp2pgpio_rdbg_5_in 0 0>; + }; + + smp2pgpio_rdbg_5_out: qcom,smp2pgpio-rdbg-5-out { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "rdbg"; + qcom,remote-pid = <5>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio_client_rdbg_5_out { + compatible = "qcom,smp2pgpio_client_rdbg_5_out"; + gpios = <&smp2pgpio_rdbg_5_out 0 0>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/msm-wsa881x.dtsi b/arch/arm64/boot/dts/qcom/msm-wsa881x.dtsi new file mode 100644 index 000000000000..948da3bb6888 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm-wsa881x.dtsi @@ -0,0 +1,45 @@ +/* Copyright (c) 2016-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. + */ + +&slim_aud { + tavil_codec { + swr_master { + compatible = "qcom,swr-wcd"; + #address-cells = <2>; + #size-cells = <0>; + + wsa881x_0211: wsa881x@20170211 { + compatible = "qcom,wsa881x"; + reg = <0x00 0x20170211>; + qcom,spkr-sd-n-node = <&wsa_spkr_wcd_sd1>; + }; + + wsa881x_0212: wsa881x@20170212 { + compatible = "qcom,wsa881x"; + reg = <0x00 0x20170212>; + qcom,spkr-sd-n-node = <&wsa_spkr_wcd_sd2>; + }; + + wsa881x_0213: wsa881x@21170213 { + compatible = "qcom,wsa881x"; + reg = <0x00 0x21170213>; + qcom,spkr-sd-n-node = <&wsa_spkr_wcd_sd1>; + }; + + wsa881x_0214: wsa881x@21170214 { + compatible = "qcom,wsa881x"; + reg = <0x00 0x21170214>; + qcom,spkr-sd-n-node = <&wsa_spkr_wcd_sd2>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/pm8005.dtsi b/arch/arm64/boot/dts/qcom/pm8005.dtsi index 4d5aca3eeb69..aff92a8100a2 100644 --- a/arch/arm64/boot/dts/qcom/pm8005.dtsi +++ b/arch/arm64/boot/dts/qcom/pm8005.dtsi @@ -1,33 +1,107 @@ -// SPDX-License-Identifier: (GPL-2.0+ OR MIT) -/* Copyright 2018 Google LLC. */ +/* 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. + */ #include #include &spmi_bus { - pm8005_lsid0: pmic@4 { - compatible = "qcom,pm8005", "qcom,spmi-pmic"; + qcom,pm8005@4 { + compatible = "qcom,spmi-pmic"; reg = <0x4 SPMI_USID>; - #address-cells = <1>; + #address-cells = <2>; #size-cells = <0>; - pm8005_gpio: gpios@c000 { - compatible = "qcom,pm8005-gpio", "qcom,spmi-gpio"; - reg = <0xc000>; + pm8005_revid: qcom,revid@100 { + compatible = "qcom,qpnp-revid"; + reg = <0x100 0x100>; + }; + + pm8005_tz: qcom,temp-alarm@2400 { + compatible = "qcom,qpnp-temp-alarm"; + reg = <0x2400 0x100>; + interrupts = <0x4 0x24 0x0 IRQ_TYPE_EDGE_RISING>; + label = "pm8005_tz"; + #thermal-sensor-cells = <0>; + }; + + pm8005_gpios: pinctrl@c000 { + compatible = "qcom,spmi-gpio"; + reg = <0xc000 0x400>; + interrupts = <0x4 0xc0 0 IRQ_TYPE_NONE>, + <0x4 0xc1 0 IRQ_TYPE_NONE>; + interrupt-names = "pm8005_gpio1", "pm8005_gpio2"; gpio-controller; #gpio-cells = <2>; - interrupts = <0 0xc0 0 IRQ_TYPE_NONE>, - <0 0xc1 0 IRQ_TYPE_NONE>, - <0 0xc2 0 IRQ_TYPE_NONE>, - <0 0xc3 0 IRQ_TYPE_NONE>; + qcom,gpios-disallowed = <3 4>; }; - }; - pm8005_lsid1: pmic@5 { - compatible = "qcom,pm8005", "qcom,spmi-pmic"; + qcom,pm8005@5 { + compatible ="qcom,spmi-pmic"; reg = <0x5 SPMI_USID>; - #address-cells = <1>; + #address-cells = <2>; #size-cells = <0>; + + regulator@1400 { + compatible = "qcom,qpnp-regulator"; + reg = <0x1400 0x100>; + regulator-name = "pm8005_s1"; + status = "disabled"; + }; + + regulator@1700 { + compatible = "qcom,qpnp-regulator"; + reg = <0x1700 0x100>; + regulator-name = "pm8005_s2"; + status = "disabled"; + }; + + regulator@1a00 { + compatible = "qcom,qpnp-regulator"; + reg = <0x1a00 0x100>; + regulator-name = "pm8005_s3"; + status = "disabled"; + }; + + regulator@1d00 { + compatible = "qcom,qpnp-regulator"; + reg = <0x1d00 0x100>; + regulator-name = "pm8005_s4"; + status = "disabled"; + }; + }; +}; + +&thermal_zones { + pm8005_tz { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&pm8005_tz>; + trips { + pm8005-trip0 { + temperature = <105000>; + hysteresis = <0>; + type = "passive"; + }; + pm8005-trip1 { + temperature = <125000>; + hysteresis = <0>; + type = "passive"; + }; + pm8005-trip2 { + temperature = <145000>; + hysteresis = <0>; + type = "passive"; + }; + }; }; }; diff --git a/arch/arm64/boot/dts/qcom/pm8998.dtsi b/arch/arm64/boot/dts/qcom/pm8998.dtsi index 92bed1e7d4bb..0d5129be09b4 100644 --- a/arch/arm64/boot/dts/qcom/pm8998.dtsi +++ b/arch/arm64/boot/dts/qcom/pm8998.dtsi @@ -1,55 +1,256 @@ -// SPDX-License-Identifier: (GPL-2.0+ OR MIT) -/* Copyright 2018 Google LLC. */ +/* Copyright (c) 2016-2017, 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. + */ #include #include +#include &spmi_bus { - pm8998_lsid0: pmic@0 { - compatible = "qcom,pm8998", "qcom,spmi-pmic"; + qcom,pm8998@0 { + compatible = "qcom,spmi-pmic"; reg = <0x0 SPMI_USID>; - #address-cells = <1>; + #address-cells = <2>; #size-cells = <0>; - pm8998_gpio: gpios@c000 { - compatible = "qcom,pm8998-gpio", "qcom,spmi-gpio"; - reg = <0xc000>; + pm8998_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_NONE>, + <0x0 0x8 0x1 IRQ_TYPE_NONE>, + <0x0 0x8 0x4 IRQ_TYPE_NONE>, + <0x0 0x8 0x5 IRQ_TYPE_NONE>; + interrupt-names = "kpdpwr", "resin", + "resin-bark", "kpdpwr-resin-bark"; + qcom,pon-dbc-delay = <15625>; + qcom,kpdpwr-sw-debounce; + qcom,system-reset; + qcom,store-hard-reset-reason; + + qcom,pon_1 { + qcom,pon-type = <0>; + qcom,pull-up = <1>; + linux,code = <116>; + }; + + qcom,pon_2 { + qcom,pon-type = <1>; + qcom,pull-up = <1>; + linux,code = <114>; + }; + + qcom,pon_3 { + qcom,pon-type = <3>; + qcom,support-reset = <1>; + qcom,pull-up = <1>; + qcom,s1-timer = <6720>; + qcom,s2-timer = <2000>; + qcom,s2-type = ; + qcom,use-bark; + }; + }; + + pm8998_tz: qcom,temp-alarm@2400 { + compatible = "qcom,qpnp-temp-alarm"; + reg = <0x2400 0x100>; + interrupts = <0x0 0x24 0x0 IRQ_TYPE_EDGE_RISING>; + label = "pm8998_tz"; + qcom,channel-num = <6>; + qcom,temp_alarm-vadc = <&pm8998_vadc>; + #thermal-sensor-cells = <0>; + }; + + pm8998_gpios: pinctrl@c000 { + compatible = "qcom,spmi-gpio"; + reg = <0xc000 0x1a00>; + interrupts = <0x0 0xc0 0 IRQ_TYPE_NONE>, + <0x0 0xc1 0 IRQ_TYPE_NONE>, + <0x0 0xc3 0 IRQ_TYPE_NONE>, + <0x0 0xc4 0 IRQ_TYPE_NONE>, + <0x0 0xc5 0 IRQ_TYPE_NONE>, + <0x0 0xc6 0 IRQ_TYPE_NONE>, + <0x0 0xc7 0 IRQ_TYPE_NONE>, + <0x0 0xc8 0 IRQ_TYPE_NONE>, + <0x0 0xc9 0 IRQ_TYPE_NONE>, + <0x0 0xca 0 IRQ_TYPE_NONE>, + <0x0 0xcb 0 IRQ_TYPE_NONE>, + <0x0 0xcc 0 IRQ_TYPE_NONE>, + <0x0 0xcd 0 IRQ_TYPE_NONE>, + <0x0 0xcf 0 IRQ_TYPE_NONE>, + <0x0 0xd0 0 IRQ_TYPE_NONE>, + <0x0 0xd1 0 IRQ_TYPE_NONE>, + <0x0 0xd2 0 IRQ_TYPE_NONE>, + <0x0 0xd4 0 IRQ_TYPE_NONE>, + <0x0 0xd6 0 IRQ_TYPE_NONE>; + interrupt-names = "pm8998_gpio1", "pm8998_gpio2", + "pm8998_gpio4", "pm8998_gpio5", + "pm8998_gpio6", "pm8998_gpio7", + "pm8998_gpio8", "pm8998_gpio9", + "pm8998_gpio10", "pm8998_gpio11", + "pm8998_gpio12", "pm8998_gpio13", + "pm8998_gpio14", "pm8998_gpio16", + "pm8998_gpio17", "pm8998_gpio18", + "pm8998_gpio19", "pm8998_gpio21", + "pm8998_gpio23"; gpio-controller; #gpio-cells = <2>; - interrupts = <0 0xc0 0 IRQ_TYPE_NONE>, - <0 0xc1 0 IRQ_TYPE_NONE>, - <0 0xc2 0 IRQ_TYPE_NONE>, - <0 0xc3 0 IRQ_TYPE_NONE>, - <0 0xc4 0 IRQ_TYPE_NONE>, - <0 0xc5 0 IRQ_TYPE_NONE>, - <0 0xc6 0 IRQ_TYPE_NONE>, - <0 0xc7 0 IRQ_TYPE_NONE>, - <0 0xc8 0 IRQ_TYPE_NONE>, - <0 0xc9 0 IRQ_TYPE_NONE>, - <0 0xca 0 IRQ_TYPE_NONE>, - <0 0xcb 0 IRQ_TYPE_NONE>, - <0 0xcc 0 IRQ_TYPE_NONE>, - <0 0xcd 0 IRQ_TYPE_NONE>, - <0 0xce 0 IRQ_TYPE_NONE>, - <0 0xcf 0 IRQ_TYPE_NONE>, - <0 0xd0 0 IRQ_TYPE_NONE>, - <0 0xd1 0 IRQ_TYPE_NONE>, - <0 0xd2 0 IRQ_TYPE_NONE>, - <0 0xd3 0 IRQ_TYPE_NONE>, - <0 0xd4 0 IRQ_TYPE_NONE>, - <0 0xd5 0 IRQ_TYPE_NONE>, - <0 0xd6 0 IRQ_TYPE_NONE>, - <0 0xd7 0 IRQ_TYPE_NONE>, - <0 0xd8 0 IRQ_TYPE_NONE>, - <0 0xd9 0 IRQ_TYPE_NONE>; + qcom,gpios-disallowed = <3 15 20 22 24 25 26>; + }; + + pm8998_coincell: qcom,coincell@2800 { + compatible = "qcom,qpnp-coincell"; + reg = <0x2800 0x100>; + }; + + pm8998_rtc: qcom,pm8998_rtc { + compatible = "qcom,qpnp-rtc"; + #address-cells = <1>; + #size-cells = <1>; + qcom,qpnp-rtc-write = <0>; + qcom,qpnp-rtc-alarm-pwrup = <0>; + + qcom,pm8998_rtc_rw@6000 { + reg = <0x6000 0x100>; + }; + qcom,pm8998_rtc_alarm@6100 { + reg = <0x6100 0x100>; + interrupts = <0x0 0x61 0x1 IRQ_TYPE_NONE>; + }; }; + pm8998_vadc: vadc@3100 { + compatible = "qcom,qpnp-vadc-hc"; + 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>; + + chan@6 { + label = "die_temp"; + reg = <6>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <3>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + qcom,cal-val = <0>; + }; + + chan@0 { + label = "ref_gnd"; + reg = <0>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + qcom,cal-val = <0>; + }; + + chan@1 { + label = "ref_1250v"; + reg = <1>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + qcom,cal-val = <0>; + }; + }; + + pm8998_adc_tm: vadc@3400 { + compatible = "qcom,qpnp-adc-tm-hc"; + reg = <0x3400 0x100>; + #address-cells = <1>; + #size-cells = <0>; + interrupts = <0x0 0x34 0x0 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "eoc-int-en-set"; + qcom,adc-vdd-reference = <1875>; + qcom,adc_tm-vadc = <&pm8998_vadc>; + qcom,decimation = <0>; + qcom,fast-avg-setup = <0>; + #thermal-sensor-cells = <1>; + }; + + pm8998_div_clk1: qcom,clkdiv@5b00 { + compatible = "qcom,qpnp-clkdiv"; + reg = <0x5b00 0x100>; + #clock-cells = <1>; + qcom,cxo-freq = <19200000>; + qcom,clkdiv-id = <1>; + qcom,clkdiv-init-freq = <19200000>; + }; + + pm8998_div_clk2: qcom,clkdiv@5c00 { + compatible = "qcom,qpnp-clkdiv"; + reg = <0x5c00 0x100>; + #clock-cells = <1>; + qcom,cxo-freq = <19200000>; + qcom,clkdiv-id = <2>; + qcom,clkdiv-init-freq = <19200000>; + }; + + pm8998_div_clk3: qcom,clkdiv@5d00 { + compatible = "qcom,qpnp-clkdiv"; + reg = <0x5d00 0x100>; + #clock-cells = <1>; + qcom,cxo-freq = <19200000>; + qcom,clkdiv-id = <3>; + qcom,clkdiv-init-freq = <19200000>; + }; }; - pm8998_lsid1: pmic@1 { - compatible = "qcom,pm8998", "qcom,spmi-pmic"; + qcom,pm8998@1 { + compatible ="qcom,spmi-pmic"; reg = <0x1 SPMI_USID>; - #address-cells = <1>; + #address-cells = <2>; #size-cells = <0>; }; }; + +&thermal_zones { + pm8998_temp_alarm: pm8998_tz { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&pm8998_tz>; + wake-capable-sensor; + + trips { + pm8998_trip0: pm8998-trip0 { + temperature = <105000>; + hysteresis = <0>; + type = "passive"; + }; + pm8998_trip1: pm8998-trip1 { + temperature = <125000>; + hysteresis = <0>; + type = "passive"; + }; + pm8998_trip2: pm8998-trip2 { + temperature = <145000>; + hysteresis = <0>; + type = "passive"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/pmi8998.dtsi b/arch/arm64/boot/dts/qcom/pmi8998.dtsi new file mode 100644 index 000000000000..30ee2cbde504 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/pmi8998.dtsi @@ -0,0 +1,898 @@ +/* Copyright (c) 2016-2017, 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. + */ + +#include +#include +#include + +&spmi_bus { + pmi8998_lsid0: qcom,pmi8998@2 { + compatible = "qcom,spmi-pmic"; + reg = <0x2 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + + pmi8998_revid: qcom,revid@100 { + compatible = "qcom,qpnp-revid"; + reg = <0x100 0x100>; + qcom,fab-id-valid; + }; + + pmi8998_misc: qcom,misc@900 { + compatible = "qcom,qpnp-misc"; + reg = <0x900 0x100>; + }; + + qcom,power-on@800 { + compatible = "qcom,qpnp-power-on"; + reg = <0x800 0x100>; + }; + + pmi8998_tz: qcom,temp-alarm@2400 { + compatible = "qcom,spmi-temp-alarm"; + reg = <0x2400 0x100>; + interrupts = <0x2 0x24 0x0 IRQ_TYPE_EDGE_RISING>; + io-channels = <&pmi8998_rradc 7>; + io-channel-names = "thermal"; + #thermal-sensor-cells = <0>; + }; + + pmi8998_gpios: pinctrl@c000 { + compatible = "qcom,spmi-gpio"; + reg = <0xc000 0xe00>; + interrupts = <0x2 0xc0 0 IRQ_TYPE_NONE>, + <0x2 0xc1 0 IRQ_TYPE_NONE>, + <0x2 0xc2 0 IRQ_TYPE_NONE>, + <0x2 0xc4 0 IRQ_TYPE_NONE>, + <0x2 0xc5 0 IRQ_TYPE_NONE>, + <0x2 0xc7 0 IRQ_TYPE_NONE>, + <0x2 0xc8 0 IRQ_TYPE_NONE>, + <0x2 0xc9 0 IRQ_TYPE_NONE>, + <0x2 0xca 0 IRQ_TYPE_NONE>, + <0x2 0xcb 0 IRQ_TYPE_NONE>, + <0x2 0xcd 0 IRQ_TYPE_NONE>; + interrupt-names = "pmi8998_gpio1", "pmi8998_gpio2", + "pmi8998_gpio3", "pmi8998_gpio5", + "pmi8998_gpio6", "pmi8998_gpio8", + "pmi8998_gpio9", "pmi8998_gpio10", + "pmi8998_gpio11", "pmi8998_gpio12", + "pmi8998_gpio14"; + gpio-controller; + #gpio-cells = <2>; + qcom,gpios-disallowed = <4 7 13>; + }; + + pmi8998_qnovo: qcom,qpnp-qnovo@1500 { + compatible = "qcom,qpnp-qnovo"; + reg = <0x1500 0x100>; + interrupts = <0x2 0x15 0x0 IRQ_TYPE_NONE>; + interrupt-names = "ptrain-done"; + qcom,pmic-revid = <&pmi8998_revid>; + }; + + pmi8998_charger: qcom,qpnp-smb2 { + compatible = "qcom,qpnp-smb2"; + #address-cells = <1>; + #size-cells = <1>; + #cooling-cells = <2>; + + qcom,pmic-revid = <&pmi8998_revid>; + + io-channels = <&pmi8998_rradc 8>, + <&pmi8998_rradc 10>, + <&pmi8998_rradc 3>, + <&pmi8998_rradc 4>; + io-channel-names = "charger_temp", + "charger_temp_max", + "usbin_i", + "usbin_v"; + + qcom,boost-threshold-ua = <100000>; + qcom,wipower-max-uw = <5000000>; + dpdm-supply = <&qusb_phy0>; + + qcom,thermal-mitigation + = <3000000 1500000 1000000 500000>; + qcom,auto-recharge-soc; + qcom,suspend-input-on-debug-batt; + + 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>; + + interrupt-names = "chg-error", + "chg-state-change", + "step-chg-state-change", + "step-chg-soc-update-fail", + "step-chg-soc-update-request"; + }; + + qcom,otg@1100 { + reg = <0x1100 0x100>; + interrupts = <0x2 0x11 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x11 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x11 0x2 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x11 0x3 IRQ_TYPE_EDGE_BOTH>; + + interrupt-names = "otg-fail", + "otg-overcurrent", + "otg-oc-dis-sw-sts", + "testmode-change-detect"; + }; + + qcom,bat-if@1200 { + reg = <0x1200 0x100>; + interrupts = + <0x2 0x12 0x0 IRQ_TYPE_EDGE_RISING>, + <0x2 0x12 0x1 IRQ_TYPE_EDGE_BOTH>, + <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>; + + interrupt-names = "bat-temp", + "bat-ocp", + "bat-ov", + "bat-low", + "bat-therm-or-id-missing", + "bat-terminal-missing"; + }; + + qcom,usb-chgpth@1300 { + reg = <0x1300 0x100>; + interrupts = + <0x2 0x13 0x0 IRQ_TYPE_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_RISING>, + <0x2 0x13 0x6 IRQ_TYPE_EDGE_RISING>, + <0x2 0x13 0x7 IRQ_TYPE_EDGE_RISING>; + + interrupt-names = "usbin-collapse", + "usbin-lt-3p6v", + "usbin-uv", + "usbin-ov", + "usbin-plugin", + "usbin-src-change", + "usbin-icl-change", + "type-c-change"; + }; + + qcom,dc-chgpth@1400 { + reg = <0x1400 0x100>; + interrupts = + <0x2 0x14 0x0 IRQ_TYPE_EDGE_BOTH>, + <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>; + + interrupt-names = "dcin-collapse", + "dcin-lt-3p6v", + "dcin-uv", + "dcin-ov", + "dcin-plugin", + "div2-en-dg", + "dcin-icl-change"; + }; + + qcom,chgr-misc@1600 { + reg = <0x1600 0x100>; + interrupts = + <0x2 0x16 0x0 IRQ_TYPE_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 0x5 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x16 0x6 IRQ_TYPE_EDGE_FALLING>, + <0x2 0x16 0x7 IRQ_TYPE_EDGE_BOTH>; + + interrupt-names = "wdog-snarl", + "wdog-bark", + "aicl-fail", + "aicl-done", + "high-duty-cycle", + "input-current-limiting", + "temperature-change", + "switcher-power-ok"; + }; + }; + + pmi8998_pdphy: qcom,usb-pdphy@1700 { + compatible = "qcom,qpnp-pdphy"; + reg = <0x1700 0x100>; + vdd-pdphy-supply = <&pm8998_l24>; + vbus-supply = <&ext_5v_boost>; + vconn-supply = <&smb2_vconn>; + interrupts = <0x2 0x17 0x0 IRQ_TYPE_EDGE_RISING>, + <0x2 0x17 0x1 IRQ_TYPE_EDGE_RISING>, + <0x2 0x17 0x2 IRQ_TYPE_EDGE_RISING>, + <0x2 0x17 0x3 IRQ_TYPE_EDGE_RISING>, + <0x2 0x17 0x4 IRQ_TYPE_EDGE_RISING>, + <0x2 0x17 0x5 IRQ_TYPE_EDGE_RISING>, + <0x2 0x17 0x6 IRQ_TYPE_EDGE_RISING>; + + interrupt-names = "sig-tx", + "sig-rx", + "msg-tx", + "msg-rx", + "msg-tx-failed", + "msg-tx-discarded", + "msg-rx-discarded"; + + qcom,default-sink-caps = <5000 3000>, /* 5V @ 3A */ + <9000 3000>, /* 9V @ 3A */ + <12000 2250>; /* 12V @ 2.25A */ + }; + + bcl_sensor: bcl@4200 { + compatible = "qcom,msm-bcl-lmh"; + reg = <0x4200 0xff>, + <0x4300 0xff>; + reg-names = "fg_user_adc", + "fg_lmh"; + interrupts = <0x2 0x42 0x0 IRQ_TYPE_NONE>, + <0x2 0x42 0x1 IRQ_TYPE_NONE>, + <0x2 0x42 0x2 IRQ_TYPE_NONE>, + <0x2 0x42 0x3 IRQ_TYPE_NONE>, + <0x2 0x42 0x4 IRQ_TYPE_NONE>; + interrupt-names = "bcl-high-ibat", + "bcl-very-high-ibat", + "bcl-low-vbat", + "bcl-very-low-vbat", + "bcl-crit-low-vbat"; + #thermal-sensor-cells = <1>; + }; + + pmi8998_rradc: rradc@4500 { + compatible = "qcom,rradc"; + reg = <0x4500 0x100>; + #address-cells = <1>; + #size-cells = <0>; + #io-channel-cells = <1>; + qcom,pmic-revid = <&pmi8998_revid>; + }; + + pmi8998_fg: qpnp,fg { + compatible = "qcom,fg-gen3"; + #address-cells = <1>; + #size-cells = <1>; + qcom,pmic-revid = <&pmi8998_revid>; + io-channels = <&pmi8998_rradc 0>; + io-channel-names = "rradc_batt_id"; + qcom,rradc-base = <0x4500>; + qcom,fg-esr-timer-awake = <96 96>; + qcom,fg-esr-timer-asleep = <256 256>; + qcom,fg-esr-timer-charging = <0 96>; + qcom,cycle-counter-en; + qcom,hold-soc-while-full; + qcom,fg-auto-recharge-soc; + qcom,fg-recharge-soc-thr = <98>; + status = "okay"; + + qcom,fg-batt-soc@4000 { + status = "okay"; + reg = <0x4000 0x100>; + interrupts = <0x2 0x40 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x40 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x40 0x2 + IRQ_TYPE_EDGE_RISING>, + <0x2 0x40 0x3 + IRQ_TYPE_EDGE_RISING>, + <0x2 0x40 0x4 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x40 0x5 + IRQ_TYPE_EDGE_RISING>, + <0x2 0x40 0x6 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x40 0x7 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "soc-update", + "soc-ready", + "bsoc-delta", + "msoc-delta", + "msoc-low", + "msoc-empty", + "msoc-high", + "msoc-full"; + }; + + qcom,fg-batt-info@4100 { + status = "okay"; + reg = <0x4100 0x100>; + interrupts = <0x2 0x41 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x41 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x41 0x2 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x41 0x3 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x41 0x6 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "vbatt-pred-delta", + "vbatt-low", + "esr-delta", + "batt-missing", + "batt-temp-delta"; + }; + + qcom,fg-memif@4400 { + status = "okay"; + reg = <0x4400 0x100>; + interrupts = <0x2 0x44 0x0 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x44 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x2 0x44 0x2 + IRQ_TYPE_EDGE_RISING>; + interrupt-names = "ima-rdy", + "mem-xcp", + "dma-grant"; + }; + }; + }; + + pmi8998_lsid1: qcom,pmi8998@3 { + compatible ="qcom,spmi-pmic"; + reg = <0x3 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + + pmi8998_pwm_1: pwm@b100 { + compatible = "qcom,qpnp-pwm"; + reg = <0xb100 0x100>, + <0xb042 0x7e>; + reg-names = "qpnp-lpg-channel-base", + "qpnp-lpg-lut-base"; + qcom,lpg-lut-size = <0x7e>; + qcom,channel-id = <1>; + qcom,supported-sizes = <6>, <9>; + qcom,ramp-index = <0>; + #pwm-cells = <2>; + status = "disabled"; + }; + + pmi8998_pwm_2: pwm@b200 { + compatible = "qcom,qpnp-pwm"; + reg = <0xb200 0x100>, + <0xb042 0x7e>; + reg-names = "qpnp-lpg-channel-base", + "qpnp-lpg-lut-base"; + qcom,lpg-lut-size = <0x7e>; + qcom,channel-id = <2>; + qcom,supported-sizes = <6>, <9>; + qcom,ramp-index = <1>; + #pwm-cells = <2>; + status = "disabled"; + }; + + pmi8998_pwm_3: pwm@b300 { + compatible = "qcom,qpnp-pwm"; + reg = <0xb300 0x100>, + <0xb042 0x7e>; + reg-names = "qpnp-lpg-channel-base", + "qpnp-lpg-lut-base"; + qcom,lpg-lut-size = <0x7e>; + qcom,channel-id = <3>; + qcom,supported-sizes = <6>, <9>; + qcom,ramp-index = <2>; + #pwm-cells = <2>; + }; + + pmi8998_pwm_4: pwm@b400 { + compatible = "qcom,qpnp-pwm"; + reg = <0xb400 0x100>, + <0xb042 0x7e>; + reg-names = "qpnp-lpg-channel-base", + "qpnp-lpg-lut-base"; + qcom,lpg-lut-size = <0x7e>; + qcom,channel-id = <4>; + qcom,supported-sizes = <6>, <9>; + qcom,ramp-index = <3>; + #pwm-cells = <2>; + }; + + pmi8998_pwm_5: pwm@b500 { + compatible = "qcom,qpnp-pwm"; + reg = <0xb500 0x100>, + <0xb042 0x7e>; + reg-names = "qpnp-lpg-channel-base", + "qpnp-lpg-lut-base"; + qcom,lpg-lut-size = <0x7e>; + qcom,channel-id = <5>; + qcom,supported-sizes = <6>, <9>; + qcom,ramp-index = <4>; + #pwm-cells = <2>; + }; + + pmi8998_pwm_6: pwm@b600 { + compatible = "qcom,qpnp-pwm"; + reg = <0xb600 0x100>, + <0xb042 0x7e>; + reg-names = "qpnp-lpg-channel-base", + "qpnp-lpg-lut-base"; + qcom,lpg-lut-size = <0x7e>; + qcom,channel-id = <6>; + qcom,supported-sizes = <6>, <9>; + qcom,ramp-index = <5>; + #pwm-cells = <2>; + status = "disabled"; + }; + + qcom,leds@d000 { + compatible = "qcom,leds-qpnp"; + reg = <0xd000 0x100>; + label = "rgb"; + status = "okay"; + + red_led: qcom,rgb_0 { + label = "rgb"; + qcom,id = <3>; + qcom,mode = "pwm"; + pwms = <&pmi8998_pwm_5 0 0>; + qcom,pwm-us = <1000>; + qcom,max-current = <12>; + qcom,default-state = "off"; + linux,name = "red"; + }; + + green_led: qcom,rgb_1 { + label = "rgb"; + qcom,id = <4>; + qcom,mode = "pwm"; + pwms = <&pmi8998_pwm_4 0 0>; + qcom,pwm-us = <1000>; + qcom,max-current = <12>; + qcom,default-state = "off"; + linux,name = "green"; + }; + + blue_led: qcom,rgb_2 { + label = "rgb"; + qcom,id = <5>; + qcom,mode = "pwm"; + pwms = <&pmi8998_pwm_3 0 0>; + qcom,pwm-us = <1000>; + qcom,max-current = <12>; + qcom,default-state = "off"; + linux,name = "blue"; + }; + }; + + labibb: qpnp-labibb-regulator { + compatible = "qcom,qpnp-labibb-regulator"; + #address-cells = <1>; + #size-cells = <1>; + qcom,pmic-revid = <&pmi8998_revid>; + status = "disabled"; + + ibb_regulator: qcom,ibb@dc00 { + reg = <0xdc00 0x100>; + reg-names = "ibb_reg"; + regulator-name = "ibb_reg"; + + regulator-min-microvolt = <4600000>; + regulator-max-microvolt = <6000000>; + + interrupts = <0x3 0xdc 0x2 + IRQ_TYPE_EDGE_RISING>; + interrupt-names = "ibb-sc-err"; + + qcom,qpnp-ibb-min-voltage = <1400000>; + qcom,qpnp-ibb-step-size = <100000>; + qcom,qpnp-ibb-slew-rate = <2000000>; + qcom,qpnp-ibb-use-default-voltage; + qcom,qpnp-ibb-init-voltage = <5500000>; + qcom,qpnp-ibb-init-amoled-voltage = <4000000>; + qcom,qpnp-ibb-init-lcd-voltage = <5500000>; + + qcom,qpnp-ibb-soft-start = <1000>; + + qcom,qpnp-ibb-lab-pwrup-delay = <8000>; + qcom,qpnp-ibb-lab-pwrdn-delay = <8000>; + qcom,qpnp-ibb-en-discharge; + + qcom,qpnp-ibb-full-pull-down; + qcom,qpnp-ibb-pull-down-enable; + qcom,qpnp-ibb-switching-clock-frequency = + <1480>; + qcom,qpnp-ibb-limit-maximum-current = <1550>; + qcom,qpnp-ibb-debounce-cycle = <16>; + qcom,qpnp-ibb-limit-max-current-enable; + qcom,qpnp-ibb-ps-enable; + }; + + lab_regulator: qcom,lab@de00 { + reg = <0xde00 0x100>; + reg-names = "lab"; + regulator-name = "lab_reg"; + + regulator-min-microvolt = <4600000>; + regulator-max-microvolt = <6000000>; + + interrupts = <0x3 0xde 0x0 + IRQ_TYPE_EDGE_RISING>, + <0x3 0xde 0x1 + IRQ_TYPE_EDGE_RISING>; + interrupt-names = "lab-vreg-ok", "lab-sc-err"; + + qcom,qpnp-lab-min-voltage = <4600000>; + qcom,qpnp-lab-step-size = <100000>; + qcom,qpnp-lab-slew-rate = <5000>; + qcom,qpnp-lab-use-default-voltage; + qcom,qpnp-lab-init-voltage = <5500000>; + qcom,qpnp-lab-init-amoled-voltage = <4600000>; + qcom,qpnp-lab-init-lcd-voltage = <5500000>; + + qcom,qpnp-lab-soft-start = <800>; + + qcom,qpnp-lab-full-pull-down; + qcom,qpnp-lab-pull-down-enable; + qcom,qpnp-lab-switching-clock-frequency = + <1600>; + qcom,qpnp-lab-limit-maximum-current = <1600>; + qcom,qpnp-lab-limit-max-current-enable; + qcom,qpnp-lab-ps-threshold = <70>; + qcom,qpnp-lab-ps-enable; + qcom,qpnp-lab-nfet-size = <100>; + qcom,qpnp-lab-pfet-size = <100>; + qcom,qpnp-lab-max-precharge-time = <500>; + }; + }; + + pmi8998_wled: qcom,leds@d800 { + compatible = "qcom,qpnp-wled"; + reg = <0xd800 0x100>, + <0xd900 0x100>; + reg-names = "qpnp-wled-ctrl-base", + "qpnp-wled-sink-base"; + interrupts = <0x3 0xd8 0x1 IRQ_TYPE_EDGE_RISING>, + <0x3 0xd8 0x2 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "ovp-irq", "sc-irq"; + linux,name = "wled"; + linux,default-trigger = "bkl-trigger"; + qcom,fdbk-output = "auto"; + qcom,vref-uv = <127500>; + qcom,switch-freq-khz = <800>; + qcom,ovp-mv = <29600>; + qcom,ilim-ma = <970>; + qcom,boost-duty-ns = <26>; + qcom,mod-freq-khz = <9600>; + qcom,dim-mode = "hybrid"; + qcom,hyb-thres = <625>; + qcom,sync-dly-us = <800>; + qcom,fs-curr-ua = <25000>; + qcom,cons-sync-write-delay-us = <1000>; + qcom,led-strings-list = [00 01 02 03]; + qcom,en-ext-pfet-sc-pro; + qcom,pmic-revid = <&pmi8998_revid>; + qcom,loop-auto-gm-en; + qcom,auto-calibration-enable; + status = "disabled"; + }; + + 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,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 = <&pmi8998_revid>; + + pmi8998_flash0: qcom,flash_0 { + label = "flash"; + qcom,led-name = "led:flash_0"; + qcom,max-current = <1500>; + qcom,default-led-trigger = "flash0_trigger"; + qcom,id = <0>; + qcom,current-ma = <1000>; + qcom,duration-ms = <1280>; + qcom,ires-ua = <12500>; + qcom,hdrm-voltage-mv = <325>; + qcom,hdrm-vol-hi-lo-win-mv = <100>; + }; + + pmi8998_flash1: qcom,flash_1 { + label = "flash"; + qcom,led-name = "led:flash_1"; + qcom,max-current = <1500>; + qcom,default-led-trigger = "flash1_trigger"; + qcom,id = <1>; + qcom,current-ma = <1000>; + qcom,duration-ms = <1280>; + qcom,ires-ua = <12500>; + qcom,hdrm-voltage-mv = <325>; + qcom,hdrm-vol-hi-lo-win-mv = <100>; + }; + + pmi8998_flash2: qcom,flash_2 { + label = "flash"; + qcom,led-name = "led:flash_2"; + qcom,max-current = <750>; + qcom,default-led-trigger = "flash2_trigger"; + qcom,id = <2>; + qcom,current-ma = <500>; + qcom,duration-ms = <1280>; + qcom,ires-ua = <12500>; + qcom,hdrm-voltage-mv = <325>; + qcom,hdrm-vol-hi-lo-win-mv = <100>; + }; + + pmi8998_torch0: qcom,torch_0 { + label = "torch"; + qcom,led-name = "led:torch_0"; + qcom,max-current = <500>; + qcom,default-led-trigger = "torch0_trigger"; + qcom,id = <0>; + qcom,current-ma = <300>; + qcom,ires-ua = <12500>; + qcom,hdrm-voltage-mv = <325>; + qcom,hdrm-vol-hi-lo-win-mv = <100>; + }; + + pmi8998_torch1: qcom,torch_1 { + label = "torch"; + qcom,led-name = "led:torch_1"; + qcom,max-current = <500>; + qcom,default-led-trigger = "torch1_trigger"; + qcom,id = <1>; + qcom,current-ma = <300>; + qcom,ires-ua = <12500>; + qcom,hdrm-voltage-mv = <325>; + qcom,hdrm-vol-hi-lo-win-mv = <100>; + }; + + pmi8998_torch2: qcom,torch_2 { + label = "torch"; + qcom,led-name = "led:torch_2"; + qcom,max-current = <500>; + qcom,default-led-trigger = "torch2_trigger"; + qcom,id = <2>; + qcom,current-ma = <300>; + qcom,ires-ua = <12500>; + qcom,hdrm-voltage-mv = <325>; + qcom,hdrm-vol-hi-lo-win-mv = <100>; + }; + + pmi8998_switch0: qcom,led_switch_0 { + label = "switch"; + qcom,led-name = "led:switch_0"; + qcom,led-mask = <3>; + qcom,default-led-trigger = "switch0_trigger"; + }; + + pmi8998_switch1: qcom,led_switch_1 { + label = "switch"; + qcom,led-name = "led:switch_1"; + qcom,led-mask = <4>; + qcom,default-led-trigger = "switch1_trigger"; + }; + + pmi8998_switch2: qcom,led_switch_2 { + label = "switch"; + qcom,led-name = "led:switch_2"; + qcom,led-mask = <4>; + qcom,default-led-trigger = "switch2_trigger"; + }; + + }; + + pmi8998_haptics: qcom,haptics@c000 { + compatible = "qcom,qpnp-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,pmic-revid = <&pmi8998_revid>; + qcom,pmic-misc = <&pmi8998_misc>; + qcom,misc-clk-trim-error-reg = <0xf3>; + qcom,actuator-type = <0>; + qcom,play-mode = "direct"; + qcom,vmax-mv = <3200>; + qcom,ilim-ma = <800>; + qcom,sc-dbc-cycles = <8>; + qcom,wave-play-rate-us = <6667>; + qcom,en-brake; + qcom,lra-high-z = "opt1"; + qcom,lra-auto-res-mode = "qwd"; + qcom,lra-res-cal-period = <4>; + status = "disabled"; + }; + }; +}; + +&thermal_zones { + ibat-high { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&bcl_sensor 0>; + wake-capable-sensor; + + trips { + ibat_high: low-ibat { + temperature = <5000>; + hysteresis = <200>; + type = "passive"; + }; + }; + }; + ibat-vhigh { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "step_wise"; + thermal-sensors = <&bcl_sensor 1>; + wake-capable-sensor; + + trips { + ibat_vhigh: ibat_vhigh { + temperature = <6000>; + hysteresis = <100>; + type = "passive"; + }; + }; + }; + vbat { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-governor = "low_limits_cap"; + thermal-sensors = <&bcl_sensor 2>; + wake-capable-sensor; + tracks-low; + + trips { + low_vbat: low-vbat { + temperature = <3200>; + hysteresis = <100>; + type = "passive"; + }; + }; + cooling-maps { + vbat_cpu4 { + trip = <&low_vbat>; + cooling-device = + <&CPU4 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + vbat_cpu5 { + trip = <&low_vbat>; + cooling-device = + <&CPU5 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + vbat_map6 { + trip = <&low_vbat>; + cooling-device = + <&CPU6 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + vbat_map7 { + trip = <&low_vbat>; + cooling-device = + <&CPU7 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + vbat_low { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_cap"; + thermal-sensors = <&bcl_sensor 3>; + wake-capable-sensor; + tracks-low; + + trips { + low-vbat { + temperature = <2800>; + hysteresis = <0>; + type = "passive"; + }; + }; + }; + vbat_too_low { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_cap"; + thermal-sensors = <&bcl_sensor 4>; + wake-capable-sensor; + tracks-low; + + trips { + low-vbat { + temperature = <2600>; + hysteresis = <0>; + type = "passive"; + }; + }; + }; + soc { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-governor = "low_limits_cap"; + thermal-sensors = <&bcl_sensor 5>; + wake-capable-sensor; + tracks-low; + + trips { + low_soc: low-soc { + temperature = <10>; + hysteresis = <0>; + type = "passive"; + }; + }; + cooling-maps { + soc_cpu4 { + trip = <&low_soc>; + cooling-device = + <&CPU4 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + soc_cpu5 { + trip = <&low_soc>; + cooling-device = + <&CPU5 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + soc_map6 { + trip = <&low_soc>; + cooling-device = + <&CPU6 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + soc_map7 { + trip = <&low_soc>; + cooling-device = + <&CPU7 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + pmi8998_tz { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&pmi8998_tz>; + wake-capable-sensor; + + trips { + pmi8998_trip0: pmi8998-trip0 { + temperature = <105000>; + hysteresis = <0>; + type = "passive"; + }; + pmi8998_trip1: pmi8998-trip1 { + temperature = <125000>; + hysteresis = <0>; + type = "passive"; + }; + pmi8998_trip2: pmi8998-trip2 { + temperature = <145000>; + hysteresis = <0>; + type = "passive"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi new file mode 100644 index 000000000000..aff49d7e4197 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi @@ -0,0 +1,608 @@ +/* + * Copyright (c) 2016-2018, 2020, 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 + +&soc { + /* Primary USB port related DWC3 controller */ + usb0: ssusb@a600000 { + compatible = "qcom,dwc-usb3-msm"; + reg = <0x0a600000 0xf8c00>, + <0x088ee000 0x400>; + reg-names = "core_base", "ahb2phy_base"; + iommus = <&apps_smmu 0x740 0x0>; + qcom,smmu-s1-bypass; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + interrupts = <0 489 0>, <0 130 0>, <0 486 0>, <0 488 0>; + interrupt-names = "dp_hs_phy_irq", "pwr_event_irq", + "ss_phy_irq", "dm_hs_phy_irq"; + + USB3_GDSC-supply = <&usb30_prim_gdsc>; + qcom,usb-dbm = <&dbm_1p5>; + qcom,dwc-usb3-msm-tx-fifo-size = <21288>; + qcom,num-gsi-evt-buffs = <0x3>; + qcom,use-pdc-interrupts; + qcom,pm-qos-latency = <44>; + extcon = <0>, <0>, <&eud>, <0>, <0>; + + 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>, + <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>, + <&clock_gcc GCC_USB3_PRIM_CLKREF_CLK>; + + clock-names = "core_clk", "iface_clk", "bus_aggr_clk", + "utmi_clk", "sleep_clk", "cfg_ahb_clk", "xo"; + + qcom,core-clk-rate = <133333333>; + qcom,core-clk-rate-hs = <66666667>; + + resets = <&clock_gcc GCC_USB30_PRIM_BCR>; + reset-names = "core_reset"; + + qcom,msm-bus,name = "usb0"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <3>; + qcom,msm-bus,vectors-KBps = + , + , + , + , + , + ; + + dwc3@a600000 { + compatible = "snps,dwc3"; + reg = <0x0a600000 0xcd00>; + interrupts = <0 133 0>; + usb-phy = <&qusb_phy0>, <&usb_qmp_dp_phy>; + tx-fifo-resize; + 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 = <0>; + }; + + qcom,usbbam@a704000 { + compatible = "qcom,usb-bam-msm"; + reg = <0xa704000 0x17000>; + interrupts = <0 132 0>; + + qcom,bam-type = <0>; + qcom,usb-bam-fifo-baseaddr = <0x146bb000>; + qcom,usb-bam-num-pipes = <8>; + qcom,ignore-core-reset-ack; + qcom,disable-clk-gating; + qcom,usb-bam-override-threshold = <0x4001>; + qcom,usb-bam-max-mbps-highspeed = <400>; + qcom,usb-bam-max-mbps-superspeed = <3600>; + qcom,reset-bam-on-connect; + + qcom,pipe0 { + label = "ssusb-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 QUSB2 PHY */ + qusb_phy0: qusb@88e2000 { + compatible = "qcom,qusb2phy-v2"; + reg = <0x088e2000 0x400>, + <0x007801e8 0x4>, + <0x088e7014 0x4>; + reg-names = "qusb_phy_base", "efuse_addr", + "refgen_north_bg_reg_addr"; + + qcom,efuse-bit-pos = <25>; + qcom,efuse-num-bits = <3>; + vdd-supply = <&pm8998_l1>; + vdda18-supply = <&pm8998_l12>; + vdda33-supply = <&pm8998_l24>; + qcom,override-bias-ctrl2; + qcom,vdd-voltage-level = <0 880000 880000>; + qcom,qusb-phy-reg-offset = + <0x240 /* QUSB2PHY_PORT_TUNE1 */ + 0x1a0 /* QUSB2PHY_PLL_COMMON_STATUS_ONE */ + 0x210 /* QUSB2PHY_PWR_CTRL1 */ + 0x230 /* QUSB2PHY_INTR_CTRL */ + 0x0a8 /* QUSB2PHY_PLL_CORE_INPUT_OVERRIDE */ + 0x254 /* QUSB2PHY_TEST1 */ + 0x198 /* PLL_BIAS_CONTROL_2 */ + 0x228 /* QUSB2PHY_SQ_CTRL1 */ + 0x22c /* QUSB2PHY_SQ_CTRL2 */ + 0x27c /* QUSB2PHY_DEBUG_CTRL1 */ + 0x280 /* QUSB2PHY_DEBUG_CTRL2 */ + 0x284 /* QUSB2PHY_DEBUG_CTRL3 */ + 0x288 /* QUSB2PHY_DEBUG_CTRL4 */ + 0x2a0>; /* QUSB2PHY_STAT5 */ + + qcom,qusb-phy-init-seq = + /* */ + <0x23 0x210 /* PWR_CTRL1 */ + 0x03 0x04 /* PLL_ANALOG_CONTROLS_TWO */ + 0x7c 0x18c /* PLL_CLOCK_INVERTERS */ + 0x80 0x2c /* PLL_CMODE */ + 0x0a 0x184 /* PLL_LOCK_DELAY */ + 0x19 0xb4 /* PLL_DIGITAL_TIMERS_TWO */ + 0x40 0x194 /* PLL_BIAS_CONTROL_1 */ + 0x20 0x198 /* PLL_BIAS_CONTROL_2 */ + 0x21 0x214 /* PWR_CTRL2 */ + 0x00 0x220 /* IMP_CTRL1 */ + 0x58 0x224 /* IMP_CTRL2 */ + 0x30 0x240 /* TUNE1 */ + 0x29 0x244 /* TUNE2 */ + 0xca 0x248 /* TUNE3 */ + 0x04 0x24c /* TUNE4 */ + 0x03 0x250 /* TUNE5 */ + 0x00 0x23c /* CHG_CTRL2 */ + 0x22 0x210>; /* PWR_CTRL1 */ + + phy_type= "utmi"; + clocks = <&clock_rpmh RPMH_CXO_CLK>, + <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>; + clock-names = "ref_clk_src", "cfg_ahb_clk"; + + resets = <&clock_gcc GCC_QUSB2PHY_PRIM_BCR>; + reset-names = "phy_reset"; + }; + + /* Primary USB port related QMP USB DP Combo PHY */ + usb_qmp_dp_phy: ssphy@88e8000 { + compatible = "qcom,usb-ssphy-qmp-dp-combo"; + reg = <0x88e8000 0x3000>; + reg-names = "qmp_phy_base"; + + vdd-supply = <&pm8998_l1>; + core-supply = <&pm8998_l26>; + qcom,vdd-voltage-level = <0 880000 880000>; + qcom,vbus-valid-override; + qcom,qmp-phy-init-seq = + /* */ + <0x1048 0x07 0x00 /* COM_PLL_IVCO */ + 0x1080 0x14 0x00 /* COM_SYSCLK_EN_SEL */ + 0x1034 0x08 0x00 /* COM_BIAS_EN_CLKBUFLR_EN */ + 0x1138 0x30 0x00 /* COM_CLK_SELECT */ + 0x103c 0x02 0x00 /* COM_SYS_CLK_CTRL */ + 0x108c 0x08 0x00 /* COM_RESETSM_CNTRL2 */ + 0x115c 0x16 0x00 /* COM_CMN_CONFIG */ + 0x1164 0x01 0x00 /* COM_SVS_MODE_CLK_SEL */ + 0x113c 0x80 0x00 /* COM_HSCLK_SEL */ + 0x10b0 0x82 0x00 /* COM_DEC_START_MODE0 */ + 0x10b8 0xab 0x00 /* COM_DIV_FRAC_START1_MODE0 */ + 0x10bc 0xea 0x00 /* COM_DIV_FRAC_START2_MODE0 */ + 0x10c0 0x02 0x00 /* COM_DIV_FRAC_START3_MODE0 */ + 0x1060 0x06 0x00 /* COM_CP_CTRL_MODE0 */ + 0x1068 0x16 0x00 /* COM_PLL_RCTRL_MODE0 */ + 0x1070 0x36 0x00 /* COM_PLL_CCTRL_MODE0 */ + 0x10dc 0x00 0x00 /* COM_INTEGLOOP_GAIN1_MODE0 */ + 0x10d8 0x3f 0x00 /* COM_INTEGLOOP_GAIN0_MODE0 */ + 0x10f8 0x01 0x00 /* COM_VCO_TUNE2_MODE0 */ + 0x10f4 0xc9 0x00 /* COM_VCO_TUNE1_MODE0 */ + 0x1148 0x0a 0x00 /* COM_CORECLK_DIV_MODE0 */ + 0x10a0 0x00 0x00 /* COM_LOCK_CMP3_MODE0 */ + 0x109c 0x34 0x00 /* COM_LOCK_CMP2_MODE0 */ + 0x1098 0x15 0x00 /* COM_LOCK_CMP1_MODE0 */ + 0x1090 0x04 0x00 /* COM_LOCK_CMP_EN */ + 0x1154 0x00 0x00 /* COM_CORE_CLK_EN */ + 0x1094 0x00 0x00 /* COM_LOCK_CMP_CFG */ + 0x10f0 0x00 0x00 /* COM_VCO_TUNE_MAP */ + 0x1040 0x0a 0x00 /* COM_SYSCLK_BUF_ENABLE */ + 0x1010 0x01 0x00 /* COM_SSC_EN_CENTER */ + 0x101c 0x31 0x00 /* COM_SSC_PER1 */ + 0x1020 0x01 0x00 /* COM_SSC_PER2 */ + 0x1014 0x00 0x00 /* COM_SSC_ADJ_PER1 */ + 0x1018 0x00 0x00 /* COM_SSC_ADJ_PER2 */ + 0x1024 0x85 0x00 /* COM_SSC_STEP_SIZE1 */ + 0x1028 0x07 0x00 /* COM_SSC_STEP_SIZE2 */ + 0x1430 0x0b 0x00 /* RXA_UCDR_FASTLOCK_FO_GAIN */ + 0x14d4 0x0f 0x00 /* RXA_RX_EQU_ADAPTOR_CNTRL2 */ + 0x14d8 0x4e 0x00 /* RXA_RX_EQU_ADAPTOR_CNTRL3 */ + 0x14dc 0x18 0x00 /* RXA_RX_EQU_ADAPTOR_CNTRL4 */ + 0x14f8 0x77 0x00 /* RXA_RX_EQ_OFFSET_ADAPTOR_CNTRL1 */ + 0x14fc 0x80 0x00 /* RXA_RX_OFFSET_ADAPTOR_CNTRL2 */ + 0x1504 0x03 0x00 /* RXA_SIGDET_CNTRL */ + 0x150c 0x16 0x00 /* RXA_SIGDET_DEGLITCH_CNTRL */ + 0x1564 0x05 0x00 /* RXA_RX_MODE_00 */ + 0x14c0 0x03 0x00 /* RXA_VGA_CAL_CNTRL2 */ + 0x1830 0x0b 0x00 /* RXB_UCDR_FASTLOCK_FO_GAIN */ + 0x18d4 0x0f 0x00 /* RXB_RX_EQU_ADAPTOR_CNTRL2 */ + 0x18d8 0x4e 0x00 /* RXB_RX_EQU_ADAPTOR_CNTRL3 */ + 0x18dc 0x18 0x00 /* RXB_RX_EQU_ADAPTOR_CNTRL4 */ + 0x18f8 0x77 0x00 /* RXB_RX_EQ_OFFSET_ADAPTOR_CNTRL1 */ + 0x18fc 0x80 0x00 /* RXB_RX_OFFSET_ADAPTOR_CNTRL2 */ + 0x1904 0x03 0x00 /* RXB_SIGDET_CNTRL */ + 0x190c 0x16 0x00 /* RXB_SIGDET_DEGLITCH_CNTRL */ + 0x1964 0x05 0x00 /* RXB_RX_MODE_00 */ + 0x18c0 0x03 0x00 /* RXB_VGA_CAL_CNTRL2 */ + 0x1260 0x10 0x00 /* TXA_HIGHZ_DRVR_EN */ + 0x12a4 0x12 0x00 /* TXA_RCV_DETECT_LVL_2 */ + 0x128c 0x16 0x00 /* TXA_LANE_MODE_1 */ + 0x1248 0x09 0x00 /* TXA_RES_CODE_LANE_OFFSET_RX */ + 0x1244 0x06 0x00 /* TXA_RES_CODE_LANE_OFFSET_TX */ + 0x1660 0x10 0x00 /* TXB_HIGHZ_DRVR_EN */ + 0x16a4 0x12 0x00 /* TXB_RCV_DETECT_LVL_2 */ + 0x168c 0x16 0x00 /* TXB_LANE_MODE_1 */ + 0x1648 0x09 0x00 /* TXB_RES_CODE_LANE_OFFSET_RX */ + 0x1644 0x06 0x00 /* TXB_RES_CODE_LANE_OFFSET_TX */ + 0x1cc8 0x83 0x00 /* PCS_FLL_CNTRL2 */ + 0x1ccc 0x09 0x00 /* PCS_FLL_CNT_VAL_L */ + 0x1cd0 0xa2 0x00 /* PCS_FLL_CNT_VAL_H_TOL */ + 0x1cd4 0x40 0x00 /* PCS_FLL_MAN_CODE */ + 0x1cc4 0x02 0x00 /* PCS_FLL_CNTRL1 */ + 0x1c80 0xd1 0x00 /* PCS_LOCK_DETECT_CONFIG1 */ + 0x1c84 0x1f 0x00 /* PCS_LOCK_DETECT_CONFIG2 */ + 0x1c88 0x47 0x00 /* PCS_LOCK_DETECT_CONFIG3 */ + 0x1c64 0x1b 0x00 /* PCS_POWER_STATE_CONFIG2 */ + 0x1434 0x75 0x00 /* RXA_UCDR_SO_SATURATION */ + 0x1834 0x75 0x00 /* RXB_UCDR_SO_SATURATION */ + 0x1dd8 0xba 0x00 /* PCS_RX_SIGDET_LVL */ + 0x1c0c 0x9f 0x00 /* PCS_TXMGN_V0 */ + 0x1c10 0x9f 0x00 /* PCS_TXMGN_V1 */ + 0x1c14 0xb7 0x00 /* PCS_TXMGN_V2 */ + 0x1c18 0x4e 0x00 /* PCS_TXMGN_V3 */ + 0x1c1c 0x65 0x00 /* PCS_TXMGN_V4 */ + 0x1c20 0x6b 0x00 /* PCS_TXMGN_LS */ + 0x1c24 0x15 0x00 /* PCS_TXDEEMPH_M6DB_V0 */ + 0x1c28 0x0d 0x00 /* PCS_TXDEEMPH_M3P5DB_V0 */ + 0x1c2c 0x15 0x00 /* PCS_TXDEEMPH_M6DB_V1 */ + 0x1c30 0x0d 0x00 /* PCS_TXDEEMPH_M3P5DB_V1 */ + 0x1c34 0x15 0x00 /* PCS_TXDEEMPH_M6DB_V2 */ + 0x1c38 0x0d 0x00 /* PCS_TXDEEMPH_M3P5DB_V2 */ + 0x1c3c 0x15 0x00 /* PCS_TXDEEMPH_M6DB_V3 */ + 0x1c40 0x1d 0x00 /* PCS_TXDEEMPH_M3P5DB_V3 */ + 0x1c44 0x15 0x00 /* PCS_TXDEEMPH_M6DB_V4 */ + 0x1c48 0x0d 0x00 /* PCS_TXDEEMPH_M3P5DB_V4 */ + 0x1c4c 0x15 0x00 /* PCS_TXDEEMPH_M6DB_LS */ + 0x1c50 0x0d 0x00 /* PCS_TXDEEMPH_M3P5DB_LS */ + 0x1e0c 0x21 0x00 /* PCS_REFGEN_REQ_CONFIG1 */ + 0x1e10 0x60 0x00 /* PCS_REFGEN_REQ_CONFIG2 */ + 0x1c5c 0x02 0x00 /* PCS_RATE_SLEW_CNTRL */ + 0x1ca0 0x04 0x00 /* PCS_PWRUP_RESET_DLY_TIME_AUXCLK */ + 0x1c8c 0x44 0x00 /* PCS_TSYNC_RSYNC_TIME */ + 0x1c70 0xe7 0x00 /* PCS_RCVR_DTCT_DLY_P1U2_L */ + 0x1c74 0x03 0x00 /* PCS_RCVR_DTCT_DLY_P1U2_H */ + 0x1c78 0x40 0x00 /* PCS_RCVR_DTCT_DLY_U3_L */ + 0x1c7c 0x00 0x00 /* PCS_RCVR_DTCT_DLY_U3_H */ + 0x1cb8 0x75 0x00 /* PCS_RXEQTRAINING_WAIT_TIME */ + 0x1cb0 0x86 0x00 /* PCS_LFPS_TX_ECSTART_EQTLOCK */ + 0x1cbc 0x13 0x00 /* PCS_RXEQTRAINING_RUN_TIME */ + 0x1cac 0x04 0x00 /* PCS_LFPS_DET_HIGH_COUNT_VAL */ + 0xffffffff 0xffffffff 0x00>; + + qcom,qmp-phy-reg-offset = + <0x1d74 /* USB3_DP_PCS_PCS_STATUS */ + 0x1cd8 /* USB3_DP_PCS_AUTONOMOUS_MODE_CTRL */ + 0x1cdc /* USB3_DP_PCS_LFPS_RXTERM_IRQ_CLEAR */ + 0x1c04 /* USB3_DP_PCS_POWER_DOWN_CONTROL */ + 0x1c00 /* USB3_DP_PCS_SW_RESET */ + 0x1c08 /* USB3_DP_PCS_START_CONTROL */ + 0x2a18 /* USB3_DP_DP_PHY_PD_CTL */ + 0x0008 /* USB3_DP_COM_POWER_DOWN_CTRL */ + 0x0004 /* USB3_DP_COM_SW_RESET */ + 0x001c /* USB3_DP_COM_RESET_OVRD_CTRL */ + 0x0000 /* USB3_DP_COM_PHY_MODE_CTRL */ + 0x0010 /* USB3_DP_COM_TYPEC_CTRL */ + 0x000c /* USB3_DP_COM_SWI_CTRL */ + 0x1a0c>; /* USB3_DP_PCS_MISC_CLAMP_ENABLE */ + + clocks = <&clock_gcc GCC_USB3_PRIM_PHY_AUX_CLK>, + <&clock_gcc GCC_USB3_PRIM_PHY_PIPE_CLK>, + <&clock_rpmh RPMH_CXO_CLK>, + <&clock_gcc GCC_USB3_PRIM_CLKREF_CLK>, + <&clock_gcc GCC_USB3_PRIM_PHY_COM_AUX_CLK>, + <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>; + + clock-names = "aux_clk", "pipe_clk", "ref_clk_src", + "ref_clk", "com_aux_clk", "cfg_ahb_clk"; + + resets = <&clock_gcc GCC_USB3_DP_PHY_PRIM_BCR>, + <&clock_gcc GCC_USB3_PHY_PRIM_BCR>; + reset-names = "global_phy_reset", "phy_reset"; + }; + + dbm_1p5: dbm@a6f8000 { + compatible = "qcom,usb-dbm-1p5"; + reg = <0xa6f8000 0x400>; + qcom,reset-ep-after-lpm-resume; + }; + + usb_audio_qmi_dev { + compatible = "qcom,usb-audio-qmi-dev"; + iommus = <&apps_smmu 0x182c 0x0>; + qcom,usb-audio-stream-id = <0xc>; + qcom,usb-audio-intr-num = <2>; + }; + + usb_nop_phy: usb_nop_phy { + compatible = "usb-nop-xceiv"; + }; + + /* Secondary USB port related DWC3 controller */ + usb1: ssusb@a800000 { + compatible = "qcom,dwc-usb3-msm"; + reg = <0x0a800000 0xf8c00>, + <0x088ee000 0x400>; + reg-names = "core_base", "ahb2phy_base"; + iommus = <&apps_smmu 0x760 0x0>; + qcom,smmu-s1-bypass; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + interrupts = <0 491 0>, <0 135 0>, <0 487 0>, <0 490 0>; + interrupt-names = "dp_hs_phy_irq", "pwr_event_irq", + "ss_phy_irq", "dm_hs_phy_irq"; + + USB3_GDSC-supply = <&usb30_sec_gdsc>; + qcom,dwc-usb3-msm-tx-fifo-size = <21288>; + qcom,use-pdc-interrupts; + + 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_USB_PHY_CFG_AHB2PHY_CLK>, + <&clock_gcc GCC_USB3_SEC_CLKREF_CLK>; + + clock-names = "core_clk", "iface_clk", "bus_aggr_clk", + "utmi_clk", "sleep_clk", "cfg_ahb_clk", "xo"; + + qcom,core-clk-rate = <133333333>; + qcom,core-clk-rate-hs = <66666667>; + + resets = <&clock_gcc GCC_USB30_SEC_BCR>; + reset-names = "core_reset"; + status = "disabled"; + + qcom,msm-bus,name = "usb1"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + , + , + , + ; + + dwc3@a800000 { + compatible = "snps,dwc3"; + reg = <0x0a800000 0xcd00>; + interrupts = <0 138 0>; + usb-phy = <&qusb_phy1>, <&usb_qmp_phy>; + tx-fifo-resize; + 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>; + dr_mode = "host"; + }; + }; + + /* Secondary USB port related QUSB2 PHY */ + qusb_phy1: qusb@88e3000 { + compatible = "qcom,qusb2phy-v2"; + reg = <0x088e3000 0x400>, + <0x088e7014 0x4>; + reg-names = "qusb_phy_base", + "refgen_north_bg_reg_addr"; + + vdd-supply = <&pm8998_l1>; + vdda18-supply = <&pm8998_l12>; + vdda33-supply = <&pm8998_l24>; + qcom,override-bias-ctrl2; + qcom,vdd-voltage-level = <0 880000 880000>; + qcom,qusb-phy-reg-offset = + <0x240 /* QUSB2PHY_PORT_TUNE1 */ + 0x1a0 /* QUSB2PHY_PLL_COMMON_STATUS_ONE */ + 0x210 /* QUSB2PHY_PWR_CTRL1 */ + 0x230 /* QUSB2PHY_INTR_CTRL */ + 0x0a8 /* QUSB2PHY_PLL_CORE_INPUT_OVERRIDE */ + 0x254 /* QUSB2PHY_TEST1 */ + 0x198 /* PLL_BIAS_CONTROL_2 */ + 0x228 /* QUSB2PHY_SQ_CTRL1 */ + 0x22c /* QUSB2PHY_SQ_CTRL2 */ + 0x27c /* QUSB2PHY_DEBUG_CTRL1 */ + 0x280 /* QUSB2PHY_DEBUG_CTRL2 */ + 0x2a0>; /* QUSB2PHY_STAT5 */ + + qcom,qusb-phy-init-seq = + /* */ + <0x23 0x210 /* PWR_CTRL1 */ + 0x03 0x04 /* PLL_ANALOG_CONTROLS_TWO */ + 0x7c 0x18c /* PLL_CLOCK_INVERTERS */ + 0x80 0x2c /* PLL_CMODE */ + 0x0a 0x184 /* PLL_LOCK_DELAY */ + 0x19 0xb4 /* PLL_DIGITAL_TIMERS_TWO */ + 0x40 0x194 /* PLL_BIAS_CONTROL_1 */ + 0x20 0x198 /* PLL_BIAS_CONTROL_2 */ + 0x21 0x214 /* PWR_CTRL2 */ + 0x00 0x220 /* IMP_CTRL1 */ + 0x58 0x224 /* IMP_CTRL2 */ + 0x20 0x240 /* TUNE1 */ + 0x29 0x244 /* TUNE2 */ + 0xca 0x248 /* TUNE3 */ + 0x04 0x24c /* TUNE4 */ + 0x03 0x250 /* TUNE5 */ + 0x00 0x23c /* CHG_CTRL2 */ + 0x22 0x210>; /* PWR_CTRL1 */ + + phy_type= "utmi"; + clocks = <&clock_rpmh RPMH_CXO_CLK>, + <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>; + clock-names = "ref_clk_src", "cfg_ahb_clk"; + + resets = <&clock_gcc GCC_QUSB2PHY_SEC_BCR>; + reset-names = "phy_reset"; + status = "disabled"; + }; + + /* Secondary USB port related QMP PHY */ + usb_qmp_phy: ssphy@88eb000 { + compatible = "qcom,usb-ssphy-qmp-v2"; + reg = <0x88eb000 0x1000>, + <0x01fcbff0 0x4>; + reg-names = "qmp_phy_base", + "vls_clamp_reg"; + + vdd-supply = <&pm8998_l1>; + core-supply = <&pm8998_l26>; + qcom,vdd-voltage-level = <0 880000 880000>; + qcom,vbus-valid-override; + qcom,qmp-phy-init-seq = + /* */ + <0x048 0x07 0x00 /* QSERDES_COM_PLL_IVCO */ + 0x080 0x14 0x00 /* QSERDES_COM_SYSCLK_EN_SEL */ + 0x034 0x04 0x00 /* QSERDES_COM_BIAS_EN_CLKBUFLR_EN */ + 0x138 0x30 0x00 /* QSERDES_COM_CLK_SELECT */ + 0x03c 0x02 0x00 /* QSERDES_COM_SYS_CLK_CTRL */ + 0x08c 0x08 0x00 /* QSERDES_COM_RESETSM_CNTRL2 */ + 0x15c 0x06 0x00 /* QSERDES_COM_CMN_CONFIG */ + 0x164 0x01 0x00 /* QSERDES_COM_SVS_MODE_CLK_SEL */ + 0x13c 0x80 0x00 /* QSERDES_COM_HSCLK_SEL */ + 0x0b0 0x82 0x00 /* QSERDES_COM_DEC_START_MODE0 */ + 0x0b8 0xab 0x00 /* QSERDES_COM_DIV_FRAC_START1_MODE0 */ + 0x0bc 0xea 0x00 /* QSERDES_COM_DIV_FRAC_START2_MODE0 */ + 0x0c0 0x02 0x00 /* QSERDES_COM_DIV_FRAC_START3_MODE0 */ + 0x060 0x06 0x00 /* QSERDES_COM_CP_CTRL_MODE0 */ + 0x068 0x16 0x00 /* QSERDES_COM_PLL_RCTRL_MODE0 */ + 0x070 0x36 0x00 /* QSERDES_COM_PLL_CCTRL_MODE0 */ + 0x0dc 0x00 0x00 /* QSERDES_COM_INTEGLOOP_GAIN1_MODE0 */ + 0x0d8 0x3f 0x00 /* QSERDES_COM_INTEGLOOP_GAIN0_MODE0 */ + 0x0f8 0x01 0x00 /* QSERDES_COM_VCO_TUNE2_MODE0 */ + 0x0f4 0xc9 0x00 /* QSERDES_COM_VCO_TUNE1_MODE0 */ + 0x148 0x0a 0x00 /* QSERDES_COM_CORECLK_DIV_MODE0 */ + 0x0a0 0x00 0x00 /* QSERDES_COM_LOCK_CMP3_MODE0 */ + 0x09c 0x34 0x00 /* QSERDES_COM_LOCK_CMP2_MODE0 */ + 0x098 0x15 0x00 /* QSERDES_COM_LOCK_CMP1_MODE0 */ + 0x090 0x04 0x00 /* QSERDES_COM_LOCK_CMP_EN */ + 0x154 0x00 0x00 /* QSERDES_COM_CORE_CLK_EN */ + 0x094 0x00 0x00 /* QSERDES_COM_LOCK_CMP_CFG */ + 0x0f0 0x00 0x00 /* QSERDES_COM_VCO_TUNE_MAP */ + 0x040 0x0a 0x00 /* QSERDES_COM_SYSCLK_BUF_ENABLE */ + 0x0d0 0x80 0x00 /* QSERDES_COM_INTEGLOOP_INITVAL */ + 0x010 0x01 0x00 /* QSERDES_COM_SSC_EN_CENTER */ + 0x01c 0x31 0x00 /* QSERDES_COM_SSC_PER1 */ + 0x020 0x01 0x00 /* QSERDES_COM_SSC_PER2 */ + 0x014 0x00 0x00 /* QSERDES_COM_SSC_ADJ_PER1 */ + 0x018 0x00 0x00 /* QSERDES_COM_SSC_ADJ_PER2 */ + 0x024 0x85 0x00 /* QSERDES_COM_SSC_STEP_SIZE1 */ + 0x028 0x07 0x00 /* QSERDES_COM_SSC_STEP_SIZE2 */ + 0x4c0 0x0c 0x00 /* QSERDES_RX_VGA_CAL_CNTRL2 */ + 0x564 0x50 0x00 /* QSERDES_RX_RX_MODE_00 */ + 0x430 0x0b 0x00 /* QSERDES_RX_UCDR_FASTLOCK_FO_GAIN */ + 0x4d4 0x0e 0x00 /* QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2 */ + 0x4d8 0x4e 0x00 /* QSERDES_RX_RX_EQU_ADAPTOR_CNTRL3 */ + 0x4dc 0x18 0x00 /* QSERDES_RX_RX_EQU_ADAPTOR_CNTRL4 */ + 0x4f8 0x77 0x00 /* RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1 */ + 0x4fc 0x80 0x00 /* RX_RX_OFFSET_ADAPTOR_CNTRL2 */ + 0x504 0x03 0x00 /* QSERDES_RX_SIGDET_CNTRL */ + 0x50c 0x1c 0x00 /* QSERDES_RX_SIGDET_DEGLITCH_CNTRL */ + 0x434 0x75 0x00 /* RX_UCDR_SO_SATURATION_AND_ENABLE */ + 0x444 0x80 0x00 /* QSERDES_RX_UCDR_PI_CONTROLS */ + 0x408 0x0a 0x00 /* QSERDES_RX_UCDR_FO_GAIN */ + 0x40c 0x06 0x00 /* QSERDES_RX_UCDR_SO_GAIN */ + 0x500 0x00 0x00 /* QSERDES_RX_SIGDET_ENABLES */ + 0x260 0x10 0x00 /* QSERDES_TX_HIGHZ_DRVR_EN */ + 0x2a4 0x12 0x00 /* QSERDES_TX_RCV_DETECT_LVL_2 */ + 0x28c 0xc6 0x00 /* QSERDES_TX_LANE_MODE_1 */ + 0x248 0x06 0x00 /* TX_RES_CODE_LANE_OFFSET_RX */ + 0x244 0x06 0x00 /* TX_RES_CODE_LANE_OFFSET_TX */ + 0x8c8 0x83 0x00 /* USB3_UNI_PCS_FLL_CNTRL2 */ + 0x8cc 0x09 0x00 /* USB3_UNI_PCS_FLL_CNT_VAL_L */ + 0x8d0 0xa2 0x00 /* USB3_UNI_PCS_FLL_CNT_VAL_H_TOL */ + 0x8d4 0x40 0x00 /* USB3_UNI_PCS_FLL_MAN_CODE */ + 0x8c4 0x02 0x00 /* USB3_UNI_PCS_FLL_CNTRL1 */ + 0x864 0x1b 0x00 /* USB3_UNI_PCS_POWER_STATE_CONFIG2 */ + 0x80c 0x9f 0x00 /* USB3_UNI_PCS_TXMGN_V0 */ + 0x810 0x9f 0x00 /* USB3_UNI_PCS_TXMGN_V1 */ + 0x814 0xb5 0x00 /* USB3_UNI_PCS_TXMGN_V2 */ + 0x818 0x4c 0x00 /* USB3_UNI_PCS_TXMGN_V3 */ + 0x81c 0x64 0x00 /* USB3_UNI_PCS_TXMGN_V4 */ + 0x820 0x6a 0x00 /* USB3_UNI_PCS_TXMGN_LS */ + 0x824 0x15 0x00 /* USB3_UNI_PCS_TXDEEMPH_M6DB_V0 */ + 0x828 0x0d 0x00 /* USB3_UNI_PCS_TXDEEMPH_M3P5DB_V0 */ + 0x82c 0x15 0x00 /* USB3_UNI_PCS_TXDEEMPH_M6DB_V1 */ + 0x830 0x0d 0x00 /* USB3_UNI_PCS_TXDEEMPH_M3P5DB_V1 */ + 0x834 0x15 0x00 /* USB3_UNI_PCS_TXDEEMPH_M6DB_V2 */ + 0x838 0x0d 0x00 /* USB3_UNI_PCS_TXDEEMPH_M3P5DB_V2 */ + 0x83c 0x15 0x00 /* USB3_UNI_PCS_TXDEEMPH_M6DB_V3 */ + 0x840 0x0d 0x00 /* USB3_UNI_PCS_TXDEEMPH_M3P5DB_V3 */ + 0x844 0x15 0x00 /* USB3_UNI_PCS_TXDEEMPH_M6DB_V4 */ + 0x848 0x0d 0x00 /* USB3_UNI_PCS_TXDEEMPH_M3P5DB_V4 */ + 0x84c 0x15 0x00 /* USB3_UNI_PCS_TXDEEMPH_M6DB_LS */ + 0x850 0x0d 0x00 /* USB3_UNI_PCS_TXDEEMPH_M3P5DB_LS */ + 0x85c 0x02 0x00 /* USB3_UNI_PCS_RATE_SLEW_CNTRL */ + 0x8a0 0x04 0x00 /* PCS_PWRUP_RESET_DLY_TIME_AUXCLK */ + 0x88c 0x44 0x00 /* USB3_UNI_PCS_TSYNC_RSYNC_TIME */ + 0x880 0xd1 0x00 /* USB3_UNI_PCS_LOCK_DETECT_CONFIG1 */ + 0x884 0x1f 0x00 /* USB3_UNI_PCS_LOCK_DETECT_CONFIG2 */ + 0x888 0x47 0x00 /* USB3_UNI_PCS_LOCK_DETECT_CONFIG3 */ + 0x870 0xe7 0x00 /* USB3_UNI_PCS_RCVR_DTCT_DLY_P1U2_L */ + 0x874 0x03 0x00 /* USB3_UNI_PCS_RCVR_DTCT_DLY_P1U2_H */ + 0x878 0x40 0x00 /* USB3_UNI_PCS_RCVR_DTCT_DLY_U3_L */ + 0x87c 0x00 0x00 /* USB3_UNI_PCS_RCVR_DTCT_DLY_U3_H */ + 0x9d8 0xba 0x00 /* USB3_UNI_PCS_RX_SIGDET_LVL */ + 0x8b8 0x75 0x00 /* RXEQTRAINING_WAIT_TIME */ + 0x8b0 0x86 0x00 /* PCS_LFPS_TX_ECSTART_EQTLOCK */ + 0x8bc 0x13 0x00 /* PCS_RXEQTRAINING_RUN_TIME */ + 0xa0c 0x21 0x00 /* USB3_UNI_PCS_REFGEN_REQ_CONFIG1 */ + 0xa10 0x60 0x00 /* USB3_UNI_PCS_REFGEN_REQ_CONFIG2 */ + 0xffffffff 0xffffffff 0x00>; + + qcom,qmp-phy-reg-offset = + <0x974 /* USB3_UNI_PCS_PCS_STATUS */ + 0x8d8 /* USB3_UNI_PCS_AUTONOMOUS_MODE_CTRL */ + 0x8dc /* USB3_UNI_PCS_LFPS_RXTERM_IRQ_CLEAR */ + 0x804 /* USB3_UNI_PCS_POWER_DOWN_CONTROL */ + 0x800 /* USB3_UNI_PCS_SW_RESET */ + 0x808>; /* USB3_UNI_PCS_START_CONTROL */ + + clocks = <&clock_gcc GCC_USB3_SEC_PHY_AUX_CLK>, + <&clock_gcc GCC_USB3_SEC_PHY_PIPE_CLK>, + <&clock_rpmh RPMH_CXO_CLK>, + <&clock_gcc GCC_USB3_SEC_CLKREF_CLK>, + <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>; + + clock-names = "aux_clk", "pipe_clk", "ref_clk_src", + "ref_clk", "cfg_ahb_clk"; + + resets = <&clock_gcc GCC_USB3_PHY_SEC_BCR>, + <&clock_gcc GCC_USB3PHY_PHY_SEC_BCR>; + reset-names = "phy_reset", "phy_phy_reset"; + status = "disabled"; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm845-audio-overlay.dtsi new file mode 100644 index 000000000000..9d485b5dbba0 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-audio-overlay.dtsi @@ -0,0 +1,185 @@ +/* + * Copyright (c) 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. + */ + +#include "sdm845-wcd.dtsi" +#include "msm-wsa881x.dtsi" +#include + +&snd_934x { + qcom,audio-routing = + "AIF4 VI", "MCLK", + "RX_BIAS", "MCLK", + "MADINPUT", "MCLK", + "hifi amp", "LINEOUT1", + "hifi amp", "LINEOUT2", + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Headset Mic", + "AMIC3", "MIC BIAS2", + "MIC BIAS2", "ANCRight Headset Mic", + "AMIC4", "MIC BIAS2", + "MIC BIAS2", "ANCLeft Headset Mic", + "AMIC5", "MIC BIAS3", + "MIC BIAS3", "Handset Mic", + "DMIC0", "MIC BIAS1", + "MIC BIAS1", "Digital Mic0", + "DMIC1", "MIC BIAS1", + "MIC BIAS1", "Digital Mic1", + "DMIC2", "MIC BIAS3", + "MIC BIAS3", "Digital Mic2", + "DMIC3", "MIC BIAS3", + "MIC BIAS3", "Digital Mic3", + "DMIC4", "MIC BIAS4", + "MIC BIAS4", "Digital Mic4", + "DMIC5", "MIC BIAS4", + "MIC BIAS4", "Digital Mic5", + "SpkrLeft IN", "SPK1 OUT", + "SpkrRight IN", "SPK2 OUT"; + + qcom,msm-mbhc-hphl-swh = <1>; + qcom,msm-mbhc-gnd-swh = <1>; + qcom,msm-mbhc-hs-mic-max-threshold-mv = <1700>; + qcom,msm-mbhc-hs-mic-min-threshold-mv = <50>; + qcom,hph-en0-gpio = <&tavil_hph_en0>; + qcom,hph-en1-gpio = <&tavil_hph_en1>; + qcom,tavil-mclk-clk-freq = <9600000>; + + asoc-codec = <&stub_codec>, <&ext_disp_audio_codec>; + asoc-codec-names = "msm-stub-codec.1", + "msm-ext-disp-audio-codec-rx"; + + qcom,usbc-analog-en1-gpio = <&wcd_usbc_analog_en1_gpio>; + qcom,usbc-analog-en2-gpio = <&tlmm 51 0>; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&wcd_usbc_analog_en2_active>; + pinctrl-1 = <&wcd_usbc_analog_en2_idle>; + + 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"; +}; + +&soc { + wcd_usbc_analog_en1_gpio: msm_cdc_pinctrl@49 { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&wcd_usbc_analog_en1_active>; + pinctrl-1 = <&wcd_usbc_analog_en1_idle>; + }; + + wcd9xxx_intc: wcd9xxx-irq { + status = "ok"; + compatible = "qcom,wcd9xxx-irq"; + interrupt-controller; + #interrupt-cells = <1>; + interrupt-parent = <&tlmm>; + qcom,gpio-connect = <&tlmm 54 0>; + pinctrl-names = "default"; + pinctrl-0 = <&wcd_intr_default>; + }; + + clock_audio_lnbb: audio_ext_clk_lnbb { + status = "ok"; + compatible = "qcom,audio-ref-clk"; + clock-names = "osr_clk"; + clocks = <&clock_rpmh RPMH_LN_BB_CLK2>; + qcom,node_has_rpm_clock; + #clock-cells = <1>; + }; + + wcd_rst_gpio: msm_cdc_pinctrl@64 { + compatible = "qcom,msm-cdc-pinctrl"; + qcom,cdc-rst-n-gpio = <&tlmm 64 0>; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&cdc_reset_active>; + pinctrl-1 = <&cdc_reset_sleep>; + }; + + qocm,wcd-dsp-glink { + compatible = "qcom,wcd-dsp-glink"; + }; + + qcom,wcd-dsp-mgr { + compatible = "qcom,wcd-dsp-mgr"; + qcom,wdsp-components = <&wcd934x_cdc 0>, + <&wcd_spi_0 1>, + <&glink_spi_xprt_wdsp 2>; + qcom,img-filename = "cpe_9340"; + }; +}; + +&slim_aud { + wcd934x_cdc: tavil_codec { + compatible = "qcom,tavil-slim-pgd"; + elemental-addr = [00 01 50 02 17 02]; + + interrupt-parent = <&wcd9xxx_intc>; + interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 + 17 18 19 20 21 22 23 24 25 26 27 28 29 + 30 31>; + + qcom,wcd-rst-gpio-node = <&wcd_rst_gpio>; + + clock-names = "wcd_clk"; + clocks = <&clock_audio_lnbb AUDIO_PMIC_LNBB_CLK>; + + cdc-vdd-buck-supply = <&pm8998_s4>; + qcom,cdc-vdd-buck-voltage = <1800000 1800000>; + qcom,cdc-vdd-buck-current = <650000>; + + cdc-buck-sido-supply = <&pm8998_s4>; + qcom,cdc-buck-sido-voltage = <1800000 1800000>; + qcom,cdc-buck-sido-current = <250000>; + + cdc-vdd-tx-h-supply = <&pm8998_s4>; + qcom,cdc-vdd-tx-h-voltage = <1800000 1800000>; + qcom,cdc-vdd-tx-h-current = <25000>; + + cdc-vdd-rx-h-supply = <&pm8998_s4>; + qcom,cdc-vdd-rx-h-voltage = <1800000 1800000>; + qcom,cdc-vdd-rx-h-current = <25000>; + + cdc-vddpx-1-supply = <&pm8998_s4>; + qcom,cdc-vddpx-1-voltage = <1800000 1800000>; + qcom,cdc-vddpx-1-current = <10000>; + + qcom,cdc-static-supplies = "cdc-vdd-buck", + "cdc-buck-sido", + "cdc-vdd-tx-h", + "cdc-vdd-rx-h", + "cdc-vddpx-1"; + + qcom,cdc-micbias1-mv = <1800>; + qcom,cdc-micbias2-mv = <1800>; + qcom,cdc-micbias3-mv = <1800>; + qcom,cdc-micbias4-mv = <1800>; + + qcom,cdc-mclk-clk-rate = <9600000>; + qcom,cdc-slim-ifd = "tavil-slim-ifd"; + qcom,cdc-slim-ifd-elemental-addr = [00 00 50 02 17 02]; + qcom,cdc-dmic-sample-rate = <4800000>; + qcom,cdc-mad-dmic-rate = <600000>; + + qcom,wdsp-cmpnt-dev-name = "tavil_codec"; + + wcd_spi_0: wcd_spi { + compatible = "qcom,wcd-spi-v2"; + qcom,master-bus-num = <0>; + qcom,chip-select = <0>; + qcom,max-frequency = <24000000>; + qcom,mem-base-addr = <0x100000>; + }; + + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi b/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi new file mode 100644 index 000000000000..83be25615415 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2016-2019, 2021, 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 "msm-audio-lpass.dtsi" + +&msm_audio_ion { + iommus = <&apps_smmu 0x1821 0x0>; + qcom,smmu-sid-mask = /bits/ 64 <0xf>; +}; + +&soc { + qcom,avtimer@170f7000 { + compatible = "qcom,avtimer"; + reg = <0x170f700c 0x4>, + <0x170f7010 0x4>; + reg-names = "avtimer_lsb_addr", "avtimer_msb_addr"; + qcom,clk-div = <192>; + qcom,clk-mult = <10>; + }; +}; + +&audio_apr { + snd_934x: sound-tavil { + compatible = "qcom,sdm845-asoc-snd-tavil"; + qcom,model = "sdm845-tavil-snd-card"; + qcom,ext-disp-audio-rx; + qcom,wcn-btfm; + qcom,mi2s-audio-intf; + qcom,auxpcm-audio-intf; + qcom,msm-mi2s-master = <1>, <1>, <1>, <1>; + + 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_hdmi>, <&dai_dp>, + <&dai_mi2s0>, <&dai_mi2s1>, + <&dai_mi2s2>, <&dai_mi2s3>, + <&dai_pri_auxpcm>, <&dai_sec_auxpcm>, + <&dai_tert_auxpcm>, <&dai_quat_auxpcm>, + <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>, + <&sb_2_rx>, <&sb_2_tx>, <&sb_3_rx>, <&sb_3_tx>, + <&sb_4_rx>, <&sb_4_tx>, <&sb_5_tx>, + <&afe_pcm_rx>, <&afe_pcm_tx>, <&afe_proxy_rx>, + <&afe_proxy_tx>, <&incall_record_rx>, + <&incall_record_tx>, <&incall_music_rx>, + <&incall_music_2_rx>, <&sb_5_rx>, <&sb_6_rx>, + <&sb_7_rx>, <&sb_7_tx>, <&sb_8_tx>, + <&usb_audio_rx>, <&usb_audio_tx>, + <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>, + <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>, + <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_tx_0>, + <&dai_quat_tdm_rx_0>, <&dai_quat_tdm_tx_0>, + <&dai_quat_tdm_rx_1>, + <&proxy_rx>, <&proxy_tx>; + asoc-cpu-names = "msm-dai-q6-hdmi.8", "msm-dai-q6-dp.24608", + "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", + "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3", + "msm-dai-q6-auxpcm.1", "msm-dai-q6-auxpcm.2", + "msm-dai-q6-auxpcm.3", "msm-dai-q6-auxpcm.4", + "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385", + "msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387", + "msm-dai-q6-dev.16388", "msm-dai-q6-dev.16389", + "msm-dai-q6-dev.16390", "msm-dai-q6-dev.16391", + "msm-dai-q6-dev.16392", "msm-dai-q6-dev.16393", + "msm-dai-q6-dev.16395", "msm-dai-q6-dev.224", + "msm-dai-q6-dev.225", "msm-dai-q6-dev.241", + "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771", + "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773", + "msm-dai-q6-dev.32770", "msm-dai-q6-dev.16394", + "msm-dai-q6-dev.16396", "msm-dai-q6-dev.16398", + "msm-dai-q6-dev.16399", "msm-dai-q6-dev.16401", + "msm-dai-q6-dev.28672", "msm-dai-q6-dev.28673", + "msm-dai-q6-tdm.36864", "msm-dai-q6-tdm.36865", + "msm-dai-q6-tdm.36880", "msm-dai-q6-tdm.36881", + "msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36897", + "msm-dai-q6-tdm.36912", "msm-dai-q6-tdm.36913", + "msm-dai-q6-tdm.36914", + "msm-dai-q6-dev.8194", "msm-dai-q6-dev.8195"; + }; +}; + +&slim_aud { + msm_dai_slim { + compatible = "qcom,msm-dai-slim"; + elemental-addr = [ff ff ff fe 17 02]; + }; +}; + +&msm_dai_tdm_quat_rx { + qcom,msm-cpudai-tdm-group-num-ports = <2>; + qcom,msm-cpudai-tdm-group-port-id = <36912 36914>; + dai_quat_tdm_rx_1: qcom,msm-dai-q6-tdm-quat-rx-1 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36914>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi b/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi new file mode 100644 index 000000000000..3ce56269be2b --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi @@ -0,0 +1,1984 @@ +/* Copyright (c) 2016-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. + */ + +#include +#include +#include + +&soc { + ad_hoc_bus: ad-hoc-bus { + compatible = "qcom,msm-bus-device"; + reg = <0x016E0000 0x40000>, + <0x1700000 0x40000>, + <0x1500000 0x40000>, + <0x14E0000 0x40000>, + <0x17900000 0x40000>, + <0x1380000 0x40000>, + <0x1380000 0x40000>, + <0x1740000 0x40000>, + <0x1620000 0x40000>, + <0x1620000 0x40000>, + <0x1620000 0x40000>; + + reg-names = "aggre1_noc-base", "aggre2_noc-base", + "config_noc-base", "dc_noc-base", + "gladiator_noc-base", "mc_virt-base", "mem_noc-base", + "mmss_noc-base", "system_noc-base", "ipa_virt-base", + "camnoc_virt-base"; + + mbox-names = "apps_rsc", "disp_rsc"; + mboxes = <&apps_rsc 0 &disp_rsc 0>; + + /*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 = <3>; + }; + + /*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_sh1: bcm-sh1 { + cell-id = ; + label = "SH1"; + qcom,bcm-name = "SH1"; + 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_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_sh5: bcm-sh5 { + cell-id = ; + label = "SH5"; + qcom,bcm-name = "SH5"; + 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_ce0: bcm-ce0 { + cell-id = ; + label = "CE0"; + qcom,bcm-name = "CE0"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_ip0: bcm-ip0 { + cell-id = ; + label = "IP0"; + qcom,bcm-name = "IP0"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_cn0: bcm-cn0 { + cell-id = ; + label = "CN0"; + qcom,bcm-name = "CN0"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_qup0: bcm-qup0 { + cell-id = ; + label = "QUP0"; + qcom,bcm-name = "QUP0"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn1: bcm-sn1 { + cell-id = ; + label = "SN1"; + qcom,bcm-name = "SN1"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn2: bcm-sn2 { + cell-id = ; + label = "SN2"; + qcom,bcm-name = "SN2"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn3: bcm-sn3 { + cell-id = ; + label = "SN3"; + qcom,bcm-name = "SN3"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn4: bcm-sn4 { + cell-id = ; + label = "SN4"; + qcom,bcm-name = "SN4"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn5: bcm-sn5 { + cell-id = ; + label = "SN5"; + qcom,bcm-name = "SN5"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn6: bcm-sn6 { + cell-id = ; + label = "SN6"; + qcom,bcm-name = "SN6"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_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_sn14: bcm-sn14 { + cell-id = ; + label = "SN14"; + qcom,bcm-name = "SN14"; + qcom,rscs = <&rsc_apps>; + qcom,bcm-dev; + }; + + bcm_sn15: bcm-sn15 { + cell-id = ; + label = "SN15"; + qcom,bcm-name = "SN15"; + qcom,rscs = <&rsc_apps>; + 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; + }; + + bcm_mm3_display: bcm-mm3_display { + cell-id = ; + label = "MM3_DISPLAY"; + qcom,bcm-name = "MM3"; + qcom,rscs = <&rsc_disp>; + qcom,bcm-dev; + }; + + /*Buses*/ + fab_aggre1_noc: fab-aggre1_noc { + cell-id = ; + label = "fab-aggre1_noc"; + qcom,fab-dev; + qcom,base-name = "aggre1_noc-base"; + qcom,qos-off = <4096>; + qcom,base-offset = <16384>; + qcom,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 = <16384>; + qcom,bus-type = <1>; + clocks = <>; + }; + + fab_camnoc_virt: fab-camnoc_virt { + cell-id = ; + label = "fab-camnoc_virt"; + qcom,fab-dev; + qcom,base-name = "camnoc_virt-base"; + qcom,bypass-qos-prg; + clocks = <>; + }; + + 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>; + clocks = <>; + }; + + fab_dc_noc: fab-dc_noc { + cell-id = ; + label = "fab-dc_noc"; + qcom,fab-dev; + qcom,base-name = "dc_noc-base"; + qcom,bypass-qos-prg; + qcom,bus-type = <1>; + clocks = <>; + }; + + fab_gladiator_noc: fab-gladiator_noc { + cell-id = ; + label = "fab-gladiator_noc"; + qcom,fab-dev; + qcom,base-name = "gladiator_noc-base"; + qcom,bypass-qos-prg; + 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,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,bypass-qos-prg; + clocks = <>; + }; + + fab_mem_noc: fab-mem_noc { + cell-id = ; + label = "fab-mem_noc"; + qcom,fab-dev; + qcom,base-name = "mem_noc-base"; + qcom,qos-off = <4096>; + qcom,base-offset = <65536>; + qcom,bus-type = <1>; + clocks = <>; + }; + + fab_mmss_noc: fab-mmss_noc { + cell-id = ; + label = "fab-mmss_noc"; + qcom,fab-dev; + qcom,base-name = "mmss_noc-base"; + qcom,qos-off = <4096>; + qcom,base-offset = <36864>; + qcom,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 = <36864>; + 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,bypass-qos-prg; + clocks = <>; + }; + + fab_mem_noc_display: fab-mem_noc_display { + cell-id = ; + label = "fab-mem_noc_display"; + qcom,fab-dev; + qcom,base-name = "mem_noc-base"; + qcom,qos-off = <4096>; + qcom,base-offset = <65536>; + qcom,bypass-qos-prg; + qcom,bus-type = <1>; + clocks = <>; + }; + + fab_mmss_noc_display: fab-mmss_noc_display { + cell-id = ; + label = "fab-mmss_noc_display"; + qcom,fab-dev; + qcom,base-name = "mmss_noc-base"; + qcom,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_qup1: mas-qhm-qup1 { + cell-id = ; + label = "mas-qhm-qup1"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qns_a1noc_snoc>; + qcom,bus-dev = <&fab_aggre1_noc>; + qcom,bcms = <&bcm_qup0>; + }; + + mas_qhm_tsif: mas-qhm-tsif { + cell-id = ; + label = "mas-qhm-tsif"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qns_a1noc_snoc>; + qcom,bus-dev = <&fab_aggre1_noc>; + }; + + mas_xm_sdc2: mas-xm-sdc2 { + cell-id = ; + label = "mas-xm-sdc2"; + 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 = <1>; + }; + + 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,ap-owned; + qcom,prio = <1>; + }; + + mas_xm_ufs_card: mas-xm-ufs-card { + cell-id = ; + label = "mas-xm-ufs-card"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <3>; + qcom,connections = <&slv_qns_a1noc_snoc>; + qcom,bus-dev = <&fab_aggre1_noc>; + qcom,ap-owned; + qcom,prio = <2>; + }; + + mas_xm_ufs_mem: mas-xm-ufs-mem { + cell-id = ; + label = "mas-xm-ufs-mem"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <4>; + qcom,connections = <&slv_qns_a1noc_snoc>; + qcom,bus-dev = <&fab_aggre1_noc>; + qcom,ap-owned; + qcom,prio = <2>; + }; + + mas_xm_pcie_0: mas-xm-pcie-0 { + cell-id = ; + label = "mas-xm-pcie-0"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <5>; + qcom,connections = <&slv_qns_pcie_a1noc_snoc>; + qcom,bus-dev = <&fab_aggre1_noc>; + qcom,ap-owned; + qcom,prio = <2>; + }; + + 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,connections = <&slv_qns_a2noc_snoc>; + qcom,bus-dev = <&fab_aggre2_noc>; + }; + + mas_qhm_qup2: mas-qhm-qup2 { + cell-id = ; + label = "mas-qhm-qup2"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qns_a2noc_snoc>; + qcom,bus-dev = <&fab_aggre2_noc>; + qcom,bcms = <&bcm_qup0>; + }; + + 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,ap-owned; + qcom,prio = <1>; + }; + + mas_qxm_crypto: mas-qxm-crypto { + cell-id = ; + label = "mas-qxm-crypto"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <1>; + qcom,connections = <&slv_qns_a2noc_snoc>; + qcom,bus-dev = <&fab_aggre2_noc>; + qcom,bcms = <&bcm_ce0>; + qcom,ap-owned; + qcom,prio = <2>; + }; + + mas_qxm_ipa: mas-qxm-ipa { + cell-id = ; + label = "mas-qxm-ipa"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <2>; + qcom,connections = <&slv_qns_a2noc_snoc>; + qcom,bus-dev = <&fab_aggre2_noc>; + qcom,ap-owned; + qcom,prio = <2>; + qcom,defer-init-qos; + qcom,node-qos-bcms = <7035 0 1>; + }; + + mas_xm_pcie3_1: mas-xm-pcie3-1 { + cell-id = ; + label = "mas-xm-pcie3-1"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <6>; + qcom,connections = <&slv_qns_pcie_snoc>; + qcom,bus-dev = <&fab_aggre2_noc>; + 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,ap-owned; + qcom,prio = <2>; + }; + + mas_xm_usb3_0: mas-xm-usb3-0 { + cell-id = ; + label = "mas-xm-usb3-0"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <10>; + qcom,connections = <&slv_qns_a2noc_snoc>; + qcom,bus-dev = <&fab_aggre2_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 = <11>; + qcom,connections = <&slv_qns_a2noc_snoc>; + qcom,bus-dev = <&fab_aggre2_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_qxm_camnoc_hf0_uncomp: mas-qxm-camnoc-hf0-uncomp { + cell-id = ; + label = "mas-qxm-camnoc-hf0-uncomp"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qns_camnoc_uncomp>; + qcom,bus-dev = <&fab_camnoc_virt>; + qcom,bcms = <&bcm_mm1>; + }; + + mas_qxm_camnoc_hf1_uncomp: mas-qxm-camnoc-hf1-uncomp { + cell-id = ; + label = "mas-qxm-camnoc-hf1-uncomp"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qns_camnoc_uncomp>; + qcom,bus-dev = <&fab_camnoc_virt>; + qcom,bcms = <&bcm_mm1>; + }; + + mas_qxm_camnoc_sf_uncomp: mas-qxm-camnoc-sf-uncomp { + cell-id = ; + label = "mas-qxm-camnoc-sf-uncomp"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qns_camnoc_uncomp>; + qcom,bus-dev = <&fab_camnoc_virt>; + qcom,bcms = <&bcm_mm1>; + }; + + mas_qhm_spdm: mas-qhm-spdm { + cell-id = ; + label = "mas-qhm-spdm"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qns_cnoc_a2noc>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + mas_qnm_snoc: mas-qnm-snoc { + cell-id = ; + label = "mas-qnm-snoc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qhs_tlmm_south + &slv_qhs_spss_cfg &slv_qhs_camera_cfg + &slv_qhs_sdc4 &slv_qhs_sdc2 + &slv_qhs_mnoc_cfg &slv_qhs_ufs_mem_cfg + &slv_qhs_snoc_cfg &slv_qhs_glm + &slv_qhs_pdm &slv_qhs_a2_noc_cfg + &slv_qhs_qdss_cfg &slv_qhs_display_cfg + &slv_qhs_tcsr &slv_qhs_dcc_cfg + &slv_qhs_ddrss_cfg &slv_qhs_phy_refgen_south + &slv_qhs_pcie_gen3_cfg &slv_qhs_pcie0_cfg + &slv_qhs_gpuss_cfg &slv_qhs_venus_cfg + &slv_qhs_tsif &slv_qhs_compute_dsp_cfg + &slv_qhs_aop &slv_qhs_qupv3_north + &slv_qhs_usb3_0 &slv_srvc_cnoc + &slv_qhs_ufs_card_cfg &slv_qhs_usb3_1 + &slv_qhs_ipa &slv_qhs_cpr_cx + &slv_qhs_a1_noc_cfg &slv_qhs_aoss + &slv_qhs_prng &slv_qhs_vsense_ctrl_cfg + &slv_qhs_qupv3_south &slv_qhs_spdm + &slv_qhs_crypto0_cfg &slv_qhs_pimem_cfg + &slv_qhs_tlmm_north &slv_qhs_clk_ctl + &slv_qhs_imem_cfg>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + mas_qhm_cnoc: mas-qhm-cnoc { + cell-id = ; + label = "mas-qhm-cnoc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qhs_memnoc &slv_qhs_llcc>; + qcom,bus-dev = <&fab_dc_noc>; + }; + + mas_acm_l3: mas-acm-l3 { + cell-id = ; + label = "mas-acm-l3"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_srvc_gnoc + &slv_qns_gladiator_sodv &slv_qns_gnoc_memnoc>; + qcom,bus-dev = <&fab_gladiator_noc>; + }; + + mas_pm_gnoc_cfg: mas-pm-gnoc-cfg { + cell-id = ; + label = "mas-pm-gnoc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_srvc_gnoc>; + qcom,bus-dev = <&fab_gladiator_noc>; + }; + + 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_acm_tcu: mas-acm-tcu { + cell-id = ; + label = "mas-acm-tcu"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <0>; + qcom,connections = <&slv_qns_apps_io &slv_qns_llcc + &slv_qns_memnoc_snoc>; + qcom,bus-dev = <&fab_mem_noc>; + qcom,bcms = <&bcm_sh3>; + qcom,ap-owned; + qcom,prio = <7>; + }; + + mas_qhm_memnoc_cfg: mas-qhm-memnoc-cfg { + cell-id = ; + label = "mas-qhm-memnoc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_srvc_memnoc + &slv_qhs_mdsp_ms_mpu_cfg>; + qcom,bus-dev = <&fab_mem_noc>; + }; + + mas_qnm_apps: mas-qnm-apps { + cell-id = ; + label = "mas-qnm-apps"; + qcom,buswidth = <32>; + qcom,agg-ports = <2>; + qcom,qport = <2 3>; + qcom,connections = <&slv_qns_llcc>; + qcom,bus-dev = <&fab_mem_noc>; + qcom,bcms = <&bcm_sh5>; + qcom,ap-owned; + qcom,prio = <0>; + }; + + mas_qnm_mnoc_hf: mas-qnm-mnoc-hf { + cell-id = ; + label = "mas-qnm-mnoc-hf"; + qcom,buswidth = <32>; + qcom,agg-ports = <2>; + qcom,qport = <4 5>; + qcom,connections = <&slv_qns_apps_io &slv_qns_llcc>; + qcom,bus-dev = <&fab_mem_noc>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_qnm_mnoc_sf: mas-qnm-mnoc-sf { + cell-id = ; + label = "mas-qnm-mnoc-sf"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <7>; + qcom,connections = <&slv_qns_apps_io + &slv_qns_llcc &slv_qns_memnoc_snoc>; + qcom,bus-dev = <&fab_mem_noc>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_qnm_snoc_gc: mas-qnm-snoc-gc { + cell-id = ; + label = "mas-qnm-snoc-gc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <8>; + qcom,connections = <&slv_qns_llcc>; + qcom,bus-dev = <&fab_mem_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 = <9>; + qcom,connections = <&slv_qns_apps_io &slv_qns_llcc>; + qcom,bus-dev = <&fab_mem_noc>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + }; + + mas_qxm_gpu: mas-qxm-gpu { + cell-id = ; + label = "mas-qxm-gpu"; + qcom,buswidth = <32>; + qcom,agg-ports = <2>; + qcom,qport = <10 11>; + qcom,connections = <&slv_qns_apps_io + &slv_qns_llcc &slv_qns_memnoc_snoc>; + qcom,bus-dev = <&fab_mem_noc>; + qcom,ap-owned; + qcom,prio = <0>; + }; + + mas_qhm_mnoc_cfg: mas-qhm-mnoc-cfg { + cell-id = ; + label = "mas-qhm-mnoc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_srvc_mnoc>; + qcom,bus-dev = <&fab_mmss_noc>; + }; + + mas_qxm_camnoc_hf0: mas-qxm-camnoc-hf0 { + cell-id = ; + label = "mas-qxm-camnoc-hf0"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <1>; + qcom,connections = <&slv_qns_mem_noc_hf>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,bcms = <&bcm_mm1>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_qxm_camnoc_hf1: mas-qxm-camnoc-hf1 { + cell-id = ; + label = "mas-qxm-camnoc-hf1"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <2>; + qcom,connections = <&slv_qns_mem_noc_hf>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,bcms = <&bcm_mm1>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_qxm_camnoc_sf: mas-qxm-camnoc-sf { + cell-id = ; + label = "mas-qxm-camnoc-sf"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <0>; + qcom,connections = <&slv_qns2_mem_noc>; + 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 = <3>; + 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 = <4>; + 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 = <5>; + qcom,connections = <&slv_qns2_mem_noc>; + 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_venus0: mas-qxm-venus0 { + cell-id = ; + label = "mas-qxm-venus0"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <6>; + qcom,connections = <&slv_qns2_mem_noc>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,bcms = <&bcm_mm3>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_qxm_venus1: mas-qxm-venus1 { + cell-id = ; + label = "mas-qxm-venus1"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <7>; + qcom,connections = <&slv_qns2_mem_noc>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,bcms = <&bcm_mm3>; + qcom,ap-owned; + qcom,prio = <0>; + qcom,forwarding; + qcom,node-qos-bcms = <7012 0 1>; + }; + + mas_qxm_venus_arm9: mas-qxm-venus-arm9 { + cell-id = ; + label = "mas-qxm-venus-arm9"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <8>; + qcom,connections = <&slv_qns2_mem_noc>; + 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_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_qxs_pimem + &slv_qns_memnoc_sf &slv_qxs_imem + &slv_qhs_apss &slv_qns_cnoc + &slv_xs_qdss_stm>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn9>; + }; + + 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_qxs_pimem + &slv_qns_memnoc_sf &slv_qxs_pcie_gen3 + &slv_qxs_imem &slv_qhs_apss + &slv_qns_cnoc &slv_qxs_pcie + &slv_xs_sys_tcu_cfg &slv_xs_qdss_stm>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn11>; + }; + + mas_qnm_gladiator_sodv: mas-qnm-gladiator-sodv { + cell-id = ; + label = "mas-qnm-gladiator-sodv"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qxs_pimem + &slv_qxs_pcie_gen3 &slv_qxs_imem + &slv_qhs_apss &slv_qns_cnoc + &slv_qxs_pcie &slv_xs_sys_tcu_cfg + &slv_xs_qdss_stm>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn12>; + }; + + mas_qnm_memnoc: mas-qnm-memnoc { + cell-id = ; + label = "mas-qnm-memnoc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qxs_imem + &slv_qhs_apss &slv_qxs_pimem + &slv_qns_cnoc &slv_xs_qdss_stm>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn15>; + }; + + mas_qnm_pcie_anoc: mas-qnm-pcie-anoc { + cell-id = ; + label = "mas-qnm-pcie-anoc"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,connections = <&slv_qxs_imem + &slv_qhs_apss &slv_qns_cnoc + &slv_qns_memnoc_sf &slv_xs_qdss_stm>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn14>; + }; + + mas_qxm_pimem: mas-qxm-pimem { + cell-id = ; + label = "mas-qxm-pimem"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <3>; + qcom,connections = <&slv_qxs_imem &slv_qns_memnoc_gc>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn4>; + qcom,ap-owned; + qcom,prio = <2>; + }; + + mas_xm_gic: mas-xm-gic { + cell-id = ; + label = "mas-xm-gic"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,qport = <0>; + qcom,connections = <&slv_qxs_imem &slv_qns_memnoc_gc>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn12>; + qcom,ap-owned; + qcom,prio = <1>; + }; + + 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_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_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 = <4 5>; + qcom,connections = <&slv_qns_llcc_display>; + qcom,bus-dev = <&fab_mem_noc_display>; + }; + + mas_qnm_mnoc_sf_display: mas-qnm-mnoc-sf_display { + cell-id = ; + label = "mas-qnm-mnoc-sf_display"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,qport = <7>; + qcom,connections = <&slv_qns_llcc_display>; + qcom,bus-dev = <&fab_mem_noc_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 = <3>; + 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 = <4>; + 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 = <5>; + qcom,connections = <&slv_qns2_mem_noc_display>; + qcom,bus-dev = <&fab_mmss_noc_display>; + qcom,bcms = <&bcm_mm3_display>; + }; + + /*Internal nodes*/ + + /*Slaves*/ + + slv_qns_a1noc_snoc:slv-qns-a1noc-snoc { + cell-id = ; + label = "slv-qns-a1noc-snoc"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_aggre1_noc>; + qcom,connections = <&mas_qnm_aggre1_noc>; + }; + + slv_srvc_aggre1_noc:slv-srvc-aggre1-noc { + cell-id = ; + label = "slv-srvc-aggre1-noc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_aggre1_noc>; + qcom,bcms = <&bcm_sn9>; + }; + + slv_qns_pcie_a1noc_snoc:slv-qns-pcie-a1noc-snoc { + cell-id = ; + label = "slv-qns-pcie-a1noc-snoc"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_aggre1_noc>; + qcom,connections = <&mas_qnm_pcie_anoc>; + }; + + 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_snoc:slv-qns-pcie-snoc { + cell-id = ; + label = "slv-qns-pcie-snoc"; + qcom,buswidth = <16>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_aggre2_noc>; + qcom,connections = <&mas_qnm_pcie_anoc>; + }; + + 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>; + qcom,bcms = <&bcm_sn11>; + }; + + slv_qns_camnoc_uncomp:slv-qns-camnoc-uncomp { + cell-id = ; + label = "slv-qns-camnoc-uncomp"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_camnoc_virt>; + }; + + 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_aop:slv-qhs-aop { + cell-id = ; + label = "slv-qhs-aop"; + 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>; + }; + + 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_cfg:slv-qhs-compute-dsp-cfg { + cell-id = ; + label = "slv-qhs-compute-dsp-cfg"; + 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_crypto0_cfg:slv-qhs-crypto0-cfg { + cell-id = ; + label = "slv-qhs-crypto0-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_dcc_cfg:slv-qhs-dcc-cfg { + cell-id = ; + label = "slv-qhs-dcc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,connections = <&mas_qhm_cnoc>; + 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,bcms = <&bcm_cn0>; + }; + + slv_qhs_display_cfg:slv-qhs-display-cfg { + cell-id = ; + label = "slv-qhs-display-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_glm:slv-qhs-glm { + cell-id = ; + label = "slv-qhs-glm"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_gpuss_cfg:slv-qhs-gpuss-cfg { + cell-id = ; + label = "slv-qhs-gpuss-cfg"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_imem_cfg:slv-qhs-imem-cfg { + cell-id = ; + label = "slv-qhs-imem-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_ipa:slv-qhs-ipa { + cell-id = ; + label = "slv-qhs-ipa"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_mnoc_cfg:slv-qhs-mnoc-cfg { + cell-id = ; + label = "slv-qhs-mnoc-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,connections = <&mas_qhm_mnoc_cfg>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_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_pcie_gen3_cfg:slv-qhs-pcie-gen3-cfg { + cell-id = ; + label = "slv-qhs-pcie-gen3-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_phy_refgen_south:slv-qhs-phy-refgen-south { + cell-id = ; + label = "slv-qhs-phy-refgen-south"; + 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_qupv3_north:slv-qhs-qupv3-north { + cell-id = ; + label = "slv-qhs-qupv3-north"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_qupv3_south:slv-qhs-qupv3-south { + cell-id = ; + label = "slv-qhs-qupv3-south"; + 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_spdm:slv-qhs-spdm { + cell-id = ; + label = "slv-qhs-spdm"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_spss_cfg:slv-qhs-spss-cfg { + cell-id = ; + label = "slv-qhs-spss-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_tcsr:slv-qhs-tcsr { + cell-id = ; + label = "slv-qhs-tcsr"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_tlmm_north:slv-qhs-tlmm-north { + cell-id = ; + label = "slv-qhs-tlmm-north"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_config_noc>; + qcom,bcms = <&bcm_cn0>; + }; + + slv_qhs_tlmm_south:slv-qhs-tlmm-south { + cell-id = ; + label = "slv-qhs-tlmm-south"; + 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>; + }; + + 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_memnoc_cfg>; + }; + + slv_qns_gladiator_sodv:slv-qns-gladiator-sodv { + cell-id = ; + label = "slv-qns-gladiator-sodv"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_gladiator_noc>; + qcom,connections = <&mas_qnm_gladiator_sodv>; + }; + + slv_qns_gnoc_memnoc:slv-qns-gnoc-memnoc { + cell-id = ; + label = "slv-qns-gnoc-memnoc"; + qcom,buswidth = <32>; + qcom,agg-ports = <2>; + qcom,bus-dev = <&fab_gladiator_noc>; + qcom,connections = <&mas_qnm_apps>; + }; + + slv_srvc_gnoc:slv-srvc-gnoc { + cell-id = ; + label = "slv-srvc-gnoc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_gladiator_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_qhs_mdsp_ms_mpu_cfg:slv-qhs-mdsp-ms-mpu-cfg { + cell-id = ; + label = "slv-qhs-mdsp-ms-mpu-cfg"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_mem_noc>; + }; + + slv_qns_apps_io:slv-qns-apps-io { + cell-id = ; + label = "slv-qns-apps-io"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_mem_noc>; + qcom,bcms = <&bcm_sh1>; + }; + + slv_qns_llcc:slv-qns-llcc { + cell-id = ; + label = "slv-qns-llcc"; + qcom,buswidth = <16>; + qcom,agg-ports = <4>; + qcom,bus-dev = <&fab_mem_noc>; + qcom,connections = <&mas_llcc_mc>; + qcom,bcms = <&bcm_sh0>; + }; + + slv_qns_memnoc_snoc:slv-qns-memnoc-snoc { + cell-id = ; + label = "slv-qns-memnoc-snoc"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_mem_noc>; + qcom,connections = <&mas_qnm_memnoc>; + qcom,bcms = <&bcm_sh2>; + }; + + slv_srvc_memnoc:slv-srvc-memnoc { + cell-id = ; + label = "slv-srvc-memnoc"; + qcom,buswidth = <4>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_mem_noc>; + }; + + slv_qns2_mem_noc:slv-qns2-mem-noc { + cell-id = ; + label = "slv-qns2-mem-noc"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_mmss_noc>; + qcom,connections = <&mas_qnm_mnoc_sf>; + qcom,bcms = <&bcm_mm2>; + }; + + 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_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_apss:slv-qhs-apss { + cell-id = ; + label = "slv-qhs-apss"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn6>; + }; + + 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>; + qcom,bcms = <&bcm_sn3>; + }; + + slv_qns_memnoc_gc:slv-qns-memnoc-gc { + cell-id = ; + label = "slv-qns-memnoc-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_memnoc_sf:slv-qns-memnoc-sf { + cell-id = ; + label = "slv-qns-memnoc-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_pcie:slv-qxs-pcie { + cell-id = ; + label = "slv-qxs-pcie"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn7>; + }; + + slv_qxs_pcie_gen3:slv-qxs-pcie-gen3 { + cell-id = ; + label = "slv-qxs-pcie-gen3"; + qcom,buswidth = <8>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_system_noc>; + qcom,bcms = <&bcm_sn8>; + }; + + 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>; + }; + + 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>; + qcom,bcms = <&bcm_sn6>; + }; + + 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_sn5>; + }; + + 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>; + qcom,bcms = <&bcm_sn6>; + }; + + 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>; + }; + + 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_mem_noc_display>; + qcom,connections = <&mas_llcc_mc_display>; + qcom,bcms = <&bcm_sh0_display>; + }; + + slv_qns2_mem_noc_display:slv-qns2-mem-noc_display { + cell-id = ; + label = "slv-qns2-mem-noc_display"; + qcom,buswidth = <32>; + qcom,agg-ports = <1>; + qcom,bus-dev = <&fab_mmss_noc_display>; + qcom,connections = <&mas_qnm_mnoc_sf_display>; + qcom,bcms = <&bcm_mm2_display>; + }; + + 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>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-mtp.dtsi new file mode 100644 index 000000000000..d708a121c4b1 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-mtp.dtsi @@ -0,0 +1,465 @@ +/* + * 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. + */ + +&soc { + led_flash_rear: qcom,camera-flash@0 { + cell-index = <0>; + reg = <0x00 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pmi8998_flash0 &pmi8998_flash1>; + torch-source = <&pmi8998_torch0 &pmi8998_torch1>; + switch-source = <&pmi8998_switch0>; + status = "ok"; + }; + + led_flash_rear_aux: qcom,camera-flash@1 { + cell-index = <1>; + reg = <0x01 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pmi8998_flash0 &pmi8998_flash1>; + torch-source = <&pmi8998_torch0 &pmi8998_torch1>; + switch-source = <&pmi8998_switch0>; + status = "ok"; + }; + + led_flash_front: qcom,camera-flash@2 { + cell-index = <2>; + reg = <0x02 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pmi8998_flash2>; + torch-source = <&pmi8998_torch2>; + switch-source = <&pmi8998_switch1>; + status = "ok"; + }; + + led_flash_iris: qcom,camera-flash@3 { + cell-index = <3>; + reg = <0x03 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pmi8998_flash2>; + torch-source = <&pmi8998_torch2>; + switch-source = <&pmi8998_switch2>; + status = "ok"; + }; + + actuator_regulator: gpio-regulator@0 { + compatible = "regulator-fixed"; + reg = <0x00 0x00>; + regulator-name = "actuator_regulator"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-enable-ramp-delay = <100>; + enable-active-high; + gpio = <&tlmm 27 0>; + vin-supply = <&pmi8998_bob>; + }; + + camera_rear_ldo: gpio-regulator@1 { + compatible = "regulator-fixed"; + reg = <0x01 0x00>; + regulator-name = "camera_rear_ldo"; + regulator-min-microvolt = <1050000>; + regulator-max-microvolt = <1050000>; + regulator-enable-ramp-delay = <135>; + enable-active-high; + gpio = <&pm8998_gpios 12 0>; + pinctrl-names = "default"; + pinctrl-0 = <&camera_rear_dvdd_en_default>; + vin-supply = <&pm8998_s3>; + }; + + camera_ldo: gpio-regulator@2 { + compatible = "regulator-fixed"; + reg = <0x02 0x00>; + regulator-name = "camera_ldo"; + regulator-min-microvolt = <1050000>; + regulator-max-microvolt = <1050000>; + regulator-enable-ramp-delay = <233>; + enable-active-high; + gpio = <&pm8998_gpios 9 0>; + pinctrl-names = "default"; + pinctrl-0 = <&camera_dvdd_en_default>; + vin-supply = <&pm8998_s3>; + }; + + camera_vana_ldo: gpio-regulator@4 { + compatible = "regulator-fixed"; + reg = <0x04 0x00>; + regulator-name = "camera_vana_ldo"; + regulator-min-microvolt = <2850000>; + regulator-max-microvolt = <2850000>; + regulator-enable-ramp-delay = <233>; + enable-active-high; + gpio = <&tlmm 8 0>; + pinctrl-names = "default"; + pinctrl-0 = <&cam_sensor_rear_vana>; + vin-supply = <&pmi8998_bob>; + }; +}; + +&cam_cci { + qcom,cam-res-mgr { + compatible = "qcom,cam-res-mgr"; + status = "ok"; + }; + + actuator_rear: qcom,actuator@0 { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,actuator"; + cci-master = <0>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; + }; + + actuator_rear_aux: qcom,actuator@1 { + cell-index = <1>; + reg = <0x1>; + compatible = "qcom,actuator"; + cci-master = <1>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; + }; + + actuator_front: qcom,actuator@2 { + cell-index = <2>; + reg = <0x2>; + compatible = "qcom,actuator"; + cci-master = <1>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; + }; + + ois_rear: qcom,ois@0 { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,ois"; + cci-master = <0>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; + status = "ok"; + }; + + eeprom_rear: qcom,eeprom@0 { + cell-index = <0>; + reg = <0>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pm8998_lvs1>; + cam_vana-supply = <&pmi8998_bob>; + cam_vdig-supply = <&camera_rear_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 3312000 1050000 0 2800000>; + rgltr-max-voltage = <0 3600000 1050000 0 2800000>; + rgltr-load-current = <0 80000 105000 0 0>; + 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-vana = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0", + "CAM_VANA0"; + 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,eeprom@1 { + cell-index = <1>; + reg = <0x1>; + compatible = "qcom,eeprom"; + cam_vdig-supply = <&camera_ldo>; + cam_vio-supply = <&pm8998_lvs1>; + cam_vana-supply = <&pmi8998_bob>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vdig", "cam_vio", "cam_vana", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <1050000 0 3312000 0 2800000>; + rgltr-max-voltage = <1050000 0 3600000 0 2800000>; + rgltr-load-current = <105000 0 80000 0 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_rear2_active>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_rear2_suspend>; + gpios = <&tlmm 15 0>, + <&tlmm 9 0>, + <&tlmm 8 0>; + gpio-reset = <1>; + gpio-vana = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1", + "CAM_VANA1"; + 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_front: qcom,eeprom@2 { + cell-index = <2>; + reg = <0x2>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pm8998_lvs1>; + cam_vana-supply = <&pmi8998_bob>; + cam_vdig-supply = <&camera_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + cam_vaf-supply = <&actuator_regulator>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk", "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 3312000 1050000 0 2800000>; + rgltr-max-voltage = <0 3600000 1050000 0 2800000>; + rgltr-load-current = <0 80000 105000 0 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_front_active>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_front_suspend>; + gpios = <&tlmm 14 0>, + <&tlmm 28 0>, + <&tlmm 8 0>; + gpio-reset = <1>; + gpio-vana = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2", + "CAM_VANA2"; + sensor-position = <1>; + 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-sensor@0 { + cell-index = <0>; + compatible = "qcom,cam-sensor"; + reg = <0x0>; + csiphy-sd-index = <0>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + led-flash-src = <&led_flash_rear>; + actuator-src = <&actuator_rear>; + ois-src = <&ois_rear>; + eeprom-src = <&eeprom_rear>; + cam_vio-supply = <&pm8998_lvs1>; + cam_vana-supply = <&pmi8998_bob>; + cam_vdig-supply = <&camera_rear_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 3312000 1050000 0>; + rgltr-max-voltage = <0 3600000 1050000 0>; + rgltr-load-current = <0 80000 105000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_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-vana = <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-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-sensor@1 { + cell-index = <1>; + compatible = "qcom,cam-sensor"; + reg = <0x1>; + 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_vdig-supply = <&camera_ldo>; + cam_vio-supply = <&pm8998_lvs1>; + cam_vana-supply = <&camera_vana_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vdig", "cam_vio", "cam_vana", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <1050000 0 2850000 0>; + rgltr-max-voltage = <1050000 0 2850000 0>; + rgltr-load-current = <105000 0 80000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_rear2_active>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_rear2_suspend>; + gpios = <&tlmm 15 0>, + <&tlmm 9 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_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@2 { + cell-index = <2>; + compatible = "qcom,cam-sensor"; + reg = <0x02>; + csiphy-sd-index = <2>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <0>; + eeprom-src = <&eeprom_front>; + actuator-src = <&actuator_front>; + led-flash-src = <&led_flash_front>; + cam_vio-supply = <&pm8998_lvs1>; + cam_vana-supply = <&camera_vana_ldo>; + cam_vdig-supply = <&camera_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 2850000 1050000 0>; + rgltr-max-voltage = <0 2850000 1050000 0>; + rgltr-load-current = <0 80000 105000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_front_active>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_front_suspend>; + gpios = <&tlmm 14 0>, + <&tlmm 28 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_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <24000000>; + }; + + qcom,cam-sensor@3 { + cell-index = <3>; + compatible = "qcom,cam-sensor"; + reg = <0x03>; + csiphy-sd-index = <3>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <0>; + led-flash-src = <&led_flash_iris>; + cam_vio-supply = <&pm8998_lvs1>; + cam_vana-supply = <&camera_vana_ldo>; + cam_vdig-supply = <&camera_ldo>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 2850000 1050000 0>; + rgltr-max-voltage = <0 2850000 1050000 0>; + rgltr-load-current = <0 80000 105000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk3_active + &cam_sensor_iris_active>; + pinctrl-1 = <&cam_sensor_mclk3_suspend + &cam_sensor_iris_suspend>; + gpios = <&tlmm 16 0>, + <&tlmm 9 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/qcom/sdm845-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi new file mode 100644 index 000000000000..8bb6d2386530 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi @@ -0,0 +1,1097 @@ +/* + * Copyright (c) 2017-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. + */ + +&soc { + qcom,cam-req-mgr { + compatible = "qcom,cam-req-mgr"; + status = "ok"; + }; + + cam_csiphy0: qcom,csiphy@ac65000 { + cell-index = <0>; + compatible = "qcom,csiphy-v1.0", "qcom,csiphy"; + reg = <0x0ac65000 0x1000>; + reg-names = "csiphy"; + reg-cam-base = <0x65000>; + interrupts = <0 477 0>; + interrupt-names = "csiphy"; + gdscr-supply = <&titan_top_gdsc>; + regulator-names = "gdscr"; + csi-vdd-voltage = <1200000>; + mipi-csi-vdd-supply = <&pm8998_l1>; + clocks = <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&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 = "camnoc_axi_clk", + "soc_ahb_clk", + "slow_ahb_src_clk", + "cpas_ahb_clk", + "cphy_rx_clk_src", + "csiphy0_clk", + "csi0phytimer_clk_src", + "csi0phytimer_clk"; + src-clock-name = "csi0phytimer_clk_src"; + clock-cntl-level = "svs", "turbo"; + clock-rates = + <0 0 0 0 320000000 0 269333333 0>, + <0 0 0 0 384000000 0 269333333 0>; + status = "ok"; + }; + + cam_csiphy1: qcom,csiphy@ac66000{ + cell-index = <1>; + compatible = "qcom,csiphy-v1.0", "qcom,csiphy"; + reg = <0xac66000 0x1000>; + reg-names = "csiphy"; + reg-cam-base = <0x66000>; + interrupts = <0 478 0>; + interrupt-names = "csiphy"; + gdscr-supply = <&titan_top_gdsc>; + regulator-names = "gdscr"; + csi-vdd-voltage = <1200000>; + mipi-csi-vdd-supply = <&pm8998_l1>; + clocks = <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&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 = "camnoc_axi_clk", + "soc_ahb_clk", + "slow_ahb_src_clk", + "cpas_ahb_clk", + "cphy_rx_clk_src", + "csiphy1_clk", + "csi1phytimer_clk_src", + "csi1phytimer_clk"; + src-clock-name = "csi1phytimer_clk_src"; + clock-cntl-level = "svs", "turbo"; + clock-rates = + <0 0 0 0 320000000 0 269333333 0>, + <0 0 0 0 384000000 0 269333333 0>; + + status = "ok"; + }; + + cam_csiphy2: qcom,csiphy@ac67000 { + cell-index = <2>; + compatible = "qcom,csiphy-v1.0", "qcom,csiphy"; + reg = <0xac67000 0x1000>; + reg-names = "csiphy"; + reg-cam-base = <0x67000>; + interrupts = <0 479 0>; + interrupt-names = "csiphy"; + gdscr-supply = <&titan_top_gdsc>; + regulator-names = "gdscr"; + csi-vdd-voltage = <1200000>; + mipi-csi-vdd-supply = <&pm8998_l1>; + clocks = <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&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 = "camnoc_axi_clk", + "soc_ahb_clk", + "slow_ahb_src_clk", + "cpas_ahb_clk", + "cphy_rx_clk_src", + "csiphy2_clk", + "csi2phytimer_clk_src", + "csi2phytimer_clk"; + src-clock-name = "csi2phytimer_clk_src"; + clock-cntl-level = "svs", "turbo"; + clock-rates = + <0 0 0 0 320000000 0 269333333 0>, + <0 0 0 0 384000000 0 269333333 0>; + status = "ok"; + }; + + cam_cci: qcom,cci@ac4a000 { + cell-index = <0>; + compatible = "qcom,cci"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xac4a000 0x4000>; + reg-names = "cci"; + reg-cam-base = <0x4a000>; + interrupt-names = "cci"; + interrupts = <0 460 0>; + status = "ok"; + gdscr-supply = <&titan_top_gdsc>; + regulator-names = "gdscr"; + clocks = <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CCI_CLK>, + <&clock_camcc CAM_CC_CCI_CLK_SRC>; + clock-names = "camnoc_axi_clk", + "soc_ahb_clk", + "slow_ahb_src_clk", + "cpas_ahb_clk", + "cci_clk", + "cci_clk_src"; + src-clock-name = "cci_clk_src"; + clock-cntl-level = "lowsvs"; + clock-rates = <0 0 0 0 0 37500000>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cci0_active &cci1_active>; + pinctrl-1 = <&cci0_suspend &cci1_suspend>; + gpios = <&tlmm 17 0>, + <&tlmm 18 0>, + <&tlmm 19 0>, + <&tlmm 20 0>; + gpio-req-tbl-num = <0 1 2 3>; + gpio-req-tbl-flags = <1 1 1 1>; + gpio-req-tbl-label = "CCI_I2C_DATA0", + "CCI_I2C_CLK0", + "CCI_I2C_DATA1", + "CCI_I2C_CLK1"; + + i2c_freq_100Khz: 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: 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: 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: 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 0x808 0x0>, + <&apps_smmu 0x810 0x8>, + <&apps_smmu 0xc08 0x0>, + <&apps_smmu 0xc10 0x8>; + 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 0x1060 0x8>, + <&apps_smmu 0x1068 0x8>; + label = "jpeg"; + 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 0x1078 0x2>, + <&apps_smmu 0x1020 0x8>, + <&apps_smmu 0x1040 0x8>, + <&apps_smmu 0x1030 0x0>, + <&apps_smmu 0x1050 0x0>; + 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 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 GB */ + iova-region-name = "io"; + iova-region-start = <0x10C00000>; + iova-region-len = <0xCF300000>; + iova-region-id = <0x3>; + status = "ok"; + }; + + iova-mem-qdss-region { + /* qdss region is approximately 1MB */ + iova-region-name = "qdss"; + iova-region-start = <0x10B00000>; + iova-region-len = <0x100000>; + iova-region-id = <0x5>; + qdss-phy-addr = <0x16790000>; + status = "ok"; + }; + }; + }; + + msm_cam_smmu_cpas_cdm { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x1000 0x0>; + label = "cpas-cdm0"; + 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 0x1070 0x0>; + 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 0x5000>; + reg-cam-base = <0x40000 0x42000>; + interrupt-names = "cpas_camnoc"; + interrupts = <0 459 0>; + qcom,cpas-hw-ver = <0x170100>; /* Titan v170 v1.0.0 */ + camnoc-axi-min-ib-bw = <3000000000>; + regulator-names = "camss-vdd"; + camss-vdd-supply = <&titan_top_gdsc>; + clock-names = "gcc_ahb_clk", + "gcc_axi_clk", + "soc_ahb_clk", + "slow_ahb_clk_src", + "cpas_ahb_clk", + "camnoc_axi_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>; + src-clock-name = "slow_ahb_clk_src"; + clock-rates = <0 0 0 0 0 0>, + <0 0 0 19200000 0 0>, + <0 0 0 60000000 0 0>, + <0 0 0 66660000 0 0>, + <0 0 0 73840000 0 0>, + <0 0 0 80000000 0 0>, + <0 0 0 80000000 0 0>; + clock-cntl-level = "suspend", "minsvs", "lowsvs", "svs", + "svs_l1", "nominal", "turbo"; + qcom,msm-bus,name = "cam_ahb"; + qcom,msm-bus,num-cases = <7>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + , + , + , + , + ; + vdd-corners = ; + vdd-corner-ahb-mapping = "suspend", "suspend", + "minsvs", "lowsvs", "svs", "svs_l1", + "nominal", "nominal", "nominal", + "turbo", "turbo"; + client-id-based; + client-names = + "csiphy0", "csiphy1", "csiphy2", "cci0", + "csid0", "csid1", "csid2", + "ife0", "ife1", "ife2", "ipe0", + "ipe1", "cam-cdm-intf0", "cpas-cdm0", "bps0", + "icp0", "jpeg-dma0", "jpeg-enc0", "fd0", "lrmecpas"; + client-axi-port-names = + "cam_hf_1", "cam_hf_2", "cam_hf_2", "cam_sf_1", + "cam_hf_1", "cam_hf_2", "cam_hf_2", + "cam_hf_1", "cam_hf_2", "cam_hf_2", "cam_sf_1", + "cam_sf_1", "cam_sf_1", "cam_sf_1", "cam_sf_1", + "cam_sf_1", "cam_sf_1", "cam_sf_1", "cam_sf_1", + "cam_sf_1"; + client-bus-camnoc-based; + qcom,axi-port-list { + qcom,axi-port1 { + qcom,axi-port-name = "cam_hf_1"; + qcom,axi-port-mnoc { + qcom,msm-bus,name = "cam_hf_1_mnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + qcom,axi-port-camnoc { + qcom,msm-bus,name = "cam_hf_1_camnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + }; + qcom,axi-port2 { + qcom,axi-port-name = "cam_hf_2"; + qcom,axi-port-mnoc { + qcom,msm-bus,name = "cam_hf_2_mnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + qcom,axi-port-camnoc { + qcom,msm-bus,name = "cam_hf_2_camnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + }; + qcom,axi-port3 { + qcom,axi-port-name = "cam_sf_1"; + qcom,axi-port-mnoc { + qcom,msm-bus,name = "cam_sf_1_mnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + qcom,axi-port-camnoc { + qcom,msm-bus,name = "cam_sf_1_camnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + }; + }; + }; + + qcom,cam-cdm-intf { + compatible = "qcom,cam-cdm-intf"; + cell-index = <0>; + label = "cam-cdm-intf"; + num-hw-cdm = <1>; + cdm-client-names = "vfe", + "jpegdma", + "jpegenc", + "fd", + "lrmecdm"; + status = "ok"; + }; + + qcom,cpas-cdm0@ac48000 { + cell-index = <0>; + compatible = "qcom,cam170-cpas-cdm0"; + label = "cpas-cdm"; + reg = <0xac48000 0x1000>; + reg-names = "cpas-cdm"; + reg-cam-base = <0x48000>; + interrupts = <0 461 0>; + interrupt-names = "cpas-cdm"; + regulator-names = "camss"; + camss-supply = <&titan_top_gdsc>; + clock-names = "gcc_camera_ahb", + "gcc_camera_axi", + "cam_cc_soc_ahb_clk", + "cam_cc_cpas_ahb_clk", + "cam_cc_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_CAMNOC_AXI_CLK>; + clock-rates = <0 0 0 0 0>; + clock-cntl-level = "svs"; + cdm-client-names = "ife"; + status = "ok"; + }; + + qcom,cam-isp { + compatible = "qcom,cam-isp"; + arch-compat = "ife"; + status = "ok"; + }; + + cam_csid0: qcom,csid0@acb3000 { + cell-index = <0>; + compatible = "qcom,csid170"; + reg-names = "csid"; + reg = <0xacb3000 0x1000>; + reg-cam-base = <0xb3000>; + interrupt-names = "csid"; + interrupts = <0 464 0>; + regulator-names = "camss", "ife0"; + camss-supply = <&titan_top_gdsc>; + ife0-supply = <&ife_0_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "slow_ahb_clk_src", + "ife_csid_clk", + "ife_csid_clk_src", + "ife_cphy_rx_clk", + "cphy_rx_clk_src", + "ife_clk", + "ife_clk_src", + "camnoc_axi_clk", + "ife_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_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_camcc CAM_CC_IFE_0_CLK>, + <&clock_camcc CAM_CC_IFE_0_CLK_SRC>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_IFE_0_AXI_CLK>; + clock-rates = + <0 0 0 0 0 0 384000000 0 0 0 404000000 0 0>, + <0 0 0 0 0 0 538000000 0 0 0 600000000 0 0>; + clock-cntl-level = "svs", "turbo"; + src-clock-name = "ife_csid_clk_src"; + clock-control-debugfs = "true"; + status = "ok"; + }; + + cam_vfe0: qcom,vfe0@acaf000 { + cell-index = <0>; + compatible = "qcom,vfe170"; + reg-names = "ife"; + reg = <0xacaf000 0x4000>; + reg-cam-base = <0xaf000>; + interrupt-names = "ife"; + interrupts = <0 465 0>; + regulator-names = "camss", "ife0"; + camss-supply = <&titan_top_gdsc>; + ife0-supply = <&ife_0_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "slow_ahb_clk_src", + "ife_clk", + "ife_clk_src", + "camnoc_axi_clk", + "ife_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_IFE_0_CLK>, + <&clock_camcc CAM_CC_IFE_0_CLK_SRC>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_IFE_0_AXI_CLK>; + clock-rates = + <0 0 0 0 0 0 404000000 0 0>, + <0 0 0 0 0 0 480000000 0 0>, + <0 0 0 0 0 0 600000000 0 0>; + clock-cntl-level = "svs", "svs_l1", "turbo"; + src-clock-name = "ife_clk_src"; + clock-control-debugfs = "true"; + clock-names-option = "ife_dsp_clk"; + clocks-option = <&clock_camcc CAM_CC_IFE_0_DSP_CLK>; + clock-rates-option = <600000000>; + status = "ok"; + }; + + cam_csid1: qcom,csid1@acba000 { + cell-index = <1>; + compatible = "qcom,csid170"; + reg-names = "csid"; + reg = <0xacba000 0x1000>; + reg-cam-base = <0xba000>; + interrupt-names = "csid"; + interrupts = <0 466 0>; + regulator-names = "camss", "ife1"; + camss-supply = <&titan_top_gdsc>; + ife1-supply = <&ife_1_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "slow_ahb_clk_src", + "ife_csid_clk", + "ife_csid_clk_src", + "ife_cphy_rx_clk", + "cphy_rx_clk_src", + "ife_clk", + "ife_clk_src", + "camnoc_axi_clk", + "ife_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_IFE_1_CSID_CLK>, + <&clock_camcc CAM_CC_IFE_1_CSID_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_1_CPHY_RX_CLK>, + <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_1_CLK>, + <&clock_camcc CAM_CC_IFE_1_CLK_SRC>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_IFE_1_AXI_CLK>; + clock-rates = + <0 0 0 0 0 0 384000000 0 0 0 404000000 0 0>, + <0 0 0 0 0 0 538000000 0 0 0 600000000 0 0>; + clock-cntl-level = "svs", "turbo"; + src-clock-name = "ife_csid_clk_src"; + clock-control-debugfs = "true"; + status = "ok"; + }; + + cam_vfe1: qcom,vfe1@acb6000 { + cell-index = <1>; + compatible = "qcom,vfe170"; + reg-names = "ife"; + reg = <0xacb6000 0x4000>; + reg-cam-base = <0xb6000>; + interrupt-names = "ife"; + interrupts = <0 467 0>; + regulator-names = "camss", "ife1"; + camss-supply = <&titan_top_gdsc>; + ife1-supply = <&ife_1_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "slow_ahb_clk_src", + "ife_clk", + "ife_clk_src", + "camnoc_axi_clk", + "ife_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_IFE_1_CLK>, + <&clock_camcc CAM_CC_IFE_1_CLK_SRC>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_IFE_1_AXI_CLK>; + clock-rates = + <0 0 0 0 0 0 404000000 0 0>, + <0 0 0 0 0 0 480000000 0 0>, + <0 0 0 0 0 0 600000000 0 0>; + clock-cntl-level = "svs", "svs_l1", "turbo"; + src-clock-name = "ife_clk_src"; + clock-control-debugfs = "true"; + clock-names-option = "ife_dsp_clk"; + clocks-option = <&clock_camcc CAM_CC_IFE_1_DSP_CLK>; + clock-rates-option = <600000000>; + status = "ok"; + }; + + cam_csid_lite: qcom,csid-lite@acc8000 { + cell-index = <2>; + compatible = "qcom,csid-lite170"; + reg-names = "csid-lite"; + reg = <0xacc8000 0x1000>; + reg-cam-base = <0xc8000>; + interrupt-names = "csid-lite"; + interrupts = <0 468 0>; + regulator-names = "camss"; + camss-supply = <&titan_top_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "slow_ahb_clk_src", + "ife_csid_clk", + "ife_csid_clk_src", + "ife_cphy_rx_clk", + "cphy_rx_clk_src", + "ife_clk", + "ife_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_IFE_LITE_CSID_CLK>, + <&clock_camcc CAM_CC_IFE_LITE_CSID_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_LITE_CPHY_RX_CLK>, + <&clock_camcc CAM_CC_CPHY_RX_CLK_SRC>, + <&clock_camcc CAM_CC_IFE_LITE_CLK>, + <&clock_camcc CAM_CC_IFE_LITE_CLK_SRC>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>; + clock-rates = + <0 0 0 0 0 0 384000000 0 0 0 404000000 0>, + <0 0 0 0 0 0 538000000 0 0 0 600000000 0>; + clock-cntl-level = "svs", "turbo"; + src-clock-name = "ife_csid_clk_src"; + clock-control-debugfs = "true"; + status = "ok"; + }; + + cam_vfe_lite: qcom,vfe-lite@acc4000 { + cell-index = <2>; + compatible = "qcom,vfe-lite170"; + reg-names = "ife-lite"; + reg = <0xacc4000 0x4000>; + reg-cam-base = <0xc4000>; + interrupt-names = "ife-lite"; + interrupts = <0 469 0>; + regulator-names = "camss"; + camss-supply = <&titan_top_gdsc>; + clock-names = "camera_ahb", + "camera_axi", + "soc_ahb_clk", + "cpas_ahb_clk", + "slow_ahb_clk_src", + "ife_clk", + "ife_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_IFE_LITE_CLK>, + <&clock_camcc CAM_CC_IFE_LITE_CLK_SRC>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>; + clock-rates = + <0 0 0 0 0 0 404000000 0>, + <0 0 0 0 0 0 480000000 0>, + <0 0 0 0 0 0 600000000 0>; + clock-cntl-level = "svs", "svs_l1", "turbo"; + src-clock-name = "ife_clk_src"; + clock-control-debugfs = "true"; + status = "ok"; + }; + + qcom,cam-icp { + compatible = "qcom,cam-icp"; + compat-hw-name = "qcom,a5", + "qcom,ipe0", + "qcom,ipe1", + "qcom,bps"; + num-a5 = <1>; + num-ipe = <2>; + num-bps = <1>; + status = "ok"; + }; + + cam_a5: qcom,a5@ac00000 { + cell-index = <0>; + compatible = "qcom,cam-a5"; + reg = <0xac00000 0x6000>, + <0xac10000 0x8000>, + <0xac18000 0x3000>; + reg-names = "a5_qgic", "a5_sierra", "a5_csr"; + reg-cam-base = <0x00000 0x10000 0x18000>; + interrupts = <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_fast_ahb", + "soc_ahb_clk", + "cpas_ahb_clk", + "camnoc_axi_clk", + "icp_clk", + "icp_clk_src"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_AXI_CLK>, + <&clock_camcc CAM_CC_FAST_AHB_CLK_SRC>, + <&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_CLK>, + <&clock_camcc CAM_CC_ICP_CLK_SRC>; + + clock-rates = + <0 0 200000000 0 0 0 0 400000000>, + <0 0 200000000 0 0 0 0 600000000>; + clock-cntl-level = "svs", "turbo"; + fw_name = "CAMERA_ICP.elf"; + ubwc-cfg = <0x7B 0x1EF>; + status = "ok"; + }; + + cam_ipe0: qcom,ipe0 { + cell-index = <0>; + compatible = "qcom,cam-ipe"; + reg = <0xac87000 0x3000>; + reg-names = "ipe0_top"; + reg-cam-base = <0x87000>; + regulator-names = "ipe0-vdd"; + ipe0-vdd-supply = <&ipe_0_gdsc>; + clock-names = "ipe_0_ahb_clk", + "ipe_0_areg_clk", + "ipe_0_axi_clk", + "ipe_0_clk", + "ipe_0_clk_src"; + 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>, + <&clock_camcc CAM_CC_IPE_0_CLK_SRC>; + + clock-rates = + <0 0 0 0 404000000>, + <0 0 0 0 480000000>, + <0 0 0 0 538000000>, + <0 0 0 0 600000000>; + clock-cntl-level = "svs", + "svs_l1", "nominal", "turbo"; + status = "ok"; + }; + + cam_ipe1: qcom,ipe1 { + cell-index = <1>; + compatible = "qcom,cam-ipe"; + reg = <0xac91000 0x3000>; + reg-names = "ipe1_top"; + reg-cam-base = <0x91000>; + regulator-names = "ipe1-vdd"; + ipe1-vdd-supply = <&ipe_1_gdsc>; + clock-names = "ipe_1_ahb_clk", + "ipe_1_areg_clk", + "ipe_1_axi_clk", + "ipe_1_clk", + "ipe_1_clk_src"; + src-clock-name = "ipe_1_clk_src"; + clock-control-debugfs = "true"; + 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 404000000>, + <0 0 0 0 480000000>, + <0 0 0 0 538000000>, + <0 0 0 0 600000000>; + clock-cntl-level = "svs", + "svs_l1", "nominal", "turbo"; + status = "ok"; + }; + + cam_bps: qcom,bps { + cell-index = <0>; + compatible = "qcom,cam-bps"; + reg = <0xac6f000 0x3000>; + reg-names = "bps_top"; + reg-cam-base = <0x6f000>; + regulator-names = "bps-vdd"; + bps-vdd-supply = <&bps_gdsc>; + clock-names = "bps_ahb_clk", + "bps_areg_clk", + "bps_axi_clk", + "bps_clk", + "bps_clk_src"; + 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>, + <&clock_camcc CAM_CC_BPS_CLK_SRC>; + + clock-rates = + <0 0 0 0 404000000>, + <0 0 0 0 480000000>, + <0 0 0 0 600000000>, + <0 0 0 0 600000000>; + clock-cntl-level = "svs", + "svs_l1", "nominal", "turbo"; + status = "ok"; + }; + + qcom,cam-jpeg { + compatible = "qcom,cam-jpeg"; + compat-hw-name = "qcom,jpegenc", + "qcom,jpegdma"; + num-jpeg-enc = <1>; + num-jpeg-dma = <1>; + status = "ok"; + }; + + cam_jpeg_enc: qcom,jpegenc@ac4e000 { + cell-index = <0>; + compatible = "qcom,cam_jpeg_enc"; + reg-names = "jpege_hw"; + reg = <0xac4e000 0x4000>; + reg-cam-base = <0x4e000>; + interrupt-names = "jpeg"; + interrupts = <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"; + }; + + qcom,cam-fd { + compatible = "qcom,cam-fd"; + compat-hw-name = "qcom,fd"; + num-fd = <1>; + status = "ok"; + }; + + cam_fd: qcom,fd@ac5a000 { + cell-index = <0>; + compatible = "qcom,fd41"; + 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-control-debugfs = "true"; + clock-cntl-level = "svs", "svs_l1", "turbo"; + clock-rates = + <0 0 0 0 0 400000000 0 0>, + <0 0 0 0 0 538000000 0 0>, + <0 0 0 0 0 600000000 0 0>; + status = "ok"; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi b/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi new file mode 100644 index 000000000000..a094f65a0402 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi @@ -0,0 +1,2457 @@ +/* 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. + */ + +&soc { + + csr: csr@6001000 { + compatible = "qcom,coresight-csr"; + reg = <0x6001000 0x1000>; + reg-names = "csr-base"; + + coresight-name = "coresight-csr"; + qcom,usb-bam-support; + qcom,hwctrl-set-support; + qcom,set-byte-cntr-support; + + qcom,blk-size = <1>; + }; + + swao_csr: csr@6b0e000 { + compatible = "qcom,coresight-csr"; + reg = <0x6b0e000 0x1000>; + reg-names = "csr-base"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + coresight-name = "coresight-swao-csr"; + qcom,timestamp-support; + + qcom,blk-size = <1>; + }; + + replicator_qdss: replicator@6046000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b909>; + + reg = <0x6046000 0x1000>; + reg-names = "replicator-base"; + + coresight-name = "coresight-replicator"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + replicator_out_tmc_etr: endpoint { + remote-endpoint= + <&tmc_etr_in_replicator>; + }; + }; + + port@1 { + reg = <0>; + replicator_in_tmc_etf: endpoint { + slave-mode; + remote-endpoint= + <&tmc_etf_out_replicator>; + }; + }; + }; + }; + + replicator_swao: replicator@6b0a000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b909>; + + reg = <0x6b0a000 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>; + + port@0 { + reg = <0>; + replicator_swao_in_tmc_etf_swao: endpoint { + slave-mode; + remote-endpoint = + <&tmc_etf_swao_out_replicator>; + }; + }; + + /* Always have EUD before funnel leading to ETR. If both + * sink are active we need to give preference to EUD + * over ETR + */ + port@1 { + reg = <1>; + replicator_swao_out_eud: endpoint { + remote-endpoint = + <&eud_in_replicator_swao>; + }; + }; + + port@2 { + reg = <0>; + replicator_swao_out_funnel_in2: endpoint { + remote-endpoint = + <&funnel_in2_in_replicator_swao>; + }; + }; + + }; + }; + + tmc_etf_swao: tmc@6b09000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b961>; + + reg = <0x6b09000 0x1000>; + reg-names = "tmc-base"; + + coresight-name = "coresight-tmc-etf-swao"; + coresight-csr = <&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: 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@0x6b08000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6b08000 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 = <6>; + funnel_swao_in_sensor_etm0: endpoint { + slave-mode; + remote-endpoint= + <&sensor_etm0_out_funnel_swao>; + }; + }; + + port@2 { + reg = <7>; + funnel_swao_in_tpda_swao: endpoint { + slave-mode; + remote-endpoint= + <&tpda_swao_out_funnel_swao>; + }; + }; + }; + }; + + tpda_swao: tpda@6b01000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x6b01000 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@6b02000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + + reg = <0x6b02000 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@6b03000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6b03000 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 = <0x0003b961>; + + reg = <0x6048000 0x1000>, + <0x6064000 0x15000>; + reg-names = "tmc-base", "bam-base"; + + arm,buffer-size = <0x400000>; + arm,sg-enable; + + coresight-name = "coresight-tmc-etr"; + coresight-ctis = <&cti0 &cti8>; + coresight-csr = <&csr>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + interrupts = ; + interrupt-names = "byte-cntr-irq"; + + port { + tmc_etr_in_replicator: endpoint { + slave-mode; + remote-endpoint = <&replicator_out_tmc_etr>; + }; + }; + }; + + tmc_etf: tmc@6047000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b961>; + + reg = <0x6047000 0x1000>; + reg-names = "tmc-base"; + + coresight-name = "coresight-tmc-etf"; + coresight-ctis = <&cti0 &cti8>; + coresight-csr = <&csr>; + arm,default-sink; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + tmc_etf_out_replicator: endpoint { + remote-endpoint = + <&replicator_in_tmc_etf>; + }; + }; + + port@1 { + reg = <1>; + tmc_etf_in_funnel_merg: endpoint { + slave-mode; + remote-endpoint = + <&funnel_merg_out_tmc_etf>; + }; + }; + }; + + }; + + funnel_merg: funnel@6045000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6045000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-merg"; + + clocks = <&clock_aop 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 = <2>; + funnel_merg_in_funnel_in2: endpoint { + slave-mode; + remote-endpoint = + <&funnel_in2_out_funnel_merg>; + }; + }; + }; + }; + + stm: stm@6002000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b962>; + + reg = <0x6002000 0x1000>, + <0x16280000 0x180000>; + reg-names = "stm-base", "stm-stimulus-base"; + + coresight-name = "coresight-stm"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + stm_out_funnel_in0: endpoint { + remote-endpoint = <&funnel_in0_in_stm>; + }; + }; + + }; + + hwevent: hwevent@0x014066f0 { + compatible = "qcom,coresight-hwevent"; + reg = <0x14066f0 0x4>, + <0x14166f0 0x4>, + <0x1406038 0x4>, + <0x1416038 0x4>; + reg-names = "ddr-ch0-cfg", "ddr-ch23-cfg", "ddr-ch0-ctrl", + "ddr-ch23-ctrl"; + + coresight-name = "coresight-hwevent"; + coresight-csr = <&csr>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + funnel_in0: funnel@0x6041000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + 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 = <3>; + funnel_in0_in_funnel_spss: endpoint { + slave-mode; + remote-endpoint = + <&funnel_spss_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_in2: funnel@0x6043000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6043000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-in2"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_in2_out_funnel_merg: endpoint { + remote-endpoint = + <&funnel_merg_in_funnel_in2>; + }; + }; + + port@1 { + reg = <0>; + funnel_in2_in_modem_etm0: endpoint { + slave-mode; + remote-endpoint = + <&modem_etm0_out_funnel_in2>; + }; + + }; + + port@2 { + reg = <1>; + funnel_in2_in_replicator_swao: endpoint { + slave-mode; + remote-endpoint = + <&replicator_swao_out_funnel_in2>; + }; + + }; + + port@3 { + reg = <2>; + funnel_in2_in_funnel_modem: endpoint { + slave-mode; + remote-endpoint = + <&funnel_modem_out_funnel_in2>; + }; + + }; + + port@4 { + reg = <5>; + funnel_in2_in_funnel_apss_merg: endpoint { + slave-mode; + remote-endpoint = + <&funnel_apss_merg_out_funnel_in2>; + }; + }; + + port@5 { + reg = <6>; + funnel_in2_in_funnel_gfx: endpoint { + slave-mode; + remote-endpoint = + <&funnel_gfx_out_funnel_in2>; + }; + }; + }; + }; + + funnel_gfx: funnel@0x6943000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6943000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-gfx"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_gfx_out_funnel_in2: endpoint { + remote-endpoint = + <&funnel_in2_in_funnel_gfx>; + }; + }; + + port@1 { + reg = <0>; + funnel_in2_in_gfx: endpoint { + slave-mode; + remote-endpoint = + <&gfx_out_funnel_in2>; + }; + }; + + port@2 { + reg = <1>; + funnel_in2_in_gfx_cx: endpoint { + slave-mode; + remote-endpoint = + <&gfx_cx_out_funnel_in2>; + }; + }; + }; + }; + + tpda: tpda@6004000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x6004000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda"; + + qcom,tpda-atid = <65>; + qcom,bc-elem-size = <10 32>, + <13 32>; + qcom,tc-elem-size = <13 32>; + qcom,dsb-elem-size = <0 32>, + <2 32>, + <3 32>, + <5 32>, + <6 32>, + <10 32>, + <11 32>, + <13 32>; + qcom,cmb-elem-size = <3 64>, + <7 64>, + <9 64>, + <13 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 = <0>; + tpda_in_tpdm_center: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_center_out_tpda>; + }; + }; + + port@2 { + reg = <2>; + tpda_in_funnel_dl_mm: endpoint { + slave-mode; + remote-endpoint = + <&funnel_dl_mm_out_tpda>; + }; + }; + + port@3 { + reg = <3>; + tpda_in_funnel_ddr_0: endpoint { + slave-mode; + remote-endpoint = + <&funnel_ddr_0_out_tpda>; + }; + }; + + port@4 { + reg = <5>; + tpda_in_funnel_lpass: endpoint { + slave-mode; + remote-endpoint = + <&funnel_lpass_out_tpda>; + }; + }; + + port@5 { + reg = <6>; + tpda_in_funnel_turing: endpoint { + slave-mode; + remote-endpoint = + <&funnel_turing_out_tpda>; + }; + }; + + port@6 { + reg = <7>; + tpda_in_tpdm_vsense: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_vsense_out_tpda>; + }; + }; + + port@7 { + reg = <9>; + tpda_in_tpdm_prng: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_prng_out_tpda>; + }; + }; + + port@8 { + reg = <10>; + tpda_in_tpdm_qm: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_qm_out_tpda>; + }; + }; + + port@9 { + reg = <11>; + tpda_in_tpdm_north: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_north_out_tpda>; + }; + }; + + port@10 { + reg = <13>; + tpda_in_tpdm_pimem: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_pimem_out_tpda>; + }; + }; + }; + }; + + funnel_modem: funnel@6832000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6832000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-modem"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_modem_out_funnel_in2: endpoint { + remote-endpoint = + <&funnel_in2_in_funnel_modem>; + }; + }; + + port@1 { + reg = <0>; + funnel_modem_in_tpda_modem: endpoint { + slave-mode; + remote-endpoint = + <&tpda_modem_out_funnel_modem>; + }; + }; + }; + }; + + tpda_modem: tpda@6831000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x6831000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-modem"; + + qcom,tpda-atid = <67>; + qcom,dsb-elem-size = <0 32>; + qcom,cmb-elem-size = <0 64>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_modem_out_funnel_modem: endpoint { + remote-endpoint = + <&funnel_modem_in_tpda_modem>; + }; + }; + + port@1 { + reg = <0>; + tpda_modem_in_tpdm_modem: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_modem_out_tpda_modem>; + }; + }; + }; + }; + + tpdm_modem: tpdm@6830000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6830000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-modem"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port { + tpdm_modem_out_tpda_modem: endpoint { + remote-endpoint = <&tpda_modem_in_tpdm_modem>; + }; + }; + }; + + funnel_lpass: funnel@6845000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6845000 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_tpda: endpoint { + remote-endpoint = + <&tpda_in_funnel_lpass>; + }; + }; + + port@1 { + reg = <0>; + funnel_lpass_in_tpdm_lpass: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_lpass_out_funnel_lpass>; + }; + }; + }; + }; + + funnel_lpass_1: funnel_1@6845000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6867010 0x10>, + <0x6845000 0x1000>; + reg-names = "funnel-base-dummy", "funnel-base-real"; + + coresight-name = "coresight-funnel-lpass-1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,duplicate-funnel; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_lpass_1_out_funnel_qatb: endpoint { + remote-endpoint = + <&funnel_qatb_in_funnel_lpass_1>; + }; + }; + + port@1 { + reg = <1>; + funnel_lpass_1_in_audio_etm0: endpoint { + slave-mode; + remote-endpoint = + <&audio_etm0_out_funnel_lpass_1>; + }; + }; + }; + }; + + tpdm_lpass: tpdm@6844000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + 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_center: tpdm@6c28000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6c28000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-center"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,msr-fix-req; + + port { + tpdm_center_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_center>; + }; + }; + }; + + tpdm_north: tpdm@6a24000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6a24000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-north"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,msr-fix-req; + + port { + tpdm_north_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_north>; + }; + }; + }; + + tpdm_qm: tpdm@69d0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + 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@7862000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x7862000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-apss"; + + qcom,tpda-atid = <66>; + qcom,dsb-elem-size = <0 32>; + + 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_apss: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_apss_out_tpda_apss>; + }; + }; + }; + }; + + tpdm_apss: tpdm@7860000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x7860000 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>; + }; + }; + }; + + tpda_llm_silver: tpda@78c0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x78c0000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-llm-silver"; + + qcom,tpda-atid = <72>; + qcom,cmb-elem-size = <0 32>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_llm_silver_out_funnel_apss_merg: endpoint { + remote-endpoint = + <&funnel_apss_merg_in_tpda_llm_silver>; + }; + }; + + port@1 { + reg = <0>; + tpda_llm_silver_in_tpdm_llm_silver: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_llm_silver_out_tpda_llm_silver>; + }; + }; + }; + }; + + tpdm_llm_silver: tpdm@78a0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + 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_llm_silver: endpoint { + remote-endpoint = + <&tpda_llm_silver_in_tpdm_llm_silver>; + }; + }; + }; + + tpda_llm_gold: tpda@78d0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x78d0000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-llm-gold"; + + qcom,tpda-atid = <73>; + qcom,cmb-elem-size = <0 32>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_llm_gold_out_funnel_apss_merg: endpoint { + remote-endpoint = + <&funnel_apss_merg_in_tpda_llm_gold>; + }; + }; + + port@1 { + reg = <0>; + tpda_llm_gold_in_tpdm_llm_gold: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_llm_gold_out_tpda_llm_gold>; + }; + }; + }; + }; + + tpdm_llm_gold: tpdm@78b0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + 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_llm_gold: endpoint { + remote-endpoint = + <&tpda_llm_gold_in_tpdm_llm_gold>; + }; + }; + }; + + funnel_dl_mm: funnel@6c0b000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + 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_tpda: endpoint { + remote-endpoint = + <&tpda_in_funnel_dl_mm>; + }; + }; + + port@1 { + reg = <1>; + funnel_dl_mm_in_tpdm_mm: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_mm_out_funnel_dl_mm>; + }; + }; + }; + }; + + tpdm_mm: tpdm@6c08000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + 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_turing: funnel@6861000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6861000 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_tpda: endpoint { + remote-endpoint = + <&tpda_in_funnel_turing>; + }; + }; + + port@1 { + reg = <0>; + funnel_turing_in_tpdm_turing: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_turing_out_funnel_turing>; + }; + }; + }; + }; + + funnel_turing_1: funnel_1@6861000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6867000 0x10>, + <0x6861000 0x1000>; + reg-names = "funnel-base-dummy", "funnel-base-real"; + + coresight-name = "coresight-funnel-turing-1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,duplicate-funnel; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_turing_1_out_funnel_qatb: endpoint { + remote-endpoint = + <&funnel_qatb_in_funnel_turing_1>; + }; + }; + + port@1 { + reg = <1>; + funnel_turing_1_in_turing_etm0: endpoint { + slave-mode; + remote-endpoint = + <&turing_etm0_out_funnel_turing_1>; + }; + }; + }; + }; + + tpdm_turing: tpdm@6860000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6860000 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>; + }; + }; + }; + + funnel_ddr_0: funnel@69e2000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x69e2000 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_tpda: endpoint { + remote-endpoint = + <&tpda_in_funnel_ddr_0>; + }; + }; + + port@1 { + reg = <0>; + funnel_ddr_0_in_tpdm_ddr: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_ddr_out_funnel_ddr_0>; + }; + }; + }; + }; + + tpdm_ddr: tpdm@69e0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x69e0000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-ddr"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + qcom,msr-fix-req; + + port { + tpdm_ddr_out_funnel_ddr_0: endpoint { + remote-endpoint = <&funnel_ddr_0_in_tpdm_ddr>; + }; + }; + }; + + tpdm_pimem: tpdm@6850000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + 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>; + }; + }; + }; + + tpdm_prng: tpdm@684c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + 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_vsense: tpdm@6840000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6840000 0x1000>; + reg-names = "tpdm-base"; + + 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>; + }; + }; + }; + + tpda_olc: tpda@7832000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x7832000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-olc"; + + qcom,tpda-atid = <69>; + qcom,cmb-elem-size = <0 64>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + tpda_olc_out_funnel_apss_merg: endpoint { + remote-endpoint = + <&funnel_apss_merg_in_tpda_olc>; + }; + }; + port@1 { + reg = <0>; + tpda_olc_in_tpdm_olc: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_olc_out_tpda_olc>; + }; + }; + }; + }; + + tpdm_olc: tpdm@7830000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x7830000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-olc"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port{ + tpdm_olc_out_tpda_olc: endpoint { + remote-endpoint = <&tpda_olc_in_tpdm_olc>; + }; + }; + }; + + tpda_spss: tpda@6882000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + reg = <0x6882000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda-spss"; + + qcom,tpda-atid = <70>; + 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_spss_out_funnel_spss: endpoint { + remote-endpoint = + <&funnel_spss_in_tpda_spss>; + }; + }; + port@1 { + reg = <0>; + tpda_spss_in_tpdm_spss: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_spss_out_tpda_spss>; + }; + }; + }; + }; + + tpdm_spss: tpdm@6880000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + reg = <0x6880000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-spss"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + port{ + tpdm_spss_out_tpda_spss: endpoint { + remote-endpoint = <&tpda_spss_in_tpdm_spss>; + }; + }; + }; + + funnel_spss: funnel@6883000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6883000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-spss"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + funnel_spss_out_funnel_in0: endpoint { + remote-endpoint = + <&funnel_in0_in_funnel_spss>; + }; + }; + + port@1 { + reg = <0>; + funnel_spss_in_tpda_spss: endpoint { + slave-mode; + remote-endpoint = + <&tpda_spss_out_funnel_spss>; + }; + }; + + port@2 { + reg = <1>; + funnel_spss_in_spss_etm0: endpoint { + slave-mode; + remote-endpoint = + <&spss_etm0_out_funnel_spss>; + }; + }; + }; + }; + + funnel_qatb: funnel@6005000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6005000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-qatb"; + + clocks = <&clock_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 = <6>; + funnel_qatb_in_funnel_lpass_1: endpoint { + slave-mode; + remote-endpoint = + <&funnel_lpass_1_out_funnel_qatb>; + }; + }; + + port@3 { + reg = <7>; + funnel_qatb_in_funnel_turing_1: endpoint { + slave-mode; + remote-endpoint = + <&funnel_turing_1_out_funnel_qatb>; + }; + }; + }; + }; + + cti0_ddr0: cti@69e1000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x69e1000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_0_cti"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_ddr1: cti@69e4000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x69e4000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_1_cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti1_ddr1: cti@69e5000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x69e5000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-ddr_dl_1_cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_dlmm: cti@6c09000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + 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 = <0x0003b966>; + reg = <0x6c0a000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-dlmm_cti1"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_apss: cti@78e0000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + 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 = <0x0003b966>; + 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 = <0x0003b966>; + reg = <0x7900000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-apss_cti2"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0: cti@6010000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + 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 = <0x0003b966>; + 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 = <0x0003b966>; + 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 = <0x0003b966>; + 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 = <0x0003b966>; + 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 = <0x0003b966>; + 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 = <0x0003b966>; + 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 = <0x0003b966>; + 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 = <0x0003b966>; + 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 = <0x0003b966>; + 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 = <0x0003b966>; + 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 = <0x0003b966>; + 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 = <0x0003b966>; + 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 = <0x0003b966>; + 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 = <0x0003b966>; + 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 = <0x0003b966>; + 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 = <0x0003b966>; + 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 = <0x0003b966>; + 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 = <0x0003b966>; + 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 = <0x0003b966>; + 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 = <0x0003b966>; + 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 = <0x0003b966>; + 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 = <0x0003b966>; + 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 = <0x0003b966>; + reg = <0x7720000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu7"; + cpu = <&CPU7>; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + cti0_swao:cti@6b04000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + reg = <0x6b04000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-swao_cti0"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + ipcb_tgu: tgu@6b0c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b999>; + reg = <0x06B0C000 0x1000>; + reg-names = "tgu-base"; + tgu-steps = <3>; + tgu-conditions = <4>; + tgu-regs = <4>; + tgu-timer-counters = <8>; + + coresight-name = "coresight-tgu-ipcb"; + + clocks = <&clock_aop QDSS_CLK>; + clock-names = "apb_pclk"; + }; + + turing_etm0 { + compatible = "qcom,coresight-remote-etm"; + + coresight-name = "coresight-turing-etm0"; + qcom,inst-id = <13>; + + port{ + turing_etm0_out_funnel_turing_1: endpoint { + remote-endpoint = + <&funnel_turing_1_in_turing_etm0>; + }; + }; + }; + + 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>; + }; + }; + }; + + sensor_etm0 { + compatible = "qcom,coresight-remote-etm"; + + coresight-name = "coresight-sensor-etm0"; + qcom,inst-id = <8>; + + port { + sensor_etm0_out_funnel_swao: endpoint { + remote-endpoint = + <&funnel_swao_in_sensor_etm0>; + }; + }; + }; + + modem_etm0 { + compatible = "qcom,coresight-remote-etm"; + + coresight-name = "coresight-modem-etm0"; + qcom,inst-id = <2>; + + port { + modem_etm0_out_funnel_in2: endpoint { + remote-endpoint = + <&funnel_in2_in_modem_etm0>; + }; + }; + }; + + audio_etm0 { + compatible = "qcom,coresight-remote-etm"; + + coresight-name = "coresight-audio-etm0"; + qcom,inst-id = <5>; + + port { + audio_etm0_out_funnel_lpass_1: endpoint { + remote-endpoint = + <&funnel_lpass_1_in_audio_etm0>; + }; + }; + }; + + spss_etm0 { + compatible = "qcom,coresight-dummy"; + + coresight-name = "coresight-spss-etm0"; + + qcom,dummy-source; + port { + spss_etm0_out_funnel_spss: endpoint { + remote-endpoint = + <&funnel_spss_in_spss_etm0>; + }; + }; + }; + + funnel_apss_merg: funnel@7810000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + 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_in2: endpoint { + remote-endpoint = + <&funnel_in2_in_funnel_apss_merg>; + }; + }; + + port@1 { + reg = <0>; + funnel_apss_merg_in_funnel_apss: endpoint { + slave-mode; + remote-endpoint = + <&funnel_apss_out_funnel_apss_merg>; + }; + }; + + port@2 { + reg = <2>; + funnel_apss_merg_in_tpda_olc: endpoint { + slave-mode; + remote-endpoint = + <&tpda_olc_out_funnel_apss_merg>; + }; + }; + + port@3 { + reg = <4>; + funnel_apss_merg_in_tpda_apss: endpoint { + slave-mode; + remote-endpoint = + <&tpda_apss_out_funnel_apss_merg>; + }; + }; + + port@4 { + reg = <5>; + funnel_apss_merg_in_tpda_llm_silver: endpoint { + slave-mode; + remote-endpoint = + <&tpda_llm_silver_out_funnel_apss_merg>; + }; + }; + + port@5 { + reg = <6>; + funnel_apss_merg_in_tpda_llm_gold: endpoint { + slave-mode; + remote-endpoint = + <&tpda_llm_gold_out_funnel_apss_merg>; + }; + }; + }; + }; + + etm0: etm@7040000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x7040000 0x1000>; + cpu = <&CPU0>; + + 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>; + + 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>; + + 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>; + + 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>; + + 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>; + + 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>; + + 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>; + + 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 = <0x0003b908>; + + 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>; + }; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi b/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi new file mode 100644 index 000000000000..d956c8f44307 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi @@ -0,0 +1,390 @@ +/* Copyright (c) 2017-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. + */ + +&soc { + + pil_gpu: qcom,kgsl-hyp { + compatible = "qcom,pil-tz-generic"; + qcom,pas-id = <13>; + qcom,firmware-name = "a630_zap"; + memory-region = <&pil_gpu_mem>; + }; + + msm_bus: qcom,kgsl-busmon{ + label = "kgsl-busmon"; + compatible = "qcom,kgsl-busmon"; + }; + + gpubw: qcom,gpubw { + compatible = "qcom,devbw"; + governor = "bw_vbif"; + qcom,src-dst-ports = <26 512>; + qcom,bw-tbl = + < 0 /* off */ >, + < 381 /* 100 MHz */ >, + < 572 /* 150 MHz */ >, + < 762 /* 200 MHz */ >, + < 1144 /* 300 MHz */ >, + < 1571 /* 412 MHz */ >, + < 2086 /* 547 MHz */ >, + < 2597 /* 681 MHz */ >, + < 2929 /* 768 MHz */ >, + < 3879 /* 1017 MHz */ >, + < 4943 /* 1296 MHz */ >, + < 5931 /* 1555 MHz */ >, + < 6881 /* 1804 MHz */ >; + }; + + msm_gpu: qcom,kgsl-3d0@5000000 { + label = "kgsl-3d0"; + compatible = "qcom,kgsl-3d0", "qcom,kgsl-3d"; + status = "ok"; + reg = <0x5000000 0x40000>, <0x5061000 0x800>, + <0x509e000 0x1000>; + reg-names = "kgsl_3d0_reg_memory", "kgsl_3d0_cx_dbgc_memory", + "cx_misc"; + interrupts = <0 300 0>; + interrupt-names = "kgsl_3d0_irq"; + qcom,id = <0>; + + qcom,chipid = <0x06030000>; + + qcom,initial-pwrlevel = <5>; + + qcom,gpu-quirk-hfi-use-reg; + qcom,gpu-quirk-secvid-set-once; + + qcom,idle-timeout = <80>; //msecs + qcom,no-nap; + + qcom,highest-bank-bit = <15>; + + qcom,min-access-length = <32>; + + qcom,ubwc-mode = <2>; + + qcom,snapshot-size = <1048576>; //bytes + + qcom,gpu-qdss-stm = <0x161c0000 0x40000>; // base addr, size + + qcom,tsens-name = "tsens_tz_sensor12"; + #cooling-cells = <2>; + + tzone-names = "gpu0-usr", "gpu1-usr"; + + qcom,pm-qos-active-latency = <460>; + + clocks = <&clock_gfx GPU_CC_GX_GFX3D_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_cpucc L3_GPU_VOTE_CLK>; + + clock-names = "core_clk", "rbbmtimer_clk", "mem_clk", + "mem_iface_clk", "gmu_clk", "l3_vote"; + + qcom,isense-clk-on-level = <1>; + + /* Bus Scale Settings */ + qcom,gpubw-dev = <&gpubw>; + qcom,bus-control; + qcom,msm-bus,name = "grp3d"; + qcom,bus-width = <32>; + qcom,msm-bus,num-cases = <13>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <26 512 0 0>, + + <26 512 0 400000>, // 1 bus=100 + <26 512 0 600000>, // 2 bus=150 + <26 512 0 800000>, // 3 bus=200 + <26 512 0 1200000>, // 4 bus=300 + <26 512 0 1648000>, // 5 bus=412 + <26 512 0 2188000>, // 6 bus=547 + <26 512 0 2724000>, // 7 bus=681 + <26 512 0 3072000>, // 8 bus=768 + <26 512 0 4068000>, // 9 bus=1017 + <26 512 0 5184000>, // 10 bus=1296 + <26 512 0 6220000>, // 11 bus=1555 + <26 512 0 7216000>; // 12 bus=1804 + + /* GDSC regulator names */ + regulator-names = "vddcx", "vdd"; + /* GDSC oxili regulators */ + vddcx-supply = <&gpu_cx_gdsc>; + vdd-supply = <&gpu_gx_gdsc>; + + /* GPU related llc slices */ + cache-slice-names = "gpu", "gpuhtw"; + cache-slices = <&llcc 12>, <&llcc 11>; + + qcom,gpu-coresights { + #address-cells = <1>; + #size-cells = <0>; + compatible = "qcom,gpu-coresight"; + + status = "disabled"; + + qcom,gpu-coresight@0 { + reg = <0>; + coresight-name = "coresight-gfx"; + coresight-atid = <50>; + port { + gfx_out_funnel_in2: endpoint { + remote-endpoint = + <&funnel_in2_in_gfx>; + }; + }; + }; + + qcom,gpu-coresight@1 { + reg = <1>; + coresight-name = "coresight-gfx-cx"; + coresight-atid = <51>; + port { + gfx_cx_out_funnel_in2: endpoint { + remote-endpoint = + <&funnel_in2_in_gfx_cx>; + }; + }; + }; + }; + + 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 = <806400000>; + }; + + qcom,l3-pwrlevel@2 { + reg = <2>; + qcom,l3-freq = <1305600000>; + }; + }; + + /* 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 = <600000000>; + qcom,bus-freq = <12>; + qcom,bus-min = <11>; + qcom,bus-max = <12>; + }; + + + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <548000000>; + qcom,bus-freq = <12>; + qcom,bus-min = <10>; + qcom,bus-max = <12>; + }; + + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <487000000>; + qcom,bus-freq = <10>; + qcom,bus-min = <9>; + qcom,bus-max = <11>; + }; + + + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <425000000>; + qcom,bus-freq = <9>; + qcom,bus-min = <8>; + qcom,bus-max = <10>; + }; + + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <338000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <7>; + qcom,bus-max = <9>; + }; + + + qcom,gpu-pwrlevel@5 { + reg = <5>; + qcom,gpu-freq = <280000000>; + qcom,bus-freq = <5>; + qcom,bus-min = <5>; + qcom,bus-max = <7>; + }; + + qcom,gpu-pwrlevel@6 { + reg = <6>; + qcom,gpu-freq = <210000000>; + qcom,bus-freq = <4>; + qcom,bus-min = <3>; + qcom,bus-max = <5>; + }; + + qcom,gpu-pwrlevel@7 { + reg = <7>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + + }; + + kgsl_msm_iommu: qcom,kgsl-iommu { + compatible = "qcom,kgsl-smmu-v2"; + + reg = <0x05040000 0x10000>; + /* CB5(ATOS) & CB5/6/7 are protected by HYP */ + qcom,protect = <0x40000 0xc000>; + qcom,micro-mmu-control = <0x6000>; + + clocks =<&clock_gcc GCC_GPU_CFG_AHB_CLK>, + <&clock_gcc GCC_DDRSS_GPU_AXI_CLK>, + <&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>; + + clock-names = "iface_clk", "mem_clk", "mem_iface_clk"; + + qcom,secure_align_mask = <0xfff>; + qcom,retention; + qcom,hyp_secure_alloc; + + gfx3d_user: gfx3d_user { + compatible = "qcom,smmu-kgsl-cb"; + label = "gfx3d_user"; + iommus = <&kgsl_smmu 0>; + qcom,gpu-offset = <0x48000>; + }; + + gfx3d_secure: gfx3d_secure { + compatible = "qcom,smmu-kgsl-cb"; + iommus = <&kgsl_smmu 2>, <&kgsl_smmu 1>; + }; + }; + + gmu: qcom,gmu { + label = "kgsl-gmu"; + compatible = "qcom,gpu-gmu"; + + reg = <0x506a000 0x30000>, <0xb200000 0x300000>; + reg-names = "kgsl_gmu_reg", "kgsl_gmu_pdc_reg"; + + interrupts = <0 304 0>, <0 305 0>; + 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-names = "gmu_clk", "cxo_clk", "axi_clk", + "memnoc_clk"; + + qcom,gmu-pwrlevels { + #address-cells = <1>; + #size-cells = <0>; + + compatible = "qcom,gmu-pwrlevels"; + + /* GMU power levels must go from lowest to highest */ + qcom,gmu-pwrlevel@0 { + reg = <0>; + qcom,gmu-freq = <0>; + }; + + qcom,gmu-pwrlevel@1 { + reg = <1>; + qcom,gmu-freq = <200000000>; + }; + + qcom,gmu-pwrlevel@2 { + reg = <2>; + qcom,gmu-freq = <400000000>; + }; + }; + + gmu_user: gmu_user { + compatible = "qcom,smmu-gmu-user-cb"; + iommus = <&kgsl_smmu 4>; + }; + + gmu_kernel: gmu_kernel { + compatible = "qcom,smmu-gmu-kernel-cb"; + iommus = <&kgsl_smmu 5>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-ion.dtsi b/arch/arm64/boot/dts/qcom/sdm845-ion.dtsi new file mode 100644 index 000000000000..7d8318497c50 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-ion.dtsi @@ -0,0 +1,59 @@ +/* Copyright (c) 2016-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. + */ + +&soc { + qcom,ion { + compatible = "qcom,msm-ion"; + #address-cells = <1>; + #size-cells = <0>; + + system_heap: qcom,ion-heap@25 { + reg = <25>; + qcom,ion-heap-type = "SYSTEM"; + }; + + qcom,ion-heap@22 { /* ADSP HEAP */ + reg = <22>; + memory-region = <&adsp_mem>; + qcom,ion-heap-type = "DMA"; + }; + + qcom,ion-heap@27 { /* QSEECOM HEAP */ + reg = <27>; + memory-region = <&qseecom_mem>; + qcom,ion-heap-type = "DMA"; + }; + + qcom,ion-heap@19 { /* QSEECOM TA HEAP */ + reg = <19>; + memory-region = <&qseecom_ta_mem>; + qcom,ion-heap-type = "DMA"; + }; + + qcom,ion-heap@13 { /* SECURE SPSS HEAP */ + reg = <13>; + memory-region = <&secure_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@9 { + reg = <9>; + qcom,ion-heap-type = "SYSTEM_SECURE"; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-mtp-overlay.dts new file mode 100644 index 000000000000..2d1d9b637c9f --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-mtp-overlay.dts @@ -0,0 +1,31 @@ +/* Copyright (c) 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. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-mtp.dtsi" +#include "sdm845-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM845 v1 MTP"; + compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp"; + qcom,msm-id = <321 0x10000>; + qcom,board-id = <8 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-mtp.dts b/arch/arm64/boot/dts/qcom/sdm845-mtp.dts index 6921f8dc5ebb..e74b342e521b 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-mtp.dts +++ b/arch/arm64/boot/dts/qcom/sdm845-mtp.dts @@ -1,64 +1,24 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * SDM845 MTP board device tree source +/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. * - * 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. */ + /dts-v1/; #include "sdm845.dtsi" +#include "sdm845-sde-display.dtsi" +#include "sdm845-mtp.dtsi" / { - model = "Qualcomm Technologies, Inc. SDM845 MTP"; - compatible = "qcom,sdm845-mtp"; - - aliases { - serial0 = &uart9; - }; - - chosen { - stdout-path = "serial0:115200n8"; - }; -}; - -&i2c10 { - status = "okay"; - clock-frequency = <400000>; -}; - -&qupv3_id_1 { - status = "okay"; -}; - -&tlmm { - gpio-reserved-ranges = <0 4>, <81 4>; -}; - -&uart9 { - status = "okay"; -}; - -/* PINCTRL - additions to nodes defined in sdm845.dtsi */ - -&qup_i2c10_default { - pinconf { - pins = "gpio55", "gpio56"; - drive-strength = <2>; - bias-disable; - }; -}; - -&qup_uart9_default { - pinconf-tx { - pins = "gpio4"; - drive-strength = <2>; - bias-disable; - }; - - pinconf-rx { - pins = "gpio5"; - drive-strength = <2>; - bias-pull-up; - }; + model = "Qualcomm Technologies, Inc. MSM sdm845 v1 MTP"; + compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp"; + qcom,board-id = <8 0>; }; diff --git a/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi new file mode 100644 index 000000000000..a776b1b60df8 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi @@ -0,0 +1,549 @@ +/* Copyright (c) 2016-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. + */ + +#include +#include "sdm845-pmic-overlay.dtsi" +#include "sdm845-pinctrl-overlay.dtsi" +#include "sdm845-camera-sensor-mtp.dtsi" + +&qupv3_se10_i2c { +#include "smb1355.dtsi" +}; + +&vendor { + bluetooth: bt_wcn3990 { + compatible = "qca,wcn3990"; + qca,bt-vdd-io-supply = <&pm8998_s3>; + qca,bt-vdd-xtal-supply = <&pm8998_s5>; + qca,bt-vdd-core-supply = <&pm8998_l7>; + qca,bt-vdd-pa-supply = <&pm8998_l17>; + qca,bt-vdd-ldo-supply = <&pm8998_l25>; + + qca,bt-vdd-io-voltage-level = <1352000 1352000>; + qca,bt-vdd-xtal-voltage-level = <2040000 2040000>; + qca,bt-vdd-core-voltage-level = <1800000 1800000>; + qca,bt-vdd-pa-voltage-level = <1304000 1304000>; + qca,bt-vdd-ldo-voltage-level = <3312000 3312000>; + + qca,bt-vdd-io-current-level = <1>; /* LPM/PFM */ + qca,bt-vdd-xtal-current-level = <1>; /* LPM/PFM */ + qca,bt-vdd-core-current-level = <1>; /* LPM/PFM */ + qca,bt-vdd-pa-current-level = <1>; /* LPM/PFM */ + qca,bt-vdd-ldo-current-level = <1>; /* LPM/PFM */ + }; +}; + +&soc { + gpio_keys { + compatible = "gpio-keys"; + label = "gpio-keys"; + + pinctrl-names = "default"; + pinctrl-0 = <&key_vol_up_default + &key_cam_snapshot_default + &key_cam_focus_default>; + + vol_up { + label = "volume_up"; + gpios = <&pm8998_gpios 6 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = <115>; + gpio-key,wakeup; + debounce-interval = <15>; + linux,can-disable; + }; + + cam_snapshot { + label = "cam_snapshot"; + gpios = <&pm8998_gpios 7 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = <766>; + gpio-key,wakeup; + debounce-interval = <15>; + linux,can-disable; + }; + + cam_focus { + label = "cam_focus"; + gpios = <&pm8998_gpios 8 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = <528>; + gpio-key,wakeup; + debounce-interval = <15>; + linux,can-disable; + }; + }; +}; + +&labibb { + status = "ok"; + qcom,qpnp-labibb-mode = "lcd"; +}; + +&dsi_dual_nt35597_truly_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_dual_nt35597_truly_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; +}; + +&dsi_nt35597_truly_dsc_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "single_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_nt35597_truly_dsc_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "single_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; +}; + +&dsi_sim_vid { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_dual_sim_vid { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_sim_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_dual_sim_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_sim_dsc_375_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_dual_sim_dsc_375_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_dual_nt35597_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_dual_nt35597_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <4095>; + qcom,mdss-dsi-mode-sel-gpio-state = "dual_port"; + qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,platform-te-gpio = <&tlmm 10 0>; +}; + +&dsi_nt35597_truly_dsc_cmd_display { + qcom,dsi-display-active; +}; + +&pmi8998_wled { + status = "okay"; + qcom,led-strings-list = [01 02]; +}; + +&pmi8998_haptics { + qcom,vmax-mv = <2400>; + qcom,lra-auto-mode; + status = "okay"; +}; + +&mdss_mdp { + #cooling-cells = <2>; +}; + +&ufsphy_mem { + compatible = "qcom,ufs-phy-qmp-v3"; + + vdda-phy-supply = <&pm8998_l1>; /* 0.88v */ + vdda-pll-supply = <&pm8998_l26>; /* 1.2v */ + vdda-phy-max-microamp = <62900>; + vdda-pll-max-microamp = <18300>; + + status = "ok"; +}; + +&ufshc_mem { + vdd-hba-supply = <&ufs_phy_gdsc>; + vdd-hba-fixed-regulator; + vcc-supply = <&pm8998_l20>; + vcc-voltage-level = <2950000 2960000>; + vccq2-supply = <&pm8998_s4>; + vcc-max-microamp = <600000>; + vccq2-max-microamp = <600000>; + + qcom,vddp-ref-clk-supply = <&pm8998_l2>; + qcom,vddp-ref-clk-max-microamp = <100>; + + status = "ok"; +}; + +&sdhc_2 { + vdd-supply = <&pm8998_l21>; + qcom,vdd-voltage-level = <2950000 2960000>; + qcom,vdd-current-level = <200 800000>; + + vdd-io-supply = <&pm8998_l13>; + qcom,vdd-io-voltage-level = <1808000 2960000>; + qcom,vdd-io-current-level = <200 22000>; + + pinctrl-names = "active", "sleep", "ds_400KHz", + "ds_50MHz", "ds_100MHz", "ds_200MHz"; + 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>; + pinctrl-2 = <&sdc2_clk_ds_400KHz + &sdc2_cmd_ds_400KHz &sdc2_data_ds_400KHz>; + pinctrl-3 = <&sdc2_clk_ds_50MHz + &sdc2_cmd_ds_50MHz &sdc2_data_ds_50MHz>; + pinctrl-4 = <&sdc2_clk_ds_100MHz + &sdc2_cmd_ds_100MHz &sdc2_data_ds_100MHz>; + pinctrl-5 = <&sdc2_clk_ds_200MHz + &sdc2_cmd_ds_200MHz &sdc2_data_ds_200MHz>; + + cd-gpios = <&tlmm 126 GPIO_ACTIVE_LOW>; + + status = "ok"; +}; + +&pmi8998_switch1 { + pinctrl-names = "led_enable", "led_disable"; + pinctrl-0 = <&flash_led3_front_en>; + pinctrl-1 = <&flash_led3_front_dis>; +}; + +&pmi8998_switch2 { + pinctrl-names = "led_enable", "led_disable"; + pinctrl-0 = <&flash_led3_iris_en>; + pinctrl-1 = <&flash_led3_iris_dis>; +}; + +&vendor { + mtp_batterydata: qcom,battery-data { + qcom,batt-id-range-pct = <15>; + #include "fg-gen3-batterydata-itech-3000mah.dtsi" + #include "fg-gen3-batterydata-ascent-3450mah.dtsi" + #include "fg-gen3-batterydata-demo-6000mah.dtsi" + }; + + extcon_usb1: extcon_usb1 { + compatible = "linux,extcon-usb-gpio"; + vbus-gpio = <&pmi8998_gpios 8 GPIO_ACTIVE_HIGH>; + + pinctrl-names = "default"; + pinctrl-0 = <&usb2_vbus_det_default>; + }; +}; + +&pmi8998_fg { + qcom,battery-data = <&mtp_batterydata>; +}; + +&smb1355_charger_0 { + status = "ok"; + qcom,disable-ctm; +}; + +&smb1355_charger_1 { + status = "ok"; + qcom,disable-ctm; +}; + +&qupv3_se9_2uart { + status = "ok"; +}; + +&qupv3_se8_spi { + status = "ok"; +}; + +&qupv3_se3_i2c { + status = "ok"; + nq@28 { + compatible = "qcom,nq-nci"; + reg = <0x28>; + qcom,nq-irq = <&tlmm 63 0x00>; + qcom,nq-ven = <&tlmm 12 0x00>; + qcom,nq-firm = <&tlmm 62 0x00>; + qcom,nq-clkreq = <&pm8998_gpios 21 0x00>; + qcom,nq-esepwr = <&tlmm 116 0x00>; + interrupt-parent = <&tlmm>; + interrupts = <63 0>; + interrupt-names = "nfc_irq"; + pinctrl-names = "nfc_active", "nfc_suspend"; + pinctrl-0 = <&nfc_int_active + &nfc_enable_active + &nfc_clk_default>; + pinctrl-1 = <&nfc_int_suspend &nfc_enable_suspend>; + }; +}; + +&qupv3_se10_i2c { + status = "ok"; +}; + +&qupv3_se6_4uart { + status = "ok"; +}; + +&usb1 { + extcon = <&extcon_usb1>; +}; + +&ext_5v_boost { + status = "ok"; +}; + +&pm8998_vadc { + chan@83 { + label = "vph_pwr"; + reg = <0x83>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <1>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@85 { + label = "vcoin"; + reg = <0x85>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <1>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + }; + + chan@4c { + label = "xo_therm"; + reg = <0x4c>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <4>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + }; + + chan@4d { + label = "msm_therm"; + reg = <0x4d>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + }; + + chan@4f { + label = "pa_therm1"; + reg = <0x4f>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + }; + + chan@51 { + label = "quiet_therm"; + reg = <0x51>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + }; +}; + +&pm8998_adc_tm { + chan@83 { + label = "vph_pwr"; + reg = <0x83>; + qcom,pre-div-channel-scaling = <1>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <0>; + qcom,btm-channel-number = <0x60>; + }; + + chan@4c { + label = "xo_therm"; + reg = <0x4c>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <4>; + qcom,hw-settle-time = <2>; + qcom,btm-channel-number = <0x68>; + qcom,thermal-node; + }; + + chan@4d { + label = "msm_therm"; + reg = <0x4d>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,btm-channel-number = <0x70>; + qcom,thermal-node; + }; + + chan@4f { + label = "pa_therm1"; + reg = <0x4f>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,btm-channel-number = <0x78>; + qcom,thermal-node; + }; + + chan@51 { + label = "quiet_therm"; + reg = <0x51>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,btm-channel-number = <0x80>; + qcom,thermal-node; + }; +}; + +&thermal_zones { + xo-therm-adc { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&pm8998_adc_tm 0x4c>; + wake-capable-sensor; + thermal-governor = "user_space"; + + trips { + active-config0 { + temperature = <125000>; + hysteresis = <10000>; + type = "passive"; + }; + + thermal-hal-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + msm-therm-adc { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&pm8998_adc_tm 0x4d>; + wake-capable-sensor; + thermal-governor = "user_space"; + + trips { + active-config0 { + temperature = <125000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + }; + + pa-therm1-adc { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&pm8998_adc_tm 0x4f>; + wake-capable-sensor; + thermal-governor = "user_space"; + + trips { + active-config0 { + temperature = <125000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + }; + + quiet-therm-adc { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&pm8998_adc_tm 0x51>; + wake-capable-sensor; + thermal-governor = "user_space"; + + trips { + active-config0 { + temperature = <125000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + }; +}; + +&wil6210 { + status = "ok"; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-pcie.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pcie.dtsi new file mode 100644 index 000000000000..c00c264649c7 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-pcie.dtsi @@ -0,0 +1,552 @@ +/* + * 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. + */ + +#include + +&soc { + pcie0: qcom,pcie@0x1c00000 { + compatible = "qcom,pci-msm"; + cell-index = <0>; + + reg = <0x1c00000 0x2000>, + <0x1c06000 0x1000>, + <0x60000000 0xf1d>, + <0x60000f20 0xa8>, + <0x60100000 0x100000>, + <0x60200000 0x100000>, + <0x60300000 0xd00000>; + + reg-names = "parf", "phy", "dm_core", "elbi", + "conf", "io", "bars"; + + #address-cells = <3>; + #size-cells = <2>; + ranges = <0x01000000 0x0 0x60200000 0x60200000 0x0 0x100000>, + <0x02000000 0x0 0x60300000 0x60300000 0x0 0xd00000>; + interrupt-parent = <&pcie0>; + interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 + 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 + 36 37>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0xffffffff>; + interrupt-map = <0 0 0 0 &pdc 0 141 0 + 0 0 0 1 &pdc 0 149 0 + 0 0 0 2 &pdc 0 150 0 + 0 0 0 3 &pdc 0 151 0 + 0 0 0 4 &pdc 0 152 0 + 0 0 0 5 &pdc 0 140 0 + 0 0 0 6 &pdc 0 672 0 + 0 0 0 7 &pdc 0 673 0 + 0 0 0 8 &pdc 0 674 0 + 0 0 0 9 &pdc 0 675 0 + 0 0 0 10 &pdc 0 676 0 + 0 0 0 11 &pdc 0 677 0 + 0 0 0 12 &pdc 0 678 0 + 0 0 0 13 &pdc 0 679 0 + 0 0 0 14 &pdc 0 680 0 + 0 0 0 15 &pdc 0 681 0 + 0 0 0 16 &pdc 0 682 0 + 0 0 0 17 &pdc 0 683 0 + 0 0 0 18 &pdc 0 684 0 + 0 0 0 19 &pdc 0 685 0 + 0 0 0 20 &pdc 0 686 0 + 0 0 0 21 &pdc 0 687 0 + 0 0 0 22 &pdc 0 688 0 + 0 0 0 23 &pdc 0 689 0 + 0 0 0 24 &pdc 0 690 0 + 0 0 0 25 &pdc 0 691 0 + 0 0 0 26 &pdc 0 692 0 + 0 0 0 27 &pdc 0 693 0 + 0 0 0 28 &pdc 0 694 0 + 0 0 0 29 &pdc 0 695 0 + 0 0 0 30 &pdc 0 696 0 + 0 0 0 31 &pdc 0 697 0 + 0 0 0 32 &pdc 0 698 0 + 0 0 0 33 &pdc 0 699 0 + 0 0 0 34 &pdc 0 700 0 + 0 0 0 35 &pdc 0 701 0 + 0 0 0 36 &pdc 0 702 0 + 0 0 0 37 &pdc 0 703 0>; + + interrupt-names = "int_msi", "int_a", "int_b", "int_c", + "int_d", "int_global_int", + "msi_0", "msi_1", "msi_2", "msi_3", + "msi_4", "msi_5", "msi_6", "msi_7", + "msi_8", "msi_9", "msi_10", "msi_11", + "msi_12", "msi_13", "msi_14", "msi_15", + "msi_16", "msi_17", "msi_18", "msi_19", + "msi_20", "msi_21", "msi_22", "msi_23", + "msi_24", "msi_25", "msi_26", "msi_27", + "msi_28", "msi_29", "msi_30", "msi_31"; + + qcom,phy-sequence = <0x804 0x01 0x0 + 0x034 0x14 0x0 + 0x138 0x30 0x0 + 0x048 0x07 0x0 + 0x15c 0x06 0x0 + 0x090 0x01 0x0 + 0x088 0x20 0x0 + 0x0f0 0x00 0x0 + 0x0f8 0x01 0x0 + 0x0f4 0xc9 0x0 + 0x11c 0xff 0x0 + 0x120 0x3f 0x0 + 0x164 0x01 0x0 + 0x154 0x00 0x0 + 0x148 0x0a 0x0 + 0x05c 0x19 0x0 + 0x038 0x90 0x0 + 0x0b0 0x82 0x0 + 0x0c0 0x02 0x0 + 0x0bc 0xea 0x0 + 0x0b8 0xab 0x0 + 0x0a0 0x00 0x0 + 0x09c 0x0d 0x0 + 0x098 0x04 0x0 + 0x13c 0x00 0x0 + 0x060 0x06 0x0 + 0x068 0x16 0x0 + 0x070 0x36 0x0 + 0x184 0x01 0x0 + 0x138 0x33 0x0 + 0x03c 0x02 0x0 + 0x040 0x06 0x0 + 0x080 0x04 0x0 + 0x0dc 0x00 0x0 + 0x0d8 0x3f 0x0 + 0x00c 0x09 0x0 + 0x010 0x01 0x0 + 0x01c 0x40 0x0 + 0x020 0x01 0x0 + 0x014 0x02 0x0 + 0x018 0x00 0x0 + 0x024 0x7e 0x0 + 0x028 0x15 0x0 + 0x244 0x02 0x0 + 0x2a4 0x12 0x0 + 0x260 0x10 0x0 + 0x28c 0x06 0x0 + 0x504 0x03 0x0 + 0x500 0x10 0x0 + 0x50c 0x14 0x0 + 0x4d4 0x0e 0x0 + 0x4d8 0x04 0x0 + 0x4dc 0x1a 0x0 + 0x434 0x4b 0x0 + 0x414 0x04 0x0 + 0x40c 0x04 0x0 + 0x4f8 0x71 0x0 + 0x564 0x59 0x0 + 0x568 0x59 0x0 + 0x4fc 0x80 0x0 + 0x51c 0x40 0x0 + 0x444 0x71 0x0 + 0x43c 0x40 0x0 + 0x854 0x04 0x0 + 0x62c 0x52 0x0 + 0x654 0x10 0x0 + 0x65c 0x1a 0x0 + 0x660 0x06 0x0 + 0x8c8 0x83 0x0 + 0x8cc 0x09 0x0 + 0x8d0 0xa2 0x0 + 0x8d4 0x40 0x0 + 0x8c4 0x02 0x0 + 0x9ac 0x00 0x0 + 0x8a0 0x01 0x0 + 0x9e0 0x00 0x0 + 0x9dc 0x20 0x0 + 0x9a8 0x00 0x0 + 0x8a4 0x01 0x0 + 0x8a8 0x73 0x0 + 0x9d8 0xbb 0x0 + 0x9b0 0x03 0x0 + 0xa0c 0x0d 0x0 + 0x86c 0x00 0x0 + 0x644 0x00 0x0 + 0x804 0x03 0x0 + 0x800 0x00 0x0 + 0x808 0x03 0x0>; + + pinctrl-names = "default"; + pinctrl-0 = <&pcie0_clkreq_default + &pcie0_perst_default + &pcie0_wake_default>; + + perst-gpio = <&tlmm 35 0>; + wake-gpio = <&tlmm 37 0>; + + gdsc-vdd-supply = <&pcie_0_gdsc>; + vreg-1.8-supply = <&pm8998_l26>; + vreg-0.9-supply = <&pm8998_l1>; + vreg-cx-supply = <&pm8998_s9_level>; + + qcom,vreg-1.8-voltage-level = <1200000 1200000 24000>; + qcom,vreg-0.9-voltage-level = <880000 880000 24000>; + qcom,vreg-cx-voltage-level = ; + + qcom,l1-supported; + qcom,l1ss-supported; + qcom,aux-clk-sync; + + qcom,ep-latency = <10>; + + qcom,phy-status-offset = <0x974>; + + qcom,boot-option = <0x1>; + + linux,pci-domain = <0>; + + qcom,msi-gicm-addr = <0x17a00040>; + qcom,msi-gicm-base = <0x2c0>; + + qcom,pcie-phy-ver = <0x30>; + qcom,use-19p2mhz-aux-clk; + + qcom,smmu-sid-base = <0x1c10>; + + iommu-map = <0x0 &apps_smmu 0x1c10 0x1>, + <0x100 &apps_smmu 0x1c11 0x1>, + <0x200 &apps_smmu 0x1c12 0x1>, + <0x300 &apps_smmu 0x1c13 0x1>, + <0x400 &apps_smmu 0x1c14 0x1>, + <0x500 &apps_smmu 0x1c15 0x1>, + <0x600 &apps_smmu 0x1c16 0x1>, + <0x700 &apps_smmu 0x1c17 0x1>, + <0x800 &apps_smmu 0x1c18 0x1>, + <0x900 &apps_smmu 0x1c19 0x1>, + <0xa00 &apps_smmu 0x1c1a 0x1>, + <0xb00 &apps_smmu 0x1c1b 0x1>, + <0xc00 &apps_smmu 0x1c1c 0x1>, + <0xd00 &apps_smmu 0x1c1d 0x1>, + <0xe00 &apps_smmu 0x1c1e 0x1>, + <0xf00 &apps_smmu 0x1c1f 0x1>; + + qcom,msm-bus,name = "pcie0"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <45 512 0 0>, + <45 512 500 800>; + + clocks = <&clock_gcc GCC_PCIE_0_PIPE_CLK>, + <&clock_rpmh RPMH_CXO_CLK>, + <&clock_gcc GCC_PCIE_0_AUX_CLK>, + <&clock_gcc GCC_PCIE_0_CFG_AHB_CLK>, + <&clock_gcc GCC_PCIE_0_MSTR_AXI_CLK>, + <&clock_gcc GCC_PCIE_0_SLV_AXI_CLK>, + <&clock_gcc GCC_PCIE_0_CLKREF_CLK>, + <&clock_gcc GCC_PCIE_0_SLV_Q2A_AXI_CLK>, + <&clock_gcc GCC_AGGRE_NOC_PCIE_TBU_CLK>, + <&clock_gcc GCC_PCIE_PHY_REFGEN_CLK>, + <&clock_gcc GCC_PCIE_PHY_AUX_CLK>; + + clock-names = "pcie_0_pipe_clk", "pcie_0_ref_clk_src", + "pcie_0_aux_clk", "pcie_0_cfg_ahb_clk", + "pcie_0_mstr_axi_clk", "pcie_0_slv_axi_clk", + "pcie_0_ldo", "pcie_0_slv_q2a_axi_clk", + "pcie_tbu_clk", "pcie_phy_refgen_clk", + "pcie_phy_aux_clk"; + + max-clock-frequency-hz = <0>, <0>, <19200000>, <0>, <0>, <0>, + <0>, <0>, <0>, <0>, <100000000>, <0>; + + resets = <&clock_gcc GCC_PCIE_0_BCR>, + <&clock_gcc GCC_PCIE_0_PHY_BCR>; + + reset-names = "pcie_0_core_reset", + "pcie_0_phy_reset"; + }; + + pcie1: qcom,pcie@0x1c08000 { + compatible = "qcom,pci-msm"; + cell-index = <1>; + + reg = <0x1c08000 0x2000>, + <0x1c0a000 0x2000>, + <0x40000000 0xf1d>, + <0x40000f20 0xa8>, + <0x40100000 0x100000>, + <0x40200000 0x100000>, + <0x40300000 0x1fd00000>; + + reg-names = "parf", "phy", "dm_core", "elbi", + "conf", "io", "bars"; + + #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 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>; + #interrupt-cells = <1>; + interrupt-map-mask = <0 0 0 0xffffffff>; + interrupt-map = <0 0 0 0 &intc 0 307 0 + 0 0 0 1 &intc 0 434 0 + 0 0 0 2 &intc 0 435 0 + 0 0 0 3 &intc 0 438 0 + 0 0 0 4 &intc 0 439 0 + 0 0 0 5 &intc 0 306 0 + 0 0 0 6 &intc 0 704 0 + 0 0 0 7 &intc 0 705 0 + 0 0 0 8 &intc 0 706 0 + 0 0 0 9 &intc 0 707 0 + 0 0 0 10 &intc 0 708 0 + 0 0 0 11 &intc 0 709 0 + 0 0 0 12 &intc 0 710 0 + 0 0 0 13 &intc 0 711 0 + 0 0 0 14 &intc 0 712 0 + 0 0 0 15 &intc 0 713 0 + 0 0 0 16 &intc 0 714 0 + 0 0 0 17 &intc 0 715 0 + 0 0 0 18 &intc 0 716 0 + 0 0 0 19 &intc 0 717 0 + 0 0 0 20 &intc 0 718 0 + 0 0 0 21 &intc 0 719 0 + 0 0 0 22 &intc 0 720 0 + 0 0 0 23 &intc 0 721 0 + 0 0 0 24 &intc 0 722 0 + 0 0 0 25 &intc 0 723 0 + 0 0 0 26 &intc 0 724 0 + 0 0 0 27 &intc 0 725 0 + 0 0 0 28 &intc 0 726 0 + 0 0 0 29 &intc 0 727 0 + 0 0 0 30 &intc 0 728 0 + 0 0 0 31 &intc 0 729 0 + 0 0 0 32 &intc 0 730 0 + 0 0 0 33 &intc 0 731 0 + 0 0 0 34 &intc 0 732 0 + 0 0 0 35 &intc 0 733 0 + 0 0 0 36 &intc 0 734 0 + 0 0 0 37 &intc 0 735 0>; + + interrupt-names = "int_msi", "int_a", "int_b", "int_c", + "int_d", "int_global_int", + "msi_0", "msi_1", "msi_2", "msi_3", + "msi_4", "msi_5", "msi_6", "msi_7", + "msi_8", "msi_9", "msi_10", "msi_11", + "msi_12", "msi_13", "msi_14", "msi_15", + "msi_16", "msi_17", "msi_18", "msi_19", + "msi_20", "msi_21", "msi_22", "msi_23", + "msi_24", "msi_25", "msi_26", "msi_27", + "msi_28", "msi_29", "msi_30", "msi_31"; + + qcom,phy-sequence = <0x1804 0x03 0x0 + 0x00dc 0x27 0x0 + 0x0014 0x01 0x0 + 0x0020 0x31 0x0 + 0x0024 0x01 0x0 + 0x0028 0xde 0x0 + 0x002c 0x07 0x0 + 0x0034 0x4c 0x0 + 0x0038 0x06 0x0 + 0x0054 0x18 0x0 + 0x0058 0xb0 0x0 + 0x006c 0x8c 0x0 + 0x0070 0x20 0x0 + 0x0078 0x14 0x0 + 0x007c 0x34 0x0 + 0x00b4 0x06 0x0 + 0x00b8 0x06 0x0 + 0x00c0 0x16 0x0 + 0x00c4 0x16 0x0 + 0x00cc 0x36 0x0 + 0x00d0 0x36 0x0 + 0x00f0 0x05 0x0 + 0x00f8 0x42 0x0 + 0x0100 0x82 0x0 + 0x0108 0x68 0x0 + 0x011c 0x55 0x0 + 0x0120 0x55 0x0 + 0x0124 0x03 0x0 + 0x0128 0xab 0x0 + 0x012c 0xaa 0x0 + 0x0130 0x02 0x0 + 0x0150 0x3f 0x0 + 0x0158 0x3f 0x0 + 0x0178 0x10 0x0 + 0x01cc 0x04 0x0 + 0x01d0 0x30 0x0 + 0x01e0 0x04 0x0 + 0x01e8 0x73 0x0 + 0x01f0 0x0c 0x0 + 0x01fc 0x15 0x0 + 0x021c 0x04 0x0 + 0x0224 0x01 0x0 + 0x0228 0x22 0x0 + 0x022c 0x00 0x0 + 0x0098 0x20 0x0 + 0x01c8 0x07 0x0 + 0x080c 0x00 0x0 + 0x0818 0x0d 0x0 + 0x0860 0x01 0x0 + 0x0864 0x1a 0x0 + 0x087c 0x2f 0x0 + 0x08c0 0x09 0x0 + 0x08c4 0x09 0x0 + 0x08c8 0x1b 0x0 + 0x08d0 0x01 0x0 + 0x08d4 0x07 0x0 + 0x08d8 0x31 0x0 + 0x08dc 0x31 0x0 + 0x08e0 0x03 0x0 + 0x08fc 0x02 0x0 + 0x0900 0x00 0x0 + 0x0908 0x12 0x0 + 0x0914 0x25 0x0 + 0x0918 0x00 0x0 + 0x091c 0x05 0x0 + 0x0920 0x01 0x0 + 0x0924 0x26 0x0 + 0x0928 0x12 0x0 + 0x0930 0x04 0x0 + 0x0934 0x04 0x0 + 0x0938 0x09 0x0 + 0x0954 0x15 0x0 + 0x0960 0x28 0x0 + 0x0968 0x7f 0x0 + 0x096c 0x07 0x0 + 0x0978 0x04 0x0 + 0x0980 0x70 0x0 + 0x0984 0x8b 0x0 + 0x0988 0x08 0x0 + 0x098c 0x0a 0x0 + 0x0990 0x03 0x0 + 0x0994 0x04 0x0 + 0x0998 0x04 0x0 + 0x099c 0x0c 0x0 + 0x09a4 0x02 0x0 + 0x09c0 0x5c 0x0 + 0x09c4 0x3e 0x0 + 0x09c8 0x3f 0x0 + 0x0a30 0x01 0x0 + 0x0a34 0xa0 0x0 + 0x0a38 0x08 0x0 + 0x0aa4 0x01 0x0 + 0x0aac 0xc3 0x0 + 0x0ab0 0x00 0x0 + 0x0ab8 0xbc 0x0 + 0x0ac0 0x7f 0x0 + 0x0ac4 0x15 0x0 + 0x0810 0x0c 0x0 + 0x0814 0x0f 0x0 + 0x0acc 0x04 0x0 + 0x093c 0x20 0x0 + 0x195c 0x3f 0x0 + 0x1974 0x50 0x0 + 0x182c 0x19 0x0 + 0x1840 0x07 0x0 + 0x1854 0x17 0x0 + 0x1868 0x09 0x0 + 0x196c 0x9f 0x0 + 0x1800 0x00 0x0 + 0x0aa8 0x01 0x0 + 0x1808 0x01 0x0>; + + pinctrl-names = "default"; + pinctrl-0 = <&pcie1_clkreq_default + &pcie1_perst_default + &pcie1_wake_default>; + + perst-gpio = <&tlmm 102 0>; + wake-gpio = <&tlmm 104 0>; + + gdsc-vdd-supply = <&pcie_1_gdsc>; + vreg-1.8-supply = <&pm8998_l26>; + vreg-0.9-supply = <&pm8998_l1>; + vreg-cx-supply = <&pm8998_s9_level>; + + qcom,vreg-1.8-voltage-level = <1200000 1200000 24000>; + qcom,vreg-0.9-voltage-level = <880000 880000 24000>; + qcom,vreg-cx-voltage-level = ; + + qcom,l1-supported; + qcom,l1ss-supported; + qcom,aux-clk-sync; + + qcom,ep-latency = <10>; + + qcom,slv-addr-space-size = <0x20000000>; + + qcom,phy-status-offset = <0x1aac>; + + qcom,boot-option = <0x1>; + + linux,pci-domain = <1>; + + qcom,msi-gicm-addr = <0x17a00040>; + qcom,msi-gicm-base = <0x2e0>; + + qcom,max-link-speed = <0x3>; + + qcom,use-19p2mhz-aux-clk; + + qcom,smmu-sid-base = <0x1c00>; + + iommu-map = <0x0 &apps_smmu 0x1c00 0x1>, + <0x100 &apps_smmu 0x1c01 0x1>, + <0x200 &apps_smmu 0x1c02 0x1>, + <0x300 &apps_smmu 0x1c03 0x1>, + <0x400 &apps_smmu 0x1c04 0x1>, + <0x500 &apps_smmu 0x1c05 0x1>, + <0x600 &apps_smmu 0x1c06 0x1>, + <0x700 &apps_smmu 0x1c07 0x1>, + <0x800 &apps_smmu 0x1c08 0x1>, + <0x900 &apps_smmu 0x1c09 0x1>, + <0xa00 &apps_smmu 0x1c0a 0x1>, + <0xb00 &apps_smmu 0x1c0b 0x1>, + <0xc00 &apps_smmu 0x1c0c 0x1>, + <0xd00 &apps_smmu 0x1c0d 0x1>, + <0xe00 &apps_smmu 0x1c0e 0x1>, + <0xf00 &apps_smmu 0x1c0f 0x1>; + + 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_1_CLKREF_CLK>, + <&clock_gcc GCC_PCIE_1_SLV_Q2A_AXI_CLK>, + <&clock_gcc GCC_AGGRE_NOC_PCIE_TBU_CLK>, + <&clock_gcc GCC_PCIE_PHY_REFGEN_CLK>, + <&clock_gcc GCC_PCIE_PHY_AUX_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_phy_aux_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"; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-pinctrl-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pinctrl-overlay.dtsi new file mode 100644 index 000000000000..67933c3784f7 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-pinctrl-overlay.dtsi @@ -0,0 +1,63 @@ +/* Copyright (c) 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. + */ + +&pmi8998_gpios { + usb2_vbus_boost { + usb2_vbus_boost_default: usb2_vbus_boost_default { + pins = "gpio2"; + function = "normal"; + output-low; + power-source = <0>; + }; + }; + + qnovo_fet_ctrl { + qnovo_fet_ctrl_default: qnovo_fet_ctrl_default { + pins = "gpio6"; + function = "func1"; + output-low; + input-disable; + bias-disable; + power-source = <0>; + qcom,drive-strength = <1>; + }; + }; + + usb2_vbus_det { + usb2_vbus_det_default: usb2_vbus_det_default { + pins = "gpio8"; + function = "normal"; + input-enable; + bias-pull-down; + power-source = <1>; /* VPH input supply */ + }; + }; + + usb2_id_det { + usb2_id_det_default: usb2_id_det_default { + pins = "gpio9"; + function = "normal"; + input-enable; + bias-pull-up; + power-source = <0>; + }; + }; + + usb2_ext_5v_boost { + usb2_ext_5v_boost_default: usb2_ext_5v_boost_default { + pins = "gpio10"; + function = "normal"; + output-low; + power-source = <0>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi new file mode 100644 index 000000000000..86320c349e75 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi @@ -0,0 +1,3664 @@ +/* Copyright (c) 2016-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. + */ + +&soc { + tlmm: pinctrl@03400000 { + compatible = "qcom,sdm845-pinctrl"; + reg = <0x03400000 0xc00000>, <0x179900F0 0x60>; + reg-names = "pinctrl_regs", "spi_cfg_regs"; + interrupts = <0 208 0>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + interrupt-parent = <&pdc>; + + 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 */ + }; + }; + + flash_led3_front { + flash_led3_front_en: flash_led3_front_en { + mux { + pins = "gpio21"; + function = "gpio"; + }; + + config { + pins = "gpio21"; + drive_strength = <2>; + output-high; + bias-disable; + }; + }; + + flash_led3_front_dis: flash_led3_front_dis { + mux { + pins = "gpio21"; + function = "gpio"; + }; + + config { + pins = "gpio21"; + drive_strength = <2>; + output-low; + bias-disable; + }; + }; + }; + + flash_led3_iris { + flash_led3_iris_en: flash_led3_iris_en { + mux { + pins = "gpio23"; + function = "gpio"; + }; + + config { + pins = "gpio23"; + drive_strength = <2>; + output-high; + bias-disable; + }; + }; + + flash_led3_iris_dis: flash_led3_iris_dis { + mux { + pins = "gpio23"; + function = "gpio"; + }; + + config { + pins = "gpio23"; + drive_strength = <2>; + output-low; + bias-disable; + }; + }; + }; + + + wcd9xxx_intr { + wcd_intr_default: wcd_intr_default{ + mux { + pins = "gpio54"; + function = "gpio"; + }; + + config { + pins = "gpio54"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* pull down */ + input-enable; + }; + }; + }; + + storage_cd: storage_cd { + mux { + pins = "gpio126"; + function = "gpio"; + }; + + config { + pins = "gpio126"; + 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 = <10>; /* 10 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 = <10>; /* 10 MA */ + }; + }; + + sdc2_cmd_ds_50MHz: sdc2_cmd_ds_50MHz { + config { + pins = "sdc2_cmd"; + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + sdc2_cmd_ds_100MHz: sdc2_cmd_ds_100MHz { + config { + pins = "sdc2_cmd"; + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + sdc2_cmd_ds_200MHz: sdc2_cmd_ds_200MHz { + config { + pins = "sdc2_cmd"; + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 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_data_ds_400KHz: sdc2_data_ds_400KHz { + config { + pins = "sdc2_data"; + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + sdc2_data_ds_50MHz: sdc2_data_ds_50MHz { + config { + pins = "sdc2_data"; + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + sdc2_data_ds_100MHz: sdc2_data_ds_100MHz { + config { + pins = "sdc2_data"; + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + sdc2_data_ds_200MHz: sdc2_data_ds_200MHz { + config { + pins = "sdc2_data"; + bias-pull-up; /* pull up */ + drive-strength = <10>; /* 10 MA */ + }; + }; + + pcie0 { + pcie0_clkreq_default: pcie0_clkreq_default { + mux { + pins = "gpio36"; + function = "pci_e0"; + }; + + config { + pins = "gpio36"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + pcie0_perst_default: pcie0_perst_default { + mux { + pins = "gpio35"; + function = "gpio"; + }; + + config { + pins = "gpio35"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + pcie0_wake_default: pcie0_wake_default { + mux { + pins = "gpio37"; + function = "gpio"; + }; + + config { + pins = "gpio37"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + pcie0_3v3_on: pcie0_3v3_on { + mux { + pins = "gpio90"; + function = "gpio"; + }; + config { + pins = "gpio90"; + drive_strength = <2>; + bias-disable; + output-high; + }; + }; + + pcie0_1v5_on: pcie0_1v5_on { + mux { + pins = "gpio90"; + function = "gpio"; + }; + config { + pins = "gpio90"; + drive_strength = <2>; + bias-disable; + output-high; + }; + }; + }; + + pcie1 { + pcie1_clkreq_default: pcie1_clkreq_default { + mux { + pins = "gpio103"; + function = "pci_e1"; + }; + + config { + pins = "gpio103"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + pcie1_perst_default: pcie1_perst_default { + mux { + pins = "gpio102"; + function = "gpio"; + }; + + config { + pins = "gpio102"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + pcie1_wake_default: pcie1_wake_default { + mux { + pins = "gpio104"; + function = "gpio"; + }; + + config { + pins = "gpio104"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + cdc_reset_ctrl { + cdc_reset_sleep: cdc_reset_sleep { + mux { + pins = "gpio64"; + function = "gpio"; + }; + config { + pins = "gpio64"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + + cdc_reset_active:cdc_reset_active { + mux { + pins = "gpio64"; + function = "gpio"; + }; + config { + pins = "gpio64"; + drive-strength = <8>; + bias-pull-down; + output-high; + }; + }; + }; + + spkr_i2s_clk_pin { + spkr_i2s_clk_sleep: spkr_i2s_clk_sleep { + mux { + pins = "gpio69"; + function = "spkr_i2s"; + }; + + config { + pins = "gpio69"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + }; + }; + + spkr_i2s_clk_active: spkr_i2s_clk_active { + mux { + pins = "gpio69"; + function = "spkr_i2s"; + }; + + config { + pins = "gpio69"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + wcd_gnd_mic_swap { + wcd_gnd_mic_swap_idle: wcd_gnd_mic_swap_idle { + mux { + pins = "gpio51"; + function = "gpio"; + }; + config { + pins = "gpio51"; + drive-strength = <2>; + bias-pull-down; + output-low; + }; + }; + + wcd_gnd_mic_swap_active: wcd_gnd_mic_swap_active { + mux { + pins = "gpio51"; + function = "gpio"; + }; + config { + pins = "gpio51"; + drive-strength = <2>; + bias-disable; + output-high; + }; + }; + }; + + /* USB C analog configuration */ + wcd_usbc_analog_en1 { + wcd_usbc_analog_en1_idle: wcd_usbc_ana_en1_idle { + mux { + pins = "gpio49"; + function = "gpio"; + }; + config { + pins = "gpio49"; + drive-strength = <2>; + bias-pull-down; + output-low; + }; + }; + + wcd_usbc_analog_en1_active: wcd_usbc_ana_en1_active { + mux { + pins = "gpio49"; + function = "gpio"; + }; + config { + pins = "gpio49"; + drive-strength = <2>; + bias-disable; + output-high; + }; + }; + }; + + wcd_usbc_analog_en2 { + wcd_usbc_analog_en2_idle: wcd_usbc_ana_en2_idle { + mux { + pins = "gpio51"; + function = "gpio"; + }; + config { + pins = "gpio51"; + drive-strength = <2>; + bias-pull-down; + output-low; + }; + }; + + wcd_usbc_analog_en2_active: wcd_usbc_ana_en2_active { + mux { + pins = "gpio51"; + function = "gpio"; + }; + config { + pins = "gpio51"; + drive-strength = <2>; + bias-disable; + output-high; + }; + }; + }; + + pri_aux_pcm_clk { + pri_aux_pcm_clk_sleep: pri_aux_pcm_clk_sleep { + mux { + pins = "gpio65"; + function = "gpio"; + }; + + config { + pins = "gpio65"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + pri_aux_pcm_clk_active: pri_aux_pcm_clk_active { + mux { + pins = "gpio65"; + function = "pri_mi2s"; + }; + + config { + pins = "gpio65"; + 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 = "gpio66"; + function = "gpio"; + }; + + config { + pins = "gpio66"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + pri_aux_pcm_sync_active: pri_aux_pcm_sync_active { + mux { + pins = "gpio66"; + function = "pri_mi2s_ws"; + }; + + config { + pins = "gpio66"; + 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 = "gpio67"; + function = "gpio"; + }; + + config { + pins = "gpio67"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + pri_aux_pcm_din_active: pri_aux_pcm_din_active { + mux { + pins = "gpio67"; + function = "pri_mi2s"; + }; + + config { + pins = "gpio67"; + 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 = "gpio68"; + function = "gpio"; + }; + + config { + pins = "gpio68"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + pri_aux_pcm_dout_active: pri_aux_pcm_dout_active { + mux { + pins = "gpio68"; + function = "pri_mi2s"; + }; + + config { + pins = "gpio68"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + pmx_sde: pmx_sde { + sde_dsi_active: sde_dsi_active { + mux { + pins = "gpio6", "gpio52"; + function = "gpio"; + }; + + config { + pins = "gpio6", "gpio52"; + drive-strength = <8>; /* 8 mA */ + bias-disable = <0>; /* no pull */ + }; + }; + sde_dsi_suspend: sde_dsi_suspend { + mux { + pins = "gpio6", "gpio52"; + function = "gpio"; + }; + + config { + pins = "gpio6", "gpio52"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + }; + }; + }; + + pmx_sde_te { + sde_te_active: sde_te_active { + mux { + pins = "gpio10"; + function = "mdp_vsync"; + }; + + config { + pins = "gpio10"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + }; + }; + + sde_te_suspend: sde_te_suspend { + mux { + pins = "gpio10"; + function = "mdp_vsync"; + }; + + config { + pins = "gpio10"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + }; + }; + }; + + sde_dp_aux_active: sde_dp_aux_active { + mux { + pins = "gpio43", "gpio51"; + function = "gpio"; + }; + + config { + pins = "gpio43", "gpio51"; + bias-disable = <0>; /* no pull */ + drive-strength = <8>; + }; + }; + + sde_dp_aux_suspend: sde_dp_aux_suspend { + mux { + pins = "gpio43", "gpio51"; + function = "gpio"; + }; + + config { + pins = "gpio43", "gpio51"; + bias-pull-down; + drive-strength = <2>; + }; + }; + + sde_dp_usbplug_cc_active: sde_dp_usbplug_cc_active { + mux { + pins = "gpio38"; + function = "gpio"; + }; + + config { + pins = "gpio38"; + bias-disable; + drive-strength = <16>; + }; + }; + + sde_dp_usbplug_cc_suspend: sde_dp_usbplug_cc_suspend { + mux { + pins = "gpio38"; + function = "gpio"; + }; + + config { + pins = "gpio38"; + bias-pull-down; + drive-strength = <2>; + }; + }; + + /* add pingrp for touchscreen */ + pmx_ts_int_active { + ts_int_active: ts_int_active { + mux { + pins = "gpio122"; + function = "gpio"; + }; + + config { + pins = "gpio122"; + drive-strength = <8>; + bias-pull-up; + }; + }; + }; + + pmx_ts_int_suspend { + ts_int_suspend1: ts_int_suspend1 { + mux { + pins = "gpio122"; + function = "gpio"; + }; + + config { + pins = "gpio122"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + pmx_ts_reset_active { + ts_reset_active: ts_reset_active { + mux { + pins = "gpio99"; + function = "gpio"; + }; + + config { + pins = "gpio99"; + drive-strength = <8>; + bias-pull-up; + }; + }; + }; + + pmx_ts_reset_suspend { + ts_reset_suspend1: ts_reset_suspend1 { + mux { + pins = "gpio99"; + function = "gpio"; + }; + + config { + pins = "gpio99"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + pmx_ts_release { + ts_release: ts_release { + mux { + pins = "gpio122", "gpio99"; + function = "gpio"; + }; + + config { + pins = "gpio122", "gpio99"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; + + ts_mux { + ts_active: ts_active { + mux { + pins = "gpio99", "gpio122"; + function = "gpio"; + }; + + config { + pins = "gpio99", "gpio122"; + drive-strength = <16>; + bias-pull-up; + }; + }; + + ts_reset_suspend: ts_reset_suspend { + mux { + pins = "gpio99"; + function = "gpio"; + }; + + config { + pins = "gpio99"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + ts_int_suspend: ts_int_suspend { + mux { + pins = "gpio122"; + function = "gpio"; + }; + + config { + pins = "gpio122"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + + ext_bridge_mux { + lt9611_pins: lt9611_pins { + mux { + pins = "gpio84", "gpio128", "gpio89"; + function = "gpio"; + }; + + config { + pins = "gpio84", "gpio128", "gpio89"; + bias-disable = <0>; /* no pull */ + drive-strength = <8>; + }; + }; + }; + + sec_aux_pcm { + sec_aux_pcm_sleep: sec_aux_pcm_sleep { + mux { + pins = "gpio80", "gpio81"; + function = "gpio"; + }; + + config { + pins = "gpio80", "gpio81"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + sec_aux_pcm_active: sec_aux_pcm_active { + mux { + pins = "gpio80", "gpio81"; + function = "sec_mi2s"; + }; + + config { + pins = "gpio80", "gpio81"; + 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 = "gpio82"; + function = "gpio"; + }; + + config { + pins = "gpio82"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + sec_aux_pcm_din_active: sec_aux_pcm_din_active { + mux { + pins = "gpio82"; + function = "sec_mi2s"; + }; + + config { + pins = "gpio82"; + 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 = "gpio83"; + function = "gpio"; + }; + + config { + pins = "gpio83"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + sec_aux_pcm_dout_active: sec_aux_pcm_dout_active { + mux { + pins = "gpio83"; + function = "sec_mi2s"; + }; + + config { + pins = "gpio83"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + tert_aux_pcm { + tert_aux_pcm_sleep: tert_aux_pcm_sleep { + mux { + pins = "gpio75", "gpio76"; + function = "gpio"; + }; + + config { + pins = "gpio75", "gpio76"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + tert_aux_pcm_active: tert_aux_pcm_active { + mux { + pins = "gpio75", "gpio76"; + function = "ter_mi2s"; + }; + + config { + pins = "gpio75", "gpio76"; + 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 = "gpio77"; + function = "gpio"; + }; + + config { + pins = "gpio77"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + tert_aux_pcm_din_active: tert_aux_pcm_din_active { + mux { + pins = "gpio77"; + function = "ter_mi2s"; + }; + + config { + pins = "gpio77"; + 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 = "gpio78"; + function = "gpio"; + }; + + config { + pins = "gpio78"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + tert_aux_pcm_dout_active: tert_aux_pcm_dout_active { + mux { + pins = "gpio78"; + function = "ter_mi2s"; + }; + + config { + pins = "gpio78"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + quat_aux_pcm { + quat_aux_pcm_sleep: quat_aux_pcm_sleep { + mux { + pins = "gpio58", "gpio59"; + function = "gpio"; + }; + + config { + pins = "gpio58", "gpio59"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_aux_pcm_active: quat_aux_pcm_active { + mux { + pins = "gpio58", "gpio59"; + function = "qua_mi2s"; + }; + + config { + pins = "gpio58", "gpio59"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_aux_pcm_din { + quat_aux_pcm_din_sleep: quat_aux_pcm_din_sleep { + mux { + pins = "gpio60"; + function = "gpio"; + }; + + config { + pins = "gpio60"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_aux_pcm_din_active: quat_aux_pcm_din_active { + mux { + pins = "gpio60"; + function = "qua_mi2s"; + }; + + config { + pins = "gpio60"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + quat_aux_pcm_dout { + quat_aux_pcm_dout_sleep: quat_aux_pcm_dout_sleep { + mux { + pins = "gpio61"; + function = "gpio"; + }; + + config { + pins = "gpio61"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_aux_pcm_dout_active: quat_aux_pcm_dout_active { + mux { + pins = "gpio61"; + function = "qua_mi2s"; + }; + + config { + pins = "gpio61"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + pri_mi2s_mclk { + pri_mi2s_mclk_sleep: pri_mi2s_mclk_sleep { + mux { + pins = "gpio64"; + function = "gpio"; + }; + + config { + pins = "gpio64"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + pri_mi2s_mclk_active: pri_mi2s_mclk_active { + mux { + pins = "gpio64"; + function = "pri_mi2s"; + }; + + config { + pins = "gpio64"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + pri_mi2s_sck { + pri_mi2s_sck_sleep: pri_mi2s_sck_sleep { + mux { + pins = "gpio65"; + function = "gpio"; + }; + + config { + pins = "gpio65"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + pri_mi2s_sck_active: pri_mi2s_sck_active { + mux { + pins = "gpio65"; + function = "pri_mi2s"; + }; + + config { + pins = "gpio65"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + pri_mi2s_ws { + pri_mi2s_ws_sleep: pri_mi2s_ws_sleep { + mux { + pins = "gpio66"; + function = "gpio"; + }; + + config { + pins = "gpio66"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + pri_mi2s_ws_active: pri_mi2s_ws_active { + mux { + pins = "gpio66"; + function = "pri_mi2s_ws"; + }; + + config { + pins = "gpio66"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + pri_mi2s_sd0 { + pri_mi2s_sd0_sleep: pri_mi2s_sd0_sleep { + mux { + pins = "gpio67"; + function = "gpio"; + }; + + config { + pins = "gpio67"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + pri_mi2s_sd0_active: pri_mi2s_sd0_active { + mux { + pins = "gpio67"; + function = "pri_mi2s"; + }; + + config { + pins = "gpio67"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + pri_mi2s_sd1 { + pri_mi2s_sd1_sleep: pri_mi2s_sd1_sleep { + mux { + pins = "gpio68"; + function = "gpio"; + }; + + config { + pins = "gpio68"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + pri_mi2s_sd1_active: pri_mi2s_sd1_active { + mux { + pins = "gpio68"; + function = "pri_mi2s"; + }; + + config { + pins = "gpio68"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + sec_mi2s_mclk { + sec_mi2s_mclk_sleep: sec_mi2s_mclk_sleep { + mux { + pins = "gpio79"; + function = "gpio"; + }; + + config { + pins = "gpio79"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + sec_mi2s_mclk_active: sec_mi2s_mclk_active { + mux { + pins = "gpio79"; + function = "sec_mi2s"; + }; + + config { + pins = "gpio79"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + sec_mi2s { + sec_mi2s_sleep: sec_mi2s_sleep { + mux { + pins = "gpio80", "gpio81"; + function = "gpio"; + }; + + config { + pins = "gpio80", "gpio81"; + drive-strength = <2>; /* 2 mA */ + bias-disable; /* NO PULL */ + input-enable; + }; + }; + + sec_mi2s_active: sec_mi2s_active { + mux { + pins = "gpio80", "gpio81"; + function = "sec_mi2s"; + }; + + config { + pins = "gpio80", "gpio81"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + sec_mi2s_sd0 { + sec_mi2s_sd0_sleep: sec_mi2s_sd0_sleep { + mux { + pins = "gpio82"; + function = "gpio"; + }; + + config { + pins = "gpio82"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + sec_mi2s_sd0_active: sec_mi2s_sd0_active { + mux { + pins = "gpio82"; + function = "sec_mi2s"; + }; + + config { + pins = "gpio82"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + sec_mi2s_sd1 { + sec_mi2s_sd1_sleep: sec_mi2s_sd1_sleep { + mux { + pins = "gpio83"; + function = "gpio"; + }; + + config { + pins = "gpio83"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + sec_mi2s_sd1_active: sec_mi2s_sd1_active { + mux { + pins = "gpio83"; + function = "sec_mi2s"; + }; + + config { + pins = "gpio83"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + tert_mi2s_mclk { + tert_mi2s_mclk_sleep: tert_mi2s_mclk_sleep { + mux { + pins = "gpio74"; + function = "gpio"; + }; + + config { + pins = "gpio74"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + tert_mi2s_mclk_active: tert_mi2s_mclk_active { + mux { + pins = "gpio74"; + function = "ter_mi2s"; + }; + + config { + pins = "gpio74"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + tert_mi2s { + tert_mi2s_sleep: tert_mi2s_sleep { + mux { + pins = "gpio75", "gpio76"; + function = "gpio"; + }; + + config { + pins = "gpio75", "gpio76"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + tert_mi2s_active: tert_mi2s_active { + mux { + pins = "gpio75", "gpio76"; + function = "ter_mi2s"; + }; + + config { + pins = "gpio75", "gpio76"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + tert_mi2s_sd0 { + tert_mi2s_sd0_sleep: tert_mi2s_sd0_sleep { + mux { + pins = "gpio77"; + function = "gpio"; + }; + + config { + pins = "gpio77"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + tert_mi2s_sd0_active: tert_mi2s_sd0_active { + mux { + pins = "gpio77"; + function = "ter_mi2s"; + }; + + config { + pins = "gpio77"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + tert_mi2s_sd1 { + tert_mi2s_sd1_sleep: tert_mi2s_sd1_sleep { + mux { + pins = "gpio78"; + function = "gpio"; + }; + + config { + pins = "gpio78"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + tert_mi2s_sd1_active: tert_mi2s_sd1_active { + mux { + pins = "gpio78"; + function = "ter_mi2s"; + }; + + config { + pins = "gpio78"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + quat_mi2s_mclk { + quat_mi2s_mclk_sleep: quat_mi2s_mclk_sleep { + mux { + pins = "gpio57"; + function = "gpio"; + }; + + config { + pins = "gpio57"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_mi2s_mclk_active: quat_mi2s_mclk_active { + mux { + pins = "gpio57"; + function = "qua_mi2s"; + }; + + config { + pins = "gpio57"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + quat_mi2s { + quat_mi2s_sleep: quat_mi2s_sleep { + mux { + pins = "gpio58", "gpio59"; + function = "gpio"; + }; + + config { + pins = "gpio58", "gpio59"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_mi2s_active: quat_mi2s_active { + mux { + pins = "gpio58", "gpio59"; + function = "qua_mi2s"; + }; + + config { + pins = "gpio58", "gpio59"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + output-high; + }; + }; + }; + + quat_mi2s_sd0 { + quat_mi2s_sd0_sleep: quat_mi2s_sd0_sleep { + mux { + pins = "gpio60"; + function = "gpio"; + }; + + config { + pins = "gpio60"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_mi2s_sd0_active: quat_mi2s_sd0_active { + mux { + pins = "gpio60"; + function = "qua_mi2s"; + }; + + config { + pins = "gpio60"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + quat_mi2s_sd1 { + quat_mi2s_sd1_sleep: quat_mi2s_sd1_sleep { + mux { + pins = "gpio61"; + function = "gpio"; + }; + + config { + pins = "gpio61"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_mi2s_sd1_active: quat_mi2s_sd1_active { + mux { + pins = "gpio61"; + function = "qua_mi2s"; + }; + + config { + pins = "gpio61"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + quat_mi2s_sd2 { + quat_mi2s_sd2_sleep: quat_mi2s_sd2_sleep { + mux { + pins = "gpio62"; + function = "gpio"; + }; + + config { + pins = "gpio62"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_mi2s_sd2_active: quat_mi2s_sd2_active { + mux { + pins = "gpio62"; + function = "qua_mi2s"; + }; + + config { + pins = "gpio62"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + quat_mi2s_sd3 { + quat_mi2s_sd3_sleep: quat_mi2s_sd3_sleep { + mux { + pins = "gpio63"; + function = "gpio"; + }; + + config { + pins = "gpio63"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + input-enable; + }; + }; + + quat_mi2s_sd3_active: quat_mi2s_sd3_active { + mux { + pins = "gpio63"; + function = "qua_mi2s"; + }; + + config { + pins = "gpio63"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + quat_tdm { + quat_tdm_sleep: quat_tdm_sleep { + mux { + pins = "gpio58", "gpio59"; + function = "qua_mi2s"; + }; + + config { + pins = "gpio58", "gpio59"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + }; + }; + + quat_tdm_active: quat_tdm_active { + mux { + pins = "gpio58", "gpio59"; + function = "qua_mi2s"; + }; + + config { + pins = "gpio58", "gpio59"; + drive-strength = <8>; /* 8 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + quat_tdm_dout { + quat_tdm_dout_sleep: quat_tdm_dout_sleep { + mux { + pins = "gpio61"; + function = "qua_mi2s"; + }; + + config { + pins = "gpio61"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + }; + }; + + quat_tdm_dout_active: quat_tdm_dout_active { + mux { + pins = "gpio61"; + function = "qua_mi2s"; + }; + + config { + pins = "gpio61"; + drive-strength = <2>; /* 2 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + quat_tdm_din { + quat_tdm_din_sleep: quat_tdm_din_sleep { + mux { + pins = "gpio60"; + function = "qua_mi2s"; + }; + + config { + pins = "gpio60"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + }; + }; + + quat_tdm_din_active: quat_tdm_din_active { + mux { + pins = "gpio60"; + function = "qua_mi2s"; + }; + + config { + pins = "gpio60"; + drive-strength = <2>; /* 2 mA */ + bias-disable; /* NO PULL */ + }; + }; + }; + + /* QUPv3 South SE mappings */ + /* SE 0 pin mappings */ + 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_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; + }; + }; + }; + + /* SE 1 pin mappings */ + qupv3_se1_i2c_pins: qupv3_se1_i2c_pins { + qupv3_se1_i2c_active: qupv3_se1_i2c_active { + mux { + pins = "gpio17", "gpio18"; + function = "qup1"; + }; + + config { + pins = "gpio17", "gpio18"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se1_i2c_sleep: qupv3_se1_i2c_sleep { + mux { + pins = "gpio17", "gpio18"; + function = "gpio"; + }; + + config { + pins = "gpio17", "gpio18"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se1_spi_pins: qupv3_se1_spi_pins { + qupv3_se1_spi_active: qupv3_se1_spi_active { + mux { + pins = "gpio17", "gpio18", "gpio19", + "gpio20"; + function = "qup1"; + }; + + config { + pins = "gpio17", "gpio18", "gpio19", + "gpio20"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se1_spi_sleep: qupv3_se1_spi_sleep { + mux { + pins = "gpio17", "gpio18", "gpio19", + "gpio20"; + function = "gpio"; + }; + + config { + pins = "gpio17", "gpio18", "gpio19", + "gpio20"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + /* SE 2 pin mappings */ + qupv3_se2_i2c_pins: qupv3_se2_i2c_pins { + qupv3_se2_i2c_active: qupv3_se2_i2c_active { + mux { + pins = "gpio27", "gpio28"; + function = "qup2"; + }; + + config { + pins = "gpio27", "gpio28"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se2_i2c_sleep: qupv3_se2_i2c_sleep { + mux { + pins = "gpio27", "gpio28"; + function = "gpio"; + }; + + config { + pins = "gpio27", "gpio28"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se2_spi_pins: qupv3_se2_spi_pins { + qupv3_se2_spi_active: qupv3_se2_spi_active { + mux { + pins = "gpio27", "gpio28", "gpio29", + "gpio30"; + function = "qup2"; + }; + + config { + pins = "gpio27", "gpio28", "gpio29", + "gpio30"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se2_spi_sleep: qupv3_se2_spi_sleep { + mux { + pins = "gpio27", "gpio28", "gpio29", + "gpio30"; + function = "gpio"; + }; + + config { + pins = "gpio27", "gpio28", "gpio29", + "gpio30"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + /* SE 3 pin mappings */ + qupv3_se3_i2c_pins: qupv3_se3_i2c_pins { + qupv3_se3_i2c_active: qupv3_se3_i2c_active { + mux { + pins = "gpio41", "gpio42"; + function = "qup3"; + }; + + config { + pins = "gpio41", "gpio42"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se3_i2c_sleep: qupv3_se3_i2c_sleep { + mux { + pins = "gpio41", "gpio42"; + function = "gpio"; + }; + + config { + pins = "gpio41", "gpio42"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + nfc { + nfc_int_active: nfc_int_active { + /* active state */ + mux { + /* GPIO 63 NFC Read Interrupt */ + pins = "gpio63"; + function = "gpio"; + }; + + config { + pins = "gpio63"; + drive-strength = <2>; /* 2 MA */ + bias-pull-up; + }; + }; + + nfc_int_suspend: nfc_int_suspend { + /* sleep state */ + mux { + /* GPIO 63 NFC Read Interrupt */ + pins = "gpio63"; + function = "gpio"; + }; + + config { + pins = "gpio63"; + drive-strength = <2>; /* 2 MA */ + bias-pull-up; + }; + }; + + nfc_enable_active: nfc_enable_active { + /* active state */ + mux { + /* 12: NFC ENABLE 116:ESE Enable */ + pins = "gpio12", "gpio62", "gpio116"; + function = "gpio"; + }; + + config { + pins = "gpio12", "gpio62", "gpio116"; + drive-strength = <2>; /* 2 MA */ + bias-pull-up; + }; + }; + + nfc_enable_suspend: nfc_enable_suspend { + /* sleep state */ + mux { + /* 12: NFC ENABLE 116:ESE Enable */ + pins = "gpio12", "gpio62", "gpio116"; + function = "gpio"; + }; + + config { + pins = "gpio12", "gpio62", "gpio116"; + drive-strength = <2>; /* 2 MA */ + bias-disable; + }; + }; + }; + + qupv3_se3_spi_pins: qupv3_se3_spi_pins { + qupv3_se3_spi_active: qupv3_se3_spi_active { + mux { + pins = "gpio41", "gpio42", "gpio43", + "gpio44"; + function = "qup3"; + }; + + config { + pins = "gpio41", "gpio42", "gpio43", + "gpio44"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se3_spi_sleep: qupv3_se3_spi_sleep { + mux { + pins = "gpio41", "gpio42", "gpio43", + "gpio44"; + function = "gpio"; + }; + + config { + pins = "gpio41", "gpio42", "gpio43", + "gpio44"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + /* SE 4 pin mappings */ + qupv3_se4_i2c_pins: qupv3_se4_i2c_pins { + qupv3_se4_i2c_active: qupv3_se4_i2c_active { + mux { + pins = "gpio89", "gpio90"; + function = "qup4"; + }; + + config { + pins = "gpio89", "gpio90"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se4_i2c_sleep: qupv3_se4_i2c_sleep { + mux { + pins = "gpio89", "gpio90"; + function = "gpio"; + }; + + config { + pins = "gpio89", "gpio90"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se4_spi_pins: qupv3_se4_spi_pins { + qupv3_se4_spi_active: qupv3_se4_spi_active { + mux { + pins = "gpio89", "gpio90", "gpio91", + "gpio92"; + function = "qup4"; + }; + + config { + pins = "gpio89", "gpio90", "gpio91", + "gpio92"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se4_spi_sleep: qupv3_se4_spi_sleep { + mux { + pins = "gpio89", "gpio90", "gpio91", + "gpio92"; + function = "gpio"; + }; + + config { + pins = "gpio89", "gpio90", "gpio91", + "gpio92"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + /* SE 5 pin mappings */ + qupv3_se5_i2c_pins: qupv3_se5_i2c_pins { + qupv3_se5_i2c_active: qupv3_se5_i2c_active { + mux { + pins = "gpio85", "gpio86"; + function = "qup5"; + }; + + config { + pins = "gpio85", "gpio86"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se5_i2c_sleep: qupv3_se5_i2c_sleep { + mux { + pins = "gpio85", "gpio86"; + function = "gpio"; + }; + + config { + pins = "gpio85", "gpio86"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se5_spi_pins: qupv3_se5_spi_pins { + qupv3_se5_spi_active: qupv3_se5_spi_active { + mux { + pins = "gpio85", "gpio86", "gpio87", + "gpio88"; + function = "qup5"; + }; + + config { + pins = "gpio85", "gpio86", "gpio87", + "gpio88"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se5_spi_sleep: qupv3_se5_spi_sleep { + mux { + pins = "gpio85", "gpio86", "gpio87", + "gpio88"; + function = "gpio"; + }; + + config { + pins = "gpio85", "gpio86", "gpio87", + "gpio88"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + /* SE 6 pin mappings */ + qupv3_se6_i2c_pins: qupv3_se6_i2c_pins { + qupv3_se6_i2c_active: qupv3_se6_i2c_active { + mux { + pins = "gpio45", "gpio46"; + function = "qup6"; + }; + + config { + pins = "gpio45", "gpio46"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se6_i2c_sleep: qupv3_se6_i2c_sleep { + mux { + pins = "gpio45", "gpio46"; + function = "gpio"; + }; + + config { + pins = "gpio45", "gpio46"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se6_4uart_pins: qupv3_se6_4uart_pins { + qupv3_se6_ctsrx: qupv3_se6_ctsrx { + mux { + pins = "gpio45", "gpio48"; + function = "qup6"; + }; + + config { + pins = "gpio45", "gpio48"; + drive-strength = <2>; + bias-no-pull; + }; + }; + + qupv3_se6_rts: qupv3_se6_rts { + mux { + pins = "gpio46"; + function = "qup6"; + }; + + config { + pins = "gpio46"; + drive-strength = <2>; + bias-pull-down; + }; + }; + qupv3_se6_tx: qupv3_se6_tx { + mux { + pins = "gpio47"; + function = "qup6"; + }; + + config { + pins = "gpio47"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se6_spi_pins: qupv3_se6_spi_pins { + qupv3_se6_spi_active: qupv3_se6_spi_active { + mux { + pins = "gpio45", "gpio46", "gpio47", + "gpio48"; + function = "qup6"; + }; + + config { + pins = "gpio45", "gpio46", "gpio47", + "gpio48"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se6_spi_sleep: qupv3_se6_spi_sleep { + mux { + pins = "gpio45", "gpio46", "gpio47", + "gpio48"; + function = "gpio"; + }; + + config { + pins = "gpio45", "gpio46", "gpio47", + "gpio48"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + /* SE 7 pin mappings */ + qupv3_se7_i2c_pins: qupv3_se7_i2c_pins { + qupv3_se7_i2c_active: qupv3_se7_i2c_active { + mux { + pins = "gpio93", "gpio94"; + function = "qup7"; + }; + + config { + pins = "gpio93", "gpio94"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se7_i2c_sleep: qupv3_se7_i2c_sleep { + mux { + pins = "gpio93", "gpio94"; + function = "gpio"; + }; + + config { + pins = "gpio93", "gpio94"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se7_4uart_pins: qupv3_se7_4uart_pins { + qupv3_se7_4uart_active: qupv3_se7_4uart_active { + mux { + pins = "gpio93", "gpio94", "gpio95", + "gpio96"; + function = "qup7"; + }; + + config { + pins = "gpio93", "gpio94", "gpio95", + "gpio96"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se7_4uart_sleep: qupv3_se7_4uart_sleep { + mux { + pins = "gpio93", "gpio94", "gpio95", + "gpio96"; + function = "gpio"; + }; + + config { + pins = "gpio93", "gpio94", "gpio95", + "gpio96"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + + qupv3_se7_spi_pins: qupv3_se7_spi_pins { + qupv3_se7_spi_active: qupv3_se7_spi_active { + mux { + pins = "gpio93", "gpio94", "gpio95", + "gpio96"; + function = "qup7"; + }; + + config { + pins = "gpio93", "gpio94", "gpio95", + "gpio96"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se7_spi_sleep: qupv3_se7_spi_sleep { + mux { + pins = "gpio93", "gpio94", "gpio95", + "gpio96"; + function = "gpio"; + }; + + config { + pins = "gpio93", "gpio94", "gpio95", + "gpio96"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + /* QUPv3 North instances */ + /* SE 8 pin mappings */ + qupv3_se8_i2c_pins: qupv3_se8_i2c_pins { + qupv3_se8_i2c_active: qupv3_se8_i2c_active { + mux { + pins = "gpio65", "gpio66"; + function = "qup8"; + }; + + config { + pins = "gpio65", "gpio66"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se8_i2c_sleep: qupv3_se8_i2c_sleep { + mux { + pins = "gpio65", "gpio66"; + function = "gpio"; + }; + + config { + pins = "gpio65", "gpio66"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se8_spi_pins: qupv3_se8_spi_pins { + qupv3_se8_spi_active: qupv3_se8_spi_active { + mux { + pins = "gpio65", "gpio66", "gpio67", + "gpio68"; + function = "qup8"; + }; + + config { + pins = "gpio65", "gpio66", "gpio67", + "gpio68"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se8_spi_sleep: qupv3_se8_spi_sleep { + mux { + pins = "gpio65", "gpio66", "gpio67", + "gpio68"; + function = "gpio"; + }; + + config { + pins = "gpio65", "gpio66", "gpio67", + "gpio68"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + /* SE 9 pin mappings */ + qupv3_se9_i2c_pins: qupv3_se9_i2c_pins { + qupv3_se9_i2c_active: qupv3_se9_i2c_active { + mux { + pins = "gpio6", "gpio7"; + function = "qup9"; + }; + + config { + pins = "gpio6", "gpio7"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se9_i2c_sleep: qupv3_se9_i2c_sleep { + mux { + pins = "gpio6", "gpio7"; + function = "gpio"; + }; + + config { + pins = "gpio6", "gpio7"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se9_2uart_pins: qupv3_se9_2uart_pins { + qupv3_se9_2uart_active: qupv3_se9_2uart_active { + mux { + pins = "gpio4", "gpio5"; + function = "qup9"; + }; + + config { + pins = "gpio4", "gpio5"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se9_2uart_sleep: qupv3_se9_2uart_sleep { + mux { + pins = "gpio4", "gpio5"; + function = "gpio"; + }; + + config { + pins = "gpio4", "gpio5"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + + qupv3_se9_spi_pins: qupv3_se9_spi_pins { + qupv3_se9_spi_active: qupv3_se9_spi_active { + mux { + pins = "gpio4", "gpio5", "gpio6", + "gpio7"; + function = "qup9"; + }; + + config { + pins = "gpio4", "gpio5", "gpio6", + "gpio7"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se9_spi_sleep: qupv3_se9_spi_sleep { + mux { + pins = "gpio4", "gpio5", "gpio6", + "gpio7"; + function = "gpio"; + }; + + config { + pins = "gpio4", "gpio5", "gpio6", + "gpio7"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + /* SE 10 pin mappings */ + qupv3_se10_i2c_pins: qupv3_se10_i2c_pins { + qupv3_se10_i2c_active: qupv3_se10_i2c_active { + mux { + pins = "gpio55", "gpio56"; + function = "qup10"; + }; + + config { + pins = "gpio55", "gpio56"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se10_i2c_sleep: qupv3_se10_i2c_sleep { + mux { + pins = "gpio55", "gpio56"; + function = "gpio"; + }; + + config { + pins = "gpio55", "gpio56"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se10_2uart_pins: qupv3_se10_2uart_pins { + qupv3_se10_2uart_active: qupv3_se10_2uart_active { + mux { + pins = "gpio53", "gpio54"; + function = "qup10"; + }; + + config { + pins = "gpio53", "gpio54"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se10_2uart_sleep: qupv3_se10_2uart_sleep { + mux { + pins = "gpio53", "gpio54"; + function = "gpio"; + }; + + config { + pins = "gpio53", "gpio54"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + + qupv3_se10_spi_pins: qupv3_se10_spi_pins { + qupv3_se10_spi_active: qupv3_se10_spi_active { + mux { + pins = "gpio53", "gpio54", "gpio55", + "gpio56"; + function = "qup10"; + }; + + config { + pins = "gpio53", "gpio54", "gpio55", + "gpio56"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se10_spi_sleep: qupv3_se10_spi_sleep { + mux { + pins = "gpio53", "gpio54", "gpio55", + "gpio56"; + function = "gpio"; + }; + + config { + pins = "gpio53", "gpio54", "gpio55", + "gpio56"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + /* SE 11 pin mappings */ + qupv3_se11_i2c_pins: qupv3_se11_i2c_pins { + qupv3_se11_i2c_active: qupv3_se11_i2c_active { + mux { + pins = "gpio31", "gpio32"; + function = "qup11"; + }; + + config { + pins = "gpio31", "gpio32"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se11_i2c_sleep: qupv3_se11_i2c_sleep { + mux { + pins = "gpio31", "gpio32"; + function = "gpio"; + }; + + config { + pins = "gpio31", "gpio32"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se11_spi_pins: qupv3_se11_spi_pins { + qupv3_se11_spi_active: qupv3_se11_spi_active { + mux { + pins = "gpio31", "gpio32", "gpio33", + "gpio34"; + function = "qup11"; + }; + + config { + pins = "gpio31", "gpio32", "gpio33", + "gpio34"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se11_spi_sleep: qupv3_se11_spi_sleep { + mux { + pins = "gpio31", "gpio32", "gpio33", + "gpio34"; + function = "gpio"; + }; + + config { + pins = "gpio31", "gpio32", "gpio33", + "gpio34"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + /* SE 12 pin mappings */ + qupv3_se12_i2c_pins: qupv3_se12_i2c_pins { + qupv3_se12_i2c_active: qupv3_se12_i2c_active { + mux { + pins = "gpio49", "gpio50"; + function = "qup12"; + }; + + config { + pins = "gpio49", "gpio50"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se12_i2c_sleep: qupv3_se12_i2c_sleep { + mux { + pins = "gpio49", "gpio50"; + function = "gpio"; + }; + + config { + pins = "gpio49", "gpio50"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se12_spi_pins: qupv3_se12_spi_pins { + qupv3_se12_spi_active: qupv3_se12_spi_active { + mux { + pins = "gpio49", "gpio50", "gpio51", + "gpio52"; + function = "qup12"; + }; + + config { + pins = "gpio49", "gpio50", "gpio51", + "gpio52"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se12_spi_sleep: qupv3_se12_spi_sleep { + mux { + pins = "gpio49", "gpio50", "gpio51", + "gpio52"; + function = "gpio"; + }; + + config { + pins = "gpio49", "gpio50", "gpio51", + "gpio52"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + /* SE 13 pin mappings */ + qupv3_se13_i2c_pins: qupv3_se13_i2c_pins { + qupv3_se13_i2c_active: qupv3_se13_i2c_active { + mux { + pins = "gpio105", "gpio106"; + function = "qup13"; + }; + + config { + pins = "gpio105", "gpio106"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se13_i2c_sleep: qupv3_se13_i2c_sleep { + mux { + pins = "gpio105", "gpio106"; + function = "gpio"; + }; + + config { + pins = "gpio105", "gpio106"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se13_spi_pins: qupv3_se13_spi_pins { + qupv3_se13_spi_active: qupv3_se13_spi_active { + mux { + pins = "gpio105", "gpio106", "gpio107", + "gpio108"; + function = "qup13"; + }; + + config { + pins = "gpio105", "gpio106", "gpio107", + "gpio108"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se13_spi_sleep: qupv3_se13_spi_sleep { + mux { + pins = "gpio105", "gpio106", "gpio107", + "gpio108"; + function = "gpio"; + }; + + config { + pins = "gpio105", "gpio106", "gpio107", + "gpio108"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + /* SE 14 pin mappings */ + qupv3_se14_i2c_pins: qupv3_se14_i2c_pins { + qupv3_se14_i2c_active: qupv3_se14_i2c_active { + mux { + pins = "gpio33", "gpio34"; + function = "qup14"; + }; + + config { + pins = "gpio33", "gpio34"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se14_i2c_sleep: qupv3_se14_i2c_sleep { + mux { + pins = "gpio33", "gpio34"; + function = "gpio"; + }; + + config { + pins = "gpio33", "gpio34"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se14_spi_pins: qupv3_se14_spi_pins { + qupv3_se14_spi_active: qupv3_se14_spi_active { + mux { + pins = "gpio31", "gpio32", "gpio33", + "gpio34"; + function = "qup14"; + }; + + config { + pins = "gpio31", "gpio32", "gpio33", + "gpio34"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se14_spi_sleep: qupv3_se14_spi_sleep { + mux { + pins = "gpio31", "gpio32", "gpio33", + "gpio34"; + function = "gpio"; + }; + + config { + pins = "gpio31", "gpio32", "gpio33", + "gpio34"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + /* SE 15 pin mappings */ + qupv3_se15_i2c_pins: qupv3_se15_i2c_pins { + qupv3_se15_i2c_active: qupv3_se15_i2c_active { + mux { + pins = "gpio81", "gpio82"; + function = "qup15"; + }; + + config { + pins = "gpio81", "gpio82"; + drive-strength = <2>; + bias-disable; + }; + }; + + qupv3_se15_i2c_sleep: qupv3_se15_i2c_sleep { + mux { + pins = "gpio81", "gpio82"; + function = "gpio"; + }; + + config { + pins = "gpio81", "gpio82"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + qupv3_se15_spi_pins: qupv3_se15_spi_pins { + qupv3_se15_spi_active: qupv3_se15_spi_active { + mux { + pins = "gpio81", "gpio82", "gpio83", + "gpio84"; + function = "qup15"; + }; + + config { + pins = "gpio81", "gpio82", "gpio83", + "gpio84"; + drive-strength = <6>; + bias-disable; + }; + }; + + qupv3_se15_spi_sleep: qupv3_se15_spi_sleep { + mux { + pins = "gpio81", "gpio82", "gpio83", + "gpio84"; + function = "gpio"; + }; + + config { + pins = "gpio81", "gpio82", "gpio83", + "gpio84"; + drive-strength = <6>; + bias-disable; + }; + }; + }; + + cci0_active: cci0_active { + mux { + /* CLK, DATA */ + pins = "gpio17","gpio18"; // Only 2 + function = "cci_i2c"; + }; + + config { + pins = "gpio17","gpio18"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci0_suspend: cci0_suspend { + mux { + /* CLK, DATA */ + pins = "gpio17","gpio18"; + function = "cci_i2c"; + }; + + config { + pins = "gpio17","gpio18"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci1_active: cci1_active { + mux { + /* CLK, DATA */ + pins = "gpio19","gpio20"; + function = "cci_i2c"; + }; + + config { + pins = "gpio19","gpio20"; + bias-pull-up; /* PULL UP*/ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cci1_suspend: cci1_suspend { + mux { + /* CLK, DATA */ + pins = "gpio19","gpio20"; + function = "cci_i2c"; + }; + + config { + pins = "gpio19","gpio20"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_fisheye_active: cam_sensor_fisheye_active { + /* RESET, AVDD LO */ + mux { + pins = "gpio76","gpio75"; + function = "gpio"; + }; + + config { + pins = "gpio76","gpio75"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_fisheye_suspend: cam_sensor_fisheye_suspend { + /* RESET, AVDD LO*/ + mux { + pins = "gpio76","gpio75"; + function = "gpio"; + }; + + config { + pins = "gpio76","gpio75"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_depth_active: cam_sensor_depth_active { + /* RESET,AVDD LO ,IMG_START, ILLU_EN */ + mux { + pins = "gpio28","gpio23","gpio24"; + function = "gpio"; + }; + + config { + pins = "gpio28","gpio23","gpio24"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_depth_suspend: cam_sensor_depth_suspend { + /* RESET, AVDD LO ,IMG_START, ILLU_EN */ + mux { + pins = "gpio28","gpio23","gpio24"; + function = "gpio"; + }; + + config { + pins = "gpio28","gpio23","gpio24"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + max_rst_active: max_rst_active { + /* RESET */ + mux { + pins = "gpio31","gpio77","gpio78","gpio32"; + function = "gpio"; + }; + + config { + pins = "gpio31","gpio77","gpio78","gpio32"; + bias-disable; /* No PULL */ + drive-strength = <8>; /* 2 MA */ + }; + }; + + max_rst_suspend: max_rst_suspend { + /* RESET */ + mux { + pins = "gpio31","gpio77","gpio78","gpio32"; + function = "gpio"; + }; + + config { + pins = "gpio31","gpio77","gpio78","gpio32"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <8>; /* 2 MA */ + }; + }; + + max_6dof_active: max_6dof_active { + /* RESET */ + mux { + pins = "gpio30","gpio95","gpio94"; + function = "gpio"; + }; + + config { + pins = "gpio30","gpio95","gpio94"; + bias-disable; /* No PULL */ + drive-strength = <8>; /* 2 MA */ + }; + }; + + max_6dof_suspend: max_6dof_suspend { + /* RESET */ + mux { + pins = "gpio30","gpio95","gpio94"; + function = "gpio"; + }; + + config { + pins = "gpio30","gpio95","gpio94"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <8>; /* 2 MA */ + }; + }; + + cam_sensor_mclk0_active: cam_sensor_mclk0_active { + /* MCLK0 */ + mux { + pins = "gpio13"; + function = "cam_mclk"; + }; + + config { + pins = "gpio13"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk0_suspend: cam_sensor_mclk0_suspend { + /* MCLK0 */ + mux { + pins = "gpio13"; + function = "cam_mclk"; + }; + + config { + pins = "gpio13"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_active: cam_sensor_rear_active { + /* RESET, AVDD LDO */ + mux { + pins = "gpio80","gpio79"; + function = "gpio"; + }; + + config { + pins = "gpio80","gpio79"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_suspend: cam_sensor_rear_suspend { + /* RESET, AVDD LDO */ + mux { + pins = "gpio80","gpio79"; + function = "gpio"; + }; + + config { + pins = "gpio80","gpio79"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_mclk1_active: cam_sensor_mclk1_active { + /* MCLK1 */ + mux { + pins = "gpio14"; + function = "cam_mclk"; + }; + + config { + pins = "gpio14"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk1_suspend: cam_sensor_mclk1_suspend { + /* MCLK1 */ + mux { + pins = "gpio14"; + function = "cam_mclk"; + }; + + config { + pins = "gpio14"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk3_active: cam_sensor_mclk3_active { + /* MCLK3 */ + mux { + pins = "gpio16"; + function = "cam_mclk"; + }; + + config { + pins = "gpio16"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk3_suspend: cam_sensor_mclk3_suspend { + /* MCLK3 */ + mux { + pins = "gpio16"; + function = "cam_mclk"; + }; + + config { + pins = "gpio16"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + + cam_sensor_front_active: cam_sensor_front_active { + /* RESET AVDD_LDO*/ + mux { + pins = "gpio28"; + function = "gpio"; + }; + + config { + pins = "gpio28"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_suspend: cam_sensor_front_suspend { + /* RESET */ + mux { + pins = "gpio28"; + function = "gpio"; + }; + + config { + pins = "gpio28"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_iris_active: cam_sensor_iris_active { + /* RESET AVDD_LDO*/ + mux { + pins = "gpio9"; + function = "gpio"; + }; + + config { + pins = "gpio9"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_iris_suspend: cam_sensor_iris_suspend { + /* RESET */ + mux { + pins = "gpio9"; + function = "gpio"; + }; + + config { + pins = "gpio9"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + + cam_sensor_mclk2_active: cam_sensor_mclk2_active { + /* MCLK1 */ + mux { + /* CLK, DATA */ + pins = "gpio15"; + function = "cam_mclk"; + }; + + config { + pins = "gpio15"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_mclk2_suspend: cam_sensor_mclk2_suspend { + /* MCLK1 */ + mux { + /* CLK, DATA */ + pins = "gpio15"; + function = "cam_mclk"; + }; + + config { + pins = "gpio15"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear2_active: cam_sensor_rear2_active { + /* RESET, STANDBY */ + mux { + pins = "gpio9"; + function = "gpio"; + }; + + config { + pins = "gpio9"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear2_suspend: cam_sensor_rear2_suspend { + /* RESET, STANDBY */ + mux { + pins = "gpio9"; + function = "gpio"; + }; + config { + pins = "gpio9"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + cam_sensor_rear_vana: cam_sensor_rear_vana { + /* AVDD LDO */ + mux { + pins = "gpio8"; + function = "gpio"; + }; + + config { + pins = "gpio8"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_res_mgr_active: cam_res_mgr_active { + /* AVDD_LDO*/ + mux { + pins = "gpio8"; + function = "gpio"; + }; + + config { + pins = "gpio8"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_res_mgr_suspend: cam_res_mgr_suspend { + /* AVDD_LDO */ + mux { + pins = "gpio8"; + function = "gpio"; + }; + + config { + pins = "gpio8"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; + }; + + trigout_a: trigout_a { + mux { + pins = "gpio90"; + function = "qdss_cti"; + }; + config { + pins = "gpio90"; + drive-strength = <2>; + bias-disable; + }; + }; + + tsif0_signals_active: tsif0_signals_active { + tsif1_clk { + pins = "gpio89"; /* TSIF0 CLK */ + function = "tsif1_clk"; + }; + tsif1_en { + pins = "gpio90"; /* TSIF0 Enable */ + function = "tsif1_en"; + }; + tsif1_data { + pins = "gpio91"; /* TSIF0 DATA */ + function = "tsif1_data"; + }; + signals_cfg { + pins = "gpio89", "gpio90", "gpio91"; + 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 = "gpio12"; /* TSIF0 SYNC */ + function = "tsif1_sync"; + drive_strength = <2>; /* 2 mA */ + bias-pull-down; /* pull down */ + }; + }; + + tsif1_signals_active: tsif1_signals_active { + tsif2_clk { + pins = "gpio93"; /* TSIF1 CLK */ + function = "tsif2_clk"; + }; + tsif2_en { + pins = "gpio94"; /* TSIF1 Enable */ + function = "tsif2_en"; + }; + tsif2_data { + pins = "gpio95"; /* TSIF1 DATA */ + function = "tsif2_data"; + }; + signals_cfg { + pins = "gpio93", "gpio94", "gpio95"; + 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 = "gpio96"; /* TSIF1 SYNC */ + function = "tsif2_sync"; + drive_strength = <2>; /* 2 mA */ + bias-pull-down; /* pull down */ + }; + }; + + ap2mdm { + ap2mdm_active: ap2mdm_active { + mux { + /* ap2mdm-status + * ap2mdm-errfatal + * ap2mdm-vddmin + */ + pins = "gpio21", "gpio23"; + function = "gpio"; + }; + + config { + pins = "gpio21", "gpio23"; + drive-strength = <16>; + bias-disable; + }; + }; + ap2mdm_sleep: ap2mdm_sleep { + mux { + /* ap2mdm-status + * ap2mdm-errfatal + * ap2mdm-vddmin + */ + pins = "gpio21", "gpio23"; + function = "gpio"; + }; + + config { + pins = "gpio21", "gpio23"; + drive-strength = <8>; + bias-disable; + }; + + }; + }; + + mdm2ap { + mdm2ap_active: mdm2ap_active { + mux { + /* mdm2ap-status + * mdm2ap-errfatal + * mdm2ap-vddmin + */ + pins = "gpio22", "gpio20"; + function = "gpio"; + }; + + config { + pins = "gpio22", "gpio20"; + drive-strength = <8>; + bias-disable; + }; + }; + mdm2ap_sleep: mdm2ap_sleep { + mux { + /* mdm2ap-status + * mdm2ap-errfatal + * mdm2ap-vddmin + */ + pins = "gpio22", "gpio20"; + function = "gpio"; + }; + + config { + pins = "gpio22", "gpio20"; + drive-strength = <8>; + bias-disable; + }; + }; + }; + }; +}; + +&pm8998_gpios { + key_home { + key_home_default: key_home_default { + pins = "gpio5"; + function = "normal"; + input-enable; + bias-pull-up; + power-source = <0>; + }; + }; + + led_bt { + led_bt_default: led_bt_default { + pins = "gpio5"; + function = "normal"; + power-source = <0>; + output-low; + }; + }; + + key_vol_up { + key_vol_up_default: key_vol_up_default { + pins = "gpio6"; + function = "normal"; + input-enable; + bias-pull-up; + power-source = <0>; + }; + }; + + key_cam_snapshot { + key_cam_snapshot_default: key_cam_snapshot_default { + pins = "gpio7"; + function = "normal"; + input-enable; + bias-pull-up; + power-source = <0>; + }; + }; + + key_cam_focus { + key_cam_focus_default: key_cam_focus_default { + pins = "gpio8"; + function = "normal"; + input-enable; + bias-pull-up; + power-source = <0>; + }; + }; + + led_wifi { + led_wifi_default: led_wifi_default { + pins = "gpio9"; + function = "normal"; + power-source = <0>; + output-low; + }; + }; + + camera_dvdd_en { + camera_dvdd_en_default: camera_dvdd_en_default { + pins = "gpio9"; + function = "normal"; + power-source = <0>; + output-low; + }; + }; + + camera_rear_avdd_en { + camera_rear_avdd_en_default: camera_rear_avdd_en_default { + pins = "gpio10"; + function = "normal"; + power-source = <0>; + output-low; + }; + }; + + camera_rear_dvdd_en { + camera_rear_dvdd_en_default: camera_rear_dvdd_en_default { + pins = "gpio12"; + function = "normal"; + power-source = <0>; + output-low; + }; + }; + + nfc_clk { + nfc_clk_default: nfc_clk_default { + pins = "gpio21"; + function = "normal"; + input-enable; + power-source = <1>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi new file mode 100644 index 000000000000..9a4e43d96907 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi @@ -0,0 +1,154 @@ +/* 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. + */ + +&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,latency-us = <51>; + qcom,ss-power = <452>; + qcom,energy-overhead = <69355>; + qcom,time-overhead = <99>; + }; + + qcom,pm-cluster-level@1 { /* LLCC off, AOSS sleep */ + reg = <1>; + label = "llcc-off"; + qcom,psci-mode = <0xC24>; + qcom,latency-us = <6562>; + qcom,ss-power = <108>; + qcom,energy-overhead = <4000000>; + qcom,time-overhead = <5000>; + qcom,min-child-idx = <2>; + qcom,is-reset; + qcom,notify-rpm; + }; + + qcom,pm-cpu@0 { + #address-cells = <1>; + #size-cells = <0>; + qcom,psci-mode-shift = <0>; + qcom,psci-mode-mask = <0xf>; + qcom,ref-stddev = <500>; + qcom,tmr-add = <1000>; + qcom,ref-premature-cnt = <1>; + qcom,cpu = <&CPU0 &CPU1 &CPU2 &CPU3>; + + qcom,pm-cpu-level@0 { /* C1 */ + reg = <0>; + label = "wfi"; + qcom,psci-cpu-mode = <0x1>; + qcom,latency-us = <43>; + qcom,ss-power = <150>; + qcom,energy-overhead = <10000>; + qcom,time-overhead = <100>; + }; + + qcom,pm-cpu-level@1 { /* C3 */ + reg = <1>; + label = "pc"; + qcom,psci-cpu-mode = <0x3>; + qcom,latency-us = <461>; + qcom,ss-power = <100>; + qcom,energy-overhead = <400000>; + qcom,time-overhead = <500>; + qcom,is-reset; + qcom,use-broadcast-timer; + }; + + qcom,pm-cpu-level@2 { /* C4 */ + reg = <2>; + label = "rail-pc"; + qcom,psci-cpu-mode = <0x4>; + qcom,latency-us = <531>; + qcom,ss-power = <73>; + qcom,energy-overhead = <500000>; + qcom,time-overhead = <600>; + qcom,is-reset; + qcom,use-broadcast-timer; + }; + }; + + qcom,pm-cpu@1 { + #address-cells = <1>; + #size-cells = <0>; + qcom,psci-mode-shift = <0>; + qcom,psci-mode-mask = <0xf>; + qcom,ref-stddev = <100>; + qcom,tmr-add = <100>; + qcom,ref-premature-cnt = <3>; + qcom,cpu = <&CPU4 &CPU5 &CPU6 &CPU7>; + + qcom,pm-cpu-level@0 { /* C1 */ + reg = <0>; + label = "wfi"; + qcom,psci-cpu-mode = <0x1>; + qcom,latency-us = <43>; + qcom,ss-power = <454>; + qcom,energy-overhead = <38639>; + qcom,time-overhead = <83>; + }; + + qcom,pm-cpu-level@1 { /* C3 */ + reg = <1>; + label = "pc"; + qcom,psci-cpu-mode = <0x3>; + qcom,latency-us = <621>; + qcom,ss-power = <436>; + qcom,energy-overhead = <418225>; + qcom,time-overhead = <885>; + qcom,is-reset; + qcom,use-broadcast-timer; + }; + + qcom,pm-cpu-level@2 { /* C4 */ + reg = <2>; + label = "rail-pc"; + qcom,psci-cpu-mode = <0x4>; + qcom,latency-us = <1061>; + qcom,ss-power = <400>; + qcom,energy-overhead = <428225>; + qcom,time-overhead = <1000>; + qcom,is-reset; + qcom,use-broadcast-timer; + }; + }; + }; + }; + + qcom,rpm-stats@c300000 { + compatible = "qcom,rpm-stats"; + reg = <0xC300000 0x1000>, <0xC3F0004 0x4>; + reg-names = "phys_addr_base", "offset_addr"; + }; + + qcom,rpmh-master-stats@b221200 { + compatible = "qcom,rpmh-master-stats-v1"; + reg = <0xb221200 0x60>; + qcom,use-alt-unit = <3>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-pmic-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pmic-overlay.dtsi new file mode 100644 index 000000000000..db4483cef8f0 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-pmic-overlay.dtsi @@ -0,0 +1,51 @@ +/* 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. + */ + +#include + +#include "pmi8998.dtsi" + +&vendor { + ext_5v_boost: ext_5v_boost { + status = "disabled"; + compatible = "regulator-fixed"; + regulator-name = "ext_5v_boost"; + gpio = <&pmi8998_gpios 10 GPIO_ACTIVE_HIGH>; + enable-active-high; + + regulator-enable-ramp-delay = <1600>; + pinctrl-names = "default"; + pinctrl-0 = <&usb2_ext_5v_boost_default>; + }; +}; + +&pmi8998_charger { + smb2_vconn: qcom,smb2-vconn { + regulator-name = "smb2-vconn"; + }; + smb2_vbus: qcom,smb2-vbus { + regulator-name = "smb2-vbus"; + }; +}; + +&pmi8998_qnovo { + pinctrl-names = "default"; + pinctrl-0 = <&qnovo_fet_ctrl_default>; +}; + +&usb0 { + extcon = <&pmi8998_pdphy>, <&pmi8998_pdphy>, <&eud>; +}; + +&usb_qmp_dp_phy { + extcon = <&pmi8998_pdphy>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi b/arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi new file mode 100644 index 000000000000..097c3ac0d452 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi @@ -0,0 +1,797 @@ +/* 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. + */ + +#include + +&soc { + /* QUPv3 South instances */ + qupv3_0: qcom,qupv3_0_geni_se@8c0000 { + compatible = "qcom,qupv3-geni-se"; + reg = <0x8c0000 0x6000>; + qcom,bus-mas-id = ; + qcom,bus-slv-id = ; + qcom,iommu-s1-bypass; + + iommu_qupv3_0_geni_se_cb: qcom,iommu_qupv3_0_geni_se_cb { + compatible = "qcom,qupv3-geni-se-cb"; + iommus = <&apps_smmu 0x003 0x0>; + }; + }; + + /* + * HS UART instances. HS UART usecases can be supported on these + * instances only. + */ + qupv3_se6_4uart: qcom,qup_uart@0x898000 { + compatible = "qcom,msm-geni-serial-hs"; + reg = <0x898000 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_ctsrx>, <&qupv3_se6_rts>, + <&qupv3_se6_tx> ; + pinctrl-1 = <&qupv3_se6_ctsrx>, <&qupv3_se6_rts>, + <&qupv3_se6_tx> ; + interrupts-extended = <&pdc GIC_SPI 607 0>, + <&tlmm 48 0>; + status = "disabled"; + qcom,wakeup-byte = <0xFD>; + qcom,wrapper-core = <&qupv3_0>; + }; + + qupv3_se7_4uart: qcom,qup_uart@0x89c000 { + compatible = "qcom,msm-geni-serial-hs"; + reg = <0x89c000 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_4uart_active>; + pinctrl-1 = <&qupv3_se7_4uart_sleep>; + interrupts-extended = <&pdc GIC_SPI 608 0>, + <&tlmm 96 0>; + status = "disabled"; + qcom,wakeup-byte = <0xFD>; + qcom,wrapper-core = <&qupv3_0>; + }; + + /* I2C */ + qupv3_se0_i2c: i2c@880000 { + compatible = "qcom,i2c-geni"; + reg = <0x880000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&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@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_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@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_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@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_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@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_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@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_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@898000 { + compatible = "qcom,i2c-geni"; + reg = <0x898000 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@89c000 { + compatible = "qcom,i2c-geni"; + reg = <0x89c000 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@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_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@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_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@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_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@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_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@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_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@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_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@898000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x898000 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@89c000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x89c000 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 North Instances */ + qupv3_1: qcom,qupv3_1_geni_se@ac0000 { + compatible = "qcom,qupv3-geni-se"; + reg = <0xac0000 0x6000>; + qcom,bus-mas-id = ; + qcom,bus-slv-id = ; + qcom,iommu-s1-bypass; + + iommu_qupv3_1_geni_se_cb: qcom,iommu_qupv3_1_geni_se_cb { + compatible = "qcom,qupv3-geni-se-cb"; + iommus = <&apps_smmu 0x6c3 0x0>; + }; + }; + + /* 2-wire UART */ + + /* Debug UART Instance for CDP/MTP platform */ + qupv3_se9_2uart: qcom,qup_uart@0xa84000 { + compatible = "qcom,msm-geni-console"; + 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_2uart_active>; + pinctrl-1 = <&qupv3_se9_2uart_sleep>; + interrupts = ; + qcom,wrapper-core = <&qupv3_1>; + status = "disabled"; + }; + + /* Debug UART Instance for RUMI platform */ + qupv3_se10_2uart: qcom,qup_uart@0xa88000 { + compatible = "qcom,msm-geni-console"; + 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_2uart_active>; + pinctrl-1 = <&qupv3_se10_2uart_sleep>; + interrupts = ; + qcom,wrapper-core = <&qupv3_1>; + 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"; + }; + + qupv3_se14_i2c: i2c@a98000 { + compatible = "qcom,i2c-geni"; + reg = <0xa98000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S6_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + dmas = <&gpi_dma1 0 6 3 64 0>, + <&gpi_dma1 1 6 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_1>; + status = "disabled"; + }; + + qupv3_se15_i2c: i2c@a9c000 { + compatible = "qcom,i2c-geni"; + reg = <0xa9c000 0x4000>; + interrupts = ; + #address-cells = <1>; + #size-cells = <0>; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S7_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, + <&clock_gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; + dmas = <&gpi_dma1 0 7 3 64 0>, + <&gpi_dma1 1 7 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_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_se14_spi: spi@a98000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xa98000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S6_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_se14_spi_active>; + pinctrl-1 = <&qupv3_se14_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_1>; + dmas = <&gpi_dma1 0 6 1 64 0>, + <&gpi_dma1 1 6 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; + + qupv3_se15_spi: spi@a9c000 { + compatible = "qcom,spi-geni"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xa9c000 0x4000>; + reg-names = "se_phys"; + clock-names = "se-clk", "m-ahb", "s-ahb"; + clocks = <&clock_gcc GCC_QUPV3_WRAP1_S7_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_se15_spi_active>; + pinctrl-1 = <&qupv3_se15_spi_sleep>; + interrupts = ; + spi-max-frequency = <50000000>; + qcom,wrapper-core = <&qupv3_1>; + dmas = <&gpi_dma1 0 7 1 64 0>, + <&gpi_dma1 1 7 1 64 0>; + dma-names = "tx", "rx"; + status = "disabled"; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi new file mode 100644 index 000000000000..34beda4b465e --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi @@ -0,0 +1,820 @@ +/* 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. + */ + +#include +#include + +/* Stub regulators */ +/ { + + /* + * RPMh does not provide support for PM8998 S4 because it is always-on + * at 1.8 V in auto mode. Therefore, use a stub regulator for S4. + */ + pm8998_s4: regulator-pm8998-s4 { + compatible = "qcom,stub-regulator"; + regulator-name = "pm8998_s4"; + qcom,hpm-min-load = <100000>; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; +}; + +&soc { + /* RPMh regulators: */ + + /* PM8998 S1 = VDD_EBI supply */ + rpmh-regulator-ebilvl { + compatible = "qcom,rpmh-arc-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ebi.lvl"; + pm8998_s1_level: regulator-s1 { + regulator-name = "pm8998_s1_level"; + qcom,set = ; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + + ebi_cdev: regulator-cdev { + compatible = "qcom,rpmh-reg-cdev"; + mboxes = <&qmp_aop 0>; + qcom,reg-resource-name = "ebi"; + #cooling-cells = <2>; + }; + }; + + rpmh-regulator-smpa2 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "smpa2"; + pm8998_s2: regulator-s2 { + regulator-name = "pm8998_s2"; + qcom,set = ; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + qcom,init-voltage = <1100000>; + }; + }; + + rpmh-regulator-smpa3 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "smpa3"; + pm8998_s3: regulator-s3 { + regulator-name = "pm8998_s3"; + qcom,set = ; + regulator-min-microvolt = <1352000>; + regulator-max-microvolt = <1352000>; + qcom,init-voltage = <1352000>; + }; + }; + + rpmh-regulator-smpa5 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "smpa5"; + pm8998_s5: regulator-s5 { + regulator-name = "pm8998_s5"; + qcom,set = ; + regulator-min-microvolt = <1904000>; + regulator-max-microvolt = <2040000>; + qcom,init-voltage = <1904000>; + }; + }; + + /* PM8998 S6 = VDD_MX supply */ + rpmh-regulator-mxlvl { + compatible = "qcom,rpmh-arc-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "mx.lvl"; + pm8998_s6_level: regulator-s6-level { + regulator-name = "pm8998_s6_level"; + qcom,set = ; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + + pm8998_s6_level_ao: regulator-s6-level-ao { + regulator-name = "pm8998_s6_level_ao"; + qcom,set = ; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + + mx_cdev: mx-cdev-lvl { + compatible = "qcom,regulator-cooling-device"; + regulator-cdev-supply = <&pm8998_s6_level>; + regulator-levels = ; + #cooling-cells = <2>; + }; + }; + + rpmh-regulator-smpa7 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "smpa7"; + pm8998_s7: regulator-s7 { + regulator-name = "pm8998_s7"; + qcom,set = ; + regulator-min-microvolt = <900000>; + regulator-max-microvolt = <1028000>; + qcom,init-voltage = <900000>; + }; + }; + + /* PM8998 S9 + S8 = VDD_CX supply */ + rpmh-regulator-cxlvl { + compatible = "qcom,rpmh-arc-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "cx.lvl"; + pm8998_s9_level-parent-supply = <&pm8998_s6_level>; + pm8998_s9_level_ao-parent-supply = <&pm8998_s6_level_ao>; + pm8998_s9_level: regulator-s9-level { + regulator-name = "pm8998_s9_level"; + qcom,set = ; + regulator-min-microvolt + = ; + regulator-max-microvolt = ; + qcom,min-dropout-voltage-level = <(-1)>; + }; + + pm8998_s9_level_ao: regulator-s9-level-ao { + regulator-name = "pm8998_s9_level_ao"; + qcom,set = ; + regulator-min-microvolt + = ; + regulator-max-microvolt = ; + qcom,min-dropout-voltage-level = <(-1)>; + }; + + cx_cdev: regulator-cdev { + compatible = "qcom,rpmh-reg-cdev"; + mboxes = <&qmp_aop 0>; + qcom,reg-resource-name = "cx"; + #cooling-cells = <2>; + }; + }; + + rpmh-regulator-ldoa1 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa1"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + proxy-supply = <&pm8998_l1>; + pm8998_l1: regulator-l1 { + regulator-name = "pm8998_l1"; + qcom,set = ; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <880000>; + qcom,proxy-consumer-enable; + qcom,proxy-consumer-current = <72000>; + qcom,init-voltage = <880000>; + qcom,init-mode = ; + }; + + pm8998_l1_ao: regulator-l1-ao { + regulator-name = "pm8998_l1_ao"; + qcom,set = ; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <880000>; + qcom,init-voltage = <880000>; + qcom,init-mode = ; + }; + + regulator-l1-so { + regulator-name = "pm8998_l1_so"; + qcom,set = ; + regulator-min-microvolt = <880000>; + regulator-max-microvolt = <880000>; + qcom,init-voltage = <880000>; + qcom,init-mode = ; + qcom,init-enable = <0>; + }; + }; + + rpmh-regulator-ldoa2 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa2"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 30000>; + pm8998_l2: regulator-l2 { + regulator-name = "pm8998_l2"; + qcom,set = ; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + qcom,init-voltage = <1200000>; + qcom,init-mode = ; + regulator-always-on; + }; + }; + + rpmh-regulator-ldoa3 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa3"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pm8998_l3: regulator-l3 { + regulator-name = "pm8998_l3"; + qcom,set = ; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1000000>; + qcom,init-voltage = <1000000>; + qcom,init-mode = ; + }; + }; + + /* PM8998 L4 = VDD_SSC_MX supply */ + rpmh-regulator-lmxlvl { + compatible = "qcom,rpmh-arc-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "lmx.lvl"; + pm8998_l4_level: regulator-l4-level { + regulator-name = "pm8998_l4_level"; + qcom,set = ; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + }; + + rpmh-regulator-ldoa5 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa5"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pm8998_l5: regulator-l5 { + regulator-name = "pm8998_l5"; + qcom,set = ; + regulator-min-microvolt = <800000>; + regulator-max-microvolt = <800000>; + qcom,init-voltage = <800000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa6 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa6"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pm8998_l6: regulator-l6 { + regulator-name = "pm8998_l6"; + qcom,set = ; + regulator-min-microvolt = <1856000>; + regulator-max-microvolt = <1856000>; + qcom,init-voltage = <1856000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa7 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa7"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 10000>; + pm8998_l7: regulator-l7 { + regulator-name = "pm8998_l7"; + qcom,set = ; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + qcom,init-voltage = <1800000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa8 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa8"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pm8998_l8: regulator-l8 { + regulator-name = "pm8998_l8"; + qcom,set = ; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1248000>; + qcom,init-voltage = <1200000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa9 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa9"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pm8998_l9: regulator-l9 { + regulator-name = "pm8998_l9"; + qcom,set = ; + regulator-min-microvolt = <1704000>; + regulator-max-microvolt = <2928000>; + qcom,init-voltage = <1704000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa10 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa10"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pm8998_l10: regulator-l10 { + regulator-name = "pm8998_l10"; + qcom,set = ; + regulator-min-microvolt = <1704000>; + regulator-max-microvolt = <2928000>; + qcom,init-voltage = <1704000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa11 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa11"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pm8998_l11: regulator-l11 { + regulator-name = "pm8998_l11"; + qcom,set = ; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1048000>; + qcom,init-voltage = <1000000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa12 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa12"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pm8998_l12: regulator-l12 { + regulator-name = "pm8998_l12"; + qcom,set = ; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + qcom,init-voltage = <1800000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa13 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa13"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 10000>; + pm8998_l13: regulator-l13 { + regulator-name = "pm8998_l13"; + qcom,set = ; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <2960000>; + qcom,init-voltage = <1800000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa14 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa14"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 10000>; + proxy-supply = <&pm8998_l14>; + pm8998_l14: regulator-l14 { + regulator-name = "pm8998_l14"; + qcom,set = ; + qcom,proxy-consumer-enable; + qcom,proxy-consumer-current = <115000>; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1880000>; + qcom,init-voltage = <1800000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa15 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa15"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pm8998_l15: regulator-l15 { + regulator-name = "pm8998_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"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa16"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pm8998_l16: regulator-l16 { + regulator-name = "pm8998_l16"; + qcom,set = ; + regulator-min-microvolt = <2704000>; + regulator-max-microvolt = <2704000>; + qcom,init-voltage = <2704000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa17 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa17"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 10000>; + pm8998_l17: regulator-l17 { + regulator-name = "pm8998_l17"; + qcom,set = ; + regulator-min-microvolt = <1304000>; + regulator-max-microvolt = <1304000>; + qcom,init-voltage = <1304000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa18 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa18"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pm8998_l18: regulator-l18 { + regulator-name = "pm8998_l18"; + qcom,set = ; + regulator-min-microvolt = <2704000>; + regulator-max-microvolt = <2960000>; + qcom,init-voltage = <2704000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa19 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa19"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pm8998_l19: regulator-l19 { + regulator-name = "pm8998_l19"; + qcom,set = ; + regulator-min-microvolt = <2856000>; + regulator-max-microvolt = <3104000>; + qcom,init-voltage = <2856000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa20 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa20"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 10000>; + pm8998_l20: regulator-l20 { + regulator-name = "pm8998_l20"; + qcom,set = ; + regulator-min-microvolt = <2704000>; + regulator-max-microvolt = <2960000>; + qcom,init-voltage = <2704000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa21 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa21"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 10000>; + pm8998_l21: regulator-l21 { + regulator-name = "pm8998_l21"; + qcom,set = ; + regulator-min-microvolt = <2704000>; + regulator-max-microvolt = <2960000>; + qcom,init-voltage = <2704000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa22 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa22"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 10000>; + pm8998_l22: regulator-l22 { + regulator-name = "pm8998_l22"; + qcom,set = ; + regulator-min-microvolt = <2864000>; + regulator-max-microvolt = <3312000>; + qcom,init-voltage = <2864000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa23 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa23"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 10000>; + pm8998_l23: regulator-l23 { + regulator-name = "pm8998_l23"; + qcom,set = ; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3312000>; + qcom,init-voltage = <3000000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa24 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa24"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 10000>; + pm8998_l24-parent-supply = <&pm8998_l12>; + pm8998_l24: regulator-l24 { + regulator-name = "pm8998_l24"; + qcom,set = ; + regulator-min-microvolt = <3088000>; + regulator-max-microvolt = <3088000>; + qcom,init-voltage = <3088000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa25 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa25"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 10000>; + pm8998_l25: regulator-l25 { + regulator-name = "pm8998_l25"; + qcom,set = ; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3312000>; + qcom,init-voltage = <3000000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-ldoa26 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa26"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + proxy-supply = <&pm8998_l26>; + pm8998_l26: regulator-l26 { + regulator-name = "pm8998_l26"; + qcom,set = ; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + qcom,proxy-consumer-enable; + qcom,proxy-consumer-current = <43600>; + qcom,init-voltage = <1200000>; + qcom,init-mode = ; + }; + }; + + /* PM8998 L27 = VDD_SSC_CX supply */ + rpmh-regulator-lcxlvl { + compatible = "qcom,rpmh-arc-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "lcx.lvl"; + pm8998_l27_level: regulator-l27-level { + regulator-name = "pm8998_l27_level"; + qcom,set = ; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + }; + + rpmh-regulator-ldoa28 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "ldoa28"; + qcom,regulator-type = "pmic4-ldo"; + qcom,supported-modes = + ; + qcom,mode-threshold-currents = <0 1>; + pm8998_l28: regulator-l28 { + regulator-name = "pm8998_l28"; + qcom,set = ; + regulator-min-microvolt = <2856000>; + regulator-max-microvolt = <3008000>; + qcom,init-voltage = <2856000>; + qcom,init-mode = ; + }; + }; + + rpmh-regulator-vsa1 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "vsa1"; + pm8998_lvs1: regulator-lvs1 { + regulator-name = "pm8998_lvs1"; + qcom,set = ; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + }; + + rpmh-regulator-vsa2 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "vsa2"; + pm8998_lvs2: regulator-lvs2 { + regulator-name = "pm8998_lvs2"; + qcom,set = ; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + }; + + rpmh-regulator-bobb1 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "bobb1"; + qcom,regulator-type = "pmic4-bob"; + qcom,send-defaults; + + pmi8998_bob: regulator-bob { + regulator-name = "pmi8998_bob"; + qcom,set = ; + regulator-min-microvolt = <3312000>; + regulator-max-microvolt = <3600000>; + qcom,init-voltage = <3312000>; + qcom,init-mode = ; + }; + + pmi8998_bob_ao: regulator-bob-ao { + regulator-name = "pmi8998_bob_ao"; + qcom,set = ; + regulator-min-microvolt = <3312000>; + regulator-max-microvolt = <3600000>; + qcom,init-voltage = <3312000>; + qcom,init-mode = ; + }; + }; + + /* PM8005 S1 + S4 = 2 phase VDD_GFX supply */ + rpmh-regulator-gfxlvl { + compatible = "qcom,rpmh-arc-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "gfx.lvl"; + pm8005_s1_level: regulator-s1-level { + regulator-name = "pm8005_s1_level"; + qcom,set = ; + regulator-min-microvolt + = ; + regulator-max-microvolt + = ; + qcom,init-voltage-level + = ; + }; + }; + + /* PM8005 S2 = VDD_MODEM supply */ + rpmh-regulator-msslvl { + compatible = "qcom,rpmh-arc-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "mss.lvl"; + pm8005_s2_level: regulator-s2-level { + regulator-name = "pm8005_s2_level"; + qcom,set = ; + regulator-min-microvolt = ; + regulator-max-microvolt = ; + }; + }; + + rpmh-regulator-smpc3 { + compatible = "qcom,rpmh-vrm-regulator"; + mboxes = <&apps_rsc 0>; + qcom,resource-name = "smpc3"; + pm8005_s3: regulator-s3 { + regulator-name = "pm8005_s3"; + qcom,set = ; + regulator-min-microvolt = <600000>; + regulator-max-microvolt = <600000>; + qcom,init-voltage = <600000>; + }; + }; + + refgen: refgen-regulator@ff1000 { + compatible = "qcom,refgen-regulator"; + reg = <0xff1000 0x60>; + regulator-name = "refgen"; + regulator-enable-ramp-delay = <5>; + status = "disabled"; + proxy-supply = <&refgen>; + qcom,proxy-consumer-enable; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi new file mode 100644 index 000000000000..aa3976d33c32 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi @@ -0,0 +1,935 @@ +/* Copyright (c) 2016-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. + */ + +#include "dsi-panel-sim-video.dtsi" +#include "dsi-panel-sim-cmd.dtsi" +#include "dsi-panel-sim-dsc375-cmd.dtsi" +#include "dsi-panel-sim-dualmipi-video.dtsi" +#include "dsi-panel-sim-dualmipi-cmd.dtsi" +#include "dsi-panel-sim-dualmipi-dsc375-cmd.dtsi" +#include "dsi-panel-sharp-dsc-4k-video.dtsi" +#include "dsi-panel-sharp-dsc-4k-cmd.dtsi" +#include "dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi" +#include "dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi" +#include "dsi-panel-nt35597-truly-dsc-wqxga-cmd.dtsi" +#include "dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi" +#include "dsi-panel-sharp-1080p-cmd.dtsi" +#include "dsi-panel-r63417-truly-1080p-cmd.dtsi" +#include "dsi-panel-sharp-dualmipi-1080p-120hz.dtsi" +#include "dsi-panel-s6e3ha3-amoled-dualmipi-wqhd-cmd.dtsi" +#include "dsi-panel-nt35597-dualmipi-wqxga-video.dtsi" +#include "dsi-panel-nt35597-dualmipi-wqxga-cmd.dtsi" +#include "dsi-panel-nt36850-truly-dualmipi-wqhd-cmd.dtsi" +#include "dsi-panel-test-dualmipi-oled-cmd.dtsi" +#include + +&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_vdd_no_labibb: dsi_panel_pwr_supply_vdd_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>; + }; + + qcom,panel-supply-entry@1 { + reg = <1>; + qcom,supply-name = "vdd"; + qcom,supply-min-voltage = <3000000>; + qcom,supply-max-voltage = <3000000>; + qcom,supply-enable-load = <857000>; + qcom,supply-disable-load = <0>; + qcom,supply-post-on-sleep = <0>; + }; + }; + + dsi_sharp_4k_dsc_video_display: qcom,dsi-display@0 { + compatible = "qcom,dsi-display"; + label = "dsi_sharp_4k_dsc_video_display"; + qcom,display-type = "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>; + clock-names = "mux_byte_clk", "mux_pixel_clk"; + + 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 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,panel-mode-gpio = <&tlmm 52 0>; + + qcom,dsi-panel = <&dsi_sharp_4k_dsc_video>; + vddio-supply = <&pm8998_l14>; + lab-supply = <&lab_regulator>; + ibb-supply = <&ibb_regulator>; + }; + + dsi_sharp_4k_dsc_cmd_display: qcom,dsi-display@1 { + compatible = "qcom,dsi-display"; + label = "dsi_sharp_4k_dsc_cmd_display"; + qcom,display-type = "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>; + clock-names = "mux_byte_clk", "mux_pixel_clk"; + + 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 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,panel-mode-gpio = <&tlmm 52 0>; + + qcom,dsi-panel = <&dsi_sharp_4k_dsc_cmd>; + vddio-supply = <&pm8998_l14>; + lab-supply = <&lab_regulator>; + ibb-supply = <&ibb_regulator>; + }; + + dsi_sharp_1080_cmd_display: qcom,dsi-display@2 { + compatible = "qcom,dsi-display"; + label = "dsi_sharp_1080_cmd_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi0>; + qcom,dsi-phy = <&mdss_dsi_phy0>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "mux_byte_clk", "mux_pixel_clk"; + + 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 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,panel-mode-gpio = <&tlmm 52 0>; + + qcom,dsi-panel = <&dsi_sharp_1080_cmd>; + vddio-supply = <&pm8998_l14>; + lab-supply = <&lab_regulator>; + ibb-supply = <&ibb_regulator>; + }; + + dsi_dual_sharp_1080_120hz_cmd_display: qcom,dsi-display@3 { + compatible = "qcom,dsi-display"; + label = "dsi_dual_sharp_1080_120hz_cmd_display"; + qcom,display-type = "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>; + clock-names = "mux_byte_clk", "mux_pixel_clk"; + + 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 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,panel-mode-gpio = <&tlmm 52 0>; + + qcom,dsi-panel = <&dsi_dual_sharp_1080_120hz_cmd>; + vddio-supply = <&pm8998_l14>; + lab-supply = <&lab_regulator>; + ibb-supply = <&ibb_regulator>; + }; + + dsi_dual_nt35597_truly_video_display: qcom,dsi-display@4 { + compatible = "qcom,dsi-display"; + label = "dsi_dual_nt35597_truly_video_display"; + qcom,display-type = "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>; + clock-names = "mux_byte_clk", "mux_pixel_clk"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,panel-mode-gpio = <&tlmm 52 0>; + + qcom,dsi-panel = <&dsi_dual_nt35597_truly_video>; + vddio-supply = <&pm8998_l14>; + lab-supply = <&lab_regulator>; + ibb-supply = <&ibb_regulator>; + }; + + dsi_dual_nt35597_truly_cmd_display: qcom,dsi-display@5 { + compatible = "qcom,dsi-display"; + label = "dsi_dual_nt35597_truly_cmd_display"; + qcom,display-type = "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>; + clock-names = "mux_byte_clk", "mux_pixel_clk"; + + 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 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,panel-mode-gpio = <&tlmm 52 0>; + + qcom,dsi-panel = <&dsi_dual_nt35597_truly_cmd>; + vddio-supply = <&pm8998_l14>; + lab-supply = <&lab_regulator>; + ibb-supply = <&ibb_regulator>; + }; + + dsi_nt35597_truly_dsc_cmd_display: qcom,dsi-display@6 { + compatible = "qcom,dsi-display"; + label = "dsi_nt35597_truly_dsc_cmd_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi1>; + qcom,dsi-phy = <&mdss_dsi_phy1>; + clocks = <&mdss_dsi1_pll BYTECLK_MUX_1_CLK>, + <&mdss_dsi1_pll PCLK_MUX_1_CLK>; + clock-names = "mux_byte_clk", "mux_pixel_clk"; + + 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 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,panel-mode-gpio = <&tlmm 52 0>; + + qcom,dsi-panel = <&dsi_nt35597_truly_dsc_cmd>; + vddio-supply = <&pm8998_l14>; + lab-supply = <&lab_regulator>; + ibb-supply = <&ibb_regulator>; + }; + + dsi_nt35597_truly_dsc_video_display: qcom,dsi-display@7 { + compatible = "qcom,dsi-display"; + label = "dsi_nt35597_truly_dsc_video_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi1>; + qcom,dsi-phy = <&mdss_dsi_phy1>; + clocks = <&mdss_dsi1_pll BYTECLK_MUX_1_CLK>, + <&mdss_dsi1_pll PCLK_MUX_1_CLK>; + clock-names = "mux_byte_clk", "mux_pixel_clk"; + + 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 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,panel-mode-gpio = <&tlmm 52 0>; + + qcom,dsi-panel = <&dsi_nt35597_truly_dsc_video>; + vddio-supply = <&pm8998_l14>; + lab-supply = <&lab_regulator>; + ibb-supply = <&ibb_regulator>; + }; + + dsi_sim_vid_display: qcom,dsi-display@8 { + compatible = "qcom,dsi-display"; + label = "dsi_sim_vid_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi0>; + qcom,dsi-phy = <&mdss_dsi_phy0>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "mux_byte_clk", "mux_pixel_clk"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + + qcom,dsi-panel = <&dsi_sim_vid>; + }; + + dsi_dual_sim_vid_display: qcom,dsi-display@9 { + compatible = "qcom,dsi-display"; + label = "dsi_dual_sim_vid_display"; + qcom,display-type = "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>; + clock-names = "mux_byte_clk", "mux_pixel_clk"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + + qcom,dsi-panel = <&dsi_dual_sim_vid>; + }; + + dsi_sim_cmd_display: qcom,dsi-display@10 { + compatible = "qcom,dsi-display"; + label = "dsi_sim_cmd_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi0>; + qcom,dsi-phy = <&mdss_dsi_phy0>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "mux_byte_clk", "mux_pixel_clk"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + + qcom,dsi-panel = <&dsi_sim_cmd>; + }; + + dsi_dual_sim_cmd_display: qcom,dsi-display@11 { + compatible = "qcom,dsi-display"; + label = "dsi_dual_sim_cmd_display"; + qcom,display-type = "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>; + clock-names = "mux_byte_clk", "mux_pixel_clk"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + + qcom,dsi-panel = <&dsi_dual_sim_cmd>; + }; + + dsi_sim_dsc_375_cmd_display: qcom,dsi-display@12 { + compatible = "qcom,dsi-display"; + label = "dsi_sim_dsc_375_cmd_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi0>; + qcom,dsi-phy = <&mdss_dsi_phy0>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "mux_byte_clk", "mux_pixel_clk"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + + qcom,dsi-panel = <&dsi_sim_dsc_375_cmd>; + }; + + dsi_dual_sim_dsc_375_cmd_display: qcom,dsi-display@13 { + compatible = "qcom,dsi-display"; + label = "dsi_dual_sim_dsc_375_cmd_display"; + qcom,display-type = "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>; + clock-names = "mux_byte_clk", "mux_pixel_clk"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + + qcom,dsi-panel = <&dsi_dual_sim_dsc_375_cmd>; + }; + + dsi_dual_nt35597_video_display: qcom,dsi-display@14 { + compatible = "qcom,dsi-display"; + label = "dsi_dual_nt35597_video_display"; + qcom,display-type = "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>; + clock-names = "mux_byte_clk", "mux_pixel_clk"; + + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; + qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,panel-mode-gpio = <&tlmm 52 0>; + + qcom,dsi-panel = <&dsi_dual_nt35597_video>; + vddio-supply = <&pm8998_l14>; + lab-supply = <&lab_regulator>; + ibb-supply = <&ibb_regulator>; + }; + + + dsi_dual_nt35597_cmd_display: qcom,dsi-display@15 { + compatible = "qcom,dsi-display"; + label = "dsi_dual_nt35597_cmd_display"; + qcom,display-type = "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>; + clock-names = "mux_byte_clk", "mux_pixel_clk"; + + 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 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,panel-mode-gpio = <&tlmm 52 0>; + + qcom,dsi-panel = <&dsi_dual_nt35597_cmd>; + vddio-supply = <&pm8998_l14>; + lab-supply = <&lab_regulator>; + ibb-supply = <&ibb_regulator>; + }; + + dsi_dual_nt36850_truly_cmd_display: qcom,dsi-display@16 { + compatible = "qcom,dsi-display"; + label = "dsi_dual_nt36850_truly_cmd_display"; + qcom,display-type = "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>; + clock-names = "mux_byte_clk", "mux_pixel_clk"; + + 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 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,panel-mode-gpio = <&tlmm 52 0>; + + qcom,dsi-panel = <&dsi_dual_nt36850_truly_cmd>; + vddio-supply = <&pm8998_l14>; + lab-supply = <&lab_regulator>; + ibb-supply = <&ibb_regulator>; + }; + + dsi_dual_test_cmd_display: qcom,dsi-display@17 { + compatible = "qcom,dsi-display"; + label = "dsi_dual_test_cmd"; + qcom,display-type = "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>; + clock-names = "mux_byte_clk", "mux_pixel_clk"; + + 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 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,panel-mode-gpio = <&tlmm 52 0>; + + qcom,dsi-panel = <&dsi_dual_test_cmd>; + vddio-supply = <&pm8998_l14>; + lab-supply = <&lab_regulator>; + ibb-supply = <&ibb_regulator>; + oled-vdda-supply = <&pm8998_l22>; + }; + + dsi_r63417_truly_1080_cmd_display: qcom,dsi-display@18 { + compatible = "qcom,dsi-display"; + label = "dsi_r63417_truly_1080_cmd_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi0>; + qcom,dsi-phy = <&mdss_dsi_phy0>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "src_byte_clk", "src_pixel_clk"; + + 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 10 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,panel-mode-gpio = <&tlmm 52 0>; + + qcom,dsi-panel = <&dsi_r63417_truly_1080_cmd>; + vddio-supply = <&pm8998_l14>; + lab-supply = <&lab_regulator>; + ibb-supply = <&ibb_regulator>; + }; + + ext_dsi_bridge_display: qcom,dsi-display@19 { + compatible = "qcom,dsi-display"; + label = "ext_dsi_bridge_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl = <&mdss_dsi0>; + qcom,dsi-phy = <&mdss_dsi_phy0>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "mux_byte_clk", "mux_pixel_clk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + ext_dsi_out: endpoint { + }; + }; + }; + }; + + sde_wb: qcom,wb-display@0 { + compatible = "qcom,wb-display"; + cell-index = <0>; + label = "wb_display"; + }; + + ext_disp: qcom,msm-ext-disp { + compatible = "qcom,msm-ext-disp"; + + ext_disp_audio_codec: qcom,msm-ext-disp-audio-codec-rx { + compatible = "qcom,msm-ext-disp-audio-codec-rx"; + }; + }; +}; + +&sde_dp { + qcom,dp-usbpd-detection = <&pmi8998_pdphy>; + qcom,ext-disp = <&ext_disp>; + + pinctrl-names = "mdss_dp_active", "mdss_dp_sleep"; + pinctrl-0 = <&sde_dp_aux_active &sde_dp_usbplug_cc_active>; + pinctrl-1 = <&sde_dp_aux_suspend &sde_dp_usbplug_cc_suspend>; + qcom,aux-en-gpio = <&tlmm 43 0>; + qcom,aux-sel-gpio = <&tlmm 51 0>; + qcom,usbplug-cc-gpio = <&tlmm 38 0>; +}; + +&mdss_mdp { + connectors = <&sde_rscc &sde_wb &sde_dp>; +}; + +&dsi_dual_nt35597_truly_video { + qcom,mdss-dsi-t-clk-post = <0x0D>; + qcom,mdss-dsi-t-clk-pre = <0x2D>; + qcom,mdss-dsi-pan-enable-dynamic-fps; + qcom,mdss-dsi-pan-fps-update = + "dfps_immediate_porch_mode_vfp"; + qcom,dsi-supported-dfps-list = <60 55 53>; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-on-check-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07 + 07 05 03 04 00]; + qcom,display-topology = <2 0 2>, + <1 0 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_dual_nt35597_truly_cmd { + qcom,mdss-dsi-t-clk-post = <0x0D>; + qcom,mdss-dsi-t-clk-pre = <0x2D>; + qcom,ulps-enabled; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-on-check-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07 + 07 05 03 04 00]; + qcom,display-topology = <2 0 2>, + <1 0 2>; + qcom,default-topology-index = <0>; + qcom,partial-update-enabled = "single_roi"; + qcom,panel-roi-alignment = <720 128 720 128 1440 128>; + }; + }; +}; + +&dsi_nt35597_truly_dsc_cmd { + qcom,mdss-dsi-t-clk-post = <0x0b>; + qcom,mdss-dsi-t-clk-pre = <0x23>; + qcom,ulps-enabled; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-on-check-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 15 05 05 20 1f 05 + 05 03 03 04 00]; + qcom,display-topology = <1 1 1>, + <2 2 1>, /* dsc merge */ + <2 1 1>; /* 3d mux */ + qcom,default-topology-index = <1>; + }; + }; +}; + +&dsi_nt35597_truly_dsc_video { + qcom,mdss-dsi-t-clk-post = <0x0b>; + qcom,mdss-dsi-t-clk-pre = <0x23>; + qcom,mdss-dsi-pan-enable-dynamic-fps; + qcom,mdss-dsi-pan-fps-update = + "dfps_immediate_porch_mode_vfp"; + qcom,dsi-supported-dfps-list = <60 55 53>; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-on-check-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 15 05 05 20 1f 05 + 04 03 03 04 00]; + qcom,display-topology = <1 1 1>, + <2 2 1>, /* dsc merge */ + <2 1 1>; /* 3d mux */ + qcom,default-topology-index = <1>; + }; + }; +}; + +&dsi_sharp_4k_dsc_video { + qcom,mdss-dsi-t-clk-post = <0x0c>; + qcom,mdss-dsi-t-clk-pre = <0x27>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 18 06 06 21 20 06 + 06 04 03 04 00]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_sharp_4k_dsc_cmd { + qcom,mdss-dsi-t-clk-post = <0x0c>; + qcom,mdss-dsi-t-clk-pre = <0x27>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 18 06 06 21 20 06 + 06 04 03 04 00]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_dual_sharp_1080_120hz_cmd { + qcom,mdss-dsi-t-clk-post = <0x0f>; + qcom,mdss-dsi-t-clk-pre = <0x36>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 24 09 09 26 24 09 + 09 06 03 04 00]; + qcom,display-topology = <2 0 2>, + <1 0 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_sharp_1080_cmd { + qcom,mdss-dsi-t-clk-post = <0x0c>; + qcom,mdss-dsi-t-clk-pre = <0x29>; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-on-check-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 1E 08 08 24 22 08 + 08 05 03 04 00]; + qcom,mdss-dsi-panel-clockrate = <900000000>; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_r63417_truly_1080_cmd { + qcom,mdss-dsi-t-clk-post = <0x0c>; + qcom,mdss-dsi-t-clk-pre = <0x29>; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-status-value = <0x1c>; + qcom,mdss-dsi-panel-on-check-value = <0x1c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 1E 08 08 24 22 08 + 08 05 03 04 00]; + qcom,mdss-dsi-panel-clockrate = <900000000>; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_sim_vid { + qcom,mdss-dsi-t-clk-post = <0x0d>; + qcom,mdss-dsi-t-clk-pre = <0x2d>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07 + 07 05 03 04 00]; + qcom,display-topology = <1 0 1>, + <2 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_dual_sim_vid { + qcom,mdss-dsi-t-clk-post = <0x0d>; + qcom,mdss-dsi-t-clk-pre = <0x2d>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07 + 07 05 03 04 00]; + qcom,display-topology = <2 0 2>, + <1 0 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_sim_cmd { + qcom,mdss-dsi-t-clk-post = <0x0c>; + qcom,mdss-dsi-t-clk-pre = <0x29>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,display-topology = <1 0 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"; + qcom,mdss-dsi-panel-phy-timings = [00 1a 06 06 22 20 07 + 07 04 03 04 00]; + }; + timing@1{ + qcom,display-topology = <1 0 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"; + qcom,mdss-dsi-panel-phy-timings = [00 1a 06 06 22 20 07 + 07 04 03 04 00]; + }; + timing@2{ + qcom,display-topology = <1 0 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"; + qcom,mdss-dsi-panel-phy-timings = [00 1a 06 06 22 20 07 + 07 04 03 04 00]; + }; + }; +}; + +&dsi_dual_sim_cmd { + qcom,mdss-dsi-t-clk-post = <0x0d>; + qcom,mdss-dsi-t-clk-pre = <0x2d>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 24 09 09 26 24 09 + 09 06 03 04 00]; + qcom,display-topology = <2 0 2>; + qcom,default-topology-index = <0>; + }; + timing@1{ + qcom,mdss-dsi-panel-phy-timings = [00 30 0c 0d 2a 27 0c + 0d 09 03 04 00]; + qcom,display-topology = <2 0 2>, + <1 0 2>; + qcom,default-topology-index = <0>; + }; + timing@2{ + qcom,mdss-dsi-panel-phy-timings = [00 18 06 06 21 20 06 + 06 04 03 04 00]; + qcom,display-topology = <2 0 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_sim_dsc_375_cmd { + qcom,mdss-dsi-t-clk-post = <0x0d>; + qcom,mdss-dsi-t-clk-pre = <0x2d>; + qcom,mdss-dsi-display-timings { + timing@0 { /* 1080p */ + qcom,mdss-dsi-panel-phy-timings = [00 1A 06 06 22 20 07 + 07 04 03 04 00]; + qcom,display-topology = <1 1 1>; + qcom,default-topology-index = <0>; + }; + timing@1 { /* qhd */ + qcom,mdss-dsi-panel-phy-timings = [00 15 05 05 20 1f 05 + 05 03 03 04 00]; + qcom,display-topology = <1 1 1>, + <2 2 1>, /* dsc merge */ + <2 1 1>; /* 3d mux */ + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_dual_sim_dsc_375_cmd { + qcom,mdss-dsi-t-clk-post = <0x0d>; + qcom,mdss-dsi-t-clk-pre = <0x2d>; + qcom,mdss-dsi-display-timings { + timing@0 { /* qhd */ + qcom,mdss-dsi-panel-phy-timings = [00 1c 07 07 23 21 07 + 07 05 03 04 00]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + }; + timing@1 { /* 4k */ + qcom,mdss-dsi-panel-phy-timings = [00 18 06 06 21 20 06 + 06 04 03 04 00]; + qcom,display-topology = <2 2 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_dual_nt35597_video { + qcom,mdss-dsi-t-clk-post = <0x0d>; + qcom,mdss-dsi-t-clk-pre = <0x2d>; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-timings = [00 1c 08 07 23 22 07 07 + 05 03 04 00]; + qcom,display-topology = <2 0 2>, + <1 0 2>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_dual_nt35597_cmd { + qcom,mdss-dsi-t-clk-post = <0x0d>; + qcom,mdss-dsi-t-clk-pre = <0x2d>; + qcom,ulps-enabled; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-timings = [00 1c 08 07 23 22 07 07 + 05 03 04 00]; + qcom,display-topology = <2 0 2>, + <1 0 2>; + qcom,default-topology-index = <0>; + qcom,partial-update-enabled = "single_roi"; + qcom,panel-roi-alignment = <720 128 720 128 1440 128>; + }; + }; +}; + +&dsi_dual_nt36850_truly_cmd { + qcom,mdss-dsi-t-clk-post = <0x0E>; + qcom,mdss-dsi-t-clk-pre = <0x30>; + qcom,mdss-dsi-display-timings { + timing@0 { + qcom,mdss-dsi-panel-phy-timings = [00 1f 08 08 24 23 08 + 08 05 03 04 00]; + qcom,display-topology = <2 0 2>, + <1 0 2>; + qcom,default-topology-index = <0>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde-pll.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde-pll.dtsi new file mode 100644 index 000000000000..967865b3ec10 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-sde-pll.dtsi @@ -0,0 +1,113 @@ +/* Copyright (c) 2016-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. + */ + +&soc { + mdss_dsi0_pll: qcom,mdss_dsi_pll@ae94a00 { + compatible = "qcom,mdss_dsi_pll_10nm"; + label = "MDSS DSI 0 PLL"; + cell-index = <0>; + #clock-cells = <1>; + reg = <0xae94a00 0x1e0>, + <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>; + qcom,dsi-pll-ssc-en; + qcom,dsi-pll-ssc-mode = "down-spread"; + gdsc-supply = <&mdss_core_gdsc>; + 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@ae96a00 { + compatible = "qcom,mdss_dsi_pll_10nm"; + label = "MDSS DSI 1 PLL"; + cell-index = <1>; + #clock-cells = <1>; + reg = <0xae96a00 0x1e0>, + <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>; + qcom,dsi-pll-ssc-en; + qcom,dsi-pll-ssc-mode = "down-spread"; + gdsc-supply = <&mdss_core_gdsc>; + 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_10nm"; + label = "MDSS DP PLL"; + cell-index = <0>; + #clock-cells = <1>; + + reg = <0x088ea000 0x200>, + <0x088eaa00 0x200>, + <0x088ea200 0x200>, + <0x088ea600 0x200>, + <0xaf03000 0x8>; + reg-names = "pll_base", "phy_base", "ln_tx0_base", + "ln_tx1_base", "gdsc_base"; + + gdsc-supply = <&mdss_core_gdsc>; + + clocks = <&clock_dispcc DISP_CC_MDSS_AHB_CLK>, + <&clock_rpmh RPMH_CXO_CLK>, + <&clock_gcc GCC_USB3_PRIM_CLKREF_CLK>, + <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>, + <&clock_gcc GCC_USB3_PRIM_PHY_PIPE_CLK>; + clock-names = "iface_clk", "ref_clk_src", "ref_clk", + "cfg_ahb_clk", "pipe_clk"; + clock-rate = <0>; + + qcom,platform-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,platform-supply-entry@0 { + reg = <0>; + qcom,supply-name = "gdsc"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + + }; + }; + +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi new file mode 100644 index 000000000000..6132722a562b --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi @@ -0,0 +1,642 @@ +/* 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. + */ +#include + +&soc { + mdss_mdp: qcom,mdss_mdp@ae00000 { + compatible = "qcom,sde-kms"; + reg = <0x0ae00000 0x81d40>, + <0x0aeb0000 0x2008>, + <0x0aeac000 0xf0>; + reg-names = "mdp_phys", + "vbif_phys", + "regdma_phys"; + + clocks = + <&clock_gcc GCC_DISP_AHB_CLK>, + <&clock_gcc GCC_DISP_AXI_CLK>, + <&clock_dispcc DISP_CC_MDSS_AHB_CLK>, + <&clock_dispcc DISP_CC_MDSS_AXI_CLK>, + <&clock_dispcc DISP_CC_MDSS_MDP_CLK>, + <&clock_dispcc DISP_CC_MDSS_VSYNC_CLK>; + clock-names = "gcc_iface", "gcc_bus", "iface_clk", + "bus_clk", "core_clk", "vsync_clk"; + clock-rate = <0 0 0 0 300000000 19200000 0>; + clock-max-rate = <0 0 0 0 412500000 19200000 0>; + + sde-vdd-supply = <&mdss_core_gdsc>; + + /* interrupt config */ + interrupt-parent = <&pdc>; + interrupts = <0 83 0>; + interrupt-controller; + #interrupt-cells = <1>; + iommus = <&apps_smmu 0x880 0x8>, + <&apps_smmu 0xc80 0x8>; + + #address-cells = <1>; + #size-cells = <0>; + + #power-domain-cells = <0>; + + /* hw blocks */ + qcom,sde-off = <0x1000>; + qcom,sde-len = <0x45C>; + + qcom,sde-ctl-off = <0x2000 0x2200 0x2400 + 0x2600 0x2800>; + qcom,sde-ctl-size = <0xE4>; + qcom,sde-ctl-display-pref = "primary", "primary", "none", + "none", "none"; + + qcom,sde-mixer-off = <0x45000 0x46000 0x47000 0 0 0x4a000>; + qcom,sde-mixer-size = <0x320>; + qcom,sde-mixer-display-pref = "primary", "primary", "none", + "none", "none", "none"; + + qcom,sde-dspp-top-off = <0x1300>; + qcom,sde-dspp-top-size = <0xc>; + + qcom,sde-dspp-off = <0x55000 0x57000 0x59000 0x5b000>; + qcom,sde-dspp-size = <0x17e0>; + + qcom,sde-dest-scaler-top-off = <0x00061000>; + qcom,sde-dest-scaler-top-size = <0xc>; + 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 = <0x3b8 24>; + + qcom,sde-intf-off = <0x6b000 0x6b800 + 0x6c000 0x6c800>; + qcom,sde-intf-size = <0x280>; + + qcom,sde-intf-type = "dp", "dsi", "dsi", "dp"; + qcom,sde-pp-off = <0x71000 0x71800 + 0x72000 0x72800 0x73000>; + qcom,sde-pp-slave = <0x0 0x0 0x0 0x0 0x1>; + qcom,sde-pp-size = <0xd4>; + + qcom,sde-te2-off = <0x2000 0x2000 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 0x0>; + 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 = <0x1c8>; + + 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_v2"; + + qcom,sde-mixer-pair-mask = <2 1 6 0 0 3>; + + qcom,sde-mixer-blend-op-off = <0x20 0x38 0x50 0x68 0x80 0x98 + 0xb0 0xc8 0xe0 0xf8 0x110>; + + /* 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 = "qseedv3"; + qcom,sde-sspp-qseed-off = <0xa00>; + qcom,sde-mixer-linewidth = <2560>; + qcom,sde-sspp-linewidth = <2560>; + qcom,sde-wb-linewidth = <4096>; + qcom,sde-mixer-blendstages = <0xb>; + qcom,sde-highest-bank-bit = <0x2>; + qcom,sde-ubwc-version = <0x200>; + qcom,sde-smart-panel-align-mode = <0xc>; + qcom,sde-panic-per-pipe; + qcom,sde-has-cdp; + qcom,sde-has-src-split; + qcom,sde-has-dim-layer; + qcom,sde-has-idle-pc; + qcom,sde-has-dest-scaler; + qcom,sde-max-dest-scaler-input-linewidth = <2048>; + qcom,sde-max-dest-scaler-output-linewidth = <2560>; + qcom,sde-max-bw-low-kbps = <6800000>; + qcom,sde-max-bw-high-kbps = <6800000>; + 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-ad-version = <0x00040000>; + qcom,sde-dspp-ad-off = <0x28000 0x27000>; + + 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-danger-lut = <0x0000000f 0x0000ffff 0x00000000 + 0x00000000>; + qcom,sde-safe-lut-linear = + <4 0xfff8>, + <0 0xfff0>; + qcom,sde-safe-lut-macrotile = + <10 0xfe00>, + <11 0xfc00>, + <12 0xf800>, + <0 0xf000>; + qcom,sde-safe-lut-nrt = + <0 0xffff>; + qcom,sde-safe-lut-cwb = + <0 0xffff>; + qcom,sde-qos-lut-linear = + <4 0x00000000 0x00000357>, + <5 0x00000000 0x00003357>, + <6 0x00000000 0x00023357>, + <7 0x00000000 0x00223357>, + <8 0x00000000 0x02223357>, + <9 0x00000000 0x22223357>, + <10 0x00000002 0x22223357>, + <11 0x00000022 0x22223357>, + <12 0x00000222 0x22223357>, + <13 0x00002222 0x22223357>, + <14 0x00012222 0x22223357>, + <0 0x00112222 0x22223357>; + qcom,sde-qos-lut-macrotile = + <10 0x00000003 0x44556677>, + <11 0x00000033 0x44556677>, + <12 0x00000233 0x44556677>, + <13 0x00002233 0x44556677>, + <14 0x00012233 0x44556677>, + <0 0x00112233 0x44556677>; + qcom,sde-qos-lut-nrt = + <0 0x00000000 0x00000000>; + qcom,sde-qos-lut-cwb = + <0 0x75300000 0x00000000>; + + qcom,sde-cdp-setting = <1 1>, <1 0>; + + qcom,sde-qos-cpu-mask = <0x3>; + qcom,sde-qos-cpu-dma-latency = <300>; + + qcom,sde-inline-rotator = <&mdss_rotator 0>; + qcom,sde-inline-rot-xin = <10 11>; + qcom,sde-inline-rot-xin-type = "sspp", "wb"; + + /* offsets are relative to "mdp_phys + qcom,sde-off */ + qcom,sde-inline-rot-clk-ctrl = <0x2bc 0x8>, <0x2bc 0xc>; + + qcom,sde-reg-dma-off = <0>; + qcom,sde-reg-dma-version = <0x1>; + qcom,sde-reg-dma-trigger-off = <0x119c>; + + 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-dspp-blocks { + qcom,sde-dspp-igc = <0x0 0x00030001>; + qcom,sde-dspp-hsic = <0x800 0x00010007>; + qcom,sde-dspp-memcolor = <0x880 0x00010007>; + qcom,sde-dspp-sixzone= <0x900 0x00010007>; + qcom,sde-dspp-vlut = <0xa00 0x00010008>; + qcom,sde-dspp-gamut = <0x1000 0x00040000>; + qcom,sde-dspp-pcc = <0x1700 0x00040000>; + qcom,sde-dspp-gc = <0x17c0 0x00010008>; + qcom,sde-dspp-hist = <0x800 0x00010007>; + 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_sec: qcom,smmu_sde_sec_cb { + compatible = "qcom,smmu_sde_sec"; + iommus = <&apps_smmu 0x881 0x8>, + <&apps_smmu 0xc81 0x8>; + }; + + /* 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,active-only; + qcom,msm-bus,vectors-KBps = + <1 590 0 0>, + <1 590 0 76800>, + <1 590 0 150000>, + <1 590 0 300000>; + }; + }; + + sde_rscc: qcom,sde_rscc@af20000 { + cell-index = <0>; + compatible = "qcom,sde-rsc"; + reg = <0xaf20000 0x1c44>, + <0xaf30000 0x3fd4>; + reg-names = "drv", "wrapper"; + qcom,sde-rsc-version = <1>; + + vdd-supply = <&mdss_core_gdsc>; + clocks = <&clock_dispcc DISP_CC_MDSS_RSCC_VSYNC_CLK>, + <&clock_dispcc DISP_CC_MDSS_RSCC_AHB_CLK>; + clock-names = "vsync_clk", "iface_clk"; + clock-rate = <0 0>; + + qcom,sde-dram-channels = <2>; + + mboxes = <&disp_rsc 0>; + mbox-names = "disp_rsc"; + + /* data and reg bus scale settings */ + qcom,sde-data-bus { + qcom,msm-bus,name = "disp_rsc_mnoc"; + qcom,msm-bus,active-only; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + <20003 20515 0 0>, <20004 20515 0 0>, + <20003 20515 0 6400000>, <20004 20515 0 6400000>, + <20003 20515 0 6400000>, <20004 20515 0 6400000>; + }; + + qcom,sde-llcc-bus { + qcom,msm-bus,name = "disp_rsc_llcc"; + qcom,msm-bus,active-only; + qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <20001 20513 0 0>, + <20001 20513 0 6400000>, + <20001 20513 0 6400000>; + }; + + qcom,sde-ebi-bus { + qcom,msm-bus,name = "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@ae00000 { + compatible = "qcom,sde_rotator"; + reg = <0x0ae00000 0xac000>, + <0x0aeb8000 0x3000>; + reg-names = "mdp_phys", + "rot_vbif_phys"; + + #list-cells = <1>; + + qcom,mdss-rot-mode = <1>; + qcom,mdss-highest-bank-bit = <0x2>; + + /* 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_AXI_CLK>, + <&clock_dispcc DISP_CC_MDSS_AHB_CLK>, + <&clock_dispcc DISP_CC_MDSS_ROT_CLK>, + <&clock_dispcc DISP_CC_MDSS_AXI_CLK>; + clock-names = "gcc_iface", "gcc_bus", + "iface_clk", "rot_clk", "axi_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>; + + /* Inline rotator QoS Setting */ + /* setting default register values for RD - qos/danger/safe */ + qcom,mdss-inline-rot-qos-lut = <0x44556677 0x00112233 + 0x44556677 0x00112233>; + qcom,mdss-inline-rot-danger-lut = <0x0055aaff 0x0000ffff>; + qcom,mdss-inline-rot-safe-lut = <0x0000f000 0x0000ff00>; + + qcom,mdss-default-ot-rd-limit = <32>; + qcom,mdss-default-ot-wr-limit = <32>; + + qcom,mdss-sbuf-headroom = <20>; + + cache-slice-names = "rotator"; + cache-slices = <&llcc 4>; + + /* 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,active-only; + qcom,msm-bus,vectors-KBps = + <1 590 0 0>, + <1 590 0 76800>; + }; + + smmu_rot_unsec: qcom,smmu_rot_unsec_cb { + compatible = "qcom,smmu_sde_rot_unsec"; + iommus = <&apps_smmu 0x1090 0x0>; + }; + + smmu_rot_sec: qcom,smmu_rot_sec_cb { + compatible = "qcom,smmu_sde_rot_sec"; + iommus = <&apps_smmu 0x1091 0x0>; + }; + }; + + mdss_dsi0: qcom,mdss_dsi_ctrl0@ae94000 { + compatible = "qcom,dsi-ctrl-hw-v2.2"; + 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 = <&pm8998_l26>; + 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,null-insertion-enabled; + qcom,ctrl-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,ctrl-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-1p2"; + qcom,supply-min-voltage = <1200000>; + qcom,supply-max-voltage = <1200000>; + qcom,supply-enable-load = <21800>; + qcom,supply-disable-load = <4>; + }; + }; + }; + + mdss_dsi1: qcom,mdss_dsi_ctrl1@ae96000 { + compatible = "qcom,dsi-ctrl-hw-v2.2"; + 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 = <&pm8998_l26>; + 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,null-insertion-enabled; + qcom,ctrl-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,ctrl-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-1p2"; + qcom,supply-min-voltage = <1200000>; + qcom,supply-max-voltage = <1200000>; + qcom,supply-enable-load = <21800>; + qcom,supply-disable-load = <4>; + }; + }; + }; + + mdss_dsi_phy0: qcom,mdss_dsi_phy0@ae94400 { + compatible = "qcom,dsi-phy-v3.0"; + label = "dsi-phy-0"; + cell-index = <0>; + reg = <0xae94400 0x7c0>; + reg-names = "dsi_phy"; + gdsc-supply = <&mdss_core_gdsc>; + vdda-0p9-supply = <&pm8998_l1>; + qcom,platform-strength-ctrl = [55 03 + 55 03 + 55 03 + 55 03 + 55 00]; + qcom,platform-lane-config = [00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 80]; + qcom,platform-regulator-settings = [1d 1d 1d 1d 1d]; + qcom,phy-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + qcom,phy-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-0p9"; + qcom,supply-min-voltage = <880000>; + qcom,supply-max-voltage = <880000>; + qcom,supply-enable-load = <36000>; + qcom,supply-disable-load = <32>; + }; + }; + }; + + mdss_dsi_phy1: qcom,mdss_dsi_phy0@ae96400 { + compatible = "qcom,dsi-phy-v3.0"; + label = "dsi-phy-1"; + cell-index = <1>; + reg = <0xae96400 0x7c0>; + reg-names = "dsi_phy"; + gdsc-supply = <&mdss_core_gdsc>; + vdda-0p9-supply = <&pm8998_l1>; + 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 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 80]; + qcom,phy-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + qcom,phy-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-0p9"; + qcom,supply-min-voltage = <880000>; + qcom,supply-max-voltage = <880000>; + qcom,supply-enable-load = <36000>; + qcom,supply-disable-load = <32>; + }; + }; + }; + + sde_dp: qcom,dp_display@0{ + cell-index = <0>; + compatible = "qcom,dp-display"; + + gdsc-supply = <&mdss_core_gdsc>; + vdda-1p2-supply = <&pm8998_l26>; + vdda-0p9-supply = <&pm8998_l1>; + + reg = <0xae90000 0x0dc>, + <0xae90200 0x0c0>, + <0xae90400 0x508>, + <0xae90a00 0x094>, + <0x88eaa00 0x200>, + <0x88ea200 0x200>, + <0x88ea600 0x200>, + <0xaf02000 0x1a0>, + <0x780000 0x621c>, + <0x88ea030 0x10>, + <0x88e8000 0x20>, + <0x0aee1000 0x034>; + /* 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"; + + interrupt-parent = <&mdss_mdp>; + interrupts = <12 0>; + + clocks = <&clock_dispcc DISP_CC_MDSS_DP_AUX_CLK>, + <&clock_rpmh RPMH_CXO_CLK>, + <&clock_gcc GCC_USB3_PRIM_CLKREF_CLK>, + <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>, + <&clock_gcc GCC_USB3_PRIM_PHY_PIPE_CLK>, + <&clock_dispcc DISP_CC_MDSS_DP_LINK_CLK>, + <&clock_dispcc DISP_CC_MDSS_DP_LINK_INTF_CLK>, + <&clock_dispcc DISP_CC_MDSS_DP_PIXEL_CLK>, + <&clock_dispcc DISP_CC_MDSS_DP_CRYPTO_CLK>, + <&clock_dispcc DISP_CC_MDSS_DP_PIXEL_CLK_SRC>, + <&mdss_dp_pll DP_VCO_DIVIDED_CLK_SRC_MUX>; + clock-names = "core_aux_clk", "core_usb_ref_clk_src", + "core_usb_ref_clk", "core_usb_cfg_ahb_clk", + "core_usb_pipe_clk", "ctrl_link_clk", + "ctrl_link_iface_clk", "ctrl_pixel_clk", + "crypto_clk", "pixel_clk_rcg", "pixel_parent"; + + qcom,aux-cfg0-settings = [20 00]; + qcom,aux-cfg1-settings = [24 13 23 1d]; + qcom,aux-cfg2-settings = [28 24]; + qcom,aux-cfg3-settings = [2c 00]; + qcom,aux-cfg4-settings = [30 0a]; + qcom,aux-cfg5-settings = [34 26]; + qcom,aux-cfg6-settings = [38 0a]; + qcom,aux-cfg7-settings = [3c 03]; + qcom,aux-cfg8-settings = [40 bb]; + qcom,aux-cfg9-settings = [44 03]; + + qcom,max-pclk-frequency-khz = <675000>; + + qcom,ctrl-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,ctrl-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-1p2"; + qcom,supply-min-voltage = <1200000>; + qcom,supply-max-voltage = <1200000>; + qcom,supply-enable-load = <21800>; + qcom,supply-disable-load = <4>; + }; + }; + + qcom,phy-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,phy-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda-0p9"; + qcom,supply-min-voltage = <880000>; + qcom,supply-max-voltage = <880000>; + qcom,supply-enable-load = <36000>; + qcom,supply-disable-load = <32>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-smp2p.dtsi b/arch/arm64/boot/dts/qcom/sdm845-smp2p.dtsi new file mode 100644 index 000000000000..a2978358bfbb --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-smp2p.dtsi @@ -0,0 +1,345 @@ +/* Copyright (c) 2016-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. + */ + +#include + +&soc { + qcom,smp2p-modem@1799000c { + compatible = "qcom,smp2p"; + reg = <0x1799000c 0x4>; + qcom,remote-pid = <1>; + qcom,irq-bitmask = <0x4000>; + interrupts = ; + }; + + qcom,smp2p-adsp@1799000c { + compatible = "qcom,smp2p"; + reg = <0x1799000c 0x4>; + qcom,remote-pid = <2>; + qcom,irq-bitmask = <0x400>; + interrupts = ; + }; + + qcom,smp2p-dsps@1799000c { + compatible = "qcom,smp2p"; + reg = <0x1799000c 0x4>; + qcom,remote-pid = <3>; + qcom,irq-bitmask = <0x4000000>; + interrupts = ; + }; + + qcom,smp2p-cdsp@1799000c { + compatible = "qcom,smp2p"; + reg = <0x1799000c 0x4>; + qcom,remote-pid = <5>; + qcom,irq-bitmask = <0x40>; + interrupts = ; + }; + + + smp2pgpio_smp2p_15_in: qcom,smp2pgpio-smp2p-15-in { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "smp2p"; + qcom,remote-pid = <15>; + qcom,is-inbound; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio_test_smp2p_15_in { + compatible = "qcom,smp2pgpio_test_smp2p_15_in"; + gpios = <&smp2pgpio_smp2p_15_in 0 0>; + }; + + smp2pgpio_smp2p_15_out: qcom,smp2pgpio-smp2p-15-out { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "smp2p"; + qcom,remote-pid = <15>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio_test_smp2p_15_out { + compatible = "qcom,smp2pgpio_test_smp2p_15_out"; + gpios = <&smp2pgpio_smp2p_15_out 0 0>; + }; + + smp2pgpio_smp2p_1_in: qcom,smp2pgpio-smp2p-1-in { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "smp2p"; + qcom,remote-pid = <1>; + qcom,is-inbound; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio_test_smp2p_1_in { + compatible = "qcom,smp2pgpio_test_smp2p_1_in"; + gpios = <&smp2pgpio_smp2p_1_in 0 0>; + }; + + smp2pgpio_smp2p_1_out: qcom,smp2pgpio-smp2p-1-out { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "smp2p"; + qcom,remote-pid = <1>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio_test_smp2p_1_out { + compatible = "qcom,smp2pgpio_test_smp2p_1_out"; + gpios = <&smp2pgpio_smp2p_1_out 0 0>; + }; + + smp2pgpio_smp2p_2_in: qcom,smp2pgpio-smp2p-2-in { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "smp2p"; + qcom,remote-pid = <2>; + qcom,is-inbound; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio_test_smp2p_2_in { + compatible = "qcom,smp2pgpio_test_smp2p_2_in"; + gpios = <&smp2pgpio_smp2p_2_in 0 0>; + }; + + smp2pgpio_smp2p_2_out: qcom,smp2pgpio-smp2p-2-out { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "smp2p"; + qcom,remote-pid = <2>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio_test_smp2p_2_out { + compatible = "qcom,smp2pgpio_test_smp2p_2_out"; + gpios = <&smp2pgpio_smp2p_2_out 0 0>; + }; + + smp2pgpio_smp2p_3_in: qcom,smp2pgpio-smp2p-3-in { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "smp2p"; + qcom,remote-pid = <3>; + qcom,is-inbound; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio_test_smp2p_3_in { + compatible = "qcom,smp2pgpio_test_smp2p_3_in"; + gpios = <&smp2pgpio_smp2p_3_in 0 0>; + }; + + smp2pgpio_smp2p_3_out: qcom,smp2pgpio-smp2p-3-out { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "smp2p"; + qcom,remote-pid = <3>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio_test_smp2p_3_out { + compatible = "qcom,smp2pgpio_test_smp2p_3_out"; + gpios = <&smp2pgpio_smp2p_3_out 0 0>; + }; + + smp2pgpio_smp2p_5_in: qcom,smp2pgpio-smp2p-5-in { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "smp2p"; + qcom,remote-pid = <5>; + qcom,is-inbound; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio_test_smp2p_5_in { + compatible = "qcom,smp2pgpio_test_smp2p_5_in"; + gpios = <&smp2pgpio_smp2p_5_in 0 0>; + }; + + smp2pgpio_smp2p_5_out: qcom,smp2pgpio-smp2p-5-out { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "smp2p"; + qcom,remote-pid = <5>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio_test_smp2p_5_out { + compatible = "qcom,smp2pgpio_test_smp2p_5_out"; + gpios = <&smp2pgpio_smp2p_5_out 0 0>; + }; + + smp2pgpio_sleepstate_3_out: qcom,smp2pgpio-sleepstate-gpio-3-out { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "sleepstate"; + qcom,remote-pid = <3>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + qcom,smp2pgpio-sleepstate-3-out { + compatible = "qcom,smp2pgpio_sleepstate_3_out"; + gpios = <&smp2pgpio_sleepstate_3_out 0 0>; + }; + + /* ssr - inbound entry from mss */ + smp2pgpio_ssr_smp2p_1_in: qcom,smp2pgpio-ssr-smp2p-1-in { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "slave-kernel"; + qcom,remote-pid = <1>; + qcom,is-inbound; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + /* ssr - outbound entry to mss */ + smp2pgpio_ssr_smp2p_1_out: qcom,smp2pgpio-ssr-smp2p-1-out { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "master-kernel"; + qcom,remote-pid = <1>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + /* ssr - inbound entry from lpass */ + smp2pgpio_ssr_smp2p_2_in: qcom,smp2pgpio-ssr-smp2p-2-in { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "slave-kernel"; + qcom,remote-pid = <2>; + qcom,is-inbound; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + /* ssr - outbound entry to lpass */ + smp2pgpio_ssr_smp2p_2_out: qcom,smp2pgpio-ssr-smp2p-2-out { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "master-kernel"; + qcom,remote-pid = <2>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + /* ssr - inbound entry from ssc */ + smp2pgpio_ssr_smp2p_3_in: qcom,smp2pgpio-ssr-smp2p-3-in { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "slave-kernel"; + qcom,remote-pid = <3>; + qcom,is-inbound; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + /* ssr - outbound entry to ssc */ + smp2pgpio_ssr_smp2p_3_out: qcom,smp2pgpio-ssr-smp2p-3-out { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "master-kernel"; + qcom,remote-pid = <3>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + /* ssr - inbound entry from cdsp */ + smp2pgpio_ssr_smp2p_5_in: qcom,smp2pgpio-ssr-smp2p-5-in { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "slave-kernel"; + qcom,remote-pid = <5>; + qcom,is-inbound; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + /* ssr - outbound entry to cdsp */ + smp2pgpio_ssr_smp2p_5_out: qcom,smp2pgpio-ssr-smp2p-5-out { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "master-kernel"; + qcom,remote-pid = <5>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + /* ipa - outbound entry to mss */ + smp2pgpio_ipa_1_out: qcom,smp2pgpio-ipa-1-out { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "ipa"; + qcom,remote-pid = <1>; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + /* ipa - inbound entry from mss */ + smp2pgpio_ipa_1_in: qcom,smp2pgpio-ipa-1-in { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "ipa"; + qcom,remote-pid = <1>; + qcom,is-inbound; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; + + /* wlan - inbound entry from mss/WLAN PD */ + smp2pgpio_wlan_1_in: qcom,smp2pgpio-wlan-1-in { + compatible = "qcom,smp2pgpio"; + qcom,entry-name = "wlan"; + qcom,remote-pid = <1>; + qcom,is-inbound; + gpio-controller; + #gpio-cells = <2>; + interrupt-controller; + #interrupt-cells = <2>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi new file mode 100644 index 000000000000..3c84a6b58662 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi @@ -0,0 +1,497 @@ +/* + * Copyright (c) 2017-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. + */ + +&soc { + cam_csiphy0: qcom,csiphy@ac65000 { + cell-index = <0>; + compatible = "qcom,csiphy-v1.0", "qcom,csiphy"; + reg = <0x0ac65000 0x1000>; + reg-names = "csiphy"; + reg-cam-base = <0x65000>; + interrupts = <0 477 0>; + interrupt-names = "csiphy"; + regulator-names = "gdscr", "refgen"; + gdscr-supply = <&titan_top_gdsc>; + refgen-supply = <&refgen>; + csi-vdd-voltage = <1200000>; + mipi-csi-vdd-supply = <&pm8998_l1>; + clocks = <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&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 = "camnoc_axi_clk", + "soc_ahb_clk", + "slow_ahb_src_clk", + "cpas_ahb_clk", + "cphy_rx_clk_src", + "csiphy0_clk", + "csi0phytimer_clk_src", + "csi0phytimer_clk"; + clock-cntl-level = "turbo"; + clock-rates = + <0 0 0 0 384000000 0 269333333 0>; + status = "ok"; + }; + + cam_csiphy1: qcom,csiphy@ac66000{ + cell-index = <1>; + compatible = "qcom,csiphy-v1.0", "qcom,csiphy"; + reg = <0xac66000 0x1000>; + reg-names = "csiphy"; + reg-cam-base = <0x66000>; + interrupts = <0 478 0>; + interrupt-names = "csiphy"; + regulator-names = "gdscr", "refgen"; + gdscr-supply = <&titan_top_gdsc>; + refgen-supply = <&refgen>; + csi-vdd-voltage = <1200000>; + mipi-csi-vdd-supply = <&pm8998_l1>; + clocks = <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&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 = "camnoc_axi_clk", + "soc_ahb_clk", + "slow_ahb_src_clk", + "cpas_ahb_clk", + "cphy_rx_clk_src", + "csiphy1_clk", + "csi1phytimer_clk_src", + "csi1phytimer_clk"; + clock-cntl-level = "turbo"; + clock-rates = + <0 0 0 0 384000000 0 269333333 0>; + + status = "ok"; + }; + + cam_csiphy2: qcom,csiphy@ac67000 { + cell-index = <2>; + compatible = "qcom,csiphy-v1.0", "qcom,csiphy"; + reg = <0xac67000 0x1000>; + reg-names = "csiphy"; + reg-cam-base = <0x67000>; + interrupts = <0 479 0>; + interrupt-names = "csiphy"; + regulator-names = "gdscr", "refgen"; + gdscr-supply = <&titan_top_gdsc>; + refgen-supply = <&refgen>; + csi-vdd-voltage = <1200000>; + mipi-csi-vdd-supply = <&pm8998_l1>; + clocks = <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&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 = "camnoc_axi_clk", + "soc_ahb_clk", + "slow_ahb_src_clk", + "cpas_ahb_clk", + "cphy_rx_clk_src", + "csiphy2_clk", + "csi2phytimer_clk_src", + "csi2phytimer_clk"; + clock-cntl-level = "turbo"; + clock-rates = + <0 0 0 0 384000000 0 269333333 0>; + status = "ok"; + }; + + cam_csiphy3: qcom,csiphy@ac68000 { + cell-index = <3>; + compatible = "qcom,csiphy-v1.0", "qcom,csiphy"; + reg = <0xac68000 0x1000>; + reg-names = "csiphy"; + reg-cam-base = <0x68000>; + interrupts = <0 448 0>; + interrupt-names = "csiphy"; + regulator-names = "gdscr", "refgen"; + gdscr-supply = <&titan_top_gdsc>; + refgen-supply = <&refgen>; + csi-vdd-voltage = <1200000>; + mipi-csi-vdd-supply = <&pm8998_l1>; + clocks = <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&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 = "camnoc_axi_clk", + "soc_ahb_clk", + "slow_ahb_src_clk", + "cpas_ahb_clk", + "cphy_rx_clk_src", + "csiphy3_clk", + "csi3phytimer_clk_src", + "csi3phytimer_clk"; + src-clock-name = "csi3phytimer_clk_src"; + clock-cntl-level = "turbo"; + clock-rates = + <0 0 0 0 384000000 0 269333333 0>; + status = "ok"; + }; + + qcom,cam_smmu { + compatible = "qcom,msm-cam-smmu"; + status = "ok"; + non-fatal-fault-disabled; + + msm_cam_smmu_lrme { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x1038 0x0>, + <&apps_smmu 0x1058 0x0>; + label = "lrme"; + lrme_iova_mem_map: iova-mem-map { + iova-mem-region-shared { + /* Shared region is 100MB long */ + iova-region-name = "shared"; + iova-region-start = <0x7400000>; + iova-region-len = <0x6400000>; + iova-region-id = <0x1>; + status = "ok"; + }; + /* IO region is approximately 3.3 GB */ + iova-mem-region-io { + iova-region-name = "io"; + iova-region-start = <0xd800000>; + iova-region-len = <0xd2800000>; + iova-region-id = <0x3>; + status = "ok"; + }; + }; + }; + + msm_cam_smmu_ife { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x808 0x0>, + <&apps_smmu 0x810 0x8>, + <&apps_smmu 0xc08 0x0>, + <&apps_smmu 0xc10 0x8>; + 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_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 0x107A 0x2>, + <&apps_smmu 0x1020 0x8>, + <&apps_smmu 0x1040 0x8>, + <&apps_smmu 0x1030 0x0>, + <&apps_smmu 0x1050 0x0>; + 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 150MB long */ + iova-region-name = "shared"; + iova-region-start = <0x7400000>; + iova-region-len = <0x9600000>; + iova-region-id = <0x1>; + iova-granularity = <0x15>; + status = "ok"; + }; + + iova-mem-region-secondary-heap { + /* Secondary heap region is 1MB long */ + iova-region-name = "secheap"; + iova-region-start = <0x10A00000>; + iova-region-len = <0x100000>; + iova-region-id = <0x4>; + status = "ok"; + }; + + iova-mem-region-io { + /* IO region is approximately 3 GB */ + iova-region-name = "io"; + iova-region-start = <0x10C00000>; + iova-region-len = <0xCF300000>; + iova-region-id = <0x3>; + status = "ok"; + }; + + iova-mem-qdss-region { + /* qdss region is approximately 1MB */ + iova-region-name = "qdss"; + iova-region-start = <0x10B00000>; + iova-region-len = <0x100000>; + iova-region-id = <0x5>; + qdss-phy-addr = <0x16790000>; + status = "ok"; + }; + }; + }; + + msm_cam_smmu_cpas_cdm { + compatible = "qcom,msm-cam-smmu-cb"; + iommus = <&apps_smmu 0x1000 0x0>; + label = "cpas-cdm0"; + 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@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>; + interrupt-names = "cpas_camnoc"; + interrupts = <0 459 0>; + qcom,cpas-hw-ver = <0x170110>; /* Titan v170 v1.1.0 */ + camnoc-axi-min-ib-bw = <3000000000>; + regulator-names = "camss-vdd"; + camss-vdd-supply = <&titan_top_gdsc>; + clock-names = "gcc_ahb_clk", + "gcc_axi_clk", + "soc_ahb_clk", + "slow_ahb_clk_src", + "cpas_ahb_clk", + "camnoc_axi_clk"; + clocks = <&clock_gcc GCC_CAMERA_AHB_CLK>, + <&clock_gcc GCC_CAMERA_AXI_CLK>, + <&clock_camcc CAM_CC_SOC_AHB_CLK>, + <&clock_camcc CAM_CC_SLOW_AHB_CLK_SRC>, + <&clock_camcc CAM_CC_CPAS_AHB_CLK>, + <&clock_camcc CAM_CC_CAMNOC_AXI_CLK>; + src-clock-name = "slow_ahb_clk_src"; + clock-rates = <0 0 0 0 0 0>, + <0 0 0 19200000 0 0>, + <0 0 0 80000000 0 0>, + <0 0 0 80000000 0 0>, + <0 0 0 80000000 0 0>, + <0 0 0 80000000 0 0>, + <0 0 0 80000000 0 0>; + clock-cntl-level = "suspend", "minsvs", "lowsvs", "svs", + "svs_l1", "nominal", "turbo"; + qcom,msm-bus,name = "cam_ahb"; + qcom,msm-bus,num-cases = <7>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + , + , + , + , + , + ; + vdd-corners = ; + vdd-corner-ahb-mapping = "suspend", "suspend", + "minsvs", "lowsvs", "svs", "svs_l1", + "nominal", "nominal", "nominal", + "turbo", "turbo"; + client-id-based; + client-names = + "csiphy0", "csiphy1", "csiphy2", "csiphy3", "cci0", + "csid0", "csid1", "csid2", + "ife0", "ife1", "ife2", "ipe0", + "ipe1", "cam-cdm-intf0", "cpas-cdm0", "bps0", + "icp0", "jpeg-dma0", "jpeg-enc0", "fd0", "lrmecpas0"; + client-axi-port-names = + "cam_hf_1", "cam_hf_2", "cam_hf_2", "cam_hf_2", + "cam_sf_1", "cam_hf_1", "cam_hf_2", "cam_hf_2", + "cam_hf_1", "cam_hf_2", "cam_hf_2", "cam_sf_1", + "cam_sf_1", "cam_sf_1", "cam_sf_1", "cam_sf_1", + "cam_sf_1", "cam_sf_1", "cam_sf_1", "cam_sf_1", + "cam_sf_1"; + client-bus-camnoc-based; + qcom,axi-port-list { + qcom,axi-port1 { + qcom,axi-port-name = "cam_hf_1"; + qcom,axi-port-mnoc { + qcom,msm-bus,name = "cam_hf_1_mnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + qcom,axi-port-camnoc { + qcom,msm-bus,name = "cam_hf_1_camnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + }; + qcom,axi-port2 { + qcom,axi-port-name = "cam_hf_2"; + qcom,axi-port-mnoc { + qcom,msm-bus,name = "cam_hf_2_mnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + qcom,axi-port-camnoc { + qcom,msm-bus,name = "cam_hf_2_camnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + }; + qcom,axi-port3 { + qcom,axi-port-name = "cam_sf_1"; + qcom,axi-port-mnoc { + qcom,msm-bus,name = "cam_sf_1_mnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + qcom,axi-port-camnoc { + qcom,msm-bus,name = "cam_sf_1_camnoc"; + qcom,msm-bus-vector-dyn-vote; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + , + ; + }; + }; + }; + }; + + qcom,cam-lrme { + compatible = "qcom,cam-lrme"; + arch-compat = "lrme"; + status = "ok"; + }; + + cam_lrme: qcom,lrme@ac6b000 { + cell-index = <0>; + compatible = "qcom,lrme"; + reg-names = "lrme"; + reg = <0xac6b000 0xa00>; + reg-cam-base = <0x6b000>; + interrupt-names = "lrme"; + interrupts = <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 200000000 200000000>, + <0 0 0 0 0 269000000 269000000>, + <0 0 0 0 0 320000000 320000000>, + <0 0 0 0 0 400000000 400000000>; + + clock-cntl-level = "lowsvs", "svs", "svs_l1", "turbo"; + src-clock-name = "lrme_clk_src"; + status = "ok"; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-v2-mtp-overlay.dts new file mode 100644 index 000000000000..e049357e6f61 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-v2-mtp-overlay.dts @@ -0,0 +1,31 @@ +/* Copyright (c) 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. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-mtp.dtsi" +#include "sdm845-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM845 v2 MTP"; + compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp"; + qcom,msm-id = <321 0x20000>; + qcom,board-id = <8 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-mtp.dts b/arch/arm64/boot/dts/qcom/sdm845-v2-mtp.dts new file mode 100644 index 000000000000..1b86ab1faec3 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-v2-mtp.dts @@ -0,0 +1,25 @@ +/* Copyright (c) 2017,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. + */ + + +/dts-v1/; + +#include "sdm845-v2.dtsi" +#include "sdm845-sde-display.dtsi" +#include "sdm845-mtp.dtsi" +#include "sdm845-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. MSM sdm845 V2 MTP"; + compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp"; + qcom,board-id = <8 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.1-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-v2.1-mtp-overlay.dts new file mode 100644 index 000000000000..7b3573a3b030 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-v2.1-mtp-overlay.dts @@ -0,0 +1,31 @@ +/* Copyright (c) 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. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-mtp.dtsi" +#include "sdm845-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM845 v2.1 MTP"; + compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp"; + qcom,msm-id = <321 0x20001>; + qcom,board-id = <8 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.1-mtp.dts b/arch/arm64/boot/dts/qcom/sdm845-v2.1-mtp.dts new file mode 100644 index 000000000000..444ce98e0cc5 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-v2.1-mtp.dts @@ -0,0 +1,111 @@ +/* Copyright (c) 2019-2020, 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. + */ + + +/dts-v1/; + +#include "sdm845-v2.1.dtsi" +#include "sdm845-sde-display.dtsi" +#include "sdm845-mtp.dtsi" +#include "sdm845-audio-overlay.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. MSM sdm845 V2.1 MTP"; + compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp"; + qcom,board-id = <8 0>; +}; + +&tlmm { + sdc2_wlan_gpio_on: sdc2_wlan_gpio_on { + mux { + pins = "gpio11"; + function = "gpio"; + }; + config { + pins = "gpio11"; + drive-strength = <10>; + bias-pull-up; + output-high; + }; + }; + + sdc2_wlan_gpio_off: sdc2_wlan_gpio_off { + mux { + pins = "gpio11"; + function = "gpio"; + }; + config { + pins = "gpio11"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; +}; + +&sdhc_2 { + /delete-property/cd-gpios; + #address-cells = <0>; + interrupt-parent = <&sdhc_2>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 204 0 + 1 &intc 0 222 0 + 2 &tlmm 11 0>; + interrupt-names = "hc_irq", "pwr_irq", "sdiowakeup_irq"; + + vdd-supply = <&pm8998_l23>; + qcom,vdd-voltage-level = <3200000 3300000>; + vdd-io-supply = <&pm8998_s4>; + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-current-level = <15000 400000>; + qcom,vdd-io-current-level = <200 50000>; + qcom,clk-rates = <400000 25000000 50000000>; + qcom,bus-speed-mode = "SDR12"; + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on + &sdc2_wlan_gpio_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off + &sdc2_wlan_gpio_off>; + qcom,nonremovable; + qcom,core_3_0v_support; + status = "ok"; +}; + +&pm8998_l6 { + regulator-boot-on; + regulator-always-on; +}; + +&pm8998_l23 { + regulator-boot-on; + regulator-always-on; +}; + +&soc { + qcom,cnss-sdio { + compatible = "qcom,cnss_sdio"; + reg = <0x87a00000 0x200000>; + reg-names = "ramdump"; + subsys-name = "AR6320"; + qcom,wlan-ramdump-dynamic = <0x200000>; + qcom,msm-bus,name = "msm-cnss"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <79 512 0 0>, /* No vote */ + <79 512 6250 200000>, /* 50 Mbps */ + <79 512 25000 200000>, /* 200 Mbps */ + <79 512 2048000 4096000>; /* MAX */ + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.1.dts b/arch/arm64/boot/dts/qcom/sdm845-v2.1.dts new file mode 100644 index 000000000000..2902a6042927 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-v2.1.dts @@ -0,0 +1,22 @@ +/* Copyright (c) 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. + */ + +/dts-v1/; + +#include "sdm845-v2.1.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM845 v2.1 SoC"; + compatible = "qcom,sdm845"; + qcom,board-id = <0 0>; +}; + diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.1.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2.1.dtsi new file mode 100644 index 000000000000..b29827270c26 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-v2.1.dtsi @@ -0,0 +1,31 @@ +/* Copyright (c) 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. + */ + +#include "sdm845-v2.dtsi" +#include "sdm845-v2-camera.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM845 V2.1"; + qcom,msm-id = <321 0x20001>; +}; + +&spmi_bus { + /delete-property/ qcom,enable-ahb-bus-workaround; +}; + +&clock_gcc { + compatible = "qcom,gcc-sdm845-v2.1", "syscon"; +}; + +&apps_smmu { + /delete-property/ qcom,no-asid-retention; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.dts b/arch/arm64/boot/dts/qcom/sdm845-v2.dts new file mode 100644 index 000000000000..d36d0fd55d83 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-v2.dts @@ -0,0 +1,21 @@ +/* Copyright (c) 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. + */ + +/dts-v1/; + +#include "sdm845-v2.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM845 v2 SoC"; + compatible = "qcom,sdm845"; + qcom,board-id = <0 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi new file mode 100644 index 000000000000..229d06b786e1 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi @@ -0,0 +1,679 @@ +/* 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. + */ + +#include "sdm845.dtsi" +#include "sdm845-v2-camera.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM845 V2"; + qcom,msm-id = <321 0x20000>; +}; + +&sdhc_2 { + /delete-property/ qcom,sdr104-wa; +}; + +/delete-node/ &pdc; + +&tlmm { + compatible = "qcom,sdm845-pinctrl-v2"; +}; + +&soc { + 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"; + }; + }; + + gpu_gx_domain_addr: syscon@0x5091508 { + compatible = "syscon"; + reg = <0x5091508 0x4>; + }; + + gpu_gx_sw_reset: syscon@0x5091008 { + compatible = "syscon"; + reg = <0x5091008 0x4>; + }; + + pdc: interrupt-controller@0xb220000{ + compatible = "qcom,pdc-sdm845-v2"; + reg = <0xb220000 0x400>; + #interrupt-cells = <3>; + interrupt-parent = <&intc>; + interrupt-controller; + }; + +}; + +&pil_modem { + qcom,mss_pdc_offset = <9>; +}; + +&clock_cpucc { + compatible = "qcom,clk-cpu-osm-v2"; +}; + +&pcie1 { + qcom,phy-sequence = <0x1804 0x03 0x0 + 0x00dc 0x27 0x0 + 0x0014 0x01 0x0 + 0x0020 0x31 0x0 + 0x0024 0x01 0x0 + 0x0028 0xde 0x0 + 0x002c 0x07 0x0 + 0x0034 0x4c 0x0 + 0x0038 0x06 0x0 + 0x0054 0x18 0x0 + 0x0058 0xb0 0x0 + 0x006c 0x8c 0x0 + 0x0070 0x20 0x0 + 0x0078 0x14 0x0 + 0x007c 0x34 0x0 + 0x00b4 0x06 0x0 + 0x00b8 0x06 0x0 + 0x00c0 0x16 0x0 + 0x00c4 0x16 0x0 + 0x00cc 0x36 0x0 + 0x00d0 0x36 0x0 + 0x00f0 0x05 0x0 + 0x00f8 0x42 0x0 + 0x0100 0x82 0x0 + 0x0108 0x68 0x0 + 0x011c 0x55 0x0 + 0x0120 0x55 0x0 + 0x0124 0x03 0x0 + 0x0128 0xab 0x0 + 0x012c 0xaa 0x0 + 0x0130 0x02 0x0 + 0x0150 0x3f 0x0 + 0x0158 0x3f 0x0 + 0x0178 0x10 0x0 + 0x01cc 0x04 0x0 + 0x01d0 0x30 0x0 + 0x01e0 0x04 0x0 + 0x01e8 0x73 0x0 + 0x01f0 0x1c 0x0 + 0x01fc 0x15 0x0 + 0x021c 0x04 0x0 + 0x0224 0x01 0x0 + 0x0228 0x22 0x0 + 0x022c 0x00 0x0 + 0x0098 0x05 0x0 + 0x080c 0x00 0x0 + 0x0818 0x0d 0x0 + 0x0860 0x01 0x0 + 0x0864 0x3a 0x0 + 0x087c 0x2f 0x0 + 0x08c0 0x09 0x0 + 0x08c4 0x09 0x0 + 0x08c8 0x1a 0x0 + 0x08d0 0x01 0x0 + 0x08d4 0x07 0x0 + 0x08d8 0x31 0x0 + 0x08dc 0x31 0x0 + 0x08e0 0x03 0x0 + 0x08fc 0x02 0x0 + 0x0900 0x01 0x0 + 0x0908 0x12 0x0 + 0x0914 0x25 0x0 + 0x0918 0x00 0x0 + 0x091c 0x05 0x0 + 0x0920 0x01 0x0 + 0x0924 0x26 0x0 + 0x0928 0x12 0x0 + 0x0930 0x04 0x0 + 0x0934 0x04 0x0 + 0x0938 0x09 0x0 + 0x0954 0x15 0x0 + 0x0960 0x32 0x0 + 0x0968 0x7f 0x0 + 0x096c 0x07 0x0 + 0x0978 0x04 0x0 + 0x0980 0x70 0x0 + 0x0984 0x8b 0x0 + 0x0988 0x08 0x0 + 0x098c 0x09 0x0 + 0x0990 0x03 0x0 + 0x0994 0x04 0x0 + 0x0998 0x02 0x0 + 0x099c 0x0c 0x0 + 0x09a4 0x02 0x0 + 0x09c0 0x5c 0x0 + 0x09c4 0x3e 0x0 + 0x09c8 0x3f 0x0 + 0x0a30 0x01 0x0 + 0x0a34 0xa0 0x0 + 0x0a38 0x08 0x0 + 0x0aa4 0x01 0x0 + 0x0aac 0xc3 0x0 + 0x0ab0 0x00 0x0 + 0x0ab8 0x8c 0x0 + 0x0ac0 0x7f 0x0 + 0x0ac4 0x2a 0x0 + 0x0810 0x0c 0x0 + 0x0814 0x00 0x0 + 0x0acc 0x04 0x0 + 0x093c 0x20 0x0 + 0x100c 0x00 0x0 + 0x1018 0x0d 0x0 + 0x1060 0x01 0x0 + 0x1064 0x3a 0x0 + 0x107c 0x2f 0x0 + 0x10c0 0x09 0x0 + 0x10c4 0x09 0x0 + 0x10c8 0x1a 0x0 + 0x10d0 0x01 0x0 + 0x10d4 0x07 0x0 + 0x10d8 0x31 0x0 + 0x10dc 0x31 0x0 + 0x10e0 0x03 0x0 + 0x10fc 0x02 0x0 + 0x1100 0x01 0x0 + 0x1108 0x12 0x0 + 0x1114 0x25 0x0 + 0x1118 0x00 0x0 + 0x111c 0x05 0x0 + 0x1120 0x01 0x0 + 0x1124 0x26 0x0 + 0x1128 0x12 0x0 + 0x1130 0x04 0x0 + 0x1134 0x04 0x0 + 0x1138 0x09 0x0 + 0x1154 0x15 0x0 + 0x1160 0x32 0x0 + 0x1168 0x7f 0x0 + 0x116c 0x07 0x0 + 0x1178 0x04 0x0 + 0x1180 0x70 0x0 + 0x1184 0x8b 0x0 + 0x1188 0x08 0x0 + 0x118c 0x09 0x0 + 0x1190 0x03 0x0 + 0x1194 0x04 0x0 + 0x1198 0x02 0x0 + 0x119c 0x0c 0x0 + 0x11a4 0x02 0x0 + 0x11c0 0x5c 0x0 + 0x11c4 0x3e 0x0 + 0x11c8 0x3f 0x0 + 0x1230 0x01 0x0 + 0x1234 0xa0 0x0 + 0x1238 0x08 0x0 + 0x12a4 0x01 0x0 + 0x12ac 0xc3 0x0 + 0x12b0 0x00 0x0 + 0x12b8 0x8c 0x0 + 0x12c0 0x7f 0x0 + 0x12c4 0x2a 0x0 + 0x1010 0x0c 0x0 + 0x1014 0x0f 0x0 + 0x12cc 0x04 0x0 + 0x113c 0x20 0x0 + 0x195c 0x3f 0x0 + 0x1974 0x50 0x0 + 0x196c 0x9f 0x0 + 0x182c 0x19 0x0 + 0x1840 0x07 0x0 + 0x1854 0x17 0x0 + 0x1868 0x09 0x0 + 0x1800 0x00 0x0 + 0x0aa8 0x01 0x0 + 0x12a8 0x01 0x0 + 0x1808 0x01 0x0>; +}; + +&devfreq_l3lat_0 { + qcom,core-dev-table = + < 300000 300000000 >, + < 480000 403200000 >, + < 652800 480000000 >, + < 748800 576000000 >, + < 902400 652800000 >, + < 979200 748800000 >, + < 1132800 844800000 >, + < 1228800 940800000 >, + < 1324800 1036800000 >, + < 1420800 1132800000 >, + < 1516800 1209600000 >, + < 1689600 1305600000 >, + < 1766400 1401600000 >; +}; + +&devfreq_l3lat_4 { + qcom,core-dev-table = + < 300000 300000000 >, + < 825600 576000000 >, + < 1132800 748800000 >, + < 1363200 940800000 >, + < 1689600 1209600000 >, + < 1996800 1305600000 >, + < 2400000 1401600000 >, + < 2745600 1593600000 >; +}; + +&bwmon { + qcom,count-unit = <0x10000>; +}; + +&cpubw { + qcom,bw-tbl = + < MHZ_TO_MBPS(150, 16) >, /* 2288 MB/s */ + < MHZ_TO_MBPS(300, 16) >, /* 4577 MB/s */ + < MHZ_TO_MBPS(426, 16) >, /* 6500 MB/s */ + < MHZ_TO_MBPS(533, 16) >, /* 8132 MB/s */ + < MHZ_TO_MBPS(600, 16) >, /* 9155 MB/s */ + < MHZ_TO_MBPS(806, 16) >, /* 12298 MB/s */ + < MHZ_TO_MBPS(933, 16) >; /* 14236 MB/s */ +}; + +&devfreq_cpufreq { + mincpubw-cpufreq { + cpu-to-dev-map-4 = + < 1881600 MHZ_TO_MBPS(200, 4) >, + < 2400000 MHZ_TO_MBPS(1017, 4) >; + }; +}; + +&devfreq_compute { + qcom,core-dev-table = + < 1881600 MHZ_TO_MBPS( 200, 4) >, + < 2649600 MHZ_TO_MBPS(1017, 4) >, + < 2745600 MHZ_TO_MBPS(1804, 4) >; +}; + +&clock_gcc { + compatible = "qcom,gcc-sdm845-v2", "syscon"; +}; + +&clock_camcc { + compatible = "qcom,cam_cc-sdm845-v2", "syscon"; + qcom,cam_cc_csi3phytimer_clk_src-opp-handle = <&cam_csiphy3>; +}; + +&clock_dispcc { + compatible = "qcom,dispcc-sdm845-v2", "syscon"; +}; + +&clock_gpucc { + compatible = "qcom,gpucc-sdm845-v2", "syscon"; +}; + +&clock_gfx { + compatible = "qcom,gfxcc-sdm845-v2"; +}; + +&clock_videocc { + compatible = "qcom,video_cc-sdm845-v2", "syscon"; +}; + +&msm_vidc { + qcom,allowed-clock-rates = <100000000 200000000 330000000 + 404000000 444000000 533000000>; +}; + +&refgen { + status = "ok"; +}; + +&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 */ +}; + +&mdss_mdp { + clock-max-rate = <0 0 0 0 430000000 19200000 0>; + qcom,sde-min-core-ib-kbps = <4800000>; + qcom,sde-max-bw-low-kbps = <9600000>; + qcom,sde-max-bw-high-kbps = <9600000>; +}; + +&mdss_dsi0 { + 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,core-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,core-supply-entry@0 { + reg = <0>; + qcom,supply-name = "refgen"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; +}; + +&sde_dp { + qcom,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>; + }; + }; +}; + +&energy_costs { + CPU_COST_0: core-cost0 { + busy-cost-data = < + 300000 12 + 403200 17 + 480000 21 + 576000 27 + 652800 31 + 748800 37 + 825600 42 + 902400 47 + 979200 52 + 1056000 57 + 1132800 62 + 1228800 70 + 1324800 78 + 1420800 89 + 1516800 103 + 1612800 122 + 1689600 141 + 1766400 160 + >; + idle-cost-data = < + 10 8 6 4 + >; + }; + CPU_COST_1: core-cost1 { + busy-cost-data = < + 300000 189 + 403200 523 + 480000 763 + 576000 1052 + 652800 1273 + 748800 1536 + 825600 1736 + 902400 1926 + 979200 2108 + 1056000 2284 + 1132800 2456 + 1209600 2628 + 1286400 2804 + 1363200 2992 + 1459200 3255 + 1536000 3499 + 1612800 3786 + 1689600 4128 + 1766400 4535 + 1843200 5019 + 1920000 5583 + 1996800 6226 + 2092800 7120 + 2169600 7876 + 2246400 8628 + 2323200 9344 + 2400000 10030 + 2476800 10806 + 2553600 12045 + 2649600 15686 + 2745600 25586 + 2764800 30000 + 2784000 35000 + 2803200 40000 + 2841600 50000 + 2956800 60000 + >; + idle-cost-data = < + 100 80 60 40 + >; + }; + CLUSTER_COST_0: cluster-cost0 { + busy-cost-data = < + 300000 3 + 403200 4 + 480000 4 + 576000 4 + 652800 5 + 748800 5 + 825600 6 + 902400 7 + 979200 7 + 1056000 8 + 1132800 9 + 1228800 9 + 1324800 10 + 1420800 11 + 1516800 12 + 1612800 13 + 1689600 15 + 1766400 17 + >; + idle-cost-data = < + 4 3 2 1 + >; + }; + CLUSTER_COST_1: cluster-cost1 { + busy-cost-data = < + 300000 24 + 403200 24 + 480000 25 + 576000 25 + 652800 26 + 748800 27 + 825600 28 + 902400 29 + 979200 30 + 1056000 32 + 1132800 34 + 1209600 37 + 1286400 40 + 1363200 45 + 1459200 50 + 1536000 57 + 1612800 64 + 1689600 74 + 1766400 84 + 1843200 96 + 1920000 106 + 1996800 113 + 2092800 120 + 2169600 125 + 2246400 127 + 2323200 130 + 2400000 135 + 2476800 140 + 2553600 145 + 2649600 150 + 2745600 155 + 2764800 160 + 2784000 165 + 2803200 170 + 2841600 180 + 2956800 190 + >; + idle-cost-data = < + 4 3 2 1 + >; + }; +}; + +&gpu_gx_gdsc { + domain-addr = <&gpu_gx_domain_addr>; + sw-reset = <&gpu_gx_sw_reset>; + qcom,reset-aon-logic; +}; + +/* GPU overrides */ +&msm_gpu { + /* Updated chip ID */ + qcom,chipid = <0x06030001>; + qcom,initial-pwrlevel = <6>; + + qcom,gpu-pwrlevels { + #address-cells = <1>; + #size-cells = <0>; + + compatible = "qcom,gpu-pwrlevels"; + + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <710000000>; + qcom,bus-freq = <12>; + qcom,bus-min = <12>; + qcom,bus-max = <12>; + }; + + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <675000000>; + qcom,bus-freq = <12>; + qcom,bus-min = <10>; + qcom,bus-max = <12>; + }; + + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <596000000>; + qcom,bus-freq = <10>; + qcom,bus-min = <9>; + qcom,bus-max = <12>; + }; + + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <520000000>; + qcom,bus-freq = <9>; + qcom,bus-min = <8>; + qcom,bus-max = <11>; + }; + + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <414000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <7>; + qcom,bus-max = <9>; + }; + + qcom,gpu-pwrlevel@5 { + reg = <5>; + qcom,gpu-freq = <342000000>; + qcom,bus-freq = <6>; + qcom,bus-min = <5>; + qcom,bus-max = <7>; + }; + + qcom,gpu-pwrlevel@6 { + reg = <6>; + qcom,gpu-freq = <257000000>; + qcom,bus-freq = <4>; + qcom,bus-min = <3>; + qcom,bus-max = <5>; + }; + + qcom,gpu-pwrlevel@7 { + reg = <7>; + qcom,gpu-freq = <0>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; +}; + +&gmu { + qcom,gmu-pwrlevels { + #address-cells = <1>; + #size-cells = <0>; + + compatible = "qcom,gmu-pwrlevels"; + + /* GMU power levels must go from lowest to highest */ + qcom,gmu-pwrlevel@0 { + reg = <0>; + qcom,gmu-freq = <0>; + }; + + qcom,gmu-pwrlevel@1 { + reg = <1>; + qcom,gmu-freq = <200000000>; + }; + + qcom,gmu-pwrlevel@2 { + reg = <2>; + qcom,gmu-freq = <500000000>; + }; + }; +}; + +&qusb_phy0 { + qcom,qusb-phy-init-seq = + /* */ + <0x23 0x210 /* PWR_CTRL1 */ + 0x03 0x04 /* PLL_ANALOG_CONTROLS_TWO */ + 0x7c 0x18c /* PLL_CLOCK_INVERTERS */ + 0x80 0x2c /* PLL_CMODE */ + 0x0a 0x184 /* PLL_LOCK_DELAY */ + 0x19 0xb4 /* PLL_DIGITAL_TIMERS_TWO */ + 0x40 0x194 /* PLL_BIAS_CONTROL_1 */ + 0x20 0x198 /* PLL_BIAS_CONTROL_2 */ + 0x21 0x214 /* PWR_CTRL2 */ + 0x08 0x220 /* IMP_CTRL1 */ + 0x58 0x224 /* IMP_CTRL2 */ + 0x45 0x240 /* TUNE1 */ + 0x29 0x244 /* TUNE2 */ + 0xca 0x248 /* TUNE3 */ + 0x04 0x24c /* TUNE4 */ + 0x03 0x250 /* TUNE5 */ + 0x00 0x23c /* CHG_CTRL2 */ + 0x22 0x210>; /* PWR_CTRL1 */ +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi b/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi new file mode 100644 index 000000000000..9588aacc1e2e --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi @@ -0,0 +1,129 @@ +/* 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. + */ + +#include +#include +#include + +&soc { + msm_vidc: qcom,vidc@aa00000 { + compatible = "qcom,msm-vidc", "qcom,sdm845-vidc"; + status = "ok"; + reg = <0xaa00000 0x200000>; + interrupts = ; + + /* LLCC Info */ + cache-slice-names = "vidsc0", "vidsc1"; + cache-slices = <&llcc 2>, <&llcc 3>; + + /* Supply */ + venus-supply = <&venus_gdsc>; + venus-core0-supply = <&vcodec0_gdsc>; + venus-core1-supply = <&vcodec1_gdsc>; + + /* Clocks */ + clock-names = "core_clk", "iface_clk", "bus_clk", + "core0_clk", "core0_bus_clk", + "core1_clk", "core1_bus_clk"; + clocks = <&clock_videocc VIDEO_CC_VENUS_CTL_CORE_CLK>, + <&clock_videocc VIDEO_CC_VENUS_AHB_CLK>, + <&clock_videocc VIDEO_CC_VENUS_CTL_AXI_CLK>, + <&clock_videocc VIDEO_CC_VCODEC0_CORE_CLK>, + <&clock_videocc VIDEO_CC_VCODEC0_AXI_CLK>, + <&clock_videocc VIDEO_CC_VCODEC1_CORE_CLK>, + <&clock_videocc VIDEO_CC_VCODEC1_AXI_CLK>; + qcom,proxy-clock-names = "core_clk", "iface_clk", + "bus_clk", "core0_clk", "core0_bus_clk", + "core1_clk", "core1_bus_clk"; + qcom,clock-configs = <0x1 0x0 0x0 0x1 0x0 0x1 0x0>; + qcom,allowed-clock-rates = <100000000 200000000 320000000 + 380000000 444000000 533000000>; + + /* Buses */ + bus_cnoc { + compatible = "qcom,msm-vidc,bus"; + label = "cnoc"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,bus-governor = "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,bus-governor = "msm-vidc-ddr"; + qcom,bus-range-kbps = <1000 3388000>; + }; + arm9_bus_ddr { + compatible = "qcom,msm-vidc,bus"; + label = "venus-arm9-ddr"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,bus-governor = "performance"; + qcom,bus-range-kbps = <1000 1000>; + }; + venus_bus_llcc { + compatible = "qcom,msm-vidc,bus"; + label = "venus-llcc"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,bus-governor = "msm-vidc-llcc"; + qcom,bus-range-kbps = <17000 3388000>; + }; + + /* MMUs */ + non_secure_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_ns"; + iommus = + <&apps_smmu 0x10a0 0x8>, + <&apps_smmu 0x10b0 0x0>; + buffer-types = <0xfff>; + virtual-addr-pool = <0x70800000 0x6f800000>; + }; + + secure_bitstream_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_bitstream"; + iommus = + <&apps_smmu 0x10a1 0x8>, + <&apps_smmu 0x10a5 0x8>; + 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 0x10a3 0x8>; + 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 0x10a4 0x8>, + <&apps_smmu 0x10b4 0x0>; + buffer-types = <0x480>; + virtual-addr-pool = <0x1000000 0x24800000>; + qcom,secure-context-bank; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-wcd.dtsi b/arch/arm64/boot/dts/qcom/sdm845-wcd.dtsi new file mode 100644 index 000000000000..aab91d60af57 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845-wcd.dtsi @@ -0,0 +1,167 @@ +/* Copyright (c) 2016-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. + */ + +&slim_aud { + tavil_codec { + wcd: wcd_pinctrl@5 { + compatible = "qcom,wcd-pinctrl"; + qcom,num-gpios = <5>; + gpio-controller; + #gpio-cells = <2>; + + us_euro_sw_wcd_active: us_euro_sw_wcd_active { + mux { + pins = "gpio1"; + }; + + config { + pins = "gpio1"; + output-high; + }; + }; + + us_euro_sw_wcd_sleep: us_euro_sw_wcd_sleep { + mux { + pins = "gpio1"; + }; + + config { + pins = "gpio1"; + output-low; + }; + }; + + spkr_1_wcd_en_active: spkr_1_wcd_en_active { + mux { + pins = "gpio2"; + }; + + config { + pins = "gpio2"; + output-high; + }; + }; + + spkr_1_wcd_en_sleep: spkr_1_wcd_en_sleep { + mux { + pins = "gpio2"; + }; + + config { + pins = "gpio2"; + input-enable; + }; + }; + + spkr_2_wcd_en_active: spkr_2_sd_n_active { + mux { + pins = "gpio3"; + }; + + config { + pins = "gpio3"; + output-high; + }; + }; + + spkr_2_wcd_en_sleep: spkr_2_sd_n_sleep { + mux { + pins = "gpio3"; + }; + + config { + pins = "gpio3"; + input-enable; + }; + }; + + hph_en0_wcd_active: hph_en0_wcd_active { + mux { + pins = "gpio4"; + }; + + config { + pins = "gpio4"; + output-high; + }; + }; + + hph_en0_wcd_sleep: hph_en0_wcd_sleep { + mux { + pins = "gpio4"; + }; + + config { + pins = "gpio4"; + output-low; + }; + }; + + hph_en1_wcd_active: hph_en1_wcd_active { + mux { + pins = "gpio5"; + }; + + config { + pins = "gpio5"; + output-high; + }; + }; + + hph_en1_wcd_sleep: hph_en1_wcd_sleep { + mux { + pins = "gpio5"; + }; + + config { + pins = "gpio5"; + output-low; + }; + }; + }; + + wsa_spkr_wcd_sd1: msm_cdc_pinctrll { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&spkr_1_wcd_en_active>; + pinctrl-1 = <&spkr_1_wcd_en_sleep>; + }; + + wsa_spkr_wcd_sd2: msm_cdc_pinctrlr { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&spkr_2_wcd_en_active>; + pinctrl-1 = <&spkr_2_wcd_en_sleep>; + }; + + tavil_us_euro_sw: msm_cdc_pinctrl_us_euro_sw { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&us_euro_sw_wcd_active>; + pinctrl-1 = <&us_euro_sw_wcd_sleep>; + }; + + tavil_hph_en0: msm_cdc_pinctrl_hph_en0 { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&hph_en0_wcd_active>; + pinctrl-1 = <&hph_en0_wcd_sleep>; + }; + + tavil_hph_en1: msm_cdc_pinctrl_hph_en1 { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&hph_en1_wcd_active>; + pinctrl-1 = <&hph_en1_wcd_sleep>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845.dts b/arch/arm64/boot/dts/qcom/sdm845.dts new file mode 100644 index 000000000000..a3fa3afd28b2 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845.dts @@ -0,0 +1,21 @@ +/* Copyright (c) 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. + */ + +/dts-v1/; + +#include "sdm845.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM845 v1 SoC"; + compatible = "qcom,sdm845"; + qcom,board-id = <0 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index 0c9a2aa6a1b5..9002c5f8afea 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -1,89 +1,53 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * SDM845 SoC device tree source +/* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. * - * 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. */ +#include "skeleton64.dtsi" #include +#include +#include +#include +#include +#include #include +#include +#include #include -#include +#include +#include +#include +#include +#include -/ { - interrupt-parent = <&intc>; +#define MHZ_TO_MBPS(mhz, w) ((mhz * 1000000 * w) / (1024 * 1024)) - #address-cells = <2>; - #size-cells = <2>; +/ { + model = "Qualcomm Technologies, Inc. SDM845"; + compatible = "qcom,sdm845"; + qcom,msm-id = <321 0x10000>; + interrupt-parent = <&pdc>; aliases { - i2c0 = &i2c0; - i2c1 = &i2c1; - i2c2 = &i2c2; - i2c3 = &i2c3; - i2c4 = &i2c4; - i2c5 = &i2c5; - i2c6 = &i2c6; - i2c7 = &i2c7; - i2c8 = &i2c8; - i2c9 = &i2c9; - i2c10 = &i2c10; - i2c11 = &i2c11; - i2c12 = &i2c12; - i2c13 = &i2c13; - i2c14 = &i2c14; - i2c15 = &i2c15; - spi0 = &spi0; - spi1 = &spi1; - spi2 = &spi2; - spi3 = &spi3; - spi4 = &spi4; - spi5 = &spi5; - spi6 = &spi6; - spi7 = &spi7; - spi8 = &spi8; - spi9 = &spi9; - spi10 = &spi10; - spi11 = &spi11; - spi12 = &spi12; - spi13 = &spi13; - spi14 = &spi14; - spi15 = &spi15; - }; - - chosen { }; - - memory@80000000 { - device_type = "memory"; - /* We expect the bootloader to fill in the size */ - reg = <0 0x80000000 0 0>; + ufshc1 = &ufshc_mem; /* Embedded UFS slot */ + pci-domain0 = &pcie0; + pci-domain1 = &pcie1; + sdhc2 = &sdhc_2; /* SDC2 SD card slot */ }; - reserved-memory { - #address-cells = <2>; - #size-cells = <2>; - ranges; - - memory@85fc0000 { - reg = <0 0x85fc0000 0 0x20000>; - no-map; - }; - - memory@85fe0000 { - compatible = "qcom,cmd-db"; - reg = <0x0 0x85fe0000 0x0 0x20000>; - no-map; - }; - - smem_mem: memory@86000000 { - reg = <0x0 0x86000000 0x0 0x200000>; - no-map; - }; - - memory@86200000 { - reg = <0 0x86200000 0 0x2d00000>; - no-map; - }; + aliases { + serial0 = &qupv3_se9_2uart; + spi0 = &qupv3_se8_spi; + i2c0 = &qupv3_se10_i2c; + i2c1 = &qupv3_se3_i2c; + hsuart0 = &qupv3_se6_4uart; }; cpus { @@ -92,1015 +56,5459 @@ CPU0: cpu@0 { device_type = "cpu"; - compatible = "qcom,kryo385"; + compatible = "arm,armv8"; reg = <0x0 0x0>; enable-method = "psci"; + efficiency = <1024>; + cache-size = <0x8000>; + cpu-release-addr = <0x0 0x90000000>; + qcom,lmh-dcvs = <&lmh_dcvs0>; + #cooling-cells = <2>; next-level-cache = <&L2_0>; + sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>; L2_0: l2-cache { - compatible = "cache"; - next-level-cache = <&L3_0>; + compatible = "arm,arch-cache"; + cache-size = <0x20000>; + cache-level = <2>; + next-level-cache = <&L3_0>; + L3_0: l3-cache { - compatible = "cache"; + compatible = "arm,arch-cache"; + cache-size = <0x200000>; + cache-level = <3>; }; }; + L1_I_0: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x12000>; + }; + L1_D_0: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0xa000>; + }; + L1_TLB_0: l1-tlb { + qcom,dump-size = <0x6000>; + }; }; CPU1: cpu@100 { device_type = "cpu"; - compatible = "qcom,kryo385"; + compatible = "arm,armv8"; reg = <0x0 0x100>; enable-method = "psci"; + efficiency = <1024>; + cache-size = <0x8000>; + cpu-release-addr = <0x0 0x90000000>; + qcom,lmh-dcvs = <&lmh_dcvs0>; + #cooling-cells = <2>; next-level-cache = <&L2_100>; + sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>; L2_100: l2-cache { - compatible = "cache"; - next-level-cache = <&L3_0>; + compatible = "arm,arch-cache"; + cache-size = <0x20000>; + cache-level = <2>; + next-level-cache = <&L3_0>; + }; + L1_I_100: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x12000>; + }; + L1_D_100: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0xa000>; + }; + L1_TLB_100: l1-tlb { + qcom,dump-size = <0x6000>; }; }; CPU2: cpu@200 { device_type = "cpu"; - compatible = "qcom,kryo385"; + compatible = "arm,armv8"; reg = <0x0 0x200>; enable-method = "psci"; + efficiency = <1024>; + cache-size = <0x8000>; + cpu-release-addr = <0x0 0x90000000>; + qcom,lmh-dcvs = <&lmh_dcvs0>; + #cooling-cells = <2>; next-level-cache = <&L2_200>; + sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>; L2_200: l2-cache { - compatible = "cache"; - next-level-cache = <&L3_0>; + compatible = "arm,arch-cache"; + cache-size = <0x20000>; + cache-level = <2>; + next-level-cache = <&L3_0>; + }; + L1_I_200: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x12000>; + }; + L1_D_200: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0xa000>; + }; + L1_TLB_200: l1-tlb { + qcom,dump-size = <0x6000>; }; }; CPU3: cpu@300 { device_type = "cpu"; - compatible = "qcom,kryo385"; + compatible = "arm,armv8"; reg = <0x0 0x300>; enable-method = "psci"; + efficiency = <1024>; + cache-size = <0x8000>; + cpu-release-addr = <0x0 0x90000000>; + qcom,lmh-dcvs = <&lmh_dcvs0>; + #cooling-cells = <2>; next-level-cache = <&L2_300>; + sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>; L2_300: l2-cache { - compatible = "cache"; - next-level-cache = <&L3_0>; + compatible = "arm,arch-cache"; + cache-size = <0x20000>; + cache-level = <2>; + next-level-cache = <&L3_0>; + }; + L1_I_300: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x12000>; + }; + L1_D_300: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0xa000>; + }; + L1_TLB_300: l1-tlb { + qcom,dump-size = <0x6000>; }; }; CPU4: cpu@400 { device_type = "cpu"; - compatible = "qcom,kryo385"; + compatible = "arm,armv8"; reg = <0x0 0x400>; enable-method = "psci"; + efficiency = <1740>; + cache-size = <0x20000>; + cpu-release-addr = <0x0 0x90000000>; + qcom,lmh-dcvs = <&lmh_dcvs1>; + #cooling-cells = <2>; next-level-cache = <&L2_400>; + sched-energy-costs = <&CPU_COST_1 &CLUSTER_COST_1>; L2_400: l2-cache { - compatible = "cache"; - next-level-cache = <&L3_0>; + compatible = "arm,arch-cache"; + cache-size = <0x40000>; + cache-level = <2>; + next-level-cache = <&L3_0>; + }; + L1_I_400: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x24000>; + }; + L1_D_400: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x14000>; + }; + L1_TLB_400: l1-tlb { + qcom,dump-size = <0x6800>; }; }; CPU5: cpu@500 { device_type = "cpu"; - compatible = "qcom,kryo385"; + compatible = "arm,armv8"; reg = <0x0 0x500>; enable-method = "psci"; + efficiency = <1740>; + cache-size = <0x20000>; + cpu-release-addr = <0x0 0x90000000>; + qcom,lmh-dcvs = <&lmh_dcvs1>; + #cooling-cells = <2>; next-level-cache = <&L2_500>; + sched-energy-costs = <&CPU_COST_1 &CLUSTER_COST_1>; L2_500: l2-cache { - compatible = "cache"; - next-level-cache = <&L3_0>; + compatible = "arm,arch-cache"; + cache-size = <0x40000>; + cache-level = <2>; + next-level-cache = <&L3_0>; + }; + L1_I_500: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x24000>; + }; + L1_D_500: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x14000>; + }; + L1_TLB_500: l1-tlb { + qcom,dump-size = <0x6800>; }; }; CPU6: cpu@600 { device_type = "cpu"; - compatible = "qcom,kryo385"; + compatible = "arm,armv8"; reg = <0x0 0x600>; enable-method = "psci"; + efficiency = <1740>; + cache-size = <0x20000>; + cpu-release-addr = <0x0 0x90000000>; + qcom,lmh-dcvs = <&lmh_dcvs1>; + #cooling-cells = <2>; next-level-cache = <&L2_600>; + sched-energy-costs = <&CPU_COST_1 &CLUSTER_COST_1>; L2_600: l2-cache { - compatible = "cache"; - next-level-cache = <&L3_0>; + compatible = "arm,arch-cache"; + cache-size = <0x40000>; + cache-level = <2>; + next-level-cache = <&L3_0>; + }; + L1_I_600: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x24000>; + }; + L1_D_600: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x14000>; + }; + L1_TLB_600: l1-tlb { + qcom,dump-size = <0x6800>; }; }; CPU7: cpu@700 { device_type = "cpu"; - compatible = "qcom,kryo385"; + compatible = "arm,armv8"; reg = <0x0 0x700>; enable-method = "psci"; + efficiency = <1740>; + cache-size = <0x20000>; + cpu-release-addr = <0x0 0x90000000>; + qcom,lmh-dcvs = <&lmh_dcvs1>; + #cooling-cells = <2>; next-level-cache = <&L2_700>; + sched-energy-costs = <&CPU_COST_1 &CLUSTER_COST_1>; L2_700: l2-cache { - compatible = "cache"; - next-level-cache = <&L3_0>; + compatible = "arm,arch-cache"; + cache-size = <0x40000>; + cache-level = <2>; + next-level-cache = <&L3_0>; + }; + L1_I_700: l1-icache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x24000>; + }; + L1_D_700: l1-dcache { + compatible = "arm,arch-cache"; + qcom,dump-size = <0x14000>; + }; + L1_TLB_700: l1-tlb { + qcom,dump-size = <0x6800>; }; }; - }; - pmu { - compatible = "arm,armv8-pmuv3"; - interrupts = ; - }; + cpu-map { + cluster0 { + core0 { + cpu = <&CPU0>; + }; - timer { - compatible = "arm,armv8-timer"; - interrupts = , - , - , - ; - }; + core1 { + cpu = <&CPU1>; + }; - clocks { - xo_board: xo-board { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <38400000>; - clock-output-names = "xo_board"; - }; + core2 { + cpu = <&CPU2>; + }; + + core3 { + cpu = <&CPU3>; + }; + }; + + cluster1 { + core0 { + cpu = <&CPU4>; + }; + + core1 { + cpu = <&CPU5>; + }; + + core2 { + cpu = <&CPU6>; + }; - sleep_clk: sleep-clk { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <32764>; + core3 { + cpu = <&CPU7>; + }; + }; }; }; - tcsr_mutex: hwlock { - compatible = "qcom,tcsr-mutex"; - syscon = <&tcsr_mutex_regs 0 0x1000>; - #hwlock-cells = <1>; - }; + energy_costs: energy-costs { + compatible = "sched-energy"; - smem { - compatible = "qcom,smem"; - memory-region = <&smem_mem>; - hwlocks = <&tcsr_mutex 3>; - }; + CPU_COST_0: core-cost0 { + busy-cost-data = < + 300000 31 + 422400 38 + 499200 42 + 576000 46 + 652800 51 + 748800 58 + 825600 64 + 902400 70 + 979200 76 + 1056000 83 + 1132800 90 + 1209600 97 + 1286400 105 + 1363200 114 + 1440000 124 + 1516800 136 + 1593600 152 + 1651200 167 /* speedbin 0,1 */ + 1670400 173 /* speedbin 2 */ + 1708800 186 /* speedbin 0,1 */ + 1747200 201 /* speedbin 2 */ + >; + idle-cost-data = < + 22 18 14 12 + >; + }; + CPU_COST_1: core-cost1 { + busy-cost-data = < + 300000 258 + 422400 260 + 499200 261 + 576000 263 + 652800 267 + 729600 272 + 806400 280 + 883200 291 + 960000 305 + 1036800 324 + 1113600 348 + 1190400 378 + 1267200 415 + 1344000 460 + 1420800 513 + 1497600 576 + 1574400 649 + 1651200 732 + 1728000 824 + 1804800 923 + 1881600 1027 + 1958400 1131 + 2035000 1228 /* speedbin 1,2 */ + 2092000 1290 /* speedbin 1 */ + 2112000 1308 /* speedbin 2 */ + 2208000 1363 /* speedbin 2 */ + >; + idle-cost-data = < + 100 80 60 40 + >; + }; + CLUSTER_COST_0: cluster-cost0 { + busy-cost-data = < + 300000 3 + 422400 4 + 499200 4 + 576000 4 + 652800 5 + 748800 5 + 825600 6 + 902400 7 + 979200 7 + 1056000 8 + 1132800 9 + 1209600 9 + 1286400 10 + 1363200 11 + 1440000 12 + 1516800 13 + 1593600 15 + 1651200 17 /* speedbin 0,1 */ + 1670400 19 /* speedbin 2 */ + 1708800 21 /* speedbin 0,1 */ + 1747200 23 /* speedbin 2 */ + >; + idle-cost-data = < + 4 3 2 1 + >; + }; + CLUSTER_COST_1: cluster-cost1 { + busy-cost-data = < + 300000 24 + 422400 24 + 499200 25 + 576000 25 + 652800 26 + 729600 27 + 806400 28 + 883200 29 + 960000 30 + 1036800 32 + 1113600 34 + 1190400 37 + 1267200 40 + 1344000 45 + 1420800 50 + 1497600 57 + 1574400 64 + 1651200 74 + 1728000 84 + 1804800 96 + 1881600 106 + 1958400 113 + 2035000 120 /* speedbin 1,2 */ + 2092000 125 /* speedbin 1 */ + 2112000 127 /* speedbin 2 */ + 2208000 130 /* speedbin 2 */ + >; + idle-cost-data = < + 4 3 2 1 + >; + }; + }; /* energy-costs */ psci { compatible = "arm,psci-1.0"; method = "smc"; }; - soc: soc { + chosen { + bootargs = "rcupdate.rcu_expedited=1"; + }; + + soc: soc { }; + + vendor: vendor { #address-cells = <1>; #size-cells = <1>; ranges = <0 0 0 0xffffffff>; compatible = "simple-bus"; + }; - gcc: clock-controller@100000 { - compatible = "qcom,gcc-sdm845"; - reg = <0x100000 0x1f0000>; - #clock-cells = <1>; - #reset-cells = <1>; - #power-domain-cells = <1>; - }; - - qupv3_id_0: geniqup@8c0000 { - compatible = "qcom,geni-se-qup"; - reg = <0x8c0000 0x6000>; - clock-names = "m-ahb", "s-ahb"; - clocks = <&gcc GCC_QUPV3_WRAP_0_M_AHB_CLK>, - <&gcc GCC_QUPV3_WRAP_0_S_AHB_CLK>; - #address-cells = <1>; - #size-cells = <1>; - ranges; - status = "disabled"; - - i2c0: i2c@880000 { - compatible = "qcom,geni-i2c"; - reg = <0x880000 0x4000>; - clock-names = "se"; - clocks = <&gcc GCC_QUPV3_WRAP0_S0_CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&qup_i2c0_default>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - - spi0: spi@880000 { - compatible = "qcom,geni-spi"; - reg = <0x880000 0x4000>; - clock-names = "se"; - clocks = <&gcc GCC_QUPV3_WRAP0_S0_CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&qup_spi0_default>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - - i2c1: i2c@884000 { - compatible = "qcom,geni-i2c"; - reg = <0x884000 0x4000>; - clock-names = "se"; - clocks = <&gcc GCC_QUPV3_WRAP0_S1_CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&qup_i2c1_default>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - - spi1: spi@884000 { - compatible = "qcom,geni-spi"; - reg = <0x884000 0x4000>; - clock-names = "se"; - clocks = <&gcc GCC_QUPV3_WRAP0_S1_CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&qup_spi1_default>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - - i2c2: i2c@888000 { - compatible = "qcom,geni-i2c"; - reg = <0x888000 0x4000>; - clock-names = "se"; - clocks = <&gcc GCC_QUPV3_WRAP0_S2_CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&qup_i2c2_default>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - - spi2: spi@888000 { - compatible = "qcom,geni-spi"; - reg = <0x888000 0x4000>; - clock-names = "se"; - clocks = <&gcc GCC_QUPV3_WRAP0_S2_CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&qup_spi2_default>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - - i2c3: i2c@88c000 { - compatible = "qcom,geni-i2c"; - reg = <0x88c000 0x4000>; - clock-names = "se"; - clocks = <&gcc GCC_QUPV3_WRAP0_S3_CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&qup_i2c3_default>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - - spi3: spi@88c000 { - compatible = "qcom,geni-spi"; - reg = <0x88c000 0x4000>; - clock-names = "se"; - clocks = <&gcc GCC_QUPV3_WRAP0_S3_CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&qup_spi3_default>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - - i2c4: i2c@890000 { - compatible = "qcom,geni-i2c"; - reg = <0x890000 0x4000>; - clock-names = "se"; - clocks = <&gcc GCC_QUPV3_WRAP0_S4_CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&qup_i2c4_default>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - - spi4: spi@890000 { - compatible = "qcom,geni-spi"; - reg = <0x890000 0x4000>; - clock-names = "se"; - clocks = <&gcc GCC_QUPV3_WRAP0_S4_CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&qup_spi4_default>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - - i2c5: i2c@894000 { - compatible = "qcom,geni-i2c"; - reg = <0x894000 0x4000>; - clock-names = "se"; - clocks = <&gcc GCC_QUPV3_WRAP0_S5_CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&qup_i2c5_default>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - - spi5: spi@894000 { - compatible = "qcom,geni-spi"; - reg = <0x894000 0x4000>; - clock-names = "se"; - clocks = <&gcc GCC_QUPV3_WRAP0_S5_CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&qup_spi5_default>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - - i2c6: i2c@898000 { - compatible = "qcom,geni-i2c"; - reg = <0x898000 0x4000>; - clock-names = "se"; - clocks = <&gcc GCC_QUPV3_WRAP0_S6_CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&qup_i2c6_default>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - - spi6: spi@898000 { - compatible = "qcom,geni-spi"; - reg = <0x898000 0x4000>; - clock-names = "se"; - clocks = <&gcc GCC_QUPV3_WRAP0_S6_CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&qup_spi6_default>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - - i2c7: i2c@89c000 { - compatible = "qcom,geni-i2c"; - reg = <0x89c000 0x4000>; - clock-names = "se"; - clocks = <&gcc GCC_QUPV3_WRAP0_S7_CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&qup_i2c7_default>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - - spi7: spi@89c000 { - compatible = "qcom,geni-spi"; - reg = <0x89c000 0x4000>; - clock-names = "se"; - clocks = <&gcc GCC_QUPV3_WRAP0_S7_CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&qup_spi7_default>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - }; - - qupv3_id_1: geniqup@ac0000 { - compatible = "qcom,geni-se-qup"; - reg = <0xac0000 0x6000>; - clock-names = "m-ahb", "s-ahb"; - clocks = <&gcc GCC_QUPV3_WRAP_1_M_AHB_CLK>, - <&gcc GCC_QUPV3_WRAP_1_S_AHB_CLK>; - #address-cells = <1>; - #size-cells = <1>; - ranges; - status = "disabled"; - - i2c8: i2c@a80000 { - compatible = "qcom,geni-i2c"; - reg = <0xa80000 0x4000>; - clock-names = "se"; - clocks = <&gcc GCC_QUPV3_WRAP1_S0_CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&qup_i2c8_default>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - - spi8: spi@a80000 { - compatible = "qcom,geni-spi"; - reg = <0xa80000 0x4000>; - clock-names = "se"; - clocks = <&gcc GCC_QUPV3_WRAP1_S0_CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&qup_spi8_default>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - - i2c9: i2c@a84000 { - compatible = "qcom,geni-i2c"; - reg = <0xa84000 0x4000>; - clock-names = "se"; - clocks = <&gcc GCC_QUPV3_WRAP1_S1_CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&qup_i2c9_default>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - - spi9: spi@a84000 { - compatible = "qcom,geni-spi"; - reg = <0xa84000 0x4000>; - clock-names = "se"; - clocks = <&gcc GCC_QUPV3_WRAP1_S1_CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&qup_spi9_default>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - - uart9: serial@a84000 { - compatible = "qcom,geni-debug-uart"; - reg = <0xa84000 0x4000>; - clock-names = "se"; - clocks = <&gcc GCC_QUPV3_WRAP1_S1_CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&qup_uart9_default>; - interrupts = ; - status = "disabled"; - }; - - i2c10: i2c@a88000 { - compatible = "qcom,geni-i2c"; - reg = <0xa88000 0x4000>; - clock-names = "se"; - clocks = <&gcc GCC_QUPV3_WRAP1_S2_CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&qup_i2c10_default>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - - spi10: spi@a88000 { - compatible = "qcom,geni-spi"; - reg = <0xa88000 0x4000>; - clock-names = "se"; - clocks = <&gcc GCC_QUPV3_WRAP1_S2_CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&qup_spi10_default>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - - i2c11: i2c@a8c000 { - compatible = "qcom,geni-i2c"; - reg = <0xa8c000 0x4000>; - clock-names = "se"; - clocks = <&gcc GCC_QUPV3_WRAP1_S3_CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&qup_i2c11_default>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - - spi11: spi@a8c000 { - compatible = "qcom,geni-spi"; - reg = <0xa8c000 0x4000>; - clock-names = "se"; - clocks = <&gcc GCC_QUPV3_WRAP1_S3_CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&qup_spi11_default>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - - i2c12: i2c@a90000 { - compatible = "qcom,geni-i2c"; - reg = <0xa90000 0x4000>; - clock-names = "se"; - clocks = <&gcc GCC_QUPV3_WRAP1_S4_CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&qup_i2c12_default>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - - spi12: spi@a90000 { - compatible = "qcom,geni-spi"; - reg = <0xa90000 0x4000>; - clock-names = "se"; - clocks = <&gcc GCC_QUPV3_WRAP1_S4_CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&qup_spi12_default>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - - i2c13: i2c@a94000 { - compatible = "qcom,geni-i2c"; - reg = <0xa94000 0x4000>; - clock-names = "se"; - clocks = <&gcc GCC_QUPV3_WRAP1_S5_CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&qup_i2c13_default>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - - spi13: spi@a94000 { - compatible = "qcom,geni-spi"; - reg = <0xa94000 0x4000>; - clock-names = "se"; - clocks = <&gcc GCC_QUPV3_WRAP1_S5_CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&qup_spi13_default>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - - i2c14: i2c@a98000 { - compatible = "qcom,geni-i2c"; - reg = <0xa98000 0x4000>; - clock-names = "se"; - clocks = <&gcc GCC_QUPV3_WRAP1_S6_CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&qup_i2c14_default>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - - spi14: spi@a98000 { - compatible = "qcom,geni-spi"; - reg = <0xa98000 0x4000>; - clock-names = "se"; - clocks = <&gcc GCC_QUPV3_WRAP1_S6_CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&qup_spi14_default>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; - }; - - i2c15: i2c@a9c000 { - compatible = "qcom,geni-i2c"; - reg = <0xa9c000 0x4000>; - clock-names = "se"; - clocks = <&gcc GCC_QUPV3_WRAP1_S7_CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&qup_i2c15_default>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; + firmware: firmware { + android { + compatible = "android,firmware"; + vbmeta { + compatible = "android,vbmeta"; + parts = "vbmeta,boot,system,vendor,dtbo"; }; - spi15: spi@a9c000 { - compatible = "qcom,geni-spi"; - reg = <0xa9c000 0x4000>; - clock-names = "se"; - clocks = <&gcc GCC_QUPV3_WRAP1_S7_CLK>; - pinctrl-names = "default"; - pinctrl-0 = <&qup_spi15_default>; - interrupts = ; - #address-cells = <1>; - #size-cells = <0>; - status = "disabled"; + 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 { + #address-cells = <2>; + #size-cells = <2>; + ranges; - tcsr_mutex_regs: syscon@1f40000 { - compatible = "syscon"; - reg = <0x1f40000 0x40000>; + hyp_region: hyp_region@85700000 { + no-map; + reg = <0 0x85700000 0 0x600000>; }; - tlmm: pinctrl@3400000 { - compatible = "qcom,sdm845-pinctrl"; - reg = <0x03400000 0xc00000>; - interrupts = ; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; + xbl_region: xbl_region@85e00000 { + no-map; + reg = <0 0x85e00000 0 0x100000>; + }; - qup_i2c0_default: qup-i2c0-default { - pinmux { - pins = "gpio0", "gpio1"; - function = "qup0"; - }; - }; + removed_region: removed_region@85fc0000 { + no-map; + reg = <0 0x85fc0000 0 0x2f40000>; + }; - qup_i2c1_default: qup-i2c1-default { - pinmux { - pins = "gpio17", "gpio18"; - function = "qup1"; - }; - }; + qseecom_mem: qseecom_region@0x8ab00000 { + compatible = "shared-dma-pool"; + no-map; + reg = <0 0x8ab00000 0 0x1400000>; + }; - qup_i2c2_default: qup-i2c2-default { - pinmux { - pins = "gpio27", "gpio28"; - function = "qup2"; - }; - }; + pil_camera_mem: camera_region@0x8bf00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0 0x8bf00000 0 0x500000>; + }; - qup_i2c3_default: qup-i2c3-default { - pinmux { - pins = "gpio41", "gpio42"; - function = "qup3"; - }; - }; + pil_ipa_fw_mem: ips_fw_region@0x8c400000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0 0x8c400000 0 0x10000>; + }; - qup_i2c4_default: qup-i2c4-default { - pinmux { - pins = "gpio89", "gpio90"; - function = "qup4"; - }; - }; + pil_ipa_gsi_mem: ipa_gsi_region@0x8c410000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0 0x8c410000 0 0x5000>; + }; - qup_i2c5_default: qup-i2c5-default { - pinmux { - pins = "gpio85", "gpio86"; - function = "qup5"; - }; - }; + pil_gpu_mem: gpu_region@0x8c415000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0 0x8c415000 0 0x2000>; + }; - qup_i2c6_default: qup-i2c6-default { - pinmux { - pins = "gpio45", "gpio46"; - function = "qup6"; - }; - }; + pil_adsp_mem: adsp_region@0x8c500000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0 0x8c500000 0 0x1a00000>; + }; - qup_i2c7_default: qup-i2c7-default { - pinmux { - pins = "gpio93", "gpio94"; - function = "qup7"; - }; - }; + wlan_fw_region: wlan_fw_region@0x8df00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0 0x8df00000 0 0x100000>; + }; - qup_i2c8_default: qup-i2c8-default { - pinmux { - pins = "gpio65", "gpio66"; - function = "qup8"; - }; - }; + pil_modem_mem: modem_region@0x8e000000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0 0x8e000000 0 0x7800000>; + }; - qup_i2c9_default: qup-i2c9-default { - pinmux { - pins = "gpio6", "gpio7"; - function = "qup9"; - }; - }; + pil_video_mem: video_region@0x95800000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0 0x95800000 0 0x500000>; + }; - qup_i2c10_default: qup-i2c10-default { - pinmux { - pins = "gpio55", "gpio56"; - function = "qup10"; - }; - }; + pil_cdsp_mem: cdsp_region@0x95d00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0 0x95d00000 0 0x800000>; + }; - qup_i2c11_default: qup-i2c11-default { - pinmux { - pins = "gpio31", "gpio32"; - function = "qup11"; - }; - }; + pil_mba_mem: mba_region@0x96500000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0 0x96500000 0 0x200000>; + }; - qup_i2c12_default: qup-i2c12-default { - pinmux { - pins = "gpio49", "gpio50"; - function = "qup12"; - }; - }; + pil_slpi_mem: slpi_region@0x96700000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0 0x96700000 0 0x1400000>; + }; - qup_i2c13_default: qup-i2c13-default { - pinmux { - pins = "gpio105", "gpio106"; - function = "qup13"; - }; - }; + pil_spss_mem: pil_spss_region@0x97b00000 { + compatible = "removed-dma-pool"; + no-map; + reg = <0 0x97b00000 0 0x100000>; + }; - qup_i2c14_default: qup-i2c14-default { - pinmux { - pins = "gpio33", "gpio34"; - function = "qup14"; - }; - }; + adsp_mem: adsp_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0 0x00000000 0 0xffffffff>; + reusable; + alignment = <0 0x400000>; + size = <0 0x1000000>; + }; - qup_i2c15_default: qup-i2c15-default { - pinmux { - pins = "gpio81", "gpio82"; - function = "qup15"; - }; - }; + qseecom_ta_mem: qseecom_ta_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0 0x00000000 0 0xffffffff>; + reusable; + alignment = <0 0x400000>; + size = <0 0x1000000>; + }; - qup_spi0_default: qup-spi0-default { - pinmux { - pins = "gpio0", "gpio1", - "gpio2", "gpio3"; - function = "qup0"; - }; - }; + secure_sp_mem: secure_sp_region { /* SPSS-HLOS ION shared mem */ + compatible = "shared-dma-pool"; + alloc-ranges = <0 0x00000000 0 0xffffffff>; /* 32-bit */ + reusable; + alignment = <0 0x400000>; + size = <0 0x800000>; + }; - qup_spi1_default: qup-spi1-default { - pinmux { - pins = "gpio17", "gpio18", - "gpio19", "gpio20"; - function = "qup1"; - }; - }; + cont_splash_memory: cont_splash_region@9d400000 { + reg = <0x0 0x9d400000 0x0 0x02400000>; + label = "cont_splash_region"; + }; - qup_spi2_default: qup-spi2-default { - pinmux { - pins = "gpio27", "gpio28", - "gpio29", "gpio30"; - function = "qup2"; - }; - }; + secure_display_memory: secure_display_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0 0x00000000 0 0xffffffff>; + reusable; + alignment = <0 0x400000>; + size = <0 0x5c00000>; + }; - qup_spi3_default: qup-spi3-default { - pinmux { - pins = "gpio41", "gpio42", - "gpio43", "gpio44"; - function = "qup3"; - }; - }; + dump_mem: mem_dump_region { + compatible = "shared-dma-pool"; + reusable; + size = <0 0x2400000>; + }; - qup_spi4_default: qup-spi4-default { - pinmux { - pins = "gpio89", "gpio90", - "gpio91", "gpio92"; - function = "qup4"; - }; - }; + /* global autoconfigured region for contiguous allocations */ + linux,cma { + compatible = "shared-dma-pool"; + alloc-ranges = <0 0x00000000 0 0xffffffff>; + reusable; + alignment = <0 0x400000>; + size = <0 0x2000000>; + linux,cma-default; + }; + }; +}; - qup_spi5_default: qup-spi5-default { - pinmux { - pins = "gpio85", "gpio86", - "gpio87", "gpio88"; - function = "qup5"; - }; - }; +#include "msm-gdsc-sdm845.dtsi" +#include "sdm845-sde-pll.dtsi" +#include "msm-rdbg.dtsi" +#include "sdm845-sde.dtsi" +#include "sdm845-qupv3.dtsi" - qup_spi6_default: qup-spi6-default { - pinmux { - pins = "gpio45", "gpio46", - "gpio47", "gpio48"; - function = "qup6"; - }; - }; +&soc { + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0 0 0xffffffff>; + compatible = "simple-bus"; - qup_spi7_default: qup-spi7-default { - pinmux { - pins = "gpio93", "gpio94", - "gpio95", "gpio96"; - function = "qup7"; - }; - }; + jtag_mm0: jtagmm@7040000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7040000 0x1000>; + reg-names = "etm-base"; - qup_spi8_default: qup-spi8-default { - pinmux { - pins = "gpio65", "gpio66", - "gpio67", "gpio68"; - function = "qup8"; - }; - }; + clocks = <&clock_aop QDSS_CLK>; + clock-names = "core_clk"; - qup_spi9_default: qup-spi9-default { - pinmux { - pins = "gpio6", "gpio7", - "gpio4", "gpio5"; - function = "qup9"; - }; - }; + qcom,coresight-jtagmm-cpu = <&CPU0>; + }; - qup_spi10_default: qup-spi10-default { - pinmux { - pins = "gpio55", "gpio56", - "gpio53", "gpio54"; - function = "qup10"; - }; - }; + jtag_mm1: jtagmm@7140000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7140000 0x1000>; + reg-names = "etm-base"; - qup_spi11_default: qup-spi11-default { - pinmux { - pins = "gpio31", "gpio32", - "gpio33", "gpio34"; - function = "qup11"; - }; - }; + clocks = <&clock_aop QDSS_CLK>; + clock-names = "core_clk"; - qup_spi12_default: qup-spi12-default { - pinmux { - pins = "gpio49", "gpio50", - "gpio51", "gpio52"; - function = "qup12"; - }; - }; + qcom,coresight-jtagmm-cpu = <&CPU1>; + }; - qup_spi13_default: qup-spi13-default { - pinmux { - pins = "gpio105", "gpio106", - "gpio107", "gpio108"; - function = "qup13"; - }; - }; + jtag_mm2: jtagmm@7240000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x7240000 0x1000>; + reg-names = "etm-base"; - qup_spi14_default: qup-spi14-default { - pinmux { - pins = "gpio33", "gpio34", - "gpio31", "gpio32"; - function = "qup14"; - }; - }; + clocks = <&clock_aop QDSS_CLK>; + clock-names = "core_clk"; - qup_spi15_default: qup-spi15-default { - pinmux { - pins = "gpio81", "gpio82", - "gpio83", "gpio84"; - function = "qup15"; - }; - }; + qcom,coresight-jtagmm-cpu = <&CPU2>; + }; - qup_uart9_default: qup-uart9-default { - pinmux { - pins = "gpio4", "gpio5"; - function = "qup9"; - }; - }; + 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>; + }; + + 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 = <1 9 4>; + interrupt-parent = <&intc>; + ignored-save-restore-irqs = <38>; + }; + + pdc: interrupt-controller@b220000{ + compatible = "qcom,pdc-sdm845"; + reg = <0xb220000 0x400>; + #interrupt-cells = <3>; + interrupt-parent = <&intc>; + interrupt-controller; + }; + + timer { + compatible = "arm,armv8-timer"; + interrupts = <1 1 0xf08>, + <1 2 0xf08>, + <1 3 0xf08>, + <1 0 0xf08>; + clock-frequency = <19200000>; + }; + + timer@0x17C90000{ + #address-cells = <1>; + #size-cells = <1>; + ranges; + compatible = "arm,armv7-timer-mem"; + reg = <0x17C90000 0x1000>; + clock-frequency = <19200000>; + + frame@0x17CA0000 { + frame-number = <0>; + interrupts = <0 7 0x4>, + <0 6 0x4>; + reg = <0x17CA0000 0x1000>, + <0x17CB0000 0x1000>; + }; + + frame@17cc0000 { + frame-number = <1>; + interrupts = <0 8 0x4>; + reg = <0x17cc0000 0x1000>; + status = "disabled"; + }; + + frame@17cd0000 { + frame-number = <2>; + interrupts = <0 9 0x4>; + reg = <0x17cd0000 0x1000>; + status = "disabled"; + }; + + frame@17ce0000 { + frame-number = <3>; + interrupts = <0 10 0x4>; + reg = <0x17ce0000 0x1000>; + status = "disabled"; + }; + + frame@17cf0000 { + frame-number = <4>; + interrupts = <0 11 0x4>; + reg = <0x17cf0000 0x1000>; + status = "disabled"; }; - tsens0: thermal-sensor@c263000 { - compatible = "qcom,sdm845-tsens", "qcom,tsens-v2"; - reg = <0xc263000 0x1ff>, /* TM */ - <0xc222000 0x1ff>; /* SROT */ - #qcom,sensors = <13>; - #thermal-sensor-cells = <1>; + frame@17d00000 { + frame-number = <5>; + interrupts = <0 12 0x4>; + reg = <0x17d00000 0x1000>; + status = "disabled"; }; - tsens1: thermal-sensor@c265000 { - compatible = "qcom,sdm845-tsens", "qcom,tsens-v2"; - reg = <0xc265000 0x1ff>, /* TM */ - <0xc223000 0x1ff>; /* SROT */ - #qcom,sensors = <8>; - #thermal-sensor-cells = <1>; + frame@17d10000 { + frame-number = <6>; + interrupts = <0 13 0x4>; + reg = <0x17d10000 0x1000>; + status = "disabled"; }; + }; + + restart@10ac000 { + compatible = "qcom,pshold"; + reg = <0xC264000 0x4>, + <0x1fd3000 0x4>; + reg-names = "pshold-base", "tcsr-boot-misc-detect"; + }; + + aop-msg-client { + compatible = "qcom,debugfs-qmp-client"; + mboxes = <&qmp_aop 0>; + mbox-names = "aop"; + }; - spmi_bus: 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 = ; - qcom,ee = <0>; - qcom,channel = <0>; + 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 = ; + qcom,ee = <0>; + qcom,channel = <0>; + #address-cells = <2>; + #size-cells = <0>; + interrupt-controller; + #interrupt-cells = <4>; + cell-index = <0>; + qcom,enable-ahb-bus-workaround; + }; + + spmi_debug_bus: qcom,spmi-debug@6b22000 { + compatible = "qcom,spmi-pmic-arb-debug"; + reg = <0x6b22000 0x60>, <0x7820A8 4>; + reg-names = "core", "fuse"; + clocks = <&clock_aop QDSS_CLK>; + clock-names = "core_clk"; + qcom,fuse-disable-bit = <12>; + #address-cells = <2>; + #size-cells = <0>; + + qcom,pm8998-debug@0 { + compatible = "qcom,spmi-pmic"; + reg = <0x0 SPMI_USID>; #address-cells = <2>; #size-cells = <0>; - interrupt-controller; - #interrupt-cells = <4>; - cell-index = <0>; - }; - - apss_shared: mailbox@17990000 { - compatible = "qcom,sdm845-apss-shared"; - reg = <0x17990000 0x1000>; - #mbox-cells = <1>; - }; - - apps_rsc: rsc@179c0000 { - label = "apps_rsc"; - compatible = "qcom,rpmh-rsc"; - reg = <0x179c0000 0x10000>, - <0x179d0000 0x10000>, - <0x179e0000 0x10000>; - reg-names = "drv-0", "drv-1", "drv-2"; - interrupts = , - , - ; - qcom,tcs-offset = <0xd00>; - qcom,drv-id = <2>; - qcom,tcs-config = , - , - , - ; - - rpmhcc: clock-controller { - compatible = "qcom,sdm845-rpmh-clk"; - #clock-cells = <1>; - }; - }; - - intc: interrupt-controller@17a00000 { - compatible = "arm,gic-v3"; - #address-cells = <1>; - #size-cells = <1>; - ranges; - #interrupt-cells = <3>; - interrupt-controller; - reg = <0x17a00000 0x10000>, /* GICD */ - <0x17a60000 0x100000>; /* GICR * 8 */ - interrupts = ; - - gic-its@17a40000 { - compatible = "arm,gic-v3-its"; - msi-controller; - #msi-cells = <1>; - reg = <0x17a40000 0x20000>; - status = "disabled"; - }; - }; - - timer@17c90000 { - #address-cells = <1>; - #size-cells = <1>; - ranges; - compatible = "arm,armv7-timer-mem"; - reg = <0x17c90000 0x1000>; - - frame@17ca0000 { - frame-number = <0>; - interrupts = , - ; - reg = <0x17ca0000 0x1000>, - <0x17cb0000 0x1000>; - }; - - frame@17cc0000 { - frame-number = <1>; - interrupts = ; - reg = <0x17cc0000 0x1000>; - status = "disabled"; - }; - - frame@17cd0000 { - frame-number = <2>; - interrupts = ; - reg = <0x17cd0000 0x1000>; - status = "disabled"; - }; - - frame@17ce0000 { - frame-number = <3>; - interrupts = ; - reg = <0x17ce0000 0x1000>; - status = "disabled"; - }; - - frame@17cf0000 { - frame-number = <4>; - interrupts = ; - reg = <0x17cf0000 0x1000>; - status = "disabled"; - }; - - frame@17d00000 { - frame-number = <5>; - interrupts = ; - reg = <0x17d00000 0x1000>; - status = "disabled"; - }; - - frame@17d10000 { - frame-number = <6>; - interrupts = ; - reg = <0x17d10000 0x1000>; - status = "disabled"; + qcom,can-sleep; + }; + + qcom,pm8998-debug@1 { + compatible = "qcom,spmi-pmic"; + reg = <0x1 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + qcom,can-sleep; + }; + + qcom,pmi8998-debug@2 { + compatible = "qcom,spmi-pmic"; + reg = <0x2 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + qcom,can-sleep; + }; + + qcom,pmi8998-debug@3 { + compatible = "qcom,spmi-pmic"; + reg = <0x3 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + qcom,can-sleep; + }; + + qcom,pm8005-debug@4 { + compatible = "qcom,spmi-pmic"; + reg = <0x4 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + qcom,can-sleep; + }; + + qcom,pm8005-debug@5 { + compatible = "qcom,spmi-pmic"; + reg = <0x5 SPMI_USID>; + #address-cells = <2>; + #size-cells = <0>; + qcom,can-sleep; + }; + }; + + cpubw: qcom,cpubw { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + qcom,bw-tbl = + < MHZ_TO_MBPS(150, 16) >, /* 2288 MB/s */ + < MHZ_TO_MBPS(300, 16) >, /* 4577 MB/s */ + < MHZ_TO_MBPS(426, 16) >, /* 6500 MB/s */ + < MHZ_TO_MBPS(533, 16) >, /* 8132 MB/s */ + < MHZ_TO_MBPS(600, 16) >, /* 9155 MB/s */ + < MHZ_TO_MBPS(700, 16) >; /* 10681 MB/s */ + }; + + bwmon: qcom,cpu-bwmon { + compatible = "qcom,bimc-bwmon4"; + reg = <0x1436400 0x300>, <0x1436300 0x200>; + reg-names = "base", "global_base"; + interrupts = <0 581 4>; + qcom,mport = <0>; + qcom,hw-timer-hz = <19200000>; + qcom,target-dev = <&cpubw>; + }; + + llccbw: qcom,llccbw { + compatible = "qcom,devbw"; + governor = "performance"; + qcom,src-dst-ports = + ; + qcom,active-only; + qcom,bw-tbl = + < MHZ_TO_MBPS( 200, 4) >, /* 762 MB/s */ + < MHZ_TO_MBPS( 300, 4) >, /* 1144 MB/s */ + < MHZ_TO_MBPS( 451, 4) >, /* 1720 MB/s */ + < MHZ_TO_MBPS( 547, 4) >, /* 2086 MB/s */ + < MHZ_TO_MBPS( 681, 4) >, /* 2597 MB/s */ + < MHZ_TO_MBPS( 768, 4) >, /* 2929 MB/s */ + < MHZ_TO_MBPS(1017, 4) >, /* 3879 MB/s */ + < MHZ_TO_MBPS(1296, 4) >, /* 4943 MB/s */ + < MHZ_TO_MBPS(1555, 4) >, /* 5931 MB/s */ + < MHZ_TO_MBPS(1804, 4) >; /* 6881 MB/s */ + }; + + llcc_bwmon: qcom,llcc-bwmon { + compatible = "qcom,bimc-bwmon5"; + reg = <0x0114A000 0x1000>; + reg-names = "base"; + interrupts = ; + qcom,hw-timer-hz = <19200000>; + qcom,target-dev = <&llccbw>; + qcom,count-unit = <0x400000>; + qcom,byte-mid-mask = <0xe000>; + qcom,byte-mid-match = <0xe000>; + }; + + memlat_cpu0: qcom,memlat-cpu0 { + compatible = "qcom,devbw"; + governor = "powersave"; + qcom,src-dst-ports = <1 512>; + qcom,active-only; + qcom,bw-tbl = + < MHZ_TO_MBPS( 200, 4) >, /* 762 MB/s */ + < MHZ_TO_MBPS( 300, 4) >, /* 1144 MB/s */ + < MHZ_TO_MBPS( 451, 4) >, /* 1720 MB/s */ + < MHZ_TO_MBPS( 547, 4) >, /* 2086 MB/s */ + < MHZ_TO_MBPS( 681, 4) >, /* 2597 MB/s */ + < MHZ_TO_MBPS( 768, 4) >, /* 2929 MB/s */ + < MHZ_TO_MBPS(1017, 4) >, /* 3879 MB/s */ + < MHZ_TO_MBPS(1296, 4) >, /* 4943 MB/s */ + < MHZ_TO_MBPS(1555, 4) >, /* 5931 MB/s */ + < MHZ_TO_MBPS(1804, 4) >; /* 6881 MB/s */ + }; + + memlat_cpu4: qcom,memlat-cpu4 { + compatible = "qcom,devbw"; + governor = "powersave"; + qcom,src-dst-ports = <1 512>; + qcom,active-only; + status = "ok"; + qcom,bw-tbl = + < MHZ_TO_MBPS( 200, 4) >, /* 762 MB/s */ + < MHZ_TO_MBPS( 300, 4) >, /* 1144 MB/s */ + < MHZ_TO_MBPS( 451, 4) >, /* 1720 MB/s */ + < MHZ_TO_MBPS( 547, 4) >, /* 2086 MB/s */ + < MHZ_TO_MBPS( 681, 4) >, /* 2597 MB/s */ + < MHZ_TO_MBPS( 768, 4) >, /* 2929 MB/s */ + < MHZ_TO_MBPS(1017, 4) >, /* 3879 MB/s */ + < MHZ_TO_MBPS(1296, 4) >, /* 4943 MB/s */ + < MHZ_TO_MBPS(1555, 4) >, /* 5931 MB/s */ + < MHZ_TO_MBPS(1804, 4) >; /* 6881 MB/s */ + }; + + snoc_cnoc_keepalive: qcom,snoc_cnoc_keepalive { + compatible = "qcom,devbw"; + governor = "powersave"; + qcom,src-dst-ports = <139 627>; + qcom,active-only; + status = "ok"; + qcom,bw-tbl = + < 1 >; + }; + + devfreq_memlat_0: qcom,cpu0-memlat-mon { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3>; + qcom,target-dev = <&memlat_cpu0>; + qcom,cachemiss-ev = <0x2A>; + qcom,core-dev-table = + < 300000 MHZ_TO_MBPS( 200, 4) >, + < 748800 MHZ_TO_MBPS( 451, 4) >, + < 1132800 MHZ_TO_MBPS( 547, 4) >, + < 1440000 MHZ_TO_MBPS( 768, 4) >, + < 1593600 MHZ_TO_MBPS(1017, 4) >; + }; + + devfreq_memlat_4: qcom,cpu4-memlat-mon { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU4 &CPU5 &CPU6 &CPU7>; + qcom,target-dev = <&memlat_cpu4>; + qcom,cachemiss-ev = <0x2A>; + qcom,core-dev-table = + < 300000 MHZ_TO_MBPS( 200, 4) >, + < 499200 MHZ_TO_MBPS( 451, 4) >, + < 806400 MHZ_TO_MBPS( 547, 4) >, + < 1036800 MHZ_TO_MBPS( 768, 4) >, + < 1190400 MHZ_TO_MBPS(1017, 4) >, + < 1574400 MHZ_TO_MBPS(1296, 4) >, + < 1728000 MHZ_TO_MBPS(1555, 4) >, + < 1958400 MHZ_TO_MBPS(1804, 4) >; + }; + + l3_cpu0: qcom,l3-cpu0 { + compatible = "devfreq-simple-dev"; + clock-names = "devfreq_clk"; + clocks = <&clock_cpucc L3_CLUSTER0_VOTE_CLK>; + governor = "performance"; + }; + + l3_cpu4: qcom,l3-cpu4 { + compatible = "devfreq-simple-dev"; + clock-names = "devfreq_clk"; + clocks = <&clock_cpucc L3_CLUSTER1_VOTE_CLK>; + governor = "performance"; + }; + + devfreq_l3lat_0: qcom,cpu0-l3lat-mon { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3>; + qcom,target-dev = <&l3_cpu0>; + qcom,cachemiss-ev = <0x17>; + qcom,core-dev-table = + < 300000 300000000 >, + < 748800 576000000 >, + < 979200 652800000 >, + < 1209600 806400000 >, + < 1516800 883200000 >, + < 1593600 960000000 >, + < 1708800 1305600000 >; + }; + + devfreq_l3lat_4: qcom,cpu4-l3lat-mon { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU4 &CPU5 &CPU6 &CPU7>; + qcom,target-dev = <&l3_cpu4>; + qcom,cachemiss-ev = <0x17>; + qcom,core-dev-table = + < 300000 300000000 >, + < 1036800 576000000 >, + < 1190400 806400000 >, + < 1574400 883200000 >, + < 1804800 960000000 >, + < 1958400 1305600000 >; + }; + + l3_cdsp: qcom,l3-cdsp { + compatible = "devfreq-simple-dev"; + clock-names = "devfreq_clk"; + clocks = <&clock_cpucc L3_MISC_VOTE_CLK>; + governor = "powersave"; + }; + + cpu_pmu: cpu-pmu { + compatible = "arm,armv8-pmuv3"; + qcom,irq-is-percpu; + interrupts = <1 5 4>; + }; + + mincpubw: qcom,mincpubw { + compatible = "qcom,devbw"; + governor = "powersave"; + qcom,src-dst-ports = <1 512>; + qcom,active-only; + qcom,bw-tbl = + < MHZ_TO_MBPS( 200, 4) >, /* 762 MB/s */ + < MHZ_TO_MBPS( 300, 4) >, /* 1144 MB/s */ + < MHZ_TO_MBPS( 451, 4) >, /* 1720 MB/s */ + < MHZ_TO_MBPS( 547, 4) >, /* 2086 MB/s */ + < MHZ_TO_MBPS( 681, 4) >, /* 2597 MB/s */ + < MHZ_TO_MBPS( 768, 4) >, /* 2929 MB/s */ + < MHZ_TO_MBPS(1017, 4) >, /* 3879 MB/s */ + < MHZ_TO_MBPS(1296, 4) >, /* 4943 MB/s */ + < MHZ_TO_MBPS(1555, 4) >, /* 5931 MB/s */ + < MHZ_TO_MBPS(1804, 4) >; /* 6881 MB/s */ + }; + + devfreq_cpufreq: devfreq-cpufreq { + mincpubw-cpufreq { + target-dev = <&mincpubw>; + cpu-to-dev-map-0 = + < 1708800 MHZ_TO_MBPS(200, 4) >; + cpu-to-dev-map-4 = + < 1881600 MHZ_TO_MBPS(200, 4) >, + < 2208000 MHZ_TO_MBPS(681, 4) >; + }; + }; + + devfreq_compute: qcom,devfreq-compute { + compatible = "qcom,arm-cpu-mon"; + qcom,cpulist = <&CPU4 &CPU5 &CPU6 &CPU7>; + qcom,target-dev = <&mincpubw>; + qcom,core-dev-table = + < 1881600 MHZ_TO_MBPS(200, 4) >, + < 2208000 MHZ_TO_MBPS(681, 4) >; + }; + + clock_rpmh: qcom,rpmhclk { + compatible = "qcom,rpmh-clk-sdm845"; + #clock-cells = <1>; + mboxes = <&apps_rsc 0>; + mbox-names = "apps"; + }; + + clock_gcc: qcom,gcc@100000 { + compatible = "qcom,gcc-sdm845", "syscon"; + reg = <0x100000 0x1f0000>; + reg-names = "cc_base"; + vdd_cx-supply = <&pm8998_s9_level>; + vdd_cx_ao-supply = <&pm8998_s9_level_ao>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + clock_videocc: qcom,videocc@ab00000 { + compatible = "qcom,video_cc-sdm845", "syscon"; + reg = <0xab00000 0x10000>; + reg-names = "cc_base"; + vdd_cx-supply = <&pm8998_s9_level>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + clock_camcc: qcom,camcc@ad00000 { + compatible = "qcom,cam_cc-sdm845", "syscon"; + reg = <0xad00000 0x10000>; + reg-names = "cc_base"; + vdd_cx-supply = <&pm8998_s9_level>; + vdd_mx-supply = <&pm8998_s6_level>; + qcom,cam_cc_csi0phytimer_clk_src-opp-handle = <&cam_csiphy0>; + qcom,cam_cc_csi1phytimer_clk_src-opp-handle = <&cam_csiphy1>; + qcom,cam_cc_csi2phytimer_clk_src-opp-handle = <&cam_csiphy2>; + qcom,cam_cc_cci_clk_src-opp-handle = <&cam_cci>; + qcom,cam_cc_ife_0_csid_clk_src-opp-handle = <&cam_csid0>; + qcom,cam_cc_ife_0_clk_src-opp-handle = <&cam_vfe0>; + qcom,cam_cc_ife_1_csid_clk_src-opp-handle = <&cam_csid1>; + qcom,cam_cc_ife_1_clk_src-opp-handle = <&cam_vfe1>; + qcom,cam_cc_ife_lite_csid_clk_src-opp-handle = <&cam_csid_lite>; + qcom,cam_cc_ife_lite_clk_src-opp-handle = <&cam_vfe_lite>; + qcom,cam_cc_icp_clk_src-opp-handle = <&cam_a5>; + qcom,cam_cc_ipe_0_clk_src-opp-handle = <&cam_ipe0>; + qcom,cam_cc_ipe_1_clk_src-opp-handle = <&cam_ipe1>; + qcom,cam_cc_bps_clk_src-opp-handle = <&cam_bps>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + clock_dispcc: qcom,dispcc@af00000 { + compatible = "qcom,dispcc-sdm845", "syscon"; + reg = <0xaf00000 0x10000>; + reg-names = "cc_base"; + vdd_cx-supply = <&pm8998_s9_level>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + clock_gpucc: qcom,gpucc@5090000 { + compatible = "qcom,gpucc-sdm845", "syscon"; + reg = <0x5090000 0x9000>; + reg-names = "cc_base"; + vdd_cx-supply = <&pm8998_s9_level>; + vdd_mx-supply = <&pm8998_s6_level>; + qcom,gpu_cc_gmu_clk_src-opp-handle = <&gmu>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + clock_gfx: qcom,gfxcc@5090000 { + compatible = "qcom,gfxcc-sdm845"; + reg = <0x5090000 0x9000>; + reg-names = "cc_base"; + vdd_gfx-supply = <&pm8005_s1_level>; + qcom,gpu_cc_gx_gfx3d_clk_src-opp-handle = <&msm_gpu>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + cpucc_debug: syscon@17970018 { + compatible = "syscon"; + reg = <0x17970018 0x4>; + }; + + clock_cpucc: qcom,cpucc@0x17d41000 { + compatible = "qcom,clk-cpu-osm"; + reg = <0x17d41000 0x1400>, + <0x17d43000 0x1400>, + <0x17d45800 0x1400>; + reg-names = "osm_l3_base", "osm_pwrcl_base", "osm_perfcl_base"; + vdd_l3_mx_ao-supply = <&pm8998_s6_level_ao>; + vdd_pwrcl_mx_ao-supply = <&pm8998_s6_level_ao>; + + qcom,mx-turbo-freq = <1478400000 1689600000 3300000001>; + l3-devs = <&l3_cpu0 &l3_cpu4 &l3_cdsp &msm_gpu>; + + clock-names = "xo_ao"; + clocks = <&clock_rpmh RPMH_CXO_CLK_A>; + #clock-cells = <1>; + }; + + clock_debug: qcom,cc-debug@100000 { + compatible = "qcom,debugcc-sdm845"; + qcom,cc-count = <6>; + qcom,gcc = <&clock_gcc>; + qcom,videocc = <&clock_videocc>; + qcom,camcc = <&clock_camcc>; + qcom,dispcc = <&clock_dispcc>; + qcom,gpucc = <&clock_gpucc>; + qcom,cpucc = <&cpucc_debug>; + clock-names = "xo_clk_src"; + clocks = <&clock_rpmh RPMH_CXO_CLK>; + #clock-cells = <1>; + }; + + clock_aop: qcom,aopclk { + compatible = "qcom,aop-qmp-clk-v1"; + #clock-cells = <1>; + mboxes = <&qmp_aop 0>; + mbox-names = "qdss_clk"; + }; + + ufs_ice: ufsice@1d90000 { + compatible = "qcom,ice"; + reg = <0x1d90000 0x8000>; + qcom,enable-ice-clk; + clock-names = "ufs_core_clk", "bus_clk", + "iface_clk", "ice_core_clk"; + clocks = <&clock_gcc GCC_UFS_PHY_AXI_CLK>, + <&clock_gcc GCC_UFS_MEM_CLKREF_CLK>, + <&clock_gcc GCC_UFS_PHY_AHB_CLK>, + <&clock_gcc GCC_UFS_PHY_ICE_CORE_CLK>; + qcom,op-freq-hz = <0>, <0>, <0>, <300000000>; + vdd-hba-supply = <&ufs_phy_gdsc>; + qcom,msm-bus,name = "ufs_ice_noc"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <1 650 0 0>, /* No vote */ + <1 650 1000 0>; /* Max. bandwidth */ + qcom,bus-vector-names = "MIN", + "MAX"; + qcom,instance-type = "ufs"; + }; + + ufsphy_mem: ufsphy_mem@1d87000 { + reg = <0x1d87000 0xda8>; /* PHY regs */ + reg-names = "phy_mem"; + #phy-cells = <0>; + + lanes-per-direction = <2>; + + clock-names = "ref_clk_src", + "ref_clk", + "ref_aux_clk"; + clocks = <&clock_rpmh RPMH_CXO_CLK>, + <&clock_gcc GCC_UFS_MEM_CLKREF_CLK>, + <&clock_gcc GCC_UFS_PHY_PHY_AUX_HW_CTL_CLK>; + + status = "disabled"; + }; + + ufshc_mem: ufshc@1d84000 { + compatible = "qcom,ufshc"; + reg = <0x1d84000 0x2500>; + interrupts = <0 265 0>; + phys = <&ufsphy_mem>; + phy-names = "ufsphy"; + ufs-qcom-crypto = <&ufs_ice>; + + 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_HW_CTL_CLK>, + <&clock_gcc GCC_AGGRE_UFS_PHY_AXI_HW_CTL_CLK>, + <&clock_gcc GCC_UFS_PHY_AHB_CLK>, + <&clock_gcc GCC_UFS_PHY_UNIPRO_CORE_HW_CTL_CLK>, + <&clock_gcc GCC_UFS_PHY_ICE_CORE_HW_CTL_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 = + <50000000 200000000>, + <0 0>, + <0 0>, + <37500000 150000000>, + <75000000 300000000>, + <0 0>, + <0 0>, + <0 0>, + <0 0>; + + non-removable; + qcom,msm-bus,name = "ufshc_mem"; + qcom,msm-bus,num-cases = <22>; + qcom,msm-bus,num-paths = <2>; + qcom,msm-bus,vectors-KBps = + /* + * During HS G3 UFS runs at nominal voltage corner, vote + * higher bandwidth to push other buses in the data path + * to run at nominal to achieve max throughput. + * 4GBps pushes BIMC to run at nominal. + * 200MBps pushes CNOC to run at nominal. + * Vote for half of this bandwidth for HS G3 1-lane. + * For max bandwidth, vote high enough to push the buses + * to run in turbo voltage corner. + */ + <123 512 0 0>, <1 757 0 0>, /* No vote */ + <123 512 922 0>, <1 757 1000 0>, /* PWM G1 */ + <123 512 1844 0>, <1 757 1000 0>, /* PWM G2 */ + <123 512 3688 0>, <1 757 1000 0>, /* PWM G3 */ + <123 512 7376 0>, <1 757 1000 0>, /* PWM G4 */ + <123 512 1844 0>, <1 757 1000 0>, /* PWM G1 L2 */ + <123 512 3688 0>, <1 757 1000 0>, /* PWM G2 L2 */ + <123 512 7376 0>, <1 757 1000 0>, /* PWM G3 L2 */ + <123 512 14752 0>, <1 757 1000 0>, /* PWM G4 L2 */ + <123 512 127796 0>, <1 757 1000 0>, /* HS G1 RA */ + <123 512 255591 0>, <1 757 1000 0>, /* HS G2 RA */ + <123 512 2097152 0>, <1 757 102400 0>, /* HS G3 RA */ + <123 512 255591 0>, <1 757 1000 0>, /* HS G1 RA L2 */ + <123 512 511181 0>, <1 757 1000 0>, /* HS G2 RA L2 */ + <123 512 4194304 0>, <1 757 204800 0>, /* HS G3 RA L2 */ + <123 512 149422 0>, <1 757 1000 0>, /* HS G1 RB */ + <123 512 298189 0>, <1 757 1000 0>, /* HS G2 RB */ + <123 512 2097152 0>, <1 757 102400 0>, /* HS G3 RB */ + <123 512 298189 0>, <1 757 1000 0>, /* HS G1 RB L2 */ + <123 512 596378 0>, <1 757 1000 0>, /* HS G2 RB L2 */ + /* As UFS working in HS G3 RB L2 mode, aggregated + * bandwidth (AB) should take care of providing + * optimum throughput requested. However, as tested, + * in order to scale up CNOC clock, instantaneous + * bindwidth (IB) needs to be given a proper value too. + */ + <123 512 4194304 0>, <1 757 204800 409600>, /* HS G3 RB L2 */ + <123 512 7643136 0>, <1 757 307200 0>; /* Max. bandwidth */ + + qcom,bus-vector-names = "MIN", + "PWM_G1_L1", "PWM_G2_L1", "PWM_G3_L1", "PWM_G4_L1", + "PWM_G1_L2", "PWM_G2_L2", "PWM_G3_L2", "PWM_G4_L2", + "HS_RA_G1_L1", "HS_RA_G2_L1", "HS_RA_G3_L1", + "HS_RA_G1_L2", "HS_RA_G2_L2", "HS_RA_G3_L2", + "HS_RB_G1_L1", "HS_RB_G2_L1", "HS_RB_G3_L1", + "HS_RB_G1_L2", "HS_RB_G2_L2", "HS_RB_G3_L2", + "MAX"; + + /* PM QoS */ + qcom,pm-qos-cpu-groups = <0x0f 0xf0>; + qcom,pm-qos-cpu-group-latency-us = <70 70>; + 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 = <0 204 0>, <0 222 0>; + 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,sdr104-wa; + + 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 = <70 70>; + qcom,pm-qos-cpu-groups = <0x3f 0xc0>; + qcom,pm-qos-legacy-latency-us = <70 70>, <70 70>; + + status = "disabled"; + }; + + pil_modem: qcom,mss@4080000 { + compatible = "qcom,pil-q6v55-mss"; + reg = <0x4080000 0x100>, + <0x1f63000 0x008>, + <0x1f65000 0x008>, + <0x1f64000 0x008>, + <0x4180000 0x020>, + <0xc2b0000 0x004>, + <0xb2e0100 0x004>, + <0x4180044 0x004>; + reg-names = "qdsp6_base", "halt_q6", "halt_modem", + "halt_nc", "rmb_base", "restart_reg", + "pdc_sync", "alt_reset"; + + clocks = <&clock_rpmh RPMH_CXO_CLK>, + <&clock_gcc GCC_MSS_CFG_AHB_CLK>, + <&clock_gcc GCC_MSS_Q6_MEMNOC_AXI_CLK>, + <&clock_gcc GCC_BOOT_ROM_AHB_CLK>, + <&clock_gcc GCC_MSS_GPLL0_DIV_CLK_SRC>, + <&clock_gcc GCC_MSS_SNOC_AXI_CLK>, + <&clock_gcc GCC_MSS_MFAB_AXIS_CLK>, + <&clock_gcc GCC_PRNG_AHB_CLK>; + clock-names = "xo", "iface_clk", "bus_clk", + "mem_clk", "gpll0_mss_clk", "snoc_axi_clk", + "mnoc_axi_clk", "prng_clk"; + qcom,proxy-clock-names = "xo", "prng_clk"; + qcom,active-clock-names = "iface_clk", "bus_clk", "mem_clk", + "gpll0_mss_clk", "snoc_axi_clk", + "mnoc_axi_clk"; + + interrupts = <0 266 1>; + vdd_cx-supply = <&pm8998_s9_level>; + vdd_cx-voltage = ; + vdd_mx-supply = <&pm8998_s6_level>; + vdd_mx-uV = ; + vdd_mss-supply = <&pm8005_s2_level>; + vdd_mss-uV = ; + qcom,firmware-name = "modem"; + qcom,sequential-fw-load; + qcom,pil-self-auth; + qcom,sysmon-id = <0>; + qcom,minidump-id = <3>; + qcom,ssctl-instance-id = <0x12>; + qcom,override-acc; + qcom,signal-aop; + qcom,qdsp6v65-1-0; + qcom,mss_pdc_offset = <8>; + status = "ok"; + memory-region = <&pil_modem_mem>; + qcom,mem-protect-id = <0xF>; + + /* GPIO inputs from mss */ + qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_1_in 0 0>; + qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_1_in 1 0>; + qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_1_in 2 0>; + qcom,gpio-stop-ack = <&smp2pgpio_ssr_smp2p_1_in 3 0>; + qcom,gpio-shutdown-ack = <&smp2pgpio_ssr_smp2p_1_in 7 0>; + + /* GPIO output to mss */ + qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_1_out 0 0>; + + mboxes = <&qmp_aop 0>; + mbox-names = "mss-pil"; + qcom,mba-mem@0 { + compatible = "qcom,pil-mba-mem"; + memory-region = <&pil_mba_mem>; + }; + }; + + qcom,lpass@17300000 { + compatible = "qcom,pil-tz-generic"; + reg = <0x17300000 0x00100>; + interrupts = <0 162 1>; + + vdd_cx-supply = <&pm8998_s9_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 = <1>; + qcom,proxy-timeout-ms = <10000>; + qcom,smem-id = <423>; + qcom,sysmon-id = <1>; + status = "ok"; + qcom,ssctl-instance-id = <0x14>; + qcom,firmware-name = "adsp"; + qcom,signal-aop; + memory-region = <&pil_adsp_mem>; + + /* GPIO inputs from lpass */ + qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_2_in 0 0>; + qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_2_in 2 0>; + qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_2_in 1 0>; + qcom,gpio-stop-ack = <&smp2pgpio_ssr_smp2p_2_in 3 0>; + + /* GPIO output to lpass */ + qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_2_out 0 0>; + + mboxes = <&qmp_aop 0>; + mbox-names = "adsp-pil"; + }; + + qcom,ssc@5c00000 { + compatible = "qcom,pil-tz-generic"; + reg = <0x5c00000 0x4000>; + interrupts = <0 494 1>; + + vdd_cx-supply = <&pm8998_l27_level>; + qcom,vdd_cx-uV-uA = ; + vdd_mx-supply = <&pm8998_l4_level>; + qcom,vdd_mx-uV-uA = ; + qcom,proxy-reg-names = "vdd_cx", "vdd_mx"; + qcom,keep-proxy-regs-on; + + 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,signal-aop; + qcom,firmware-name = "slpi"; + status = "ok"; + memory-region = <&pil_slpi_mem>; + + /* GPIO inputs from ssc */ + qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_3_in 0 0>; + qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_3_in 2 0>; + qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_3_in 1 0>; + qcom,gpio-stop-ack = <&smp2pgpio_ssr_smp2p_3_in 3 0>; + + /* GPIO output to ssc */ + qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_3_out 0 0>; + + mboxes = <&qmp_aop 0>; + mbox-names = "slpi-pil"; + }; + + slim_aud: slim@171c0000 { + cell-index = <1>; + compatible = "qcom,slim-ngd"; + reg = <0x171c0000 0x2c000>, + <0x17184000 0x2a000>; + reg-names = "slimbus_physical", "slimbus_bam_physical"; + interrupts = <0 163 0>, <0 164 0>; + interrupt-names = "slimbus_irq", "slimbus_bam_irq"; + qcom,apps-ch-pipes = <0x780000>; + qcom,ea-pc = <0x270>; + qcom,iommu-s1-bypass; + + iommu_slim_aud_ctrl_cb: qcom,iommu_slim_ctrl_cb { + compatible = "qcom,iommu-slim-ctrl-cb"; + iommus = <&apps_smmu 0x1806 0x0>, + <&apps_smmu 0x180d 0x0>, + <&apps_smmu 0x180e 0x1>, + <&apps_smmu 0x1810 0x1>; + }; + }; + + slim_qca: slim@17240000 { + status = "ok"; + cell-index = <3>; + compatible = "qcom,slim-ngd"; + reg = <0x17240000 0x2c000>, + <0x17204000 0x20000>; + reg-names = "slimbus_physical", "slimbus_bam_physical"; + interrupts = <0 291 0>, <0 292 0>; + interrupt-names = "slimbus_irq", "slimbus_bam_irq"; + qcom,iommu-s1-bypass; + + iommu_slim_qca_ctrl_cb: qcom,iommu_slim_ctrl_cb { + compatible = "qcom,iommu-slim-ctrl-cb"; + iommus = <&apps_smmu 0x1813 0x0>; + }; + + /* 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]; + }; + }; + + eud: qcom,msm-eud@88e0000 { + compatible = "qcom,msm-eud"; + interrupt-names = "eud_irq"; + interrupts = ; + reg = <0x88e0000 0x2000>; + reg-names = "eud_base"; + clocks = <&clock_gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>; + clock-names = "cfg_ahb_clk"; + vdda33-supply = <&pm8998_l24>; + status = "ok"; + }; + + 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 = <&pm8998_s9_level>; + qcom,proxy-reg-names = "vdd_cx"; + qcom,vdd_cx-uV-uA = ; + vdd_mx-supply = <&pm8998_s6_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,pas-id = <14>; + qcom,proxy-timeout-ms = <10000>; + qcom,signal-aop; + qcom,firmware-name = "spss"; + memory-region = <&pil_spss_mem>; + qcom,spss-scsr-bits = <24 25>; + + mboxes = <&qmp_aop 0>; + mbox-names = "spss-pil"; + }; + + wdog: qcom,wdt@17980000{ + compatible = "qcom,msm-watchdog"; + reg = <0x17980000 0x1000>; + reg-names = "wdt-base"; + interrupts = <0 0 0>, <0 1 0>; + qcom,bark-time = <11000>; + qcom,pet-time = <9360>; + qcom,ipi-ping; + qcom,wakeup-enable; + }; + + qcom,turing@8300000 { + compatible = "qcom,pil-tz-generic"; + reg = <0x8300000 0x100000>; + interrupts = <0 578 1>; + + vdd_cx-supply = <&pm8998_s9_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"; + qcom,signal-aop; + memory-region = <&pil_cdsp_mem>; + + /* GPIO inputs from turing */ + qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_5_in 0 0>; + qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_5_in 2 0>; + qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_5_in 1 0>; + qcom,gpio-stop-ack = <&smp2pgpio_ssr_smp2p_5_in 3 0>; + + /* GPIO output to turing*/ + qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_5_out 0 0>; + status = "ok"; + + mboxes = <&qmp_aop 0>; + mbox-names = "cdsp-pil"; + }; + + qcom,msm-rtb { + compatible = "qcom,msm-rtb"; + qcom,rtb-size = <0x100000>; + }; + + qcom,mpm2-sleep-counter@0x0c221000 { + compatible = "qcom,mpm2-sleep-counter"; + reg = <0x0c221000 0x1000>; + clock-frequency = <32768>; + }; + + 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>; + }; + + qcom,msm_fastrpc { + compatible = "qcom,msm-fastrpc-compute"; + qcom,rpc-latency-us = <611>; + + qcom,msm_fastrpc_compute_cb1 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1401 0x30>; + dma-coherent; + }; + qcom,msm_fastrpc_compute_cb2 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1402 0x30>; + dma-coherent; + }; + qcom,msm_fastrpc_compute_cb3 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1403 0x30>; + dma-coherent; + }; + qcom,msm_fastrpc_compute_cb4 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1404 0x30>; + dma-coherent; + }; + qcom,msm_fastrpc_compute_cb5 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1405 0x30>; + dma-coherent; + }; + qcom,msm_fastrpc_compute_cb6 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1406 0x30>; + dma-coherent; + }; + qcom,msm_fastrpc_compute_cb7 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1407 0x30>; + dma-coherent; + }; + qcom,msm_fastrpc_compute_cb8 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + iommus = <&apps_smmu 0x1408 0x30>; + dma-coherent; + }; + qcom,msm_fastrpc_compute_cb9 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + qcom,secure-context-bank; + iommus = <&apps_smmu 0x1409 0x30>; + dma-coherent; + }; + qcom,msm_fastrpc_compute_cb10 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "cdsprpc-smd"; + qcom,secure-context-bank; + iommus = <&apps_smmu 0x140A 0x30>; + dma-coherent; + }; + qcom,msm_fastrpc_compute_cb11 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "adsprpc-smd"; + iommus = <&apps_smmu 0x1823 0x0>; + dma-coherent; + }; + qcom,msm_fastrpc_compute_cb12 { + compatible = "qcom,msm-fastrpc-compute-cb"; + label = "adsprpc-smd"; + iommus = <&apps_smmu 0x1824 0x0>; + dma-coherent; + }; + }; + + qcom,msm-imem@146bf000 { + compatible = "qcom,msm-imem"; + reg = <0x146bf000 0x1000>; + ranges = <0x0 0x146bf000 0x1000>; + #address-cells = <1>; + #size-cells = <1>; + + mem_dump_table@10 { + compatible = "qcom,msm-imem-mem_dump_table"; + reg = <0x10 8>; + }; + + restart_reason@65c { + compatible = "qcom,msm-imem-restart_reason"; + reg = <0x65c 4>; + }; + + dload_type@1c { + compatible = "qcom,msm-imem-dload-type"; + reg = <0x1c 0x4>; + }; + + boot_stats@6b0 { + compatible = "qcom,msm-imem-boot_stats"; + reg = <0x6b0 32>; + }; + + pil@94c { + compatible = "qcom,msm-imem-pil"; + reg = <0x94c 200>; + }; + + kaslr_offset@6d0 { + compatible = "qcom,msm-imem-kaslr_offset"; + reg = <0x6d0 12>; + }; + + diag_dload@c8 { + compatible = "qcom,msm-imem-diag-dload"; + reg = <0xc8 200>; + }; + }; + + qcom,venus@aae0000 { + compatible = "qcom,pil-tz-generic"; + reg = <0xaae0000 0x4000>; + + vdd-supply = <&venus_gdsc>; + qcom,proxy-reg-names = "vdd"; + + clocks = <&clock_videocc VIDEO_CC_VENUS_CTL_CORE_CLK>, + <&clock_videocc VIDEO_CC_VENUS_AHB_CLK>, + <&clock_videocc VIDEO_CC_VENUS_CTL_AXI_CLK>; + clock-names = "core_clk", "iface_clk", "bus_clk"; + qcom,proxy-clock-names = "core_clk", "iface_clk", "bus_clk"; + + 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>; + status = "ok"; + }; + + ssc_sensors: qcom,msm-ssc-sensors { + compatible = "qcom,msm-ssc-sensors"; + status = "ok"; + qcom,firmware-name = "slpi"; + }; + + cpuss_dump { + compatible = "qcom,cpuss-dump"; + qcom,l1_i_cache0 { + qcom,dump-node = <&L1_I_0>; + qcom,dump-id = <0x60>; + }; + qcom,l1_i_cache1 { + qcom,dump-node = <&L1_I_100>; + qcom,dump-id = <0x61>; + }; + qcom,l1_i_cache2 { + qcom,dump-node = <&L1_I_200>; + qcom,dump-id = <0x62>; + }; + qcom,l1_i_cache3 { + qcom,dump-node = <&L1_I_300>; + qcom,dump-id = <0x63>; + }; + qcom,l1_i_cache100 { + qcom,dump-node = <&L1_I_400>; + qcom,dump-id = <0x64>; + }; + qcom,l1_i_cache101 { + qcom,dump-node = <&L1_I_500>; + qcom,dump-id = <0x65>; + }; + qcom,l1_i_cache102 { + qcom,dump-node = <&L1_I_600>; + qcom,dump-id = <0x66>; + }; + qcom,l1_i_cache103 { + qcom,dump-node = <&L1_I_700>; + qcom,dump-id = <0x67>; + }; + qcom,l1_d_cache0 { + qcom,dump-node = <&L1_D_0>; + qcom,dump-id = <0x80>; + }; + qcom,l1_d_cache1 { + qcom,dump-node = <&L1_D_100>; + qcom,dump-id = <0x81>; + }; + qcom,l1_d_cache2 { + qcom,dump-node = <&L1_D_200>; + qcom,dump-id = <0x82>; + }; + qcom,l1_d_cache3 { + qcom,dump-node = <&L1_D_300>; + qcom,dump-id = <0x83>; + }; + qcom,l1_d_cache100 { + qcom,dump-node = <&L1_D_400>; + qcom,dump-id = <0x84>; + }; + qcom,l1_d_cache101 { + qcom,dump-node = <&L1_D_500>; + qcom,dump-id = <0x85>; + }; + qcom,l1_d_cache102 { + qcom,dump-node = <&L1_D_600>; + qcom,dump-id = <0x86>; + }; + qcom,l1_d_cache103 { + qcom,dump-node = <&L1_D_700>; + qcom,dump-id = <0x87>; + }; + qcom,llcc1_d_cache { + qcom,dump-node = <&LLCC_1>; + qcom,dump-id = <0x140>; + }; + qcom,llcc2_d_cache { + qcom,dump-node = <&LLCC_2>; + qcom,dump-id = <0x141>; + }; + qcom,llcc3_d_cache { + qcom,dump-node = <&LLCC_3>; + qcom,dump-id = <0x142>; + }; + qcom,llcc4_d_cache { + qcom,dump-node = <&LLCC_4>; + qcom,dump-id = <0x143>; + }; + qcom,l1_tlb_dump0 { + qcom,dump-node = <&L1_TLB_0>; + qcom,dump-id = <0x120>; + }; + qcom,l1_tlb_dump100 { + qcom,dump-node = <&L1_TLB_100>; + qcom,dump-id = <0x121>; + }; + qcom,l1_tlb_dump200 { + qcom,dump-node = <&L1_TLB_200>; + qcom,dump-id = <0x122>; + }; + qcom,l1_tlb_dump300 { + qcom,dump-node = <&L1_TLB_300>; + qcom,dump-id = <0x123>; + }; + qcom,l1_tlb_dump400 { + qcom,dump-node = <&L1_TLB_400>; + qcom,dump-id = <0x124>; + }; + qcom,l1_tlb_dump500 { + qcom,dump-node = <&L1_TLB_500>; + qcom,dump-id = <0x125>; + }; + qcom,l1_tlb_dump600 { + qcom,dump-node = <&L1_TLB_600>; + qcom,dump-id = <0x126>; + }; + qcom,l1_tlb_dump700 { + qcom,dump-node = <&L1_TLB_700>; + qcom,dump-id = <0x127>; + }; + }; + + kryo3xx-erp { + compatible = "arm,arm64-kryo3xx-cpu-erp"; + interrupts = <1 6 4>, + <1 7 4>, + <0 34 4>, + <0 35 4>; + + interrupt-names = "l1-l2-faultirq", + "l1-l2-errirq", + "l3-scu-errirq", + "l3-scu-faultirq"; + }; + + qcom,llcc@1100000 { + compatible = "qcom,llcc-core", "syscon", "simple-mfd"; + reg = <0x1100000 0x250000>; + reg-names = "llcc_base"; + qcom,llcc-banks-off = <0x0 0x80000 0x100000 0x180000>; + qcom,llcc-broadcast-off = <0x200000>; + + llcc: qcom,sdm845-llcc { + compatible = "qcom,sdm845-llcc"; + #cache-cells = <1>; + max-slices = <32>; + }; + + qcom,llcc-perfmon { + compatible = "qcom,llcc-perfmon"; + }; + + qcom,llcc-erp { + compatible = "qcom,llcc-erp"; + interrupt-names = "ecc_irq"; + interrupts = ; + }; + + qcom,llcc-amon { + compatible = "qcom,llcc-amon"; + }; + + LLCC_1: llcc_1_dcache { + qcom,dump-size = <0x1141c0>; + }; + + LLCC_2: llcc_2_dcache { + qcom,dump-size = <0x1141c0>; + }; + + LLCC_3: llcc_3_dcache { + qcom,dump-size = <0x1141c0>; + }; + + LLCC_4: llcc_4_dcache { + qcom,dump-size = <0x1141c0>; + }; + }; + + qcom,ipc-spinlock@1f40000 { + compatible = "qcom,ipc-spinlock-sfpb"; + reg = <0x1f40000 0x8000>; + qcom,num-locks = <8>; + }; + + qcom,smem@86000000 { + compatible = "qcom,smem"; + reg = <0x86000000 0x200000>, + <0x17911008 0x4>, + <0x778000 0x7000>, + <0x1fd4000 0x8>; + reg-names = "smem", "irq-reg-base", "aux-mem1", + "smem_targ_info_reg"; + qcom,mpu-enabled; + }; + + qcom,glink-mailbox-xprt-spss@1885008 { + compatible = "qcom,glink-mailbox-xprt"; + reg = <0x1885008 0x8>, + <0x1885010 0x4>, + <0x188501c 0x4>, + <0x1886008 0x4>; + reg-names = "mbox-loc-addr", "mbox-loc-size", "irq-reg-base", + "irq-rx-reset"; + qcom,irq-mask = <0x1>; + interrupts = <0 348 4>; + label = "spss"; + qcom,tx-ring-size = <0x400>; + qcom,rx-ring-size = <0x400>; + }; + + qmp_aop: qcom,qmp-aop@c300000 { + compatible = "qcom,qmp-mbox"; + label = "aop"; + reg = <0xc300000 0x100000>, + <0x1799000c 0x4>; + reg-names = "msgram", "irq-reg-base"; + qcom,irq-mask = <0x1>; + interrupts = <0 389 1>; + priority = <0>; + mbox-desc-offset = <0x0>; + #mbox-cells = <1>; + }; + + apps_rsc: mailbox@179e0000 { + compatible = "qcom,tcs-drv"; + label = "apps_rsc"; + reg = <0x179e0000 0x100>, <0x179e0d00 0x3000>; + interrupts = <0 5 0>; + #mbox-cells = <1>; + qcom,drv-id = <2>; + qcom,tcs-config = , + , + , + ; + }; + + disp_rsc: mailbox@af20000 { + compatible = "qcom,tcs-drv"; + label = "display_rsc"; + reg = <0xaf20000 0x100>, <0xaf21c00 0x3000>; + interrupts = <0 129 0>; + #mbox-cells = <1>; + qcom,drv-id = <0>; + qcom,tcs-config = , + , + , + ; + }; + + system_pm { + compatible = "qcom,system-pm"; + mboxes = <&apps_rsc 0>; + }; + + qcom,glink-smem-native-xprt-modem@86000000 { + compatible = "qcom,glink-smem-native-xprt"; + reg = <0x86000000 0x200000>, + <0x1799000c 0x4>; + reg-names = "smem", "irq-reg-base"; + qcom,irq-mask = <0x1000>; + interrupts = ; + label = "mpss"; + }; + + qcom,glink-smem-native-xprt-adsp@86000000 { + compatible = "qcom,glink-smem-native-xprt"; + reg = <0x86000000 0x200000>, + <0x1799000c 0x4>; + reg-names = "smem", "irq-reg-base"; + qcom,irq-mask = <0x100>; + interrupts = ; + label = "lpass"; + cpu-affinity = <1 2>; + qcom,qos-config = <&glink_qos_adsp>; + qcom,ramp-time = <0xaf>; + }; + + glink_qos_adsp: qcom,glink-qos-config-adsp { + compatible = "qcom,glink-qos-config"; + qcom,flow-info = <0x3c 0x0>, + <0x3c 0x0>, + <0x3c 0x0>, + <0x3c 0x0>; + qcom,mtu-size = <0x800>; + qcom,tput-stats-cycle = <0xa>; + }; + + qcom,glink-smem-native-xprt-dsps@86000000 { + compatible = "qcom,glink-smem-native-xprt"; + reg = <0x86000000 0x200000>, + <0x1799000c 0x4>; + reg-names = "smem", "irq-reg-base"; + qcom,irq-mask = <0x1000000>; + interrupts = ; + label = "dsps"; + }; + + glink_spi_xprt_wdsp: qcom,glink-spi-xprt-wdsp { + compatible = "qcom,glink-spi-xprt"; + label = "wdsp"; + qcom,remote-fifo-config = <&glink_fifo_wdsp>; + qcom,qos-config = <&glink_qos_wdsp>; + qcom,ramp-time = <0x10>, + <0x20>, + <0x30>, + <0x40>; + }; + + glink_fifo_wdsp: qcom,glink-fifo-config-wdsp { + compatible = "qcom,glink-fifo-config"; + qcom,out-read-idx-reg = <0x12000>; + qcom,out-write-idx-reg = <0x12004>; + qcom,in-read-idx-reg = <0x1200C>; + qcom,in-write-idx-reg = <0x12010>; + }; + + glink_qos_wdsp: qcom,glink-qos-config-wdsp { + compatible = "qcom,glink-qos-config"; + qcom,flow-info = <0x80 0x0>, + <0x70 0x1>, + <0x60 0x2>, + <0x50 0x3>; + qcom,mtu-size = <0x800>; + qcom,tput-stats-cycle = <0xa>; + }; + + qcom,glink-smem-native-xprt-cdsp@86000000 { + compatible = "qcom,glink-smem-native-xprt"; + reg = <0x86000000 0x200000>, + <0x1799000c 0x4>; + reg-names = "smem", "irq-reg-base"; + qcom,irq-mask = <0x10>; + interrupts = ; + label = "cdsp"; + }; + + glink_mpss: qcom,glink-ssr-modem { + compatible = "qcom,glink_ssr"; + label = "modem"; + qcom,edge = "mpss"; + qcom,notify-edges = <&glink_lpass>, <&glink_dsps>, + <&glink_cdsp>, <&glink_spss>; + qcom,xprt = "smem"; + }; + + glink_lpass: qcom,glink-ssr-adsp { + compatible = "qcom,glink_ssr"; + label = "adsp"; + qcom,edge = "lpass"; + qcom,notify-edges = <&glink_mpss>, <&glink_dsps>, <&glink_cdsp>; + qcom,xprt = "smem"; + }; + + glink_dsps: qcom,glink-ssr-dsps { + compatible = "qcom,glink_ssr"; + label = "slpi"; + qcom,edge = "dsps"; + qcom,notify-edges = <&glink_mpss>, <&glink_lpass>, + <&glink_cdsp>; + qcom,xprt = "smem"; + }; + + glink_cdsp: qcom,glink-ssr-cdsp { + compatible = "qcom,glink_ssr"; + label = "cdsp"; + qcom,edge = "cdsp"; + qcom,notify-edges = <&glink_mpss>, <&glink_lpass>, + <&glink_dsps>; + qcom,xprt = "smem"; + }; + + glink_spss: qcom,glink-ssr-spss { + compatible = "qcom,glink_ssr"; + label = "spss"; + qcom,edge = "spss"; + qcom,notify-edges = <&glink_mpss>; + qcom,xprt = "mailbox"; + }; + + qcom,ipc_router { + compatible = "qcom,ipc_router"; + qcom,node-id = <1>; + }; + + qcom,ipc_router_modem_xprt { + compatible = "qcom,ipc_router_glink_xprt"; + qcom,ch-name = "IPCRTR"; + qcom,xprt-remote = "mpss"; + qcom,glink-xprt = "smem"; + qcom,xprt-linkid = <1>; + qcom,xprt-version = <1>; + qcom,fragmented-data; + }; + + qcom,ipc_router_q6_xprt { + compatible = "qcom,ipc_router_glink_xprt"; + qcom,ch-name = "IPCRTR"; + qcom,xprt-remote = "lpass"; + qcom,glink-xprt = "smem"; + qcom,xprt-linkid = <1>; + qcom,xprt-version = <1>; + qcom,fragmented-data; + }; + + qcom,ipc_router_dsps_xprt { + compatible = "qcom,ipc_router_glink_xprt"; + qcom,ch-name = "IPCRTR"; + qcom,xprt-remote = "dsps"; + qcom,glink-xprt = "smem"; + qcom,xprt-linkid = <1>; + qcom,xprt-version = <1>; + qcom,fragmented-data; + qcom,dynamic-wakeup-source; + qcom,low-latency-xprt; + }; + + qcom,ipc_router_cdsp_xprt { + compatible = "qcom,ipc_router_glink_xprt"; + qcom,ch-name = "IPCRTR"; + qcom,xprt-remote = "cdsp"; + qcom,glink-xprt = "smem"; + qcom,xprt-linkid = <1>; + qcom,xprt-version = <1>; + qcom,fragmented-data; + }; + + qcom,qsee_ipc_irq_bridge { + compatible = "qcom,qsee-ipc-irq-bridge"; + + qcom,qsee-ipc-irq-spss { + qcom,rx-irq-clr = <0x1888008 0x4>; + qcom,rx-irq-clr-mask = <0x1>; + qcom,dev-name = "qsee_ipc_irq_spss"; + interrupts = <0 349 4>; + label = "spss"; + }; + }; + + qcom,spcom { + compatible = "qcom,spcom"; + + /* predefined channels, remote side is server */ + qcom,spcom-ch-names = "sp_kernel", "sp_ssr"; + status = "ok"; + }; + + spss_utils: qcom,spss_utils { + compatible = "qcom,spss-utils"; + /* spss fuses physical address */ + qcom,spss-fuse1-addr = <0x007841c4>; + qcom,spss-fuse1-bit = <27>; + qcom,spss-fuse2-addr = <0x007841c4>; + qcom,spss-fuse2-bit = <26>; + 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>; + status = "ok"; + }; + + qcom,glink_pkt { + compatible = "qcom,glinkpkt"; + + qcom,glinkpkt-at-mdm0 { + qcom,glinkpkt-transport = "smem"; + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DS"; + qcom,glinkpkt-dev-name = "at_mdm0"; + }; + + qcom,glinkpkt-loopback_cntl { + qcom,glinkpkt-transport = "lloop"; + qcom,glinkpkt-edge = "local"; + qcom,glinkpkt-ch-name = "LOCAL_LOOPBACK_CLNT"; + qcom,glinkpkt-dev-name = "glink_pkt_loopback_ctrl"; + }; + + qcom,glinkpkt-loopback_data { + qcom,glinkpkt-transport = "lloop"; + qcom,glinkpkt-edge = "local"; + qcom,glinkpkt-ch-name = "glink_pkt_lloop_CLNT"; + qcom,glinkpkt-dev-name = "glink_pkt_loopback"; + }; + + qcom,glinkpkt-apr-apps2 { + qcom,glinkpkt-transport = "smem"; + qcom,glinkpkt-edge = "adsp"; + qcom,glinkpkt-ch-name = "apr_apps2"; + qcom,glinkpkt-dev-name = "apr_apps2"; + }; + + qcom,glinkpkt-data40-cntl { + qcom,glinkpkt-transport = "smem"; + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA40_CNTL"; + qcom,glinkpkt-dev-name = "smdcntl8"; + }; + + qcom,glinkpkt-data1 { + qcom,glinkpkt-transport = "smem"; + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA1"; + qcom,glinkpkt-dev-name = "smd7"; + }; + + qcom,glinkpkt-data4 { + qcom,glinkpkt-transport = "smem"; + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA4"; + qcom,glinkpkt-dev-name = "smd8"; + }; + + qcom,glinkpkt-data11 { + qcom,glinkpkt-transport = "smem"; + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA11"; + qcom,glinkpkt-dev-name = "smd11"; + }; + }; + + qcom,sps { + compatible = "qcom,msm_sps_4k"; + qcom,pipe-attr-ee; + }; + + qcom,qbt1000 { + compatible = "qcom,qbt1000"; + clock-names = "core", "iface"; + clock-frequency = <25000000>; + qcom,ipc-gpio = <&tlmm 121 0>; + qcom,finger-detect-gpio = <&pm8998_gpios 5 0>; + }; + + qcom_seecom: qseecom@86d00000 { + compatible = "qcom,qseecom"; + reg = <0x86d00000 0x2200000>; + reg-names = "secapp-region"; + qcom,hlos-num-ce-hw-instances = <1>; + qcom,hlos-ce-hw-instance = <0>; + qcom,qsee-ce-hw-instance = <0>; + qcom,disk-encrypt-pipe-pair = <2>; + qcom,support-fde; + qcom,no-clock-support; + qcom,fde-key-size; + 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 = + <125 512 0 0>, + <125 512 200000 400000>, + <125 512 300000 800000>, + <125 512 400000 1000000>; + clock-names = "core_clk_src", "core_clk", + "iface_clk", "bus_clk"; + clocks = <&clock_gcc GCC_CE1_CLK>, + <&clock_gcc GCC_CE1_CLK>, + <&clock_gcc GCC_CE1_AHB_CLK>, + <&clock_gcc GCC_CE1_AXI_CLK>; + qcom,ce-opp-freq = <171430000>; + 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"; + }; + + qcom_tzlog: tz-log@146bf720 { + compatible = "qcom,tz-log"; + reg = <0x146bf720 0x3000>; + qcom,hyplog-enabled; + hyplog-address-offset = <0x410>; + hyplog-size-offset = <0x414>; + }; + + qcom_cedev: qcedev@1de0000 { + compatible = "qcom,qcedev"; + reg = <0x1de0000 0x20000>, + <0x1dc4000 0x24000>; + reg-names = "crypto-base","crypto-bam-base"; + interrupts = <0 272 0>; + 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>; + clock-names = "core_clk_src", "core_clk", + "iface_clk", "bus_clk"; + clocks = <&clock_gcc GCC_CE1_CLK>, + <&clock_gcc GCC_CE1_CLK>, + <&clock_gcc GCC_CE1_AHB_CLK>, + <&clock_gcc GCC_CE1_AXI_CLK>; + qcom,ce-opp-freq = <171430000>; + qcom,request-bw-before-clk; + + qcom,smmu-s1-enable; + iommus = <&apps_smmu 0x706 0x1>, + <&apps_smmu 0x716 0x1>; + + qcom_cedev_ns_cb { + compatible = "qcom,qcedev,context-bank"; + label = "ns_context"; + iommus = <&apps_smmu 0x712 0>, + <&apps_smmu 0x71f 0>; + virtual-addr = <0x60000000>; + virtual-size = <0x40000000>; + }; + + qcom_cedev_s_cb { + compatible = "qcom,qcedev,context-bank"; + label = "secure_context"; + iommus = <&apps_smmu 0x713 0>, + <&apps_smmu 0x71c 0>, + <&apps_smmu 0x71d 0>, + <&apps_smmu 0x71e 0>; + virtual-addr = <0x60200000>; + virtual-size = <0x40000000>; + qcom,secure-context-bank; + }; + }; + + qcom_msmhdcp: qcom,msm_hdcp { + compatible = "qcom,msm-hdcp"; + }; + + qcom_crypto: qcrypto@1de0000 { + compatible = "qcom,qcrypto"; + reg = <0x1de0000 0x20000>, + <0x1dc4000 0x24000>; + reg-names = "crypto-base","crypto-bam-base"; + interrupts = <0 272 0>; + 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>; + clock-names = "core_clk_src", "core_clk", + "iface_clk", "bus_clk"; + clocks = <&clock_gcc GCC_CE1_CLK>, + <&clock_gcc GCC_CE1_CLK>, + <&clock_gcc GCC_CE1_AHB_CLK>, + <&clock_gcc GCC_CE1_AXI_CLK>; + qcom,ce-opp-freq = <171430000>; + qcom,request-bw-before-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 0x704 0x1>, + <&apps_smmu 0x714 0x1>; + }; + + qcom,msm_gsi { + compatible = "qcom,msm_gsi"; + }; + + qcom,rmtfs_sharedmem@0 { + compatible = "qcom,sharedmem-uio"; + reg = <0x0 0x200000>; + reg-names = "rmtfs"; + qcom,client-id = <0x00000001>; + qcom,guard-memory; + }; + + qcom,rmnet-ipa { + compatible = "qcom,rmnet-ipa3"; + qcom,rmnet-ipa-ssr; + qcom,ipa-loaduC; + qcom,ipa-advertise-sg-support; + qcom,ipa-napi-enable; + }; + + ipa_hw: qcom,ipa@01e00000 { + compatible = "qcom,ipa"; + reg = <0x1e00000 0x34000>, + <0x1e04000 0x2c000>; + reg-names = "ipa-base", "gsi-base"; + interrupts = + <0 311 0>, + <0 432 0>; + interrupt-names = "ipa-irq", "gsi-irq"; + qcom,ipa-hw-ver = <13>; /* IPA core version = IPAv3.5.1 */ + qcom,ipa-hw-mode = <0>; + qcom,ee = <0>; + qcom,use-ipa-tethering-bridge; + qcom,modem-cfg-emb-pipe-flt; + qcom,ipa-wdi2; + qcom,use-64-bit-dma-mask; + qcom,arm-smmu; + qcom,smmu-fast-map; + qcom,bandwidth-vote-for-ipa; + qcom,msm-bus,name = "ipa"; + qcom,msm-bus,num-cases = <5>; + qcom,msm-bus,num-paths = <4>; + qcom,msm-bus,vectors-KBps = + /* No vote */ + <90 512 0 0>, + <90 585 0 0>, + <1 676 0 0>, + <143 777 0 0>, + /* SVS2 */ + <90 512 80000 600000>, + <90 585 80000 350000>, + <1 676 40000 40000>, /*gcc_config_noc_clk_src */ + <143 777 0 75>, /* IB defined for IPA2X_clk in MHz*/ + /* SVS */ + <90 512 80000 640000>, + <90 585 80000 640000>, + <1 676 80000 80000>, + <143 777 0 150>, /* IB defined for IPA2X_clk in MHz*/ + /* NOMINAL */ + <90 512 206000 960000>, + <90 585 206000 960000>, + <1 676 206000 160000>, + <143 777 0 300>, /* IB defined for IPA2X_clk in MHz*/ + /* TURBO */ + <90 512 206000 3600000>, + <90 585 206000 3600000>, + <1 676 206000 300000>, + <143 777 0 355>; /* IB defined for IPA clk in MHz*/ + qcom,bus-vector-names = + "MIN", "SVS2", "SVS", "NOMINAL", "TURBO"; + + /* IPA RAM mmap */ + qcom,ipa-ram-mmap = < + 0x280 /* ofst_start; */ + 0x0 /* nat_ofst; */ + 0x0 /* nat_size; */ + 0x288 /* v4_flt_hash_ofst; */ + 0x78 /* v4_flt_hash_size; */ + 0x4000 /* v4_flt_hash_size_ddr; */ + 0x308 /* v4_flt_nhash_ofst; */ + 0x78 /* v4_flt_nhash_size; */ + 0x4000 /* v4_flt_nhash_size_ddr; */ + 0x388 /* v6_flt_hash_ofst; */ + 0x78 /* v6_flt_hash_size; */ + 0x4000 /* v6_flt_hash_size_ddr; */ + 0x408 /* v6_flt_nhash_ofst; */ + 0x78 /* v6_flt_nhash_size; */ + 0x4000 /* v6_flt_nhash_size_ddr; */ + 0xf /* v4_rt_num_index; */ + 0x0 /* v4_modem_rt_index_lo; */ + 0x7 /* v4_modem_rt_index_hi; */ + 0x8 /* v4_apps_rt_index_lo; */ + 0xe /* v4_apps_rt_index_hi; */ + 0x488 /* v4_rt_hash_ofst; */ + 0x78 /* v4_rt_hash_size; */ + 0x4000 /* v4_rt_hash_size_ddr; */ + 0x508 /* v4_rt_nhash_ofst; */ + 0x78 /* v4_rt_nhash_size; */ + 0x4000 /* v4_rt_nhash_size_ddr; */ + 0xf /* v6_rt_num_index; */ + 0x0 /* v6_modem_rt_index_lo; */ + 0x7 /* v6_modem_rt_index_hi; */ + 0x8 /* v6_apps_rt_index_lo; */ + 0xe /* v6_apps_rt_index_hi; */ + 0x588 /* v6_rt_hash_ofst; */ + 0x78 /* v6_rt_hash_size; */ + 0x4000 /* v6_rt_hash_size_ddr; */ + 0x608 /* v6_rt_nhash_ofst; */ + 0x78 /* v6_rt_nhash_size; */ + 0x4000 /* v6_rt_nhash_size_ddr; */ + 0x688 /* modem_hdr_ofst; */ + 0x140 /* modem_hdr_size; */ + 0x7c8 /* apps_hdr_ofst; */ + 0x0 /* apps_hdr_size; */ + 0x800 /* apps_hdr_size_ddr; */ + 0x7d0 /* modem_hdr_proc_ctx_ofst; */ + 0x200 /* modem_hdr_proc_ctx_size; */ + 0x9d0 /* apps_hdr_proc_ctx_ofst; */ + 0x200 /* apps_hdr_proc_ctx_size; */ + 0x0 /* apps_hdr_proc_ctx_size_ddr; */ + 0x0 /* modem_comp_decomp_ofst; diff */ + 0x0 /* modem_comp_decomp_size; diff */ + 0xbd8 /* modem_ofst; */ + 0x1024 /* modem_size; */ + 0x2000 /* apps_v4_flt_hash_ofst; */ + 0x0 /* apps_v4_flt_hash_size; */ + 0x2000 /* apps_v4_flt_nhash_ofst; */ + 0x0 /* apps_v4_flt_nhash_size; */ + 0x2000 /* apps_v6_flt_hash_ofst; */ + 0x0 /* apps_v6_flt_hash_size; */ + 0x2000 /* apps_v6_flt_nhash_ofst; */ + 0x0 /* apps_v6_flt_nhash_size; */ + 0x80 /* uc_info_ofst; */ + 0x200 /* uc_info_size; */ + 0x2000 /* end_ofst; */ + 0x2000 /* apps_v4_rt_hash_ofst; */ + 0x0 /* apps_v4_rt_hash_size; */ + 0x2000 /* apps_v4_rt_nhash_ofst; */ + 0x0 /* apps_v4_rt_nhash_size; */ + 0x2000 /* apps_v6_rt_hash_ofst; */ + 0x0 /* apps_v6_rt_hash_size; */ + 0x2000 /* apps_v6_rt_nhash_ofst; */ + 0x0 /* apps_v6_rt_nhash_size; */ + 0x1c00 /* uc_event_ring_ofst; */ + 0x400 /* uc_event_ring_size; */ + >; + + /* smp2p gpio information */ + qcom,smp2pgpio_map_ipa_1_out { + compatible = "qcom,smp2pgpio-map-ipa-1-out"; + gpios = <&smp2pgpio_ipa_1_out 0 0>; + }; + + qcom,smp2pgpio_map_ipa_1_in { + compatible = "qcom,smp2pgpio-map-ipa-1-in"; + gpios = <&smp2pgpio_ipa_1_in 0 0>; + }; + + ipa_smmu_ap: ipa_smmu_ap { + compatible = "qcom,ipa-smmu-ap-cb"; + iommus = <&apps_smmu 0x720 0x0>; + qcom,iova-mapping = <0x20000000 0x40000000>; + qcom,additional-mapping = + /* modem tables in IMEM */ + <0x146BD000 0x146BD000 0x2000>; + }; + + ipa_smmu_wlan: ipa_smmu_wlan { + compatible = "qcom,ipa-smmu-wlan-cb"; + iommus = <&apps_smmu 0x721 0x0>; + qcom,additional-mapping = + /* ipa-uc ram */ + <0x1E60000 0x1E60000 0x80000>; + }; + + ipa_smmu_uc: ipa_smmu_uc { + compatible = "qcom,ipa-smmu-uc-cb"; + iommus = <&apps_smmu 0x722 0x0>; + qcom,iova-mapping = <0x40000000 0x20000000>; + }; + }; + + 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,chd_sliver { + compatible = "qcom,core-hang-detect"; + label = "silver"; + qcom,threshold-arr = <0x17e00058 0x17e10058 + 0x17e20058 0x17e30058>; + qcom,config-arr = <0x17e00060 0x17e10060 + 0x17e20060 0x17e30060>; + }; + + qcom,chd_gold { + compatible = "qcom,core-hang-detect"; + label = "gold"; + qcom,threshold-arr = <0x17e40058 0x17e50058 + 0x17e60058 0x17e70058>; + qcom,config-arr = <0x17e40060 0x17e50060 + 0x17e60060 0x17e70060>; + }; + + qcom,ghd { + compatible = "qcom,gladiator-hang-detect-v2"; + qcom,threshold-arr = <0x1799041c 0x17990420>; + qcom,config-reg = <0x17990434>; + }; + + qcom,msm-gladiator-v3@17900000 { + compatible = "qcom,msm-gladiator-v3"; + reg = <0x17900000 0xd080>; + reg-names = "gladiator_base"; + interrupts = <0 17 0>; + }; + + cmd_db: qcom,cmd-db@861e0000 { + compatible = "qcom,cmd-db"; + reg = <0xc3f000c 8>; + }; + + dcc: dcc_v2@10a2000 { + compatible = "qcom,dcc-v2"; + reg = <0x10a2000 0x1000>, + <0x10ae000 0x2000>; + reg-names = "dcc-base", "dcc-ram-base"; + + dcc-ram-offset = <0x6000>; + + qcom,curr-link-list = <2>; + qcom,link-list = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + }; + + qcom,msm-core@780000 { + compatible = "qcom,apss-core-ea"; + reg = <0x780000 0x1000>; + }; + + qcom,icnss@18800000 { + compatible = "qcom,icnss"; + reg = <0x18800000 0x800000>, + <0xa0000000 0x10000000>, + <0xb0000000 0x10000>; + reg-names = "membase", "smmu_iova_base", "smmu_iova_ipa"; + iommus = <&apps_smmu 0x0040 0x1>; + interrupts = <0 414 0 /* CE0 */ >, + <0 415 0 /* CE1 */ >, + <0 416 0 /* CE2 */ >, + <0 417 0 /* CE3 */ >, + <0 418 0 /* CE4 */ >, + <0 419 0 /* CE5 */ >, + <0 420 0 /* CE6 */ >, + <0 421 0 /* CE7 */ >, + <0 422 0 /* CE8 */ >, + <0 423 0 /* CE9 */ >, + <0 424 0 /* CE10 */ >, + <0 425 0 /* CE11 */ >; + qcom,wlan-msa-memory = <0x100000>; + qcom,gpio-force-fatal-error = <&smp2pgpio_wlan_1_in 0 0>; + qcom,gpio-early-crash-ind = <&smp2pgpio_wlan_1_in 1 0>; + + vdd-0.8-cx-mx-supply = <&pm8998_l5>; + vdd-1.8-xo-supply = <&pm8998_l7>; + vdd-1.3-rfa-supply = <&pm8998_l17>; + vdd-3.3-ch0-supply = <&pm8998_l25>; + qcom,vdd-0.8-cx-mx-config = <800000 800000>; + qcom,vdd-3.3-ch0-config = <3104000 3312000>; + }; + + qmi-tmd-devices { + compatible = "qcom,qmi_cooling_devices"; + + modem { + qcom,instance-id = <0x0>; + + modem_pa: modem_pa { + qcom,qmi-dev-name = "pa"; + #cooling-cells = <2>; + }; + + modem_proc: modem_proc { + qcom,qmi-dev-name = "modem"; + #cooling-cells = <2>; + }; + + modem_current: modem_current { + qcom,qmi-dev-name = "modem_current"; + #cooling-cells = <2>; + }; + + modem_skin: modem_skin { + qcom,qmi-dev-name = "modem_skin"; + #cooling-cells = <2>; + }; + + modem_vdd: modem_vdd { + qcom,qmi-dev-name = "cpuv_restriction_cold"; + #cooling-cells = <2>; + }; + }; + + adsp { + qcom,instance-id = <0x1>; + + adsp_vdd: adsp_vdd { + qcom,qmi-dev-name = "cpuv_restriction_cold"; + #cooling-cells = <2>; + }; + }; + + cdsp { + qcom,instance-id = <0x43>; + + cdsp_vdd: cdsp_vdd { + qcom,qmi-dev-name = "cpuv_restriction_cold"; + #cooling-cells = <2>; + }; + }; + + slpi { + qcom,instance-id = <0x53>; + + slpi_vdd: slpi_vdd { + qcom,qmi-dev-name = "cpuv_restriction_cold"; + #cooling-cells = <2>; + }; + }; + }; + + thermal_zones: 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"; + }; + }; + }; + + cpu0-silver-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"; + }; + + thermal-hal-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu1-silver-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"; + }; + + thermal-hal-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu2-silver-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"; + }; + + thermal-hal-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu3-silver-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 4>; + wake-capable-sensor; + thermal-governor = "user_space"; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + thermal-hal-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + kryo-l3-0-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 5>; + wake-capable-sensor; + thermal-governor = "user_space"; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + kryo-l3-1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 6>; + wake-capable-sensor; + thermal-governor = "user_space"; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + cpu0-gold-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 7>; + wake-capable-sensor; + thermal-governor = "user_space"; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + thermal-hal-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu1-gold-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 8>; + wake-capable-sensor; + thermal-governor = "user_space"; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + thermal-hal-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu2-gold-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 9>; + wake-capable-sensor; + thermal-governor = "user_space"; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + thermal-hal-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + cpu3-gold-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 10>; + wake-capable-sensor; + thermal-governor = "user_space"; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + thermal-hal-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + gpu0-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens0 11>; + wake-capable-sensor; + thermal-governor = "user_space"; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + + thermal-hal-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + gpu1-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"; + }; + + thermal-hal-cfg { + temperature = <115000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + }; + + aoss1-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 0>; + wake-capable-sensor; + thermal-governor = "user_space"; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + mdm-dsp-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 1>; + wake-capable-sensor; + thermal-governor = "user_space"; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + + + ddr-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 2>; + wake-capable-sensor; + thermal-governor = "user_space"; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + wlan-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 3>; + wake-capable-sensor; + thermal-governor = "user_space"; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + compute-hvx-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 4>; + wake-capable-sensor; + thermal-governor = "user_space"; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + camera-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 5>; + wake-capable-sensor; + thermal-governor = "user_space"; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + mmss-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 6>; + wake-capable-sensor; + thermal-governor = "user_space"; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + mdm-core-usr { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&tsens1 7>; + wake-capable-sensor; + thermal-governor = "user_space"; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + gpu-virt-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_cdev0 { + trip = <&gpu_trip0>; + cooling-device = + <&msm_gpu 0 THERMAL_NO_LIMIT>; + }; + }; + }; + + silv-virt-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"; + }; + }; + }; + + gold-virt-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 2>; + wake-capable-sensor; + thermal-governor = "step_wise"; + 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_MAX_LIMIT-1)>; + }; + pop_cdev5 { + trip = <&pop_trip>; + cooling-device = + <&CPU5 THERMAL_NO_LIMIT + (THERMAL_MAX_LIMIT-1)>; + }; + pop_cdev6 { + trip = <&pop_trip>; + cooling-device = + <&CPU6 THERMAL_NO_LIMIT + (THERMAL_MAX_LIMIT-1)>; + }; + pop_cdev7 { + trip = <&pop_trip>; + cooling-device = + <&CPU7 THERMAL_NO_LIMIT + (THERMAL_MAX_LIMIT-1)>; + }; + }; + }; + + cpu0-silver-step { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-sensors = <&tsens0 1>; + wake-capable-sensor; + thermal-governor = "step_wise"; + trips { + emerg_config0: emerg-config0 { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + cooling-maps { + emerg_cdev0 { + trip = <&emerg_config0>; + cooling-device = + <&CPU0 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + cpu1-silver-step { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-sensors = <&tsens0 2>; + wake-capable-sensor; + thermal-governor = "step_wise"; + trips { + emerg_config1: emerg-config1 { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + cooling-maps { + emerg_cdev1 { + trip = <&emerg_config1>; + cooling-device = + <&CPU1 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + cpu2-silver-step { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-sensors = <&tsens0 3>; + wake-capable-sensor; + thermal-governor = "step_wise"; + trips { + emerg_config2: emerg-config2 { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + cooling-maps { + emerg_cdev2 { + trip = <&emerg_config2>; + cooling-device = + <&CPU2 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + cpu3-silver-step { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-sensors = <&tsens0 4>; + wake-capable-sensor; + thermal-governor = "step_wise"; + trips { + emerg_config3: emerg-config3 { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + cooling-maps { + emerg_cdev3 { + trip = <&emerg_config3>; + cooling-device = + <&CPU3 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + cpu0-gold-step { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-sensors = <&tsens0 7>; + wake-capable-sensor; + thermal-governor = "step_wise"; + trips { + emerg_config4: emerg-config4 { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + cooling-maps { + emerg_cdev4 { + trip = <&emerg_config4>; + cooling-device = + <&CPU4 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + cpu1-gold-step { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-sensors = <&tsens0 8>; + wake-capable-sensor; + thermal-governor = "step_wise"; + trips { + emerg_config5: emerg-config5 { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + cooling-maps { + emerg_cdev5 { + trip = <&emerg_config5>; + cooling-device = + <&CPU5 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + cpu2-gold-step { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-sensors = <&tsens0 9>; + wake-capable-sensor; + thermal-governor = "step_wise"; + trips { + emerg_config6: emerg-config6 { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + cooling-maps { + emerg_cdev6 { + trip = <&emerg_config6>; + cooling-device = + <&CPU6 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + cpu3-gold-step { + polling-delay-passive = <100>; + polling-delay = <0>; + thermal-sensors = <&tsens0 10>; + wake-capable-sensor; + thermal-governor = "step_wise"; + trips { + emerg_config7: emerg-config7 { + temperature = <110000>; + hysteresis = <10000>; + type = "passive"; + }; + }; + cooling-maps { + emerg_cdev7 { + trip = <&emerg_config7>; + cooling-device = + <&CPU7 THERMAL_MAX_LIMIT + THERMAL_MAX_LIMIT>; + }; + }; + }; + + lmh-dcvs-01 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&lmh_dcvs1>; + wake-capable-sensor; + + trips { + active-config { + temperature = <95000>; + hysteresis = <30000>; + type = "passive"; + }; + }; + }; + + lmh-dcvs-00 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&lmh_dcvs0>; + wake-capable-sensor; + + trips { + active-config { + temperature = <95000>; + hysteresis = <30000>; + type = "passive"; + }; + }; + }; + + }; + + tsens0: tsens@c222000 { + compatible = "qcom,sdm845-tsens"; + reg = <0xc222000 0x4>, + <0xc263000 0x1ff>; + reg-names = "tsens_srot_physical", + "tsens_tm_physical"; + interrupts = <0 506 0>, <0 508 0>; + interrupt-names = "tsens-upper-lower", "tsens-critical"; + #thermal-sensor-cells = <1>; + }; + + tsens1: tsens@c223000 { + compatible = "qcom,sdm845-tsens"; + reg = <0xc223000 0x4>, + <0xc265000 0x1ff>; + reg-names = "tsens_srot_physical", + "tsens_tm_physical"; + interrupts = <0 507 0>, <0 509 0>; + interrupt-names = "tsens-upper-lower", "tsens-critical"; + #thermal-sensor-cells = <1>; + }; + + mem_dump { + compatible = "qcom,mem-dump"; + memory-region = <&dump_mem>; + + rpmh { + qcom,dump-size = <0x2000000>; + qcom,dump-id = <0xec>; + }; + + fcm { + qcom,dump-size = <0x8400>; + qcom,dump-id = <0xee>; + }; + + rpm_sw { + qcom,dump-size = <0x28000>; + qcom,dump-id = <0xea>; + }; + + pmic { + qcom,dump-size = <0x10000>; + qcom,dump-id = <0xe4>; + }; + + tmc_etf { + qcom,dump-size = <0x10000>; + qcom,dump-id = <0xf0>; + }; + + tmc_etfswao { + qcom,dump-size = <0x8400>; + qcom,dump-id = <0xf1>; + }; + + tmc_etr_reg { + qcom,dump-size = <0x1000>; + qcom,dump-id = <0x100>; + }; + + tmc_etf_reg { + qcom,dump-size = <0x1000>; + qcom,dump-id = <0x101>; + }; + + etfswao_reg { + qcom,dump-size = <0x1000>; + qcom,dump-id = <0x102>; + }; + + misc_data { + qcom,dump-size = <0x1000>; + qcom,dump-id = <0xe8>; + }; + + tpdm_swao { + qcom,dump-size = <0x512>; + qcom,dump-id = <0xf2>; + }; + }; + + gpi_dma0: qcom,gpi-dma@0x800000 { + #dma-cells = <5>; + compatible = "qcom,gpi-dma"; + reg = <0x800000 0x60000>; + reg-names = "gpi-top"; + interrupts = <0 244 0>, <0 245 0>, <0 246 0>, <0 247 0>, + <0 248 0>, <0 249 0>, <0 250 0>, <0 251 0>, + <0 252 0>, <0 253 0>, <0 254 0>, <0 255 0>, + <0 256 0>; + qcom,max-num-gpii = <13>; + qcom,gpii-mask = <0xfa>; + qcom,ev-factor = <2>; + iommus = <&apps_smmu 0x0016 0x0>; + qcom,smmu-cfg = <0x1>; + qcom,iova-range = <0x0 0x100000 0x0 0x100000>; + status = "ok"; + }; + + gpi_dma1: qcom,gpi-dma@0xa00000 { + #dma-cells = <5>; + compatible = "qcom,gpi-dma"; + reg = <0xa00000 0x60000>; + reg-names = "gpi-top"; + interrupts = <0 279 0>, <0 280 0>, <0 281 0>, <0 282 0>, + <0 283 0>, <0 284 0>, <0 293 0>, <0 294 0>, + <0 295 0>, <0 296 0>, <0 297 0>, <0 298 0>, + <0 299 0>; + qcom,max-num-gpii = <13>; + qcom,gpii-mask = <0xfa>; + qcom,ev-factor = <2>; + iommus = <&apps_smmu 0x06d6 0x0>; + qcom,smmu-cfg = <0x1>; + qcom,iova-range = <0x0 0x100000 0x0 0x100000>; + status = "ok"; + }; + + tspp: msm_tspp@0x8880000 { + compatible = "qcom,msm_tspp"; + reg = <0x088a7000 0x200>, /* MSM_TSIF0_PHYS */ + <0x088a8000 0x200>, /* MSM_TSIF1_PHYS */ + <0x088a9000 0x1000>, /* MSM_TSPP_PHYS */ + <0x08884000 0x23000>; /* MSM_TSPP_BAM_PHYS */ + reg-names = "MSM_TSIF0_PHYS", + "MSM_TSIF1_PHYS", + "MSM_TSPP_PHYS", + "MSM_TSPP_BAM_PHYS"; + interrupts = <0 121 0>, /* TSIF_TSPP_IRQ */ + <0 119 0>, /* TSIF0_IRQ */ + <0 120 0>, /* TSIF1_IRQ */ + <0 122 0>; /* TSIF_BAM_IRQ */ + interrupt-names = "TSIF_TSPP_IRQ", + "TSIF0_IRQ", + "TSIF1_IRQ", + "TSIF_BAM_IRQ"; + + clock-names = "iface_clk", "ref_clk"; + clocks = <&clock_gcc GCC_TSIF_AHB_CLK>, + <&clock_gcc GCC_TSIF_REF_CLK>; + + qcom,msm-bus,name = "tsif"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <82 512 0 0>, /* No vote */ + <82 512 12288 24576>; + /* Max. bandwidth, 2xTSIF, each max of 96Mbps */ + + pinctrl-names = "disabled", + "tsif0-mode1", "tsif0-mode2", + "tsif1-mode1", "tsif1-mode2", + "dual-tsif-mode1", "dual-tsif-mode2"; + + pinctrl-0 = <>; /* disabled */ + pinctrl-1 = <&tsif0_signals_active>; /* tsif0-mode1 */ + pinctrl-2 = <&tsif0_signals_active + &tsif0_sync_active>; /* tsif0-mode2 */ + pinctrl-3 = <&tsif1_signals_active>; /* tsif1-mode1 */ + pinctrl-4 = <&tsif1_signals_active + &tsif1_sync_active>; /* tsif1-mode2 */ + pinctrl-5 = <&tsif0_signals_active + &tsif1_signals_active>; /* dual-tsif-mode1 */ + pinctrl-6 = <&tsif0_signals_active + &tsif0_sync_active + &tsif1_signals_active + &tsif1_sync_active>; /* dual-tsif-mode2 */ + + qcom,smmu-s1-bypass; + iommus = <&apps_smmu 0x20 0x0f>; + }; +}; + +&clock_cpucc { + lmh_dcvs0: qcom,limits-dcvs@0 { + compatible = "qcom,msm-hw-limits"; + interrupts = ; + qcom,affinity = <0>; + #thermal-sensor-cells = <0>; + }; + + lmh_dcvs1: qcom,limits-dcvs@1 { + compatible = "qcom,msm-hw-limits"; + interrupts = ; + qcom,affinity = <1>; + #thermal-sensor-cells = <0>; + isens_vref-supply = <&pm8998_l1_ao>; + isens-vref-settings = <880000 880000 20000>; + }; + + wil6210: qcom,wil6210 { + compatible = "qcom,wil6210"; + qcom,pcie-parent = <&pcie0>; + qcom,wigig-en = <&tlmm 39 0>; + qcom,msm-bus,name = "wil6210"; + qcom,msm-bus,num-cases = <2>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <45 512 0 0>, + <45 512 600000 800000>; /* ~4.6Gbps (MCS12) */ + qcom,use-ext-supply; + vdd-supply= <&pm8998_s7>; + vddio-supply= <&pm8998_s5>; + qcom,use-ext-clocks; + clocks = <&clock_rpmh RPMH_RF_CLK3>, + <&clock_rpmh RPMH_RF_CLK3_A>; + clock-names = "rf_clk3_clk", "rf_clk3_pin_clk"; + qcom,smmu-support; + qcom,smmu-mapping = <0x20000000 0xe0000000>; + qcom,smmu-s1-en; + qcom,smmu-fast-map; + qcom,smmu-coherent; + qcom,keep-radio-on-during-sleep; + status = "disabled"; + }; +}; + +&pcie_0_gdsc { + status = "ok"; +}; + +&pcie_1_gdsc { + status = "ok"; +}; + +&ufs_card_gdsc { + status = "ok"; +}; + +&ufs_phy_gdsc { + status = "ok"; +}; + +&usb30_prim_gdsc { + status = "ok"; +}; + +&usb30_sec_gdsc { + status = "ok"; +}; + +&hlos1_vote_aggre_noc_mmu_audio_tbu_gdsc { + status = "ok"; +}; + +&hlos1_vote_aggre_noc_mmu_pcie_tbu_gdsc { + status = "ok"; +}; + +&hlos1_vote_aggre_noc_mmu_tbu1_gdsc { + status = "ok"; +}; + +&hlos1_vote_aggre_noc_mmu_tbu2_gdsc { + status = "ok"; +}; + +&hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc { + status = "ok"; +}; + +&hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc { + status = "ok"; +}; + +&hlos1_vote_mmnoc_mmu_tbu_sf_gdsc { + status = "ok"; +}; + +&bps_gdsc { + qcom,support-hw-trigger; + status = "ok"; +}; + +&ife_0_gdsc { + status = "ok"; +}; + +&ife_1_gdsc { + status = "ok"; +}; + +&ipe_0_gdsc { + qcom,support-hw-trigger; + status = "ok"; +}; + +&ipe_1_gdsc { + qcom,support-hw-trigger; + status = "ok"; +}; + +&titan_top_gdsc { + status = "ok"; +}; + +&mdss_core_gdsc { + status = "ok"; + qcom,en-few-wait-val = <6>; + qcom,en-rest-wait-val = <5>; +}; + +&gpu_cx_gdsc { + parent-supply = <&pm8998_s9_level>; + vdd_parent-supply = <&pm8998_s9_level>; + status = "ok"; +}; + +&gpu_gx_gdsc { + clock-names = "core_root_clk"; + clocks = <&clock_gfx GPU_CC_GX_GFX3D_CLK_SRC>; + qcom,force-enable-root-clk; + parent-supply = <&pm8005_s1_level>; + status = "ok"; +}; + +&vcodec0_gdsc { + qcom,support-hw-trigger; + status = "ok"; +}; + +&vcodec1_gdsc { + qcom,support-hw-trigger; + status = "ok"; +}; + +&venus_gdsc { + status = "ok"; +}; + +#include "pm8998.dtsi" +#include "pm8005.dtsi" +#include "sdm845-regulator.dtsi" +#include "sdm845-coresight.dtsi" +#include "msm-arm-smmu-sdm845.dtsi" +#include "sdm845-ion.dtsi" +#include "sdm845-smp2p.dtsi" +#include "sdm845-camera.dtsi" +#include "sdm845-bus.dtsi" +#include "sdm845-vidc.dtsi" +#include "sdm845-pm.dtsi" +#include "sdm845-pinctrl.dtsi" +#include "sdm845-pcie.dtsi" +#include "sdm845-audio.dtsi" +#include "sdm845-gpu.dtsi" +#include "sdm845-670-usb-common.dtsi" + +&pm8998_temp_alarm { + cooling-maps { + trip0_cpu0 { + trip = <&pm8998_trip0>; + cooling-device = + <&CPU0 (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + trip0_cpu1 { + trip = <&pm8998_trip0>; + cooling-device = + <&CPU1 (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + trip0_cpu2 { + trip = <&pm8998_trip0>; + cooling-device = + <&CPU2 (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + trip0_cpu3 { + trip = <&pm8998_trip0>; + cooling-device = + <&CPU3 (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + trip0_cpu4 { + trip = <&pm8998_trip0>; + cooling-device = + <&CPU4 (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + trip0_cpu5 { + trip = <&pm8998_trip0>; + cooling-device = + <&CPU5 (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + trip0_cpu6 { + trip = <&pm8998_trip0>; + cooling-device = + <&CPU6 (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + trip0_cpu7 { + trip = <&pm8998_trip0>; + cooling-device = + <&CPU7 (THERMAL_MAX_LIMIT-1) + (THERMAL_MAX_LIMIT-1)>; + }; + trip1_cpu1 { + trip = <&pm8998_trip1>; + cooling-device = + <&CPU1 THERMAL_MAX_LIMIT THERMAL_MAX_LIMIT>; + }; + trip1_cpu2 { + trip = <&pm8998_trip1>; + cooling-device = + <&CPU2 THERMAL_MAX_LIMIT THERMAL_MAX_LIMIT>; + }; + trip1_cpu3 { + trip = <&pm8998_trip1>; + cooling-device = + <&CPU3 THERMAL_MAX_LIMIT THERMAL_MAX_LIMIT>; + }; + trip1_cpu4 { + trip = <&pm8998_trip1>; + cooling-device = + <&CPU4 THERMAL_MAX_LIMIT THERMAL_MAX_LIMIT>; + }; + trip1_cpu5 { + trip = <&pm8998_trip1>; + cooling-device = + <&CPU5 THERMAL_MAX_LIMIT THERMAL_MAX_LIMIT>; + }; + trip1_cpu6 { + trip = <&pm8998_trip1>; + cooling-device = + <&CPU6 THERMAL_MAX_LIMIT THERMAL_MAX_LIMIT>; + }; + trip1_cpu7 { + trip = <&pm8998_trip1>; + cooling-device = + <&CPU7 THERMAL_MAX_LIMIT THERMAL_MAX_LIMIT>; + }; + }; +}; + +&thermal_zones { + aoss0-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 0>; + wake-capable-sensor; + tracks-low; + trips { + aoss0_trip: aoss0-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&aoss0_trip>; + cooling-device = <&CPU0 4 4>; + }; + cpu4_vdd_cdev { + trip = <&aoss0_trip>; + cooling-device = <&CPU4 9 9>; + }; + gpu_vdd_cdev { + trip = <&aoss0_trip>; + cooling-device = <&msm_gpu 1 1>; + }; + cx_vdd_cdev { + trip = <&aoss0_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + mx_vdd_cdev { + trip = <&aoss0_trip>; + cooling-device = <&mx_cdev 0 0>; + }; + ebi_vdd_cdev { + trip = <&aoss0_trip>; + cooling-device = <&ebi_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&aoss0_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + adsp_vdd_cdev { + trip = <&aoss0_trip>; + cooling-device = <&adsp_vdd 0 0>; + }; + cdsp_vdd_cdev { + trip = <&aoss0_trip>; + cooling-device = <&cdsp_vdd 0 0>; + }; + slpi_vdd_cdev { + trip = <&aoss0_trip>; + cooling-device = <&slpi_vdd 0 0>; + }; + }; + }; + + cpu0-silver-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 1>; + wake-capable-sensor; + tracks-low; + trips { + cpu0_trip: cpu0-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&cpu0_trip>; + cooling-device = <&CPU0 4 4>; + }; + cpu4_vdd_cdev { + trip = <&cpu0_trip>; + cooling-device = <&CPU4 9 9>; + }; + gpu_vdd_cdev { + trip = <&cpu0_trip>; + cooling-device = <&msm_gpu 1 1>; + }; + cx_vdd_cdev { + trip = <&cpu0_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + mx_vdd_cdev { + trip = <&cpu0_trip>; + cooling-device = <&mx_cdev 0 0>; + }; + ebi_vdd_cdev { + trip = <&cpu0_trip>; + cooling-device = <&ebi_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&cpu0_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + adsp_vdd_cdev { + trip = <&cpu0_trip>; + cooling-device = <&adsp_vdd 0 0>; + }; + cdsp_vdd_cdev { + trip = <&cpu0_trip>; + cooling-device = <&cdsp_vdd 0 0>; + }; + slpi_vdd_cdev { + trip = <&cpu0_trip>; + cooling-device = <&slpi_vdd 0 0>; + }; + }; + }; + + cpu1-silver-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 2>; + wake-capable-sensor; + tracks-low; + trips { + cpu1_trip: cpu1-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&cpu1_trip>; + cooling-device = <&CPU0 4 4>; + }; + cpu4_vdd_cdev { + trip = <&cpu1_trip>; + cooling-device = <&CPU4 9 9>; + }; + gpu_vdd_cdev { + trip = <&cpu1_trip>; + cooling-device = <&msm_gpu 1 1>; + }; + cx_vdd_cdev { + trip = <&cpu1_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + mx_vdd_cdev { + trip = <&cpu1_trip>; + cooling-device = <&mx_cdev 0 0>; + }; + ebi_vdd_cdev { + trip = <&cpu1_trip>; + cooling-device = <&ebi_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&cpu1_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + adsp_vdd_cdev { + trip = <&cpu1_trip>; + cooling-device = <&adsp_vdd 0 0>; + }; + cdsp_vdd_cdev { + trip = <&cpu1_trip>; + cooling-device = <&cdsp_vdd 0 0>; + }; + slpi_vdd_cdev { + trip = <&cpu1_trip>; + cooling-device = <&slpi_vdd 0 0>; + }; + }; + }; + + cpu2-silver-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 3>; + wake-capable-sensor; + tracks-low; + trips { + cpu2_trip: cpu2-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&cpu2_trip>; + cooling-device = <&CPU0 4 4>; + }; + cpu4_vdd_cdev { + trip = <&cpu2_trip>; + cooling-device = <&CPU4 9 9>; + }; + gpu_vdd_cdev { + trip = <&cpu2_trip>; + cooling-device = <&msm_gpu 1 1>; + }; + cx_vdd_cdev { + trip = <&cpu2_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + mx_vdd_cdev { + trip = <&cpu2_trip>; + cooling-device = <&mx_cdev 0 0>; + }; + ebi_vdd_cdev { + trip = <&cpu2_trip>; + cooling-device = <&ebi_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&cpu2_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + adsp_vdd_cdev { + trip = <&cpu2_trip>; + cooling-device = <&adsp_vdd 0 0>; + }; + cdsp_vdd_cdev { + trip = <&cpu2_trip>; + cooling-device = <&cdsp_vdd 0 0>; + }; + slpi_vdd_cdev { + trip = <&cpu2_trip>; + cooling-device = <&slpi_vdd 0 0>; + }; + }; + }; + + cpu3-silver-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 4>; + wake-capable-sensor; + tracks-low; + trips { + cpu3_trip: cpu3-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&cpu3_trip>; + cooling-device = <&CPU0 4 4>; + }; + cpu4_vdd_cdev { + trip = <&cpu3_trip>; + cooling-device = <&CPU4 9 9>; + }; + gpu_vdd_cdev { + trip = <&cpu3_trip>; + cooling-device = <&msm_gpu 1 1>; + }; + cx_vdd_cdev { + trip = <&cpu3_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + mx_vdd_cdev { + trip = <&cpu3_trip>; + cooling-device = <&mx_cdev 0 0>; + }; + ebi_vdd_cdev { + trip = <&cpu3_trip>; + cooling-device = <&ebi_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&cpu3_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + adsp_vdd_cdev { + trip = <&cpu3_trip>; + cooling-device = <&adsp_vdd 0 0>; + }; + cdsp_vdd_cdev { + trip = <&cpu3_trip>; + cooling-device = <&cdsp_vdd 0 0>; + }; + slpi_vdd_cdev { + trip = <&cpu3_trip>; + cooling-device = <&slpi_vdd 0 0>; + }; + }; + }; + + kryo-l3-0-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 5>; + wake-capable-sensor; + tracks-low; + trips { + l3_0_trip: l3-0-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&l3_0_trip>; + cooling-device = <&CPU0 4 4>; + }; + cpu4_vdd_cdev { + trip = <&l3_0_trip>; + cooling-device = <&CPU4 9 9>; + }; + gpu_vdd_cdev { + trip = <&l3_0_trip>; + cooling-device = <&msm_gpu 1 1>; + }; + cx_vdd_cdev { + trip = <&l3_0_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + mx_vdd_cdev { + trip = <&l3_0_trip>; + cooling-device = <&mx_cdev 0 0>; + }; + ebi_vdd_cdev { + trip = <&l3_0_trip>; + cooling-device = <&ebi_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&l3_0_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + adsp_vdd_cdev { + trip = <&l3_0_trip>; + cooling-device = <&adsp_vdd 0 0>; + }; + cdsp_vdd_cdev { + trip = <&l3_0_trip>; + cooling-device = <&cdsp_vdd 0 0>; + }; + slpi_vdd_cdev { + trip = <&l3_0_trip>; + cooling-device = <&slpi_vdd 0 0>; + }; + }; + }; + + kryo-l3-1-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 6>; + wake-capable-sensor; + tracks-low; + trips { + l3_1_trip: l3-1-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&l3_1_trip>; + cooling-device = <&CPU0 4 4>; + }; + cpu4_vdd_cdev { + trip = <&l3_1_trip>; + cooling-device = <&CPU4 9 9>; + }; + gpu_vdd_cdev { + trip = <&l3_1_trip>; + cooling-device = <&msm_gpu 1 1>; + }; + cx_vdd_cdev { + trip = <&l3_1_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + mx_vdd_cdev { + trip = <&l3_1_trip>; + cooling-device = <&mx_cdev 0 0>; + }; + ebi_vdd_cdev { + trip = <&l3_1_trip>; + cooling-device = <&ebi_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&l3_1_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + adsp_vdd_cdev { + trip = <&l3_1_trip>; + cooling-device = <&adsp_vdd 0 0>; + }; + cdsp_vdd_cdev { + trip = <&l3_1_trip>; + cooling-device = <&cdsp_vdd 0 0>; + }; + slpi_vdd_cdev { + trip = <&l3_1_trip>; + cooling-device = <&slpi_vdd 0 0>; + }; + }; + }; + + cpu0-gold-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 7>; + wake-capable-sensor; + tracks-low; + trips { + cpug0_trip: cpug0-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&cpug0_trip>; + cooling-device = <&CPU0 4 4>; + }; + cpu4_vdd_cdev { + trip = <&cpug0_trip>; + cooling-device = <&CPU4 9 9>; + }; + gpu_vdd_cdev { + trip = <&cpug0_trip>; + cooling-device = <&msm_gpu 1 1>; + }; + cx_vdd_cdev { + trip = <&cpug0_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + mx_vdd_cdev { + trip = <&cpug0_trip>; + cooling-device = <&mx_cdev 0 0>; + }; + ebi_vdd_cdev { + trip = <&cpug0_trip>; + cooling-device = <&ebi_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&cpug0_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + adsp_vdd_cdev { + trip = <&cpug0_trip>; + cooling-device = <&adsp_vdd 0 0>; + }; + cdsp_vdd_cdev { + trip = <&cpug0_trip>; + cooling-device = <&cdsp_vdd 0 0>; + }; + slpi_vdd_cdev { + trip = <&cpug0_trip>; + cooling-device = <&slpi_vdd 0 0>; + }; + }; + }; + + cpu1-gold-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 8>; + wake-capable-sensor; + tracks-low; + trips { + cpug1_trip: cpug1-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&cpug1_trip>; + cooling-device = <&CPU0 4 4>; + }; + cpu4_vdd_cdev { + trip = <&cpug1_trip>; + cooling-device = <&CPU4 9 9>; + }; + gpu_vdd_cdev { + trip = <&cpug1_trip>; + cooling-device = <&msm_gpu 1 1>; + }; + cx_vdd_cdev { + trip = <&cpug1_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + mx_vdd_cdev { + trip = <&cpug1_trip>; + cooling-device = <&mx_cdev 0 0>; + }; + ebi_vdd_cdev { + trip = <&cpug1_trip>; + cooling-device = <&ebi_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&cpug1_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + adsp_vdd_cdev { + trip = <&cpug1_trip>; + cooling-device = <&adsp_vdd 0 0>; + }; + cdsp_vdd_cdev { + trip = <&cpug1_trip>; + cooling-device = <&cdsp_vdd 0 0>; + }; + slpi_vdd_cdev { + trip = <&cpug1_trip>; + cooling-device = <&slpi_vdd 0 0>; + }; + }; + }; + + cpu2-gold-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 9>; + wake-capable-sensor; + tracks-low; + trips { + cpug2_trip: cpug2-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&cpug2_trip>; + cooling-device = <&CPU0 4 4>; + }; + cpu4_vdd_cdev { + trip = <&cpug2_trip>; + cooling-device = <&CPU4 9 9>; + }; + gpu_vdd_cdev { + trip = <&cpug2_trip>; + cooling-device = <&msm_gpu 1 1>; + }; + cx_vdd_cdev { + trip = <&cpug2_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + mx_vdd_cdev { + trip = <&cpug2_trip>; + cooling-device = <&mx_cdev 0 0>; + }; + ebi_vdd_cdev { + trip = <&cpug2_trip>; + cooling-device = <&ebi_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&cpug2_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + adsp_vdd_cdev { + trip = <&cpug2_trip>; + cooling-device = <&adsp_vdd 0 0>; + }; + cdsp_vdd_cdev { + trip = <&cpug2_trip>; + cooling-device = <&cdsp_vdd 0 0>; + }; + slpi_vdd_cdev { + trip = <&cpug2_trip>; + cooling-device = <&slpi_vdd 0 0>; + }; + }; + }; + + cpu3-gold-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 10>; + wake-capable-sensor; + tracks-low; + trips { + cpug3_trip: cpug3-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&cpug3_trip>; + cooling-device = <&CPU0 4 4>; + }; + cpu4_vdd_cdev { + trip = <&cpug3_trip>; + cooling-device = <&CPU4 9 9>; + }; + gpu_vdd_cdev { + trip = <&cpug3_trip>; + cooling-device = <&msm_gpu 1 1>; + }; + cx_vdd_cdev { + trip = <&cpug3_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + mx_vdd_cdev { + trip = <&cpug3_trip>; + cooling-device = <&mx_cdev 0 0>; + }; + ebi_vdd_cdev { + trip = <&cpug3_trip>; + cooling-device = <&ebi_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&cpug3_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + adsp_vdd_cdev { + trip = <&cpug3_trip>; + cooling-device = <&adsp_vdd 0 0>; + }; + cdsp_vdd_cdev { + trip = <&cpug3_trip>; + cooling-device = <&cdsp_vdd 0 0>; + }; + slpi_vdd_cdev { + trip = <&cpug3_trip>; + cooling-device = <&slpi_vdd 0 0>; + }; + }; + }; + + gpu0-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 11>; + wake-capable-sensor; + tracks-low; + trips { + gpu0_trip_l: gpu0-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&gpu0_trip_l>; + cooling-device = <&CPU0 4 4>; + }; + cpu4_vdd_cdev { + trip = <&gpu0_trip_l>; + cooling-device = <&CPU4 9 9>; + }; + gpu_vdd_cdev { + trip = <&gpu0_trip_l>; + cooling-device = <&msm_gpu 1 1>; + }; + cx_vdd_cdev { + trip = <&gpu0_trip_l>; + cooling-device = <&cx_cdev 0 0>; + }; + mx_vdd_cdev { + trip = <&gpu0_trip_l>; + cooling-device = <&mx_cdev 0 0>; + }; + ebi_vdd_cdev { + trip = <&gpu0_trip_l>; + cooling-device = <&ebi_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&gpu0_trip_l>; + cooling-device = <&modem_vdd 0 0>; + }; + adsp_vdd_cdev { + trip = <&gpu0_trip_l>; + cooling-device = <&adsp_vdd 0 0>; + }; + cdsp_vdd_cdev { + trip = <&gpu0_trip_l>; + cooling-device = <&cdsp_vdd 0 0>; + }; + slpi_vdd_cdev { + trip = <&gpu0_trip_l>; + cooling-device = <&slpi_vdd 0 0>; + }; + }; + }; + + gpu1-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens0 12>; + wake-capable-sensor; + tracks-low; + trips { + gpu1_trip_l: gpu1-trip_l { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&gpu1_trip_l>; + cooling-device = <&CPU0 4 4>; + }; + cpu4_vdd_cdev { + trip = <&gpu1_trip_l>; + cooling-device = <&CPU4 9 9>; + }; + gpu_vdd_cdev { + trip = <&gpu1_trip_l>; + cooling-device = <&msm_gpu 1 1>; + }; + cx_vdd_cdev { + trip = <&gpu1_trip_l>; + cooling-device = <&cx_cdev 0 0>; + }; + mx_vdd_cdev { + trip = <&gpu1_trip_l>; + cooling-device = <&mx_cdev 0 0>; + }; + ebi_vdd_cdev { + trip = <&gpu1_trip_l>; + cooling-device = <&ebi_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&gpu1_trip_l>; + cooling-device = <&modem_vdd 0 0>; + }; + adsp_vdd_cdev { + trip = <&gpu1_trip_l>; + cooling-device = <&adsp_vdd 0 0>; + }; + cdsp_vdd_cdev { + trip = <&gpu1_trip_l>; + cooling-device = <&cdsp_vdd 0 0>; + }; + slpi_vdd_cdev { + trip = <&gpu1_trip_l>; + cooling-device = <&slpi_vdd 0 0>; + }; + }; + }; + + aoss1-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens1 0>; + wake-capable-sensor; + tracks-low; + trips { + aoss1_trip: aoss1-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&aoss1_trip>; + cooling-device = <&CPU0 4 4>; + }; + cpu4_vdd_cdev { + trip = <&aoss1_trip>; + cooling-device = <&CPU4 9 9>; + }; + gpu_vdd_cdev { + trip = <&aoss1_trip>; + cooling-device = <&msm_gpu 1 1>; + }; + cx_vdd_cdev { + trip = <&aoss1_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + mx_vdd_cdev { + trip = <&aoss1_trip>; + cooling-device = <&mx_cdev 0 0>; + }; + ebi_vdd_cdev { + trip = <&aoss1_trip>; + cooling-device = <&ebi_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&aoss1_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + adsp_vdd_cdev { + trip = <&aoss1_trip>; + cooling-device = <&adsp_vdd 0 0>; + }; + cdsp_vdd_cdev { + trip = <&aoss1_trip>; + cooling-device = <&cdsp_vdd 0 0>; + }; + slpi_vdd_cdev { + trip = <&aoss1_trip>; + cooling-device = <&slpi_vdd 0 0>; + }; + }; + }; + + mdm-dsp-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens1 1>; + wake-capable-sensor; + tracks-low; + trips { + dsp_trip: dsp-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&dsp_trip>; + cooling-device = <&CPU0 4 4>; + }; + cpu4_vdd_cdev { + trip = <&dsp_trip>; + cooling-device = <&CPU4 9 9>; + }; + gpu_vdd_cdev { + trip = <&dsp_trip>; + cooling-device = <&msm_gpu 1 1>; + }; + cx_vdd_cdev { + trip = <&dsp_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + mx_vdd_cdev { + trip = <&dsp_trip>; + cooling-device = <&mx_cdev 0 0>; + }; + ebi_vdd_cdev { + trip = <&dsp_trip>; + cooling-device = <&ebi_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&dsp_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + adsp_vdd_cdev { + trip = <&dsp_trip>; + cooling-device = <&adsp_vdd 0 0>; + }; + cdsp_vdd_cdev { + trip = <&dsp_trip>; + cooling-device = <&cdsp_vdd 0 0>; + }; + slpi_vdd_cdev { + trip = <&dsp_trip>; + cooling-device = <&slpi_vdd 0 0>; + }; + }; + }; + + ddr-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens1 2>; + wake-capable-sensor; + tracks-low; + trips { + ddr_trip: ddr-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&ddr_trip>; + cooling-device = <&CPU0 4 4>; + }; + cpu4_vdd_cdev { + trip = <&ddr_trip>; + cooling-device = <&CPU4 9 9>; + }; + gpu_vdd_cdev { + trip = <&ddr_trip>; + cooling-device = <&msm_gpu 1 1>; + }; + cx_vdd_cdev { + trip = <&ddr_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + mx_vdd_cdev { + trip = <&ddr_trip>; + cooling-device = <&mx_cdev 0 0>; + }; + ebi_vdd_cdev { + trip = <&ddr_trip>; + cooling-device = <&ebi_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&ddr_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + adsp_vdd_cdev { + trip = <&ddr_trip>; + cooling-device = <&adsp_vdd 0 0>; + }; + cdsp_vdd_cdev { + trip = <&ddr_trip>; + cooling-device = <&cdsp_vdd 0 0>; + }; + slpi_vdd_cdev { + trip = <&ddr_trip>; + cooling-device = <&slpi_vdd 0 0>; + }; + }; + }; + + wlan-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens1 3>; + wake-capable-sensor; + tracks-low; + trips { + wlan_trip: wlan-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&wlan_trip>; + cooling-device = <&CPU0 4 4>; + }; + cpu4_vdd_cdev { + trip = <&wlan_trip>; + cooling-device = <&CPU4 9 9>; + }; + gpu_vdd_cdev { + trip = <&wlan_trip>; + cooling-device = <&msm_gpu 1 1>; + }; + cx_vdd_cdev { + trip = <&wlan_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + mx_vdd_cdev { + trip = <&wlan_trip>; + cooling-device = <&mx_cdev 0 0>; + }; + ebi_vdd_cdev { + trip = <&wlan_trip>; + cooling-device = <&ebi_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&wlan_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + adsp_vdd_cdev { + trip = <&wlan_trip>; + cooling-device = <&adsp_vdd 0 0>; + }; + cdsp_vdd_cdev { + trip = <&wlan_trip>; + cooling-device = <&cdsp_vdd 0 0>; + }; + slpi_vdd_cdev { + trip = <&wlan_trip>; + cooling-device = <&slpi_vdd 0 0>; + }; + }; + }; + + compute-hvx-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens1 4>; + wake-capable-sensor; + tracks-low; + trips { + hvx_trip: hvx-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&hvx_trip>; + cooling-device = <&CPU0 4 4>; + }; + cpu4_vdd_cdev { + trip = <&hvx_trip>; + cooling-device = <&CPU4 9 9>; + }; + gpu_vdd_cdev { + trip = <&hvx_trip>; + cooling-device = <&msm_gpu 1 1>; + }; + cx_vdd_cdev { + trip = <&hvx_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + mx_vdd_cdev { + trip = <&hvx_trip>; + cooling-device = <&mx_cdev 0 0>; + }; + ebi_vdd_cdev { + trip = <&hvx_trip>; + cooling-device = <&ebi_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&hvx_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + adsp_vdd_cdev { + trip = <&hvx_trip>; + cooling-device = <&adsp_vdd 0 0>; + }; + cdsp_vdd_cdev { + trip = <&hvx_trip>; + cooling-device = <&cdsp_vdd 0 0>; + }; + slpi_vdd_cdev { + trip = <&hvx_trip>; + cooling-device = <&slpi_vdd 0 0>; + }; + }; + }; + + camera-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens1 5>; + wake-capable-sensor; + tracks-low; + trips { + camera_trip: camera-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&camera_trip>; + cooling-device = <&CPU0 4 4>; + }; + cpu4_vdd_cdev { + trip = <&camera_trip>; + cooling-device = <&CPU4 9 9>; + }; + gpu_vdd_cdev { + trip = <&camera_trip>; + cooling-device = <&msm_gpu 1 1>; + }; + cx_vdd_cdev { + trip = <&camera_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + mx_vdd_cdev { + trip = <&camera_trip>; + cooling-device = <&mx_cdev 0 0>; + }; + ebi_vdd_cdev { + trip = <&camera_trip>; + cooling-device = <&ebi_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>; + }; + cdsp_vdd_cdev { + trip = <&camera_trip>; + cooling-device = <&cdsp_vdd 0 0>; + }; + slpi_vdd_cdev { + trip = <&camera_trip>; + cooling-device = <&slpi_vdd 0 0>; + }; + }; + }; + + mmss-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens1 6>; + wake-capable-sensor; + tracks-low; + trips { + mmss_trip: mmss-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&mmss_trip>; + cooling-device = <&CPU0 4 4>; + }; + cpu4_vdd_cdev { + trip = <&mmss_trip>; + cooling-device = <&CPU4 9 9>; + }; + gpu_vdd_cdev { + trip = <&mmss_trip>; + cooling-device = <&msm_gpu 1 1>; + }; + cx_vdd_cdev { + trip = <&mmss_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + mx_vdd_cdev { + trip = <&mmss_trip>; + cooling-device = <&mx_cdev 0 0>; + }; + ebi_vdd_cdev { + trip = <&mmss_trip>; + cooling-device = <&ebi_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&mmss_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + adsp_vdd_cdev { + trip = <&mmss_trip>; + cooling-device = <&adsp_vdd 0 0>; + }; + cdsp_vdd_cdev { + trip = <&mmss_trip>; + cooling-device = <&cdsp_vdd 0 0>; + }; + slpi_vdd_cdev { + trip = <&mmss_trip>; + cooling-device = <&slpi_vdd 0 0>; + }; + }; + }; + + mdm-core-lowf { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "low_limits_floor"; + thermal-sensors = <&tsens1 7>; + wake-capable-sensor; + tracks-low; + trips { + mdm_trip: mdm-trip { + temperature = <5000>; + hysteresis = <5000>; + type = "passive"; + }; + }; + cooling-maps { + cpu0_vdd_cdev { + trip = <&mdm_trip>; + cooling-device = <&CPU0 4 4>; + }; + cpu4_vdd_cdev { + trip = <&mdm_trip>; + cooling-device = <&CPU4 9 9>; + }; + gpu_vdd_cdev { + trip = <&mdm_trip>; + cooling-device = <&msm_gpu 1 1>; + }; + cx_vdd_cdev { + trip = <&mdm_trip>; + cooling-device = <&cx_cdev 0 0>; + }; + mx_vdd_cdev { + trip = <&mdm_trip>; + cooling-device = <&mx_cdev 0 0>; + }; + ebi_vdd_cdev { + trip = <&mdm_trip>; + cooling-device = <&ebi_cdev 0 0>; + }; + modem_vdd_cdev { + trip = <&mdm_trip>; + cooling-device = <&modem_vdd 0 0>; + }; + adsp_vdd_cdev { + trip = <&mdm_trip>; + cooling-device = <&adsp_vdd 0 0>; + }; + cdsp_vdd_cdev { + trip = <&mdm_trip>; + cooling-device = <&cdsp_vdd 0 0>; + }; + slpi_vdd_cdev { + trip = <&mdm_trip>; + cooling-device = <&slpi_vdd 0 0>; }; }; }; diff --git a/arch/arm64/boot/dts/qcom/skeleton64.dtsi b/arch/arm64/boot/dts/qcom/skeleton64.dtsi index bd349aeb0566..1f8ba28132c4 100644 --- a/arch/arm64/boot/dts/qcom/skeleton64.dtsi +++ b/arch/arm64/boot/dts/qcom/skeleton64.dtsi @@ -1,4 +1,3 @@ -// SPDX-License-Identifier: GPL-2.0-only /* * Skeleton device tree in the 64 bits version; the bare minimum * needed to boot; just include and add a compatible value. The diff --git a/arch/arm64/boot/dts/qcom/smb1355.dtsi b/arch/arm64/boot/dts/qcom/smb1355.dtsi new file mode 100644 index 000000000000..5939440cfa47 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/smb1355.dtsi @@ -0,0 +1,107 @@ +/* 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. + */ + +#include + +smb1355_0: qcom,smb1355@8 { + compatible = "qcom,i2c-pmic"; + reg = <0x8>; + #address-cells = <1>; + #size-cells = <0>; + interrupt-parent = <&spmi_bus>; + interrupts = <0x0 0xd1 0x0 IRQ_TYPE_LEVEL_LOW>; + interrupt_names = "smb1355_0"; + interrupt-controller; + #interrupt-cells = <3>; + qcom,periph-map = <0x10 0x12 0x13 0x16>; + + smb1355_revid_0: qcom,revid@100 { + compatible = "qcom,qpnp-revid"; + reg = <0x100 0x100>; + }; + + smb1355_charger_0: qcom,smb1355-charger@1000 { + compatible = "qcom,smb1355"; + qcom,pmic-revid = <&smb1355_revid_0>; + reg = <0x1000 0x700>; + #address-cells = <1>; + #size-cells = <1>; + interrupt-parent = <&smb1355_0>; + status = "disabled"; + + io-channels = <&pmi8998_rradc 2>, + <&pmi8998_rradc 12>; + io-channel-names = "charger_temp", + "charger_temp_max"; + + qcom,chgr@1000 { + reg = <0x1000 0x100>; + interrupts = <0x10 0x1 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "chg-state-change"; + }; + + qcom,chgr-misc@1600 { + reg = <0x1600 0x100>; + interrupts = <0x16 0x1 IRQ_TYPE_EDGE_RISING>, + <0x16 0x6 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "wdog-bark", + "temperature-change"; + }; + }; +}; + +smb1355_1: qcom,smb1355@c { + compatible = "qcom,i2c-pmic"; + reg = <0xc>; + #address-cells = <1>; + #size-cells = <0>; + interrupt-parent = <&spmi_bus>; + interrupts = <0x0 0xd1 0x0 IRQ_TYPE_LEVEL_LOW>; + interrupt_names = "smb1355_1"; + interrupt-controller; + #interrupt-cells = <3>; + qcom,periph-map = <0x10 0x12 0x13 0x16>; + + smb1355_revid_1: qcom,revid@100 { + compatible = "qcom,qpnp-revid"; + reg = <0x100 0x100>; + }; + + smb1355_charger_1: qcom,smb1355-charger@1000 { + compatible = "qcom,smb1355"; + qcom,pmic-revid = <&smb1355_revid_1>; + reg = <0x1000 0x700>; + #address-cells = <1>; + #size-cells = <1>; + interrupt-parent = <&smb1355_1>; + status = "disabled"; + + io-channels = <&pmi8998_rradc 2>, + <&pmi8998_rradc 12>; + io-channel-names = "charger_temp", + "charger_temp_max"; + + qcom,chgr@1000 { + reg = <0x1000 0x100>; + interrupts = <0x10 0x1 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "chg-state-change"; + }; + + qcom,chgr-misc@1600 { + reg = <0x1600 0x100>; + interrupts = <0x16 0x1 IRQ_TYPE_EDGE_RISING>, + <0x16 0x6 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "wdog-bark", + "temperature-change"; + }; + }; +}; From 1a723458fbf7ff6a6600c9186f0f5850cdc56916 Mon Sep 17 00:00:00 2001 From: MrArtemSid Date: Mon, 25 Dec 2023 16:14:14 +0400 Subject: [PATCH 005/356] arm64: dts: qcom: sdm845: Update License --- .../qcom/dsi-panel-nt35597-dualmipi-wqxga-cmd.dtsi | 13 +++---------- .../dsi-panel-nt35597-dualmipi-wqxga-video.dtsi | 13 +++---------- .../dsi-panel-nt35597-truly-dsc-wqxga-cmd.dtsi | 13 +++---------- .../dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi | 13 +++---------- ...dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi | 13 +++---------- ...i-panel-nt35597-truly-dualmipi-wqxga-video.dtsi | 13 +++---------- .../dsi-panel-nt36850-truly-dualmipi-wqhd-cmd.dtsi | 13 +++---------- .../dts/qcom/dsi-panel-r63417-truly-1080p-cmd.dtsi | 13 +++---------- ...dsi-panel-s6e3ha3-amoled-dualmipi-wqhd-cmd.dtsi | 13 +++---------- .../boot/dts/qcom/dsi-panel-sharp-1080p-cmd.dtsi | 13 +++---------- .../boot/dts/qcom/dsi-panel-sharp-dsc-4k-cmd.dtsi | 13 +++---------- .../dts/qcom/dsi-panel-sharp-dsc-4k-video.dtsi | 13 +++---------- .../qcom/dsi-panel-sharp-dualmipi-1080p-120hz.dtsi | 13 +++---------- arch/arm64/boot/dts/qcom/dsi-panel-sim-cmd.dtsi | 13 +++---------- .../boot/dts/qcom/dsi-panel-sim-dsc375-cmd.dtsi | 13 +++---------- .../boot/dts/qcom/dsi-panel-sim-dualmipi-cmd.dtsi | 13 +++---------- .../qcom/dsi-panel-sim-dualmipi-dsc375-cmd.dtsi | 13 +++---------- .../dts/qcom/dsi-panel-sim-dualmipi-video.dtsi | 13 +++---------- arch/arm64/boot/dts/qcom/dsi-panel-sim-video.dtsi | 13 +++---------- .../dts/qcom/dsi-panel-test-dualmipi-oled-cmd.dtsi | 13 +++---------- .../qcom/fg-gen3-batterydata-ascent-3450mah.dtsi | 13 +++---------- .../dts/qcom/fg-gen3-batterydata-demo-6000mah.dtsi | 13 +++---------- .../qcom/fg-gen3-batterydata-itech-3000mah.dtsi | 13 +++---------- arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi | 13 +++---------- arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi | 10 +--------- arch/arm64/boot/dts/qcom/msm-gdsc-sdm845.dtsi | 10 +--------- arch/arm64/boot/dts/qcom/msm-rdbg.dtsi | 13 +++---------- arch/arm64/boot/dts/qcom/msm-wsa881x.dtsi | 13 +++---------- arch/arm64/boot/dts/qcom/pm8005.dtsi | 13 +++---------- arch/arm64/boot/dts/qcom/pm8998.dtsi | 13 +++---------- arch/arm64/boot/dts/qcom/pmi8998.dtsi | 13 +++---------- .../arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi | 10 +--------- arch/arm64/boot/dts/qcom/sdm845-audio-overlay.dtsi | 10 +--------- arch/arm64/boot/dts/qcom/sdm845-audio.dtsi | 12 ++---------- arch/arm64/boot/dts/qcom/sdm845-bus.dtsi | 13 +++---------- .../boot/dts/qcom/sdm845-camera-sensor-mtp.dtsi | 10 +--------- arch/arm64/boot/dts/qcom/sdm845-camera.dtsi | 10 +--------- arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi | 13 +++---------- arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi | 13 +++---------- arch/arm64/boot/dts/qcom/sdm845-ion.dtsi | 13 +++---------- arch/arm64/boot/dts/qcom/sdm845-mtp-overlay.dts | 13 +++---------- arch/arm64/boot/dts/qcom/sdm845-mtp.dts | 13 +++---------- arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi | 13 +++---------- arch/arm64/boot/dts/qcom/sdm845-pcie.dtsi | 10 +--------- .../boot/dts/qcom/sdm845-pinctrl-overlay.dtsi | 13 +++---------- arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi | 13 +++---------- arch/arm64/boot/dts/qcom/sdm845-pm.dtsi | 13 +++---------- arch/arm64/boot/dts/qcom/sdm845-pmic-overlay.dtsi | 13 +++---------- arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi | 13 +++---------- arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi | 13 +++---------- arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi | 13 +++---------- arch/arm64/boot/dts/qcom/sdm845-sde-pll.dtsi | 13 +++---------- arch/arm64/boot/dts/qcom/sdm845-sde.dtsi | 14 ++++---------- arch/arm64/boot/dts/qcom/sdm845-smp2p.dtsi | 13 +++---------- arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi | 10 +--------- arch/arm64/boot/dts/qcom/sdm845-v2-mtp-overlay.dts | 13 +++---------- arch/arm64/boot/dts/qcom/sdm845-v2-mtp.dts | 14 +++----------- .../boot/dts/qcom/sdm845-v2.1-mtp-overlay.dts | 13 +++---------- arch/arm64/boot/dts/qcom/sdm845-v2.1-mtp.dts | 14 +++----------- arch/arm64/boot/dts/qcom/sdm845-v2.1.dts | 13 +++---------- arch/arm64/boot/dts/qcom/sdm845-v2.1.dtsi | 13 +++---------- arch/arm64/boot/dts/qcom/sdm845-v2.dts | 13 +++---------- arch/arm64/boot/dts/qcom/sdm845-v2.dtsi | 13 +++---------- arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi | 13 +++---------- arch/arm64/boot/dts/qcom/sdm845-wcd.dtsi | 13 +++---------- arch/arm64/boot/dts/qcom/sdm845.dts | 13 +++---------- arch/arm64/boot/dts/qcom/sdm845.dtsi | 13 +++---------- arch/arm64/boot/dts/qcom/skeleton64.dtsi | 1 + arch/arm64/boot/dts/qcom/smb1355.dtsi | 13 +++---------- 69 files changed, 189 insertions(+), 674 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-dualmipi-wqxga-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-dualmipi-wqxga-cmd.dtsi index 78f933ad23c2..a17fd632981a 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-dualmipi-wqxga-cmd.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-dualmipi-wqxga-cmd.dtsi @@ -1,13 +1,6 @@ -/* 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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. */ &mdss_mdp { diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-dualmipi-wqxga-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-dualmipi-wqxga-video.dtsi index 9cd5815e7529..7c29159da016 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-dualmipi-wqxga-video.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-dualmipi-wqxga-video.dtsi @@ -1,13 +1,6 @@ -/* 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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. */ &mdss_mdp { diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-cmd.dtsi index 0e60a0c1f22e..65fe181d8f71 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-cmd.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-cmd.dtsi @@ -1,13 +1,6 @@ -/* Copyright (c) 2016-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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. */ &mdss_mdp { diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi index b2a541d9384e..93d894cb84aa 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi @@ -1,13 +1,6 @@ -/* 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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. */ &mdss_mdp { diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi index 1a8ce910fc2a..eb714b92360b 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-cmd.dtsi @@ -1,13 +1,6 @@ -/* Copyright (c) 2016-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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. */ &mdss_mdp { diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi index 95e0e5ae1db8..838a1480b65c 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dualmipi-wqxga-video.dtsi @@ -1,13 +1,6 @@ -/* Copyright (c) 2016-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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. */ &mdss_mdp { diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-nt36850-truly-dualmipi-wqhd-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-nt36850-truly-dualmipi-wqhd-cmd.dtsi index ca28261a82a7..fe029dff06f1 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-nt36850-truly-dualmipi-wqhd-cmd.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-nt36850-truly-dualmipi-wqhd-cmd.dtsi @@ -1,13 +1,6 @@ -/* 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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. */ &mdss_mdp { diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-r63417-truly-1080p-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-r63417-truly-1080p-cmd.dtsi index 29aab25ec15e..87fdc371c11e 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-r63417-truly-1080p-cmd.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-r63417-truly-1080p-cmd.dtsi @@ -1,13 +1,6 @@ -/* Copyright (c) 2015-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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved. */ &mdss_mdp { diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-s6e3ha3-amoled-dualmipi-wqhd-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-s6e3ha3-amoled-dualmipi-wqhd-cmd.dtsi index 834a08fd4625..fad5491282fb 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-s6e3ha3-amoled-dualmipi-wqhd-cmd.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-s6e3ha3-amoled-dualmipi-wqhd-cmd.dtsi @@ -1,13 +1,6 @@ -/* Copyright (c) 2016-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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. */ &mdss_mdp { diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-sharp-1080p-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sharp-1080p-cmd.dtsi index aebc8b924182..61338f2d099a 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-sharp-1080p-cmd.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-sharp-1080p-cmd.dtsi @@ -1,13 +1,6 @@ -/* 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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. */ &mdss_mdp { diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-cmd.dtsi index 86c8836ca518..16c03f15b312 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-cmd.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-cmd.dtsi @@ -1,13 +1,6 @@ -/* Copyright (c) 2016-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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. */ &mdss_mdp { diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-video.dtsi index 66beead39bed..a8e45b1adbff 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-video.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dsc-4k-video.dtsi @@ -1,13 +1,6 @@ -/* Copyright (c) 2016-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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. */ &mdss_mdp { diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dualmipi-1080p-120hz.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dualmipi-1080p-120hz.dtsi index 6dc621ed8922..152a9ccb4e75 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dualmipi-1080p-120hz.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dualmipi-1080p-120hz.dtsi @@ -1,13 +1,6 @@ -/* Copyright (c) 2014-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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. */ &mdss_mdp { diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-sim-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sim-cmd.dtsi index 45ac04219915..fc18d060c9bc 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-sim-cmd.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-sim-cmd.dtsi @@ -1,13 +1,6 @@ -/* Copyright (c) 2014-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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2014-2015, 2017, The Linux Foundation. All rights reserved. */ &mdss_mdp { diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-sim-dsc375-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sim-dsc375-cmd.dtsi index ceb68568fa9f..bea236f819e9 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-sim-dsc375-cmd.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-sim-dsc375-cmd.dtsi @@ -1,13 +1,6 @@ -/* 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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. */ &mdss_mdp { diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-cmd.dtsi index 9a4e318ba756..b47609f5a614 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-cmd.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-cmd.dtsi @@ -1,13 +1,6 @@ -/* Copyright (c) 2014-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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. */ &mdss_mdp { diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-dsc375-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-dsc375-cmd.dtsi index 5d977e7cb675..96ee5e9fc30a 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-dsc375-cmd.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-dsc375-cmd.dtsi @@ -1,13 +1,6 @@ -/* Copyright (c) 2016-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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. */ &mdss_mdp { diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-video.dtsi index dbfedb92865a..b0ef38fd6dad 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-video.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-sim-dualmipi-video.dtsi @@ -1,13 +1,6 @@ -/* Copyright (c) 2014-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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. */ &mdss_mdp { diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-sim-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sim-video.dtsi index 40bedd0e462c..bacbb97f7f3c 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-sim-video.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-sim-video.dtsi @@ -1,13 +1,6 @@ -/* Copyright (c) 2012-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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2012-2015, 2017, The Linux Foundation. All rights reserved. */ &mdss_mdp { diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-test-dualmipi-oled-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-test-dualmipi-oled-cmd.dtsi index 3a5d272903b1..531f040156e2 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-test-dualmipi-oled-cmd.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-test-dualmipi-oled-cmd.dtsi @@ -1,13 +1,6 @@ -/* 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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. */ &mdss_mdp { diff --git a/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-ascent-3450mah.dtsi b/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-ascent-3450mah.dtsi index a57ea7c9e3e0..a0e73b2c6c2d 100644 --- a/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-ascent-3450mah.dtsi +++ b/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-ascent-3450mah.dtsi @@ -1,13 +1,6 @@ -/* Copyright (c) 2016-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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. */ qcom,ascent_3450mah { diff --git a/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-demo-6000mah.dtsi b/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-demo-6000mah.dtsi index 1e8cd16567b8..c776a100b1de 100644 --- a/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-demo-6000mah.dtsi +++ b/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-demo-6000mah.dtsi @@ -1,13 +1,6 @@ -/* Copyright (c) 2016-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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. */ qcom,demo_6000mah { diff --git a/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-itech-3000mah.dtsi b/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-itech-3000mah.dtsi index 3888047b9f8c..600dbbf28e6a 100644 --- a/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-itech-3000mah.dtsi +++ b/arch/arm64/boot/dts/qcom/fg-gen3-batterydata-itech-3000mah.dtsi @@ -1,13 +1,6 @@ -/* Copyright (c) 2016-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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. */ qcom,itech_3000mah { diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi index 0ac9c2a1dc3f..4fc1fa85c1e7 100644 --- a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi @@ -1,13 +1,6 @@ -/* 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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. */ #include diff --git a/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi b/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi index bb05a2e86926..a95de6c04c04 100644 --- a/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi +++ b/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi @@ -1,14 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016-2020, 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. */ &soc { diff --git a/arch/arm64/boot/dts/qcom/msm-gdsc-sdm845.dtsi b/arch/arm64/boot/dts/qcom/msm-gdsc-sdm845.dtsi index b43c87633365..cfc500f1050d 100644 --- a/arch/arm64/boot/dts/qcom/msm-gdsc-sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/msm-gdsc-sdm845.dtsi @@ -1,14 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016-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. */ &soc { diff --git a/arch/arm64/boot/dts/qcom/msm-rdbg.dtsi b/arch/arm64/boot/dts/qcom/msm-rdbg.dtsi index d9d1be428c71..e0d7b571efc1 100644 --- a/arch/arm64/boot/dts/qcom/msm-rdbg.dtsi +++ b/arch/arm64/boot/dts/qcom/msm-rdbg.dtsi @@ -1,13 +1,6 @@ -/* Copyright (c) 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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. */ &soc { diff --git a/arch/arm64/boot/dts/qcom/msm-wsa881x.dtsi b/arch/arm64/boot/dts/qcom/msm-wsa881x.dtsi index 948da3bb6888..d638c006d043 100644 --- a/arch/arm64/boot/dts/qcom/msm-wsa881x.dtsi +++ b/arch/arm64/boot/dts/qcom/msm-wsa881x.dtsi @@ -1,13 +1,6 @@ -/* Copyright (c) 2016-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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. */ &slim_aud { diff --git a/arch/arm64/boot/dts/qcom/pm8005.dtsi b/arch/arm64/boot/dts/qcom/pm8005.dtsi index aff92a8100a2..a4f8d99c134a 100644 --- a/arch/arm64/boot/dts/qcom/pm8005.dtsi +++ b/arch/arm64/boot/dts/qcom/pm8005.dtsi @@ -1,13 +1,6 @@ -/* 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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. */ #include diff --git a/arch/arm64/boot/dts/qcom/pm8998.dtsi b/arch/arm64/boot/dts/qcom/pm8998.dtsi index 0d5129be09b4..253cfd3decaf 100644 --- a/arch/arm64/boot/dts/qcom/pm8998.dtsi +++ b/arch/arm64/boot/dts/qcom/pm8998.dtsi @@ -1,13 +1,6 @@ -/* Copyright (c) 2016-2017, 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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2017, 2019, The Linux Foundation. All rights reserved. */ #include diff --git a/arch/arm64/boot/dts/qcom/pmi8998.dtsi b/arch/arm64/boot/dts/qcom/pmi8998.dtsi index 30ee2cbde504..e4f6ff62f1b0 100644 --- a/arch/arm64/boot/dts/qcom/pmi8998.dtsi +++ b/arch/arm64/boot/dts/qcom/pmi8998.dtsi @@ -1,13 +1,6 @@ -/* Copyright (c) 2016-2017, 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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2017, 2019, The Linux Foundation. All rights reserved. */ #include diff --git a/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi index aff49d7e4197..117f616bcb7a 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi @@ -1,14 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016-2018, 2020, 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 diff --git a/arch/arm64/boot/dts/qcom/sdm845-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm845-audio-overlay.dtsi index 9d485b5dbba0..dc6a177b5c2b 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-audio-overlay.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-audio-overlay.dtsi @@ -1,14 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 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. */ #include "sdm845-wcd.dtsi" diff --git a/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi b/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi index 83be25615415..b3d048976167 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi @@ -1,14 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2016-2019, 2021, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. */ #include "msm-audio-lpass.dtsi" diff --git a/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi b/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi index 3ce56269be2b..1001de0d06f6 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi @@ -1,13 +1,6 @@ -/* Copyright (c) 2016-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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. */ #include diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-mtp.dtsi index d708a121c4b1..4afdf5600708 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-mtp.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-mtp.dtsi @@ -1,14 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * 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. */ &soc { diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi index 8bb6d2386530..c4d8a0c4c733 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi @@ -1,14 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-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. */ &soc { diff --git a/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi b/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi index a094f65a0402..a4a5f1cc55a2 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-coresight.dtsi @@ -1,13 +1,6 @@ -/* 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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. */ &soc { diff --git a/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi b/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi index d956c8f44307..07f2f0164b67 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi @@ -1,13 +1,6 @@ -/* Copyright (c) 2017-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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. */ &soc { diff --git a/arch/arm64/boot/dts/qcom/sdm845-ion.dtsi b/arch/arm64/boot/dts/qcom/sdm845-ion.dtsi index 7d8318497c50..5c899e5d2f01 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-ion.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-ion.dtsi @@ -1,13 +1,6 @@ -/* Copyright (c) 2016-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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. */ &soc { diff --git a/arch/arm64/boot/dts/qcom/sdm845-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-mtp-overlay.dts index 2d1d9b637c9f..3ece5cd553fd 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-mtp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sdm845-mtp-overlay.dts @@ -1,13 +1,6 @@ -/* Copyright (c) 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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. */ /dts-v1/; diff --git a/arch/arm64/boot/dts/qcom/sdm845-mtp.dts b/arch/arm64/boot/dts/qcom/sdm845-mtp.dts index e74b342e521b..cf56e16b3de7 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-mtp.dts +++ b/arch/arm64/boot/dts/qcom/sdm845-mtp.dts @@ -1,13 +1,6 @@ -/* Copyright (c) 2016-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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. */ diff --git a/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi index a776b1b60df8..5d7d6c568850 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi @@ -1,13 +1,6 @@ -/* Copyright (c) 2016-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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. */ #include diff --git a/arch/arm64/boot/dts/qcom/sdm845-pcie.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pcie.dtsi index c00c264649c7..1167a04db53d 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-pcie.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-pcie.dtsi @@ -1,14 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * 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. */ #include diff --git a/arch/arm64/boot/dts/qcom/sdm845-pinctrl-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pinctrl-overlay.dtsi index 67933c3784f7..2ac159a79871 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-pinctrl-overlay.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-pinctrl-overlay.dtsi @@ -1,13 +1,6 @@ -/* Copyright (c) 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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. */ &pmi8998_gpios { diff --git a/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi index 86320c349e75..b3990c270b43 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi @@ -1,13 +1,6 @@ -/* Copyright (c) 2016-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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. */ &soc { diff --git a/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi index 9a4e43d96907..dd9bafc76adc 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi @@ -1,13 +1,6 @@ -/* 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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. */ &soc { diff --git a/arch/arm64/boot/dts/qcom/sdm845-pmic-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pmic-overlay.dtsi index db4483cef8f0..b66eb5c20032 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-pmic-overlay.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-pmic-overlay.dtsi @@ -1,13 +1,6 @@ -/* 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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. */ #include diff --git a/arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi b/arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi index 097c3ac0d452..92067ea43d6a 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi @@ -1,13 +1,6 @@ -/* 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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. */ #include diff --git a/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi index 34beda4b465e..0590863cb9e9 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi @@ -1,13 +1,6 @@ -/* 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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. */ #include diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi index aa3976d33c32..d52b1172dd25 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi @@ -1,13 +1,6 @@ -/* Copyright (c) 2016-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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. */ #include "dsi-panel-sim-video.dtsi" diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde-pll.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde-pll.dtsi index 967865b3ec10..5e5f113f1f3c 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-sde-pll.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-sde-pll.dtsi @@ -1,13 +1,6 @@ -/* Copyright (c) 2016-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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. */ &soc { diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi index 6132722a562b..eba11a158323 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi @@ -1,14 +1,8 @@ -/* 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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. */ + #include &soc { diff --git a/arch/arm64/boot/dts/qcom/sdm845-smp2p.dtsi b/arch/arm64/boot/dts/qcom/sdm845-smp2p.dtsi index a2978358bfbb..8882ed04d872 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-smp2p.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-smp2p.dtsi @@ -1,13 +1,6 @@ -/* Copyright (c) 2016-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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. */ #include diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi index 3c84a6b58662..a8020c87c4ea 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi @@ -1,14 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-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. */ &soc { diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-v2-mtp-overlay.dts index e049357e6f61..7794bd578bdd 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-v2-mtp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sdm845-v2-mtp-overlay.dts @@ -1,13 +1,6 @@ -/* Copyright (c) 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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. */ /dts-v1/; diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-mtp.dts b/arch/arm64/boot/dts/qcom/sdm845-v2-mtp.dts index 1b86ab1faec3..a2447e2e1436 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-v2-mtp.dts +++ b/arch/arm64/boot/dts/qcom/sdm845-v2-mtp.dts @@ -1,16 +1,8 @@ -/* Copyright (c) 2017,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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. */ - /dts-v1/; #include "sdm845-v2.dtsi" diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.1-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-v2.1-mtp-overlay.dts index 7b3573a3b030..7a1101d2a5ef 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-v2.1-mtp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sdm845-v2.1-mtp-overlay.dts @@ -1,13 +1,6 @@ -/* Copyright (c) 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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. */ /dts-v1/; diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.1-mtp.dts b/arch/arm64/boot/dts/qcom/sdm845-v2.1-mtp.dts index 444ce98e0cc5..200801e7d8d1 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-v2.1-mtp.dts +++ b/arch/arm64/boot/dts/qcom/sdm845-v2.1-mtp.dts @@ -1,16 +1,8 @@ -/* Copyright (c) 2019-2020, 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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. */ - /dts-v1/; #include "sdm845-v2.1.dtsi" diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.1.dts b/arch/arm64/boot/dts/qcom/sdm845-v2.1.dts index 2902a6042927..20329fc06cac 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-v2.1.dts +++ b/arch/arm64/boot/dts/qcom/sdm845-v2.1.dts @@ -1,13 +1,6 @@ -/* Copyright (c) 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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. */ /dts-v1/; diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.1.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2.1.dtsi index b29827270c26..c374b488c2fe 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-v2.1.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-v2.1.dtsi @@ -1,13 +1,6 @@ -/* Copyright (c) 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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. */ #include "sdm845-v2.dtsi" diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.dts b/arch/arm64/boot/dts/qcom/sdm845-v2.dts index d36d0fd55d83..62ec1afa9501 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-v2.dts +++ b/arch/arm64/boot/dts/qcom/sdm845-v2.dts @@ -1,13 +1,6 @@ -/* Copyright (c) 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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. */ /dts-v1/; diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi index 229d06b786e1..73f1e70d2bb6 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi @@ -1,13 +1,6 @@ -/* 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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. */ #include "sdm845.dtsi" diff --git a/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi b/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi index 9588aacc1e2e..04aaf7e2f15f 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi @@ -1,13 +1,6 @@ -/* 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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. */ #include diff --git a/arch/arm64/boot/dts/qcom/sdm845-wcd.dtsi b/arch/arm64/boot/dts/qcom/sdm845-wcd.dtsi index aab91d60af57..64931fd9a60a 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-wcd.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-wcd.dtsi @@ -1,13 +1,6 @@ -/* Copyright (c) 2016-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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. */ &slim_aud { diff --git a/arch/arm64/boot/dts/qcom/sdm845.dts b/arch/arm64/boot/dts/qcom/sdm845.dts index a3fa3afd28b2..286d69ec3e2e 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dts +++ b/arch/arm64/boot/dts/qcom/sdm845.dts @@ -1,13 +1,6 @@ -/* Copyright (c) 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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. */ /dts-v1/; diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index 9002c5f8afea..f93d4d3b9d3b 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -1,13 +1,6 @@ -/* Copyright (c) 2016-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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. */ #include "skeleton64.dtsi" diff --git a/arch/arm64/boot/dts/qcom/skeleton64.dtsi b/arch/arm64/boot/dts/qcom/skeleton64.dtsi index 1f8ba28132c4..bd349aeb0566 100644 --- a/arch/arm64/boot/dts/qcom/skeleton64.dtsi +++ b/arch/arm64/boot/dts/qcom/skeleton64.dtsi @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Skeleton device tree in the 64 bits version; the bare minimum * needed to boot; just include and add a compatible value. The diff --git a/arch/arm64/boot/dts/qcom/smb1355.dtsi b/arch/arm64/boot/dts/qcom/smb1355.dtsi index 5939440cfa47..a4a90f174bc3 100644 --- a/arch/arm64/boot/dts/qcom/smb1355.dtsi +++ b/arch/arm64/boot/dts/qcom/smb1355.dtsi @@ -1,13 +1,6 @@ -/* 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. +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. */ #include From 27be20dfdf775013c8d5773ee0e2c9c444d6df72 Mon Sep 17 00:00:00 2001 From: Michael Bestas Date: Mon, 5 Jun 2023 22:33:43 +0300 Subject: [PATCH 006/356] arm64: dts: Use standard dts for sdm845 even if vendor dts exists Change-Id: I487a8da555cc95bdb1902765083f3b4161194a98 --- arch/arm64/boot/dts/Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/boot/dts/Makefile b/arch/arm64/boot/dts/Makefile index d3f2212c9ce2..3f97a65461e5 100644 --- a/arch/arm64/boot/dts/Makefile +++ b/arch/arm64/boot/dts/Makefile @@ -33,7 +33,11 @@ subdir-y += zte else + ifeq ($(CONFIG_ARCH_SDM845),y) + subdir-y += qcom + else subdir-y += vendor + endif endif dtb-$(CONFIG_OF_ALL_DTBS) := $(patsubst $(dtstree)/%.dts,%.dtb, $(foreach d,$(subdir), $(wildcard $(dtstree)/$(d)/*.dts))) From 7c6a759bea731dffbb98aca352e1b77490f00344 Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Sat, 6 Nov 2021 09:33:49 +0200 Subject: [PATCH 007/356] arm64: dts: qcom: sdm845: Update header for voltage levels constants RPMh regulator voltage level constans are now located in qcom,rpmh-regulator-levels.h header. Signed-off-by: Pavel Dubrova --- arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi | 2 +- arch/arm64/boot/dts/qcom/sdm845.dtsi | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi index 0590863cb9e9..d88079972c1b 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi @@ -4,7 +4,7 @@ */ #include -#include +#include /* Stub regulators */ / { diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index f93d4d3b9d3b..99187acb36dd 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include From 5f39093b49d552b9fbe7c819384e1513ba0b4d27 Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Tue, 9 Nov 2021 19:38:26 +0200 Subject: [PATCH 008/356] arm64: dts: qcom: sdm845: Update min voltage for RPMh regulators Update the minimum supported voltage for RPMh regulators from LEVEL_OFF to LEVEL_RETENTION. Signed-off-by: Pavel Dubrova --- arch/arm64/boot/dts/qcom/sdm845-camera.dtsi | 7 +++---- arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi | 14 +++++++------- arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi | 7 +++---- 3 files changed, 13 insertions(+), 15 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi index c4d8a0c4c733..75414f0c124b 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi @@ -419,8 +419,7 @@ MSM_BUS_SLAVE_CAMERA_CFG 0 300000>, ; - vdd-corners = ; - vdd-corner-ahb-mapping = "suspend", "suspend", - "minsvs", "lowsvs", "svs", "svs_l1", + vdd-corner-ahb-mapping = "suspend", "minsvs", + "lowsvs", "svs", "svs_l1", "nominal", "nominal", "nominal", "turbo", "turbo"; client-id-based; diff --git a/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi index d88079972c1b..2b7237550710 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi @@ -33,7 +33,7 @@ pm8998_s1_level: regulator-s1 { regulator-name = "pm8998_s1_level"; qcom,set = ; - regulator-min-microvolt = ; + regulator-min-microvolt = ; regulator-max-microvolt = ; }; @@ -92,14 +92,14 @@ pm8998_s6_level: regulator-s6-level { regulator-name = "pm8998_s6_level"; qcom,set = ; - regulator-min-microvolt = ; + regulator-min-microvolt = ; regulator-max-microvolt = ; }; pm8998_s6_level_ao: regulator-s6-level-ao { regulator-name = "pm8998_s6_level_ao"; qcom,set = ; - regulator-min-microvolt = ; + regulator-min-microvolt = ; regulator-max-microvolt = ; }; @@ -107,7 +107,7 @@ compatible = "qcom,regulator-cooling-device"; regulator-cdev-supply = <&pm8998_s6_level>; regulator-levels = ; + RPMH_REGULATOR_LEVEL_RETENTION>; #cooling-cells = <2>; }; }; @@ -246,7 +246,7 @@ pm8998_l4_level: regulator-l4-level { regulator-name = "pm8998_l4_level"; qcom,set = ; - regulator-min-microvolt = ; + regulator-min-microvolt = ; regulator-max-microvolt = ; }; }; @@ -684,7 +684,7 @@ pm8998_l27_level: regulator-l27-level { regulator-name = "pm8998_l27_level"; qcom,set = ; - regulator-min-microvolt = ; + regulator-min-microvolt = ; regulator-max-microvolt = ; }; }; @@ -783,7 +783,7 @@ pm8005_s2_level: regulator-s2-level { regulator-name = "pm8005_s2_level"; qcom,set = ; - regulator-min-microvolt = ; + regulator-min-microvolt = ; regulator-max-microvolt = ; }; }; diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi index a8020c87c4ea..582ec86d215f 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi @@ -338,8 +338,7 @@ MSM_BUS_SLAVE_CAMERA_CFG 0 300000>, ; - vdd-corners = ; - vdd-corner-ahb-mapping = "suspend", "suspend", - "minsvs", "lowsvs", "svs", "svs_l1", + vdd-corner-ahb-mapping = "suspend", "minsvs", + "lowsvs", "svs", "svs_l1", "nominal", "nominal", "nominal", "turbo", "turbo"; client-id-based; From b334fab5993f038e0533ae0489242a2a34cabd32 Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Sat, 6 Nov 2021 21:41:51 +0200 Subject: [PATCH 009/356] arm64: dts: qcom: sdm845: Update SMEM nodes Update SMEM and add all the necessary nodes to support SMEM driver on kernel 4.19. Also add required memory region. Signed-off-by: Pavel Dubrova --- arch/arm64/boot/dts/qcom/sdm845.dtsi | 34 ++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index 99187acb36dd..f00d00ddc4c3 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -524,7 +524,17 @@ removed_region: removed_region@85fc0000 { no-map; - reg = <0 0x85fc0000 0 0x2f40000>; + reg = <0 0x85fc0000 0 0x40000>; + }; + + smem_mem: smem_region@86000000 { + no-map; + reg = <0 0x86000000 0 0x200000>; + }; + + removed_region1: removed_region@86200000 { + no-map; + reg = <0 0x86200000 0 0x2d00000>; }; qseecom_mem: qseecom_region@0x8ab00000 { @@ -2142,15 +2152,21 @@ qcom,num-locks = <8>; }; - qcom,smem@86000000 { + 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"; - reg = <0x86000000 0x200000>, - <0x17911008 0x4>, - <0x778000 0x7000>, - <0x1fd4000 0x8>; - reg-names = "smem", "irq-reg-base", "aux-mem1", - "smem_targ_info_reg"; - qcom,mpu-enabled; + memory-region = <&smem_mem>; + hwlocks = <&tcsr_mutex 3>; }; qcom,glink-mailbox-xprt-spss@1885008 { From ad8d006911f54136012c00267649dfe8d4fcae3a Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Sat, 6 Nov 2021 22:11:16 +0200 Subject: [PATCH 010/356] arm64: dts: qcom: sdm845: Update apps/display RSC nodes Update apps and display RSC nodes for the new RPMH RSC driver. Signed-off-by: Pavel Dubrova --- arch/arm64/boot/dts/qcom/sdm845-bus.dtsi | 2 +- arch/arm64/boot/dts/qcom/sdm845.dtsi | 32 ++++++++++++++---------- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi b/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi index 1001de0d06f6..db1b4ab5034f 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi @@ -4,7 +4,7 @@ */ #include -#include +#include #include &soc { diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index f00d00ddc4c3..e62505a28fc6 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include @@ -2197,12 +2197,17 @@ #mbox-cells = <1>; }; - apps_rsc: mailbox@179e0000 { - compatible = "qcom,tcs-drv"; + apps_rsc: rsc@179c0000 { + compatible = "qcom,rpmh-rsc"; label = "apps_rsc"; - reg = <0x179e0000 0x100>, <0x179e0d00 0x3000>; - interrupts = <0 5 0>; - #mbox-cells = <1>; + reg = <0x179c0000 0x10000>, + <0x179d0000 0x10000>, + <0x179e0000 0x10000>; + reg-names = "drv-0", "drv-1", "drv-2"; + interrupts = , + , + ; + qcom,tcs-offset = <0xd00>; qcom,drv-id = <2>; qcom,tcs-config = , , @@ -2210,16 +2215,17 @@ ; }; - disp_rsc: mailbox@af20000 { - compatible = "qcom,tcs-drv"; + disp_rsc: rsc@af20000 { + compatible = "qcom,rpmh-rsc"; label = "display_rsc"; - reg = <0xaf20000 0x100>, <0xaf21c00 0x3000>; - interrupts = <0 129 0>; - #mbox-cells = <1>; + reg = <0xaf20000 0x10000>; + reg-names = "drv-0"; + interrupts = ; + qcom,tcs-offset = <0x1c00>; qcom,drv-id = <0>; - qcom,tcs-config = , + qcom,tcs-config = , + , , - , ; }; From 1d17bd9691293c76ff147c7e37872b45c8c0e3b7 Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Sat, 6 Nov 2021 22:22:06 +0200 Subject: [PATCH 011/356] arm64: dts: qcom: sdm845: Add msm bus apps rsc device Since the Resource Power Manager Hardened (RPMH) driver is no longer using the mailbox framework. Create a new device as the child node of the RPMH driver to help fetch handles for each Resource State Coordinator(RSC). This is required to interface with the RPMH driver in order to communicate with a set of Qualcomm specific ASICs controlling bus clock resources. Signed-off-by: Pavel Dubrova --- arch/arm64/boot/dts/qcom/sdm845.dtsi | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index e62505a28fc6..a96fde211682 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -2213,6 +2213,11 @@ , , ; + + msm_bus_apps_rsc { + compatible = "qcom,msm-bus-rsc"; + qcom,msm-bus-id = ; + }; }; disp_rsc: rsc@af20000 { @@ -2227,6 +2232,11 @@ , , ; + + msm_bus_disp_rsc { + compatible = "qcom,msm-bus-rsc"; + qcom,msm-bus-id = ; + }; }; system_pm { From 30b79cae80cdc0d65fa7d9108a5a3bdbc8ce10f5 Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Sat, 6 Nov 2021 22:47:58 +0200 Subject: [PATCH 012/356] arm64: dts: qcom: sdm845: Update system PM node System PM device handles all activities supporting the SoC's capability to enter system sleep modes. Update system PM node to use apps_rsc. Signed-off-by: Pavel Dubrova --- arch/arm64/boot/dts/qcom/sdm845.dtsi | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index a96fde211682..6659acd94349 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -2218,6 +2218,10 @@ compatible = "qcom,msm-bus-rsc"; qcom,msm-bus-id = ; }; + + system_pm { + compatible = "qcom,system-pm"; + }; }; disp_rsc: rsc@af20000 { @@ -2239,11 +2243,6 @@ }; }; - system_pm { - compatible = "qcom,system-pm"; - mboxes = <&apps_rsc 0>; - }; - qcom,glink-smem-native-xprt-modem@86000000 { compatible = "qcom,glink-smem-native-xprt"; reg = <0x86000000 0x200000>, From c46110968ceee6f0d3fba276a1918ee4fcd8fc41 Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Sat, 6 Nov 2021 22:57:02 +0200 Subject: [PATCH 013/356] arm64: dts: qcom: sdm845: Update clock RPMh node Update RPMh clock node to use apps_rsc to communicate for RPMh controlled clocks. Also add SDE RSC RPMh child node to disp_rsc. Signed-off-by: Pavel Dubrova --- arch/arm64/boot/dts/qcom/sdm845.dtsi | 33 ++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index 6659acd94349..75f427ab3df0 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -668,6 +668,22 @@ linux,cma-default; }; }; + + 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 = "sleep_clk"; + #clock-cells = <0>; + }; + }; }; #include "msm-gdsc-sdm845.dtsi" @@ -1177,13 +1193,6 @@ < 2208000 MHZ_TO_MBPS(681, 4) >; }; - clock_rpmh: qcom,rpmhclk { - compatible = "qcom,rpmh-clk-sdm845"; - #clock-cells = <1>; - mboxes = <&apps_rsc 0>; - mbox-names = "apps"; - }; - clock_gcc: qcom,gcc@100000 { compatible = "qcom,gcc-sdm845", "syscon"; reg = <0x100000 0x1f0000>; @@ -2222,6 +2231,11 @@ system_pm { compatible = "qcom,system-pm"; }; + + clock_rpmh: qcom,rpmhclk { + compatible = "qcom,sdm845-rpmh-clk"; + #clock-cells = <1>; + }; }; disp_rsc: rsc@af20000 { @@ -2241,6 +2255,11 @@ compatible = "qcom,msm-bus-rsc"; qcom,msm-bus-id = ; }; + + sde_rsc_rpmh { + compatible = "qcom,sde-rsc-rpmh"; + cell-index = <0>; + }; }; qcom,glink-smem-native-xprt-modem@86000000 { From a3ef1aa95792e3c0fb287cc9f46b47144be09264 Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Sat, 6 Nov 2021 23:16:49 +0200 Subject: [PATCH 014/356] arm64: dts: qcom: sdm845-regulator: Fix parent node of RPMh regulators Change the parent node of RPMh regulators from soc to apps_rsc. Remove RPMh mailbox phandle and channel indentifiers. Signed-off-by: Pavel Dubrova --- arch/arm64/boot/dts/qcom/sdm845-bus.dtsi | 3 -- .../arm64/boot/dts/qcom/sdm845-regulator.dtsi | 49 ++----------------- arch/arm64/boot/dts/qcom/sdm845-sde.dtsi | 3 -- 3 files changed, 5 insertions(+), 50 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi b/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi index db1b4ab5034f..49e0f2721113 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-bus.dtsi @@ -28,9 +28,6 @@ "mmss_noc-base", "system_noc-base", "ipa_virt-base", "camnoc_virt-base"; - mbox-names = "apps_rsc", "disp_rsc"; - mboxes = <&apps_rsc 0 &disp_rsc 0>; - /*RSCs*/ rsc_apps: rsc-apps { cell-id = ; diff --git a/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi index 2b7237550710..41c1695433a0 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-regulator.dtsi @@ -22,13 +22,12 @@ }; }; -&soc { - /* RPMh regulators: */ +/* RPMh regulators */ +&apps_rsc { /* PM8998 S1 = VDD_EBI supply */ rpmh-regulator-ebilvl { compatible = "qcom,rpmh-arc-regulator"; - mboxes = <&apps_rsc 0>; qcom,resource-name = "ebi.lvl"; pm8998_s1_level: regulator-s1 { regulator-name = "pm8998_s1_level"; @@ -47,7 +46,6 @@ rpmh-regulator-smpa2 { compatible = "qcom,rpmh-vrm-regulator"; - mboxes = <&apps_rsc 0>; qcom,resource-name = "smpa2"; pm8998_s2: regulator-s2 { regulator-name = "pm8998_s2"; @@ -60,7 +58,6 @@ rpmh-regulator-smpa3 { compatible = "qcom,rpmh-vrm-regulator"; - mboxes = <&apps_rsc 0>; qcom,resource-name = "smpa3"; pm8998_s3: regulator-s3 { regulator-name = "pm8998_s3"; @@ -73,7 +70,6 @@ rpmh-regulator-smpa5 { compatible = "qcom,rpmh-vrm-regulator"; - mboxes = <&apps_rsc 0>; qcom,resource-name = "smpa5"; pm8998_s5: regulator-s5 { regulator-name = "pm8998_s5"; @@ -87,7 +83,6 @@ /* PM8998 S6 = VDD_MX supply */ rpmh-regulator-mxlvl { compatible = "qcom,rpmh-arc-regulator"; - mboxes = <&apps_rsc 0>; qcom,resource-name = "mx.lvl"; pm8998_s6_level: regulator-s6-level { regulator-name = "pm8998_s6_level"; @@ -114,7 +109,6 @@ rpmh-regulator-smpa7 { compatible = "qcom,rpmh-vrm-regulator"; - mboxes = <&apps_rsc 0>; qcom,resource-name = "smpa7"; pm8998_s7: regulator-s7 { regulator-name = "pm8998_s7"; @@ -128,7 +122,6 @@ /* PM8998 S9 + S8 = VDD_CX supply */ rpmh-regulator-cxlvl { compatible = "qcom,rpmh-arc-regulator"; - mboxes = <&apps_rsc 0>; qcom,resource-name = "cx.lvl"; pm8998_s9_level-parent-supply = <&pm8998_s6_level>; pm8998_s9_level_ao-parent-supply = <&pm8998_s6_level_ao>; @@ -160,7 +153,6 @@ rpmh-regulator-ldoa1 { compatible = "qcom,rpmh-vrm-regulator"; - mboxes = <&apps_rsc 0>; qcom,resource-name = "ldoa1"; qcom,regulator-type = "pmic4-ldo"; qcom,supported-modes = @@ -201,7 +193,6 @@ rpmh-regulator-ldoa2 { compatible = "qcom,rpmh-vrm-regulator"; - mboxes = <&apps_rsc 0>; qcom,resource-name = "ldoa2"; qcom,regulator-type = "pmic4-ldo"; qcom,supported-modes = @@ -221,7 +212,6 @@ rpmh-regulator-ldoa3 { compatible = "qcom,rpmh-vrm-regulator"; - mboxes = <&apps_rsc 0>; qcom,resource-name = "ldoa3"; qcom,regulator-type = "pmic4-ldo"; qcom,supported-modes = @@ -241,7 +231,6 @@ /* PM8998 L4 = VDD_SSC_MX supply */ rpmh-regulator-lmxlvl { compatible = "qcom,rpmh-arc-regulator"; - mboxes = <&apps_rsc 0>; qcom,resource-name = "lmx.lvl"; pm8998_l4_level: regulator-l4-level { regulator-name = "pm8998_l4_level"; @@ -253,7 +242,6 @@ rpmh-regulator-ldoa5 { compatible = "qcom,rpmh-vrm-regulator"; - mboxes = <&apps_rsc 0>; qcom,resource-name = "ldoa5"; qcom,regulator-type = "pmic4-ldo"; qcom,supported-modes = @@ -272,7 +260,6 @@ rpmh-regulator-ldoa6 { compatible = "qcom,rpmh-vrm-regulator"; - mboxes = <&apps_rsc 0>; qcom,resource-name = "ldoa6"; qcom,regulator-type = "pmic4-ldo"; qcom,supported-modes = @@ -291,7 +278,6 @@ rpmh-regulator-ldoa7 { compatible = "qcom,rpmh-vrm-regulator"; - mboxes = <&apps_rsc 0>; qcom,resource-name = "ldoa7"; qcom,regulator-type = "pmic4-ldo"; qcom,supported-modes = @@ -310,7 +296,6 @@ rpmh-regulator-ldoa8 { compatible = "qcom,rpmh-vrm-regulator"; - mboxes = <&apps_rsc 0>; qcom,resource-name = "ldoa8"; qcom,regulator-type = "pmic4-ldo"; qcom,supported-modes = @@ -329,7 +314,6 @@ rpmh-regulator-ldoa9 { compatible = "qcom,rpmh-vrm-regulator"; - mboxes = <&apps_rsc 0>; qcom,resource-name = "ldoa9"; qcom,regulator-type = "pmic4-ldo"; qcom,supported-modes = @@ -348,7 +332,6 @@ rpmh-regulator-ldoa10 { compatible = "qcom,rpmh-vrm-regulator"; - mboxes = <&apps_rsc 0>; qcom,resource-name = "ldoa10"; qcom,regulator-type = "pmic4-ldo"; qcom,supported-modes = @@ -367,7 +350,6 @@ rpmh-regulator-ldoa11 { compatible = "qcom,rpmh-vrm-regulator"; - mboxes = <&apps_rsc 0>; qcom,resource-name = "ldoa11"; qcom,regulator-type = "pmic4-ldo"; qcom,supported-modes = @@ -386,7 +368,6 @@ rpmh-regulator-ldoa12 { compatible = "qcom,rpmh-vrm-regulator"; - mboxes = <&apps_rsc 0>; qcom,resource-name = "ldoa12"; qcom,regulator-type = "pmic4-ldo"; qcom,supported-modes = @@ -405,7 +386,6 @@ rpmh-regulator-ldoa13 { compatible = "qcom,rpmh-vrm-regulator"; - mboxes = <&apps_rsc 0>; qcom,resource-name = "ldoa13"; qcom,regulator-type = "pmic4-ldo"; qcom,supported-modes = @@ -424,7 +404,6 @@ rpmh-regulator-ldoa14 { compatible = "qcom,rpmh-vrm-regulator"; - mboxes = <&apps_rsc 0>; qcom,resource-name = "ldoa14"; qcom,regulator-type = "pmic4-ldo"; qcom,supported-modes = @@ -446,7 +425,6 @@ rpmh-regulator-ldoa15 { compatible = "qcom,rpmh-vrm-regulator"; - mboxes = <&apps_rsc 0>; qcom,resource-name = "ldoa15"; qcom,regulator-type = "pmic4-ldo"; qcom,supported-modes = @@ -465,7 +443,6 @@ rpmh-regulator-ldoa16 { compatible = "qcom,rpmh-vrm-regulator"; - mboxes = <&apps_rsc 0>; qcom,resource-name = "ldoa16"; qcom,regulator-type = "pmic4-ldo"; qcom,supported-modes = @@ -484,7 +461,6 @@ rpmh-regulator-ldoa17 { compatible = "qcom,rpmh-vrm-regulator"; - mboxes = <&apps_rsc 0>; qcom,resource-name = "ldoa17"; qcom,regulator-type = "pmic4-ldo"; qcom,supported-modes = @@ -503,7 +479,6 @@ rpmh-regulator-ldoa18 { compatible = "qcom,rpmh-vrm-regulator"; - mboxes = <&apps_rsc 0>; qcom,resource-name = "ldoa18"; qcom,regulator-type = "pmic4-ldo"; qcom,supported-modes = @@ -522,7 +497,6 @@ rpmh-regulator-ldoa19 { compatible = "qcom,rpmh-vrm-regulator"; - mboxes = <&apps_rsc 0>; qcom,resource-name = "ldoa19"; qcom,regulator-type = "pmic4-ldo"; qcom,supported-modes = @@ -541,7 +515,6 @@ rpmh-regulator-ldoa20 { compatible = "qcom,rpmh-vrm-regulator"; - mboxes = <&apps_rsc 0>; qcom,resource-name = "ldoa20"; qcom,regulator-type = "pmic4-ldo"; qcom,supported-modes = @@ -560,7 +533,6 @@ rpmh-regulator-ldoa21 { compatible = "qcom,rpmh-vrm-regulator"; - mboxes = <&apps_rsc 0>; qcom,resource-name = "ldoa21"; qcom,regulator-type = "pmic4-ldo"; qcom,supported-modes = @@ -579,7 +551,6 @@ rpmh-regulator-ldoa22 { compatible = "qcom,rpmh-vrm-regulator"; - mboxes = <&apps_rsc 0>; qcom,resource-name = "ldoa22"; qcom,regulator-type = "pmic4-ldo"; qcom,supported-modes = @@ -598,7 +569,6 @@ rpmh-regulator-ldoa23 { compatible = "qcom,rpmh-vrm-regulator"; - mboxes = <&apps_rsc 0>; qcom,resource-name = "ldoa23"; qcom,regulator-type = "pmic4-ldo"; qcom,supported-modes = @@ -617,7 +587,6 @@ rpmh-regulator-ldoa24 { compatible = "qcom,rpmh-vrm-regulator"; - mboxes = <&apps_rsc 0>; qcom,resource-name = "ldoa24"; qcom,regulator-type = "pmic4-ldo"; qcom,supported-modes = @@ -637,7 +606,6 @@ rpmh-regulator-ldoa25 { compatible = "qcom,rpmh-vrm-regulator"; - mboxes = <&apps_rsc 0>; qcom,resource-name = "ldoa25"; qcom,regulator-type = "pmic4-ldo"; qcom,supported-modes = @@ -656,7 +624,6 @@ rpmh-regulator-ldoa26 { compatible = "qcom,rpmh-vrm-regulator"; - mboxes = <&apps_rsc 0>; qcom,resource-name = "ldoa26"; qcom,regulator-type = "pmic4-ldo"; qcom,supported-modes = @@ -679,7 +646,6 @@ /* PM8998 L27 = VDD_SSC_CX supply */ rpmh-regulator-lcxlvl { compatible = "qcom,rpmh-arc-regulator"; - mboxes = <&apps_rsc 0>; qcom,resource-name = "lcx.lvl"; pm8998_l27_level: regulator-l27-level { regulator-name = "pm8998_l27_level"; @@ -691,7 +657,6 @@ rpmh-regulator-ldoa28 { compatible = "qcom,rpmh-vrm-regulator"; - mboxes = <&apps_rsc 0>; qcom,resource-name = "ldoa28"; qcom,regulator-type = "pmic4-ldo"; qcom,supported-modes = @@ -710,7 +675,6 @@ rpmh-regulator-vsa1 { compatible = "qcom,rpmh-vrm-regulator"; - mboxes = <&apps_rsc 0>; qcom,resource-name = "vsa1"; pm8998_lvs1: regulator-lvs1 { regulator-name = "pm8998_lvs1"; @@ -722,7 +686,6 @@ rpmh-regulator-vsa2 { compatible = "qcom,rpmh-vrm-regulator"; - mboxes = <&apps_rsc 0>; qcom,resource-name = "vsa2"; pm8998_lvs2: regulator-lvs2 { regulator-name = "pm8998_lvs2"; @@ -734,7 +697,6 @@ rpmh-regulator-bobb1 { compatible = "qcom,rpmh-vrm-regulator"; - mboxes = <&apps_rsc 0>; qcom,resource-name = "bobb1"; qcom,regulator-type = "pmic4-bob"; qcom,send-defaults; @@ -761,7 +723,6 @@ /* PM8005 S1 + S4 = 2 phase VDD_GFX supply */ rpmh-regulator-gfxlvl { compatible = "qcom,rpmh-arc-regulator"; - mboxes = <&apps_rsc 0>; qcom,resource-name = "gfx.lvl"; pm8005_s1_level: regulator-s1-level { regulator-name = "pm8005_s1_level"; @@ -778,7 +739,6 @@ /* PM8005 S2 = VDD_MODEM supply */ rpmh-regulator-msslvl { compatible = "qcom,rpmh-arc-regulator"; - mboxes = <&apps_rsc 0>; qcom,resource-name = "mss.lvl"; pm8005_s2_level: regulator-s2-level { regulator-name = "pm8005_s2_level"; @@ -790,7 +750,6 @@ rpmh-regulator-smpc3 { compatible = "qcom,rpmh-vrm-regulator"; - mboxes = <&apps_rsc 0>; qcom,resource-name = "smpc3"; pm8005_s3: regulator-s3 { regulator-name = "pm8005_s3"; @@ -800,9 +759,11 @@ qcom,init-voltage = <600000>; }; }; +}; +&soc { refgen: refgen-regulator@ff1000 { - compatible = "qcom,refgen-regulator"; + compatible = "qcom,refgen-sdm845-regulator"; reg = <0xff1000 0x60>; regulator-name = "refgen"; regulator-enable-ramp-delay = <5>; diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi index eba11a158323..c3c0c287120b 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi @@ -290,9 +290,6 @@ qcom,sde-dram-channels = <2>; - mboxes = <&disp_rsc 0>; - mbox-names = "disp_rsc"; - /* data and reg bus scale settings */ qcom,sde-data-bus { qcom,msm-bus,name = "disp_rsc_mnoc"; From fe7b65dfd837aec82035b846567c464d32781d70 Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Sat, 6 Nov 2021 23:56:21 +0200 Subject: [PATCH 015/356] arm64: dts: qcom: sdm845-sde: Update pixel_parent clock Clock names have been changed as of https://source.codeaurora.org/quic/la/platform/vendor/opensource/display-drivers commit cbe6ebb ("disp: pll: update clk names for lagoon target"). DP_LINK_CLK_DIVSEL_TEN -> DP_PHY_PLL_LINK_CLK DP_VCO_DIVIDED_CLK_SRC_MUX -> DP_PHY_PLL_VCO_DIV_CLK Signed-off-by: Pavel Dubrova --- arch/arm64/boot/dts/qcom/sdm845-sde.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi index c3c0c287120b..918bc3ed1851 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi @@ -582,7 +582,7 @@ <&clock_dispcc DISP_CC_MDSS_DP_PIXEL_CLK>, <&clock_dispcc DISP_CC_MDSS_DP_CRYPTO_CLK>, <&clock_dispcc DISP_CC_MDSS_DP_PIXEL_CLK_SRC>, - <&mdss_dp_pll DP_VCO_DIVIDED_CLK_SRC_MUX>; + <&mdss_dp_pll DP_PHY_PLL_VCO_DIV_CLK>; clock-names = "core_aux_clk", "core_usb_ref_clk_src", "core_usb_ref_clk", "core_usb_cfg_ahb_clk", "core_usb_pipe_clk", "ctrl_link_clk", From c606fb752350dd1cb2404f9110c176179a3b99c5 Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Sun, 7 Nov 2021 00:39:54 +0200 Subject: [PATCH 016/356] arm64: dts: qcom: sdm845: Add PDC ranges Specify the PDC pin offset and the number of PDC ports. Also update compatible string. Signed-off-by: Pavel Dubrova --- arch/arm64/boot/dts/qcom/sdm845-v2.dtsi | 13 +++---------- arch/arm64/boot/dts/qcom/sdm845.dtsi | 5 +++-- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi index 73f1e70d2bb6..428e0dc3d556 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi @@ -15,7 +15,9 @@ /delete-property/ qcom,sdr104-wa; }; -/delete-node/ &pdc; +&pdc { + qcom,pdc-ranges = <0 480 94>, <94 609 15>, <115 630 7>; +}; &tlmm { compatible = "qcom,sdm845-pinctrl-v2"; @@ -58,15 +60,6 @@ compatible = "syscon"; reg = <0x5091008 0x4>; }; - - pdc: interrupt-controller@0xb220000{ - compatible = "qcom,pdc-sdm845-v2"; - reg = <0xb220000 0x400>; - #interrupt-cells = <3>; - interrupt-parent = <&intc>; - interrupt-controller; - }; - }; &pil_modem { diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index 75f427ab3df0..f49ccec80235 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -799,9 +799,10 @@ ignored-save-restore-irqs = <38>; }; - pdc: interrupt-controller@b220000{ - compatible = "qcom,pdc-sdm845"; + pdc: interrupt-controller@b220000 { + compatible = "qcom,sdm845-pdc"; reg = <0xb220000 0x400>; + qcom,pdc-ranges = <0 480 94>, <94 609 15>, <119 634 7>; #interrupt-cells = <3>; interrupt-parent = <&intc>; interrupt-controller; From db7724aa20baea955f20eef9b102a0720a317908 Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Sun, 7 Nov 2021 13:44:00 +0200 Subject: [PATCH 017/356] arm64: dts: qcom: sdm845: Update entries for SMP2P Update entries for Shared Memory Point to Point(SMP2P) support protocol for kernel 4.19. Add device node for the smp2p sleepstate entry and the device node for the smp2p sleep driver to notify power state changes. Signed-off-by: Pavel Dubrova --- arch/arm64/boot/dts/qcom/sdm845-smp2p.dtsi | 439 ++++++--------------- arch/arm64/boot/dts/qcom/sdm845.dtsi | 137 ++++--- 2 files changed, 220 insertions(+), 356 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845-smp2p.dtsi b/arch/arm64/boot/dts/qcom/sdm845-smp2p.dtsi index 8882ed04d872..8901a3792132 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-smp2p.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-smp2p.dtsi @@ -6,333 +6,148 @@ #include &soc { - qcom,smp2p-modem@1799000c { + qcom,smp2p-modem { compatible = "qcom,smp2p"; - reg = <0x1799000c 0x4>; - qcom,remote-pid = <1>; - qcom,irq-bitmask = <0x4000>; + qcom,smem = <435>, <428>; interrupts = ; - }; + mboxes = <&apss_shared 14>; + qcom,local-pid = <0>; + qcom,remote-pid = <1>; - qcom,smp2p-adsp@1799000c { + 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"; - reg = <0x1799000c 0x4>; - qcom,remote-pid = <2>; - qcom,irq-bitmask = <0x400>; + qcom,smem = <443>, <429>; interrupts = ; - }; - - qcom,smp2p-dsps@1799000c { - compatible = "qcom,smp2p"; - reg = <0x1799000c 0x4>; - qcom,remote-pid = <3>; - qcom,irq-bitmask = <0x4000000>; - interrupts = ; - }; - - qcom,smp2p-cdsp@1799000c { - compatible = "qcom,smp2p"; - reg = <0x1799000c 0x4>; - qcom,remote-pid = <5>; - qcom,irq-bitmask = <0x40>; - interrupts = ; - }; - - - smp2pgpio_smp2p_15_in: qcom,smp2pgpio-smp2p-15-in { - compatible = "qcom,smp2pgpio"; - qcom,entry-name = "smp2p"; - qcom,remote-pid = <15>; - qcom,is-inbound; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - }; - - qcom,smp2pgpio_test_smp2p_15_in { - compatible = "qcom,smp2pgpio_test_smp2p_15_in"; - gpios = <&smp2pgpio_smp2p_15_in 0 0>; - }; - - smp2pgpio_smp2p_15_out: qcom,smp2pgpio-smp2p-15-out { - compatible = "qcom,smp2pgpio"; - qcom,entry-name = "smp2p"; - qcom,remote-pid = <15>; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - }; - - qcom,smp2pgpio_test_smp2p_15_out { - compatible = "qcom,smp2pgpio_test_smp2p_15_out"; - gpios = <&smp2pgpio_smp2p_15_out 0 0>; - }; - - smp2pgpio_smp2p_1_in: qcom,smp2pgpio-smp2p-1-in { - compatible = "qcom,smp2pgpio"; - qcom,entry-name = "smp2p"; - qcom,remote-pid = <1>; - qcom,is-inbound; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - }; - - qcom,smp2pgpio_test_smp2p_1_in { - compatible = "qcom,smp2pgpio_test_smp2p_1_in"; - gpios = <&smp2pgpio_smp2p_1_in 0 0>; - }; - - smp2pgpio_smp2p_1_out: qcom,smp2pgpio-smp2p-1-out { - compatible = "qcom,smp2pgpio"; - qcom,entry-name = "smp2p"; - qcom,remote-pid = <1>; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - }; - - qcom,smp2pgpio_test_smp2p_1_out { - compatible = "qcom,smp2pgpio_test_smp2p_1_out"; - gpios = <&smp2pgpio_smp2p_1_out 0 0>; - }; - - smp2pgpio_smp2p_2_in: qcom,smp2pgpio-smp2p-2-in { - compatible = "qcom,smp2pgpio"; - qcom,entry-name = "smp2p"; + mboxes = <&apss_shared 10>; + qcom,local-pid = <0>; qcom,remote-pid = <2>; - qcom,is-inbound; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - }; - - qcom,smp2pgpio_test_smp2p_2_in { - compatible = "qcom,smp2pgpio_test_smp2p_2_in"; - gpios = <&smp2pgpio_smp2p_2_in 0 0>; - }; - - smp2pgpio_smp2p_2_out: qcom,smp2pgpio-smp2p-2-out { - compatible = "qcom,smp2pgpio"; - qcom,entry-name = "smp2p"; - qcom,remote-pid = <2>; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - }; - - qcom,smp2pgpio_test_smp2p_2_out { - compatible = "qcom,smp2pgpio_test_smp2p_2_out"; - gpios = <&smp2pgpio_smp2p_2_out 0 0>; - }; - - smp2pgpio_smp2p_3_in: qcom,smp2pgpio-smp2p-3-in { - compatible = "qcom,smp2pgpio"; - qcom,entry-name = "smp2p"; - qcom,remote-pid = <3>; - qcom,is-inbound; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - }; - - qcom,smp2pgpio_test_smp2p_3_in { - compatible = "qcom,smp2pgpio_test_smp2p_3_in"; - gpios = <&smp2pgpio_smp2p_3_in 0 0>; - }; - - smp2pgpio_smp2p_3_out: qcom,smp2pgpio-smp2p-3-out { - compatible = "qcom,smp2pgpio"; - qcom,entry-name = "smp2p"; - qcom,remote-pid = <3>; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - }; - - qcom,smp2pgpio_test_smp2p_3_out { - compatible = "qcom,smp2pgpio_test_smp2p_3_out"; - gpios = <&smp2pgpio_smp2p_3_out 0 0>; - }; - - smp2pgpio_smp2p_5_in: qcom,smp2pgpio-smp2p-5-in { - compatible = "qcom,smp2pgpio"; - qcom,entry-name = "smp2p"; - qcom,remote-pid = <5>; - qcom,is-inbound; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - }; - - qcom,smp2pgpio_test_smp2p_5_in { - compatible = "qcom,smp2pgpio_test_smp2p_5_in"; - gpios = <&smp2pgpio_smp2p_5_in 0 0>; - }; - - smp2pgpio_smp2p_5_out: qcom,smp2pgpio-smp2p-5-out { - compatible = "qcom,smp2pgpio"; - qcom,entry-name = "smp2p"; - qcom,remote-pid = <5>; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - }; - - qcom,smp2pgpio_test_smp2p_5_out { - compatible = "qcom,smp2pgpio_test_smp2p_5_out"; - gpios = <&smp2pgpio_smp2p_5_out 0 0>; - }; - smp2pgpio_sleepstate_3_out: qcom,smp2pgpio-sleepstate-gpio-3-out { - compatible = "qcom,smp2pgpio"; - qcom,entry-name = "sleepstate"; - qcom,remote-pid = <3>; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - }; + adsp_smp2p_out: master-kernel { + qcom,entry-name = "master-kernel"; + #qcom,smem-state-cells = <1>; + }; - qcom,smp2pgpio-sleepstate-3-out { - compatible = "qcom,smp2pgpio_sleepstate_3_out"; - gpios = <&smp2pgpio_sleepstate_3_out 0 0>; - }; + adsp_smp2p_in: slave-kernel { + qcom,entry-name = "slave-kernel"; + interrupt-controller; + #interrupt-cells = <2>; + }; - /* ssr - inbound entry from mss */ - smp2pgpio_ssr_smp2p_1_in: qcom,smp2pgpio-ssr-smp2p-1-in { - compatible = "qcom,smp2pgpio"; - qcom,entry-name = "slave-kernel"; - qcom,remote-pid = <1>; - qcom,is-inbound; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - }; + smp2p_rdbg2_out: qcom,smp2p-rdbg2-out { + qcom,entry-name = "rdbg"; + #qcom,smem-state-cells = <1>; + }; - /* ssr - outbound entry to mss */ - smp2pgpio_ssr_smp2p_1_out: qcom,smp2pgpio-ssr-smp2p-1-out { - compatible = "qcom,smp2pgpio"; - qcom,entry-name = "master-kernel"; - qcom,remote-pid = <1>; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; + smp2p_rdbg2_in: qcom,smp2p-rdbg2-in { + qcom,entry-name = "rdbg"; + interrupt-controller; + #interrupt-cells = <2>; + }; }; - /* ssr - inbound entry from lpass */ - smp2pgpio_ssr_smp2p_2_in: qcom,smp2pgpio-ssr-smp2p-2-in { - compatible = "qcom,smp2pgpio"; - qcom,entry-name = "slave-kernel"; - qcom,remote-pid = <2>; - qcom,is-inbound; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - }; - - /* ssr - outbound entry to lpass */ - smp2pgpio_ssr_smp2p_2_out: qcom,smp2pgpio-ssr-smp2p-2-out { - compatible = "qcom,smp2pgpio"; - qcom,entry-name = "master-kernel"; - qcom,remote-pid = <2>; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - }; - - /* ssr - inbound entry from ssc */ - smp2pgpio_ssr_smp2p_3_in: qcom,smp2pgpio-ssr-smp2p-3-in { - compatible = "qcom,smp2pgpio"; - qcom,entry-name = "slave-kernel"; - qcom,remote-pid = <3>; - qcom,is-inbound; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - }; - - /* ssr - outbound entry to ssc */ - smp2pgpio_ssr_smp2p_3_out: qcom,smp2pgpio-ssr-smp2p-3-out { - compatible = "qcom,smp2pgpio"; - qcom,entry-name = "master-kernel"; + qcom,smp2p-dsps { + compatible = "qcom,smp2p"; + qcom,smem = <481>, <430>; + interrupts = ; + mboxes = <&apss_shared 26>; + qcom,local-pid = <0>; qcom,remote-pid = <3>; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - }; - /* ssr - inbound entry from cdsp */ - smp2pgpio_ssr_smp2p_5_in: qcom,smp2pgpio-ssr-smp2p-5-in { - compatible = "qcom,smp2pgpio"; - qcom,entry-name = "slave-kernel"; - qcom,remote-pid = <5>; - qcom,is-inbound; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - }; - - /* ssr - outbound entry to cdsp */ - smp2pgpio_ssr_smp2p_5_out: qcom,smp2pgpio-ssr-smp2p-5-out { - compatible = "qcom,smp2pgpio"; - qcom,entry-name = "master-kernel"; + dsps_smp2p_out: master-kernel { + #address-cells = <0>; + qcom,entry-name = "master-kernel"; + #qcom,smem-state-cells = <1>; + }; + + dsps_smp2p_in: slave-kernel { + #address-cells = <0>; + qcom,entry-name = "slave-kernel"; + interrupt-controller; + #interrupt-cells = <2>; + }; + + sleepstate_smp2p_out: sleepstate-out { + #address-cells = <0>; + qcom,entry-name = "sleepstate"; + #qcom,smem-state-cells = <1>; + }; + + sleepstate_smp2p_in: qcom,sleepstate-in { + #address-cells = <0>; + qcom,entry-name = "sleepstate_see"; + interrupt-controller; + #interrupt-cells = <2>; + }; + }; + + qcom,smp2p-cdsp { + compatible = "qcom,smp2p"; + qcom,smem = <94>, <432>; + interrupts = ; + mboxes = <&apss_shared 6>; + qcom,local-pid = <0>; qcom,remote-pid = <5>; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - }; - /* ipa - outbound entry to mss */ - smp2pgpio_ipa_1_out: qcom,smp2pgpio-ipa-1-out { - compatible = "qcom,smp2pgpio"; - qcom,entry-name = "ipa"; - qcom,remote-pid = <1>; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - }; - - /* ipa - inbound entry from mss */ - smp2pgpio_ipa_1_in: qcom,smp2pgpio-ipa-1-in { - compatible = "qcom,smp2pgpio"; - qcom,entry-name = "ipa"; - qcom,remote-pid = <1>; - qcom,is-inbound; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; - }; - - /* wlan - inbound entry from mss/WLAN PD */ - smp2pgpio_wlan_1_in: qcom,smp2pgpio-wlan-1-in { - compatible = "qcom,smp2pgpio"; - qcom,entry-name = "wlan"; - qcom,remote-pid = <1>; - qcom,is-inbound; - gpio-controller; - #gpio-cells = <2>; - interrupt-controller; - #interrupt-cells = <2>; + cdsp_smp2p_out: master-kernel { + #address-cells = <0>; + qcom,entry-name = "master-kernel"; + #qcom,smem-state-cells = <1>; + }; + + cdsp_smp2p_in: slave-kernel { + #address-cells = <0>; + qcom,entry-name = "slave-kernel"; + interrupt-controller; + #interrupt-cells = <2>; + }; + + smp2p_qvrexternal5_out: qcom,smp2p-qvrexternal5-out { + #address-cells = <0>; + qcom,entry-name = "qvrexternal"; + #qcom,smem-state-cells = <1>; + }; + + smp2p_rdbg5_out: qcom,smp2p-rdbg5-out { + #address-cells = <0>; + qcom,entry-name = "rdbg"; + #qcom,smem-state-cells = <1>; + }; + + smp2p_rdbg5_in: qcom,smp2p-rdbg5-in { + #address-cells = <0>; + qcom,entry-name = "rdbg"; + interrupt-controller; + #interrupt-cells = <2>; + }; }; }; diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index f49ccec80235..7dd7f4de6666 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -1554,7 +1554,6 @@ "gpll0_mss_clk", "snoc_axi_clk", "mnoc_axi_clk"; - interrupts = <0 266 1>; vdd_cx-supply = <&pm8998_s9_level>; vdd_cx-voltage = ; vdd_mx-supply = <&pm8998_s6_level>; @@ -1575,15 +1574,24 @@ memory-region = <&pil_modem_mem>; qcom,mem-protect-id = <0xF>; - /* GPIO inputs from mss */ - qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_1_in 0 0>; - qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_1_in 1 0>; - qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_1_in 2 0>; - qcom,gpio-stop-ack = <&smp2pgpio_ssr_smp2p_1_in 3 0>; - qcom,gpio-shutdown-ack = <&smp2pgpio_ssr_smp2p_1_in 7 0>; - - /* GPIO output to mss */ - qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_1_out 0 0>; + /* Inputs from mss */ + interrupts-extended = <&intc GIC_SPI 266 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"; mboxes = <&qmp_aop 0>; mbox-names = "mss-pil"; @@ -1596,7 +1604,6 @@ qcom,lpass@17300000 { compatible = "qcom,pil-tz-generic"; reg = <0x17300000 0x00100>; - interrupts = <0 162 1>; vdd_cx-supply = <&pm8998_s9_level>; qcom,proxy-reg-names = "vdd_cx"; @@ -1616,14 +1623,22 @@ qcom,signal-aop; memory-region = <&pil_adsp_mem>; - /* GPIO inputs from lpass */ - qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_2_in 0 0>; - qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_2_in 2 0>; - qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_2_in 1 0>; - qcom,gpio-stop-ack = <&smp2pgpio_ssr_smp2p_2_in 3 0>; + /* Inputs from lpass */ + interrupts-extended = <&intc GIC_SPI 162 1>, + <&adsp_smp2p_in 0 0>, + <&adsp_smp2p_in 2 0>, + <&adsp_smp2p_in 1 0>, + <&adsp_smp2p_in 3 0>; + + interrupt-names = "qcom,wdog", + "qcom,err-fatal", + "qcom,proxy-unvote", + "qcom,err-ready", + "qcom,stop-ack"; - /* GPIO output to lpass */ - qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_2_out 0 0>; + /* 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"; @@ -1632,7 +1647,6 @@ qcom,ssc@5c00000 { compatible = "qcom,pil-tz-generic"; reg = <0x5c00000 0x4000>; - interrupts = <0 494 1>; vdd_cx-supply = <&pm8998_l27_level>; qcom,vdd_cx-uV-uA = ; @@ -1655,14 +1669,22 @@ status = "ok"; memory-region = <&pil_slpi_mem>; - /* GPIO inputs from ssc */ - qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_3_in 0 0>; - qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_3_in 2 0>; - qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_3_in 1 0>; - qcom,gpio-stop-ack = <&smp2pgpio_ssr_smp2p_3_in 3 0>; + /* Inputs from ssc */ + interrupts-extended = <&intc GIC_SPI 494 1>, + <&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"; - /* GPIO output to ssc */ - qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_3_out 0 0>; + /* 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"; @@ -1774,7 +1796,6 @@ qcom,turing@8300000 { compatible = "qcom,pil-tz-generic"; reg = <0x8300000 0x100000>; - interrupts = <0 578 1>; vdd_cx-supply = <&pm8998_s9_level>; qcom,proxy-reg-names = "vdd_cx"; @@ -1793,15 +1814,22 @@ qcom,signal-aop; memory-region = <&pil_cdsp_mem>; - /* GPIO inputs from turing */ - qcom,gpio-err-fatal = <&smp2pgpio_ssr_smp2p_5_in 0 0>; - qcom,gpio-proxy-unvote = <&smp2pgpio_ssr_smp2p_5_in 2 0>; - qcom,gpio-err-ready = <&smp2pgpio_ssr_smp2p_5_in 1 0>; - qcom,gpio-stop-ack = <&smp2pgpio_ssr_smp2p_5_in 3 0>; + /* Inputs from turing */ + interrupts-extended = <&intc GIC_SPI 578 1>, + <&cdsp_smp2p_in 0 0>, + <&cdsp_smp2p_in 2 0>, + <&cdsp_smp2p_in 1 0>, + <&cdsp_smp2p_in 3 0>; - /* GPIO output to turing*/ - qcom,gpio-force-stop = <&smp2pgpio_ssr_smp2p_5_out 0 0>; - status = "ok"; + 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"; @@ -1818,6 +1846,14 @@ clock-frequency = <32768>; }; + 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"; @@ -2207,6 +2243,12 @@ #mbox-cells = <1>; }; + apss_shared: mailbox@17990000 { + compatible = "qcom,sdm845-apss-shared"; + reg = <0x17990000 0x1000>; + #mbox-cells = <1>; + }; + apps_rsc: rsc@179c0000 { compatible = "qcom,rpmh-rsc"; label = "apps_rsc"; @@ -2835,15 +2877,17 @@ 0x400 /* uc_event_ring_size; */ >; - /* smp2p gpio information */ - qcom,smp2pgpio_map_ipa_1_out { - compatible = "qcom,smp2pgpio-map-ipa-1-out"; - gpios = <&smp2pgpio_ipa_1_out 0 0>; + /* 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,smp2pgpio_map_ipa_1_in { - compatible = "qcom,smp2pgpio-map-ipa-1-in"; - gpios = <&smp2pgpio_ipa_1_in 0 0>; + 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 { @@ -3146,8 +3190,6 @@ <0 424 0 /* CE10 */ >, <0 425 0 /* CE11 */ >; qcom,wlan-msa-memory = <0x100000>; - qcom,gpio-force-fatal-error = <&smp2pgpio_wlan_1_in 0 0>; - qcom,gpio-early-crash-ind = <&smp2pgpio_wlan_1_in 1 0>; vdd-0.8-cx-mx-supply = <&pm8998_l5>; vdd-1.8-xo-supply = <&pm8998_l7>; @@ -3155,6 +3197,13 @@ vdd-3.3-ch0-supply = <&pm8998_l25>; qcom,vdd-0.8-cx-mx-config = <800000 800000>; qcom,vdd-3.3-ch0-config = <3104000 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"; + }; }; qmi-tmd-devices { From f0bce7738991518c02d68b92361f97554597684a Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Sun, 7 Nov 2021 14:16:43 +0200 Subject: [PATCH 018/356] arm64: dts: qcom: sdm845: Update entries for LLCC Update entries for Last Level Cache Controller(LLCC) for kernel 4.19. Signed-off-by: Pavel Dubrova --- arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi | 1 - arch/arm64/boot/dts/qcom/sdm845-sde.dtsi | 1 - arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi | 1 - arch/arm64/boot/dts/qcom/sdm845.dtsi | 31 ++++------------------- 4 files changed, 5 insertions(+), 29 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi b/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi index 07f2f0164b67..4cdf6772be54 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi @@ -119,7 +119,6 @@ /* GPU related llc slices */ cache-slice-names = "gpu", "gpuhtw"; - cache-slices = <&llcc 12>, <&llcc 11>; qcom,gpu-coresights { #address-cells = <1>; diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi index 918bc3ed1851..d89c6a973a00 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi @@ -384,7 +384,6 @@ qcom,mdss-sbuf-headroom = <20>; cache-slice-names = "rotator"; - cache-slices = <&llcc 4>; /* reg bus scale settings */ rot_reg: qcom,rot-reg-bus { diff --git a/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi b/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi index 04aaf7e2f15f..982065d6a04b 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi @@ -16,7 +16,6 @@ /* LLCC Info */ cache-slice-names = "vidsc0", "vidsc1"; - cache-slices = <&llcc 2>, <&llcc 3>; /* Supply */ venus-supply = <&venus_gdsc>; diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index 7dd7f4de6666..25997891a068 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -2148,32 +2148,11 @@ "l3-scu-faultirq"; }; - qcom,llcc@1100000 { - compatible = "qcom,llcc-core", "syscon", "simple-mfd"; - reg = <0x1100000 0x250000>; - reg-names = "llcc_base"; - qcom,llcc-banks-off = <0x0 0x80000 0x100000 0x180000>; - qcom,llcc-broadcast-off = <0x200000>; - - llcc: qcom,sdm845-llcc { - compatible = "qcom,sdm845-llcc"; - #cache-cells = <1>; - max-slices = <32>; - }; - - qcom,llcc-perfmon { - compatible = "qcom,llcc-perfmon"; - }; - - qcom,llcc-erp { - compatible = "qcom,llcc-erp"; - interrupt-names = "ecc_irq"; - interrupts = ; - }; - - qcom,llcc-amon { - compatible = "qcom,llcc-amon"; - }; + cache-controller@1100000 { + compatible = "qcom,sdm845-llcc"; + reg = <0x01100000 0x200000>, <0x01300000 0x50000>; + reg-names = "llcc_base", "llcc_broadcast_base"; + cap-based-alloc-and-pwr-collapse; LLCC_1: llcc_1_dcache { qcom,dump-size = <0x1141c0>; From 08acb56c94cda1b52397435c80166f9d011ed4cd Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Sun, 7 Nov 2021 16:08:23 +0200 Subject: [PATCH 019/356] arm64: dts: qcom: sdm845: Add Glink RPMSG nodes Add GLINK nodes for Modem, ADSP, SLPI, CDSP and SPSS to enable communication to those remote procs. This change also includes intent configurations for the glink_ssr and IPCRTR channels. Remove deprecated Signed-off-by: Pavel Dubrova --- arch/arm64/boot/dts/qcom/sdm845.dtsi | 439 +++++++++++++++------------ 1 file changed, 250 insertions(+), 189 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index 25997891a068..4b71b6f6f8a4 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -2194,21 +2194,6 @@ hwlocks = <&tcsr_mutex 3>; }; - qcom,glink-mailbox-xprt-spss@1885008 { - compatible = "qcom,glink-mailbox-xprt"; - reg = <0x1885008 0x8>, - <0x1885010 0x4>, - <0x188501c 0x4>, - <0x1886008 0x4>; - reg-names = "mbox-loc-addr", "mbox-loc-size", "irq-reg-base", - "irq-rx-reset"; - qcom,irq-mask = <0x1>; - interrupts = <0 348 4>; - label = "spss"; - qcom,tx-ring-size = <0x400>; - qcom,rx-ring-size = <0x400>; - }; - qmp_aop: qcom,qmp-aop@c300000 { compatible = "qcom,qmp-mbox"; label = "aop"; @@ -2284,187 +2269,263 @@ }; }; - qcom,glink-smem-native-xprt-modem@86000000 { - compatible = "qcom,glink-smem-native-xprt"; - reg = <0x86000000 0x200000>, - <0x1799000c 0x4>; - reg-names = "smem", "irq-reg-base"; - qcom,irq-mask = <0x1000>; - interrupts = ; - label = "mpss"; + sp_scsr: mailbox@188501c { + compatible = "qcom,sdm845-spcs-global"; + reg = <0x188501c 0x4>; + #mbox-cells = <1>; }; - qcom,glink-smem-native-xprt-adsp@86000000 { - compatible = "qcom,glink-smem-native-xprt"; - reg = <0x86000000 0x200000>, - <0x1799000c 0x4>; - reg-names = "smem", "irq-reg-base"; - qcom,irq-mask = <0x100>; - interrupts = ; - label = "lpass"; - cpu-affinity = <1 2>; - qcom,qos-config = <&glink_qos_adsp>; - qcom,ramp-time = <0xaf>; - }; - - glink_qos_adsp: qcom,glink-qos-config-adsp { - compatible = "qcom,glink-qos-config"; - qcom,flow-info = <0x3c 0x0>, - <0x3c 0x0>, - <0x3c 0x0>, - <0x3c 0x0>; - qcom,mtu-size = <0x800>; - qcom,tput-stats-cycle = <0xa>; - }; - - qcom,glink-smem-native-xprt-dsps@86000000 { - compatible = "qcom,glink-smem-native-xprt"; - reg = <0x86000000 0x200000>, - <0x1799000c 0x4>; - reg-names = "smem", "irq-reg-base"; - qcom,irq-mask = <0x1000000>; - interrupts = ; - label = "dsps"; - }; - - glink_spi_xprt_wdsp: qcom,glink-spi-xprt-wdsp { - compatible = "qcom,glink-spi-xprt"; - label = "wdsp"; - qcom,remote-fifo-config = <&glink_fifo_wdsp>; - qcom,qos-config = <&glink_qos_wdsp>; - qcom,ramp-time = <0x10>, - <0x20>, - <0x30>, - <0x40>; - }; - - glink_fifo_wdsp: qcom,glink-fifo-config-wdsp { - compatible = "qcom,glink-fifo-config"; - qcom,out-read-idx-reg = <0x12000>; - qcom,out-write-idx-reg = <0x12004>; - qcom,in-read-idx-reg = <0x1200C>; - qcom,in-write-idx-reg = <0x12010>; - }; - - glink_qos_wdsp: qcom,glink-qos-config-wdsp { - compatible = "qcom,glink-qos-config"; - qcom,flow-info = <0x80 0x0>, - <0x70 0x1>, - <0x60 0x2>, - <0x50 0x3>; - qcom,mtu-size = <0x800>; - qcom,tput-stats-cycle = <0xa>; - }; - - qcom,glink-smem-native-xprt-cdsp@86000000 { - compatible = "qcom,glink-smem-native-xprt"; - reg = <0x86000000 0x200000>, - <0x1799000c 0x4>; - reg-names = "smem", "irq-reg-base"; - qcom,irq-mask = <0x10>; - interrupts = ; - label = "cdsp"; - }; - - glink_mpss: qcom,glink-ssr-modem { - compatible = "qcom,glink_ssr"; - label = "modem"; - qcom,edge = "mpss"; - qcom,notify-edges = <&glink_lpass>, <&glink_dsps>, - <&glink_cdsp>, <&glink_spss>; - qcom,xprt = "smem"; - }; - - glink_lpass: qcom,glink-ssr-adsp { - compatible = "qcom,glink_ssr"; - label = "adsp"; - qcom,edge = "lpass"; - qcom,notify-edges = <&glink_mpss>, <&glink_dsps>, <&glink_cdsp>; - qcom,xprt = "smem"; - }; - - glink_dsps: qcom,glink-ssr-dsps { - compatible = "qcom,glink_ssr"; - label = "slpi"; - qcom,edge = "dsps"; - qcom,notify-edges = <&glink_mpss>, <&glink_lpass>, - <&glink_cdsp>; - qcom,xprt = "smem"; - }; - - glink_cdsp: qcom,glink-ssr-cdsp { - compatible = "qcom,glink_ssr"; - label = "cdsp"; - qcom,edge = "cdsp"; - qcom,notify-edges = <&glink_mpss>, <&glink_lpass>, - <&glink_dsps>; - qcom,xprt = "smem"; - }; - - glink_spss: qcom,glink-ssr-spss { - compatible = "qcom,glink_ssr"; - label = "spss"; - qcom,edge = "spss"; - qcom,notify-edges = <&glink_mpss>; - qcom,xprt = "mailbox"; - }; - - qcom,ipc_router { - compatible = "qcom,ipc_router"; - qcom,node-id = <1>; - }; - - qcom,ipc_router_modem_xprt { - compatible = "qcom,ipc_router_glink_xprt"; - qcom,ch-name = "IPCRTR"; - qcom,xprt-remote = "mpss"; - qcom,glink-xprt = "smem"; - qcom,xprt-linkid = <1>; - qcom,xprt-version = <1>; - qcom,fragmented-data; - }; - - qcom,ipc_router_q6_xprt { - compatible = "qcom,ipc_router_glink_xprt"; - qcom,ch-name = "IPCRTR"; - qcom,xprt-remote = "lpass"; - qcom,glink-xprt = "smem"; - qcom,xprt-linkid = <1>; - qcom,xprt-version = <1>; - qcom,fragmented-data; - }; - - qcom,ipc_router_dsps_xprt { - compatible = "qcom,ipc_router_glink_xprt"; - qcom,ch-name = "IPCRTR"; - qcom,xprt-remote = "dsps"; - qcom,glink-xprt = "smem"; - qcom,xprt-linkid = <1>; - qcom,xprt-version = <1>; - qcom,fragmented-data; - qcom,dynamic-wakeup-source; - qcom,low-latency-xprt; - }; - - qcom,ipc_router_cdsp_xprt { - compatible = "qcom,ipc_router_glink_xprt"; - qcom,ch-name = "IPCRTR"; - qcom,xprt-remote = "cdsp"; - qcom,glink-xprt = "smem"; - qcom,xprt-linkid = <1>; - qcom,xprt-version = <1>; - qcom,fragmented-data; - }; - - qcom,qsee_ipc_irq_bridge { + sp_scsr_block: syscon@1880000 { + compatible = "syscon"; + reg = <0x1880000 0x10000>; + }; + + intsp: qcom,qsee_irq { + #address-cells = <0>; + compatible = "qcom,sdm845-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,glink { + compatible = "qcom,glink"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + glink_modem: modem { + qcom,remote-pid = <1>; + transport = "smem"; + mboxes = <&apss_shared 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_cdsp>, + <&glink_spss>; + }; + }; + + glink_adsp: adsp { + qcom,remote-pid = <2>; + transport = "smem"; + mboxes = <&apss_shared 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_slpi>, + <&glink_cdsp>; + }; + }; + + glink_slpi: dsps { + qcom,remote-pid = <3>; + transport = "smem"; + mboxes = <&apss_shared 26>; + mbox-names = "dsps_smem"; + interrupts = ; + + label = "slpi"; + qcom,glink-label = "dsps"; + + qcom,slpi_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,slpi_glink_ssr { + qcom,glink-channels = "glink_ssr"; + qcom,notify-edges = <&glink_modem>, + <&glink_adsp>, + <&glink_cdsp>; + }; + }; + + glink_cdsp: cdsp { + qcom,remote-pid = <5>; + transport = "smem"; + mboxes = <&apss_shared 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>, + <&glink_slpi>; + }; + }; + + 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"; + + qcom,spss_glink_ssr { + qcom,glink-channels = "glink_ssr"; + qcom,notify-edges = <&glink_modem>; + }; + }; + + glink_spi_xprt_wdsp: wdsp { + transport = "spi"; + tx-descriptors = <0x12000 0x12004>; + rx-descriptors = <0x1200c 0x12010>; + + label = "wdsp"; + qcom,glink-label = "wdsp"; + + qcom,wdsp_ctrl { + qcom,glink-channels = "g_glink_ctrl"; + qcom,intents = <0x400 1>; + }; + + qcom,wdsp_ild { + qcom,glink-channels = + "g_glink_persistent_data_ild"; + }; + + qcom,wdsp_nild { + qcom,glink-channels = + "g_glink_persistent_data_nild"; + }; + + qcom,wdsp_data { + qcom,glink-channels = "g_glink_audio_data"; + qcom,intents = <0x1000 2>; + }; + + qcom,diag_data { + qcom,glink-channels = "DIAG_DATA"; + qcom,intents = <0x4000 2>; + }; + + qcom,diag_ctrl { + qcom,glink-channels = "DIAG_CTRL"; + qcom,intents = <0x4000 1>; + }; + + qcom,diag_cmd { + qcom,glink-channels = "DIAG_CMD"; + qcom,intents = <0x4000 1 >; + }; + }; + }; + + qcom,qsee_irq_bridge { compatible = "qcom,qsee-ipc-irq-bridge"; qcom,qsee-ipc-irq-spss { - qcom,rx-irq-clr = <0x1888008 0x4>; - qcom,rx-irq-clr-mask = <0x1>; qcom,dev-name = "qsee_ipc_irq_spss"; - interrupts = <0 349 4>; label = "spss"; + interrupt-parent = <&intsp>; + interrupts = ; }; }; From 19ef980ef21747d3dc2f061953e03243ceed2bda Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Tue, 9 Nov 2021 20:26:11 +0200 Subject: [PATCH 020/356] arm64: dts: qcom: sdm845: Update Command DB node In 4.19 kernel Command DB reserved memory node should be described in the reserved-memory region directly. Signed-off-by: Pavel Dubrova --- arch/arm64/boot/dts/qcom/sdm845.dtsi | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index 4b71b6f6f8a4..cf977aa9ec21 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -524,7 +524,13 @@ removed_region: removed_region@85fc0000 { no-map; - reg = <0 0x85fc0000 0 0x40000>; + reg = <0 0x85fc0000 0 0x20000>; + }; + + cmd_db: reserved-memory@85fe0000 { + compatible = "qcom,cmd-db"; + reg = <0 0x85fe0000 0 0x20000>; + no-map; }; smem_mem: smem_region@86000000 { @@ -2993,11 +2999,6 @@ interrupts = <0 17 0>; }; - cmd_db: qcom,cmd-db@861e0000 { - compatible = "qcom,cmd-db"; - reg = <0xc3f000c 8>; - }; - dcc: dcc_v2@10a2000 { compatible = "qcom,dcc-v2"; reg = <0x10a2000 0x1000>, From e639604b0aba6d1d6111f7ea1d2433a20e60119a Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Tue, 9 Nov 2021 23:43:03 +0200 Subject: [PATCH 021/356] arm64: dts: qcom: sdm845: Remove all instances of IRQ_TYPE_NONE This patch removes all instances of IRQ_TYPE_NONE, which fixes warning messages during boot. This warning was introduced by commit 6ef6386 ("irqchip/gic-v3: Loudly complain about the use of IRQ_TYPE_NONE"). It also changes interrupt types to their corresponding macros, as defined in arm-gic.h. Also replace hard-coded number with appropriate define for GIC_SPI/PPI specifier in interrupt. Signed-off-by: Pavel Dubrova --- .../boot/dts/qcom/sdm845-670-usb-common.dtsi | 16 +- arch/arm64/boot/dts/qcom/sdm845-camera.dtsi | 32 +-- arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi | 5 +- arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi | 2 +- arch/arm64/boot/dts/qcom/sdm845-pcie.dtsi | 152 +++++++------- arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi | 2 +- arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi | 76 +++---- arch/arm64/boot/dts/qcom/sdm845-sde.dtsi | 10 +- .../arm64/boot/dts/qcom/sdm845-v2-camera.dtsi | 12 +- arch/arm64/boot/dts/qcom/sdm845-v2.1-mtp.dts | 8 +- arch/arm64/boot/dts/qcom/sdm845.dtsi | 194 ++++++++++-------- 11 files changed, 270 insertions(+), 239 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi index 117f616bcb7a..ac11134668d5 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi @@ -19,7 +19,10 @@ #size-cells = <1>; ranges; - interrupts = <0 489 0>, <0 130 0>, <0 486 0>, <0 488 0>; + interrupts = , + , + , + ; interrupt-names = "dp_hs_phy_irq", "pwr_event_irq", "ss_phy_irq", "dm_hs_phy_irq"; @@ -64,7 +67,7 @@ dwc3@a600000 { compatible = "snps,dwc3"; reg = <0x0a600000 0xcd00>; - interrupts = <0 133 0>; + interrupts = ; usb-phy = <&qusb_phy0>, <&usb_qmp_dp_phy>; tx-fifo-resize; linux,sysdev_is_parent; @@ -78,7 +81,7 @@ qcom,usbbam@a704000 { compatible = "qcom,usb-bam-msm"; reg = <0xa704000 0x17000>; - interrupts = <0 132 0>; + interrupts = ; qcom,bam-type = <0>; qcom,usb-bam-fifo-baseaddr = <0x146bb000>; @@ -352,7 +355,10 @@ #size-cells = <1>; ranges; - interrupts = <0 491 0>, <0 135 0>, <0 487 0>, <0 490 0>; + interrupts = , + , + , + ; interrupt-names = "dp_hs_phy_irq", "pwr_event_irq", "ss_phy_irq", "dm_hs_phy_irq"; @@ -391,7 +397,7 @@ dwc3@a800000 { compatible = "snps,dwc3"; reg = <0x0a800000 0xcd00>; - interrupts = <0 138 0>; + interrupts = ; usb-phy = <&qusb_phy1>, <&usb_qmp_phy>; tx-fifo-resize; linux,sysdev_is_parent; diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi index 75414f0c124b..8d516e6238a7 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi @@ -15,7 +15,7 @@ reg = <0x0ac65000 0x1000>; reg-names = "csiphy"; reg-cam-base = <0x65000>; - interrupts = <0 477 0>; + interrupts = ; interrupt-names = "csiphy"; gdscr-supply = <&titan_top_gdsc>; regulator-names = "gdscr"; @@ -51,7 +51,7 @@ reg = <0xac66000 0x1000>; reg-names = "csiphy"; reg-cam-base = <0x66000>; - interrupts = <0 478 0>; + interrupts = ; interrupt-names = "csiphy"; gdscr-supply = <&titan_top_gdsc>; regulator-names = "gdscr"; @@ -88,7 +88,7 @@ reg = <0xac67000 0x1000>; reg-names = "csiphy"; reg-cam-base = <0x67000>; - interrupts = <0 479 0>; + interrupts = ; interrupt-names = "csiphy"; gdscr-supply = <&titan_top_gdsc>; regulator-names = "gdscr"; @@ -127,7 +127,7 @@ reg-names = "cci"; reg-cam-base = <0x4a000>; interrupt-names = "cci"; - interrupts = <0 460 0>; + interrupts = ; status = "ok"; gdscr-supply = <&titan_top_gdsc>; regulator-names = "gdscr"; @@ -374,7 +374,7 @@ <0xac42000 0x5000>; reg-cam-base = <0x40000 0x42000>; interrupt-names = "cpas_camnoc"; - interrupts = <0 459 0>; + interrupts = ; qcom,cpas-hw-ver = <0x170100>; /* Titan v170 v1.0.0 */ camnoc-axi-min-ib-bw = <3000000000>; regulator-names = "camss-vdd"; @@ -547,7 +547,7 @@ reg = <0xac48000 0x1000>; reg-names = "cpas-cdm"; reg-cam-base = <0x48000>; - interrupts = <0 461 0>; + interrupts = ; interrupt-names = "cpas-cdm"; regulator-names = "camss"; camss-supply = <&titan_top_gdsc>; @@ -580,7 +580,7 @@ reg = <0xacb3000 0x1000>; reg-cam-base = <0xb3000>; interrupt-names = "csid"; - interrupts = <0 464 0>; + interrupts = ; regulator-names = "camss", "ife0"; camss-supply = <&titan_top_gdsc>; ife0-supply = <&ife_0_gdsc>; @@ -626,7 +626,7 @@ reg = <0xacaf000 0x4000>; reg-cam-base = <0xaf000>; interrupt-names = "ife"; - interrupts = <0 465 0>; + interrupts = ; regulator-names = "camss", "ife0"; camss-supply = <&titan_top_gdsc>; ife0-supply = <&ife_0_gdsc>; @@ -668,7 +668,7 @@ reg = <0xacba000 0x1000>; reg-cam-base = <0xba000>; interrupt-names = "csid"; - interrupts = <0 466 0>; + interrupts = ; regulator-names = "camss", "ife1"; camss-supply = <&titan_top_gdsc>; ife1-supply = <&ife_1_gdsc>; @@ -714,7 +714,7 @@ reg = <0xacb6000 0x4000>; reg-cam-base = <0xb6000>; interrupt-names = "ife"; - interrupts = <0 467 0>; + interrupts = ; regulator-names = "camss", "ife1"; camss-supply = <&titan_top_gdsc>; ife1-supply = <&ife_1_gdsc>; @@ -756,7 +756,7 @@ reg = <0xacc8000 0x1000>; reg-cam-base = <0xc8000>; interrupt-names = "csid-lite"; - interrupts = <0 468 0>; + interrupts = ; regulator-names = "camss"; camss-supply = <&titan_top_gdsc>; clock-names = "camera_ahb", @@ -799,7 +799,7 @@ reg = <0xacc4000 0x4000>; reg-cam-base = <0xc4000>; interrupt-names = "ife-lite"; - interrupts = <0 469 0>; + interrupts = ; regulator-names = "camss"; camss-supply = <&titan_top_gdsc>; clock-names = "camera_ahb", @@ -848,7 +848,7 @@ <0xac18000 0x3000>; reg-names = "a5_qgic", "a5_sierra", "a5_csr"; reg-cam-base = <0x00000 0x10000 0x18000>; - interrupts = <0 463 0>; + interrupts = ; interrupt-names = "a5"; regulator-names = "camss-vdd"; camss-vdd-supply = <&titan_top_gdsc>; @@ -987,7 +987,7 @@ reg = <0xac4e000 0x4000>; reg-cam-base = <0x4e000>; interrupt-names = "jpeg"; - interrupts = <0 474 0>; + interrupts = ; regulator-names = "camss-vdd"; camss-vdd-supply = <&titan_top_gdsc>; clock-names = "camera_ahb", @@ -1018,7 +1018,7 @@ reg = <0xac52000 0x4000>; reg-cam-base = <0x52000>; interrupt-names = "jpegdma"; - interrupts = <0 475 0>; + interrupts = ; regulator-names = "camss-vdd"; camss-vdd-supply = <&titan_top_gdsc>; clock-names = "camera_ahb", @@ -1057,7 +1057,7 @@ <0xac5b000 0x400>; reg-cam-base = <0x5a000 0x5b000>; interrupt-names = "fd"; - interrupts = <0 462 0>; + interrupts = ; regulator-names = "camss-vdd"; camss-vdd-supply = <&titan_top_gdsc>; clock-names = "gcc_ahb_clk", diff --git a/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi b/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi index 4cdf6772be54..8347497ff351 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi @@ -45,7 +45,7 @@ <0x509e000 0x1000>; reg-names = "kgsl_3d0_reg_memory", "kgsl_3d0_cx_dbgc_memory", "cx_misc"; - interrupts = <0 300 0>; + interrupts = ; interrupt-names = "kgsl_3d0_irq"; qcom,id = <0>; @@ -323,7 +323,8 @@ reg = <0x506a000 0x30000>, <0xb200000 0x300000>; reg-names = "kgsl_gmu_reg", "kgsl_gmu_pdc_reg"; - interrupts = <0 304 0>, <0 305 0>; + interrupts = , + ; interrupt-names = "kgsl_hfi_irq", "kgsl_gmu_irq"; qcom,msm-bus,name = "cnoc"; diff --git a/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi index 5d7d6c568850..fcfb3c9be4bb 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi @@ -315,7 +315,7 @@ qcom,nq-clkreq = <&pm8998_gpios 21 0x00>; qcom,nq-esepwr = <&tlmm 116 0x00>; interrupt-parent = <&tlmm>; - interrupts = <63 0>; + interrupts = <63 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "nfc_irq"; pinctrl-names = "nfc_active", "nfc_suspend"; pinctrl-0 = <&nfc_int_active diff --git a/arch/arm64/boot/dts/qcom/sdm845-pcie.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pcie.dtsi index 1167a04db53d..ca2f5497b890 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-pcie.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-pcie.dtsi @@ -31,44 +31,44 @@ 36 37>; #interrupt-cells = <1>; interrupt-map-mask = <0 0 0 0xffffffff>; - interrupt-map = <0 0 0 0 &pdc 0 141 0 - 0 0 0 1 &pdc 0 149 0 - 0 0 0 2 &pdc 0 150 0 - 0 0 0 3 &pdc 0 151 0 - 0 0 0 4 &pdc 0 152 0 - 0 0 0 5 &pdc 0 140 0 - 0 0 0 6 &pdc 0 672 0 - 0 0 0 7 &pdc 0 673 0 - 0 0 0 8 &pdc 0 674 0 - 0 0 0 9 &pdc 0 675 0 - 0 0 0 10 &pdc 0 676 0 - 0 0 0 11 &pdc 0 677 0 - 0 0 0 12 &pdc 0 678 0 - 0 0 0 13 &pdc 0 679 0 - 0 0 0 14 &pdc 0 680 0 - 0 0 0 15 &pdc 0 681 0 - 0 0 0 16 &pdc 0 682 0 - 0 0 0 17 &pdc 0 683 0 - 0 0 0 18 &pdc 0 684 0 - 0 0 0 19 &pdc 0 685 0 - 0 0 0 20 &pdc 0 686 0 - 0 0 0 21 &pdc 0 687 0 - 0 0 0 22 &pdc 0 688 0 - 0 0 0 23 &pdc 0 689 0 - 0 0 0 24 &pdc 0 690 0 - 0 0 0 25 &pdc 0 691 0 - 0 0 0 26 &pdc 0 692 0 - 0 0 0 27 &pdc 0 693 0 - 0 0 0 28 &pdc 0 694 0 - 0 0 0 29 &pdc 0 695 0 - 0 0 0 30 &pdc 0 696 0 - 0 0 0 31 &pdc 0 697 0 - 0 0 0 32 &pdc 0 698 0 - 0 0 0 33 &pdc 0 699 0 - 0 0 0 34 &pdc 0 700 0 - 0 0 0 35 &pdc 0 701 0 - 0 0 0 36 &pdc 0 702 0 - 0 0 0 37 &pdc 0 703 0>; + interrupt-map = <0 0 0 0 &pdc GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH + 0 0 0 1 &pdc GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH + 0 0 0 2 &pdc GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH + 0 0 0 3 &pdc GIC_SPI 151 IRQ_TYPE_LEVEL_HIGH + 0 0 0 4 &pdc GIC_SPI 152 IRQ_TYPE_LEVEL_HIGH + 0 0 0 5 &pdc GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH + 0 0 0 6 &pdc GIC_SPI 672 IRQ_TYPE_LEVEL_HIGH + 0 0 0 7 &pdc GIC_SPI 673 IRQ_TYPE_LEVEL_HIGH + 0 0 0 8 &pdc GIC_SPI 674 IRQ_TYPE_LEVEL_HIGH + 0 0 0 9 &pdc GIC_SPI 675 IRQ_TYPE_LEVEL_HIGH + 0 0 0 10 &pdc GIC_SPI 676 IRQ_TYPE_LEVEL_HIGH + 0 0 0 11 &pdc GIC_SPI 677 IRQ_TYPE_LEVEL_HIGH + 0 0 0 12 &pdc GIC_SPI 678 IRQ_TYPE_LEVEL_HIGH + 0 0 0 13 &pdc GIC_SPI 679 IRQ_TYPE_LEVEL_HIGH + 0 0 0 14 &pdc GIC_SPI 680 IRQ_TYPE_LEVEL_HIGH + 0 0 0 15 &pdc GIC_SPI 681 IRQ_TYPE_LEVEL_HIGH + 0 0 0 16 &pdc GIC_SPI 682 IRQ_TYPE_LEVEL_HIGH + 0 0 0 17 &pdc GIC_SPI 683 IRQ_TYPE_LEVEL_HIGH + 0 0 0 18 &pdc GIC_SPI 684 IRQ_TYPE_LEVEL_HIGH + 0 0 0 19 &pdc GIC_SPI 685 IRQ_TYPE_LEVEL_HIGH + 0 0 0 20 &pdc GIC_SPI 686 IRQ_TYPE_LEVEL_HIGH + 0 0 0 21 &pdc GIC_SPI 687 IRQ_TYPE_LEVEL_HIGH + 0 0 0 22 &pdc GIC_SPI 688 IRQ_TYPE_LEVEL_HIGH + 0 0 0 23 &pdc GIC_SPI 689 IRQ_TYPE_LEVEL_HIGH + 0 0 0 24 &pdc GIC_SPI 690 IRQ_TYPE_LEVEL_HIGH + 0 0 0 25 &pdc GIC_SPI 691 IRQ_TYPE_LEVEL_HIGH + 0 0 0 26 &pdc GIC_SPI 692 IRQ_TYPE_LEVEL_HIGH + 0 0 0 27 &pdc GIC_SPI 693 IRQ_TYPE_LEVEL_HIGH + 0 0 0 28 &pdc GIC_SPI 694 IRQ_TYPE_LEVEL_HIGH + 0 0 0 29 &pdc GIC_SPI 695 IRQ_TYPE_LEVEL_HIGH + 0 0 0 30 &pdc GIC_SPI 696 IRQ_TYPE_LEVEL_HIGH + 0 0 0 31 &pdc GIC_SPI 697 IRQ_TYPE_LEVEL_HIGH + 0 0 0 32 &pdc GIC_SPI 698 IRQ_TYPE_LEVEL_HIGH + 0 0 0 33 &pdc GIC_SPI 699 IRQ_TYPE_LEVEL_HIGH + 0 0 0 34 &pdc GIC_SPI 700 IRQ_TYPE_LEVEL_HIGH + 0 0 0 35 &pdc GIC_SPI 701 IRQ_TYPE_LEVEL_HIGH + 0 0 0 36 &pdc GIC_SPI 702 IRQ_TYPE_LEVEL_HIGH + 0 0 0 37 &pdc GIC_SPI 703 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "int_msi", "int_a", "int_b", "int_c", "int_d", "int_global_int", @@ -286,44 +286,44 @@ 36 37>; #interrupt-cells = <1>; interrupt-map-mask = <0 0 0 0xffffffff>; - interrupt-map = <0 0 0 0 &intc 0 307 0 - 0 0 0 1 &intc 0 434 0 - 0 0 0 2 &intc 0 435 0 - 0 0 0 3 &intc 0 438 0 - 0 0 0 4 &intc 0 439 0 - 0 0 0 5 &intc 0 306 0 - 0 0 0 6 &intc 0 704 0 - 0 0 0 7 &intc 0 705 0 - 0 0 0 8 &intc 0 706 0 - 0 0 0 9 &intc 0 707 0 - 0 0 0 10 &intc 0 708 0 - 0 0 0 11 &intc 0 709 0 - 0 0 0 12 &intc 0 710 0 - 0 0 0 13 &intc 0 711 0 - 0 0 0 14 &intc 0 712 0 - 0 0 0 15 &intc 0 713 0 - 0 0 0 16 &intc 0 714 0 - 0 0 0 17 &intc 0 715 0 - 0 0 0 18 &intc 0 716 0 - 0 0 0 19 &intc 0 717 0 - 0 0 0 20 &intc 0 718 0 - 0 0 0 21 &intc 0 719 0 - 0 0 0 22 &intc 0 720 0 - 0 0 0 23 &intc 0 721 0 - 0 0 0 24 &intc 0 722 0 - 0 0 0 25 &intc 0 723 0 - 0 0 0 26 &intc 0 724 0 - 0 0 0 27 &intc 0 725 0 - 0 0 0 28 &intc 0 726 0 - 0 0 0 29 &intc 0 727 0 - 0 0 0 30 &intc 0 728 0 - 0 0 0 31 &intc 0 729 0 - 0 0 0 32 &intc 0 730 0 - 0 0 0 33 &intc 0 731 0 - 0 0 0 34 &intc 0 732 0 - 0 0 0 35 &intc 0 733 0 - 0 0 0 36 &intc 0 734 0 - 0 0 0 37 &intc 0 735 0>; + interrupt-map = <0 0 0 0 &intc GIC_SPI 307 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 + 0 0 0 5 &intc GIC_SPI 306 IRQ_TYPE_LEVEL_HIGH + 0 0 0 6 &intc GIC_SPI 704 IRQ_TYPE_LEVEL_HIGH + 0 0 0 7 &intc GIC_SPI 705 IRQ_TYPE_LEVEL_HIGH + 0 0 0 8 &intc GIC_SPI 706 IRQ_TYPE_LEVEL_HIGH + 0 0 0 9 &intc GIC_SPI 707 IRQ_TYPE_LEVEL_HIGH + 0 0 0 10 &intc GIC_SPI 708 IRQ_TYPE_LEVEL_HIGH + 0 0 0 11 &intc GIC_SPI 709 IRQ_TYPE_LEVEL_HIGH + 0 0 0 12 &intc GIC_SPI 710 IRQ_TYPE_LEVEL_HIGH + 0 0 0 13 &intc GIC_SPI 711 IRQ_TYPE_LEVEL_HIGH + 0 0 0 14 &intc GIC_SPI 712 IRQ_TYPE_LEVEL_HIGH + 0 0 0 15 &intc GIC_SPI 713 IRQ_TYPE_LEVEL_HIGH + 0 0 0 16 &intc GIC_SPI 714 IRQ_TYPE_LEVEL_HIGH + 0 0 0 17 &intc GIC_SPI 715 IRQ_TYPE_LEVEL_HIGH + 0 0 0 18 &intc GIC_SPI 716 IRQ_TYPE_LEVEL_HIGH + 0 0 0 19 &intc GIC_SPI 717 IRQ_TYPE_LEVEL_HIGH + 0 0 0 20 &intc GIC_SPI 718 IRQ_TYPE_LEVEL_HIGH + 0 0 0 21 &intc GIC_SPI 719 IRQ_TYPE_LEVEL_HIGH + 0 0 0 22 &intc GIC_SPI 720 IRQ_TYPE_LEVEL_HIGH + 0 0 0 23 &intc GIC_SPI 721 IRQ_TYPE_LEVEL_HIGH + 0 0 0 24 &intc GIC_SPI 722 IRQ_TYPE_LEVEL_HIGH + 0 0 0 25 &intc GIC_SPI 723 IRQ_TYPE_LEVEL_HIGH + 0 0 0 26 &intc GIC_SPI 724 IRQ_TYPE_LEVEL_HIGH + 0 0 0 27 &intc GIC_SPI 725 IRQ_TYPE_LEVEL_HIGH + 0 0 0 28 &intc GIC_SPI 726 IRQ_TYPE_LEVEL_HIGH + 0 0 0 29 &intc GIC_SPI 727 IRQ_TYPE_LEVEL_HIGH + 0 0 0 30 &intc GIC_SPI 728 IRQ_TYPE_LEVEL_HIGH + 0 0 0 31 &intc GIC_SPI 729 IRQ_TYPE_LEVEL_HIGH + 0 0 0 32 &intc GIC_SPI 730 IRQ_TYPE_LEVEL_HIGH + 0 0 0 33 &intc GIC_SPI 731 IRQ_TYPE_LEVEL_HIGH + 0 0 0 34 &intc GIC_SPI 732 IRQ_TYPE_LEVEL_HIGH + 0 0 0 35 &intc GIC_SPI 733 IRQ_TYPE_LEVEL_HIGH + 0 0 0 36 &intc GIC_SPI 734 IRQ_TYPE_LEVEL_HIGH + 0 0 0 37 &intc GIC_SPI 735 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "int_msi", "int_a", "int_b", "int_c", "int_d", "int_global_int", diff --git a/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi index b3990c270b43..5049dbf04ed3 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi @@ -8,7 +8,7 @@ compatible = "qcom,sdm845-pinctrl"; reg = <0x03400000 0xc00000>, <0x179900F0 0x60>; reg-names = "pinctrl_regs", "spi_cfg_regs"; - interrupts = <0 208 0>; + interrupts = ; gpio-controller; #gpio-cells = <2>; interrupt-controller; diff --git a/arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi b/arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi index 92067ea43d6a..777b2e33d2d0 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi @@ -37,8 +37,8 @@ <&qupv3_se6_tx> ; pinctrl-1 = <&qupv3_se6_ctsrx>, <&qupv3_se6_rts>, <&qupv3_se6_tx> ; - interrupts-extended = <&pdc GIC_SPI 607 0>, - <&tlmm 48 0>; + interrupts-extended = <&pdc GIC_SPI 607 IRQ_TYPE_LEVEL_HIGH>, + <&tlmm 48 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; qcom,wakeup-byte = <0xFD>; qcom,wrapper-core = <&qupv3_0>; @@ -55,8 +55,8 @@ pinctrl-names = "default", "sleep"; pinctrl-0 = <&qupv3_se7_4uart_active>; pinctrl-1 = <&qupv3_se7_4uart_sleep>; - interrupts-extended = <&pdc GIC_SPI 608 0>, - <&tlmm 96 0>; + interrupts-extended = <&pdc GIC_SPI 608 IRQ_TYPE_LEVEL_HIGH>, + <&tlmm 96 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; qcom,wakeup-byte = <0xFD>; qcom,wrapper-core = <&qupv3_0>; @@ -66,7 +66,7 @@ qupv3_se0_i2c: i2c@880000 { compatible = "qcom,i2c-geni"; reg = <0x880000 0x4000>; - interrupts = ; + interrupts = ; #address-cells = <1>; #size-cells = <0>; clock-names = "se-clk", "m-ahb", "s-ahb"; @@ -86,7 +86,7 @@ qupv3_se1_i2c: i2c@884000 { compatible = "qcom,i2c-geni"; reg = <0x884000 0x4000>; - interrupts = ; + interrupts = ; #address-cells = <1>; #size-cells = <0>; clock-names = "se-clk", "m-ahb", "s-ahb"; @@ -106,7 +106,7 @@ qupv3_se2_i2c: i2c@888000 { compatible = "qcom,i2c-geni"; reg = <0x888000 0x4000>; - interrupts = ; + interrupts = ; #address-cells = <1>; #size-cells = <0>; clock-names = "se-clk", "m-ahb", "s-ahb"; @@ -126,7 +126,7 @@ qupv3_se3_i2c: i2c@88c000 { compatible = "qcom,i2c-geni"; reg = <0x88c000 0x4000>; - interrupts = ; + interrupts = ; #address-cells = <1>; #size-cells = <0>; clock-names = "se-clk", "m-ahb", "s-ahb"; @@ -146,7 +146,7 @@ qupv3_se4_i2c: i2c@890000 { compatible = "qcom,i2c-geni"; reg = <0x890000 0x4000>; - interrupts = ; + interrupts = ; #address-cells = <1>; #size-cells = <0>; clock-names = "se-clk", "m-ahb", "s-ahb"; @@ -166,7 +166,7 @@ qupv3_se5_i2c: i2c@894000 { compatible = "qcom,i2c-geni"; reg = <0x894000 0x4000>; - interrupts = ; + interrupts = ; #address-cells = <1>; #size-cells = <0>; clock-names = "se-clk", "m-ahb", "s-ahb"; @@ -186,7 +186,7 @@ qupv3_se6_i2c: i2c@898000 { compatible = "qcom,i2c-geni"; reg = <0x898000 0x4000>; - interrupts = ; + interrupts = ; #address-cells = <1>; #size-cells = <0>; clock-names = "se-clk", "m-ahb", "s-ahb"; @@ -206,7 +206,7 @@ qupv3_se7_i2c: i2c@89c000 { compatible = "qcom,i2c-geni"; reg = <0x89c000 0x4000>; - interrupts = ; + interrupts = ; #address-cells = <1>; #size-cells = <0>; clock-names = "se-clk", "m-ahb", "s-ahb"; @@ -237,7 +237,7 @@ pinctrl-names = "default", "sleep"; pinctrl-0 = <&qupv3_se0_spi_active>; pinctrl-1 = <&qupv3_se0_spi_sleep>; - interrupts = ; + interrupts = ; spi-max-frequency = <50000000>; qcom,wrapper-core = <&qupv3_0>; dmas = <&gpi_dma0 0 0 1 64 0>, @@ -259,7 +259,7 @@ pinctrl-names = "default", "sleep"; pinctrl-0 = <&qupv3_se1_spi_active>; pinctrl-1 = <&qupv3_se1_spi_sleep>; - interrupts = ; + interrupts = ; spi-max-frequency = <50000000>; qcom,wrapper-core = <&qupv3_0>; dmas = <&gpi_dma0 0 1 1 64 0>, @@ -281,7 +281,7 @@ pinctrl-names = "default", "sleep"; pinctrl-0 = <&qupv3_se2_spi_active>; pinctrl-1 = <&qupv3_se2_spi_sleep>; - interrupts = ; + interrupts = ; spi-max-frequency = <50000000>; qcom,wrapper-core = <&qupv3_0>; dmas = <&gpi_dma0 0 2 1 64 0>, @@ -303,7 +303,7 @@ pinctrl-names = "default", "sleep"; pinctrl-0 = <&qupv3_se3_spi_active>; pinctrl-1 = <&qupv3_se3_spi_sleep>; - interrupts = ; + interrupts = ; spi-max-frequency = <50000000>; qcom,wrapper-core = <&qupv3_0>; dmas = <&gpi_dma0 0 3 1 64 0>, @@ -325,7 +325,7 @@ pinctrl-names = "default", "sleep"; pinctrl-0 = <&qupv3_se4_spi_active>; pinctrl-1 = <&qupv3_se4_spi_sleep>; - interrupts = ; + interrupts = ; spi-max-frequency = <50000000>; qcom,wrapper-core = <&qupv3_0>; dmas = <&gpi_dma0 0 4 1 64 0>, @@ -347,7 +347,7 @@ pinctrl-names = "default", "sleep"; pinctrl-0 = <&qupv3_se5_spi_active>; pinctrl-1 = <&qupv3_se5_spi_sleep>; - interrupts = ; + interrupts = ; spi-max-frequency = <50000000>; qcom,wrapper-core = <&qupv3_0>; dmas = <&gpi_dma0 0 5 1 64 0>, @@ -369,7 +369,7 @@ pinctrl-names = "default", "sleep"; pinctrl-0 = <&qupv3_se6_spi_active>; pinctrl-1 = <&qupv3_se6_spi_sleep>; - interrupts = ; + interrupts = ; spi-max-frequency = <50000000>; qcom,wrapper-core = <&qupv3_0>; dmas = <&gpi_dma0 0 6 1 64 0>, @@ -391,7 +391,7 @@ pinctrl-names = "default", "sleep"; pinctrl-0 = <&qupv3_se7_spi_active>; pinctrl-1 = <&qupv3_se7_spi_sleep>; - interrupts = ; + interrupts = ; spi-max-frequency = <50000000>; qcom,wrapper-core = <&qupv3_0>; dmas = <&gpi_dma0 0 7 1 64 0>, @@ -428,7 +428,7 @@ pinctrl-names = "default", "sleep"; pinctrl-0 = <&qupv3_se9_2uart_active>; pinctrl-1 = <&qupv3_se9_2uart_sleep>; - interrupts = ; + interrupts = ; qcom,wrapper-core = <&qupv3_1>; status = "disabled"; }; @@ -445,7 +445,7 @@ pinctrl-names = "default", "sleep"; pinctrl-0 = <&qupv3_se10_2uart_active>; pinctrl-1 = <&qupv3_se10_2uart_sleep>; - interrupts = ; + interrupts = ; qcom,wrapper-core = <&qupv3_1>; status = "disabled"; }; @@ -454,7 +454,7 @@ qupv3_se8_i2c: i2c@a80000 { compatible = "qcom,i2c-geni"; reg = <0xa80000 0x4000>; - interrupts = ; + interrupts = ; #address-cells = <1>; #size-cells = <0>; clock-names = "se-clk", "m-ahb", "s-ahb"; @@ -474,7 +474,7 @@ qupv3_se9_i2c: i2c@a84000 { compatible = "qcom,i2c-geni"; reg = <0xa84000 0x4000>; - interrupts = ; + interrupts = ; #address-cells = <1>; #size-cells = <0>; clock-names = "se-clk", "m-ahb", "s-ahb"; @@ -494,7 +494,7 @@ qupv3_se10_i2c: i2c@a88000 { compatible = "qcom,i2c-geni"; reg = <0xa88000 0x4000>; - interrupts = ; + interrupts = ; #address-cells = <1>; #size-cells = <0>; clock-names = "se-clk", "m-ahb", "s-ahb"; @@ -514,7 +514,7 @@ qupv3_se11_i2c: i2c@a8c000 { compatible = "qcom,i2c-geni"; reg = <0xa8c000 0x4000>; - interrupts = ; + interrupts = ; #address-cells = <1>; #size-cells = <0>; clock-names = "se-clk", "m-ahb", "s-ahb"; @@ -534,7 +534,7 @@ qupv3_se12_i2c: i2c@a90000 { compatible = "qcom,i2c-geni"; reg = <0xa90000 0x4000>; - interrupts = ; + interrupts = ; #address-cells = <1>; #size-cells = <0>; clock-names = "se-clk", "m-ahb", "s-ahb"; @@ -554,7 +554,7 @@ qupv3_se13_i2c: i2c@a94000 { compatible = "qcom,i2c-geni"; reg = <0xa94000 0x4000>; - interrupts = ; + interrupts = ; #address-cells = <1>; #size-cells = <0>; clock-names = "se-clk", "m-ahb", "s-ahb"; @@ -574,7 +574,7 @@ qupv3_se14_i2c: i2c@a98000 { compatible = "qcom,i2c-geni"; reg = <0xa98000 0x4000>; - interrupts = ; + interrupts = ; #address-cells = <1>; #size-cells = <0>; clock-names = "se-clk", "m-ahb", "s-ahb"; @@ -594,7 +594,7 @@ qupv3_se15_i2c: i2c@a9c000 { compatible = "qcom,i2c-geni"; reg = <0xa9c000 0x4000>; - interrupts = ; + interrupts = ; #address-cells = <1>; #size-cells = <0>; clock-names = "se-clk", "m-ahb", "s-ahb"; @@ -625,7 +625,7 @@ pinctrl-names = "default", "sleep"; pinctrl-0 = <&qupv3_se8_spi_active>; pinctrl-1 = <&qupv3_se8_spi_active>; - interrupts = ; + interrupts = ; spi-max-frequency = <50000000>; qcom,wrapper-core = <&qupv3_1>; dmas = <&gpi_dma1 0 0 1 64 0>, @@ -647,7 +647,7 @@ pinctrl-names = "default", "sleep"; pinctrl-0 = <&qupv3_se9_spi_active>; pinctrl-1 = <&qupv3_se9_spi_sleep>; - interrupts = ; + interrupts = ; spi-max-frequency = <50000000>; qcom,wrapper-core = <&qupv3_1>; dmas = <&gpi_dma1 0 1 1 64 0>, @@ -669,7 +669,7 @@ pinctrl-names = "default", "sleep"; pinctrl-0 = <&qupv3_se10_spi_active>; pinctrl-1 = <&qupv3_se10_spi_sleep>; - interrupts = ; + interrupts = ; spi-max-frequency = <50000000>; qcom,wrapper-core = <&qupv3_1>; dmas = <&gpi_dma1 0 2 1 64 0>, @@ -691,7 +691,7 @@ pinctrl-names = "default", "sleep"; pinctrl-0 = <&qupv3_se11_spi_active>; pinctrl-1 = <&qupv3_se11_spi_sleep>; - interrupts = ; + interrupts = ; spi-max-frequency = <50000000>; qcom,wrapper-core = <&qupv3_1>; dmas = <&gpi_dma1 0 3 1 64 0>, @@ -713,7 +713,7 @@ pinctrl-names = "default", "sleep"; pinctrl-0 = <&qupv3_se12_spi_active>; pinctrl-1 = <&qupv3_se12_spi_sleep>; - interrupts = ; + interrupts = ; spi-max-frequency = <50000000>; qcom,wrapper-core = <&qupv3_1>; dmas = <&gpi_dma1 0 4 1 64 0>, @@ -735,7 +735,7 @@ pinctrl-names = "default", "sleep"; pinctrl-0 = <&qupv3_se13_spi_active>; pinctrl-1 = <&qupv3_se13_spi_sleep>; - interrupts = ; + interrupts = ; spi-max-frequency = <50000000>; qcom,wrapper-core = <&qupv3_1>; dmas = <&gpi_dma1 0 5 1 64 0>, @@ -757,7 +757,7 @@ pinctrl-names = "default", "sleep"; pinctrl-0 = <&qupv3_se14_spi_active>; pinctrl-1 = <&qupv3_se14_spi_sleep>; - interrupts = ; + interrupts = ; spi-max-frequency = <50000000>; qcom,wrapper-core = <&qupv3_1>; dmas = <&gpi_dma1 0 6 1 64 0>, @@ -779,7 +779,7 @@ pinctrl-names = "default", "sleep"; pinctrl-0 = <&qupv3_se15_spi_active>; pinctrl-1 = <&qupv3_se15_spi_sleep>; - interrupts = ; + interrupts = ; spi-max-frequency = <50000000>; qcom,wrapper-core = <&qupv3_1>; dmas = <&gpi_dma1 0 7 1 64 0>, diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi index d89c6a973a00..47a954f2366f 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi @@ -31,7 +31,7 @@ /* interrupt config */ interrupt-parent = <&pdc>; - interrupts = <0 83 0>; + interrupts = ; interrupt-controller; #interrupt-cells = <1>; iommus = <&apps_smmu 0x880 0x8>, @@ -359,7 +359,7 @@ "iface_clk", "rot_clk", "axi_clk"; interrupt-parent = <&mdss_mdp>; - interrupts = <2 0>; + interrupts = <2 IRQ_TYPE_LEVEL_HIGH>; power-domains = <&mdss_mdp>; @@ -415,7 +415,7 @@ <0xaf08000 0x4>; reg-names = "dsi_ctrl", "disp_cc_base"; interrupt-parent = <&mdss_mdp>; - interrupts = <4 0>; + interrupts = <4 IRQ_TYPE_LEVEL_HIGH>; vdda-1p2-supply = <&pm8998_l26>; clocks = <&clock_dispcc DISP_CC_MDSS_BYTE0_CLK>, <&clock_dispcc DISP_CC_MDSS_BYTE0_CLK_SRC>, @@ -450,7 +450,7 @@ <0xaf08000 0x4>; reg-names = "dsi_ctrl", "disp_cc_base"; interrupt-parent = <&mdss_mdp>; - interrupts = <5 0>; + interrupts = <5 IRQ_TYPE_LEVEL_HIGH>; vdda-1p2-supply = <&pm8998_l26>; clocks = <&clock_dispcc DISP_CC_MDSS_BYTE1_CLK>, <&clock_dispcc DISP_CC_MDSS_BYTE1_CLK_SRC>, @@ -569,7 +569,7 @@ "usb3_dp_com", "hdcp_physical"; interrupt-parent = <&mdss_mdp>; - interrupts = <12 0>; + interrupts = <12 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clock_dispcc DISP_CC_MDSS_DP_AUX_CLK>, <&clock_rpmh RPMH_CXO_CLK>, diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi index 582ec86d215f..6b82b5ff154b 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi @@ -10,7 +10,7 @@ reg = <0x0ac65000 0x1000>; reg-names = "csiphy"; reg-cam-base = <0x65000>; - interrupts = <0 477 0>; + interrupts = ; interrupt-names = "csiphy"; regulator-names = "gdscr", "refgen"; gdscr-supply = <&titan_top_gdsc>; @@ -45,7 +45,7 @@ reg = <0xac66000 0x1000>; reg-names = "csiphy"; reg-cam-base = <0x66000>; - interrupts = <0 478 0>; + interrupts = ; interrupt-names = "csiphy"; regulator-names = "gdscr", "refgen"; gdscr-supply = <&titan_top_gdsc>; @@ -81,7 +81,7 @@ reg = <0xac67000 0x1000>; reg-names = "csiphy"; reg-cam-base = <0x67000>; - interrupts = <0 479 0>; + interrupts = ; interrupt-names = "csiphy"; regulator-names = "gdscr", "refgen"; gdscr-supply = <&titan_top_gdsc>; @@ -116,7 +116,7 @@ reg = <0xac68000 0x1000>; reg-names = "csiphy"; reg-cam-base = <0x68000>; - interrupts = <0 448 0>; + interrupts = ; interrupt-names = "csiphy"; regulator-names = "gdscr", "refgen"; gdscr-supply = <&titan_top_gdsc>; @@ -293,7 +293,7 @@ <0xac42000 0x5000>; reg-cam-base = <0x40000 0x42000>; interrupt-names = "cpas_camnoc"; - interrupts = <0 459 0>; + interrupts = ; qcom,cpas-hw-ver = <0x170110>; /* Titan v170 v1.1.0 */ camnoc-axi-min-ib-bw = <3000000000>; regulator-names = "camss-vdd"; @@ -459,7 +459,7 @@ reg = <0xac6b000 0xa00>; reg-cam-base = <0x6b000>; interrupt-names = "lrme"; - interrupts = <0 476 0>; + interrupts = ; regulator-names = "camss"; camss-supply = <&titan_top_gdsc>; clock-names = "camera_ahb", diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.1-mtp.dts b/arch/arm64/boot/dts/qcom/sdm845-v2.1-mtp.dts index 200801e7d8d1..7a0d7aa3a315 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-v2.1-mtp.dts +++ b/arch/arm64/boot/dts/qcom/sdm845-v2.1-mtp.dts @@ -48,12 +48,12 @@ /delete-property/cd-gpios; #address-cells = <0>; interrupt-parent = <&sdhc_2>; - interrupts = <0 1 2>; + interrupts = ; #interrupt-cells = <1>; interrupt-map-mask = <0xffffffff>; - interrupt-map = <0 &intc 0 204 0 - 1 &intc 0 222 0 - 2 &tlmm 11 0>; + interrupt-map = <0 &intc GIC_SPI 204 IRQ_TYPE_LEVEL_HIGH + 1 &intc GIC_SPI 222 IRQ_TYPE_LEVEL_HIGH + 2 &tlmm 11 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "hc_irq", "pwr_irq", "sdiowakeup_irq"; vdd-supply = <&pm8998_l23>; diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index cf977aa9ec21..e95d9b1d9d23 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -800,7 +800,7 @@ redistributor-stride = <0x0 0x20000>; reg = <0x17a00000 0x10000>, /* GICD */ <0x17a60000 0x100000>; /* GICR * 8 */ - interrupts = <1 9 4>; + interrupts = ; interrupt-parent = <&intc>; ignored-save-restore-irqs = <38>; }; @@ -816,10 +816,10 @@ timer { compatible = "arm,armv8-timer"; - interrupts = <1 1 0xf08>, - <1 2 0xf08>, - <1 3 0xf08>, - <1 0 0xf08>; + interrupts = , + , + , + ; clock-frequency = <19200000>; }; @@ -833,50 +833,50 @@ frame@0x17CA0000 { frame-number = <0>; - interrupts = <0 7 0x4>, - <0 6 0x4>; + interrupts = , + ; reg = <0x17CA0000 0x1000>, <0x17CB0000 0x1000>; }; frame@17cc0000 { frame-number = <1>; - interrupts = <0 8 0x4>; + interrupts = ; reg = <0x17cc0000 0x1000>; status = "disabled"; }; frame@17cd0000 { frame-number = <2>; - interrupts = <0 9 0x4>; + interrupts = ; reg = <0x17cd0000 0x1000>; status = "disabled"; }; frame@17ce0000 { frame-number = <3>; - interrupts = <0 10 0x4>; + interrupts = ; reg = <0x17ce0000 0x1000>; status = "disabled"; }; frame@17cf0000 { frame-number = <4>; - interrupts = <0 11 0x4>; + interrupts = ; reg = <0x17cf0000 0x1000>; status = "disabled"; }; frame@17d00000 { frame-number = <5>; - interrupts = <0 12 0x4>; + interrupts = ; reg = <0x17d00000 0x1000>; status = "disabled"; }; frame@17d10000 { frame-number = <6>; - interrupts = <0 13 0x4>; + interrupts = ; reg = <0x17d10000 0x1000>; status = "disabled"; }; @@ -904,7 +904,7 @@ <0xc40a000 0x26000>; reg-names = "core", "chnls", "obsrvr", "intr", "cnfg"; interrupt-names = "periph_irq"; - interrupts = ; + interrupts = ; qcom,ee = <0>; qcom,channel = <0>; #address-cells = <2>; @@ -993,7 +993,7 @@ compatible = "qcom,bimc-bwmon4"; reg = <0x1436400 0x300>, <0x1436300 0x200>; reg-names = "base", "global_base"; - interrupts = <0 581 4>; + interrupts = ; qcom,mport = <0>; qcom,hw-timer-hz = <19200000>; qcom,target-dev = <&cpubw>; @@ -1159,7 +1159,7 @@ cpu_pmu: cpu-pmu { compatible = "arm,armv8-pmuv3"; qcom,irq-is-percpu; - interrupts = <1 5 4>; + interrupts = ; }; mincpubw: qcom,mincpubw { @@ -1359,7 +1359,7 @@ ufshc_mem: ufshc@1d84000 { compatible = "qcom,ufshc"; reg = <0x1d84000 0x2500>; - interrupts = <0 265 0>; + interrupts = ; phys = <&ufsphy_mem>; phy-names = "ufsphy"; ufs-qcom-crypto = <&ufs_ice>; @@ -1471,7 +1471,8 @@ reg = <0x8804000 0x1000>; reg-names = "hc_mem"; - interrupts = <0 204 0>, <0 222 0>; + interrupts = , + ; interrupt-names = "hc_irq", "pwr_irq"; qcom,bus-width = <4>; @@ -1581,12 +1582,12 @@ qcom,mem-protect-id = <0xF>; /* Inputs from mss */ - interrupts-extended = <&intc GIC_SPI 266 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>; + interrupts-extended = <&intc GIC_SPI 266 IRQ_TYPE_EDGE_RISING>, + <&modem_smp2p_in 0 IRQ_TYPE_LEVEL_HIGH>, + <&modem_smp2p_in 2 IRQ_TYPE_LEVEL_HIGH>, + <&modem_smp2p_in 1 IRQ_TYPE_LEVEL_HIGH>, + <&modem_smp2p_in 3 IRQ_TYPE_LEVEL_HIGH>, + <&modem_smp2p_in 7 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "qcom,wdog", "qcom,err-fatal", @@ -1630,11 +1631,11 @@ memory-region = <&pil_adsp_mem>; /* Inputs from lpass */ - interrupts-extended = <&intc GIC_SPI 162 1>, - <&adsp_smp2p_in 0 0>, - <&adsp_smp2p_in 2 0>, - <&adsp_smp2p_in 1 0>, - <&adsp_smp2p_in 3 0>; + interrupts-extended = <&intc GIC_SPI 162 IRQ_TYPE_EDGE_RISING>, + <&adsp_smp2p_in 0 IRQ_TYPE_LEVEL_HIGH>, + <&adsp_smp2p_in 2 IRQ_TYPE_LEVEL_HIGH>, + <&adsp_smp2p_in 1 IRQ_TYPE_LEVEL_HIGH>, + <&adsp_smp2p_in 3 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "qcom,wdog", "qcom,err-fatal", @@ -1676,11 +1677,11 @@ memory-region = <&pil_slpi_mem>; /* Inputs from ssc */ - interrupts-extended = <&intc GIC_SPI 494 1>, - <&dsps_smp2p_in 0 0>, - <&dsps_smp2p_in 2 0>, - <&dsps_smp2p_in 1 0>, - <&dsps_smp2p_in 3 0>; + interrupts-extended = <&intc GIC_SPI 494 IRQ_TYPE_EDGE_RISING>, + <&dsps_smp2p_in 0 IRQ_TYPE_LEVEL_HIGH>, + <&dsps_smp2p_in 2 IRQ_TYPE_LEVEL_HIGH>, + <&dsps_smp2p_in 1 IRQ_TYPE_LEVEL_HIGH>, + <&dsps_smp2p_in 3 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "qcom,wdog", "qcom,err-fatal", @@ -1702,7 +1703,8 @@ reg = <0x171c0000 0x2c000>, <0x17184000 0x2a000>; reg-names = "slimbus_physical", "slimbus_bam_physical"; - interrupts = <0 163 0>, <0 164 0>; + interrupts = , + ; interrupt-names = "slimbus_irq", "slimbus_bam_irq"; qcom,apps-ch-pipes = <0x780000>; qcom,ea-pc = <0x270>; @@ -1724,7 +1726,8 @@ reg = <0x17240000 0x2c000>, <0x17204000 0x20000>; reg-names = "slimbus_physical", "slimbus_bam_physical"; - interrupts = <0 291 0>, <0 292 0>; + interrupts = , + ; interrupt-names = "slimbus_irq", "slimbus_bam_irq"; qcom,iommu-s1-bypass; @@ -1763,7 +1766,7 @@ <0x1882014 0x4>; reg-names = "sp2soc_irq_status", "sp2soc_irq_clr", "sp2soc_irq_mask", "rmb_err", "rmb_err_spare2"; - interrupts = <0 352 1>; + interrupts = ; vdd_cx-supply = <&pm8998_s9_level>; qcom,proxy-reg-names = "vdd_cx"; @@ -1792,7 +1795,8 @@ compatible = "qcom,msm-watchdog"; reg = <0x17980000 0x1000>; reg-names = "wdt-base"; - interrupts = <0 0 0>, <0 1 0>; + interrupts = , + ; qcom,bark-time = <11000>; qcom,pet-time = <9360>; qcom,ipi-ping; @@ -1821,11 +1825,11 @@ memory-region = <&pil_cdsp_mem>; /* Inputs from turing */ - interrupts-extended = <&intc GIC_SPI 578 1>, - <&cdsp_smp2p_in 0 0>, - <&cdsp_smp2p_in 2 0>, - <&cdsp_smp2p_in 1 0>, - <&cdsp_smp2p_in 3 0>; + interrupts-extended = <&intc GIC_SPI 578 IRQ_TYPE_EDGE_RISING>, + <&cdsp_smp2p_in 0 IRQ_TYPE_LEVEL_HIGH>, + <&cdsp_smp2p_in 2 IRQ_TYPE_LEVEL_HIGH>, + <&cdsp_smp2p_in 1 IRQ_TYPE_LEVEL_HIGH>, + <&cdsp_smp2p_in 3 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "qcom,wdog", "qcom,err-fatal", @@ -1856,7 +1860,7 @@ compatible = "qcom,smp2p-sleepstate"; qcom,smem-states = <&sleepstate_smp2p_out 0>; interrupt-parent = <&sleepstate_smp2p_in>; - interrupts = <0 0>; + interrupts = <0 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "smp2p-sleepstate-in"; }; @@ -2143,10 +2147,10 @@ kryo3xx-erp { compatible = "arm,arm64-kryo3xx-cpu-erp"; - interrupts = <1 6 4>, - <1 7 4>, - <0 34 4>, - <0 35 4>; + interrupts = , + , + , + ; interrupt-names = "l1-l2-faultirq", "l1-l2-errirq", @@ -2207,7 +2211,7 @@ <0x1799000c 0x4>; reg-names = "msgram", "irq-reg-base"; qcom,irq-mask = <0x1>; - interrupts = <0 389 1>; + interrupts = ; priority = <0>; mbox-desc-offset = <0x0>; #mbox-cells = <1>; @@ -2291,8 +2295,8 @@ compatible = "qcom,sdm845-qsee-irq"; syscon = <&sp_scsr_block>; - interrupts = <0 348 IRQ_TYPE_LEVEL_HIGH>, - <0 349 IRQ_TYPE_LEVEL_HIGH>; + interrupts = , + ; interrupt-names = "sp_ipc0", "sp_ipc1"; @@ -2463,7 +2467,7 @@ mboxes = <&sp_scsr 0>; mbox-names = "spss_spss"; interrupt-parent = <&intsp>; - interrupts = <0 0 IRQ_TYPE_LEVEL_HIGH>; + interrupts = ; reg = <0x1885008 0x8>, <0x1885010 0x4>; @@ -2688,7 +2692,7 @@ reg = <0x1de0000 0x20000>, <0x1dc4000 0x24000>; reg-names = "crypto-base","crypto-bam-base"; - interrupts = <0 272 0>; + interrupts = ; qcom,bam-pipe-pair = <3>; qcom,ce-hw-instance = <0>; qcom,ce-device = <0>; @@ -2744,7 +2748,7 @@ reg = <0x1de0000 0x20000>, <0x1dc4000 0x24000>; reg-names = "crypto-base","crypto-bam-base"; - interrupts = <0 272 0>; + interrupts = ; qcom,bam-pipe-pair = <2>; qcom,ce-hw-instance = <0>; qcom,ce-device = <0>; @@ -2802,8 +2806,8 @@ <0x1e04000 0x2c000>; reg-names = "ipa-base", "gsi-base"; interrupts = - <0 311 0>, - <0 432 0>; + , + ; interrupt-names = "ipa-irq", "gsi-irq"; qcom,ipa-hw-ver = <13>; /* IPA core version = IPAv3.5.1 */ qcom,ipa-hw-mode = <0>; @@ -2932,7 +2936,7 @@ qcom,smp2p_map_ipa_1_in { compatible = "qcom,smp2p-map-ipa-1-in"; - interrupts-extended = <&smp2p_ipa_1_in 0 0>; + interrupts-extended = <&smp2p_ipa_1_in 0 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "ipa-smp2p-in"; }; @@ -2996,7 +3000,7 @@ compatible = "qcom,msm-gladiator-v3"; reg = <0x17900000 0xd080>; reg-names = "gladiator_base"; - interrupts = <0 17 0>; + interrupts = ; }; dcc: dcc_v2@10a2000 { @@ -3218,18 +3222,18 @@ <0xb0000000 0x10000>; reg-names = "membase", "smmu_iova_base", "smmu_iova_ipa"; iommus = <&apps_smmu 0x0040 0x1>; - interrupts = <0 414 0 /* CE0 */ >, - <0 415 0 /* CE1 */ >, - <0 416 0 /* CE2 */ >, - <0 417 0 /* CE3 */ >, - <0 418 0 /* CE4 */ >, - <0 419 0 /* CE5 */ >, - <0 420 0 /* CE6 */ >, - <0 421 0 /* CE7 */ >, - <0 422 0 /* CE8 */ >, - <0 423 0 /* CE9 */ >, - <0 424 0 /* CE10 */ >, - <0 425 0 /* CE11 */ >; + interrupts = , + , + , + , + , + , + , + , + , + , + , + ; qcom,wlan-msa-memory = <0x100000>; vdd-0.8-cx-mx-supply = <&pm8998_l5>; @@ -3240,7 +3244,7 @@ qcom,vdd-3.3-ch0-config = <3104000 3312000>; qcom,smp2p_map_wlan_1_in { - interrupts-extended = <&smp2p_wlan_1_in 0 0>, + interrupts-extended = <&smp2p_wlan_1_in 0 IRQ_TYPE_LEVEL_HIGH>, <&smp2p_wlan_1_in 1 0>; interrupt-names = "qcom,smp2p-force-fatal-error", "qcom,smp2p-early-crash-ind"; @@ -3999,7 +4003,8 @@ <0xc263000 0x1ff>; reg-names = "tsens_srot_physical", "tsens_tm_physical"; - interrupts = <0 506 0>, <0 508 0>; + interrupts = , + ; interrupt-names = "tsens-upper-lower", "tsens-critical"; #thermal-sensor-cells = <1>; }; @@ -4010,7 +4015,8 @@ <0xc265000 0x1ff>; reg-names = "tsens_srot_physical", "tsens_tm_physical"; - interrupts = <0 507 0>, <0 509 0>; + interrupts = , + ; interrupt-names = "tsens-upper-lower", "tsens-critical"; #thermal-sensor-cells = <1>; }; @@ -4080,10 +4086,19 @@ compatible = "qcom,gpi-dma"; reg = <0x800000 0x60000>; reg-names = "gpi-top"; - interrupts = <0 244 0>, <0 245 0>, <0 246 0>, <0 247 0>, - <0 248 0>, <0 249 0>, <0 250 0>, <0 251 0>, - <0 252 0>, <0 253 0>, <0 254 0>, <0 255 0>, - <0 256 0>; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + ; qcom,max-num-gpii = <13>; qcom,gpii-mask = <0xfa>; qcom,ev-factor = <2>; @@ -4098,10 +4113,19 @@ compatible = "qcom,gpi-dma"; reg = <0xa00000 0x60000>; reg-names = "gpi-top"; - interrupts = <0 279 0>, <0 280 0>, <0 281 0>, <0 282 0>, - <0 283 0>, <0 284 0>, <0 293 0>, <0 294 0>, - <0 295 0>, <0 296 0>, <0 297 0>, <0 298 0>, - <0 299 0>; + interrupts = , + , + , + , + , + , + , + , + , + , + , + , + ; qcom,max-num-gpii = <13>; qcom,gpii-mask = <0xfa>; qcom,ev-factor = <2>; @@ -4121,10 +4145,10 @@ "MSM_TSIF1_PHYS", "MSM_TSPP_PHYS", "MSM_TSPP_BAM_PHYS"; - interrupts = <0 121 0>, /* TSIF_TSPP_IRQ */ - <0 119 0>, /* TSIF0_IRQ */ - <0 120 0>, /* TSIF1_IRQ */ - <0 122 0>; /* TSIF_BAM_IRQ */ + interrupts = , /* TSIF_TSPP_IRQ */ + , /* TSIF0_IRQ */ + , /* TSIF1_IRQ */ + ; /* TSIF_BAM_IRQ */ interrupt-names = "TSIF_TSPP_IRQ", "TSIF0_IRQ", "TSIF1_IRQ", From 0da97f3bd4e2b7a8747c7d099f783ffe8276ba5d Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Wed, 24 Nov 2021 07:32:38 +0200 Subject: [PATCH 022/356] arm64: dts: sdm845: Update interrupt controller Set GICv3 as interrupt controller as SOC interrupt parent and as a child domain under intc. Signed-off-by: Pavel Dubrova --- arch/arm64/boot/dts/qcom/sdm845-pcie.dtsi | 76 ++++++++++---------- arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi | 1 - arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi | 4 +- arch/arm64/boot/dts/qcom/sdm845-sde.dtsi | 1 - arch/arm64/boot/dts/qcom/sdm845.dtsi | 2 +- 5 files changed, 41 insertions(+), 43 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845-pcie.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pcie.dtsi index ca2f5497b890..41918e2d0cc9 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-pcie.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-pcie.dtsi @@ -31,44 +31,44 @@ 36 37>; #interrupt-cells = <1>; interrupt-map-mask = <0 0 0 0xffffffff>; - interrupt-map = <0 0 0 0 &pdc GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH - 0 0 0 1 &pdc GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH - 0 0 0 2 &pdc GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH - 0 0 0 3 &pdc GIC_SPI 151 IRQ_TYPE_LEVEL_HIGH - 0 0 0 4 &pdc GIC_SPI 152 IRQ_TYPE_LEVEL_HIGH - 0 0 0 5 &pdc GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH - 0 0 0 6 &pdc GIC_SPI 672 IRQ_TYPE_LEVEL_HIGH - 0 0 0 7 &pdc GIC_SPI 673 IRQ_TYPE_LEVEL_HIGH - 0 0 0 8 &pdc GIC_SPI 674 IRQ_TYPE_LEVEL_HIGH - 0 0 0 9 &pdc GIC_SPI 675 IRQ_TYPE_LEVEL_HIGH - 0 0 0 10 &pdc GIC_SPI 676 IRQ_TYPE_LEVEL_HIGH - 0 0 0 11 &pdc GIC_SPI 677 IRQ_TYPE_LEVEL_HIGH - 0 0 0 12 &pdc GIC_SPI 678 IRQ_TYPE_LEVEL_HIGH - 0 0 0 13 &pdc GIC_SPI 679 IRQ_TYPE_LEVEL_HIGH - 0 0 0 14 &pdc GIC_SPI 680 IRQ_TYPE_LEVEL_HIGH - 0 0 0 15 &pdc GIC_SPI 681 IRQ_TYPE_LEVEL_HIGH - 0 0 0 16 &pdc GIC_SPI 682 IRQ_TYPE_LEVEL_HIGH - 0 0 0 17 &pdc GIC_SPI 683 IRQ_TYPE_LEVEL_HIGH - 0 0 0 18 &pdc GIC_SPI 684 IRQ_TYPE_LEVEL_HIGH - 0 0 0 19 &pdc GIC_SPI 685 IRQ_TYPE_LEVEL_HIGH - 0 0 0 20 &pdc GIC_SPI 686 IRQ_TYPE_LEVEL_HIGH - 0 0 0 21 &pdc GIC_SPI 687 IRQ_TYPE_LEVEL_HIGH - 0 0 0 22 &pdc GIC_SPI 688 IRQ_TYPE_LEVEL_HIGH - 0 0 0 23 &pdc GIC_SPI 689 IRQ_TYPE_LEVEL_HIGH - 0 0 0 24 &pdc GIC_SPI 690 IRQ_TYPE_LEVEL_HIGH - 0 0 0 25 &pdc GIC_SPI 691 IRQ_TYPE_LEVEL_HIGH - 0 0 0 26 &pdc GIC_SPI 692 IRQ_TYPE_LEVEL_HIGH - 0 0 0 27 &pdc GIC_SPI 693 IRQ_TYPE_LEVEL_HIGH - 0 0 0 28 &pdc GIC_SPI 694 IRQ_TYPE_LEVEL_HIGH - 0 0 0 29 &pdc GIC_SPI 695 IRQ_TYPE_LEVEL_HIGH - 0 0 0 30 &pdc GIC_SPI 696 IRQ_TYPE_LEVEL_HIGH - 0 0 0 31 &pdc GIC_SPI 697 IRQ_TYPE_LEVEL_HIGH - 0 0 0 32 &pdc GIC_SPI 698 IRQ_TYPE_LEVEL_HIGH - 0 0 0 33 &pdc GIC_SPI 699 IRQ_TYPE_LEVEL_HIGH - 0 0 0 34 &pdc GIC_SPI 700 IRQ_TYPE_LEVEL_HIGH - 0 0 0 35 &pdc GIC_SPI 701 IRQ_TYPE_LEVEL_HIGH - 0 0 0 36 &pdc GIC_SPI 702 IRQ_TYPE_LEVEL_HIGH - 0 0 0 37 &pdc GIC_SPI 703 IRQ_TYPE_LEVEL_HIGH>; + interrupt-map = <0 0 0 0 &intc GIC_SPI 141 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 + 0 0 0 5 &intc GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH + 0 0 0 6 &intc GIC_SPI 672 IRQ_TYPE_LEVEL_HIGH + 0 0 0 7 &intc GIC_SPI 673 IRQ_TYPE_LEVEL_HIGH + 0 0 0 8 &intc GIC_SPI 674 IRQ_TYPE_LEVEL_HIGH + 0 0 0 9 &intc GIC_SPI 675 IRQ_TYPE_LEVEL_HIGH + 0 0 0 10 &intc GIC_SPI 676 IRQ_TYPE_LEVEL_HIGH + 0 0 0 11 &intc GIC_SPI 677 IRQ_TYPE_LEVEL_HIGH + 0 0 0 12 &intc GIC_SPI 678 IRQ_TYPE_LEVEL_HIGH + 0 0 0 13 &intc GIC_SPI 679 IRQ_TYPE_LEVEL_HIGH + 0 0 0 14 &intc GIC_SPI 680 IRQ_TYPE_LEVEL_HIGH + 0 0 0 15 &intc GIC_SPI 681 IRQ_TYPE_LEVEL_HIGH + 0 0 0 16 &intc GIC_SPI 682 IRQ_TYPE_LEVEL_HIGH + 0 0 0 17 &intc GIC_SPI 683 IRQ_TYPE_LEVEL_HIGH + 0 0 0 18 &intc GIC_SPI 684 IRQ_TYPE_LEVEL_HIGH + 0 0 0 19 &intc GIC_SPI 685 IRQ_TYPE_LEVEL_HIGH + 0 0 0 20 &intc GIC_SPI 686 IRQ_TYPE_LEVEL_HIGH + 0 0 0 21 &intc GIC_SPI 687 IRQ_TYPE_LEVEL_HIGH + 0 0 0 22 &intc GIC_SPI 688 IRQ_TYPE_LEVEL_HIGH + 0 0 0 23 &intc GIC_SPI 689 IRQ_TYPE_LEVEL_HIGH + 0 0 0 24 &intc GIC_SPI 690 IRQ_TYPE_LEVEL_HIGH + 0 0 0 25 &intc GIC_SPI 691 IRQ_TYPE_LEVEL_HIGH + 0 0 0 26 &intc GIC_SPI 692 IRQ_TYPE_LEVEL_HIGH + 0 0 0 27 &intc GIC_SPI 693 IRQ_TYPE_LEVEL_HIGH + 0 0 0 28 &intc GIC_SPI 694 IRQ_TYPE_LEVEL_HIGH + 0 0 0 29 &intc GIC_SPI 695 IRQ_TYPE_LEVEL_HIGH + 0 0 0 30 &intc GIC_SPI 696 IRQ_TYPE_LEVEL_HIGH + 0 0 0 31 &intc GIC_SPI 697 IRQ_TYPE_LEVEL_HIGH + 0 0 0 32 &intc GIC_SPI 698 IRQ_TYPE_LEVEL_HIGH + 0 0 0 33 &intc GIC_SPI 699 IRQ_TYPE_LEVEL_HIGH + 0 0 0 34 &intc GIC_SPI 700 IRQ_TYPE_LEVEL_HIGH + 0 0 0 35 &intc GIC_SPI 701 IRQ_TYPE_LEVEL_HIGH + 0 0 0 36 &intc GIC_SPI 702 IRQ_TYPE_LEVEL_HIGH + 0 0 0 37 &intc GIC_SPI 703 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "int_msi", "int_a", "int_b", "int_c", "int_d", "int_global_int", diff --git a/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi index 5049dbf04ed3..359f0feac9f0 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi @@ -13,7 +13,6 @@ #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; - interrupt-parent = <&pdc>; ufs_dev_reset_assert: ufs_dev_reset_assert { config { diff --git a/arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi b/arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi index 777b2e33d2d0..85f5c889a581 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi @@ -37,7 +37,7 @@ <&qupv3_se6_tx> ; pinctrl-1 = <&qupv3_se6_ctsrx>, <&qupv3_se6_rts>, <&qupv3_se6_tx> ; - interrupts-extended = <&pdc GIC_SPI 607 IRQ_TYPE_LEVEL_HIGH>, + interrupts-extended = <&intc GIC_SPI 607 IRQ_TYPE_LEVEL_HIGH>, <&tlmm 48 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; qcom,wakeup-byte = <0xFD>; @@ -55,7 +55,7 @@ pinctrl-names = "default", "sleep"; pinctrl-0 = <&qupv3_se7_4uart_active>; pinctrl-1 = <&qupv3_se7_4uart_sleep>; - interrupts-extended = <&pdc GIC_SPI 608 IRQ_TYPE_LEVEL_HIGH>, + interrupts-extended = <&intc GIC_SPI 608 IRQ_TYPE_LEVEL_HIGH>, <&tlmm 96 IRQ_TYPE_LEVEL_HIGH>; status = "disabled"; qcom,wakeup-byte = <0xFD>; diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi index 47a954f2366f..028425556513 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi @@ -30,7 +30,6 @@ sde-vdd-supply = <&mdss_core_gdsc>; /* interrupt config */ - interrupt-parent = <&pdc>; interrupts = ; interrupt-controller; #interrupt-cells = <1>; diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index e95d9b1d9d23..183a141e6318 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -26,7 +26,7 @@ model = "Qualcomm Technologies, Inc. SDM845"; compatible = "qcom,sdm845"; qcom,msm-id = <321 0x10000>; - interrupt-parent = <&pdc>; + interrupt-parent = <&intc>; aliases { ufshc1 = &ufshc_mem; /* Embedded UFS slot */ From 8d19508f9df4bf7a0c88d60d1cb9cf001b3ffe0e Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Thu, 11 Nov 2021 19:53:44 +0200 Subject: [PATCH 023/356] arm64: dts: qcom: sdm845-gpu: Disable iommu dma for GPU and GMU Set iommu dma to disabled for GPU and GMU as GPU takes care of creating desired dma mapping by itself. Signed-off-by: Pavel Dubrova --- arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi b/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi index 8347497ff351..e396ecf4c983 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi @@ -307,12 +307,14 @@ compatible = "qcom,smmu-kgsl-cb"; label = "gfx3d_user"; iommus = <&kgsl_smmu 0>; + qcom,iommu-dma = "disabled"; qcom,gpu-offset = <0x48000>; }; gfx3d_secure: gfx3d_secure { compatible = "qcom,smmu-kgsl-cb"; iommus = <&kgsl_smmu 2>, <&kgsl_smmu 1>; + qcom,iommu-dma = "disabled"; }; }; @@ -373,11 +375,13 @@ gmu_user: gmu_user { compatible = "qcom,smmu-gmu-user-cb"; iommus = <&kgsl_smmu 4>; + qcom,iommu-dma = "disabled"; }; gmu_kernel: gmu_kernel { compatible = "qcom,smmu-gmu-kernel-cb"; iommus = <&kgsl_smmu 5>; + qcom,iommu-dma = "disabled"; }; }; }; From 33fb6a33493087501e31ab19651b3e776e4942fd Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Thu, 11 Nov 2021 19:48:17 +0200 Subject: [PATCH 024/356] arm64: dts: qcom: sdm845: Add early-boot prop to AOP QMP The AOP processor may trigger an interrupt to the APPS proc before the QMP driver is probed. Add early-boot property so QMP knows to check for missed interrupts. Signed-off-by: Pavel Dubrova --- arch/arm64/boot/dts/qcom/sdm845.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index 183a141e6318..f891a70000ee 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -2212,6 +2212,7 @@ reg-names = "msgram", "irq-reg-base"; qcom,irq-mask = <0x1>; interrupts = ; + qcom,early-boot; priority = <0>; mbox-desc-offset = <0x0>; #mbox-cells = <1>; From 4e0b809e7fe6da0a45238e9d1a04c8400af09fc6 Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Thu, 11 Nov 2021 20:34:45 +0200 Subject: [PATCH 025/356] arm64: dts: qcom: sdm845-pinctrl: Add PDC GPIO mapping Add PDC to GPIO mapping to wakeup the APSS from deep sleep. Signed-off-by: Pavel Dubrova --- arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi | 79 ++++++++++++++++++++ arch/arm64/boot/dts/qcom/sdm845-v2.dtsi | 79 ++++++++++++++++++++ 2 files changed, 158 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi index 359f0feac9f0..99e146c66569 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi @@ -13,6 +13,85 @@ #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; + wakeup-parent = <&pdc>; + irqdomain-map = <1 0 &pdc 30 0>, + <3 0 &pdc 31 0>, + <5 0 &pdc 32 0>, + <10 0 &pdc 33 0>, + <11 0 &pdc 34 0>, + <20 0 &pdc 35 0>, + <22 0 &pdc 36 0>, + <24 0 &pdc 37 0>, + <26 0 &pdc 38 0>, + <30 0 &pdc 39 0>, + <31 0 &pdc 117 0>, + <32 0 &pdc 41 0>, + <34 0 &pdc 42 0>, + <36 0 &pdc 43 0>, + <37 0 &pdc 44 0>, + <38 0 &pdc 45 0>, + <39 0 &pdc 46 0>, + <40 0 &pdc 47 0>, + <41 0 &pdc 115 0>, + <43 0 &pdc 49 0>, + <44 0 &pdc 50 0>, + <46 0 &pdc 51 0>, + <48 0 &pdc 52 0>, + <49 0 &pdc 118 0>, + <52 0 &pdc 54 0>, + <53 0 &pdc 55 0>, + <54 0 &pdc 56 0>, + <56 0 &pdc 57 0>, + <57 0 &pdc 58 0>, + <58 0 &pdc 59 0>, + <59 0 &pdc 60 0>, + <60 0 &pdc 61 0>, + <61 0 &pdc 62 0>, + <62 0 &pdc 63 0>, + <63 0 &pdc 64 0>, + <64 0 &pdc 65 0>, + <66 0 &pdc 66 0>, + <68 0 &pdc 67 0>, + <71 0 &pdc 68 0>, + <73 0 &pdc 69 0>, + <77 0 &pdc 70 0>, + <78 0 &pdc 71 0>, + <79 0 &pdc 72 0>, + <80 0 &pdc 73 0>, + <84 0 &pdc 74 0>, + <85 0 &pdc 75 0>, + <86 0 &pdc 76 0>, + <88 0 &pdc 77 0>, + <89 0 &pdc 116 0>, + <91 0 &pdc 79 0>, + <92 0 &pdc 80 0>, + <95 0 &pdc 81 0>, + <96 0 &pdc 82 0>, + <97 0 &pdc 83 0>, + <101 0 &pdc 84 0>, + <103 0 &pdc 85 0>, + <104 0 &pdc 86 0>, + <115 0 &pdc 90 0>, + <116 0 &pdc 91 0>, + <117 0 &pdc 92 0>, + <118 0 &pdc 93 0>, + <119 0 &pdc 94 0>, + <120 0 &pdc 95 0>, + <121 0 &pdc 96 0>, + <122 0 &pdc 97 0>, + <123 0 &pdc 98 0>, + <124 0 &pdc 99 0>, + <125 0 &pdc 100 0>, + //<126 0 &pdc ?? 0>, + <127 0 &pdc 102 0>, + <128 0 &pdc 103 0>, + <129 0 &pdc 104 0>, + <130 0 &pdc 105 0>, + <132 0 &pdc 106 0>, + <133 0 &pdc 107 0>, + <145 0 &pdc 108 0>; + irqdomain-map-mask = <0xff 0>; + irqdomain-map-pass-thru = <0 0xff>; ufs_dev_reset_assert: ufs_dev_reset_assert { config { diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi index 428e0dc3d556..2e303ba9907a 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi @@ -21,6 +21,85 @@ &tlmm { compatible = "qcom,sdm845-pinctrl-v2"; + irqdomain-map = <1 0 &pdc 30 0>, + <3 0 &pdc 31 0>, + <5 0 &pdc 32 0>, + <10 0 &pdc 33 0>, + <11 0 &pdc 34 0>, + <20 0 &pdc 35 0>, + <22 0 &pdc 36 0>, + <24 0 &pdc 37 0>, + <26 0 &pdc 38 0>, + <30 0 &pdc 39 0>, + <31 0 &pdc 117 0>, + <32 0 &pdc 41 0>, + <34 0 &pdc 42 0>, + <36 0 &pdc 43 0>, + <37 0 &pdc 44 0>, + <38 0 &pdc 45 0>, + <39 0 &pdc 46 0>, + <40 0 &pdc 47 0>, + <41 0 &pdc 115 0>, + <43 0 &pdc 49 0>, + <44 0 &pdc 50 0>, + <46 0 &pdc 51 0>, + <48 0 &pdc 52 0>, + <49 0 &pdc 118 0>, + <52 0 &pdc 54 0>, + <53 0 &pdc 55 0>, + <54 0 &pdc 56 0>, + <56 0 &pdc 57 0>, + <57 0 &pdc 58 0>, + <58 0 &pdc 59 0>, + <59 0 &pdc 60 0>, + <60 0 &pdc 61 0>, + <61 0 &pdc 62 0>, + <62 0 &pdc 63 0>, + <63 0 &pdc 64 0>, + <64 0 &pdc 65 0>, + <66 0 &pdc 66 0>, + <68 0 &pdc 67 0>, + <71 0 &pdc 68 0>, + <73 0 &pdc 69 0>, + <77 0 &pdc 70 0>, + <78 0 &pdc 71 0>, + <79 0 &pdc 72 0>, + <80 0 &pdc 73 0>, + <84 0 &pdc 74 0>, + <85 0 &pdc 75 0>, + <86 0 &pdc 76 0>, + <88 0 &pdc 77 0>, + <89 0 &pdc 116 0>, + <91 0 &pdc 79 0>, + <92 0 &pdc 80 0>, + <95 0 &pdc 81 0>, + <96 0 &pdc 82 0>, + <97 0 &pdc 83 0>, + <101 0 &pdc 84 0>, + <103 0 &pdc 85 0>, + //<108 0 &pdc ?? 0>, + //<112 0 &pdc ?? 0>, + //<113 0 &pdc ?? 0>, + <104 0 &pdc 86 0>, + <115 0 &pdc 90 0>, + <116 0 &pdc 91 0>, + <117 0 &pdc 92 0>, + <118 0 &pdc 93 0>, + <119 0 &pdc 94 0>, + <120 0 &pdc 95 0>, + <121 0 &pdc 96 0>, + <122 0 &pdc 97 0>, + <123 0 &pdc 98 0>, + <124 0 &pdc 99 0>, + <125 0 &pdc 100 0>, + //<126 0 &pdc ?? 0>, + <127 0 &pdc 102 0>, + <128 0 &pdc 103 0>, + <129 0 &pdc 104 0>, + <130 0 &pdc 105 0>, + <132 0 &pdc 106 0>, + <133 0 &pdc 107 0>, + <145 0 &pdc 108 0>; }; &soc { From 77a14e9d90ea038a7d1a2b3a2fc7a2bb3e39ac8f Mon Sep 17 00:00:00 2001 From: "Angelo G. Del Regno" Date: Fri, 12 Jul 2019 17:20:04 +0200 Subject: [PATCH 026/356] arm64: DT: SDM845: Fix SPS 4K compatible name The name changed from qcom,msm_sps_4k to qcom,msm-sps-4k. --- arch/arm64/boot/dts/qcom/sdm845.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index f891a70000ee..2268d34bec71 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -2623,7 +2623,7 @@ }; qcom,sps { - compatible = "qcom,msm_sps_4k"; + compatible = "qcom,msm-sps-4k"; qcom,pipe-attr-ee; }; From fdb7a5d5de963981ef4b4153af0008fc0d6cb11d Mon Sep 17 00:00:00 2001 From: MarijnS95 Date: Tue, 28 May 2019 20:40:22 +0200 Subject: [PATCH 027/356] arm64: DT: sdm845-pm: Convert latencies as per latest k4.14 spec. The latencies in the k4.14 lpm_levels driver have to be specified directly in the DT, without the driver calculating them based on other real hardware parameters. Port the DT to adhere to this. Change-Id: I55b720c53255c2b3af3216ad7a42dc336e4702a7 Signed-off-by: MarijnS95 --- arch/arm64/boot/dts/qcom/sdm845-pm.dtsi | 56 +++++++++++-------------- 1 file changed, 24 insertions(+), 32 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi index dd9bafc76adc..e25180c4a43e 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi @@ -22,20 +22,18 @@ reg = <0>; label = "l3-wfi"; qcom,psci-mode = <0x1>; - qcom,latency-us = <51>; - qcom,ss-power = <452>; - qcom,energy-overhead = <69355>; - qcom,time-overhead = <99>; + 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,latency-us = <6562>; - qcom,ss-power = <108>; - qcom,energy-overhead = <4000000>; - qcom,time-overhead = <5000>; + qcom,entry-latency-us = <1562>; + qcom,exit-latency-us = <6562>; + qcom,min-residency-us = <9987>; qcom,min-child-idx = <2>; qcom,is-reset; qcom,notify-rpm; @@ -55,20 +53,18 @@ reg = <0>; label = "wfi"; qcom,psci-cpu-mode = <0x1>; - qcom,latency-us = <43>; - qcom,ss-power = <150>; - qcom,energy-overhead = <10000>; - qcom,time-overhead = <100>; + qcom,entry-latency-us = <57>; + qcom,exit-latency-us = <43>; + qcom,min-residency-us = <100>; }; qcom,pm-cpu-level@1 { /* C3 */ reg = <1>; label = "pc"; qcom,psci-cpu-mode = <0x3>; - qcom,latency-us = <461>; - qcom,ss-power = <100>; - qcom,energy-overhead = <400000>; - qcom,time-overhead = <500>; + qcom,entry-latency-us = <39>; + qcom,exit-latency-us = <461>; + qcom,min-residency-us = <5990>; qcom,is-reset; qcom,use-broadcast-timer; }; @@ -77,10 +73,9 @@ reg = <2>; label = "rail-pc"; qcom,psci-cpu-mode = <0x4>; - qcom,latency-us = <531>; - qcom,ss-power = <73>; - qcom,energy-overhead = <500000>; - qcom,time-overhead = <600>; + qcom,entry-latency-us = <69>; + qcom,exit-latency-us = <531>; + qcom,min-residency-us = <3934>; qcom,is-reset; qcom,use-broadcast-timer; }; @@ -100,20 +95,18 @@ reg = <0>; label = "wfi"; qcom,psci-cpu-mode = <0x1>; - qcom,latency-us = <43>; - qcom,ss-power = <454>; - qcom,energy-overhead = <38639>; - qcom,time-overhead = <83>; + qcom,entry-latency-us = <40>; + qcom,exit-latency-us = <43>; + qcom,min-residency-us = <83>; }; qcom,pm-cpu-level@1 { /* C3 */ reg = <1>; label = "pc"; qcom,psci-cpu-mode = <0x3>; - qcom,latency-us = <621>; - qcom,ss-power = <436>; - qcom,energy-overhead = <418225>; - qcom,time-overhead = <885>; + qcom,entry-latency-us = <264>; + qcom,exit-latency-us = <621>; + qcom,min-residency-us = <1001>; qcom,is-reset; qcom,use-broadcast-timer; }; @@ -122,10 +115,9 @@ reg = <2>; label = "rail-pc"; qcom,psci-cpu-mode = <0x4>; - qcom,latency-us = <1061>; - qcom,ss-power = <400>; - qcom,energy-overhead = <428225>; - qcom,time-overhead = <1000>; + qcom,entry-latency-us = <61>; + qcom,exit-latency-us = <1061>; + qcom,min-residency-us = <1001>; qcom,is-reset; qcom,use-broadcast-timer; }; From af1072410ad4920edc2c744ce833d077d7ec53cb Mon Sep 17 00:00:00 2001 From: Artem Labazov <123321artyom@gmail.com> Date: Thu, 6 Jun 2019 17:58:13 +0300 Subject: [PATCH 028/356] arm64: DT: SDM845: Rename efficiency property to capacity-dmips-mhz Signed-off-by: Artem Labazov <123321artyom@gmail.com> --- arch/arm64/boot/dts/qcom/sdm845.dtsi | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index 2268d34bec71..bb0598603fad 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -52,7 +52,7 @@ compatible = "arm,armv8"; reg = <0x0 0x0>; enable-method = "psci"; - efficiency = <1024>; + capacity-dmips-mhz = <1024>; cache-size = <0x8000>; cpu-release-addr = <0x0 0x90000000>; qcom,lmh-dcvs = <&lmh_dcvs0>; @@ -89,7 +89,7 @@ compatible = "arm,armv8"; reg = <0x0 0x100>; enable-method = "psci"; - efficiency = <1024>; + capacity-dmips-mhz = <1024>; cache-size = <0x8000>; cpu-release-addr = <0x0 0x90000000>; qcom,lmh-dcvs = <&lmh_dcvs0>; @@ -120,7 +120,7 @@ compatible = "arm,armv8"; reg = <0x0 0x200>; enable-method = "psci"; - efficiency = <1024>; + capacity-dmips-mhz = <1024>; cache-size = <0x8000>; cpu-release-addr = <0x0 0x90000000>; qcom,lmh-dcvs = <&lmh_dcvs0>; @@ -151,7 +151,7 @@ compatible = "arm,armv8"; reg = <0x0 0x300>; enable-method = "psci"; - efficiency = <1024>; + capacity-dmips-mhz = <1024>; cache-size = <0x8000>; cpu-release-addr = <0x0 0x90000000>; qcom,lmh-dcvs = <&lmh_dcvs0>; @@ -182,7 +182,7 @@ compatible = "arm,armv8"; reg = <0x0 0x400>; enable-method = "psci"; - efficiency = <1740>; + capacity-dmips-mhz = <1740>; cache-size = <0x20000>; cpu-release-addr = <0x0 0x90000000>; qcom,lmh-dcvs = <&lmh_dcvs1>; @@ -213,7 +213,7 @@ compatible = "arm,armv8"; reg = <0x0 0x500>; enable-method = "psci"; - efficiency = <1740>; + capacity-dmips-mhz = <1740>; cache-size = <0x20000>; cpu-release-addr = <0x0 0x90000000>; qcom,lmh-dcvs = <&lmh_dcvs1>; @@ -244,7 +244,7 @@ compatible = "arm,armv8"; reg = <0x0 0x600>; enable-method = "psci"; - efficiency = <1740>; + capacity-dmips-mhz = <1740>; cache-size = <0x20000>; cpu-release-addr = <0x0 0x90000000>; qcom,lmh-dcvs = <&lmh_dcvs1>; @@ -275,7 +275,7 @@ compatible = "arm,armv8"; reg = <0x0 0x700>; enable-method = "psci"; - efficiency = <1740>; + capacity-dmips-mhz = <1740>; cache-size = <0x20000>; cpu-release-addr = <0x0 0x90000000>; qcom,lmh-dcvs = <&lmh_dcvs1>; From 048e4f0be0b6aee0ea446104e0b3512041cfe807 Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Sat, 13 Nov 2021 21:29:56 +0200 Subject: [PATCH 029/356] arm64: dts: qcom: sdm845: Update memlat nodes Update the arm-memlat-mon nodes for new design[1] where multiple monitors are managed by a single controller. Update bandwidth tables in terms of operating points instead of instantaneous bandwidth (IB) votes. [1] An instance of arm-memlat-mon must be described in two levels of device nodes. The first level describes the controller while the second level describes the monitors that the controller manages. At least one monitor is required per controller. Signed-off-by: Pavel Dubrova --- arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi | 32 ++- arch/arm64/boot/dts/qcom/sdm845-v2.dtsi | 38 ++- arch/arm64/boot/dts/qcom/sdm845.dtsi | 309 +++++++++++------------ 3 files changed, 189 insertions(+), 190 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi b/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi index e396ecf4c983..7a945c3052ae 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi @@ -17,24 +17,28 @@ compatible = "qcom,kgsl-busmon"; }; + gpu_bw_tbl: gpu-bw-tbl { + compatible = "operating-points-v2"; + BW_OPP_ENTRY( 0, 4); /* 0 MB/s */ + BW_OPP_ENTRY( 100, 4); /* 381 MB/s */ + BW_OPP_ENTRY( 150, 4); /* 572 MB/s */ + BW_OPP_ENTRY( 200, 4); /* 762 MB/s */ + BW_OPP_ENTRY( 300, 4); /* 1144 MB/s */ + BW_OPP_ENTRY( 412, 4); /* 1571 MB/s */ + BW_OPP_ENTRY( 547, 4); /* 2086 MB/s */ + BW_OPP_ENTRY( 681, 4); /* 2597 MB/s */ + BW_OPP_ENTRY( 768, 4); /* 2929 MB/s */ + BW_OPP_ENTRY(1017, 4); /* 3879 MB/s */ + BW_OPP_ENTRY(1296, 4); /* 4943 MB/s */ + BW_OPP_ENTRY(1555, 4); /* 5931 MB/s */ + BW_OPP_ENTRY(1804, 4); /* 6881 MB/s */ + }; + gpubw: qcom,gpubw { compatible = "qcom,devbw"; governor = "bw_vbif"; qcom,src-dst-ports = <26 512>; - qcom,bw-tbl = - < 0 /* off */ >, - < 381 /* 100 MHz */ >, - < 572 /* 150 MHz */ >, - < 762 /* 200 MHz */ >, - < 1144 /* 300 MHz */ >, - < 1571 /* 412 MHz */ >, - < 2086 /* 547 MHz */ >, - < 2597 /* 681 MHz */ >, - < 2929 /* 768 MHz */ >, - < 3879 /* 1017 MHz */ >, - < 4943 /* 1296 MHz */ >, - < 5931 /* 1555 MHz */ >, - < 6881 /* 1804 MHz */ >; + operating-points-v2 = <&gpu_bw_tbl>; }; msm_gpu: qcom,kgsl-3d0@5000000 { diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi index 2e303ba9907a..b74daf9a7245 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi @@ -139,6 +139,17 @@ compatible = "syscon"; reg = <0x5091008 0x4>; }; + + llcc_bw_opp_table_v2: llcc-bw-opp-table-v2 { + compatible = "operating-points-v2"; + BW_OPP_ENTRY( 150, 16); /* 2288 MB/s */ + BW_OPP_ENTRY( 300, 16); /* 4577 MB/s */ + BW_OPP_ENTRY( 426, 16); /* 6500 MB/s */ + BW_OPP_ENTRY( 533, 16); /* 8132 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 */ + }; }; &pil_modem { @@ -318,7 +329,7 @@ 0x1808 0x01 0x0>; }; -&devfreq_l3lat_0 { +&cpu0_cpu_l3_latmon { qcom,core-dev-table = < 300000 300000000 >, < 480000 403200000 >, @@ -335,7 +346,7 @@ < 1766400 1401600000 >; }; -&devfreq_l3lat_4 { +&cpu4_cpu_l3_latmon { qcom,core-dev-table = < 300000 300000000 >, < 825600 576000000 >, @@ -347,30 +358,15 @@ < 2745600 1593600000 >; }; -&bwmon { +&cpu_cpu_llcc_bwmon { qcom,count-unit = <0x10000>; }; -&cpubw { - qcom,bw-tbl = - < MHZ_TO_MBPS(150, 16) >, /* 2288 MB/s */ - < MHZ_TO_MBPS(300, 16) >, /* 4577 MB/s */ - < MHZ_TO_MBPS(426, 16) >, /* 6500 MB/s */ - < MHZ_TO_MBPS(533, 16) >, /* 8132 MB/s */ - < MHZ_TO_MBPS(600, 16) >, /* 9155 MB/s */ - < MHZ_TO_MBPS(806, 16) >, /* 12298 MB/s */ - < MHZ_TO_MBPS(933, 16) >; /* 14236 MB/s */ -}; - -&devfreq_cpufreq { - mincpubw-cpufreq { - cpu-to-dev-map-4 = - < 1881600 MHZ_TO_MBPS(200, 4) >, - < 2400000 MHZ_TO_MBPS(1017, 4) >; - }; +&cpu_cpu_llcc_bw { + operating-points-v2 = <&llcc_bw_opp_table_v2>; }; -&devfreq_compute { +&cpu4_computemon { qcom,core-dev-table = < 1881600 MHZ_TO_MBPS( 200, 4) >, < 2649600 MHZ_TO_MBPS(1017, 4) >, diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index bb0598603fad..5f5675c0095b 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -21,6 +21,7 @@ #include #define MHZ_TO_MBPS(mhz, w) ((mhz * 1000000 * w) / (1024 * 1024)) +#define BW_OPP_ENTRY(mhz, w) opp-mhz {opp-hz = /bits/ 64 ;} / { model = "Qualcomm Technologies, Inc. SDM845"; @@ -974,97 +975,192 @@ }; }; - cpubw: qcom,cpubw { + 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( 426, 16); /* 6500 MB/s */ + BW_OPP_ENTRY( 533, 16); /* 8132 MB/s */ + BW_OPP_ENTRY( 600, 16); /* 9155 MB/s */ + BW_OPP_ENTRY( 700, 16); /* 10681 MB/s */ + }; + + cpu_cpu_llcc_bw: qcom,cpu-cpu-llcc-bw { compatible = "qcom,devbw"; governor = "performance"; qcom,src-dst-ports = ; qcom,active-only; - qcom,bw-tbl = - < MHZ_TO_MBPS(150, 16) >, /* 2288 MB/s */ - < MHZ_TO_MBPS(300, 16) >, /* 4577 MB/s */ - < MHZ_TO_MBPS(426, 16) >, /* 6500 MB/s */ - < MHZ_TO_MBPS(533, 16) >, /* 8132 MB/s */ - < MHZ_TO_MBPS(600, 16) >, /* 9155 MB/s */ - < MHZ_TO_MBPS(700, 16) >; /* 10681 MB/s */ + operating-points-v2 = <&llcc_bw_opp_table>; }; - bwmon: qcom,cpu-bwmon { + cpu_cpu_llcc_bwmon: qcom,cpu-cpu-llcc-bwmon { compatible = "qcom,bimc-bwmon4"; reg = <0x1436400 0x300>, <0x1436300 0x200>; reg-names = "base", "global_base"; interrupts = ; qcom,mport = <0>; qcom,hw-timer-hz = <19200000>; - qcom,target-dev = <&cpubw>; + qcom,target-dev = <&cpu_cpu_llcc_bw>; + }; + + ddr_bw_opp_table: ddr-bw-opp-table { + compatible = "operating-points-v2"; + BW_OPP_ENTRY( 200, 4); /* 762 MB/s */ + BW_OPP_ENTRY( 300, 4); /* 1144 MB/s */ + BW_OPP_ENTRY( 451, 4); /* 1720 MB/s */ + BW_OPP_ENTRY( 547, 4); /* 2086 MB/s */ + BW_OPP_ENTRY( 681, 4); /* 2597 MB/s */ + BW_OPP_ENTRY( 768, 4); /* 2929 MB/s */ + BW_OPP_ENTRY(1017, 4); /* 3879 MB/s */ + BW_OPP_ENTRY(1296, 4); /* 4943 MB/s */ + BW_OPP_ENTRY(1555, 4); /* 5931 MB/s */ + BW_OPP_ENTRY(1804, 4); /* 6881 MB/s */ }; - llccbw: qcom,llccbw { + cpu_llcc_ddr_bw: qcom,cpu-llcc-ddr-bw { compatible = "qcom,devbw"; governor = "performance"; qcom,src-dst-ports = ; qcom,active-only; - qcom,bw-tbl = - < MHZ_TO_MBPS( 200, 4) >, /* 762 MB/s */ - < MHZ_TO_MBPS( 300, 4) >, /* 1144 MB/s */ - < MHZ_TO_MBPS( 451, 4) >, /* 1720 MB/s */ - < MHZ_TO_MBPS( 547, 4) >, /* 2086 MB/s */ - < MHZ_TO_MBPS( 681, 4) >, /* 2597 MB/s */ - < MHZ_TO_MBPS( 768, 4) >, /* 2929 MB/s */ - < MHZ_TO_MBPS(1017, 4) >, /* 3879 MB/s */ - < MHZ_TO_MBPS(1296, 4) >, /* 4943 MB/s */ - < MHZ_TO_MBPS(1555, 4) >, /* 5931 MB/s */ - < MHZ_TO_MBPS(1804, 4) >; /* 6881 MB/s */ - }; - - llcc_bwmon: qcom,llcc-bwmon { + operating-points-v2 = <&ddr_bw_opp_table>; + }; + + cpu_llcc_ddr_bwmon: qcom,cpu-llcc-ddr-bwmon { compatible = "qcom,bimc-bwmon5"; reg = <0x0114A000 0x1000>; reg-names = "base"; interrupts = ; qcom,hw-timer-hz = <19200000>; - qcom,target-dev = <&llccbw>; + qcom,target-dev = <&cpu_llcc_ddr_bw>; qcom,count-unit = <0x400000>; qcom,byte-mid-mask = <0xe000>; qcom,byte-mid-match = <0xe000>; }; - memlat_cpu0: qcom,memlat-cpu0 { + cpu0_cpu_llcc_lat: qcom,cpu0-cpu-llcc-lat { compatible = "qcom,devbw"; governor = "powersave"; qcom,src-dst-ports = <1 512>; qcom,active-only; - qcom,bw-tbl = - < MHZ_TO_MBPS( 200, 4) >, /* 762 MB/s */ - < MHZ_TO_MBPS( 300, 4) >, /* 1144 MB/s */ - < MHZ_TO_MBPS( 451, 4) >, /* 1720 MB/s */ - < MHZ_TO_MBPS( 547, 4) >, /* 2086 MB/s */ - < MHZ_TO_MBPS( 681, 4) >, /* 2597 MB/s */ - < MHZ_TO_MBPS( 768, 4) >, /* 2929 MB/s */ - < MHZ_TO_MBPS(1017, 4) >, /* 3879 MB/s */ - < MHZ_TO_MBPS(1296, 4) >, /* 4943 MB/s */ - < MHZ_TO_MBPS(1555, 4) >, /* 5931 MB/s */ - < MHZ_TO_MBPS(1804, 4) >; /* 6881 MB/s */ - }; - - memlat_cpu4: qcom,memlat-cpu4 { + operating-points-v2 = <&ddr_bw_opp_table>; + }; + + cpu0_cpu_ddr_latfloor: qcom,cpu0-cpu-ddr-latfloor { compatible = "qcom,devbw"; governor = "powersave"; qcom,src-dst-ports = <1 512>; qcom,active-only; - status = "ok"; - qcom,bw-tbl = - < MHZ_TO_MBPS( 200, 4) >, /* 762 MB/s */ - < MHZ_TO_MBPS( 300, 4) >, /* 1144 MB/s */ - < MHZ_TO_MBPS( 451, 4) >, /* 1720 MB/s */ - < MHZ_TO_MBPS( 547, 4) >, /* 2086 MB/s */ - < MHZ_TO_MBPS( 681, 4) >, /* 2597 MB/s */ - < MHZ_TO_MBPS( 768, 4) >, /* 2929 MB/s */ - < MHZ_TO_MBPS(1017, 4) >, /* 3879 MB/s */ - < MHZ_TO_MBPS(1296, 4) >, /* 4943 MB/s */ - < MHZ_TO_MBPS(1555, 4) >, /* 5931 MB/s */ - < MHZ_TO_MBPS(1804, 4) >; /* 6881 MB/s */ + 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_l3_latmon: qcom,cpu0-cpu-l3-latmon { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3>; + qcom,target-dev = <&cpu0_l3>; + qcom,cachemiss-ev = <0x17>; + qcom,core-dev-table = + < 300000 300000000 >, + < 748800 576000000 >, + < 979200 652800000 >, + < 1209600 806400000 >, + < 1516800 883200000 >, + < 1593600 960000000 >, + < 1708800 1305600000 >; + }; + + cpu0_cpu_llcc_latmon: qcom,cpu0-cpu-llcc-latmon { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3>; + qcom,target-dev = <&cpu0_cpu_llcc_lat>; + qcom,cachemiss-ev = <0x2A>; + qcom,core-dev-table = + < 300000 MHZ_TO_MBPS( 200, 4) >, + < 748800 MHZ_TO_MBPS( 451, 4) >, + < 1132800 MHZ_TO_MBPS( 547, 4) >, + < 1440000 MHZ_TO_MBPS( 768, 4) >, + < 1593600 MHZ_TO_MBPS(1017, 4) >; + }; + + cpu0_computemon: qcom,cpu0-computeon { + compatible = "qcom,arm-compute-mon"; + qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3>; + qcom,target-dev = <&cpu0_cpu_ddr_latfloor>; + qcom,core-dev-table = + < 1708800 MHZ_TO_MBPS(200, 4) >; + }; + }; + + cpu4_cpu_llcc_lat: qcom,cpu4-cpu-llcc-lat { + compatible = "qcom,devbw"; + governor = "powersave"; + qcom,src-dst-ports = <1 512>; + qcom,active-only; + operating-points-v2 = <&ddr_bw_opp_table>; + }; + + cpu4_cpu_ddr_latfloor: qcom,cpu4-cpu-ddr-latfloor { + compatible = "qcom,devbw"; + governor = "powersave"; + qcom,src-dst-ports = <1 512>; + 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_l3_latmon: qcom,cpu4-cpu-l3-latmon { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU4 &CPU5 &CPU6 &CPU7>; + qcom,target-dev = <&cpu4_l3>; + qcom,cachemiss-ev = <0x17>; + qcom,core-dev-table = + < 300000 300000000 >, + < 1036800 576000000 >, + < 1190400 806400000 >, + < 1574400 883200000 >, + < 1804800 960000000 >, + < 1958400 1305600000 >; + }; + + cpu4_cpu_llcc_latmon: qcom,cpu4-cpu-llcc-latmon { + compatible = "qcom,arm-memlat-mon"; + qcom,cpulist = <&CPU4 &CPU5 &CPU6 &CPU7>; + qcom,target-dev = <&cpu4_cpu_llcc_lat>; + qcom,cachemiss-ev = <0x2A>; + qcom,core-dev-table = + < 300000 MHZ_TO_MBPS( 200, 4) >, + < 499200 MHZ_TO_MBPS( 451, 4) >, + < 806400 MHZ_TO_MBPS( 547, 4) >, + < 1036800 MHZ_TO_MBPS( 768, 4) >, + < 1190400 MHZ_TO_MBPS(1017, 4) >, + < 1574400 MHZ_TO_MBPS(1296, 4) >, + < 1728000 MHZ_TO_MBPS(1555, 4) >, + < 1958400 MHZ_TO_MBPS(1804, 4) >; + }; + + cpu4_computemon: qcom,cpu4-computeon { + compatible = "qcom,arm-compute-mon"; + qcom,cpulist = <&CPU4 &CPU5 &CPU6 &CPU7>; + qcom,target-dev = <&cpu4_cpu_ddr_latfloor>; + qcom,core-dev-table = + < 1881600 MHZ_TO_MBPS(200, 4) >, + < 2208000 MHZ_TO_MBPS(681, 4) >; + }; + }; + + keepalive_opp_table: keepalive-opp-table { + compatible = "operating-points-v2"; + opp-1 { + opp-hz = /bits/ 64 < 1 >; + }; }; snoc_cnoc_keepalive: qcom,snoc_cnoc_keepalive { @@ -1073,83 +1169,24 @@ qcom,src-dst-ports = <139 627>; qcom,active-only; status = "ok"; - qcom,bw-tbl = - < 1 >; + operating-points-v2 = <&keepalive_opp_table>; }; - devfreq_memlat_0: qcom,cpu0-memlat-mon { - compatible = "qcom,arm-memlat-mon"; - qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3>; - qcom,target-dev = <&memlat_cpu0>; - qcom,cachemiss-ev = <0x2A>; - qcom,core-dev-table = - < 300000 MHZ_TO_MBPS( 200, 4) >, - < 748800 MHZ_TO_MBPS( 451, 4) >, - < 1132800 MHZ_TO_MBPS( 547, 4) >, - < 1440000 MHZ_TO_MBPS( 768, 4) >, - < 1593600 MHZ_TO_MBPS(1017, 4) >; - }; - - devfreq_memlat_4: qcom,cpu4-memlat-mon { - compatible = "qcom,arm-memlat-mon"; - qcom,cpulist = <&CPU4 &CPU5 &CPU6 &CPU7>; - qcom,target-dev = <&memlat_cpu4>; - qcom,cachemiss-ev = <0x2A>; - qcom,core-dev-table = - < 300000 MHZ_TO_MBPS( 200, 4) >, - < 499200 MHZ_TO_MBPS( 451, 4) >, - < 806400 MHZ_TO_MBPS( 547, 4) >, - < 1036800 MHZ_TO_MBPS( 768, 4) >, - < 1190400 MHZ_TO_MBPS(1017, 4) >, - < 1574400 MHZ_TO_MBPS(1296, 4) >, - < 1728000 MHZ_TO_MBPS(1555, 4) >, - < 1958400 MHZ_TO_MBPS(1804, 4) >; - }; - - l3_cpu0: qcom,l3-cpu0 { + cpu0_l3: qcom,cpu0-cpu-l3-lat { compatible = "devfreq-simple-dev"; clock-names = "devfreq_clk"; clocks = <&clock_cpucc L3_CLUSTER0_VOTE_CLK>; governor = "performance"; }; - l3_cpu4: qcom,l3-cpu4 { + cpu4_l3: qcom,cpu4-cpu-l3-lat { compatible = "devfreq-simple-dev"; clock-names = "devfreq_clk"; clocks = <&clock_cpucc L3_CLUSTER1_VOTE_CLK>; governor = "performance"; }; - devfreq_l3lat_0: qcom,cpu0-l3lat-mon { - compatible = "qcom,arm-memlat-mon"; - qcom,cpulist = <&CPU0 &CPU1 &CPU2 &CPU3>; - qcom,target-dev = <&l3_cpu0>; - qcom,cachemiss-ev = <0x17>; - qcom,core-dev-table = - < 300000 300000000 >, - < 748800 576000000 >, - < 979200 652800000 >, - < 1209600 806400000 >, - < 1516800 883200000 >, - < 1593600 960000000 >, - < 1708800 1305600000 >; - }; - - devfreq_l3lat_4: qcom,cpu4-l3lat-mon { - compatible = "qcom,arm-memlat-mon"; - qcom,cpulist = <&CPU4 &CPU5 &CPU6 &CPU7>; - qcom,target-dev = <&l3_cpu4>; - qcom,cachemiss-ev = <0x17>; - qcom,core-dev-table = - < 300000 300000000 >, - < 1036800 576000000 >, - < 1190400 806400000 >, - < 1574400 883200000 >, - < 1804800 960000000 >, - < 1958400 1305600000 >; - }; - - l3_cdsp: qcom,l3-cdsp { + cdsp_l3: qcom,cdsp-cdsp-l3-lat { compatible = "devfreq-simple-dev"; clock-names = "devfreq_clk"; clocks = <&clock_cpucc L3_MISC_VOTE_CLK>; @@ -1162,44 +1199,6 @@ interrupts = ; }; - mincpubw: qcom,mincpubw { - compatible = "qcom,devbw"; - governor = "powersave"; - qcom,src-dst-ports = <1 512>; - qcom,active-only; - qcom,bw-tbl = - < MHZ_TO_MBPS( 200, 4) >, /* 762 MB/s */ - < MHZ_TO_MBPS( 300, 4) >, /* 1144 MB/s */ - < MHZ_TO_MBPS( 451, 4) >, /* 1720 MB/s */ - < MHZ_TO_MBPS( 547, 4) >, /* 2086 MB/s */ - < MHZ_TO_MBPS( 681, 4) >, /* 2597 MB/s */ - < MHZ_TO_MBPS( 768, 4) >, /* 2929 MB/s */ - < MHZ_TO_MBPS(1017, 4) >, /* 3879 MB/s */ - < MHZ_TO_MBPS(1296, 4) >, /* 4943 MB/s */ - < MHZ_TO_MBPS(1555, 4) >, /* 5931 MB/s */ - < MHZ_TO_MBPS(1804, 4) >; /* 6881 MB/s */ - }; - - devfreq_cpufreq: devfreq-cpufreq { - mincpubw-cpufreq { - target-dev = <&mincpubw>; - cpu-to-dev-map-0 = - < 1708800 MHZ_TO_MBPS(200, 4) >; - cpu-to-dev-map-4 = - < 1881600 MHZ_TO_MBPS(200, 4) >, - < 2208000 MHZ_TO_MBPS(681, 4) >; - }; - }; - - devfreq_compute: qcom,devfreq-compute { - compatible = "qcom,arm-cpu-mon"; - qcom,cpulist = <&CPU4 &CPU5 &CPU6 &CPU7>; - qcom,target-dev = <&mincpubw>; - qcom,core-dev-table = - < 1881600 MHZ_TO_MBPS(200, 4) >, - < 2208000 MHZ_TO_MBPS(681, 4) >; - }; - clock_gcc: qcom,gcc@100000 { compatible = "qcom,gcc-sdm845", "syscon"; reg = <0x100000 0x1f0000>; @@ -1288,7 +1287,7 @@ vdd_pwrcl_mx_ao-supply = <&pm8998_s6_level_ao>; qcom,mx-turbo-freq = <1478400000 1689600000 3300000001>; - l3-devs = <&l3_cpu0 &l3_cpu4 &l3_cdsp &msm_gpu>; + l3-devs = <&cpu0_l3 &cpu4_l3 &cdsp_l3 &msm_gpu>; clock-names = "xo_ao"; clocks = <&clock_rpmh RPMH_CXO_CLK_A>; From 37af298f2a25ddb28453e4dd5a08ab9c22ff9ce3 Mon Sep 17 00:00:00 2001 From: "Angelo G. Del Regno" Date: Thu, 11 Jul 2019 16:16:58 +0200 Subject: [PATCH 030/356] arm64: DT: smmu-sdm845: Add phandle to hwspinlock 6 to qsmmu-v500 The ARM-SMMU driver needs to use the hwspinlock S:6 in the MMU-500 errata path. --- arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi index 4fc1fa85c1e7..cd2a7cee1c93 100644 --- a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi @@ -354,4 +354,5 @@ <0x10a5 0x8 0x103>; qcom,mmu500-errata-1 = <0x800 0x3ff>, <0xc00 0x3ff>; + hwlocks = <&tcsr_mutex 6>; }; From 2ca740c32859f72832aa04dad0b4a93b789d5f61 Mon Sep 17 00:00:00 2001 From: "Angelo G. Del Regno" Date: Fri, 12 Jul 2019 12:00:00 +0200 Subject: [PATCH 031/356] arm64: DT: SDM845-670: Move DBM in DWC3 and declare maximum speed The primary DWC3 port is USB3.1 capable (super-speed-plus), while the secondary one is super-speed. Moreover, the DBM node was moved inside of DWC3: move the related properties in the DWC3 node. --- arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi index ac11134668d5..c156e17dd315 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi @@ -27,7 +27,7 @@ "ss_phy_irq", "dm_hs_phy_irq"; USB3_GDSC-supply = <&usb30_prim_gdsc>; - qcom,usb-dbm = <&dbm_1p5>; + qcom,reset-ep-after-lpm-resume; qcom,dwc-usb3-msm-tx-fifo-size = <21288>; qcom,num-gsi-evt-buffs = <0x3>; qcom,use-pdc-interrupts; @@ -76,6 +76,8 @@ snps,hird-threshold = /bits/ 8 <0x10>; snps,usb3_lpm_capable; usb-core-id = <0>; + dr_mode = "drd"; + maximum-speed = "super-speed-plus"; }; qcom,usbbam@a704000 { @@ -326,12 +328,6 @@ reset-names = "global_phy_reset", "phy_reset"; }; - dbm_1p5: dbm@a6f8000 { - compatible = "qcom,usb-dbm-1p5"; - reg = <0xa6f8000 0x400>; - qcom,reset-ep-after-lpm-resume; - }; - usb_audio_qmi_dev { compatible = "qcom,usb-audio-qmi-dev"; iommus = <&apps_smmu 0x182c 0x0>; @@ -407,6 +403,7 @@ snps,usb3_lpm_capable; usb-core-id = <1>; dr_mode = "host"; + maximum-speed = "super-speed"; }; }; From 5a22276bf65328e13ce52e226657b8eadc8c3235 Mon Sep 17 00:00:00 2001 From: "Angelo G. Del Regno" Date: Fri, 12 Jul 2019 12:08:19 +0200 Subject: [PATCH 032/356] arm64: DT: SDM845-670: Declare GSI register offsets The new driver in kernel 4.14 wants us to declare the GSI register offsets in DT, while the old driver had them hardcoded. Follow the new trend. Signed-off-by: Pavel Dubrova --- .../arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi index c156e17dd315..4f7ddda4b4bb 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi @@ -30,6 +30,13 @@ qcom,reset-ep-after-lpm-resume; qcom,dwc-usb3-msm-tx-fifo-size = <21288>; 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,use-pdc-interrupts; qcom,pm-qos-latency = <44>; extcon = <0>, <0>, <&eud>, <0>, <0>; @@ -360,6 +367,13 @@ USB3_GDSC-supply = <&usb30_sec_gdsc>; qcom,dwc-usb3-msm-tx-fifo-size = <21288>; + 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,use-pdc-interrupts; clocks = <&clock_gcc GCC_USB30_SEC_MASTER_CLK>, From 91f24b819f30a7f950c33f3c32ab9b75ab025174 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Tue, 26 Nov 2019 12:56:12 +0100 Subject: [PATCH 033/356] arm64: DT: sdm845-670-usb: Limit USB speed to super-speed The super-speed-plus mode is not supported properly by this PHY and it will get limited to full-speed (12MBit/s) if we declare an unsupported maximum-speed. For this reason, limit the maximum speed to SuperSpeed, so that we get the maximum performance out of this PHY. --- arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi index 4f7ddda4b4bb..d6b9c97ae80d 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi @@ -84,7 +84,7 @@ snps,usb3_lpm_capable; usb-core-id = <0>; dr_mode = "drd"; - maximum-speed = "super-speed-plus"; + maximum-speed = "super-speed"; }; qcom,usbbam@a704000 { From 55859bc4154c0f700402f79eed920ab79f0773c1 Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Tue, 16 Nov 2021 01:28:14 +0200 Subject: [PATCH 034/356] arm64: dts: qcom: sdm845-usb: Update phy register offstets Update phy register offsets in an order defined in phy driver. QUSB phy register offset: enum qusb_phy_reg { PORT_TUNE1, PLL_COMMON_STATUS_ONE, PWR_CTRL1, INTR_CTRL, PLL_CORE_INPUT_OVERRIDE, TEST1, BIAS_CTRL_2, DEBUG_CTRL1, DEBUG_CTRL2, DEBUG_CTRL3, DEBUG_CTRL4, STAT5, USB2_PHY_REG_MAX, }; Signed-off-by: Pavel Dubrova --- arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi index d6b9c97ae80d..8d538e491851 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi @@ -143,8 +143,6 @@ 0x0a8 /* QUSB2PHY_PLL_CORE_INPUT_OVERRIDE */ 0x254 /* QUSB2PHY_TEST1 */ 0x198 /* PLL_BIAS_CONTROL_2 */ - 0x228 /* QUSB2PHY_SQ_CTRL1 */ - 0x22c /* QUSB2PHY_SQ_CTRL2 */ 0x27c /* QUSB2PHY_DEBUG_CTRL1 */ 0x280 /* QUSB2PHY_DEBUG_CTRL2 */ 0x284 /* QUSB2PHY_DEBUG_CTRL3 */ @@ -442,10 +440,10 @@ 0x0a8 /* QUSB2PHY_PLL_CORE_INPUT_OVERRIDE */ 0x254 /* QUSB2PHY_TEST1 */ 0x198 /* PLL_BIAS_CONTROL_2 */ - 0x228 /* QUSB2PHY_SQ_CTRL1 */ - 0x22c /* QUSB2PHY_SQ_CTRL2 */ 0x27c /* QUSB2PHY_DEBUG_CTRL1 */ 0x280 /* QUSB2PHY_DEBUG_CTRL2 */ + 0x284 /* QUSB2PHY_DEBUG_CTRL3 */ + 0x288 /* QUSB2PHY_DEBUG_CTRL4 */ 0x2a0>; /* QUSB2PHY_STAT5 */ qcom,qusb-phy-init-seq = From 9c448598e1b93ba23046585c339fb3b82635d1b8 Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Thu, 18 Nov 2021 18:14:27 +0200 Subject: [PATCH 035/356] arm64: dts: qcom: sdm845-usb: Add dpdm regulator DWC3 driver requires a reference to USB PHY which exposes a DPDM regulator to be enabled. Signed-off-by: Pavel Dubrova --- arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi index 8d538e491851..7a50ffa93ce0 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi @@ -27,6 +27,7 @@ "ss_phy_irq", "dm_hs_phy_irq"; USB3_GDSC-supply = <&usb30_prim_gdsc>; + dpdm-supply = <&qusb_phy0>; qcom,reset-ep-after-lpm-resume; qcom,dwc-usb3-msm-tx-fifo-size = <21288>; qcom,num-gsi-evt-buffs = <0x3>; From a0f6fae1289252412d383738970a9f811e102390 Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Wed, 17 Nov 2021 03:46:02 +0200 Subject: [PATCH 036/356] arm64: dts: qcom: sdm845-usb: Add refgen supply for QUSB2PHY Since refgen is needed for QUSB2PHY to operate, add refgen supply for QUSB2PHY. Signed-off-by: Pavel Dubrova --- arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi index 7a50ffa93ce0..46e71f29d049 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi @@ -134,6 +134,7 @@ vdd-supply = <&pm8998_l1>; vdda18-supply = <&pm8998_l12>; vdda33-supply = <&pm8998_l24>; + refgen-supply = <&pm8998_l26>; qcom,override-bias-ctrl2; qcom,vdd-voltage-level = <0 880000 880000>; qcom,qusb-phy-reg-offset = From c2ad5854d48b23c0641c0844808a6cda8b05a02f Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Tue, 16 Nov 2021 20:31:58 +0200 Subject: [PATCH 037/356] arm64: dts: qcom: sdm845: Add alloc-ranges property for dump_mem node Add the alloc-ranges property for the dump_mem cma heap node to specify the address range within which the cma heap allocated. Signed-off-by: Pavel Dubrova --- arch/arm64/boot/dts/qcom/sdm845.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index 5f5675c0095b..8c472fd531bc 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -661,6 +661,7 @@ dump_mem: mem_dump_region { compatible = "shared-dma-pool"; + alloc-ranges = <0 0x00000000 0 0xffffffff>; reusable; size = <0 0x2400000>; }; From cb87adf74b6694b2d04912e33607a9877274b454 Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Thu, 18 Nov 2021 18:25:40 +0200 Subject: [PATCH 038/356] arm64: dts: qcom: smmu-sdm845: Limit test device context bank use Ensure that test devices won't try to allocate a context bank at probe time. Signed-off-by: Pavel Dubrova --- arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi index cd2a7cee1c93..4ee27426ee64 100644 --- a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi @@ -316,6 +316,7 @@ * anyways, so using a dummy value is ok. */ iommus = <&kgsl_smmu 0x7>; + qcom,iommu-dma = "disabled"; }; apps_iommu_test_device { @@ -325,6 +326,7 @@ * the apps_smmu device. */ iommus = <&apps_smmu 0x20 0>; + qcom,iommu-dma = "disabled"; }; apps_iommu_coherent_test_device { @@ -334,6 +336,7 @@ * the apps_smmu device. */ iommus = <&apps_smmu 0x20 0>; + qcom,iommu-dma = "disabled"; dma-coherent; }; }; From 3be40df8308b6c3129485045c51911a5277494b2 Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Thu, 18 Nov 2021 18:52:02 +0200 Subject: [PATCH 039/356] arm64: dts: qcom: Update IOMMU configuration for SDM845 Add DMA address pool ranges and vmid entries for secure context banks. Signed-off-by: Pavel Dubrova --- arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi | 1 + .../boot/dts/qcom/sdm845-670-usb-common.dtsi | 7 +- arch/arm64/boot/dts/qcom/sdm845-camera.dtsi | 5 ++ arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi | 18 ++--- arch/arm64/boot/dts/qcom/sdm845-sde.dtsi | 7 ++ .../arm64/boot/dts/qcom/sdm845-v2-camera.dtsi | 4 ++ arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi | 15 ++++ arch/arm64/boot/dts/qcom/sdm845.dtsi | 72 +++++++++++++------ 8 files changed, 93 insertions(+), 36 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi b/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi index a95de6c04c04..038e32a5c3c9 100644 --- a/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi +++ b/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi @@ -388,6 +388,7 @@ qcom,smmu-version = <2>; qcom,smmu-enabled; iommus = <&apps_smmu 0x1821 0x0>; + qcom,iommu-dma-addr-pool = <0x10000000 0x10000000>; }; qcom,msm-adsp-loader { diff --git a/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi index 46e71f29d049..ec73b4f90ef0 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi @@ -14,7 +14,8 @@ <0x088ee000 0x400>; reg-names = "core_base", "ahb2phy_base"; iommus = <&apps_smmu 0x740 0x0>; - qcom,smmu-s1-bypass; + qcom,iommu-dma = "atomic"; + qcom,iommu-dma-addr-pool = <0x90000000 0x60000000>; #address-cells = <1>; #size-cells = <1>; ranges; @@ -338,6 +339,7 @@ usb_audio_qmi_dev { compatible = "qcom,usb-audio-qmi-dev"; iommus = <&apps_smmu 0x182c 0x0>; + qcom,iommu-dma = "disabled"; qcom,usb-audio-stream-id = <0xc>; qcom,usb-audio-intr-num = <2>; }; @@ -353,7 +355,8 @@ <0x088ee000 0x400>; reg-names = "core_base", "ahb2phy_base"; iommus = <&apps_smmu 0x760 0x0>; - qcom,smmu-s1-bypass; + qcom,iommu-dma = "atomic"; + qcom,iommu-dma-addr-pool = <0x90000000 0x60000000>; #address-cells = <1>; #size-cells = <1>; ranges; diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi index 8d516e6238a7..e7717a1d3afb 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-camera.dtsi @@ -231,6 +231,7 @@ <&apps_smmu 0x810 0x8>, <&apps_smmu 0xc08 0x0>, <&apps_smmu 0xc10 0x8>; + qcom,iommu-dma-addr-pool = <0x7400000 0xd8c00000>; label = "ife"; ife_iova_mem_map: iova-mem-map { /* IO region is approximately 3.4 GB */ @@ -248,6 +249,7 @@ compatible = "qcom,msm-cam-smmu-cb"; iommus = <&apps_smmu 0x1060 0x8>, <&apps_smmu 0x1068 0x8>; + qcom,iommu-dma-addr-pool = <0x7400000 0xd8c00000>; label = "jpeg"; jpeg_iova_mem_map: iova-mem-map { /* IO region is approximately 3.4 GB */ @@ -274,6 +276,7 @@ <&apps_smmu 0x1040 0x8>, <&apps_smmu 0x1030 0x0>, <&apps_smmu 0x1050 0x0>; + qcom,iommu-dma-addr-pool = <0x10c00000 0xcf300000>; label = "icp"; icp_iova_mem_map: iova-mem-map { iova-mem-region-firmware { @@ -327,6 +330,7 @@ msm_cam_smmu_cpas_cdm { compatible = "qcom,msm-cam-smmu-cb"; iommus = <&apps_smmu 0x1000 0x0>; + qcom,iommu-dma-addr-pool = <0x7400000 0xd8c00000>; label = "cpas-cdm0"; cpas_cdm_iova_mem_map: iova-mem-map { iova-mem-region-io { @@ -349,6 +353,7 @@ msm_cam_smmu_fd { compatible = "qcom,msm-cam-smmu-cb"; iommus = <&apps_smmu 0x1070 0x0>; + qcom,iommu-dma-addr-pool = <0x7400000 0xd8c00000>; label = "fd"; fd_iova_mem_map: iova-mem-map { iova-mem-region-io { diff --git a/arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi b/arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi index 85f5c889a581..ec8a8f560300 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi @@ -12,12 +12,9 @@ reg = <0x8c0000 0x6000>; qcom,bus-mas-id = ; qcom,bus-slv-id = ; - qcom,iommu-s1-bypass; - - iommu_qupv3_0_geni_se_cb: qcom,iommu_qupv3_0_geni_se_cb { - compatible = "qcom,qupv3-geni-se-cb"; - iommus = <&apps_smmu 0x003 0x0>; - }; + iommus = <&apps_smmu 0x003 0x0>; + qcom,iommu-dma-addr-pool = <0x40000000 0xc0000000>; + qcom,iommu-dma = "fastmap"; }; /* @@ -406,12 +403,9 @@ reg = <0xac0000 0x6000>; qcom,bus-mas-id = ; qcom,bus-slv-id = ; - qcom,iommu-s1-bypass; - - iommu_qupv3_1_geni_se_cb: qcom,iommu_qupv3_1_geni_se_cb { - compatible = "qcom,qupv3-geni-se-cb"; - iommus = <&apps_smmu 0x6c3 0x0>; - }; + iommus = <&apps_smmu 0x6c3 0x0>; + qcom,iommu-dma-addr-pool = <0x40000000 0xc0000000>; + qcom,iommu-dma = "fastmap"; }; /* 2-wire UART */ diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi index 028425556513..1936d9187c8b 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi @@ -247,6 +247,9 @@ compatible = "qcom,smmu_sde_sec"; iommus = <&apps_smmu 0x881 0x8>, <&apps_smmu 0xc81 0x8>; + qcom,iommu-dma-addr-pool = <0x00020000 0xfffe0000>; + qcom,iommu-faults = "non-fatal"; + qcom,iommu-vmid = <0xa>; /* VMID_CP_PIXEL */ }; /* data and reg bus scale settings */ @@ -398,11 +401,15 @@ smmu_rot_unsec: qcom,smmu_rot_unsec_cb { compatible = "qcom,smmu_sde_rot_unsec"; iommus = <&apps_smmu 0x1090 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 0x1091 0x0>; + qcom,iommu-dma-addr-pool = <0x00020000 0xfffe0000>; + qcom,iommu-faults = "non-fatal"; }; }; diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi index 6b82b5ff154b..355c9c9ca4db 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-v2-camera.dtsi @@ -155,6 +155,7 @@ compatible = "qcom,msm-cam-smmu-cb"; iommus = <&apps_smmu 0x1038 0x0>, <&apps_smmu 0x1058 0x0>; + qcom,iommu-dma-addr-pool = <0x7400000 0xd8c00000>; label = "lrme"; lrme_iova_mem_map: iova-mem-map { iova-mem-region-shared { @@ -182,6 +183,7 @@ <&apps_smmu 0x810 0x8>, <&apps_smmu 0xc08 0x0>, <&apps_smmu 0xc10 0x8>; + qcom,iommu-dma-addr-pool = <0x7400000 0xd8c00000>; label = "ife"; ife_iova_mem_map: iova-mem-map { /* IO region is approximately 3.4 GB */ @@ -208,6 +210,7 @@ <&apps_smmu 0x1040 0x8>, <&apps_smmu 0x1030 0x0>, <&apps_smmu 0x1050 0x0>; + qcom,iommu-dma-addr-pool = <0x10c00000 0xcf300000>; label = "icp"; icp_iova_mem_map: iova-mem-map { iova-mem-region-firmware { @@ -262,6 +265,7 @@ msm_cam_smmu_cpas_cdm { compatible = "qcom,msm-cam-smmu-cb"; iommus = <&apps_smmu 0x1000 0x0>; + qcom,iommu-dma-addr-pool = <0x7400000 0xd8c00000>; label = "cpas-cdm0"; cpas_cdm_iova_mem_map: iova-mem-map { iova-mem-region-io { diff --git a/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi b/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi index 982065d6a04b..9d6885b3b4f9 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi @@ -82,6 +82,9 @@ iommus = <&apps_smmu 0x10a0 0x8>, <&apps_smmu 0x10b0 0x0>; + qcom,iommu-dma-addr-pool = <0x70800000 0x6f800000>; + qcom,iommu-faults = "non-fatal"; + qcom,iommu-pagetable = "LLC"; buffer-types = <0xfff>; virtual-addr-pool = <0x70800000 0x6f800000>; }; @@ -92,6 +95,10 @@ iommus = <&apps_smmu 0x10a1 0x8>, <&apps_smmu 0x10a5 0x8>; + qcom,iommu-dma-addr-pool = <0x4b000000 0x25800000>; + qcom,iommu-faults = "non-fatal"; + qcom,iommu-pagetable = "LLC"; + qcom,iommu-vmid = <0xB>; /* VMID_CP_BITSTREAM */ buffer-types = <0x241>; virtual-addr-pool = <0x4b000000 0x25800000>; qcom,secure-context-bank; @@ -102,6 +109,10 @@ label = "venus_sec_pixel"; iommus = <&apps_smmu 0x10a3 0x8>; + qcom,iommu-dma-addr-pool = <0x25800000 0x25800000>; + qcom,iommu-faults = "non-fatal"; + qcom,iommu-pagetable = "LLC"; + qcom,iommu-vmid = <0xA>; /* VMID_CP_PIXEL */ buffer-types = <0x106>; virtual-addr-pool = <0x25800000 0x25800000>; qcom,secure-context-bank; @@ -113,6 +124,10 @@ iommus = <&apps_smmu 0x10a4 0x8>, <&apps_smmu 0x10b4 0x0>; + qcom,iommu-dma-addr-pool = <0x1000000 0x24800000>; + qcom,iommu-faults = "non-fatal"; + qcom,iommu-pagetable = "LLC"; + 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/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index 8c472fd531bc..5ed7989b7a94 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -1709,14 +1709,12 @@ qcom,apps-ch-pipes = <0x780000>; qcom,ea-pc = <0x270>; qcom,iommu-s1-bypass; - - iommu_slim_aud_ctrl_cb: qcom,iommu_slim_ctrl_cb { - compatible = "qcom,iommu-slim-ctrl-cb"; - iommus = <&apps_smmu 0x1806 0x0>, - <&apps_smmu 0x180d 0x0>, - <&apps_smmu 0x180e 0x1>, - <&apps_smmu 0x1810 0x1>; - }; + iommus = <&apps_smmu 0x1806 0x0>, + <&apps_smmu 0x180d 0x0>, + <&apps_smmu 0x180e 0x1>, + <&apps_smmu 0x1810 0x1>; + qcom,iommu-dma-addr-pool = <0x40000000 0xc0000000>; + qcom,iommu-dma = "atomic"; }; slim_qca: slim@17240000 { @@ -1730,11 +1728,9 @@ ; interrupt-names = "slimbus_irq", "slimbus_bam_irq"; qcom,iommu-s1-bypass; - - iommu_slim_qca_ctrl_cb: qcom,iommu_slim_ctrl_cb { - compatible = "qcom,iommu-slim-ctrl-cb"; - iommus = <&apps_smmu 0x1813 0x0>; - }; + iommus = <&apps_smmu 0x1813 0x0>; + qcom,iommu-dma-addr-pool = <0x40000000 0xc0000000>; + qcom,iommu-dma = "atomic"; /* Slimbus Slave DT for WCN3990 */ btfmslim_codec: wcn3990 { @@ -1882,48 +1878,64 @@ compatible = "qcom,msm-fastrpc-compute-cb"; label = "cdsprpc-smd"; iommus = <&apps_smmu 0x1401 0x30>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; dma-coherent; }; qcom,msm_fastrpc_compute_cb2 { compatible = "qcom,msm-fastrpc-compute-cb"; label = "cdsprpc-smd"; iommus = <&apps_smmu 0x1402 0x30>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; dma-coherent; }; qcom,msm_fastrpc_compute_cb3 { compatible = "qcom,msm-fastrpc-compute-cb"; label = "cdsprpc-smd"; iommus = <&apps_smmu 0x1403 0x30>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; dma-coherent; }; qcom,msm_fastrpc_compute_cb4 { compatible = "qcom,msm-fastrpc-compute-cb"; label = "cdsprpc-smd"; iommus = <&apps_smmu 0x1404 0x30>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; dma-coherent; }; qcom,msm_fastrpc_compute_cb5 { compatible = "qcom,msm-fastrpc-compute-cb"; label = "cdsprpc-smd"; iommus = <&apps_smmu 0x1405 0x30>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; dma-coherent; }; qcom,msm_fastrpc_compute_cb6 { compatible = "qcom,msm-fastrpc-compute-cb"; label = "cdsprpc-smd"; iommus = <&apps_smmu 0x1406 0x30>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; dma-coherent; }; qcom,msm_fastrpc_compute_cb7 { compatible = "qcom,msm-fastrpc-compute-cb"; label = "cdsprpc-smd"; iommus = <&apps_smmu 0x1407 0x30>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; dma-coherent; }; qcom,msm_fastrpc_compute_cb8 { compatible = "qcom,msm-fastrpc-compute-cb"; label = "cdsprpc-smd"; iommus = <&apps_smmu 0x1408 0x30>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; dma-coherent; }; qcom,msm_fastrpc_compute_cb9 { @@ -1931,6 +1943,9 @@ label = "cdsprpc-smd"; qcom,secure-context-bank; iommus = <&apps_smmu 0x1409 0x30>; + 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 { @@ -1938,18 +1953,25 @@ label = "cdsprpc-smd"; qcom,secure-context-bank; iommus = <&apps_smmu 0x140A 0x30>; + 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_cb11 { compatible = "qcom,msm-fastrpc-compute-cb"; label = "adsprpc-smd"; iommus = <&apps_smmu 0x1823 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 0x1824 0x0>; + qcom,iommu-dma-addr-pool = <0x80000000 0x78000000>; + qcom,iommu-faults = "stall-disable", "HUPCF"; dma-coherent; }; }; @@ -2717,6 +2739,7 @@ qcom,smmu-s1-enable; iommus = <&apps_smmu 0x706 0x1>, <&apps_smmu 0x716 0x1>; + qcom,iommu-dma = "atomic"; qcom_cedev_ns_cb { compatible = "qcom,qcedev,context-bank"; @@ -2734,6 +2757,7 @@ <&apps_smmu 0x71c 0>, <&apps_smmu 0x71d 0>, <&apps_smmu 0x71e 0>; + qcom,iommu-vmid = <0x9>; /* VMID_CP_BITSTREAM */ virtual-addr = <0x60200000>; virtual-size = <0x40000000>; qcom,secure-context-bank; @@ -2779,6 +2803,7 @@ qcom,smmu-s1-enable; iommus = <&apps_smmu 0x704 0x1>, <&apps_smmu 0x714 0x1>; + qcom,iommu-dma = "atomic"; }; qcom,msm_gsi { @@ -2944,24 +2969,24 @@ ipa_smmu_ap: ipa_smmu_ap { compatible = "qcom,ipa-smmu-ap-cb"; iommus = <&apps_smmu 0x720 0x0>; - qcom,iova-mapping = <0x20000000 0x40000000>; - qcom,additional-mapping = + qcom,iommu-dma-addr-pool = <0x20000000 0x40000000>; /* modem tables in IMEM */ - <0x146BD000 0x146BD000 0x2000>; + qcom,additional-mapping = <0x146BD000 0x146BD000 0x2000>; + qcom,iommu-dma = "fastmap"; }; ipa_smmu_wlan: ipa_smmu_wlan { compatible = "qcom,ipa-smmu-wlan-cb"; iommus = <&apps_smmu 0x721 0x0>; - qcom,additional-mapping = /* ipa-uc ram */ - <0x1E60000 0x1E60000 0x80000>; + qcom,additional-mapping = <0x1E60000 0x1E60000 0x80000>; + qcom,iommu-dma = "atomic"; }; ipa_smmu_uc: ipa_smmu_uc { compatible = "qcom,ipa-smmu-uc-cb"; iommus = <&apps_smmu 0x722 0x0>; - qcom,iova-mapping = <0x40000000 0x20000000>; + qcom,iommu-dma-addr-pool = <0x40000000 0x20000000>; }; }; @@ -3235,6 +3260,8 @@ , , ; + qcom,iommu-dma = "fastmap"; + qcom,iommu-faults = "stall-disable", "non-fatal"; qcom,wlan-msa-memory = <0x100000>; vdd-0.8-cx-mx-supply = <&pm8998_l5>; @@ -4105,7 +4132,7 @@ qcom,ev-factor = <2>; iommus = <&apps_smmu 0x0016 0x0>; qcom,smmu-cfg = <0x1>; - qcom,iova-range = <0x0 0x100000 0x0 0x100000>; + qcom,iommu-dma-addr-pool = <0x100000 0x100000>; status = "ok"; }; @@ -4132,7 +4159,7 @@ qcom,ev-factor = <2>; iommus = <&apps_smmu 0x06d6 0x0>; qcom,smmu-cfg = <0x1>; - qcom,iova-range = <0x0 0x100000 0x0 0x100000>; + qcom,iommu-dma-addr-pool = <0x100000 0x100000>; status = "ok"; }; @@ -4186,8 +4213,9 @@ &tsif1_signals_active &tsif1_sync_active>; /* dual-tsif-mode2 */ - qcom,smmu-s1-bypass; iommus = <&apps_smmu 0x20 0x0f>; + qcom,iommu-dma-addr-pool = <0x10000000 0x40000000>; + qcom,smmu-s1-enable; }; }; From 0d56a8bf3026d820e122ec5b90dd73de77b6a443 Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Thu, 18 Nov 2021 20:51:40 +0200 Subject: [PATCH 040/356] arm64: dts: qcom: sdm845: Add inline crypto register details New FBE framework parses crypto engine details from host controller node. Add this detail for ufs host. Signed-off-by: Pavel Dubrova --- arch/arm64/boot/dts/qcom/sdm845.dtsi | 31 ++++------------------------ 1 file changed, 4 insertions(+), 27 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index 5ed7989b7a94..a0365267bb2f 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -1316,32 +1316,9 @@ mbox-names = "qdss_clk"; }; - ufs_ice: ufsice@1d90000 { - compatible = "qcom,ice"; - reg = <0x1d90000 0x8000>; - qcom,enable-ice-clk; - clock-names = "ufs_core_clk", "bus_clk", - "iface_clk", "ice_core_clk"; - clocks = <&clock_gcc GCC_UFS_PHY_AXI_CLK>, - <&clock_gcc GCC_UFS_MEM_CLKREF_CLK>, - <&clock_gcc GCC_UFS_PHY_AHB_CLK>, - <&clock_gcc GCC_UFS_PHY_ICE_CORE_CLK>; - qcom,op-freq-hz = <0>, <0>, <0>, <300000000>; - vdd-hba-supply = <&ufs_phy_gdsc>; - qcom,msm-bus,name = "ufs_ice_noc"; - qcom,msm-bus,num-cases = <2>; - qcom,msm-bus,num-paths = <1>; - qcom,msm-bus,vectors-KBps = - <1 650 0 0>, /* No vote */ - <1 650 1000 0>; /* Max. bandwidth */ - qcom,bus-vector-names = "MIN", - "MAX"; - qcom,instance-type = "ufs"; - }; - ufsphy_mem: ufsphy_mem@1d87000 { - reg = <0x1d87000 0xda8>; /* PHY regs */ - reg-names = "phy_mem"; + reg = <0x1d87000 0xda8>, <0x1d90000 0x8000>; /* PHY regs */ + reg-names = "phy_mem", "ufs_ice"; #phy-cells = <0>; lanes-per-direction = <2>; @@ -1358,11 +1335,11 @@ ufshc_mem: ufshc@1d84000 { compatible = "qcom,ufshc"; - reg = <0x1d84000 0x2500>; + reg = <0x1d84000 0x2500>, <0x1d90000 0x8000>; + reg-names = "ufs_mem", "ufs_ice"; interrupts = ; phys = <&ufsphy_mem>; phy-names = "ufsphy"; - ufs-qcom-crypto = <&ufs_ice>; lanes-per-direction = <2>; dev-ref-clk-freq = <0>; /* 19.2 MHz */ From 362ab78e2fd21c8f9616504f8aade72e155201f3 Mon Sep 17 00:00:00 2001 From: "Angelo G. Del Regno" Date: Sat, 13 Jul 2019 17:40:30 +0200 Subject: [PATCH 041/356] arm64: DT: SDM845-sde: Keep RSC as the only mdss_core GDSC user On kernel 4.14 the SDE Resource State Coordinator is responsible to .. coordinate .. resource states, and this includes the main GDSC to enable any resource for the SDE. Since the GDSC is coordinated by the RSC, remove it from all the SDE nodes, including the DisplayPort, PHY and DSI hardware control. --- arch/arm64/boot/dts/qcom/sdm845-sde.dtsi | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi index 1936d9187c8b..c9d933cfd66f 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi @@ -27,8 +27,6 @@ clock-rate = <0 0 0 0 300000000 19200000 0>; clock-max-rate = <0 0 0 0 412500000 19200000 0>; - sde-vdd-supply = <&mdss_core_gdsc>; - /* interrupt config */ interrupts = ; interrupt-controller; @@ -229,20 +227,6 @@ 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_sec: qcom,smmu_sde_sec_cb { compatible = "qcom,smmu_sde_sec"; iommus = <&apps_smmu 0x881 0x8>, @@ -488,7 +472,7 @@ cell-index = <0>; reg = <0xae94400 0x7c0>; reg-names = "dsi_phy"; - gdsc-supply = <&mdss_core_gdsc>; + vdda-0p9-supply = <&pm8998_l1>; qcom,platform-strength-ctrl = [55 03 55 03 @@ -521,7 +505,7 @@ cell-index = <1>; reg = <0xae96400 0x7c0>; reg-names = "dsi_phy"; - gdsc-supply = <&mdss_core_gdsc>; + vdda-0p9-supply = <&pm8998_l1>; qcom,platform-strength-ctrl = [55 03 55 03 @@ -552,7 +536,6 @@ cell-index = <0>; compatible = "qcom,dp-display"; - gdsc-supply = <&mdss_core_gdsc>; vdda-1p2-supply = <&pm8998_l26>; vdda-0p9-supply = <&pm8998_l1>; From ad63c2fffda5d4b31f8468715dc44be2d192ba7e Mon Sep 17 00:00:00 2001 From: "Angelo G. Del Regno" Date: Fri, 12 Jul 2019 17:08:01 +0200 Subject: [PATCH 042/356] arm64: DT: SDM845-sde: Add missing properties for kernel 4.14 Declare the CWB mixers and the per-pipe bandwidth. --- arch/arm64/boot/dts/qcom/sdm845-sde.dtsi | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi index c9d933cfd66f..c98ac5203a75 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi @@ -53,6 +53,8 @@ qcom,sde-mixer-size = <0x320>; qcom,sde-mixer-display-pref = "primary", "primary", "none", "none", "none", "none"; + qcom,sde-mixer-cwb-pref = "none", "none", "cwb", + "none", "none", "cwb"; qcom,sde-dspp-top-off = <0x1300>; qcom,sde-dspp-top-size = <0xc>; @@ -107,6 +109,10 @@ qcom,sde-smart-dma-rev = "smart_dma_v2"; qcom,sde-mixer-pair-mask = <2 1 6 0 0 3>; + qcom,sde-max-per-pipe-bw-kbps = <4500000 4500000 + 4500000 4500000 + 4500000 4500000 + 4500000 4500000>; qcom,sde-mixer-blend-op-off = <0x20 0x38 0x50 0x68 0x80 0x98 0xb0 0xc8 0xe0 0xf8 0x110>; From ce194cb03d2ba7bfe519d3e1a18ec91877f8640d Mon Sep 17 00:00:00 2001 From: "Angelo G. Del Regno" Date: Sat, 13 Jul 2019 13:21:29 +0200 Subject: [PATCH 043/356] arm64: DT: sdm845-sde: Add lut clock for SDE The new SDE driver supports setting LUT clock memory retention. Feed it. Signed-off-by: Pavel Dubrova --- arch/arm64/boot/dts/qcom/sdm845-sde.dtsi | 10 ++++++---- arch/arm64/boot/dts/qcom/sdm845-v2.dtsi | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi index c98ac5203a75..d3c45653bb18 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi @@ -21,11 +21,13 @@ <&clock_dispcc DISP_CC_MDSS_AHB_CLK>, <&clock_dispcc DISP_CC_MDSS_AXI_CLK>, <&clock_dispcc DISP_CC_MDSS_MDP_CLK>, - <&clock_dispcc DISP_CC_MDSS_VSYNC_CLK>; + <&clock_dispcc DISP_CC_MDSS_VSYNC_CLK>, + <&clock_dispcc DISP_CC_MDSS_MDP_LUT_CLK>; clock-names = "gcc_iface", "gcc_bus", "iface_clk", - "bus_clk", "core_clk", "vsync_clk"; - clock-rate = <0 0 0 0 300000000 19200000 0>; - clock-max-rate = <0 0 0 0 412500000 19200000 0>; + "bus_clk", "core_clk", "vsync_clk", + "lut_clk"; + clock-rate = <0 0 0 0 300000000 19200000 0 300000000>; + clock-max-rate = <0 0 0 0 412500000 19200000 0 412500000>; /* interrupt config */ interrupts = ; diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi index b74daf9a7245..1e132941d2d0 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi @@ -414,7 +414,7 @@ }; &mdss_mdp { - clock-max-rate = <0 0 0 0 430000000 19200000 0>; + clock-max-rate = <0 0 0 0 430000000 19200000 0 430000000>; qcom,sde-min-core-ib-kbps = <4800000>; qcom,sde-max-bw-low-kbps = <9600000>; qcom,sde-max-bw-high-kbps = <9600000>; From 38b1af2de24020d95b2879426eb852f18de5a995 Mon Sep 17 00:00:00 2001 From: "Angelo G. Del Regno" Date: Sat, 13 Jul 2019 14:34:40 +0200 Subject: [PATCH 044/356] arm64: DT: SDM845-sde: Add qseed safe and QoS LUTs The qseed safe and qos luts are now transferred to DT. --- arch/arm64/boot/dts/qcom/sdm845-sde.dtsi | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi index d3c45653bb18..0d2e093f3fb2 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi @@ -171,6 +171,11 @@ <11 0xfc00>, <12 0xf800>, <0 0xf000>; + qcom,sde-safe-lut-macrotile-qseed = + <10 0xfe00>, + <11 0xfc00>, + <12 0xf800>, + <0 0xf000>; qcom,sde-safe-lut-nrt = <0 0xffff>; qcom,sde-safe-lut-cwb = @@ -195,6 +200,13 @@ <13 0x00002233 0x44556677>, <14 0x00012233 0x44556677>, <0 0x00112233 0x44556677>; + qcom,sde-qos-lut-macrotile-qseed = + <10 0x00000003 0x66777777>, + <11 0x00000033 0x66777777>, + <12 0x00000233 0x66777777>, + <13 0x00002233 0x66777777>, + <14 0x00012233 0x66777777>, + <0 0x00112233 0x66777777>; qcom,sde-qos-lut-nrt = <0 0x00000000 0x00000000>; qcom,sde-qos-lut-cwb = From a907f11c0b4478c98928df40e4c3c27be4502072 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Sat, 14 Dec 2019 12:32:08 +0100 Subject: [PATCH 045/356] arm64: DT: sdm845-sde: Enable PM QoS for SDM845 rotator Define the CPU mask and latency values in order to enable PM QoS for the rotator on SDM845. This helps saving some power and reducing some jitter. --- arch/arm64/boot/dts/qcom/sdm845-sde.dtsi | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi index 0d2e093f3fb2..4a33b13df015 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi @@ -384,6 +384,9 @@ qcom,mdss-inline-rot-danger-lut = <0x0055aaff 0x0000ffff>; qcom,mdss-inline-rot-safe-lut = <0x0000f000 0x0000ff00>; + qcom,mdss-rot-qos-cpu-mask = <0xf>; + qcom,mdss-rot-qos-cpu-dma-latency = <75>; + qcom,mdss-default-ot-rd-limit = <32>; qcom,mdss-default-ot-wr-limit = <32>; From ce62d05035902cd020b16288bf1efc328c6b87b5 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Tue, 12 Nov 2019 15:37:14 +0100 Subject: [PATCH 046/356] arm64: DT: SDM845: Fill in parameters for dynamic pll support This SoC supports Dynamic PLL (dynamic seamless display frame-rate and resolution change): fill in the parameters to get support enabled. --- arch/arm64/boot/dts/qcom/sdm845-sde-pll.dtsi | 8 ++++++-- arch/arm64/boot/dts/qcom/sdm845-sde.dtsi | 19 +++++++++++-------- arch/arm64/boot/dts/qcom/sdm845-v2.dtsi | 2 +- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde-pll.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde-pll.dtsi index 5e5f113f1f3c..5d21169bd949 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-sde-pll.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-sde-pll.dtsi @@ -10,9 +10,11 @@ cell-index = <0>; #clock-cells = <1>; reg = <0xae94a00 0x1e0>, + <0xae94200 0x100>, <0xae94400 0x800>, <0xaf03000 0x8>; - reg-names = "pll_base", "phy_base", "gdsc_base"; + reg-names = "pll_base", "dynamic_pll_base", + "phy_base", "gdsc_base"; clocks = <&clock_dispcc DISP_CC_MDSS_AHB_CLK>; clock-names = "iface_clk"; clock-rate = <0>; @@ -39,9 +41,11 @@ cell-index = <1>; #clock-cells = <1>; reg = <0xae96a00 0x1e0>, + <0xae96200 0x100>, <0xae96400 0x800>, <0xaf03000 0x8>; - reg-names = "pll_base", "phy_base", "gdsc_base"; + reg-names = "pll_base", "dynamic_pll_base", + "phy_base", "gdsc_base"; clocks = <&clock_dispcc DISP_CC_MDSS_AHB_CLK>; clock-names = "iface_clk"; clock-rate = <0>; diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi index 4a33b13df015..152a03fd952e 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi @@ -22,12 +22,13 @@ <&clock_dispcc DISP_CC_MDSS_AXI_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_MDP_LUT_CLK>, + <&clock_dispcc DISP_CC_MDSS_ROT_CLK>; clock-names = "gcc_iface", "gcc_bus", "iface_clk", "bus_clk", "core_clk", "vsync_clk", - "lut_clk"; - clock-rate = <0 0 0 0 300000000 19200000 0 300000000>; - clock-max-rate = <0 0 0 0 412500000 19200000 0 412500000>; + "lut_clk", "rot_clk"; + clock-rate = <0 0 0 0 300000000 19200000 300000000 19200000>; + clock-max-rate = <0 0 0 0 412500000 19200000 412500000 412500000>; /* interrupt config */ interrupts = ; @@ -493,8 +494,9 @@ compatible = "qcom,dsi-phy-v3.0"; label = "dsi-phy-0"; cell-index = <0>; - reg = <0xae94400 0x7c0>; - reg-names = "dsi_phy"; + reg = <0xae94400 0x7c0>, + <0xae94200 0x100>; + reg-names = "dsi_phy", "dyn_refresh_base"; vdda-0p9-supply = <&pm8998_l1>; qcom,platform-strength-ctrl = [55 03 @@ -526,8 +528,9 @@ compatible = "qcom,dsi-phy-v3.0"; label = "dsi-phy-1"; cell-index = <1>; - reg = <0xae96400 0x7c0>; - reg-names = "dsi_phy"; + reg = <0xae96400 0x7c0>, + <0xae96200 0x100>; + reg-names = "dsi_phy", "dyn_refresh_base"; vdda-0p9-supply = <&pm8998_l1>; qcom,platform-strength-ctrl = [55 03 diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi index 1e132941d2d0..89cc6d26f39f 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi @@ -414,7 +414,7 @@ }; &mdss_mdp { - clock-max-rate = <0 0 0 0 430000000 19200000 0 430000000>; + clock-max-rate = <0 0 0 0 430000000 19200000 430000000 430000000>; qcom,sde-min-core-ib-kbps = <4800000>; qcom,sde-max-bw-low-kbps = <9600000>; qcom,sde-max-bw-high-kbps = <9600000>; From 58b39ed82f18aa162559acbef7670a54dcf17c7c Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Tue, 20 Sep 2022 01:34:02 +0300 Subject: [PATCH 047/356] arm64: dts: qcom: sdm845-sde: Add dsc pair mask Add dsc pair mask to be used for dsc rerservation considering hw restrictions. Signed-off-by: Konrad Dybcio Signed-off-by: Pavel Dubrova --- arch/arm64/boot/dts/qcom/sdm845-sde.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi index 152a03fd952e..82cd4ceea482 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi @@ -92,6 +92,7 @@ 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 0x0>; qcom,sde-dither-version = <0x00010000>; From d716138184c843a66d74165441f1237410e02e53 Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Tue, 23 Nov 2021 03:00:19 +0200 Subject: [PATCH 048/356] arm64: dts: qcom: sdm845-sde: Move MDP non-secure CB to a separate device Currently, the MDP non-secure context-bank is part of the MDP device. Move it to a separate device, so that it would have its own probe and make the implementation similar to other display context-banks. Signed-off-by: Pavel Dubrova --- arch/arm64/boot/dts/qcom/sdm845-sde.dtsi | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi index 82cd4ceea482..600d43fa07bf 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi @@ -34,8 +34,6 @@ interrupts = ; interrupt-controller; #interrupt-cells = <1>; - iommus = <&apps_smmu 0x880 0x8>, - <&apps_smmu 0xc80 0x8>; #address-cells = <1>; #size-cells = <0>; @@ -249,6 +247,15 @@ qcom,sde-dspp-dither = <0x82c 0x00010007>; }; + smmu_sde_unsec: qcom,smmu_sde_unsec_cb { + compatible = "qcom,smmu_sde_unsec"; + iommus = <&apps_smmu 0x880 0x8>, + <&apps_smmu 0xc80 0x8>; + 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 0x881 0x8>, From 3d94367b6a0d4893d8d497f5ff50b3c2d6ae5ed6 Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Thu, 18 Nov 2021 23:38:09 +0200 Subject: [PATCH 049/356] arm64: dts: qcom: pm8998: Update SPMI based pmic drivers Update SPMI based pmic driver instead of qpnp drivers in the compatible string to take care of the driver changes for vadc, temp-alarm, WLED. Update the PMI8998 dtsi to use QTI LPG, QTI TRI_LED and QTI HAPTICS drivers. Signed-off-by: Pavel Dubrova --- arch/arm64/boot/dts/qcom/pm8998.dtsi | 132 ++++----- arch/arm64/boot/dts/qcom/pmi8998.dtsi | 330 +++++++++++++---------- arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi | 142 ++++------ 3 files changed, 281 insertions(+), 323 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/pm8998.dtsi b/arch/arm64/boot/dts/qcom/pm8998.dtsi index 253cfd3decaf..9e6e231f9622 100644 --- a/arch/arm64/boot/dts/qcom/pm8998.dtsi +++ b/arch/arm64/boot/dts/qcom/pm8998.dtsi @@ -3,9 +3,12 @@ * Copyright (c) 2016-2017, 2019, The Linux Foundation. All rights reserved. */ -#include -#include #include +#include +#include +#include +#include +#include &spmi_bus { qcom,pm8998@0 { @@ -34,19 +37,19 @@ qcom,store-hard-reset-reason; qcom,pon_1 { - qcom,pon-type = <0>; + qcom,pon-type = ; qcom,pull-up = <1>; - linux,code = <116>; + linux,code = ; }; qcom,pon_2 { - qcom,pon-type = <1>; + qcom,pon-type = ; qcom,pull-up = <1>; - linux,code = <114>; + linux,code = ; }; qcom,pon_3 { - qcom,pon-type = <3>; + qcom,pon-type = ; qcom,support-reset = <1>; qcom,pull-up = <1>; qcom,s1-timer = <6720>; @@ -57,13 +60,13 @@ }; pm8998_tz: qcom,temp-alarm@2400 { - compatible = "qcom,qpnp-temp-alarm"; + compatible = "qcom,spmi-temp-alarm"; reg = <0x2400 0x100>; interrupts = <0x0 0x24 0x0 IRQ_TYPE_EDGE_RISING>; - label = "pm8998_tz"; - qcom,channel-num = <6>; - qcom,temp_alarm-vadc = <&pm8998_vadc>; + io-channels = <&pm8998_vadc ADC_DIE_TEMP>; + io-channel-names = "thermal"; #thermal-sensor-cells = <0>; + qcom,temperature-threshold-set = <1>; }; pm8998_gpios: pinctrl@c000 { @@ -109,111 +112,66 @@ }; pm8998_rtc: qcom,pm8998_rtc { - compatible = "qcom,qpnp-rtc"; - #address-cells = <1>; - #size-cells = <1>; - qcom,qpnp-rtc-write = <0>; - qcom,qpnp-rtc-alarm-pwrup = <0>; - - qcom,pm8998_rtc_rw@6000 { - reg = <0x6000 0x100>; - }; - qcom,pm8998_rtc_alarm@6100 { - reg = <0x6100 0x100>; - interrupts = <0x0 0x61 0x1 IRQ_TYPE_NONE>; - }; + compatible = "qcom,pm8941-rtc"; + interrupts = <0x0 0x61 0x1 IRQ_TYPE_NONE>; }; pm8998_vadc: vadc@3100 { - compatible = "qcom,qpnp-vadc-hc"; + compatible = "qcom,spmi-adc-rev2"; reg = <0x3100 0x100>; #address-cells = <1>; #size-cells = <0>; interrupts = <0x0 0x31 0x0 IRQ_TYPE_EDGE_RISING>; interrupt-names = "eoc-int-en-set"; qcom,adc-vdd-reference = <1875>; + #io-channel-cells = <1>; + io-channel-ranges; - chan@6 { - label = "die_temp"; - reg = <6>; - qcom,decimation = <2>; - qcom,pre-div-channel-scaling = <0>; - qcom,calibration-type = "absolute"; - qcom,scale-function = <3>; - qcom,hw-settle-time = <0>; - qcom,fast-avg-setup = <0>; - qcom,cal-val = <0>; + /* Channel nodes */ + ref_gnd@0 { + label = "ref_gnd"; + reg = ; + qcom,pre-scaling = <1 1>; }; - chan@0 { - label = "ref_gnd"; - reg = <0>; - qcom,decimation = <2>; - qcom,pre-div-channel-scaling = <0>; - qcom,calibration-type = "absolute"; - qcom,scale-function = <0>; - qcom,hw-settle-time = <0>; - qcom,fast-avg-setup = <0>; - qcom,cal-val = <0>; + vref_1p25@1 { + label = "vref_1p25"; + reg = ; + qcom,pre-scaling = <1 1>; }; - chan@1 { - label = "ref_1250v"; - reg = <1>; - qcom,decimation = <2>; - qcom,pre-div-channel-scaling = <0>; - qcom,calibration-type = "absolute"; - qcom,scale-function = <0>; - qcom,hw-settle-time = <0>; - qcom,fast-avg-setup = <0>; - qcom,cal-val = <0>; + die_temp@6 { + label = "die_temp"; + reg = ; + qcom,pre-scaling = <1 1>; }; }; pm8998_adc_tm: vadc@3400 { - compatible = "qcom,qpnp-adc-tm-hc"; + compatible = "qcom,adc-tm-rev2"; reg = <0x3400 0x100>; + interrupts = <0x0 0x34 0x0 IRQ_TYPE_EDGE_RISING>; + interrupt-names = "thr-int-en"; #address-cells = <1>; #size-cells = <0>; - interrupts = <0x0 0x34 0x0 IRQ_TYPE_EDGE_RISING>; - interrupt-names = "eoc-int-en-set"; - qcom,adc-vdd-reference = <1875>; - qcom,adc_tm-vadc = <&pm8998_vadc>; - qcom,decimation = <0>; - qcom,fast-avg-setup = <0>; #thermal-sensor-cells = <1>; + qcom,pmic-revid = <&pm8998_revid>; }; - pm8998_div_clk1: qcom,clkdiv@5b00 { - compatible = "qcom,qpnp-clkdiv"; - reg = <0x5b00 0x100>; + pm8998_clkdiv: clock-controller@5b00 { + compatible = "qcom,spmi-clkdiv"; + reg = <0x5b00 0x300>; #clock-cells = <1>; - qcom,cxo-freq = <19200000>; - qcom,clkdiv-id = <1>; - qcom,clkdiv-init-freq = <19200000>; - }; - - pm8998_div_clk2: qcom,clkdiv@5c00 { - compatible = "qcom,qpnp-clkdiv"; - reg = <0x5c00 0x100>; - #clock-cells = <1>; - qcom,cxo-freq = <19200000>; - qcom,clkdiv-id = <2>; - qcom,clkdiv-init-freq = <19200000>; - }; - - pm8998_div_clk3: qcom,clkdiv@5d00 { - compatible = "qcom,qpnp-clkdiv"; - reg = <0x5d00 0x100>; - #clock-cells = <1>; - qcom,cxo-freq = <19200000>; - qcom,clkdiv-id = <3>; - qcom,clkdiv-init-freq = <19200000>; + qcom,num-clkdivs = <3>; + clock-output-names = "pm8998_div_clk1", + "pm8998_div_clk2", "pm8998_div_clk3"; + clocks = <&clock_rpmh RPMH_CXO_CLK>; + clock-names = "xo"; }; }; qcom,pm8998@1 { - compatible ="qcom,spmi-pmic"; + compatible = "qcom,spmi-pmic"; reg = <0x1 SPMI_USID>; #address-cells = <2>; #size-cells = <0>; diff --git a/arch/arm64/boot/dts/qcom/pmi8998.dtsi b/arch/arm64/boot/dts/qcom/pmi8998.dtsi index e4f6ff62f1b0..fe497c651166 100644 --- a/arch/arm64/boot/dts/qcom/pmi8998.dtsi +++ b/arch/arm64/boot/dts/qcom/pmi8998.dtsi @@ -37,6 +37,7 @@ io-channels = <&pmi8998_rradc 7>; io-channel-names = "thermal"; #thermal-sensor-cells = <0>; + qcom,temperature-threshold-set = <1>; }; pmi8998_gpios: pinctrl@c000 { @@ -341,124 +342,105 @@ #address-cells = <2>; #size-cells = <0>; - pmi8998_pwm_1: pwm@b100 { - compatible = "qcom,qpnp-pwm"; - reg = <0xb100 0x100>, - <0xb042 0x7e>; - reg-names = "qpnp-lpg-channel-base", - "qpnp-lpg-lut-base"; - qcom,lpg-lut-size = <0x7e>; - qcom,channel-id = <1>; - qcom,supported-sizes = <6>, <9>; - qcom,ramp-index = <0>; - #pwm-cells = <2>; - status = "disabled"; - }; - - pmi8998_pwm_2: pwm@b200 { - compatible = "qcom,qpnp-pwm"; - reg = <0xb200 0x100>, - <0xb042 0x7e>; - reg-names = "qpnp-lpg-channel-base", - "qpnp-lpg-lut-base"; - qcom,lpg-lut-size = <0x7e>; - qcom,channel-id = <2>; - qcom,supported-sizes = <6>, <9>; - qcom,ramp-index = <1>; - #pwm-cells = <2>; - status = "disabled"; - }; - - pmi8998_pwm_3: pwm@b300 { - compatible = "qcom,qpnp-pwm"; - reg = <0xb300 0x100>, - <0xb042 0x7e>; - reg-names = "qpnp-lpg-channel-base", - "qpnp-lpg-lut-base"; - qcom,lpg-lut-size = <0x7e>; - qcom,channel-id = <3>; - qcom,supported-sizes = <6>, <9>; - qcom,ramp-index = <2>; - #pwm-cells = <2>; - }; - - pmi8998_pwm_4: pwm@b400 { - compatible = "qcom,qpnp-pwm"; - reg = <0xb400 0x100>, - <0xb042 0x7e>; - reg-names = "qpnp-lpg-channel-base", - "qpnp-lpg-lut-base"; - qcom,lpg-lut-size = <0x7e>; - qcom,channel-id = <4>; - qcom,supported-sizes = <6>, <9>; - qcom,ramp-index = <3>; + pmi8998_lpg: qcom,pwms@b100 { + compatible = "qcom,pwm-lpg"; + reg = <0xb100 0x600>, <0xb000 0x100>; + reg-names = "lpg-base", "lut-base"; #pwm-cells = <2>; + qcom,num-lpg-channels = <6>; + 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; + }; + + lpg4 { + qcom,lpg-chan-id = <4>; + 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; + }; + + lpg5 { + qcom,lpg-chan-id = <5>; + 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; + }; + + lpg6 { + qcom,lpg-chan-id = <6>; + 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; + }; }; - pmi8998_pwm_5: pwm@b500 { - compatible = "qcom,qpnp-pwm"; - reg = <0xb500 0x100>, - <0xb042 0x7e>; - reg-names = "qpnp-lpg-channel-base", - "qpnp-lpg-lut-base"; - qcom,lpg-lut-size = <0x7e>; - qcom,channel-id = <5>; - qcom,supported-sizes = <6>, <9>; - qcom,ramp-index = <4>; - #pwm-cells = <2>; - }; + pmi8998_rgb_led: qcom,pwms@d000 { + compatible = "qcom,tri-led"; + reg = <0xd000 0x100>; - pmi8998_pwm_6: pwm@b600 { - compatible = "qcom,qpnp-pwm"; - reg = <0xb600 0x100>, - <0xb042 0x7e>; - reg-names = "qpnp-lpg-channel-base", - "qpnp-lpg-lut-base"; - qcom,lpg-lut-size = <0x7e>; - qcom,channel-id = <6>; - qcom,supported-sizes = <6>, <9>; - qcom,ramp-index = <5>; - #pwm-cells = <2>; - status = "disabled"; - }; + red { + label = "red"; + pwms = <&pmi8998_lpg 4 1000000>; + led-sources = <0>; + linux,default-trigger = "timer"; + }; - qcom,leds@d000 { - compatible = "qcom,leds-qpnp"; - reg = <0xd000 0x100>; - label = "rgb"; - status = "okay"; + green { + label = "green"; + pwms = <&pmi8998_lpg 3 1000000>; + led-sources = <1>; + linux,default-trigger = "timer"; + }; - red_led: qcom,rgb_0 { - label = "rgb"; - qcom,id = <3>; - qcom,mode = "pwm"; - pwms = <&pmi8998_pwm_5 0 0>; - qcom,pwm-us = <1000>; - qcom,max-current = <12>; - qcom,default-state = "off"; - linux,name = "red"; - }; - - green_led: qcom,rgb_1 { - label = "rgb"; - qcom,id = <4>; - qcom,mode = "pwm"; - pwms = <&pmi8998_pwm_4 0 0>; - qcom,pwm-us = <1000>; - qcom,max-current = <12>; - qcom,default-state = "off"; - linux,name = "green"; - }; - - blue_led: qcom,rgb_2 { - label = "rgb"; - qcom,id = <5>; - qcom,mode = "pwm"; - pwms = <&pmi8998_pwm_3 0 0>; - qcom,pwm-us = <1000>; - qcom,max-current = <12>; - qcom,default-state = "off"; - linux,name = "blue"; + blue { + label = "blue"; + pwms = <&pmi8998_lpg 2 1000000>; + led-sources = <2>; + linux,default-trigger = "timer"; }; }; @@ -544,33 +526,23 @@ }; pmi8998_wled: qcom,leds@d800 { - compatible = "qcom,qpnp-wled"; + compatible = "qcom,pmi8998-spmi-wled"; reg = <0xd800 0x100>, <0xd900 0x100>; - reg-names = "qpnp-wled-ctrl-base", - "qpnp-wled-sink-base"; + reg-names = "wled-ctrl-base", + "wled-sink-base"; interrupts = <0x3 0xd8 0x1 IRQ_TYPE_EDGE_RISING>, <0x3 0xd8 0x2 IRQ_TYPE_EDGE_RISING>; interrupt-names = "ovp-irq", "sc-irq"; - linux,name = "wled"; - linux,default-trigger = "bkl-trigger"; - qcom,fdbk-output = "auto"; - qcom,vref-uv = <127500>; - qcom,switch-freq-khz = <800>; - qcom,ovp-mv = <29600>; - qcom,ilim-ma = <970>; - qcom,boost-duty-ns = <26>; - qcom,mod-freq-khz = <9600>; - qcom,dim-mode = "hybrid"; - qcom,hyb-thres = <625>; - qcom,sync-dly-us = <800>; - qcom,fs-curr-ua = <25000>; - qcom,cons-sync-write-delay-us = <1000>; - qcom,led-strings-list = [00 01 02 03]; - qcom,en-ext-pfet-sc-pro; + label = "backlight"; + qcom,fs-current-limit = <25000>; + qcom,boost-current-limit = <970>; + qcom,switching-freq = <800>; + qcom,ovp = <29600>; + qcom,sync-dly = <800>; + qcom,string-cfg = <15>; qcom,pmic-revid = <&pmi8998_revid>; - qcom,loop-auto-gm-en; - qcom,auto-calibration-enable; + qcom,auto-calibration; status = "disabled"; }; @@ -693,25 +665,89 @@ }; pmi8998_haptics: qcom,haptics@c000 { - compatible = "qcom,qpnp-haptics"; + 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,pmic-revid = <&pmi8998_revid>; - qcom,pmic-misc = <&pmi8998_misc>; - qcom,misc-clk-trim-error-reg = <0xf3>; - qcom,actuator-type = <0>; - qcom,play-mode = "direct"; + qcom,actuator-type = "lra"; qcom,vmax-mv = <3200>; - qcom,ilim-ma = <800>; - qcom,sc-dbc-cycles = <8>; - qcom,wave-play-rate-us = <6667>; - qcom,en-brake; - qcom,lra-high-z = "opt1"; - qcom,lra-auto-res-mode = "qwd"; - qcom,lra-res-cal-period = <4>; - status = "disabled"; + 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; + }; }; }; }; diff --git a/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi index fcfb3c9be4bb..9792f0a613b9 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi @@ -3,6 +3,7 @@ * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. */ +#include #include #include "sdm845-pmic-overlay.dtsi" #include "sdm845-pinctrl-overlay.dtsi" @@ -186,13 +187,12 @@ }; &pmi8998_wled { + qcom,string-cfg = <3>; status = "okay"; - qcom,led-strings-list = [01 02]; }; &pmi8998_haptics { qcom,vmax-mv = <2400>; - qcom,lra-auto-mode; status = "okay"; }; @@ -342,126 +342,90 @@ }; &pm8998_vadc { - chan@83 { + vph_pwr@83 { label = "vph_pwr"; - reg = <0x83>; - qcom,decimation = <2>; - qcom,pre-div-channel-scaling = <1>; - qcom,calibration-type = "absolute"; - qcom,scale-function = <0>; - qcom,hw-settle-time = <0>; - qcom,fast-avg-setup = <0>; + reg = ; + qcom,pre-scaling = <1 1>; }; - chan@85 { + vcoin@85 { label = "vcoin"; - reg = <0x85>; - qcom,decimation = <2>; - qcom,pre-div-channel-scaling = <1>; - qcom,calibration-type = "absolute"; - qcom,scale-function = <0>; - qcom,hw-settle-time = <0>; - qcom,fast-avg-setup = <0>; + reg = ; + qcom,pre-scaling = <1 1>; }; - chan@4c { + xo_therm@4c { label = "xo_therm"; - reg = <0x4c>; - qcom,decimation = <2>; - qcom,pre-div-channel-scaling = <0>; - qcom,calibration-type = "ratiometric"; - qcom,scale-function = <4>; - qcom,hw-settle-time = <2>; - qcom,fast-avg-setup = <0>; + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; }; - chan@4d { + msm_therm@4d { label = "msm_therm"; - reg = <0x4d>; - qcom,decimation = <2>; - qcom,pre-div-channel-scaling = <0>; - qcom,calibration-type = "ratiometric"; - qcom,scale-function = <2>; - qcom,hw-settle-time = <2>; - qcom,fast-avg-setup = <0>; + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; }; - chan@4f { + pa_therm1@4f { label = "pa_therm1"; - reg = <0x4f>; - qcom,decimation = <2>; - qcom,pre-div-channel-scaling = <0>; - qcom,calibration-type = "ratiometric"; - qcom,scale-function = <2>; - qcom,hw-settle-time = <2>; - qcom,fast-avg-setup = <0>; + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; }; - chan@51 { + quiet_therm@51 { label = "quiet_therm"; - reg = <0x51>; - qcom,decimation = <2>; - qcom,pre-div-channel-scaling = <0>; - qcom,calibration-type = "ratiometric"; - qcom,scale-function = <2>; - qcom,hw-settle-time = <2>; - qcom,fast-avg-setup = <0>; + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; }; }; &pm8998_adc_tm { - chan@83 { + io-channels = <&pm8998_vadc ADC_VPH_PWR>, + <&pm8998_vadc ADC_XO_THERM_PU2>, + <&pm8998_vadc ADC_AMUX_THM1_PU2>, + <&pm8998_vadc ADC_AMUX_THM3_PU2>, + <&pm8998_vadc ADC_AMUX_THM5_PU2>; + + /* Channel nodes */ + vph_pwr@83 { label = "vph_pwr"; - reg = <0x83>; - qcom,pre-div-channel-scaling = <1>; - qcom,calibration-type = "absolute"; - qcom,scale-function = <0>; - qcom,hw-settle-time = <0>; - qcom,btm-channel-number = <0x60>; + reg = ; }; - chan@4c { + xo_therm@4c { label = "xo_therm"; - reg = <0x4c>; - qcom,pre-div-channel-scaling = <0>; - qcom,calibration-type = "ratiometric"; - qcom,scale-function = <4>; - qcom,hw-settle-time = <2>; - qcom,btm-channel-number = <0x68>; - qcom,thermal-node; + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; }; - chan@4d { + msm_therm@4d { label = "msm_therm"; - reg = <0x4d>; - qcom,pre-div-channel-scaling = <0>; - qcom,calibration-type = "ratiometric"; - qcom,scale-function = <2>; - qcom,hw-settle-time = <2>; - qcom,btm-channel-number = <0x70>; - qcom,thermal-node; + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; }; - chan@4f { + pa_therm1@4f { label = "pa_therm1"; - reg = <0x4f>; - qcom,pre-div-channel-scaling = <0>; - qcom,calibration-type = "ratiometric"; - qcom,scale-function = <2>; - qcom,hw-settle-time = <2>; - qcom,btm-channel-number = <0x78>; - qcom,thermal-node; + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; }; - chan@51 { + quiet_therm@51 { label = "quiet_therm"; - reg = <0x51>; - qcom,pre-div-channel-scaling = <0>; - qcom,calibration-type = "ratiometric"; - qcom,scale-function = <2>; - qcom,hw-settle-time = <2>; - qcom,btm-channel-number = <0x80>; - qcom,thermal-node; + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; }; }; From 1ebaf75db6d4741efa7e263480fa76ec5214f221 Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Thu, 2 Dec 2021 22:45:27 +0200 Subject: [PATCH 050/356] arm64: dts: sdm845-usb: Use interrupts-extended for PDC IRQ PDC interrupt is child of interrupt controller. Hence define PDC interrupts using interrupts-extended property having PDC phandle, PDC output port and IRQ type. Signed-off-by: Pavel Dubrova --- .../boot/dts/qcom/sdm845-670-usb-common.dtsi | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi index ec73b4f90ef0..703463d7d8d3 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi @@ -20,10 +20,10 @@ #size-cells = <1>; ranges; - interrupts = , - , - , - ; + interrupts-extended = <&pdc 9 IRQ_TYPE_LEVEL_HIGH>, + <&intc GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 6 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 8 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "dp_hs_phy_irq", "pwr_event_irq", "ss_phy_irq", "dm_hs_phy_irq"; @@ -361,10 +361,10 @@ #size-cells = <1>; ranges; - interrupts = , - , - , - ; + interrupts-extended = <&pdc 11 IRQ_TYPE_LEVEL_HIGH>, + <&intc GIC_SPI 135 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 7 IRQ_TYPE_LEVEL_HIGH>, + <&pdc 10 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "dp_hs_phy_irq", "pwr_event_irq", "ss_phy_irq", "dm_hs_phy_irq"; From c4206931e2556c9139dc73295739a8fd04e83ceb Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Thu, 2 Dec 2021 22:48:08 +0200 Subject: [PATCH 051/356] arm64: dts: sdm845-usb: Change trigger type of dp/dm_hs_phy_irq IRQ type mentioned in dwc3-msm driver at usb_irq_info for dp_hs_phy_irq and dm_hs_phy_irq is trigger rising, hence change the trigger type to EDGE RISING. Signed-off-by: Pavel Dubrova --- arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi index 703463d7d8d3..c9a37b705577 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi @@ -20,10 +20,10 @@ #size-cells = <1>; ranges; - interrupts-extended = <&pdc 9 IRQ_TYPE_LEVEL_HIGH>, + interrupts-extended = <&pdc 9 IRQ_TYPE_EDGE_RISING>, <&intc GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>, <&pdc 6 IRQ_TYPE_LEVEL_HIGH>, - <&pdc 8 IRQ_TYPE_LEVEL_HIGH>; + <&pdc 8 IRQ_TYPE_EDGE_RISING>; interrupt-names = "dp_hs_phy_irq", "pwr_event_irq", "ss_phy_irq", "dm_hs_phy_irq"; @@ -361,10 +361,10 @@ #size-cells = <1>; ranges; - interrupts-extended = <&pdc 11 IRQ_TYPE_LEVEL_HIGH>, + interrupts-extended = <&pdc 11 IRQ_TYPE_EDGE_RISING>, <&intc GIC_SPI 135 IRQ_TYPE_LEVEL_HIGH>, <&pdc 7 IRQ_TYPE_LEVEL_HIGH>, - <&pdc 10 IRQ_TYPE_LEVEL_HIGH>; + <&pdc 10 IRQ_TYPE_EDGE_RISING>; interrupt-names = "dp_hs_phy_irq", "pwr_event_irq", "ss_phy_irq", "dm_hs_phy_irq"; From 96a79aaed17b63c6973ed5e4c7410b80d053ae54 Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Fri, 3 Dec 2021 16:22:00 +0200 Subject: [PATCH 052/356] arm64: dts: qcom: sdm845: Update interrupts-cells of PDC interrupts-cells of PDC interrupt controller must be 2. The first element of the tuple is the PDC pin for the interrupt. The second element is the trigger type. Signed-off-by: Pavel Dubrova --- arch/arm64/boot/dts/qcom/sdm845.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index a0365267bb2f..64457b2e3695 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -811,7 +811,7 @@ compatible = "qcom,sdm845-pdc"; reg = <0xb220000 0x400>; qcom,pdc-ranges = <0 480 94>, <94 609 15>, <119 634 7>; - #interrupt-cells = <3>; + #interrupt-cells = <2>; interrupt-parent = <&intc>; interrupt-controller; }; From 0d0937142dc7753501380c46e1a23f5501e36934 Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Mon, 6 Dec 2021 00:54:04 +0200 Subject: [PATCH 053/356] arm64: dts: qcom: sdm845-sde-display: Rewrite dts for display support Rewrite display device tree support for kernel 4.19. Signed-off-by: Pavel Dubrova --- .../dsi-panel-r63417-truly-1080p-cmd.dtsi | 4 + .../dsi-panel-sharp-dualmipi-1080p-120hz.dtsi | 4 + .../dsi-panel-test-dualmipi-oled-cmd.dtsi | 4 + arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi | 4 - .../boot/dts/qcom/sdm845-sde-display.dtsi | 453 ++---------------- .../dsi-panel-nt35597-dualmipi-wqxga-cmd.dtsi | 4 + ...si-panel-nt35597-dualmipi-wqxga-video.dtsi | 4 + 7 files changed, 49 insertions(+), 428 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-r63417-truly-1080p-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-r63417-truly-1080p-cmd.dtsi index 87fdc371c11e..1311ee4203a3 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-r63417-truly-1080p-cmd.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-r63417-truly-1080p-cmd.dtsi @@ -8,6 +8,10 @@ qcom,mdss-dsi-panel-name = "r63417 truly 1080p 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>; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dualmipi-1080p-120hz.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dualmipi-1080p-120hz.dtsi index 152a9ccb4e75..235bbebb7a38 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dualmipi-1080p-120hz.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-sharp-dualmipi-1080p-120hz.dtsi @@ -8,6 +8,10 @@ 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,mdss-dsi-virtual-channel-id = <0>; qcom,mdss-dsi-stream = <0>; qcom,mdss-dsi-bpp = <24>; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-test-dualmipi-oled-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-test-dualmipi-oled-cmd.dtsi index 531f040156e2..ccca03c4aba2 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-test-dualmipi-oled-cmd.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-test-dualmipi-oled-cmd.dtsi @@ -8,6 +8,10 @@ qcom,mdss-dsi-panel-name = "Dual test cmd mode DSI amoled non-DSC 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>; diff --git a/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi index 9792f0a613b9..8f0a40b37ac0 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi @@ -182,10 +182,6 @@ qcom,platform-te-gpio = <&tlmm 10 0>; }; -&dsi_nt35597_truly_dsc_cmd_display { - qcom,dsi-display-active; -}; - &pmi8998_wled { qcom,string-cfg = <3>; status = "okay"; diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi index d52b1172dd25..3a7aa883a256 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi @@ -100,447 +100,34 @@ }; }; - dsi_sharp_4k_dsc_video_display: qcom,dsi-display@0 { + sde_dsi: qcom,dsi-display-primary { compatible = "qcom,dsi-display"; - label = "dsi_sharp_4k_dsc_video_display"; - qcom,display-type = "primary"; + 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>; - clock-names = "mux_byte_clk", "mux_pixel_clk"; - - 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 10 0>; - qcom,platform-reset-gpio = <&tlmm 6 0>; - qcom,panel-mode-gpio = <&tlmm 52 0>; - - qcom,dsi-panel = <&dsi_sharp_4k_dsc_video>; - vddio-supply = <&pm8998_l14>; - lab-supply = <&lab_regulator>; - ibb-supply = <&ibb_regulator>; - }; - - dsi_sharp_4k_dsc_cmd_display: qcom,dsi-display@1 { - compatible = "qcom,dsi-display"; - label = "dsi_sharp_4k_dsc_cmd_display"; - qcom,display-type = "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>; - clock-names = "mux_byte_clk", "mux_pixel_clk"; - - 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 10 0>; - qcom,platform-reset-gpio = <&tlmm 6 0>; - qcom,panel-mode-gpio = <&tlmm 52 0>; - - qcom,dsi-panel = <&dsi_sharp_4k_dsc_cmd>; - vddio-supply = <&pm8998_l14>; - lab-supply = <&lab_regulator>; - ibb-supply = <&ibb_regulator>; - }; - - dsi_sharp_1080_cmd_display: qcom,dsi-display@2 { - compatible = "qcom,dsi-display"; - label = "dsi_sharp_1080_cmd_display"; - qcom,display-type = "primary"; - - qcom,dsi-ctrl = <&mdss_dsi0>; - qcom,dsi-phy = <&mdss_dsi_phy0>; - clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, - <&mdss_dsi0_pll PCLK_MUX_0_CLK>; - clock-names = "mux_byte_clk", "mux_pixel_clk"; - - 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 10 0>; - qcom,platform-reset-gpio = <&tlmm 6 0>; - qcom,panel-mode-gpio = <&tlmm 52 0>; - - qcom,dsi-panel = <&dsi_sharp_1080_cmd>; - vddio-supply = <&pm8998_l14>; - lab-supply = <&lab_regulator>; - ibb-supply = <&ibb_regulator>; - }; - - dsi_dual_sharp_1080_120hz_cmd_display: qcom,dsi-display@3 { - compatible = "qcom,dsi-display"; - label = "dsi_dual_sharp_1080_120hz_cmd_display"; - qcom,display-type = "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>; - clock-names = "mux_byte_clk", "mux_pixel_clk"; - - 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 10 0>; - qcom,platform-reset-gpio = <&tlmm 6 0>; - qcom,panel-mode-gpio = <&tlmm 52 0>; - - qcom,dsi-panel = <&dsi_dual_sharp_1080_120hz_cmd>; - vddio-supply = <&pm8998_l14>; - lab-supply = <&lab_regulator>; - ibb-supply = <&ibb_regulator>; - }; - - dsi_dual_nt35597_truly_video_display: qcom,dsi-display@4 { - compatible = "qcom,dsi-display"; - label = "dsi_dual_nt35597_truly_video_display"; - qcom,display-type = "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>; - clock-names = "mux_byte_clk", "mux_pixel_clk"; - - pinctrl-names = "panel_active", "panel_suspend"; - pinctrl-0 = <&sde_dsi_active &sde_te_active>; - pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; - qcom,platform-reset-gpio = <&tlmm 6 0>; - qcom,panel-mode-gpio = <&tlmm 52 0>; - - qcom,dsi-panel = <&dsi_dual_nt35597_truly_video>; - vddio-supply = <&pm8998_l14>; - lab-supply = <&lab_regulator>; - ibb-supply = <&ibb_regulator>; - }; - - dsi_dual_nt35597_truly_cmd_display: qcom,dsi-display@5 { - compatible = "qcom,dsi-display"; - label = "dsi_dual_nt35597_truly_cmd_display"; - qcom,display-type = "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>; - clock-names = "mux_byte_clk", "mux_pixel_clk"; - - 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 10 0>; - qcom,platform-reset-gpio = <&tlmm 6 0>; - qcom,panel-mode-gpio = <&tlmm 52 0>; - - qcom,dsi-panel = <&dsi_dual_nt35597_truly_cmd>; - vddio-supply = <&pm8998_l14>; - lab-supply = <&lab_regulator>; - ibb-supply = <&ibb_regulator>; - }; - - dsi_nt35597_truly_dsc_cmd_display: qcom,dsi-display@6 { - compatible = "qcom,dsi-display"; - label = "dsi_nt35597_truly_dsc_cmd_display"; - qcom,display-type = "primary"; - - qcom,dsi-ctrl = <&mdss_dsi1>; - qcom,dsi-phy = <&mdss_dsi_phy1>; - clocks = <&mdss_dsi1_pll BYTECLK_MUX_1_CLK>, - <&mdss_dsi1_pll PCLK_MUX_1_CLK>; - clock-names = "mux_byte_clk", "mux_pixel_clk"; - - 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 10 0>; - qcom,platform-reset-gpio = <&tlmm 6 0>; - qcom,panel-mode-gpio = <&tlmm 52 0>; - - qcom,dsi-panel = <&dsi_nt35597_truly_dsc_cmd>; - vddio-supply = <&pm8998_l14>; - lab-supply = <&lab_regulator>; - ibb-supply = <&ibb_regulator>; - }; - - dsi_nt35597_truly_dsc_video_display: qcom,dsi-display@7 { - compatible = "qcom,dsi-display"; - label = "dsi_nt35597_truly_dsc_video_display"; - qcom,display-type = "primary"; - - qcom,dsi-ctrl = <&mdss_dsi1>; - qcom,dsi-phy = <&mdss_dsi_phy1>; - clocks = <&mdss_dsi1_pll BYTECLK_MUX_1_CLK>, - <&mdss_dsi1_pll PCLK_MUX_1_CLK>; - clock-names = "mux_byte_clk", "mux_pixel_clk"; - - 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 10 0>; - qcom,platform-reset-gpio = <&tlmm 6 0>; - qcom,panel-mode-gpio = <&tlmm 52 0>; - - qcom,dsi-panel = <&dsi_nt35597_truly_dsc_video>; - vddio-supply = <&pm8998_l14>; - lab-supply = <&lab_regulator>; - ibb-supply = <&ibb_regulator>; - }; - - dsi_sim_vid_display: qcom,dsi-display@8 { - compatible = "qcom,dsi-display"; - label = "dsi_sim_vid_display"; - qcom,display-type = "primary"; - - qcom,dsi-ctrl = <&mdss_dsi0>; - qcom,dsi-phy = <&mdss_dsi_phy0>; - clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, - <&mdss_dsi0_pll PCLK_MUX_0_CLK>; - clock-names = "mux_byte_clk", "mux_pixel_clk"; - - pinctrl-names = "panel_active", "panel_suspend"; - pinctrl-0 = <&sde_dsi_active &sde_te_active>; - pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; - - qcom,dsi-panel = <&dsi_sim_vid>; - }; - - dsi_dual_sim_vid_display: qcom,dsi-display@9 { - compatible = "qcom,dsi-display"; - label = "dsi_dual_sim_vid_display"; - qcom,display-type = "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>; - clock-names = "mux_byte_clk", "mux_pixel_clk"; - - pinctrl-names = "panel_active", "panel_suspend"; - pinctrl-0 = <&sde_dsi_active &sde_te_active>; - pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; - - qcom,dsi-panel = <&dsi_dual_sim_vid>; - }; - - dsi_sim_cmd_display: qcom,dsi-display@10 { - compatible = "qcom,dsi-display"; - label = "dsi_sim_cmd_display"; - qcom,display-type = "primary"; - - qcom,dsi-ctrl = <&mdss_dsi0>; - qcom,dsi-phy = <&mdss_dsi_phy0>; - clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, - <&mdss_dsi0_pll PCLK_MUX_0_CLK>; - clock-names = "mux_byte_clk", "mux_pixel_clk"; - - pinctrl-names = "panel_active", "panel_suspend"; - pinctrl-0 = <&sde_dsi_active &sde_te_active>; - pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; - - qcom,dsi-panel = <&dsi_sim_cmd>; - }; - - dsi_dual_sim_cmd_display: qcom,dsi-display@11 { - compatible = "qcom,dsi-display"; - label = "dsi_dual_sim_cmd_display"; - qcom,display-type = "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>; - clock-names = "mux_byte_clk", "mux_pixel_clk"; + <&mdss_dsi0_pll PCLK_MUX_0_CLK>, + <&mdss_dsi1_pll BYTECLK_MUX_1_CLK>, + <&mdss_dsi1_pll PCLK_MUX_1_CLK>; + clock-names = "mux_byte_clk0", "mux_pixel_clk0", + "mux_byte_clk1", "mux_pixel_clk1"; pinctrl-names = "panel_active", "panel_suspend"; pinctrl-0 = <&sde_dsi_active &sde_te_active>; pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; - qcom,dsi-panel = <&dsi_dual_sim_cmd>; - }; - - dsi_sim_dsc_375_cmd_display: qcom,dsi-display@12 { - compatible = "qcom,dsi-display"; - label = "dsi_sim_dsc_375_cmd_display"; - qcom,display-type = "primary"; - - qcom,dsi-ctrl = <&mdss_dsi0>; - qcom,dsi-phy = <&mdss_dsi_phy0>; - clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, - <&mdss_dsi0_pll PCLK_MUX_0_CLK>; - clock-names = "mux_byte_clk", "mux_pixel_clk"; - - pinctrl-names = "panel_active", "panel_suspend"; - pinctrl-0 = <&sde_dsi_active &sde_te_active>; - pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; - - qcom,dsi-panel = <&dsi_sim_dsc_375_cmd>; - }; - - dsi_dual_sim_dsc_375_cmd_display: qcom,dsi-display@13 { - compatible = "qcom,dsi-display"; - label = "dsi_dual_sim_dsc_375_cmd_display"; - qcom,display-type = "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>; - clock-names = "mux_byte_clk", "mux_pixel_clk"; - - pinctrl-names = "panel_active", "panel_suspend"; - pinctrl-0 = <&sde_dsi_active &sde_te_active>; - pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; - - qcom,dsi-panel = <&dsi_dual_sim_dsc_375_cmd>; - }; - - dsi_dual_nt35597_video_display: qcom,dsi-display@14 { - compatible = "qcom,dsi-display"; - label = "dsi_dual_nt35597_video_display"; - qcom,display-type = "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>; - clock-names = "mux_byte_clk", "mux_pixel_clk"; - - pinctrl-names = "panel_active", "panel_suspend"; - pinctrl-0 = <&sde_dsi_active &sde_te_active>; - pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend>; - qcom,platform-reset-gpio = <&tlmm 6 0>; - qcom,panel-mode-gpio = <&tlmm 52 0>; - - qcom,dsi-panel = <&dsi_dual_nt35597_video>; - vddio-supply = <&pm8998_l14>; - lab-supply = <&lab_regulator>; - ibb-supply = <&ibb_regulator>; - }; - - - dsi_dual_nt35597_cmd_display: qcom,dsi-display@15 { - compatible = "qcom,dsi-display"; - label = "dsi_dual_nt35597_cmd_display"; - qcom,display-type = "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>; - clock-names = "mux_byte_clk", "mux_pixel_clk"; - - 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 10 0>; - qcom,platform-reset-gpio = <&tlmm 6 0>; - qcom,panel-mode-gpio = <&tlmm 52 0>; - - qcom,dsi-panel = <&dsi_dual_nt35597_cmd>; - vddio-supply = <&pm8998_l14>; - lab-supply = <&lab_regulator>; - ibb-supply = <&ibb_regulator>; - }; - - dsi_dual_nt36850_truly_cmd_display: qcom,dsi-display@16 { - compatible = "qcom,dsi-display"; - label = "dsi_dual_nt36850_truly_cmd_display"; - qcom,display-type = "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>; - clock-names = "mux_byte_clk", "mux_pixel_clk"; - - 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 10 0>; - qcom,platform-reset-gpio = <&tlmm 6 0>; - qcom,panel-mode-gpio = <&tlmm 52 0>; - - qcom,dsi-panel = <&dsi_dual_nt36850_truly_cmd>; - vddio-supply = <&pm8998_l14>; - lab-supply = <&lab_regulator>; - ibb-supply = <&ibb_regulator>; - }; - - dsi_dual_test_cmd_display: qcom,dsi-display@17 { - compatible = "qcom,dsi-display"; - label = "dsi_dual_test_cmd"; - qcom,display-type = "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>; - clock-names = "mux_byte_clk", "mux_pixel_clk"; - - 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 10 0>; - qcom,platform-reset-gpio = <&tlmm 6 0>; - qcom,panel-mode-gpio = <&tlmm 52 0>; + qcom,panel-te-source = <0>; - qcom,dsi-panel = <&dsi_dual_test_cmd>; vddio-supply = <&pm8998_l14>; lab-supply = <&lab_regulator>; ibb-supply = <&ibb_regulator>; oled-vdda-supply = <&pm8998_l22>; - }; - - dsi_r63417_truly_1080_cmd_display: qcom,dsi-display@18 { - compatible = "qcom,dsi-display"; - label = "dsi_r63417_truly_1080_cmd_display"; - qcom,display-type = "primary"; - qcom,dsi-ctrl = <&mdss_dsi0>; - qcom,dsi-phy = <&mdss_dsi_phy0>; - clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, - <&mdss_dsi0_pll PCLK_MUX_0_CLK>; - clock-names = "src_byte_clk", "src_pixel_clk"; - - 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 10 0>; - qcom,platform-reset-gpio = <&tlmm 6 0>; - qcom,panel-mode-gpio = <&tlmm 52 0>; - - qcom,dsi-panel = <&dsi_r63417_truly_1080_cmd>; - vddio-supply = <&pm8998_l14>; - lab-supply = <&lab_regulator>; - ibb-supply = <&ibb_regulator>; - }; - - ext_dsi_bridge_display: qcom,dsi-display@19 { - compatible = "qcom,dsi-display"; - label = "ext_dsi_bridge_display"; - qcom,display-type = "primary"; - - qcom,dsi-ctrl = <&mdss_dsi0>; - qcom,dsi-phy = <&mdss_dsi_phy0>; - clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, - <&mdss_dsi0_pll PCLK_MUX_0_CLK>; - clock-names = "mux_byte_clk", "mux_pixel_clk"; - - ports { - #address-cells = <1>; - #size-cells = <0>; - - port@0 { - reg = <0>; - ext_dsi_out: endpoint { - }; - }; - }; + qcom,mdp = <&mdss_mdp>; + qcom,dsi-default-panel = <&dsi_nt35597_truly_dsc_cmd>; }; sde_wb: qcom,wb-display@0 { @@ -571,10 +158,11 @@ }; &mdss_mdp { - connectors = <&sde_rscc &sde_wb &sde_dp>; + connectors = <&sde_rscc &sde_wb &sde_dsi &sde_dp>; }; &dsi_dual_nt35597_truly_video { + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; qcom,mdss-dsi-t-clk-post = <0x0D>; qcom,mdss-dsi-t-clk-pre = <0x2D>; qcom,mdss-dsi-pan-enable-dynamic-fps; @@ -600,6 +188,7 @@ }; &dsi_dual_nt35597_truly_cmd { + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; qcom,mdss-dsi-t-clk-post = <0x0D>; qcom,mdss-dsi-t-clk-pre = <0x2D>; qcom,ulps-enabled; @@ -624,6 +213,7 @@ }; &dsi_nt35597_truly_dsc_cmd { + qcom,dsi-select-clocks = "mux_byte_clk1", "mux_pixel_clk1"; qcom,mdss-dsi-t-clk-post = <0x0b>; qcom,mdss-dsi-t-clk-pre = <0x23>; qcom,ulps-enabled; @@ -647,6 +237,7 @@ }; &dsi_nt35597_truly_dsc_video { + qcom,dsi-select-clocks = "mux_byte_clk1", "mux_pixel_clk1"; qcom,mdss-dsi-t-clk-post = <0x0b>; qcom,mdss-dsi-t-clk-pre = <0x23>; qcom,mdss-dsi-pan-enable-dynamic-fps; @@ -673,6 +264,7 @@ }; &dsi_sharp_4k_dsc_video { + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; qcom,mdss-dsi-t-clk-post = <0x0c>; qcom,mdss-dsi-t-clk-pre = <0x27>; qcom,mdss-dsi-display-timings { @@ -686,6 +278,7 @@ }; &dsi_sharp_4k_dsc_cmd { + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; qcom,mdss-dsi-t-clk-post = <0x0c>; qcom,mdss-dsi-t-clk-pre = <0x27>; qcom,mdss-dsi-display-timings { @@ -699,6 +292,7 @@ }; &dsi_dual_sharp_1080_120hz_cmd { + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; qcom,mdss-dsi-t-clk-post = <0x0f>; qcom,mdss-dsi-t-clk-pre = <0x36>; qcom,mdss-dsi-display-timings { @@ -713,6 +307,7 @@ }; &dsi_sharp_1080_cmd { + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; qcom,mdss-dsi-t-clk-post = <0x0c>; qcom,mdss-dsi-t-clk-pre = <0x29>; qcom,esd-check-enabled; @@ -734,6 +329,7 @@ }; &dsi_r63417_truly_1080_cmd { + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; qcom,mdss-dsi-t-clk-post = <0x0c>; qcom,mdss-dsi-t-clk-pre = <0x29>; qcom,esd-check-enabled; @@ -755,6 +351,7 @@ }; &dsi_sim_vid { + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; qcom,mdss-dsi-t-clk-post = <0x0d>; qcom,mdss-dsi-t-clk-pre = <0x2d>; qcom,mdss-dsi-display-timings { @@ -769,6 +366,7 @@ }; &dsi_dual_sim_vid { + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; qcom,mdss-dsi-t-clk-post = <0x0d>; qcom,mdss-dsi-t-clk-pre = <0x2d>; qcom,mdss-dsi-display-timings { @@ -783,6 +381,7 @@ }; &dsi_sim_cmd { + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; qcom,mdss-dsi-t-clk-post = <0x0c>; qcom,mdss-dsi-t-clk-pre = <0x29>; qcom,mdss-dsi-display-timings { @@ -817,6 +416,7 @@ }; &dsi_dual_sim_cmd { + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; qcom,mdss-dsi-t-clk-post = <0x0d>; qcom,mdss-dsi-t-clk-pre = <0x2d>; qcom,mdss-dsi-display-timings { @@ -843,6 +443,7 @@ }; &dsi_sim_dsc_375_cmd { + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; qcom,mdss-dsi-t-clk-post = <0x0d>; qcom,mdss-dsi-t-clk-pre = <0x2d>; qcom,mdss-dsi-display-timings { @@ -864,6 +465,7 @@ }; &dsi_dual_sim_dsc_375_cmd { + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; qcom,mdss-dsi-t-clk-post = <0x0d>; qcom,mdss-dsi-t-clk-pre = <0x2d>; qcom,mdss-dsi-display-timings { @@ -883,6 +485,7 @@ }; &dsi_dual_nt35597_video { + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; qcom,mdss-dsi-t-clk-post = <0x0d>; qcom,mdss-dsi-t-clk-pre = <0x2d>; qcom,mdss-dsi-display-timings { @@ -897,6 +500,7 @@ }; &dsi_dual_nt35597_cmd { + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; qcom,mdss-dsi-t-clk-post = <0x0d>; qcom,mdss-dsi-t-clk-pre = <0x2d>; qcom,ulps-enabled; @@ -914,6 +518,7 @@ }; &dsi_dual_nt36850_truly_cmd { + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; qcom,mdss-dsi-t-clk-post = <0x0E>; qcom,mdss-dsi-t-clk-pre = <0x30>; qcom,mdss-dsi-display-timings { diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-nt35597-dualmipi-wqxga-cmd.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-nt35597-dualmipi-wqxga-cmd.dtsi index f05fc5fc7827..d119d43d2f91 100644 --- a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-nt35597-dualmipi-wqxga-cmd.dtsi +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-nt35597-dualmipi-wqxga-cmd.dtsi @@ -3,6 +3,10 @@ qcom,mdss-dsi-panel-name = "Dual nt35597 cmd mode dsi 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-panel-framerate = <60>; qcom,mdss-dsi-virtual-channel-id = <0>; qcom,mdss-dsi-stream = <0>; diff --git a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-nt35597-dualmipi-wqxga-video.dtsi b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-nt35597-dualmipi-wqxga-video.dtsi index 4059d721eb88..3a99197eb2f6 100644 --- a/arch/arm64/boot/dts/vendor/qcom/dsi-panel-nt35597-dualmipi-wqxga-video.dtsi +++ b/arch/arm64/boot/dts/vendor/qcom/dsi-panel-nt35597-dualmipi-wqxga-video.dtsi @@ -3,6 +3,10 @@ qcom,mdss-dsi-panel-name = "Dual nt35597 video mode dsi 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-panel-framerate = <60>; qcom,mdss-dsi-virtual-channel-id = <0>; qcom,mdss-dsi-stream = <0>; From f0c17f89aac92481ba748f6e9a231f07eb903368 Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Mon, 13 Dec 2021 06:25:13 +0200 Subject: [PATCH 054/356] Revert "ARM: dts: msm: Use carve out memory to load GPU zap shader for sdm845" This reverts commit 7afa7cec6f09015205f3a870b14b6112ab68c08b. Signed-off-by: Pavel Dubrova --- arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi b/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi index 7a945c3052ae..bafad11adbae 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi @@ -9,7 +9,6 @@ compatible = "qcom,pil-tz-generic"; qcom,pas-id = <13>; qcom,firmware-name = "a630_zap"; - memory-region = <&pil_gpu_mem>; }; msm_bus: qcom,kgsl-busmon{ From c85e279f0452db895576dea3a969fa525c5a3287 Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Sun, 12 Dec 2021 03:15:45 +0200 Subject: [PATCH 055/356] arm64: dts: qcom: sdm845: Use PDC IRQ for SPMI_BUS Interrupts that are expected to wakeup the SoC from suspend or deep sleep mode need to be requested from the PDC interrupt controller. Change SPMI_BUS configuration to request PDC interrupt 1 instead of GIC interrupt 481. Signed-off-by: Pavel Dubrova --- arch/arm64/boot/dts/qcom/sdm845.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index 64457b2e3695..eac2ac3c93b8 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -906,7 +906,7 @@ <0xc40a000 0x26000>; reg-names = "core", "chnls", "obsrvr", "intr", "cnfg"; interrupt-names = "periph_irq"; - interrupts = ; + interrupts-extended = <&pdc 1 IRQ_TYPE_LEVEL_HIGH>; qcom,ee = <0>; qcom,channel = <0>; #address-cells = <2>; From f47df6023d07eb67a0cf0aba2f48dadd6d532a02 Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Sun, 19 Dec 2021 14:23:15 +0200 Subject: [PATCH 056/356] arm64: dts: qcom: sdm845: Remove IPA SRAM mapping IPA SRAM mapping array is hardcoded in the driver. Signed-off-by: Pavel Dubrova --- arch/arm64/boot/dts/qcom/sdm845.dtsi | 76 ---------------------------- 1 file changed, 76 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index eac2ac3c93b8..0d9c9f66b3ac 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -2854,82 +2854,6 @@ qcom,bus-vector-names = "MIN", "SVS2", "SVS", "NOMINAL", "TURBO"; - /* IPA RAM mmap */ - qcom,ipa-ram-mmap = < - 0x280 /* ofst_start; */ - 0x0 /* nat_ofst; */ - 0x0 /* nat_size; */ - 0x288 /* v4_flt_hash_ofst; */ - 0x78 /* v4_flt_hash_size; */ - 0x4000 /* v4_flt_hash_size_ddr; */ - 0x308 /* v4_flt_nhash_ofst; */ - 0x78 /* v4_flt_nhash_size; */ - 0x4000 /* v4_flt_nhash_size_ddr; */ - 0x388 /* v6_flt_hash_ofst; */ - 0x78 /* v6_flt_hash_size; */ - 0x4000 /* v6_flt_hash_size_ddr; */ - 0x408 /* v6_flt_nhash_ofst; */ - 0x78 /* v6_flt_nhash_size; */ - 0x4000 /* v6_flt_nhash_size_ddr; */ - 0xf /* v4_rt_num_index; */ - 0x0 /* v4_modem_rt_index_lo; */ - 0x7 /* v4_modem_rt_index_hi; */ - 0x8 /* v4_apps_rt_index_lo; */ - 0xe /* v4_apps_rt_index_hi; */ - 0x488 /* v4_rt_hash_ofst; */ - 0x78 /* v4_rt_hash_size; */ - 0x4000 /* v4_rt_hash_size_ddr; */ - 0x508 /* v4_rt_nhash_ofst; */ - 0x78 /* v4_rt_nhash_size; */ - 0x4000 /* v4_rt_nhash_size_ddr; */ - 0xf /* v6_rt_num_index; */ - 0x0 /* v6_modem_rt_index_lo; */ - 0x7 /* v6_modem_rt_index_hi; */ - 0x8 /* v6_apps_rt_index_lo; */ - 0xe /* v6_apps_rt_index_hi; */ - 0x588 /* v6_rt_hash_ofst; */ - 0x78 /* v6_rt_hash_size; */ - 0x4000 /* v6_rt_hash_size_ddr; */ - 0x608 /* v6_rt_nhash_ofst; */ - 0x78 /* v6_rt_nhash_size; */ - 0x4000 /* v6_rt_nhash_size_ddr; */ - 0x688 /* modem_hdr_ofst; */ - 0x140 /* modem_hdr_size; */ - 0x7c8 /* apps_hdr_ofst; */ - 0x0 /* apps_hdr_size; */ - 0x800 /* apps_hdr_size_ddr; */ - 0x7d0 /* modem_hdr_proc_ctx_ofst; */ - 0x200 /* modem_hdr_proc_ctx_size; */ - 0x9d0 /* apps_hdr_proc_ctx_ofst; */ - 0x200 /* apps_hdr_proc_ctx_size; */ - 0x0 /* apps_hdr_proc_ctx_size_ddr; */ - 0x0 /* modem_comp_decomp_ofst; diff */ - 0x0 /* modem_comp_decomp_size; diff */ - 0xbd8 /* modem_ofst; */ - 0x1024 /* modem_size; */ - 0x2000 /* apps_v4_flt_hash_ofst; */ - 0x0 /* apps_v4_flt_hash_size; */ - 0x2000 /* apps_v4_flt_nhash_ofst; */ - 0x0 /* apps_v4_flt_nhash_size; */ - 0x2000 /* apps_v6_flt_hash_ofst; */ - 0x0 /* apps_v6_flt_hash_size; */ - 0x2000 /* apps_v6_flt_nhash_ofst; */ - 0x0 /* apps_v6_flt_nhash_size; */ - 0x80 /* uc_info_ofst; */ - 0x200 /* uc_info_size; */ - 0x2000 /* end_ofst; */ - 0x2000 /* apps_v4_rt_hash_ofst; */ - 0x0 /* apps_v4_rt_hash_size; */ - 0x2000 /* apps_v4_rt_nhash_ofst; */ - 0x0 /* apps_v4_rt_nhash_size; */ - 0x2000 /* apps_v6_rt_hash_ofst; */ - 0x0 /* apps_v6_rt_hash_size; */ - 0x2000 /* apps_v6_rt_nhash_ofst; */ - 0x0 /* apps_v6_rt_nhash_size; */ - 0x1c00 /* uc_event_ring_ofst; */ - 0x400 /* uc_event_ring_size; */ - >; - /* smp2p information */ qcom,smp2p_map_ipa_1_out { compatible = "qcom,smp2p-map-ipa-1-out"; From f9743cb4f41657d1b770fc73c6aaebae4762c86f Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Sun, 19 Dec 2021 14:59:08 +0200 Subject: [PATCH 057/356] arm64: dts: qcom: sdm845: Configure MSM platform type for IPA SDM845 platform type is MSM where there is IPA H/W with Modem. This require special configuration at IPA driver. Signed-off-by: Pavel Dubrova --- arch/arm64/boot/dts/qcom/sdm845.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index 0d9c9f66b3ac..7e277031de2a 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -2814,6 +2814,7 @@ interrupt-names = "ipa-irq", "gsi-irq"; qcom,ipa-hw-ver = <13>; /* IPA core version = IPAv3.5.1 */ 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; From 25250d5f9289d955ad1542274a7d0b19073c4f20 Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Sun, 19 Dec 2021 15:15:19 +0200 Subject: [PATCH 058/356] arm64: dts: qcom: sdm845-sde: Remove unnecessary #address-cells/#size-cells Remove the unnecessary #address-cells/#size-cells because the node do not have child nodes with a register block and to avoid warnings like this: msmdrm_smmu ae00000.qcom,mdss_mdp:qcom,smmu_sde_unsec_cb: Invalid #address-cells 1 or #size-cells 0 msmdrm_smmu ae00000.qcom,mdss_mdp:qcom,smmu_sde_sec_cb: Invalid #address-cells 1 or #size-cells 0 Signed-off-by: Pavel Dubrova --- arch/arm64/boot/dts/qcom/sdm845-sde.dtsi | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi index 600d43fa07bf..1c3c090dc098 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi @@ -35,9 +35,6 @@ interrupt-controller; #interrupt-cells = <1>; - #address-cells = <1>; - #size-cells = <0>; - #power-domain-cells = <0>; /* hw blocks */ From 2a51c3909bbeed6d56a7b0c58d0ca0c16dda18f1 Mon Sep 17 00:00:00 2001 From: "Angelo G. Del Regno" Date: Thu, 18 Jul 2019 11:32:36 +0200 Subject: [PATCH 059/356] arm64: DT: SDM845-gpu: Rectify CX_DBGC block resource name The CX_DBGC block has changed name in kernel 4.14. --- arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi b/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi index bafad11adbae..249e60f2ccc0 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi @@ -46,7 +46,7 @@ status = "ok"; reg = <0x5000000 0x40000>, <0x5061000 0x800>, <0x509e000 0x1000>; - reg-names = "kgsl_3d0_reg_memory", "kgsl_3d0_cx_dbgc_memory", + reg-names = "kgsl_3d0_reg_memory", "cx_dbgc", "cx_misc"; interrupts = ; interrupt-names = "kgsl_3d0_irq"; From aaf47f1dd69c8259acc4a03a126645361bf39569 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Sun, 10 May 2020 21:12:58 +0200 Subject: [PATCH 060/356] arm64: DT: SDM845: Fix VDD-CX-MX supply for ICNSS This power supply has changed its name to "vdd-cx-mx" in kernel 4.14: update the DT property in order to actually set the right voltage and turn it on/off when needded, so that we can save power. --- arch/arm64/boot/dts/qcom/sdm845.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index 7e277031de2a..0a35aa89fe0f 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -3166,11 +3166,11 @@ qcom,iommu-faults = "stall-disable", "non-fatal"; qcom,wlan-msa-memory = <0x100000>; - vdd-0.8-cx-mx-supply = <&pm8998_l5>; + vdd-cx-mx-supply = <&pm8998_l5>; vdd-1.8-xo-supply = <&pm8998_l7>; vdd-1.3-rfa-supply = <&pm8998_l17>; vdd-3.3-ch0-supply = <&pm8998_l25>; - qcom,vdd-0.8-cx-mx-config = <800000 800000>; + qcom,vdd-cx-mx-config = <800000 800000>; qcom,vdd-3.3-ch0-config = <3104000 3312000>; qcom,smp2p_map_wlan_1_in { From 5273b1688cf176aadf337c2d32bfe550b1f20211 Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Wed, 22 Dec 2021 04:29:40 +0200 Subject: [PATCH 061/356] arm64: dts: qcom: sdm845: Update iommu configuration for ICNSS Update iommu properties for icnss wlan platform device. Signed-off-by: Pavel Dubrova --- arch/arm64/boot/dts/qcom/sdm845.dtsi | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index 0a35aa89fe0f..35916bf3d17d 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -3146,9 +3146,8 @@ qcom,icnss@18800000 { compatible = "qcom,icnss"; reg = <0x18800000 0x800000>, - <0xa0000000 0x10000000>, <0xb0000000 0x10000>; - reg-names = "membase", "smmu_iova_base", "smmu_iova_ipa"; + reg-names = "membase", "smmu_iova_ipa"; iommus = <&apps_smmu 0x0040 0x1>; interrupts = , , @@ -3162,8 +3161,10 @@ , , ; + qcom,iommu-dma-addr-pool = <0xa0000000 0x10000000>; qcom,iommu-dma = "fastmap"; qcom,iommu-faults = "stall-disable", "non-fatal"; + qcom,hyp_enabled; qcom,wlan-msa-memory = <0x100000>; vdd-cx-mx-supply = <&pm8998_l5>; @@ -3175,7 +3176,7 @@ qcom,smp2p_map_wlan_1_in { interrupts-extended = <&smp2p_wlan_1_in 0 IRQ_TYPE_LEVEL_HIGH>, - <&smp2p_wlan_1_in 1 0>; + <&smp2p_wlan_1_in 1 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "qcom,smp2p-force-fatal-error", "qcom,smp2p-early-crash-ind"; }; From f91b345e5ad654951b0166a5acf885dabf8f59fd Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Fri, 24 Dec 2021 05:42:20 +0200 Subject: [PATCH 062/356] arm64: dts: qcom: sdm845: Add throughput threshold property for IPA Add qcom,throughput-threshold property that represents an array of throughput threshold bandwidth for SVS, NOMINAL and TURBO clocks. Signed-off-by: Pavel Dubrova --- arch/arm64/boot/dts/qcom/sdm845.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index 35916bf3d17d..24fbeacdd685 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -2854,6 +2854,7 @@ <143 777 0 355>; /* IB defined for IPA clk in MHz*/ qcom,bus-vector-names = "MIN", "SVS2", "SVS", "NOMINAL", "TURBO"; + qcom,throughput-threshold = <310 600 1000>; /* smp2p information */ qcom,smp2p_map_ipa_1_out { From 7e3b3dcb1c9354e2cad86a70501008f619f0ed6c Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Sat, 19 Oct 2019 17:22:43 +0200 Subject: [PATCH 063/356] arm64: DT: sdm845-audio-overlay: Migrate to the new k4.14 audio-ref-clk The new audio-ref-clk clock driver selects the clock number as a property in the DT declaration for it, then forces us to select clock cell zero when we call it by phandle. That just reached the limit of monkeyness. --- arch/arm64/boot/dts/qcom/sdm845-audio-overlay.dtsi | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm845-audio-overlay.dtsi index dc6a177b5c2b..79a235f2bc82 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-audio-overlay.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-audio-overlay.dtsi @@ -84,6 +84,7 @@ clock_audio_lnbb: audio_ext_clk_lnbb { status = "ok"; compatible = "qcom,audio-ref-clk"; + qcom,codec-ext-clk-src = <1>; clock-names = "osr_clk"; clocks = <&clock_rpmh RPMH_LN_BB_CLK2>; qcom,node_has_rpm_clock; @@ -124,7 +125,7 @@ qcom,wcd-rst-gpio-node = <&wcd_rst_gpio>; clock-names = "wcd_clk"; - clocks = <&clock_audio_lnbb AUDIO_PMIC_LNBB_CLK>; + clocks = <&clock_audio_lnbb 0>; cdc-vdd-buck-supply = <&pm8998_s4>; qcom,cdc-vdd-buck-voltage = <1800000 1800000>; From f74ccf2363343be4e65e80eec21b6e533d6d3313 Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Fri, 24 Dec 2021 04:36:43 +0200 Subject: [PATCH 064/356] arm64: dts: qcom: sdm845-audio: Correct dev-id for hdmi cpu-dai Correct dev-id for hdmi cpu-dai to align with recent audio driver. Signed-off-by: Pavel Dubrova --- arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi | 2 +- arch/arm64/boot/dts/qcom/sdm845-audio.dtsi | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi b/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi index 038e32a5c3c9..5bd5dda5dba6 100644 --- a/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi +++ b/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi @@ -70,7 +70,7 @@ dai_dp: qcom,msm-dai-q6-dp { compatible = "qcom,msm-dai-q6-hdmi"; - qcom,msm-dai-q6-dev-id = <24608>; + qcom,msm-dai-q6-dev-id = <0>; }; loopback: qcom,msm-pcm-loopback { diff --git a/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi b/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi index b3d048976167..d2bf77e875c4 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi @@ -62,7 +62,7 @@ <&dai_quat_tdm_rx_0>, <&dai_quat_tdm_tx_0>, <&dai_quat_tdm_rx_1>, <&proxy_rx>, <&proxy_tx>; - asoc-cpu-names = "msm-dai-q6-hdmi.8", "msm-dai-q6-dp.24608", + asoc-cpu-names = "msm-dai-q6-hdmi.8", "msm-dai-q6-dp.0", "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", From 9f17cc6e1584b5c4c1225a3ecaf67798184972d7 Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Fri, 24 Dec 2021 04:50:12 +0200 Subject: [PATCH 065/356] arm64: dts: qcom: sdm845-audio: Set msm-audio-ion as child node of apr During bootup, ION probe may get called before adsp up notification arrives. And it would fail to register ION SMMU which would cause playback or record has no sound. Move msm-audio-ion as child node of apr to make sure ION probe is called after adsp up notification arrives. Signed-off-by: Pavel Dubrova --- arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi b/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi index 5bd5dda5dba6..0c3421f67f00 100644 --- a/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi +++ b/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi @@ -306,6 +306,14 @@ 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 0x1821 0x0>; + qcom,iommu-dma-addr-pool = <0x10000000 0x10000000>; + }; }; dai_pri_auxpcm: qcom,msm-pri-auxpcm { @@ -383,14 +391,6 @@ qcom,dba-bridge-chip = "adv7533"; }; - msm_audio_ion: qcom,msm-audio-ion { - compatible = "qcom,msm-audio-ion"; - qcom,smmu-version = <2>; - qcom,smmu-enabled; - iommus = <&apps_smmu 0x1821 0x0>; - qcom,iommu-dma-addr-pool = <0x10000000 0x10000000>; - }; - qcom,msm-adsp-loader { status = "ok"; compatible = "qcom,adsp-loader"; From 88a0f116f34e7645200b87b842881f354aa80dfb Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Fri, 24 Dec 2021 05:02:23 +0200 Subject: [PATCH 066/356] arm64: dts: qcom: sdm845-audio: enable q6core platform device Switch q6core to platform to register for snd notification. Move tavil-snd-card as child node of q6core device. Signed-off-by: Pavel Dubrova --- arch/arm64/boot/dts/qcom/sdm845-audio.dtsi | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi b/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi index d2bf77e875c4..08bb65b99dee 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi @@ -22,6 +22,12 @@ }; &audio_apr { + q6core: qcom,q6core-audio { + compatible = "qcom,q6core-audio"; + }; +}; + +&q6core { snd_934x: sound-tavil { compatible = "qcom,sdm845-asoc-snd-tavil"; qcom,model = "sdm845-tavil-snd-card"; From c77213f5c0e0a0682291000ba3fae2dc9e960aa0 Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Fri, 14 Jan 2022 04:03:25 +0200 Subject: [PATCH 067/356] arm64: dts: qcom: sdm845: Update qmi-cooling-devices compatible Update compatible string for QTI QMI cooling devices. Signed-off-by: Pavel Dubrova --- arch/arm64/boot/dts/qcom/sdm845.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index 24fbeacdd685..a22d21c0c4d0 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -3184,7 +3184,7 @@ }; qmi-tmd-devices { - compatible = "qcom,qmi_cooling_devices"; + compatible = "qcom,qmi-cooling-devices"; modem { qcom,instance-id = <0x0>; From 92bc2bf2a0c1ece1aefd9bf130a605cb81a60819 Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Wed, 26 Jan 2022 21:43:12 +0200 Subject: [PATCH 068/356] arm64: dts: qcom: sdm845: Fix mailbox channel for CDSP GLINK CDSP mailbox channel was accidentally set to the wrong value during porting. Also fix duplication in the qcom,notify-edges property for GLINK Modem subnode. Signed-off-by: Pavel Dubrova --- arch/arm64/boot/dts/qcom/sdm845.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index a22d21c0c4d0..b53cceed6e5a 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -2343,7 +2343,7 @@ qcom,modem_glink_ssr { qcom,glink-channels = "glink_ssr"; qcom,notify-edges = <&glink_adsp>, - <&glink_cdsp>, + <&glink_slpi>, <&glink_cdsp>, <&glink_spss>; }; @@ -2421,7 +2421,7 @@ glink_cdsp: cdsp { qcom,remote-pid = <5>; transport = "smem"; - mboxes = <&apss_shared 28>; + mboxes = <&apss_shared 4>; mbox-names = "cdsp_smem"; interrupts = ; From cd43161efaf15a3292b1c3748d6813b7eb9e0c8c Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Mon, 7 Feb 2022 03:31:35 +0200 Subject: [PATCH 069/356] arm64: dts: qcom: sdm845: Fix mailbox channel for SLPI GLINK SLPI mailbox channel was accidentally set to the wrong value during porting. Signed-off-by: Pavel Dubrova --- arch/arm64/boot/dts/qcom/sdm845.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index b53cceed6e5a..4cdba9e76eed 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -2389,7 +2389,7 @@ glink_slpi: dsps { qcom,remote-pid = <3>; transport = "smem"; - mboxes = <&apss_shared 26>; + mboxes = <&apss_shared 24>; mbox-names = "dsps_smem"; interrupts = ; From a857e6845fab8266970c4bfdd8df5916b43c9884 Mon Sep 17 00:00:00 2001 From: MrArtemSid Date: Fri, 11 Feb 2022 07:44:38 +0200 Subject: [PATCH 070/356] ARM64: dts: qcom: sdm845-audio-overlay: add qcom,wdsp-channels --- arch/arm64/boot/dts/qcom/sdm845-audio-overlay.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm845-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm845-audio-overlay.dtsi index 79a235f2bc82..96b1e05600ab 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-audio-overlay.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-audio-overlay.dtsi @@ -101,6 +101,10 @@ qocm,wcd-dsp-glink { compatible = "qcom,wcd-dsp-glink"; + qcom,wdsp-channels = "g_glink_ctrl", + "g_glink_persistent_data_nild", + "g_glink_persistent_data_ild", + "g_glink_audio_data"; }; qcom,wcd-dsp-mgr { From fc20f3bd9027e8821851723431f3e49bd076304f Mon Sep 17 00:00:00 2001 From: MrArtemSid Date: Sat, 9 Oct 2021 13:47:44 +0400 Subject: [PATCH 071/356] arm64: dts: qcom: sdm845-wcd: Add #gpio-cells to tavil_hph_en to fix DTC warnings --- arch/arm64/boot/dts/qcom/sdm845-wcd.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm845-wcd.dtsi b/arch/arm64/boot/dts/qcom/sdm845-wcd.dtsi index 64931fd9a60a..d42493becd02 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-wcd.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-wcd.dtsi @@ -144,6 +144,7 @@ }; tavil_hph_en0: msm_cdc_pinctrl_hph_en0 { + #gpio-cells = <0>; compatible = "qcom,msm-cdc-pinctrl"; pinctrl-names = "aud_active", "aud_sleep"; pinctrl-0 = <&hph_en0_wcd_active>; @@ -151,6 +152,7 @@ }; tavil_hph_en1: msm_cdc_pinctrl_hph_en1 { + #gpio-cells = <0>; compatible = "qcom,msm-cdc-pinctrl"; pinctrl-names = "aud_active", "aud_sleep"; pinctrl-0 = <&hph_en1_wcd_active>; From f2483841a046e935f2734a1b240094055c9925a3 Mon Sep 17 00:00:00 2001 From: MrArtemSid Date: Tue, 15 Feb 2022 10:32:42 +0400 Subject: [PATCH 072/356] ARM64: dts: qcom: sdm845: add regs to lmh_dcvs --- arch/arm64/boot/dts/qcom/sdm845.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index 4cdba9e76eed..340e498f126b 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -4127,6 +4127,8 @@ lmh_dcvs0: qcom,limits-dcvs@0 { compatible = "qcom,msm-hw-limits"; interrupts = ; + reg = <0x17d78800 0x1000>, + <0x17d43000 0x1000>; qcom,affinity = <0>; #thermal-sensor-cells = <0>; }; @@ -4135,6 +4137,8 @@ compatible = "qcom,msm-hw-limits"; interrupts = ; qcom,affinity = <1>; + reg = <0x17d70800 0x1000>, + <0x17d45800 0x1000>; #thermal-sensor-cells = <0>; isens_vref-supply = <&pm8998_l1_ao>; isens-vref-settings = <880000 880000 20000>; From f6ab76667191a8b63e22bf365a354601c9af3a55 Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Tue, 20 Sep 2022 05:16:10 +0300 Subject: [PATCH 073/356] arm64: dts: qcom: sdm845-vidc: Remove governor Devfreq governors have been replaced with internal handling. New entry qcom,mode decides how the BW is calculated. Fix qcom,iommu-vmid for secure bitstream cb. Signed-off-by: Pavel Dubrova --- arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi b/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi index 9d6885b3b4f9..0b05270f85a9 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi @@ -46,7 +46,7 @@ label = "cnoc"; qcom,bus-master = ; qcom,bus-slave = ; - qcom,bus-governor = "performance"; + qcom,mode = "performance"; qcom,bus-range-kbps = <1000 1000>; }; @@ -55,7 +55,7 @@ label = "venus-ddr"; qcom,bus-master = ; qcom,bus-slave = ; - qcom,bus-governor = "msm-vidc-ddr"; + qcom,mode = "venus-ddr"; qcom,bus-range-kbps = <1000 3388000>; }; arm9_bus_ddr { @@ -63,7 +63,7 @@ label = "venus-arm9-ddr"; qcom,bus-master = ; qcom,bus-slave = ; - qcom,bus-governor = "performance"; + qcom,mode = "performance"; qcom,bus-range-kbps = <1000 1000>; }; venus_bus_llcc { @@ -71,7 +71,7 @@ label = "venus-llcc"; qcom,bus-master = ; qcom,bus-slave = ; - qcom,bus-governor = "msm-vidc-llcc"; + qcom,mode = "venus-llcc"; qcom,bus-range-kbps = <17000 3388000>; }; @@ -98,7 +98,7 @@ qcom,iommu-dma-addr-pool = <0x4b000000 0x25800000>; qcom,iommu-faults = "non-fatal"; qcom,iommu-pagetable = "LLC"; - qcom,iommu-vmid = <0xB>; /* VMID_CP_BITSTREAM */ + qcom,iommu-vmid = <0x9>; /* VMID_CP_BITSTREAM */ buffer-types = <0x241>; virtual-addr-pool = <0x4b000000 0x25800000>; qcom,secure-context-bank; From f2c950aa77d9e27dcf154a147fb21c04fa3c6f4b Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Sat, 11 Jul 2020 20:44:00 +0200 Subject: [PATCH 074/356] pinctrl: qcom: Import SDM845 pinctrl driver from Open Devices 4.14 Import the pinctrl driver for the SDM845 SoC from the Open Devices kernel 4.14 as of the latest HEAD. --- drivers/pinctrl/qcom/Makefile | 2 +- drivers/pinctrl/qcom/pinctrl-sdm845-v2.c | 1821 ++++++++++++++++++++++ drivers/pinctrl/qcom/pinctrl-sdm845.c | 1252 ++++++++++----- 3 files changed, 2681 insertions(+), 394 deletions(-) create mode 100644 drivers/pinctrl/qcom/pinctrl-sdm845-v2.c diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile index d5ea857844ba..a5e137c7753e 100644 --- a/drivers/pinctrl/qcom/Makefile +++ b/drivers/pinctrl/qcom/Makefile @@ -21,7 +21,7 @@ obj-$(CONFIG_PINCTRL_QCOM_SPMI_PMIC) += pinctrl-spmi-gpio.o obj-$(CONFIG_PINCTRL_QCOM_SPMI_PMIC) += pinctrl-spmi-mpp.o obj-$(CONFIG_PINCTRL_QCOM_SSBI_PMIC) += pinctrl-ssbi-gpio.o obj-$(CONFIG_PINCTRL_QCOM_SSBI_PMIC) += pinctrl-ssbi-mpp.o -obj-$(CONFIG_PINCTRL_SDM845) += pinctrl-sdm845.o +obj-$(CONFIG_PINCTRL_SDM845) += pinctrl-sdm845.o pinctrl-sdm845-v2.o obj-$(CONFIG_PINCTRL_KONA) += pinctrl-kona.o obj-$(CONFIG_PINCTRL_LITO) += pinctrl-lito.o obj-$(CONFIG_PINCTRL_BENGAL) += pinctrl-bengal.o diff --git a/drivers/pinctrl/qcom/pinctrl-sdm845-v2.c b/drivers/pinctrl/qcom/pinctrl-sdm845-v2.c new file mode 100644 index 000000000000..bc8ec394d620 --- /dev/null +++ b/drivers/pinctrl/qcom/pinctrl-sdm845-v2.c @@ -0,0 +1,1821 @@ +/* + * 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. + */ + +#include +#include +#include +#include + +#include "pinctrl-msm.h" + +#define FUNCTION(fname) \ + [msm_mux_##fname] = { \ + .name = #fname, \ + .groups = fname##_groups, \ + .ngroups = ARRAY_SIZE(fname##_groups), \ + } + +#define NORTH 0x00500000 +#define SOUTH 0x00900000 +#define EAST 0x00100000 +#define REG_SIZE 0x1000 +#define PINGROUP(id, base, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10) \ + { \ + .name = "gpio" #id, \ + .pins = gpio##id##_pins, \ + .npins = (unsigned int)ARRAY_SIZE(gpio##id##_pins), \ + .funcs = (int[]){ \ + msm_mux_gpio, /* gpio mode */ \ + msm_mux_##f1, \ + msm_mux_##f2, \ + msm_mux_##f3, \ + msm_mux_##f4, \ + msm_mux_##f5, \ + msm_mux_##f6, \ + msm_mux_##f7, \ + msm_mux_##f8, \ + msm_mux_##f9, \ + msm_mux_##f10 \ + }, \ + .nfuncs = 11, \ + .ctl_reg = base + REG_SIZE * id, \ + .io_reg = base + 0x4 + REG_SIZE * id, \ + .intr_cfg_reg = base + 0x8 + REG_SIZE * id, \ + .intr_status_reg = base + 0xc + REG_SIZE * id, \ + .intr_target_reg = base + 0x8 + REG_SIZE * id, \ + .dir_conn_reg = (base == NORTH) ? base + 0xa4000 : \ + ((base == SOUTH) ? base + 0xa8000 : base + 0x9e000), \ + .mux_bit = 2, \ + .pull_bit = 0, \ + .drv_bit = 6, \ + .oe_bit = 9, \ + .in_bit = 0, \ + .out_bit = 1, \ + .intr_enable_bit = 0, \ + .intr_status_bit = 0, \ + .intr_target_bit = 5, \ + .intr_target_kpss_val = 3, \ + .intr_raw_status_bit = 4, \ + .intr_polarity_bit = 1, \ + .intr_detection_bit = 2, \ + .intr_detection_width = 2, \ + .dir_conn_en_bit = 8, \ + } + +#define SDC_QDSD_PINGROUP(pg_name, ctl, pull, drv) \ + { \ + .name = #pg_name, \ + .pins = pg_name##_pins, \ + .npins = (unsigned int)ARRAY_SIZE(pg_name##_pins), \ + .ctl_reg = ctl, \ + .io_reg = 0, \ + .intr_cfg_reg = 0, \ + .intr_status_reg = 0, \ + .intr_target_reg = 0, \ + .mux_bit = -1, \ + .pull_bit = pull, \ + .drv_bit = drv, \ + .oe_bit = -1, \ + .in_bit = -1, \ + .out_bit = -1, \ + .intr_enable_bit = -1, \ + .intr_status_bit = -1, \ + .intr_target_bit = -1, \ + .intr_raw_status_bit = -1, \ + .intr_polarity_bit = -1, \ + .intr_detection_bit = -1, \ + .intr_detection_width = -1, \ + } + +#define UFS_RESET(pg_name, offset) \ + { \ + .name = #pg_name, \ + .pins = pg_name##_pins, \ + .npins = (unsigned int)ARRAY_SIZE(pg_name##_pins), \ + .ctl_reg = offset, \ + .io_reg = offset + 0x4, \ + .intr_cfg_reg = 0, \ + .intr_status_reg = 0, \ + .intr_target_reg = 0, \ + .mux_bit = -1, \ + .pull_bit = 3, \ + .drv_bit = 0, \ + .oe_bit = -1, \ + .in_bit = -1, \ + .out_bit = 0, \ + .intr_enable_bit = -1, \ + .intr_status_bit = -1, \ + .intr_target_bit = -1, \ + .intr_raw_status_bit = -1, \ + .intr_polarity_bit = -1, \ + .intr_detection_bit = -1, \ + .intr_detection_width = -1, \ + } +static const struct pinctrl_pin_desc sdm845_pins[] = { + PINCTRL_PIN(0, "GPIO_0"), + PINCTRL_PIN(1, "GPIO_1"), + PINCTRL_PIN(2, "GPIO_2"), + PINCTRL_PIN(3, "GPIO_3"), + PINCTRL_PIN(4, "GPIO_4"), + PINCTRL_PIN(5, "GPIO_5"), + PINCTRL_PIN(6, "GPIO_6"), + PINCTRL_PIN(7, "GPIO_7"), + PINCTRL_PIN(8, "GPIO_8"), + PINCTRL_PIN(9, "GPIO_9"), + PINCTRL_PIN(10, "GPIO_10"), + PINCTRL_PIN(11, "GPIO_11"), + PINCTRL_PIN(12, "GPIO_12"), + PINCTRL_PIN(13, "GPIO_13"), + PINCTRL_PIN(14, "GPIO_14"), + PINCTRL_PIN(15, "GPIO_15"), + PINCTRL_PIN(16, "GPIO_16"), + PINCTRL_PIN(17, "GPIO_17"), + PINCTRL_PIN(18, "GPIO_18"), + PINCTRL_PIN(19, "GPIO_19"), + PINCTRL_PIN(20, "GPIO_20"), + PINCTRL_PIN(21, "GPIO_21"), + PINCTRL_PIN(22, "GPIO_22"), + PINCTRL_PIN(23, "GPIO_23"), + PINCTRL_PIN(24, "GPIO_24"), + PINCTRL_PIN(25, "GPIO_25"), + PINCTRL_PIN(26, "GPIO_26"), + PINCTRL_PIN(27, "GPIO_27"), + PINCTRL_PIN(28, "GPIO_28"), + PINCTRL_PIN(29, "GPIO_29"), + PINCTRL_PIN(30, "GPIO_30"), + PINCTRL_PIN(31, "GPIO_31"), + PINCTRL_PIN(32, "GPIO_32"), + PINCTRL_PIN(33, "GPIO_33"), + PINCTRL_PIN(34, "GPIO_34"), + PINCTRL_PIN(35, "GPIO_35"), + PINCTRL_PIN(36, "GPIO_36"), + PINCTRL_PIN(37, "GPIO_37"), + PINCTRL_PIN(38, "GPIO_38"), + PINCTRL_PIN(39, "GPIO_39"), + PINCTRL_PIN(40, "GPIO_40"), + PINCTRL_PIN(41, "GPIO_41"), + PINCTRL_PIN(42, "GPIO_42"), + PINCTRL_PIN(43, "GPIO_43"), + PINCTRL_PIN(44, "GPIO_44"), + PINCTRL_PIN(45, "GPIO_45"), + PINCTRL_PIN(46, "GPIO_46"), + PINCTRL_PIN(47, "GPIO_47"), + PINCTRL_PIN(48, "GPIO_48"), + PINCTRL_PIN(49, "GPIO_49"), + PINCTRL_PIN(50, "GPIO_50"), + PINCTRL_PIN(51, "GPIO_51"), + PINCTRL_PIN(52, "GPIO_52"), + PINCTRL_PIN(53, "GPIO_53"), + PINCTRL_PIN(54, "GPIO_54"), + PINCTRL_PIN(55, "GPIO_55"), + PINCTRL_PIN(56, "GPIO_56"), + PINCTRL_PIN(57, "GPIO_57"), + PINCTRL_PIN(58, "GPIO_58"), + PINCTRL_PIN(59, "GPIO_59"), + PINCTRL_PIN(60, "GPIO_60"), + PINCTRL_PIN(61, "GPIO_61"), + PINCTRL_PIN(62, "GPIO_62"), + PINCTRL_PIN(63, "GPIO_63"), + PINCTRL_PIN(64, "GPIO_64"), + PINCTRL_PIN(65, "GPIO_65"), + PINCTRL_PIN(66, "GPIO_66"), + PINCTRL_PIN(67, "GPIO_67"), + PINCTRL_PIN(68, "GPIO_68"), + PINCTRL_PIN(69, "GPIO_69"), + PINCTRL_PIN(70, "GPIO_70"), + PINCTRL_PIN(71, "GPIO_71"), + PINCTRL_PIN(72, "GPIO_72"), + PINCTRL_PIN(73, "GPIO_73"), + PINCTRL_PIN(74, "GPIO_74"), + PINCTRL_PIN(75, "GPIO_75"), + PINCTRL_PIN(76, "GPIO_76"), + PINCTRL_PIN(77, "GPIO_77"), + PINCTRL_PIN(78, "GPIO_78"), + PINCTRL_PIN(79, "GPIO_79"), + PINCTRL_PIN(80, "GPIO_80"), + PINCTRL_PIN(81, "GPIO_81"), + PINCTRL_PIN(82, "GPIO_82"), + PINCTRL_PIN(83, "GPIO_83"), + PINCTRL_PIN(84, "GPIO_84"), + PINCTRL_PIN(85, "GPIO_85"), + PINCTRL_PIN(86, "GPIO_86"), + PINCTRL_PIN(87, "GPIO_87"), + PINCTRL_PIN(88, "GPIO_88"), + PINCTRL_PIN(89, "GPIO_89"), + PINCTRL_PIN(90, "GPIO_90"), + PINCTRL_PIN(91, "GPIO_91"), + PINCTRL_PIN(92, "GPIO_92"), + PINCTRL_PIN(93, "GPIO_93"), + PINCTRL_PIN(94, "GPIO_94"), + PINCTRL_PIN(95, "GPIO_95"), + PINCTRL_PIN(96, "GPIO_96"), + PINCTRL_PIN(97, "GPIO_97"), + PINCTRL_PIN(98, "GPIO_98"), + PINCTRL_PIN(99, "GPIO_99"), + PINCTRL_PIN(100, "GPIO_100"), + PINCTRL_PIN(101, "GPIO_101"), + PINCTRL_PIN(102, "GPIO_102"), + PINCTRL_PIN(103, "GPIO_103"), + PINCTRL_PIN(104, "GPIO_104"), + PINCTRL_PIN(105, "GPIO_105"), + PINCTRL_PIN(106, "GPIO_106"), + PINCTRL_PIN(107, "GPIO_107"), + PINCTRL_PIN(108, "GPIO_108"), + PINCTRL_PIN(109, "GPIO_109"), + PINCTRL_PIN(110, "GPIO_110"), + PINCTRL_PIN(111, "GPIO_111"), + PINCTRL_PIN(112, "GPIO_112"), + PINCTRL_PIN(113, "GPIO_113"), + PINCTRL_PIN(114, "GPIO_114"), + PINCTRL_PIN(115, "GPIO_115"), + PINCTRL_PIN(116, "GPIO_116"), + PINCTRL_PIN(117, "GPIO_117"), + PINCTRL_PIN(118, "GPIO_118"), + PINCTRL_PIN(119, "GPIO_119"), + PINCTRL_PIN(120, "GPIO_120"), + PINCTRL_PIN(121, "GPIO_121"), + PINCTRL_PIN(122, "GPIO_122"), + PINCTRL_PIN(123, "GPIO_123"), + PINCTRL_PIN(124, "GPIO_124"), + PINCTRL_PIN(125, "GPIO_125"), + PINCTRL_PIN(126, "GPIO_126"), + PINCTRL_PIN(127, "GPIO_127"), + PINCTRL_PIN(128, "GPIO_128"), + PINCTRL_PIN(129, "GPIO_129"), + PINCTRL_PIN(130, "GPIO_130"), + PINCTRL_PIN(131, "GPIO_131"), + PINCTRL_PIN(132, "GPIO_132"), + PINCTRL_PIN(133, "GPIO_133"), + PINCTRL_PIN(134, "GPIO_134"), + PINCTRL_PIN(135, "GPIO_135"), + PINCTRL_PIN(136, "GPIO_136"), + PINCTRL_PIN(137, "GPIO_137"), + PINCTRL_PIN(138, "GPIO_138"), + PINCTRL_PIN(139, "GPIO_139"), + PINCTRL_PIN(140, "GPIO_140"), + PINCTRL_PIN(141, "GPIO_141"), + PINCTRL_PIN(142, "GPIO_142"), + PINCTRL_PIN(143, "GPIO_143"), + PINCTRL_PIN(144, "GPIO_144"), + PINCTRL_PIN(145, "GPIO_145"), + PINCTRL_PIN(146, "GPIO_146"), + PINCTRL_PIN(147, "GPIO_147"), + PINCTRL_PIN(148, "GPIO_148"), + PINCTRL_PIN(149, "GPIO_149"), + PINCTRL_PIN(150, "SDC2_CLK"), + PINCTRL_PIN(151, "SDC2_CMD"), + PINCTRL_PIN(152, "SDC2_DATA"), + PINCTRL_PIN(153, "UFS_RESET"), +}; + +#define DECLARE_MSM_GPIO_PINS(pin) \ + static const unsigned int gpio##pin##_pins[] = { pin } +DECLARE_MSM_GPIO_PINS(0); +DECLARE_MSM_GPIO_PINS(1); +DECLARE_MSM_GPIO_PINS(2); +DECLARE_MSM_GPIO_PINS(3); +DECLARE_MSM_GPIO_PINS(4); +DECLARE_MSM_GPIO_PINS(5); +DECLARE_MSM_GPIO_PINS(6); +DECLARE_MSM_GPIO_PINS(7); +DECLARE_MSM_GPIO_PINS(8); +DECLARE_MSM_GPIO_PINS(9); +DECLARE_MSM_GPIO_PINS(10); +DECLARE_MSM_GPIO_PINS(11); +DECLARE_MSM_GPIO_PINS(12); +DECLARE_MSM_GPIO_PINS(13); +DECLARE_MSM_GPIO_PINS(14); +DECLARE_MSM_GPIO_PINS(15); +DECLARE_MSM_GPIO_PINS(16); +DECLARE_MSM_GPIO_PINS(17); +DECLARE_MSM_GPIO_PINS(18); +DECLARE_MSM_GPIO_PINS(19); +DECLARE_MSM_GPIO_PINS(20); +DECLARE_MSM_GPIO_PINS(21); +DECLARE_MSM_GPIO_PINS(22); +DECLARE_MSM_GPIO_PINS(23); +DECLARE_MSM_GPIO_PINS(24); +DECLARE_MSM_GPIO_PINS(25); +DECLARE_MSM_GPIO_PINS(26); +DECLARE_MSM_GPIO_PINS(27); +DECLARE_MSM_GPIO_PINS(28); +DECLARE_MSM_GPIO_PINS(29); +DECLARE_MSM_GPIO_PINS(30); +DECLARE_MSM_GPIO_PINS(31); +DECLARE_MSM_GPIO_PINS(32); +DECLARE_MSM_GPIO_PINS(33); +DECLARE_MSM_GPIO_PINS(34); +DECLARE_MSM_GPIO_PINS(35); +DECLARE_MSM_GPIO_PINS(36); +DECLARE_MSM_GPIO_PINS(37); +DECLARE_MSM_GPIO_PINS(38); +DECLARE_MSM_GPIO_PINS(39); +DECLARE_MSM_GPIO_PINS(40); +DECLARE_MSM_GPIO_PINS(41); +DECLARE_MSM_GPIO_PINS(42); +DECLARE_MSM_GPIO_PINS(43); +DECLARE_MSM_GPIO_PINS(44); +DECLARE_MSM_GPIO_PINS(45); +DECLARE_MSM_GPIO_PINS(46); +DECLARE_MSM_GPIO_PINS(47); +DECLARE_MSM_GPIO_PINS(48); +DECLARE_MSM_GPIO_PINS(49); +DECLARE_MSM_GPIO_PINS(50); +DECLARE_MSM_GPIO_PINS(51); +DECLARE_MSM_GPIO_PINS(52); +DECLARE_MSM_GPIO_PINS(53); +DECLARE_MSM_GPIO_PINS(54); +DECLARE_MSM_GPIO_PINS(55); +DECLARE_MSM_GPIO_PINS(56); +DECLARE_MSM_GPIO_PINS(57); +DECLARE_MSM_GPIO_PINS(58); +DECLARE_MSM_GPIO_PINS(59); +DECLARE_MSM_GPIO_PINS(60); +DECLARE_MSM_GPIO_PINS(61); +DECLARE_MSM_GPIO_PINS(62); +DECLARE_MSM_GPIO_PINS(63); +DECLARE_MSM_GPIO_PINS(64); +DECLARE_MSM_GPIO_PINS(65); +DECLARE_MSM_GPIO_PINS(66); +DECLARE_MSM_GPIO_PINS(67); +DECLARE_MSM_GPIO_PINS(68); +DECLARE_MSM_GPIO_PINS(69); +DECLARE_MSM_GPIO_PINS(70); +DECLARE_MSM_GPIO_PINS(71); +DECLARE_MSM_GPIO_PINS(72); +DECLARE_MSM_GPIO_PINS(73); +DECLARE_MSM_GPIO_PINS(74); +DECLARE_MSM_GPIO_PINS(75); +DECLARE_MSM_GPIO_PINS(76); +DECLARE_MSM_GPIO_PINS(77); +DECLARE_MSM_GPIO_PINS(78); +DECLARE_MSM_GPIO_PINS(79); +DECLARE_MSM_GPIO_PINS(80); +DECLARE_MSM_GPIO_PINS(81); +DECLARE_MSM_GPIO_PINS(82); +DECLARE_MSM_GPIO_PINS(83); +DECLARE_MSM_GPIO_PINS(84); +DECLARE_MSM_GPIO_PINS(85); +DECLARE_MSM_GPIO_PINS(86); +DECLARE_MSM_GPIO_PINS(87); +DECLARE_MSM_GPIO_PINS(88); +DECLARE_MSM_GPIO_PINS(89); +DECLARE_MSM_GPIO_PINS(90); +DECLARE_MSM_GPIO_PINS(91); +DECLARE_MSM_GPIO_PINS(92); +DECLARE_MSM_GPIO_PINS(93); +DECLARE_MSM_GPIO_PINS(94); +DECLARE_MSM_GPIO_PINS(95); +DECLARE_MSM_GPIO_PINS(96); +DECLARE_MSM_GPIO_PINS(97); +DECLARE_MSM_GPIO_PINS(98); +DECLARE_MSM_GPIO_PINS(99); +DECLARE_MSM_GPIO_PINS(100); +DECLARE_MSM_GPIO_PINS(101); +DECLARE_MSM_GPIO_PINS(102); +DECLARE_MSM_GPIO_PINS(103); +DECLARE_MSM_GPIO_PINS(104); +DECLARE_MSM_GPIO_PINS(105); +DECLARE_MSM_GPIO_PINS(106); +DECLARE_MSM_GPIO_PINS(107); +DECLARE_MSM_GPIO_PINS(108); +DECLARE_MSM_GPIO_PINS(109); +DECLARE_MSM_GPIO_PINS(110); +DECLARE_MSM_GPIO_PINS(111); +DECLARE_MSM_GPIO_PINS(112); +DECLARE_MSM_GPIO_PINS(113); +DECLARE_MSM_GPIO_PINS(114); +DECLARE_MSM_GPIO_PINS(115); +DECLARE_MSM_GPIO_PINS(116); +DECLARE_MSM_GPIO_PINS(117); +DECLARE_MSM_GPIO_PINS(118); +DECLARE_MSM_GPIO_PINS(119); +DECLARE_MSM_GPIO_PINS(120); +DECLARE_MSM_GPIO_PINS(121); +DECLARE_MSM_GPIO_PINS(122); +DECLARE_MSM_GPIO_PINS(123); +DECLARE_MSM_GPIO_PINS(124); +DECLARE_MSM_GPIO_PINS(125); +DECLARE_MSM_GPIO_PINS(126); +DECLARE_MSM_GPIO_PINS(127); +DECLARE_MSM_GPIO_PINS(128); +DECLARE_MSM_GPIO_PINS(129); +DECLARE_MSM_GPIO_PINS(130); +DECLARE_MSM_GPIO_PINS(131); +DECLARE_MSM_GPIO_PINS(132); +DECLARE_MSM_GPIO_PINS(133); +DECLARE_MSM_GPIO_PINS(134); +DECLARE_MSM_GPIO_PINS(135); +DECLARE_MSM_GPIO_PINS(136); +DECLARE_MSM_GPIO_PINS(137); +DECLARE_MSM_GPIO_PINS(138); +DECLARE_MSM_GPIO_PINS(139); +DECLARE_MSM_GPIO_PINS(140); +DECLARE_MSM_GPIO_PINS(141); +DECLARE_MSM_GPIO_PINS(142); +DECLARE_MSM_GPIO_PINS(143); +DECLARE_MSM_GPIO_PINS(144); +DECLARE_MSM_GPIO_PINS(145); +DECLARE_MSM_GPIO_PINS(146); +DECLARE_MSM_GPIO_PINS(147); +DECLARE_MSM_GPIO_PINS(148); +DECLARE_MSM_GPIO_PINS(149); + +static const unsigned int sdc2_clk_pins[] = { 150 }; +static const unsigned int sdc2_cmd_pins[] = { 151 }; +static const unsigned int sdc2_data_pins[] = { 152 }; +static const unsigned int ufs_reset_pins[] = { 153 }; + +enum sdm845_functions { + msm_mux_ddr_pxi3, + msm_mux_cam_mclk, + msm_mux_pll_bypassnl, + msm_mux_qdss_gpio0, + msm_mux_pll_reset, + msm_mux_qdss_gpio1, + msm_mux_qdss_gpio2, + msm_mux_qdss_gpio3, + msm_mux_cci_i2c, + msm_mux_qup1, + msm_mux_qdss_gpio4, + msm_mux_qdss_gpio5, + msm_mux_qdss_gpio6, + msm_mux_qdss_gpio7, + msm_mux_cci_timer0, + msm_mux_gcc_gp2, + msm_mux_qdss_gpio8, + msm_mux_cci_timer1, + msm_mux_gcc_gp3, + msm_mux_qdss_gpio, + msm_mux_cci_timer2, + msm_mux_qdss_gpio9, + msm_mux_cci_timer3, + msm_mux_cci_async, + msm_mux_qdss_gpio10, + msm_mux_cci_timer4, + msm_mux_qdss_gpio11, + msm_mux_qdss_gpio12, + msm_mux_qup2, + msm_mux_qdss_gpio13, + msm_mux_qdss_gpio14, + msm_mux_phase_flag1, + msm_mux_qdss_gpio15, + msm_mux_phase_flag2, + msm_mux_qup11, + msm_mux_qup14, + msm_mux_pci_e0, + msm_mux_jitter_bist, + msm_mux_pll_bist, + msm_mux_atest_tsens, + msm_mux_agera_pll, + msm_mux_usb_phy, + msm_mux_lpass_slimbus, + msm_mux_sd_write, + msm_mux_tsif1_error, + msm_mux_qup3, + msm_mux_qup6, + msm_mux_qup12, + msm_mux_phase_flag16, + msm_mux_qup10, + msm_mux_phase_flag11, + msm_mux_phase_flag12, + msm_mux_phase_flag13, + msm_mux_phase_flag17, + msm_mux_qua_mi2s, + msm_mux_gcc_gp1, + msm_mux_phase_flag18, + msm_mux_phase_flag19, + msm_mux_phase_flag20, + msm_mux_cri_trng0, + msm_mux_phase_flag21, + msm_mux_cri_trng1, + msm_mux_phase_flag22, + msm_mux_cri_trng, + msm_mux_phase_flag23, + msm_mux_phase_flag24, + msm_mux_pri_mi2s, + msm_mux_sp_cmu, + msm_mux_phase_flag25, + msm_mux_qup8, + msm_mux_pri_mi2s_ws, + msm_mux_spkr_i2s, + msm_mux_audio_ref, + msm_mux_tsense_pwm1, + msm_mux_tsense_pwm2, + msm_mux_btfm_slimbus, + msm_mux_atest_usb2, + msm_mux_ter_mi2s, + msm_mux_phase_flag7, + msm_mux_atest_usb23, + msm_mux_phase_flag8, + msm_mux_atest_usb22, + msm_mux_phase_flag9, + msm_mux_atest_usb21, + msm_mux_phase_flag4, + msm_mux_atest_usb20, + msm_mux_sec_mi2s, + msm_mux_qup15, + msm_mux_qup5, + msm_mux_tsif1_clk, + msm_mux_qup4, + msm_mux_qspi_cs, + msm_mux_tgu_ch3, + msm_mux_phase_flag10, + msm_mux_tsif1_en, + msm_mux_mdp_vsync0, + msm_mux_mdp_vsync1, + msm_mux_mdp_vsync2, + msm_mux_mdp_vsync3, + msm_mux_tgu_ch0, + msm_mux_phase_flag0, + msm_mux_tsif1_data, + msm_mux_sdc4_cmd, + msm_mux_qspi0, + msm_mux_tgu_ch1, + msm_mux_tsif2_error, + msm_mux_sdc43, + msm_mux_qspi1, + msm_mux_vfr_1, + msm_mux_tgu_ch2, + msm_mux_tsif2_clk, + msm_mux_sdc4_clk, + msm_mux_qup7, + msm_mux_qspi2, + msm_mux_tsif2_en, + msm_mux_sdc42, + msm_mux_qspi3, + msm_mux_tsif2_data, + msm_mux_sdc41, + msm_mux_qspi_clk, + msm_mux_tsif2_sync, + msm_mux_sdc40, + msm_mux_phase_flag3, + msm_mux_ldo_en, + msm_mux_ldo_update, + msm_mux_phase_flag14, + msm_mux_phase_flag15, + msm_mux_pci_e1, + msm_mux_prng_rosc, + msm_mux_phase_flag5, + msm_mux_uim2_data, + msm_mux_qup13, + msm_mux_uim2_clk, + msm_mux_uim2_reset, + msm_mux_uim2_present, + msm_mux_uim1_data, + msm_mux_uim1_clk, + msm_mux_uim1_reset, + msm_mux_uim1_present, + msm_mux_uim_batt, + msm_mux_edp_hot, + msm_mux_nav_pps, + msm_mux_atest_char, + msm_mux_adsp_ext, + msm_mux_atest_char3, + msm_mux_atest_char2, + msm_mux_atest_char1, + msm_mux_atest_char0, + msm_mux_qlink_request, + msm_mux_qlink_enable, + msm_mux_pa_indicator, + msm_mux_phase_flag26, + msm_mux_phase_flag27, + msm_mux_phase_flag28, + msm_mux_phase_flag6, + msm_mux_phase_flag29, + msm_mux_phase_flag30, + msm_mux_phase_flag31, + msm_mux_mss_lte, + msm_mux_qup0, + msm_mux_gpio, + msm_mux_qup9, + msm_mux_qdss_cti, + msm_mux_ddr_pxi0, + msm_mux_ddr_bist, + msm_mux_atest_tsens2, + msm_mux_vsense_trigger, + msm_mux_atest_usb1, + msm_mux_qup_l4, + msm_mux_wlan1_adc1, + msm_mux_atest_usb13, + msm_mux_ddr_pxi1, + msm_mux_qup_l5, + msm_mux_wlan1_adc0, + msm_mux_atest_usb12, + msm_mux_mdp_vsync, + msm_mux_qup_l6, + msm_mux_wlan2_adc1, + msm_mux_atest_usb11, + msm_mux_ddr_pxi2, + msm_mux_edp_lcd, + msm_mux_dbg_out, + msm_mux_wlan2_adc0, + msm_mux_atest_usb10, + msm_mux_m_voc, + msm_mux_tsif1_sync, + msm_mux_NA, +}; + +static const char * const ddr_pxi3_groups[] = { + "gpio12", "gpio13", +}; +static const char * const cam_mclk_groups[] = { + "gpio13", "gpio14", "gpio15", "gpio16", +}; +static const char * const pll_bypassnl_groups[] = { + "gpio13", +}; +static const char * const qdss_gpio0_groups[] = { + "gpio13", "gpio117", +}; +static const char * const pll_reset_groups[] = { + "gpio14", +}; +static const char * const qdss_gpio1_groups[] = { + "gpio14", "gpio118", +}; +static const char * const qdss_gpio2_groups[] = { + "gpio15", "gpio119", +}; +static const char * const qdss_gpio3_groups[] = { + "gpio16", "gpio120", +}; +static const char * const cci_i2c_groups[] = { + "gpio17", "gpio18", "gpio19", "gpio20", +}; +static const char * const qup1_groups[] = { + "gpio17", "gpio18", "gpio19", "gpio20", +}; +static const char * const qdss_gpio4_groups[] = { + "gpio17", "gpio121", +}; +static const char * const qdss_gpio5_groups[] = { + "gpio18", "gpio122", +}; +static const char * const qdss_gpio6_groups[] = { + "gpio19", "gpio41", +}; +static const char * const qdss_gpio7_groups[] = { + "gpio20", "gpio42", +}; +static const char * const cci_timer0_groups[] = { + "gpio21", +}; +static const char * const gcc_gp2_groups[] = { + "gpio21", "gpio58", +}; +static const char * const qdss_gpio8_groups[] = { + "gpio21", "gpio75", +}; +static const char * const cci_timer1_groups[] = { + "gpio22", +}; +static const char * const gcc_gp3_groups[] = { + "gpio22", "gpio59", +}; +static const char * const qdss_gpio_groups[] = { + "gpio22", "gpio30", "gpio123", "gpio124", +}; +static const char * const cci_timer2_groups[] = { + "gpio23", +}; +static const char * const qdss_gpio9_groups[] = { + "gpio23", "gpio76", +}; +static const char * const cci_timer3_groups[] = { + "gpio24", +}; +static const char * const cci_async_groups[] = { + "gpio24", "gpio25", "gpio26", +}; +static const char * const qdss_gpio10_groups[] = { + "gpio24", "gpio77", +}; +static const char * const cci_timer4_groups[] = { + "gpio25", +}; +static const char * const qdss_gpio11_groups[] = { + "gpio25", "gpio79", +}; +static const char * const qdss_gpio12_groups[] = { + "gpio26", "gpio80", +}; +static const char * const qup2_groups[] = { + "gpio27", "gpio28", "gpio29", "gpio30", +}; +static const char * const qdss_gpio13_groups[] = { + "gpio27", "gpio93", +}; +static const char * const qdss_gpio14_groups[] = { + "gpio28", "gpio43", +}; +static const char * const phase_flag1_groups[] = { + "gpio29", +}; +static const char * const qdss_gpio15_groups[] = { + "gpio29", "gpio44", +}; +static const char * const phase_flag2_groups[] = { + "gpio30", +}; +static const char * const qup11_groups[] = { + "gpio31", "gpio32", "gpio33", "gpio34", +}; +static const char * const qup14_groups[] = { + "gpio31", "gpio32", "gpio33", "gpio34", +}; +static const char * const pci_e0_groups[] = { + "gpio35", "gpio36", +}; +static const char * const jitter_bist_groups[] = { + "gpio35", +}; +static const char * const pll_bist_groups[] = { + "gpio36", +}; +static const char * const atest_tsens_groups[] = { + "gpio36", +}; +static const char * const agera_pll_groups[] = { + "gpio37", +}; +static const char * const usb_phy_groups[] = { + "gpio38", +}; +static const char * const lpass_slimbus_groups[] = { + "gpio39", "gpio70", "gpio71", "gpio72", +}; +static const char * const sd_write_groups[] = { + "gpio40", +}; +static const char * const tsif1_error_groups[] = { + "gpio40", +}; +static const char * const qup3_groups[] = { + "gpio41", "gpio42", "gpio43", "gpio44", +}; +static const char * const qup6_groups[] = { + "gpio45", "gpio46", "gpio47", "gpio48", +}; +static const char * const qup12_groups[] = { + "gpio49", "gpio50", "gpio51", "gpio52", +}; +static const char * const phase_flag16_groups[] = { + "gpio52", +}; +static const char * const qup10_groups[] = { + "gpio53", "gpio54", "gpio55", "gpio56", +}; +static const char * const phase_flag11_groups[] = { + "gpio53", +}; +static const char * const phase_flag12_groups[] = { + "gpio54", +}; +static const char * const phase_flag13_groups[] = { + "gpio55", +}; +static const char * const phase_flag17_groups[] = { + "gpio56", +}; +static const char * const qua_mi2s_groups[] = { + "gpio57", "gpio58", "gpio59", "gpio60", "gpio61", "gpio62", "gpio63", +}; +static const char * const gcc_gp1_groups[] = { + "gpio57", "gpio78", +}; +static const char * const phase_flag18_groups[] = { + "gpio57", +}; +static const char * const phase_flag19_groups[] = { + "gpio58", +}; +static const char * const phase_flag20_groups[] = { + "gpio59", +}; +static const char * const cri_trng0_groups[] = { + "gpio60", +}; +static const char * const phase_flag21_groups[] = { + "gpio60", +}; +static const char * const cri_trng1_groups[] = { + "gpio61", +}; +static const char * const phase_flag22_groups[] = { + "gpio61", +}; +static const char * const cri_trng_groups[] = { + "gpio62", +}; +static const char * const phase_flag23_groups[] = { + "gpio62", +}; +static const char * const phase_flag24_groups[] = { + "gpio63", +}; +static const char * const pri_mi2s_groups[] = { + "gpio64", "gpio65", "gpio67", "gpio68", +}; +static const char * const sp_cmu_groups[] = { + "gpio64", +}; +static const char * const phase_flag25_groups[] = { + "gpio64", +}; +static const char * const qup8_groups[] = { + "gpio65", "gpio66", "gpio67", "gpio68", +}; +static const char * const pri_mi2s_ws_groups[] = { + "gpio66", +}; +static const char * const spkr_i2s_groups[] = { + "gpio69", "gpio70", "gpio71", "gpio72", +}; +static const char * const audio_ref_groups[] = { + "gpio69", +}; +static const char * const tsense_pwm1_groups[] = { + "gpio71", +}; +static const char * const tsense_pwm2_groups[] = { + "gpio71", +}; +static const char * const btfm_slimbus_groups[] = { + "gpio73", "gpio74", +}; +static const char * const atest_usb2_groups[] = { + "gpio73", +}; +static const char * const ter_mi2s_groups[] = { + "gpio74", "gpio75", "gpio76", "gpio77", "gpio78", +}; +static const char * const phase_flag7_groups[] = { + "gpio74", +}; +static const char * const atest_usb23_groups[] = { + "gpio74", +}; +static const char * const phase_flag8_groups[] = { + "gpio75", +}; +static const char * const atest_usb22_groups[] = { + "gpio75", +}; +static const char * const phase_flag9_groups[] = { + "gpio76", +}; +static const char * const atest_usb21_groups[] = { + "gpio76", +}; +static const char * const phase_flag4_groups[] = { + "gpio77", +}; +static const char * const atest_usb20_groups[] = { + "gpio77", +}; +static const char * const sec_mi2s_groups[] = { + "gpio79", "gpio80", "gpio81", "gpio82", "gpio83", +}; +static const char * const qup15_groups[] = { + "gpio81", "gpio82", "gpio83", "gpio84", +}; +static const char * const qup5_groups[] = { + "gpio85", "gpio86", "gpio87", "gpio88", +}; +static const char * const tsif1_clk_groups[] = { + "gpio89", +}; +static const char * const qup4_groups[] = { + "gpio89", "gpio90", "gpio91", "gpio92", +}; +static const char * const qspi_cs_groups[] = { + "gpio89", "gpio90", +}; +static const char * const tgu_ch3_groups[] = { + "gpio89", +}; +static const char * const phase_flag10_groups[] = { + "gpio89", +}; +static const char * const tsif1_en_groups[] = { + "gpio90", +}; +static const char * const mdp_vsync0_groups[] = { + "gpio90", +}; +static const char * const mdp_vsync1_groups[] = { + "gpio90", +}; +static const char * const mdp_vsync2_groups[] = { + "gpio90", +}; +static const char * const mdp_vsync3_groups[] = { + "gpio90", +}; +static const char * const tgu_ch0_groups[] = { + "gpio90", +}; +static const char * const phase_flag0_groups[] = { + "gpio90", +}; +static const char * const tsif1_data_groups[] = { + "gpio91", +}; +static const char * const sdc4_cmd_groups[] = { + "gpio91", +}; +static const char * const qspi0_groups[] = { + "gpio91", +}; +static const char * const tgu_ch1_groups[] = { + "gpio91", +}; +static const char * const tsif2_error_groups[] = { + "gpio92", +}; +static const char * const sdc43_groups[] = { + "gpio92", +}; +static const char * const qspi1_groups[] = { + "gpio92", +}; +static const char * const vfr_1_groups[] = { + "gpio92", +}; +static const char * const tgu_ch2_groups[] = { + "gpio92", +}; +static const char * const tsif2_clk_groups[] = { + "gpio93", +}; +static const char * const sdc4_clk_groups[] = { + "gpio93", +}; +static const char * const qup7_groups[] = { + "gpio93", "gpio94", "gpio95", "gpio96", +}; +static const char * const qspi2_groups[] = { + "gpio93", +}; +static const char * const tsif2_en_groups[] = { + "gpio94", +}; +static const char * const sdc42_groups[] = { + "gpio94", +}; +static const char * const qspi3_groups[] = { + "gpio94", +}; +static const char * const tsif2_data_groups[] = { + "gpio95", +}; +static const char * const sdc41_groups[] = { + "gpio95", +}; +static const char * const qspi_clk_groups[] = { + "gpio95", +}; +static const char * const tsif2_sync_groups[] = { + "gpio96", +}; +static const char * const sdc40_groups[] = { + "gpio96", +}; +static const char * const phase_flag3_groups[] = { + "gpio96", +}; +static const char * const ldo_en_groups[] = { + "gpio97", +}; +static const char * const ldo_update_groups[] = { + "gpio98", +}; +static const char * const phase_flag14_groups[] = { + "gpio99", +}; +static const char * const phase_flag15_groups[] = { + "gpio100", +}; +static const char * const pci_e1_groups[] = { + "gpio102", "gpio103", +}; +static const char * const prng_rosc_groups[] = { + "gpio102", +}; +static const char * const phase_flag5_groups[] = { + "gpio103", +}; +static const char * const uim2_data_groups[] = { + "gpio105", +}; +static const char * const qup13_groups[] = { + "gpio105", "gpio106", "gpio107", "gpio108", +}; +static const char * const uim2_clk_groups[] = { + "gpio106", +}; +static const char * const uim2_reset_groups[] = { + "gpio107", +}; +static const char * const uim2_present_groups[] = { + "gpio108", +}; +static const char * const uim1_data_groups[] = { + "gpio109", +}; +static const char * const uim1_clk_groups[] = { + "gpio110", +}; +static const char * const uim1_reset_groups[] = { + "gpio111", +}; +static const char * const uim1_present_groups[] = { + "gpio112", +}; +static const char * const uim_batt_groups[] = { + "gpio113", +}; +static const char * const edp_hot_groups[] = { + "gpio113", +}; +static const char * const nav_pps_groups[] = { + "gpio114", "gpio114", "gpio115", "gpio115", "gpio128", "gpio128", + "gpio129", "gpio129", "gpio143", "gpio143", +}; +static const char * const atest_char_groups[] = { + "gpio117", +}; +static const char * const adsp_ext_groups[] = { + "gpio118", +}; +static const char * const atest_char3_groups[] = { + "gpio118", +}; +static const char * const atest_char2_groups[] = { + "gpio119", +}; +static const char * const atest_char1_groups[] = { + "gpio120", +}; +static const char * const atest_char0_groups[] = { + "gpio121", +}; +static const char * const qlink_request_groups[] = { + "gpio130", +}; +static const char * const qlink_enable_groups[] = { + "gpio131", +}; +static const char * const pa_indicator_groups[] = { + "gpio135", +}; +static const char * const phase_flag26_groups[] = { + "gpio137", +}; +static const char * const phase_flag27_groups[] = { + "gpio138", +}; +static const char * const phase_flag28_groups[] = { + "gpio139", +}; +static const char * const phase_flag6_groups[] = { + "gpio140", +}; +static const char * const phase_flag29_groups[] = { + "gpio141", +}; +static const char * const phase_flag30_groups[] = { + "gpio142", +}; +static const char * const phase_flag31_groups[] = { + "gpio143", +}; +static const char * const mss_lte_groups[] = { + "gpio144", "gpio145", +}; +static const char * const qup0_groups[] = { + "gpio0", "gpio1", "gpio2", "gpio3", +}; +static const char * const gpio_groups[] = { + "gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7", + "gpio8", "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14", + "gpio15", "gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21", + "gpio22", "gpio23", "gpio24", "gpio25", "gpio26", "gpio27", "gpio28", + "gpio29", "gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35", + "gpio36", "gpio37", "gpio38", "gpio39", "gpio40", "gpio41", "gpio42", + "gpio43", "gpio44", "gpio45", "gpio46", "gpio47", "gpio48", "gpio49", + "gpio50", "gpio51", "gpio52", "gpio53", "gpio54", "gpio55", "gpio56", + "gpio57", "gpio58", "gpio59", "gpio60", "gpio61", "gpio62", "gpio63", + "gpio64", "gpio65", "gpio66", "gpio67", "gpio68", "gpio69", "gpio70", + "gpio71", "gpio72", "gpio73", "gpio74", "gpio75", "gpio76", "gpio77", + "gpio78", "gpio79", "gpio80", "gpio81", "gpio82", "gpio83", "gpio84", + "gpio85", "gpio86", "gpio87", "gpio88", "gpio89", "gpio90", "gpio91", + "gpio92", "gpio93", "gpio94", "gpio95", "gpio96", "gpio97", "gpio98", + "gpio99", "gpio100", "gpio101", "gpio102", "gpio103", "gpio104", + "gpio105", "gpio106", "gpio107", "gpio108", "gpio109", "gpio110", + "gpio111", "gpio112", "gpio113", "gpio114", "gpio115", "gpio116", + "gpio117", "gpio118", "gpio119", "gpio120", "gpio121", "gpio122", + "gpio123", "gpio124", "gpio125", "gpio126", "gpio127", "gpio128", + "gpio129", "gpio130", "gpio131", "gpio132", "gpio133", "gpio134", + "gpio135", "gpio136", "gpio137", "gpio138", "gpio139", "gpio140", + "gpio141", "gpio142", "gpio143", "gpio144", "gpio145", "gpio146", + "gpio147", "gpio148", "gpio149", +}; +static const char * const qup9_groups[] = { + "gpio4", "gpio5", "gpio6", "gpio7", +}; +static const char * const qdss_cti_groups[] = { + "gpio4", "gpio5", "gpio51", "gpio52", "gpio62", "gpio63", "gpio90", + "gpio91", +}; +static const char * const ddr_pxi0_groups[] = { + "gpio6", "gpio7", +}; +static const char * const ddr_bist_groups[] = { + "gpio7", "gpio8", "gpio9", "gpio10", +}; +static const char * const atest_tsens2_groups[] = { + "gpio7", +}; +static const char * const vsense_trigger_groups[] = { + "gpio7", +}; +static const char * const atest_usb1_groups[] = { + "gpio7", +}; +static const char * const qup_l4_groups[] = { + "gpio8", "gpio35", "gpio105", "gpio123", +}; +static const char * const wlan1_adc1_groups[] = { + "gpio8", +}; +static const char * const atest_usb13_groups[] = { + "gpio8", +}; +static const char * const ddr_pxi1_groups[] = { + "gpio8", "gpio9", +}; +static const char * const qup_l5_groups[] = { + "gpio9", "gpio36", "gpio106", "gpio124", +}; +static const char * const wlan1_adc0_groups[] = { + "gpio9", +}; +static const char * const atest_usb12_groups[] = { + "gpio9", +}; +static const char * const mdp_vsync_groups[] = { + "gpio10", "gpio11", "gpio12", "gpio97", "gpio98", +}; +static const char * const qup_l6_groups[] = { + "gpio10", "gpio37", "gpio107", "gpio125", +}; +static const char * const wlan2_adc1_groups[] = { + "gpio10", +}; +static const char * const atest_usb11_groups[] = { + "gpio10", +}; +static const char * const ddr_pxi2_groups[] = { + "gpio10", "gpio11", +}; +static const char * const edp_lcd_groups[] = { + "gpio11", +}; +static const char * const dbg_out_groups[] = { + "gpio11", +}; +static const char * const wlan2_adc0_groups[] = { + "gpio11", +}; +static const char * const atest_usb10_groups[] = { + "gpio11", +}; +static const char * const m_voc_groups[] = { + "gpio12", +}; +static const char * const tsif1_sync_groups[] = { + "gpio12", +}; + +static const struct msm_function sdm845_functions[] = { + FUNCTION(ddr_pxi3), + FUNCTION(cam_mclk), + FUNCTION(pll_bypassnl), + FUNCTION(qdss_gpio0), + FUNCTION(pll_reset), + FUNCTION(qdss_gpio1), + FUNCTION(qdss_gpio2), + FUNCTION(qdss_gpio3), + FUNCTION(cci_i2c), + FUNCTION(qup1), + FUNCTION(qdss_gpio4), + FUNCTION(qdss_gpio5), + FUNCTION(qdss_gpio6), + FUNCTION(qdss_gpio7), + FUNCTION(cci_timer0), + FUNCTION(gcc_gp2), + FUNCTION(qdss_gpio8), + FUNCTION(cci_timer1), + FUNCTION(gcc_gp3), + FUNCTION(qdss_gpio), + FUNCTION(cci_timer2), + FUNCTION(qdss_gpio9), + FUNCTION(cci_timer3), + FUNCTION(cci_async), + FUNCTION(qdss_gpio10), + FUNCTION(cci_timer4), + FUNCTION(qdss_gpio11), + FUNCTION(qdss_gpio12), + FUNCTION(qup2), + FUNCTION(qdss_gpio13), + FUNCTION(qdss_gpio14), + FUNCTION(phase_flag1), + FUNCTION(qdss_gpio15), + FUNCTION(phase_flag2), + FUNCTION(qup11), + FUNCTION(qup14), + FUNCTION(pci_e0), + FUNCTION(jitter_bist), + FUNCTION(pll_bist), + FUNCTION(atest_tsens), + FUNCTION(agera_pll), + FUNCTION(usb_phy), + FUNCTION(lpass_slimbus), + FUNCTION(sd_write), + FUNCTION(tsif1_error), + FUNCTION(qup3), + FUNCTION(qup6), + FUNCTION(qup12), + FUNCTION(phase_flag16), + FUNCTION(qup10), + FUNCTION(phase_flag11), + FUNCTION(phase_flag12), + FUNCTION(phase_flag13), + FUNCTION(phase_flag17), + FUNCTION(qua_mi2s), + FUNCTION(gcc_gp1), + FUNCTION(phase_flag18), + FUNCTION(phase_flag19), + FUNCTION(phase_flag20), + FUNCTION(cri_trng0), + FUNCTION(phase_flag21), + FUNCTION(cri_trng1), + FUNCTION(phase_flag22), + FUNCTION(cri_trng), + FUNCTION(phase_flag23), + FUNCTION(phase_flag24), + FUNCTION(pri_mi2s), + FUNCTION(sp_cmu), + FUNCTION(phase_flag25), + FUNCTION(qup8), + FUNCTION(pri_mi2s_ws), + FUNCTION(spkr_i2s), + FUNCTION(audio_ref), + FUNCTION(tsense_pwm1), + FUNCTION(tsense_pwm2), + FUNCTION(btfm_slimbus), + FUNCTION(atest_usb2), + FUNCTION(ter_mi2s), + FUNCTION(phase_flag7), + FUNCTION(atest_usb23), + FUNCTION(phase_flag8), + FUNCTION(atest_usb22), + FUNCTION(phase_flag9), + FUNCTION(atest_usb21), + FUNCTION(phase_flag4), + FUNCTION(atest_usb20), + FUNCTION(sec_mi2s), + FUNCTION(qup15), + FUNCTION(qup5), + FUNCTION(tsif1_clk), + FUNCTION(qup4), + FUNCTION(qspi_cs), + FUNCTION(tgu_ch3), + FUNCTION(phase_flag10), + FUNCTION(tsif1_en), + FUNCTION(mdp_vsync0), + FUNCTION(mdp_vsync1), + FUNCTION(mdp_vsync2), + FUNCTION(mdp_vsync3), + FUNCTION(tgu_ch0), + FUNCTION(phase_flag0), + FUNCTION(tsif1_data), + FUNCTION(sdc4_cmd), + FUNCTION(qspi0), + FUNCTION(tgu_ch1), + FUNCTION(tsif2_error), + FUNCTION(sdc43), + FUNCTION(qspi1), + FUNCTION(vfr_1), + FUNCTION(tgu_ch2), + FUNCTION(tsif2_clk), + FUNCTION(sdc4_clk), + FUNCTION(qup7), + FUNCTION(qspi2), + FUNCTION(tsif2_en), + FUNCTION(sdc42), + FUNCTION(qspi3), + FUNCTION(tsif2_data), + FUNCTION(sdc41), + FUNCTION(qspi_clk), + FUNCTION(tsif2_sync), + FUNCTION(sdc40), + FUNCTION(phase_flag3), + FUNCTION(ldo_en), + FUNCTION(ldo_update), + FUNCTION(phase_flag14), + FUNCTION(phase_flag15), + FUNCTION(pci_e1), + FUNCTION(prng_rosc), + FUNCTION(phase_flag5), + FUNCTION(uim2_data), + FUNCTION(qup13), + FUNCTION(uim2_clk), + FUNCTION(uim2_reset), + FUNCTION(uim2_present), + FUNCTION(uim1_data), + FUNCTION(uim1_clk), + FUNCTION(uim1_reset), + FUNCTION(uim1_present), + FUNCTION(uim_batt), + FUNCTION(edp_hot), + FUNCTION(nav_pps), + FUNCTION(atest_char), + FUNCTION(adsp_ext), + FUNCTION(atest_char3), + FUNCTION(atest_char2), + FUNCTION(atest_char1), + FUNCTION(atest_char0), + FUNCTION(qlink_request), + FUNCTION(qlink_enable), + FUNCTION(pa_indicator), + FUNCTION(phase_flag26), + FUNCTION(phase_flag27), + FUNCTION(phase_flag28), + FUNCTION(phase_flag6), + FUNCTION(phase_flag29), + FUNCTION(phase_flag30), + FUNCTION(phase_flag31), + FUNCTION(mss_lte), + FUNCTION(qup0), + FUNCTION(gpio), + FUNCTION(qup9), + FUNCTION(qdss_cti), + FUNCTION(ddr_pxi0), + FUNCTION(ddr_bist), + FUNCTION(atest_tsens2), + FUNCTION(vsense_trigger), + FUNCTION(atest_usb1), + FUNCTION(qup_l4), + FUNCTION(wlan1_adc1), + FUNCTION(atest_usb13), + FUNCTION(ddr_pxi1), + FUNCTION(qup_l5), + FUNCTION(wlan1_adc0), + FUNCTION(atest_usb12), + FUNCTION(mdp_vsync), + FUNCTION(qup_l6), + FUNCTION(wlan2_adc1), + FUNCTION(atest_usb11), + FUNCTION(ddr_pxi2), + FUNCTION(edp_lcd), + FUNCTION(dbg_out), + FUNCTION(wlan2_adc0), + FUNCTION(atest_usb10), + FUNCTION(m_voc), + FUNCTION(tsif1_sync), +}; + +/* Every pin is maintained as a single group, and missing or non-existing pin + * would be maintained as dummy group to synchronize pin group index with + * pin descriptor registered with pinctrl core. + * Clients would not be able to request these dummy pin groups. + */ +static const struct msm_pingroup sdm845_groups[] = { + [0] = PINGROUP(0, EAST, qup0, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [1] = PINGROUP(1, EAST, qup0, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [2] = PINGROUP(2, EAST, qup0, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [3] = PINGROUP(3, EAST, qup0, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [4] = PINGROUP(4, NORTH, qup9, qdss_cti, NA, NA, NA, NA, NA, NA, NA, + NA), + [5] = PINGROUP(5, NORTH, qup9, qdss_cti, NA, NA, NA, NA, NA, NA, NA, + NA), + [6] = PINGROUP(6, NORTH, qup9, NA, ddr_pxi0, NA, NA, NA, NA, NA, NA, + NA), + [7] = PINGROUP(7, NORTH, qup9, ddr_bist, NA, atest_tsens2, + vsense_trigger, atest_usb1, ddr_pxi0, NA, NA, NA), + [8] = PINGROUP(8, EAST, qup_l4, NA, ddr_bist, NA, NA, wlan1_adc1, + atest_usb13, ddr_pxi1, NA, NA), + [9] = PINGROUP(9, EAST, qup_l5, ddr_bist, NA, wlan1_adc0, atest_usb12, + ddr_pxi1, NA, NA, NA, NA), + [10] = PINGROUP(10, EAST, mdp_vsync, qup_l6, ddr_bist, wlan2_adc1, + atest_usb11, ddr_pxi2, NA, NA, NA, NA), + [11] = PINGROUP(11, EAST, mdp_vsync, edp_lcd, dbg_out, wlan2_adc0, + atest_usb10, ddr_pxi2, NA, NA, NA, NA), + [12] = PINGROUP(12, SOUTH, mdp_vsync, m_voc, tsif1_sync, ddr_pxi3, NA, + NA, NA, NA, NA, NA), + [13] = PINGROUP(13, SOUTH, cam_mclk, pll_bypassnl, qdss_gpio0, + ddr_pxi3, NA, NA, NA, NA, NA, NA), + [14] = PINGROUP(14, SOUTH, cam_mclk, pll_reset, qdss_gpio1, NA, NA, NA, + NA, NA, NA, NA), + [15] = PINGROUP(15, SOUTH, cam_mclk, qdss_gpio2, NA, NA, NA, NA, NA, + NA, NA, NA), + [16] = PINGROUP(16, SOUTH, cam_mclk, qdss_gpio3, NA, NA, NA, NA, NA, + NA, NA, NA), + [17] = PINGROUP(17, SOUTH, cci_i2c, qup1, qdss_gpio4, NA, NA, NA, NA, + NA, NA, NA), + [18] = PINGROUP(18, SOUTH, cci_i2c, qup1, NA, qdss_gpio5, NA, NA, NA, + NA, NA, NA), + [19] = PINGROUP(19, SOUTH, cci_i2c, qup1, NA, qdss_gpio6, NA, NA, NA, + NA, NA, NA), + [20] = PINGROUP(20, SOUTH, cci_i2c, qup1, NA, qdss_gpio7, NA, NA, NA, + NA, NA, NA), + [21] = PINGROUP(21, SOUTH, cci_timer0, gcc_gp2, qdss_gpio8, NA, NA, NA, + NA, NA, NA, NA), + [22] = PINGROUP(22, SOUTH, cci_timer1, gcc_gp3, qdss_gpio, NA, NA, NA, + NA, NA, NA, NA), + [23] = PINGROUP(23, SOUTH, cci_timer2, qdss_gpio9, NA, NA, NA, NA, NA, + NA, NA, NA), + [24] = PINGROUP(24, SOUTH, cci_timer3, cci_async, qdss_gpio10, NA, NA, + NA, NA, NA, NA, NA), + [25] = PINGROUP(25, SOUTH, cci_timer4, cci_async, qdss_gpio11, NA, NA, + NA, NA, NA, NA, NA), + [26] = PINGROUP(26, SOUTH, cci_async, qdss_gpio12, NA, NA, NA, NA, NA, + NA, NA, NA), + [27] = PINGROUP(27, EAST, qup2, qdss_gpio13, NA, NA, NA, NA, NA, NA, + NA, NA), + [28] = PINGROUP(28, EAST, qup2, qdss_gpio14, NA, NA, NA, NA, NA, NA, + NA, NA), + [29] = PINGROUP(29, EAST, qup2, NA, phase_flag1, qdss_gpio15, NA, NA, + NA, NA, NA, NA), + [30] = PINGROUP(30, EAST, qup2, phase_flag2, qdss_gpio, NA, NA, NA, NA, + NA, NA, NA), + [31] = PINGROUP(31, NORTH, qup11, qup14, NA, NA, NA, NA, NA, NA, NA, + NA), + [32] = PINGROUP(32, NORTH, qup11, qup14, NA, NA, NA, NA, NA, NA, NA, + NA), + [33] = PINGROUP(33, NORTH, qup11, qup14, NA, NA, NA, NA, NA, NA, NA, + NA), + [34] = PINGROUP(34, NORTH, qup11, qup14, NA, NA, NA, NA, NA, NA, NA, + NA), + [35] = PINGROUP(35, SOUTH, pci_e0, qup_l4, jitter_bist, NA, NA, NA, NA, + NA, NA, NA), + [36] = PINGROUP(36, SOUTH, pci_e0, qup_l5, pll_bist, NA, atest_tsens, + NA, NA, NA, NA, NA), + [37] = PINGROUP(37, SOUTH, qup_l6, agera_pll, NA, NA, NA, NA, NA, NA, + NA, NA), + [38] = PINGROUP(38, NORTH, usb_phy, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [39] = PINGROUP(39, EAST, lpass_slimbus, NA, NA, NA, NA, NA, NA, NA, + NA, NA), + [40] = PINGROUP(40, SOUTH, sd_write, tsif1_error, NA, NA, NA, NA, NA, + NA, NA, NA), + [41] = PINGROUP(41, EAST, qup3, NA, qdss_gpio6, NA, NA, NA, NA, NA, NA, + NA), + [42] = PINGROUP(42, EAST, qup3, NA, qdss_gpio7, NA, NA, NA, NA, NA, NA, + NA), + [43] = PINGROUP(43, EAST, qup3, NA, qdss_gpio14, NA, NA, NA, NA, NA, + NA, NA), + [44] = PINGROUP(44, EAST, qup3, NA, qdss_gpio15, NA, NA, NA, NA, NA, + NA, NA), + [45] = PINGROUP(45, EAST, qup6, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [46] = PINGROUP(46, EAST, qup6, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [47] = PINGROUP(47, EAST, qup6, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [48] = PINGROUP(48, EAST, qup6, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [49] = PINGROUP(49, NORTH, qup12, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [50] = PINGROUP(50, NORTH, qup12, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [51] = PINGROUP(51, NORTH, qup12, qdss_cti, NA, NA, NA, NA, NA, NA, NA, + NA), + [52] = PINGROUP(52, NORTH, qup12, phase_flag16, qdss_cti, NA, NA, NA, + NA, NA, NA, NA), + [53] = PINGROUP(53, NORTH, qup10, phase_flag11, NA, NA, NA, NA, NA, NA, + NA, NA), + [54] = PINGROUP(54, NORTH, qup10, NA, phase_flag12, NA, NA, NA, NA, NA, + NA, NA), + [55] = PINGROUP(55, NORTH, qup10, phase_flag13, NA, NA, NA, NA, NA, NA, + NA, NA), + [56] = PINGROUP(56, NORTH, qup10, phase_flag17, NA, NA, NA, NA, NA, NA, + NA, NA), + [57] = PINGROUP(57, NORTH, qua_mi2s, gcc_gp1, phase_flag18, NA, NA, NA, + NA, NA, NA, NA), + [58] = PINGROUP(58, NORTH, qua_mi2s, gcc_gp2, phase_flag19, NA, NA, NA, + NA, NA, NA, NA), + [59] = PINGROUP(59, NORTH, qua_mi2s, gcc_gp3, phase_flag20, NA, NA, NA, + NA, NA, NA, NA), + [60] = PINGROUP(60, NORTH, qua_mi2s, cri_trng0, phase_flag21, NA, NA, + NA, NA, NA, NA, NA), + [61] = PINGROUP(61, NORTH, qua_mi2s, cri_trng1, phase_flag22, NA, NA, + NA, NA, NA, NA, NA), + [62] = PINGROUP(62, NORTH, qua_mi2s, cri_trng, phase_flag23, qdss_cti, + NA, NA, NA, NA, NA, NA), + [63] = PINGROUP(63, NORTH, qua_mi2s, NA, phase_flag24, qdss_cti, NA, + NA, NA, NA, NA, NA), + [64] = PINGROUP(64, NORTH, pri_mi2s, sp_cmu, phase_flag25, NA, NA, NA, + NA, NA, NA, NA), + [65] = PINGROUP(65, NORTH, pri_mi2s, qup8, NA, NA, NA, NA, NA, NA, NA, + NA), + [66] = PINGROUP(66, NORTH, pri_mi2s_ws, qup8, NA, NA, NA, NA, NA, NA, + NA, NA), + [67] = PINGROUP(67, NORTH, pri_mi2s, qup8, NA, NA, NA, NA, NA, NA, NA, + NA), + [68] = PINGROUP(68, NORTH, pri_mi2s, qup8, NA, NA, NA, NA, NA, NA, NA, + NA), + [69] = PINGROUP(69, EAST, spkr_i2s, audio_ref, NA, NA, NA, NA, NA, NA, + NA, NA), + [70] = PINGROUP(70, EAST, lpass_slimbus, spkr_i2s, NA, NA, NA, NA, NA, + NA, NA, NA), + [71] = PINGROUP(71, EAST, lpass_slimbus, spkr_i2s, tsense_pwm1, + tsense_pwm2, NA, NA, NA, NA, NA, NA), + [72] = PINGROUP(72, EAST, lpass_slimbus, spkr_i2s, NA, NA, NA, NA, NA, + NA, NA, NA), + [73] = PINGROUP(73, EAST, btfm_slimbus, atest_usb2, NA, NA, NA, NA, NA, + NA, NA, NA), + [74] = PINGROUP(74, EAST, btfm_slimbus, ter_mi2s, phase_flag7, + atest_usb23, NA, NA, NA, NA, NA, NA), + [75] = PINGROUP(75, EAST, ter_mi2s, phase_flag8, qdss_gpio8, + atest_usb22, NA, NA, NA, NA, NA, NA), + [76] = PINGROUP(76, EAST, ter_mi2s, phase_flag9, qdss_gpio9, + atest_usb21, NA, NA, NA, NA, NA, NA), + [77] = PINGROUP(77, EAST, ter_mi2s, phase_flag4, qdss_gpio10, + atest_usb20, NA, NA, NA, NA, NA, NA), + [78] = PINGROUP(78, EAST, ter_mi2s, gcc_gp1, NA, NA, NA, NA, NA, NA, + NA, NA), + [79] = PINGROUP(79, NORTH, sec_mi2s, NA, NA, qdss_gpio11, NA, NA, NA, + NA, NA, NA), + [80] = PINGROUP(80, NORTH, sec_mi2s, NA, qdss_gpio12, NA, NA, NA, NA, + NA, NA, NA), + [81] = PINGROUP(81, NORTH, sec_mi2s, qup15, NA, NA, NA, NA, NA, NA, NA, + NA), + [82] = PINGROUP(82, NORTH, sec_mi2s, qup15, NA, NA, NA, NA, NA, NA, NA, + NA), + [83] = PINGROUP(83, NORTH, sec_mi2s, qup15, NA, NA, NA, NA, NA, NA, NA, + NA), + [84] = PINGROUP(84, NORTH, qup15, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [85] = PINGROUP(85, EAST, qup5, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [86] = PINGROUP(86, EAST, qup5, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [87] = PINGROUP(87, EAST, qup5, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [88] = PINGROUP(88, EAST, qup5, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [89] = PINGROUP(89, SOUTH, tsif1_clk, qup4, qspi_cs, tgu_ch3, + phase_flag10, NA, NA, NA, NA, NA), + [90] = PINGROUP(90, SOUTH, tsif1_en, mdp_vsync0, qup4, qspi_cs, + mdp_vsync1, mdp_vsync2, mdp_vsync3, tgu_ch0, + phase_flag0, qdss_cti), + [91] = PINGROUP(91, SOUTH, tsif1_data, sdc4_cmd, qup4, qspi0, tgu_ch1, + NA, qdss_cti, NA, NA, NA), + [92] = PINGROUP(92, SOUTH, tsif2_error, sdc43, qup4, qspi1, vfr_1, + tgu_ch2, NA, NA, NA, NA), + [93] = PINGROUP(93, SOUTH, tsif2_clk, sdc4_clk, qup7, qspi2, NA, + qdss_gpio13, NA, NA, NA, NA), + [94] = PINGROUP(94, SOUTH, tsif2_en, sdc42, qup7, qspi3, NA, NA, NA, + NA, NA, NA), + [95] = PINGROUP(95, SOUTH, tsif2_data, sdc41, qup7, qspi_clk, NA, NA, + NA, NA, NA, NA), + [96] = PINGROUP(96, SOUTH, tsif2_sync, sdc40, qup7, phase_flag3, NA, + NA, NA, NA, NA, NA), + [97] = PINGROUP(97, NORTH, NA, NA, mdp_vsync, ldo_en, NA, NA, NA, NA, + NA, NA), + [98] = PINGROUP(98, NORTH, NA, mdp_vsync, ldo_update, NA, NA, NA, NA, + NA, NA, NA), + [99] = PINGROUP(99, NORTH, phase_flag14, NA, NA, NA, NA, NA, NA, NA, + NA, NA), + [100] = PINGROUP(100, NORTH, phase_flag15, NA, NA, NA, NA, NA, NA, NA, + NA, NA), + [101] = PINGROUP(101, NORTH, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [102] = PINGROUP(102, NORTH, pci_e1, prng_rosc, NA, NA, NA, NA, NA, NA, + NA, NA), + [103] = PINGROUP(103, NORTH, pci_e1, phase_flag5, NA, NA, NA, NA, NA, + NA, NA, NA), + [104] = PINGROUP(104, NORTH, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [105] = PINGROUP(105, NORTH, uim2_data, qup13, qup_l4, NA, NA, NA, NA, + NA, NA, NA), + [106] = PINGROUP(106, NORTH, uim2_clk, qup13, qup_l5, NA, NA, NA, NA, + NA, NA, NA), + [107] = PINGROUP(107, NORTH, uim2_reset, qup13, qup_l6, NA, NA, NA, NA, + NA, NA, NA), + [108] = PINGROUP(108, NORTH, uim2_present, qup13, NA, NA, NA, NA, NA, + NA, NA, NA), + [109] = PINGROUP(109, NORTH, uim1_data, NA, NA, NA, NA, NA, NA, NA, NA, + NA), + [110] = PINGROUP(110, NORTH, uim1_clk, NA, NA, NA, NA, NA, NA, NA, NA, + NA), + [111] = PINGROUP(111, NORTH, uim1_reset, NA, NA, NA, NA, NA, NA, NA, + NA, NA), + [112] = PINGROUP(112, NORTH, uim1_present, NA, NA, NA, NA, NA, NA, NA, + NA, NA), + [113] = PINGROUP(113, NORTH, uim_batt, edp_hot, NA, NA, NA, NA, NA, NA, + NA, NA), + [114] = PINGROUP(114, NORTH, NA, nav_pps, nav_pps, NA, NA, NA, NA, NA, + NA, NA), + [115] = PINGROUP(115, NORTH, NA, nav_pps, nav_pps, NA, NA, NA, NA, NA, + NA, NA), + [116] = PINGROUP(116, NORTH, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [117] = PINGROUP(117, NORTH, NA, qdss_gpio0, atest_char, NA, NA, NA, + NA, NA, NA, NA), + [118] = PINGROUP(118, NORTH, adsp_ext, NA, qdss_gpio1, atest_char3, NA, + NA, NA, NA, NA, NA), + [119] = PINGROUP(119, NORTH, NA, qdss_gpio2, atest_char2, NA, NA, NA, + NA, NA, NA, NA), + [120] = PINGROUP(120, NORTH, NA, qdss_gpio3, atest_char1, NA, NA, NA, + NA, NA, NA, NA), + [121] = PINGROUP(121, NORTH, NA, qdss_gpio4, atest_char0, NA, NA, NA, + NA, NA, NA, NA), + [122] = PINGROUP(122, EAST, NA, qdss_gpio5, NA, NA, NA, NA, NA, NA, NA, + NA), + [123] = PINGROUP(123, EAST, qup_l4, NA, qdss_gpio, NA, NA, NA, NA, NA, + NA, NA), + [124] = PINGROUP(124, EAST, qup_l5, NA, qdss_gpio, NA, NA, NA, NA, NA, + NA, NA), + [125] = PINGROUP(125, EAST, qup_l6, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [126] = PINGROUP(126, EAST, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [127] = PINGROUP(127, NORTH, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [128] = PINGROUP(128, NORTH, nav_pps, nav_pps, NA, NA, NA, NA, NA, NA, + NA, NA), + [129] = PINGROUP(129, NORTH, nav_pps, nav_pps, NA, NA, NA, NA, NA, NA, + NA, NA), + [130] = PINGROUP(130, NORTH, qlink_request, NA, NA, NA, NA, NA, NA, NA, + NA, NA), + [131] = PINGROUP(131, NORTH, qlink_enable, NA, NA, NA, NA, NA, NA, NA, + NA, NA), + [132] = PINGROUP(132, NORTH, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [133] = PINGROUP(133, NORTH, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [134] = PINGROUP(134, NORTH, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [135] = PINGROUP(135, NORTH, NA, pa_indicator, NA, NA, NA, NA, NA, NA, + NA, NA), + [136] = PINGROUP(136, NORTH, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [137] = PINGROUP(137, NORTH, NA, NA, phase_flag26, NA, NA, NA, NA, NA, + NA, NA), + [138] = PINGROUP(138, NORTH, NA, NA, phase_flag27, NA, NA, NA, NA, NA, + NA, NA), + [139] = PINGROUP(139, NORTH, NA, phase_flag28, NA, NA, NA, NA, NA, NA, + NA, NA), + [140] = PINGROUP(140, NORTH, NA, NA, phase_flag6, NA, NA, NA, NA, NA, + NA, NA), + [141] = PINGROUP(141, NORTH, NA, phase_flag29, NA, NA, NA, NA, NA, NA, + NA, NA), + [142] = PINGROUP(142, NORTH, NA, phase_flag30, NA, NA, NA, NA, NA, NA, + NA, NA), + [143] = PINGROUP(143, NORTH, NA, nav_pps, nav_pps, NA, phase_flag31, + NA, NA, NA, NA, NA), + [144] = PINGROUP(144, NORTH, mss_lte, NA, NA, NA, NA, NA, NA, NA, NA, + NA), + [145] = PINGROUP(145, NORTH, mss_lte, NA, NA, NA, NA, NA, NA, NA, NA, + NA), + [146] = PINGROUP(146, NORTH, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [147] = PINGROUP(147, NORTH, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [148] = PINGROUP(148, NORTH, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [149] = PINGROUP(149, NORTH, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [150] = SDC_QDSD_PINGROUP(sdc2_clk, 0x99a000, 14, 6), + [151] = SDC_QDSD_PINGROUP(sdc2_cmd, 0x99a000, 11, 3), + [152] = SDC_QDSD_PINGROUP(sdc2_data, 0x99a000, 9, 0), + [153] = UFS_RESET(ufs_reset, 0x99f000), +}; + +static struct msm_dir_conn sdm845_dir_conn[] = { + {1, 510}, + {3, 511}, + {5, 512}, + {10, 513}, + {11, 514}, + {20, 515}, + {22, 516}, + {24, 517}, + {26, 518}, + {30, 519}, + {31, 632}, + {32, 521}, + {34, 522}, + {36, 523}, + {37, 524}, + {38, 525}, + {39, 526}, + {40, 527}, + {41, 630}, + {43, 529}, + {44, 530}, + {46, 531}, + {48, 532}, + {49, 633 }, + {52, 534}, + {53, 535}, + {54, 536}, + {56, 537}, + {57, 538}, + {58, 539}, + {59, 540}, + {60, 541}, + {61, 542}, + {62, 543}, + {63, 544}, + {64, 545}, + {66, 546}, + {68, 547}, + {71, 548}, + {73, 549}, + {77, 550}, + {78, 551}, + {79, 552}, + {80, 553}, + {84, 554}, + {85, 555}, + {86, 556}, + {88, 557}, + {89, 631}, + {91, 559}, + {92, 560}, + {95, 561}, + {96, 562}, + {97, 563}, + {101, 564}, + {103, 565}, + {108, 567}, + {112, 568}, + {113, 569}, + {104, 566}, + {115, 570}, + {116, 571}, + {117, 572}, + {118, 573}, + {119, 609}, + {120, 610}, + {121, 611}, + {122, 612}, + {123, 613}, + {124, 614}, + {125, 615}, + {126, 616}, + {127, 617}, + {128, 618}, + {129, 619}, + {130, 620}, + {132, 621}, + {133, 622}, + {145, 623}, + {0, 216}, + {0, 215}, + {0, 214}, + {0, 213}, + {0, 212}, + {0, 211}, + {0, 210}, + {0, 209}, +}; + +static const struct msm_pinctrl_soc_data sdm845_pinctrl = { + .pins = sdm845_pins, + .npins = ARRAY_SIZE(sdm845_pins), + .functions = sdm845_functions, + .nfunctions = ARRAY_SIZE(sdm845_functions), + .groups = sdm845_groups, + .ngroups = ARRAY_SIZE(sdm845_groups), + .ngpios = 150, + .dir_conn = sdm845_dir_conn, + .n_dir_conns = ARRAY_SIZE(sdm845_dir_conn), + .dir_conn_irq_base = 216, +}; + +static int sdm845_pinctrl_probe(struct platform_device *pdev) +{ + return msm_pinctrl_probe(pdev, &sdm845_pinctrl); +} + +static const struct of_device_id sdm845_pinctrl_of_match[] = { + { .compatible = "qcom,sdm845-pinctrl-v2", }, + { }, +}; + +static struct platform_driver sdm845_pinctrl_driver = { + .driver = { + .name = "sdm845-v2-pinctrl", + .owner = THIS_MODULE, + .of_match_table = sdm845_pinctrl_of_match, + }, + .probe = sdm845_pinctrl_probe, + .remove = msm_pinctrl_remove, +}; + +static int __init sdm845_pinctrl_init(void) +{ + return platform_driver_register(&sdm845_pinctrl_driver); +} +arch_initcall(sdm845_pinctrl_init); + +static void __exit sdm845_pinctrl_exit(void) +{ + platform_driver_unregister(&sdm845_pinctrl_driver); +} +module_exit(sdm845_pinctrl_exit); + +MODULE_DESCRIPTION("QTI sdm845-v2 pinctrl driver"); +MODULE_LICENSE("GPL v2"); +MODULE_DEVICE_TABLE(of, sdm845_pinctrl_of_match); diff --git a/drivers/pinctrl/qcom/pinctrl-sdm845.c b/drivers/pinctrl/qcom/pinctrl-sdm845.c index 2ab7a8885757..ee5bd19c2618 100644 --- a/drivers/pinctrl/qcom/pinctrl-sdm845.c +++ b/drivers/pinctrl/qcom/pinctrl-sdm845.c @@ -1,6 +1,14 @@ -// SPDX-License-Identifier: GPL-2.0 /* - * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 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. */ #include @@ -19,13 +27,12 @@ #define NORTH 0x00500000 #define SOUTH 0x00900000 -#define EAST 0x00100000 #define REG_SIZE 0x1000 #define PINGROUP(id, base, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10) \ { \ .name = "gpio" #id, \ .pins = gpio##id##_pins, \ - .npins = ARRAY_SIZE(gpio##id##_pins), \ + .npins = (unsigned int)ARRAY_SIZE(gpio##id##_pins), \ .funcs = (int[]){ \ msm_mux_gpio, /* gpio mode */ \ msm_mux_##f1, \ @@ -45,6 +52,8 @@ .intr_cfg_reg = base + 0x8 + REG_SIZE * id, \ .intr_status_reg = base + 0xc + REG_SIZE * id, \ .intr_target_reg = base + 0x8 + REG_SIZE * id, \ + .dir_conn_reg = (base == NORTH) ? base + 0xa5000 :\ + base + 0xa8000, \ .mux_bit = 2, \ .pull_bit = 0, \ .drv_bit = 6, \ @@ -59,13 +68,14 @@ .intr_polarity_bit = 1, \ .intr_detection_bit = 2, \ .intr_detection_width = 2, \ + .dir_conn_en_bit = 8, \ } #define SDC_QDSD_PINGROUP(pg_name, ctl, pull, drv) \ { \ .name = #pg_name, \ .pins = pg_name##_pins, \ - .npins = ARRAY_SIZE(pg_name##_pins), \ + .npins = (unsigned int)ARRAY_SIZE(pg_name##_pins), \ .ctl_reg = ctl, \ .io_reg = 0, \ .intr_cfg_reg = 0, \ @@ -90,7 +100,7 @@ { \ .name = #pg_name, \ .pins = pg_name##_pins, \ - .npins = ARRAY_SIZE(pg_name##_pins), \ + .npins = (unsigned int)ARRAY_SIZE(pg_name##_pins), \ .ctl_reg = offset, \ .io_reg = offset + 0x4, \ .intr_cfg_reg = 0, \ @@ -110,6 +120,7 @@ .intr_detection_bit = -1, \ .intr_detection_width = -1, \ } + static const struct pinctrl_pin_desc sdm845_pins[] = { PINCTRL_PIN(0, "GPIO_0"), PINCTRL_PIN(1, "GPIO_1"), @@ -426,136 +437,187 @@ static const unsigned int sdc2_data_pins[] = { 152 }; static const unsigned int ufs_reset_pins[] = { 153 }; enum sdm845_functions { - msm_mux_gpio, - msm_mux_adsp_ext, - msm_mux_agera_pll, - msm_mux_atest_char, - msm_mux_atest_tsens, - msm_mux_atest_tsens2, - msm_mux_atest_usb1, - msm_mux_atest_usb10, - msm_mux_atest_usb11, - msm_mux_atest_usb12, - msm_mux_atest_usb13, - msm_mux_atest_usb2, - msm_mux_atest_usb20, - msm_mux_atest_usb21, - msm_mux_atest_usb22, - msm_mux_atest_usb23, - msm_mux_audio_ref, - msm_mux_btfm_slimbus, + msm_mux_ddr_pxi3, msm_mux_cam_mclk, - msm_mux_cci_async, + msm_mux_pll_bypassnl, + msm_mux_qdss_gpio0, + msm_mux_pll_reset, + msm_mux_qdss_gpio1, + msm_mux_qdss_gpio2, + msm_mux_qdss_gpio3, msm_mux_cci_i2c, + msm_mux_qup1, + msm_mux_qdss_gpio4, + msm_mux_qdss_gpio5, + msm_mux_qdss_gpio6, + msm_mux_qdss_gpio7, msm_mux_cci_timer0, + msm_mux_gcc_gp2, + msm_mux_qdss_gpio8, msm_mux_cci_timer1, + msm_mux_gcc_gp3, + msm_mux_qdss_gpio, msm_mux_cci_timer2, + msm_mux_qdss_gpio9, msm_mux_cci_timer3, + msm_mux_cci_async, + msm_mux_qdss_gpio10, msm_mux_cci_timer4, - msm_mux_cri_trng, - msm_mux_cri_trng0, - msm_mux_cri_trng1, - msm_mux_dbg_out, - msm_mux_ddr_bist, - msm_mux_ddr_pxi0, - msm_mux_ddr_pxi1, - msm_mux_ddr_pxi2, - msm_mux_ddr_pxi3, - msm_mux_edp_hot, - msm_mux_edp_lcd, - msm_mux_gcc_gp1, - msm_mux_gcc_gp2, - msm_mux_gcc_gp3, - msm_mux_jitter_bist, - msm_mux_ldo_en, - msm_mux_ldo_update, - msm_mux_lpass_slimbus, - msm_mux_m_voc, - msm_mux_mdp_vsync, - msm_mux_mdp_vsync0, - msm_mux_mdp_vsync1, - msm_mux_mdp_vsync2, - msm_mux_mdp_vsync3, - msm_mux_mss_lte, - msm_mux_nav_pps, - msm_mux_pa_indicator, - msm_mux_pci_e0, - msm_mux_pci_e1, - msm_mux_phase_flag, - msm_mux_pll_bist, - msm_mux_pll_bypassnl, - msm_mux_pll_reset, - msm_mux_pri_mi2s, - msm_mux_pri_mi2s_ws, - msm_mux_prng_rosc, - msm_mux_qdss_cti, - msm_mux_qdss, - msm_mux_qlink_enable, - msm_mux_qlink_request, - msm_mux_qspi_clk, - msm_mux_qspi_cs, - msm_mux_qspi_data, - msm_mux_qua_mi2s, - msm_mux_qup0, - msm_mux_qup1, - msm_mux_qup10, + msm_mux_qdss_gpio11, + msm_mux_qdss_gpio12, + msm_mux_qup2, + msm_mux_qdss_gpio13, + msm_mux_qdss_gpio14, + msm_mux_phase_flag1, + msm_mux_qdss_gpio15, + msm_mux_phase_flag2, msm_mux_qup11, - msm_mux_qup12, - msm_mux_qup13, msm_mux_qup14, - msm_mux_qup15, - msm_mux_qup2, + msm_mux_pci_e0, + msm_mux_jitter_bist, + msm_mux_pll_bist, + msm_mux_atest_tsens, + msm_mux_agera_pll, + msm_mux_usb_phy, + msm_mux_lpass_slimbus, + msm_mux_sd_write, + msm_mux_tsif1_error, msm_mux_qup3, - msm_mux_qup4, - msm_mux_qup5, msm_mux_qup6, - msm_mux_qup7, - msm_mux_qup8, - msm_mux_qup9, - msm_mux_qup_l4, - msm_mux_qup_l5, - msm_mux_qup_l6, - msm_mux_sd_write, - msm_mux_sdc4_clk, - msm_mux_sdc4_cmd, - msm_mux_sdc4_data, - msm_mux_sec_mi2s, + msm_mux_qup12, + msm_mux_phase_flag16, + msm_mux_qup10, + msm_mux_phase_flag11, + msm_mux_phase_flag12, + msm_mux_phase_flag13, + msm_mux_phase_flag17, + msm_mux_qua_mi2s, + msm_mux_gcc_gp1, + msm_mux_phase_flag18, + msm_mux_phase_flag19, + msm_mux_phase_flag20, + msm_mux_cri_trng0, + msm_mux_phase_flag21, + msm_mux_cri_trng1, + msm_mux_phase_flag22, + msm_mux_cri_trng, + msm_mux_phase_flag23, + msm_mux_phase_flag24, + msm_mux_pri_mi2s, msm_mux_sp_cmu, + msm_mux_phase_flag25, + msm_mux_qup8, + msm_mux_pri_mi2s_ws, msm_mux_spkr_i2s, - msm_mux_ter_mi2s, - msm_mux_tgu_ch0, - msm_mux_tgu_ch1, - msm_mux_tgu_ch2, - msm_mux_tgu_ch3, + msm_mux_audio_ref, msm_mux_tsense_pwm1, msm_mux_tsense_pwm2, + msm_mux_btfm_slimbus, + msm_mux_atest_usb2, + msm_mux_ter_mi2s, + msm_mux_phase_flag7, + msm_mux_atest_usb23, + msm_mux_phase_flag8, + msm_mux_atest_usb22, + msm_mux_phase_flag9, + msm_mux_atest_usb21, + msm_mux_phase_flag4, + msm_mux_atest_usb20, + msm_mux_sec_mi2s, + msm_mux_qup15, + msm_mux_qup5, msm_mux_tsif1_clk, - msm_mux_tsif1_data, + msm_mux_qup4, + msm_mux_tgu_ch3, + msm_mux_phase_flag10, msm_mux_tsif1_en, - msm_mux_tsif1_error, - msm_mux_tsif1_sync, + msm_mux_mdp_vsync0, + msm_mux_mdp_vsync1, + msm_mux_mdp_vsync2, + msm_mux_mdp_vsync3, + msm_mux_tgu_ch0, + msm_mux_phase_flag0, + msm_mux_tsif1_data, + msm_mux_sdc4_cmd, + msm_mux_tgu_ch1, + msm_mux_tsif2_error, + msm_mux_sdc43, + msm_mux_vfr_1, + msm_mux_tgu_ch2, msm_mux_tsif2_clk, - msm_mux_tsif2_data, + msm_mux_sdc4_clk, + msm_mux_qup7, msm_mux_tsif2_en, - msm_mux_tsif2_error, + msm_mux_sdc42, + msm_mux_tsif2_data, + msm_mux_sdc41, msm_mux_tsif2_sync, - msm_mux_uim1_clk, - msm_mux_uim1_data, - msm_mux_uim1_present, - msm_mux_uim1_reset, - msm_mux_uim2_clk, + msm_mux_sdc40, + msm_mux_phase_flag3, + msm_mux_ldo_en, + msm_mux_ldo_update, + msm_mux_phase_flag14, + msm_mux_phase_flag15, + msm_mux_pci_e1, + msm_mux_prng_rosc, + msm_mux_phase_flag5, msm_mux_uim2_data, - msm_mux_uim2_present, + msm_mux_qup13, + msm_mux_uim2_clk, msm_mux_uim2_reset, + msm_mux_uim2_present, + msm_mux_uim1_data, + msm_mux_uim1_clk, + msm_mux_uim1_reset, + msm_mux_uim1_present, msm_mux_uim_batt, - msm_mux_usb_phy, - msm_mux_vfr_1, + msm_mux_edp_hot, + msm_mux_nav_pps, + msm_mux_atest_char, + msm_mux_adsp_ext, + msm_mux_atest_char3, + msm_mux_atest_char2, + msm_mux_atest_char1, + msm_mux_atest_char0, + msm_mux_qlink_request, + msm_mux_qlink_enable, + msm_mux_pa_indicator, + msm_mux_phase_flag26, + msm_mux_phase_flag27, + msm_mux_phase_flag28, + msm_mux_phase_flag6, + msm_mux_phase_flag29, + msm_mux_phase_flag30, + msm_mux_phase_flag31, + msm_mux_mss_lte, + msm_mux_qup0, + msm_mux_gpio, + msm_mux_qup9, + msm_mux_qdss_cti, + msm_mux_ddr_pxi0, + msm_mux_ddr_bist, + msm_mux_atest_tsens2, msm_mux_vsense_trigger, - msm_mux_wlan1_adc0, + msm_mux_atest_usb1, + msm_mux_qup_l4, msm_mux_wlan1_adc1, - msm_mux_wlan2_adc0, + msm_mux_atest_usb13, + msm_mux_ddr_pxi1, + msm_mux_qup_l5, + msm_mux_wlan1_adc0, + msm_mux_atest_usb12, + msm_mux_mdp_vsync, + msm_mux_qup_l6, msm_mux_wlan2_adc1, - msm_mux__, + msm_mux_atest_usb11, + msm_mux_ddr_pxi2, + msm_mux_edp_lcd, + msm_mux_dbg_out, + msm_mux_wlan2_adc0, + msm_mux_atest_usb10, + msm_mux_m_voc, + msm_mux_tsif1_sync, + msm_mux_NA, }; static const char * const ddr_pxi3_groups[] = { @@ -567,56 +629,98 @@ static const char * const cam_mclk_groups[] = { static const char * const pll_bypassnl_groups[] = { "gpio13", }; -static const char * const qdss_groups[] = { - "gpio13", "gpio14", "gpio15", "gpio16", "gpio17", "gpio18", "gpio19", - "gpio20", "gpio21", "gpio22", "gpio23", "gpio24", "gpio25", "gpio26", - "gpio27", "gpio28", "gpio29", "gpio30", "gpio41", "gpio42", "gpio43", - "gpio44", "gpio75", "gpio76", "gpio77", "gpio79", "gpio80", "gpio93", - "gpio117", "gpio118", "gpio119", "gpio120", "gpio121", "gpio122", - "gpio123", "gpio124", +static const char * const qdss_gpio0_groups[] = { + "gpio13", "gpio117", }; static const char * const pll_reset_groups[] = { "gpio14", }; +static const char * const qdss_gpio1_groups[] = { + "gpio14", "gpio118", +}; +static const char * const qdss_gpio2_groups[] = { + "gpio15", "gpio119", +}; +static const char * const qdss_gpio3_groups[] = { + "gpio16", "gpio120", +}; static const char * const cci_i2c_groups[] = { "gpio17", "gpio18", "gpio19", "gpio20", }; static const char * const qup1_groups[] = { "gpio17", "gpio18", "gpio19", "gpio20", }; +static const char * const qdss_gpio4_groups[] = { + "gpio17", "gpio121", +}; +static const char * const qdss_gpio5_groups[] = { + "gpio18", "gpio122", +}; +static const char * const qdss_gpio6_groups[] = { + "gpio19", "gpio41", +}; +static const char * const qdss_gpio7_groups[] = { + "gpio20", "gpio42", +}; static const char * const cci_timer0_groups[] = { "gpio21", }; static const char * const gcc_gp2_groups[] = { "gpio21", "gpio58", }; +static const char * const qdss_gpio8_groups[] = { + "gpio21", "gpio75", +}; static const char * const cci_timer1_groups[] = { "gpio22", }; static const char * const gcc_gp3_groups[] = { "gpio22", "gpio59", }; +static const char * const qdss_gpio_groups[] = { + "gpio22", "gpio30", "gpio123", "gpio124", +}; static const char * const cci_timer2_groups[] = { "gpio23", }; +static const char * const qdss_gpio9_groups[] = { + "gpio23", "gpio76", +}; static const char * const cci_timer3_groups[] = { "gpio24", }; static const char * const cci_async_groups[] = { "gpio24", "gpio25", "gpio26", }; +static const char * const qdss_gpio10_groups[] = { + "gpio24", "gpio77", +}; static const char * const cci_timer4_groups[] = { "gpio25", }; +static const char * const qdss_gpio11_groups[] = { + "gpio25", "gpio79", +}; +static const char * const qdss_gpio12_groups[] = { + "gpio26", "gpio80", +}; static const char * const qup2_groups[] = { "gpio27", "gpio28", "gpio29", "gpio30", }; -static const char * const phase_flag_groups[] = { - "gpio29", "gpio30", "gpio52", "gpio53", "gpio54", "gpio55", "gpio56", - "gpio57", "gpio58", "gpio59", "gpio60", "gpio61", "gpio62", "gpio63", - "gpio64", "gpio74", "gpio75", "gpio76", "gpio77", "gpio89", "gpio90", - "gpio96", "gpio99", "gpio100", "gpio103", "gpio137", "gpio138", - "gpio139", "gpio140", "gpio141", "gpio142", "gpio143", +static const char * const qdss_gpio13_groups[] = { + "gpio27", "gpio93", +}; +static const char * const qdss_gpio14_groups[] = { + "gpio28", "gpio43", +}; +static const char * const phase_flag1_groups[] = { + "gpio29", +}; +static const char * const qdss_gpio15_groups[] = { + "gpio29", "gpio44", +}; +static const char * const phase_flag2_groups[] = { + "gpio30", }; static const char * const qup11_groups[] = { "gpio31", "gpio32", "gpio33", "gpio34", @@ -660,30 +764,69 @@ static const char * const qup6_groups[] = { static const char * const qup12_groups[] = { "gpio49", "gpio50", "gpio51", "gpio52", }; +static const char * const phase_flag16_groups[] = { + "gpio52", +}; static const char * const qup10_groups[] = { "gpio53", "gpio54", "gpio55", "gpio56", }; +static const char * const phase_flag11_groups[] = { + "gpio53", +}; +static const char * const phase_flag12_groups[] = { + "gpio54", +}; +static const char * const phase_flag13_groups[] = { + "gpio55", +}; +static const char * const phase_flag17_groups[] = { + "gpio56", +}; static const char * const qua_mi2s_groups[] = { "gpio57", "gpio58", "gpio59", "gpio60", "gpio61", "gpio62", "gpio63", }; static const char * const gcc_gp1_groups[] = { "gpio57", "gpio78", }; +static const char * const phase_flag18_groups[] = { + "gpio57", +}; +static const char * const phase_flag19_groups[] = { + "gpio58", +}; +static const char * const phase_flag20_groups[] = { + "gpio59", +}; static const char * const cri_trng0_groups[] = { "gpio60", }; +static const char * const phase_flag21_groups[] = { + "gpio60", +}; static const char * const cri_trng1_groups[] = { "gpio61", }; +static const char * const phase_flag22_groups[] = { + "gpio61", +}; static const char * const cri_trng_groups[] = { "gpio62", }; +static const char * const phase_flag23_groups[] = { + "gpio62", +}; +static const char * const phase_flag24_groups[] = { + "gpio63", +}; static const char * const pri_mi2s_groups[] = { "gpio64", "gpio65", "gpio67", "gpio68", }; static const char * const sp_cmu_groups[] = { "gpio64", }; +static const char * const phase_flag25_groups[] = { + "gpio64", +}; static const char * const qup8_groups[] = { "gpio65", "gpio66", "gpio67", "gpio68", }; @@ -711,15 +854,27 @@ static const char * const atest_usb2_groups[] = { static const char * const ter_mi2s_groups[] = { "gpio74", "gpio75", "gpio76", "gpio77", "gpio78", }; +static const char * const phase_flag7_groups[] = { + "gpio74", +}; static const char * const atest_usb23_groups[] = { "gpio74", }; +static const char * const phase_flag8_groups[] = { + "gpio75", +}; static const char * const atest_usb22_groups[] = { "gpio75", }; +static const char * const phase_flag9_groups[] = { + "gpio76", +}; static const char * const atest_usb21_groups[] = { "gpio76", }; +static const char * const phase_flag4_groups[] = { + "gpio77", +}; static const char * const atest_usb20_groups[] = { "gpio77", }; @@ -738,12 +893,12 @@ static const char * const tsif1_clk_groups[] = { static const char * const qup4_groups[] = { "gpio89", "gpio90", "gpio91", "gpio92", }; -static const char * const qspi_cs_groups[] = { - "gpio89", "gpio90", -}; static const char * const tgu_ch3_groups[] = { "gpio89", }; +static const char * const phase_flag10_groups[] = { + "gpio89", +}; static const char * const tsif1_en_groups[] = { "gpio90", }; @@ -762,26 +917,23 @@ static const char * const mdp_vsync3_groups[] = { static const char * const tgu_ch0_groups[] = { "gpio90", }; +static const char * const phase_flag0_groups[] = { + "gpio90", +}; static const char * const tsif1_data_groups[] = { "gpio91", }; static const char * const sdc4_cmd_groups[] = { "gpio91", }; -static const char * const qspi_data_groups[] = { - "gpio91", "gpio92", "gpio93", "gpio94", -}; static const char * const tgu_ch1_groups[] = { "gpio91", }; static const char * const tsif2_error_groups[] = { "gpio92", }; -static const char * const sdc4_data_groups[] = { +static const char * const sdc43_groups[] = { "gpio92", - "gpio94", - "gpio95", - "gpio96", }; static const char * const vfr_1_groups[] = { "gpio92", @@ -801,27 +953,45 @@ static const char * const qup7_groups[] = { static const char * const tsif2_en_groups[] = { "gpio94", }; +static const char * const sdc42_groups[] = { + "gpio94", +}; static const char * const tsif2_data_groups[] = { "gpio95", }; -static const char * const qspi_clk_groups[] = { +static const char * const sdc41_groups[] = { "gpio95", }; static const char * const tsif2_sync_groups[] = { "gpio96", }; +static const char * const sdc40_groups[] = { + "gpio96", +}; +static const char * const phase_flag3_groups[] = { + "gpio96", +}; static const char * const ldo_en_groups[] = { "gpio97", }; static const char * const ldo_update_groups[] = { "gpio98", }; +static const char * const phase_flag14_groups[] = { + "gpio99", +}; +static const char * const phase_flag15_groups[] = { + "gpio100", +}; static const char * const pci_e1_groups[] = { "gpio102", "gpio103", }; static const char * const prng_rosc_groups[] = { "gpio102", }; +static const char * const phase_flag5_groups[] = { + "gpio103", +}; static const char * const uim2_data_groups[] = { "gpio105", }; @@ -860,11 +1030,23 @@ static const char * const nav_pps_groups[] = { "gpio129", "gpio129", "gpio143", "gpio143", }; static const char * const atest_char_groups[] = { - "gpio117", "gpio118", "gpio119", "gpio120", "gpio121", + "gpio117", }; static const char * const adsp_ext_groups[] = { "gpio118", }; +static const char * const atest_char3_groups[] = { + "gpio118", +}; +static const char * const atest_char2_groups[] = { + "gpio119", +}; +static const char * const atest_char1_groups[] = { + "gpio120", +}; +static const char * const atest_char0_groups[] = { + "gpio121", +}; static const char * const qlink_request_groups[] = { "gpio130", }; @@ -874,6 +1056,27 @@ static const char * const qlink_enable_groups[] = { static const char * const pa_indicator_groups[] = { "gpio135", }; +static const char * const phase_flag26_groups[] = { + "gpio137", +}; +static const char * const phase_flag27_groups[] = { + "gpio138", +}; +static const char * const phase_flag28_groups[] = { + "gpio139", +}; +static const char * const phase_flag6_groups[] = { + "gpio140", +}; +static const char * const phase_flag29_groups[] = { + "gpio141", +}; +static const char * const phase_flag30_groups[] = { + "gpio142", +}; +static const char * const phase_flag31_groups[] = { + "gpio143", +}; static const char * const mss_lte_groups[] = { "gpio144", "gpio145", }; @@ -983,135 +1186,186 @@ static const char * const tsif1_sync_groups[] = { }; static const struct msm_function sdm845_functions[] = { - FUNCTION(gpio), - FUNCTION(adsp_ext), - FUNCTION(agera_pll), - FUNCTION(atest_char), - FUNCTION(atest_tsens), - FUNCTION(atest_tsens2), - FUNCTION(atest_usb1), - FUNCTION(atest_usb10), - FUNCTION(atest_usb11), - FUNCTION(atest_usb12), - FUNCTION(atest_usb13), - FUNCTION(atest_usb2), - FUNCTION(atest_usb20), - FUNCTION(atest_usb21), - FUNCTION(atest_usb22), - FUNCTION(atest_usb23), - FUNCTION(audio_ref), - FUNCTION(btfm_slimbus), + FUNCTION(ddr_pxi3), FUNCTION(cam_mclk), - FUNCTION(cci_async), + FUNCTION(pll_bypassnl), + FUNCTION(qdss_gpio0), + FUNCTION(pll_reset), + FUNCTION(qdss_gpio1), + FUNCTION(qdss_gpio2), + FUNCTION(qdss_gpio3), FUNCTION(cci_i2c), + FUNCTION(qup1), + FUNCTION(qdss_gpio4), + FUNCTION(qdss_gpio5), + FUNCTION(qdss_gpio6), + FUNCTION(qdss_gpio7), FUNCTION(cci_timer0), + FUNCTION(gcc_gp2), + FUNCTION(qdss_gpio8), FUNCTION(cci_timer1), + FUNCTION(gcc_gp3), + FUNCTION(qdss_gpio), FUNCTION(cci_timer2), + FUNCTION(qdss_gpio9), FUNCTION(cci_timer3), + FUNCTION(cci_async), + FUNCTION(qdss_gpio10), FUNCTION(cci_timer4), - FUNCTION(cri_trng), - FUNCTION(cri_trng0), - FUNCTION(cri_trng1), - FUNCTION(dbg_out), - FUNCTION(ddr_bist), - FUNCTION(ddr_pxi0), - FUNCTION(ddr_pxi1), - FUNCTION(ddr_pxi2), - FUNCTION(ddr_pxi3), - FUNCTION(edp_hot), - FUNCTION(edp_lcd), - FUNCTION(gcc_gp1), - FUNCTION(gcc_gp2), - FUNCTION(gcc_gp3), - FUNCTION(jitter_bist), - FUNCTION(ldo_en), - FUNCTION(ldo_update), - FUNCTION(lpass_slimbus), - FUNCTION(m_voc), - FUNCTION(mdp_vsync), - FUNCTION(mdp_vsync0), - FUNCTION(mdp_vsync1), - FUNCTION(mdp_vsync2), - FUNCTION(mdp_vsync3), - FUNCTION(mss_lte), - FUNCTION(nav_pps), - FUNCTION(pa_indicator), - FUNCTION(pci_e0), - FUNCTION(pci_e1), - FUNCTION(phase_flag), - FUNCTION(pll_bist), - FUNCTION(pll_bypassnl), - FUNCTION(pll_reset), - FUNCTION(pri_mi2s), - FUNCTION(pri_mi2s_ws), - FUNCTION(prng_rosc), - FUNCTION(qdss_cti), - FUNCTION(qdss), - FUNCTION(qlink_enable), - FUNCTION(qlink_request), - FUNCTION(qspi_clk), - FUNCTION(qspi_cs), - FUNCTION(qspi_data), - FUNCTION(qua_mi2s), - FUNCTION(qup0), - FUNCTION(qup1), - FUNCTION(qup10), + FUNCTION(qdss_gpio11), + FUNCTION(qdss_gpio12), + FUNCTION(qup2), + FUNCTION(qdss_gpio13), + FUNCTION(qdss_gpio14), + FUNCTION(phase_flag1), + FUNCTION(qdss_gpio15), + FUNCTION(phase_flag2), FUNCTION(qup11), - FUNCTION(qup12), - FUNCTION(qup13), FUNCTION(qup14), - FUNCTION(qup15), - FUNCTION(qup2), + FUNCTION(pci_e0), + FUNCTION(jitter_bist), + FUNCTION(pll_bist), + FUNCTION(atest_tsens), + FUNCTION(agera_pll), + FUNCTION(usb_phy), + FUNCTION(lpass_slimbus), + FUNCTION(sd_write), + FUNCTION(tsif1_error), FUNCTION(qup3), - FUNCTION(qup4), - FUNCTION(qup5), FUNCTION(qup6), - FUNCTION(qup7), - FUNCTION(qup8), - FUNCTION(qup9), - FUNCTION(qup_l4), - FUNCTION(qup_l5), - FUNCTION(qup_l6), - FUNCTION(sd_write), - FUNCTION(sdc4_clk), - FUNCTION(sdc4_cmd), - FUNCTION(sdc4_data), - FUNCTION(sec_mi2s), + FUNCTION(qup12), + FUNCTION(phase_flag16), + FUNCTION(qup10), + FUNCTION(phase_flag11), + FUNCTION(phase_flag12), + FUNCTION(phase_flag13), + FUNCTION(phase_flag17), + FUNCTION(qua_mi2s), + FUNCTION(gcc_gp1), + FUNCTION(phase_flag18), + FUNCTION(phase_flag19), + FUNCTION(phase_flag20), + FUNCTION(cri_trng0), + FUNCTION(phase_flag21), + FUNCTION(cri_trng1), + FUNCTION(phase_flag22), + FUNCTION(cri_trng), + FUNCTION(phase_flag23), + FUNCTION(phase_flag24), + FUNCTION(pri_mi2s), FUNCTION(sp_cmu), + FUNCTION(phase_flag25), + FUNCTION(qup8), + FUNCTION(pri_mi2s_ws), FUNCTION(spkr_i2s), - FUNCTION(ter_mi2s), - FUNCTION(tgu_ch0), - FUNCTION(tgu_ch1), - FUNCTION(tgu_ch2), - FUNCTION(tgu_ch3), + FUNCTION(audio_ref), FUNCTION(tsense_pwm1), FUNCTION(tsense_pwm2), + FUNCTION(btfm_slimbus), + FUNCTION(atest_usb2), + FUNCTION(ter_mi2s), + FUNCTION(phase_flag7), + FUNCTION(atest_usb23), + FUNCTION(phase_flag8), + FUNCTION(atest_usb22), + FUNCTION(phase_flag9), + FUNCTION(atest_usb21), + FUNCTION(phase_flag4), + FUNCTION(atest_usb20), + FUNCTION(sec_mi2s), + FUNCTION(qup15), + FUNCTION(qup5), FUNCTION(tsif1_clk), - FUNCTION(tsif1_data), + FUNCTION(qup4), + FUNCTION(tgu_ch3), + FUNCTION(phase_flag10), FUNCTION(tsif1_en), - FUNCTION(tsif1_error), - FUNCTION(tsif1_sync), + FUNCTION(mdp_vsync0), + FUNCTION(mdp_vsync1), + FUNCTION(mdp_vsync2), + FUNCTION(mdp_vsync3), + FUNCTION(tgu_ch0), + FUNCTION(phase_flag0), + FUNCTION(tsif1_data), + FUNCTION(sdc4_cmd), + FUNCTION(tgu_ch1), + FUNCTION(tsif2_error), + FUNCTION(sdc43), + FUNCTION(vfr_1), + FUNCTION(tgu_ch2), FUNCTION(tsif2_clk), - FUNCTION(tsif2_data), + FUNCTION(sdc4_clk), + FUNCTION(qup7), FUNCTION(tsif2_en), - FUNCTION(tsif2_error), + FUNCTION(sdc42), + FUNCTION(tsif2_data), + FUNCTION(sdc41), FUNCTION(tsif2_sync), - FUNCTION(uim1_clk), - FUNCTION(uim1_data), - FUNCTION(uim1_present), - FUNCTION(uim1_reset), - FUNCTION(uim2_clk), + FUNCTION(sdc40), + FUNCTION(phase_flag3), + FUNCTION(ldo_en), + FUNCTION(ldo_update), + FUNCTION(phase_flag14), + FUNCTION(phase_flag15), + FUNCTION(pci_e1), + FUNCTION(prng_rosc), + FUNCTION(phase_flag5), FUNCTION(uim2_data), - FUNCTION(uim2_present), + FUNCTION(qup13), + FUNCTION(uim2_clk), FUNCTION(uim2_reset), + FUNCTION(uim2_present), + FUNCTION(uim1_data), + FUNCTION(uim1_clk), + FUNCTION(uim1_reset), + FUNCTION(uim1_present), FUNCTION(uim_batt), - FUNCTION(usb_phy), - FUNCTION(vfr_1), + FUNCTION(edp_hot), + FUNCTION(nav_pps), + FUNCTION(atest_char), + FUNCTION(adsp_ext), + FUNCTION(atest_char3), + FUNCTION(atest_char2), + FUNCTION(atest_char1), + FUNCTION(atest_char0), + FUNCTION(qlink_request), + FUNCTION(qlink_enable), + FUNCTION(pa_indicator), + FUNCTION(phase_flag26), + FUNCTION(phase_flag27), + FUNCTION(phase_flag28), + FUNCTION(phase_flag6), + FUNCTION(phase_flag29), + FUNCTION(phase_flag30), + FUNCTION(phase_flag31), + FUNCTION(mss_lte), + FUNCTION(qup0), + FUNCTION(gpio), + FUNCTION(qup9), + FUNCTION(qdss_cti), + FUNCTION(ddr_pxi0), + FUNCTION(ddr_bist), + FUNCTION(atest_tsens2), FUNCTION(vsense_trigger), - FUNCTION(wlan1_adc0), + FUNCTION(atest_usb1), + FUNCTION(qup_l4), FUNCTION(wlan1_adc1), - FUNCTION(wlan2_adc0), + FUNCTION(atest_usb13), + FUNCTION(ddr_pxi1), + FUNCTION(qup_l5), + FUNCTION(wlan1_adc0), + FUNCTION(atest_usb12), + FUNCTION(mdp_vsync), + FUNCTION(qup_l6), FUNCTION(wlan2_adc1), + FUNCTION(atest_usb11), + FUNCTION(ddr_pxi2), + FUNCTION(edp_lcd), + FUNCTION(dbg_out), + FUNCTION(wlan2_adc0), + FUNCTION(atest_usb10), + FUNCTION(m_voc), + FUNCTION(tsif1_sync), }; /* Every pin is maintained as a single group, and missing or non-existing pin @@ -1120,161 +1374,369 @@ static const struct msm_function sdm845_functions[] = { * Clients would not be able to request these dummy pin groups. */ static const struct msm_pingroup sdm845_groups[] = { - PINGROUP(0, EAST, qup0, _, _, _, _, _, _, _, _, _), - PINGROUP(1, EAST, qup0, _, _, _, _, _, _, _, _, _), - PINGROUP(2, EAST, qup0, _, _, _, _, _, _, _, _, _), - PINGROUP(3, EAST, qup0, _, _, _, _, _, _, _, _, _), - PINGROUP(4, NORTH, qup9, qdss_cti, _, _, _, _, _, _, _, _), - PINGROUP(5, NORTH, qup9, qdss_cti, _, _, _, _, _, _, _, _), - PINGROUP(6, NORTH, qup9, _, ddr_pxi0, _, _, _, _, _, _, _), - PINGROUP(7, NORTH, qup9, ddr_bist, _, atest_tsens2, vsense_trigger, atest_usb1, ddr_pxi0, _, _, _), - PINGROUP(8, EAST, qup_l4, _, ddr_bist, _, _, wlan1_adc1, atest_usb13, ddr_pxi1, _, _), - PINGROUP(9, EAST, qup_l5, ddr_bist, _, wlan1_adc0, atest_usb12, ddr_pxi1, _, _, _, _), - PINGROUP(10, EAST, mdp_vsync, qup_l6, ddr_bist, wlan2_adc1, atest_usb11, ddr_pxi2, _, _, _, _), - PINGROUP(11, EAST, mdp_vsync, edp_lcd, dbg_out, wlan2_adc0, atest_usb10, ddr_pxi2, _, _, _, _), - PINGROUP(12, SOUTH, mdp_vsync, m_voc, tsif1_sync, ddr_pxi3, _, _, _, _, _, _), - PINGROUP(13, SOUTH, cam_mclk, pll_bypassnl, qdss, ddr_pxi3, _, _, _, _, _, _), - PINGROUP(14, SOUTH, cam_mclk, pll_reset, qdss, _, _, _, _, _, _, _), - PINGROUP(15, SOUTH, cam_mclk, qdss, _, _, _, _, _, _, _, _), - PINGROUP(16, SOUTH, cam_mclk, qdss, _, _, _, _, _, _, _, _), - PINGROUP(17, SOUTH, cci_i2c, qup1, qdss, _, _, _, _, _, _, _), - PINGROUP(18, SOUTH, cci_i2c, qup1, _, qdss, _, _, _, _, _, _), - PINGROUP(19, SOUTH, cci_i2c, qup1, _, qdss, _, _, _, _, _, _), - PINGROUP(20, SOUTH, cci_i2c, qup1, _, qdss, _, _, _, _, _, _), - PINGROUP(21, SOUTH, cci_timer0, gcc_gp2, qdss, _, _, _, _, _, _, _), - PINGROUP(22, SOUTH, cci_timer1, gcc_gp3, qdss, _, _, _, _, _, _, _), - PINGROUP(23, SOUTH, cci_timer2, qdss, _, _, _, _, _, _, _, _), - PINGROUP(24, SOUTH, cci_timer3, cci_async, qdss, _, _, _, _, _, _, _), - PINGROUP(25, SOUTH, cci_timer4, cci_async, qdss, _, _, _, _, _, _, _), - PINGROUP(26, SOUTH, cci_async, qdss, _, _, _, _, _, _, _, _), - PINGROUP(27, EAST, qup2, qdss, _, _, _, _, _, _, _, _), - PINGROUP(28, EAST, qup2, qdss, _, _, _, _, _, _, _, _), - PINGROUP(29, EAST, qup2, _, phase_flag, qdss, _, _, _, _, _, _), - PINGROUP(30, EAST, qup2, phase_flag, qdss, _, _, _, _, _, _, _), - PINGROUP(31, NORTH, qup11, qup14, _, _, _, _, _, _, _, _), - PINGROUP(32, NORTH, qup11, qup14, _, _, _, _, _, _, _, _), - PINGROUP(33, NORTH, qup11, qup14, _, _, _, _, _, _, _, _), - PINGROUP(34, NORTH, qup11, qup14, _, _, _, _, _, _, _, _), - PINGROUP(35, SOUTH, pci_e0, qup_l4, jitter_bist, _, _, _, _, _, _, _), - PINGROUP(36, SOUTH, pci_e0, qup_l5, pll_bist, _, atest_tsens, _, _, _, _, _), - PINGROUP(37, SOUTH, qup_l6, agera_pll, _, _, _, _, _, _, _, _), - PINGROUP(38, NORTH, usb_phy, _, _, _, _, _, _, _, _, _), - PINGROUP(39, EAST, lpass_slimbus, _, _, _, _, _, _, _, _, _), - PINGROUP(40, SOUTH, sd_write, tsif1_error, _, _, _, _, _, _, _, _), - PINGROUP(41, EAST, qup3, _, qdss, _, _, _, _, _, _, _), - PINGROUP(42, EAST, qup3, _, qdss, _, _, _, _, _, _, _), - PINGROUP(43, EAST, qup3, _, qdss, _, _, _, _, _, _, _), - PINGROUP(44, EAST, qup3, _, qdss, _, _, _, _, _, _, _), - PINGROUP(45, EAST, qup6, _, _, _, _, _, _, _, _, _), - PINGROUP(46, EAST, qup6, _, _, _, _, _, _, _, _, _), - PINGROUP(47, EAST, qup6, _, _, _, _, _, _, _, _, _), - PINGROUP(48, EAST, qup6, _, _, _, _, _, _, _, _, _), - PINGROUP(49, NORTH, qup12, _, _, _, _, _, _, _, _, _), - PINGROUP(50, NORTH, qup12, _, _, _, _, _, _, _, _, _), - PINGROUP(51, NORTH, qup12, qdss_cti, _, _, _, _, _, _, _, _), - PINGROUP(52, NORTH, qup12, phase_flag, qdss_cti, _, _, _, _, _, _, _), - PINGROUP(53, NORTH, qup10, phase_flag, _, _, _, _, _, _, _, _), - PINGROUP(54, NORTH, qup10, _, phase_flag, _, _, _, _, _, _, _), - PINGROUP(55, NORTH, qup10, phase_flag, _, _, _, _, _, _, _, _), - PINGROUP(56, NORTH, qup10, phase_flag, _, _, _, _, _, _, _, _), - PINGROUP(57, NORTH, qua_mi2s, gcc_gp1, phase_flag, _, _, _, _, _, _, _), - PINGROUP(58, NORTH, qua_mi2s, gcc_gp2, phase_flag, _, _, _, _, _, _, _), - PINGROUP(59, NORTH, qua_mi2s, gcc_gp3, phase_flag, _, _, _, _, _, _, _), - PINGROUP(60, NORTH, qua_mi2s, cri_trng0, phase_flag, _, _, _, _, _, _, _), - PINGROUP(61, NORTH, qua_mi2s, cri_trng1, phase_flag, _, _, _, _, _, _, _), - PINGROUP(62, NORTH, qua_mi2s, cri_trng, phase_flag, qdss_cti, _, _, _, _, _, _), - PINGROUP(63, NORTH, qua_mi2s, _, phase_flag, qdss_cti, _, _, _, _, _, _), - PINGROUP(64, NORTH, pri_mi2s, sp_cmu, phase_flag, _, _, _, _, _, _, _), - PINGROUP(65, NORTH, pri_mi2s, qup8, _, _, _, _, _, _, _, _), - PINGROUP(66, NORTH, pri_mi2s_ws, qup8, _, _, _, _, _, _, _, _), - PINGROUP(67, NORTH, pri_mi2s, qup8, _, _, _, _, _, _, _, _), - PINGROUP(68, NORTH, pri_mi2s, qup8, _, _, _, _, _, _, _, _), - PINGROUP(69, EAST, spkr_i2s, audio_ref, _, _, _, _, _, _, _, _), - PINGROUP(70, EAST, lpass_slimbus, spkr_i2s, _, _, _, _, _, _, _, _), - PINGROUP(71, EAST, lpass_slimbus, spkr_i2s, tsense_pwm1, tsense_pwm2, _, _, _, _, _, _), - PINGROUP(72, EAST, lpass_slimbus, spkr_i2s, _, _, _, _, _, _, _, _), - PINGROUP(73, EAST, btfm_slimbus, atest_usb2, _, _, _, _, _, _, _, _), - PINGROUP(74, EAST, btfm_slimbus, ter_mi2s, phase_flag, atest_usb23, _, _, _, _, _, _), - PINGROUP(75, EAST, ter_mi2s, phase_flag, qdss, atest_usb22, _, _, _, _, _, _), - PINGROUP(76, EAST, ter_mi2s, phase_flag, qdss, atest_usb21, _, _, _, _, _, _), - PINGROUP(77, EAST, ter_mi2s, phase_flag, qdss, atest_usb20, _, _, _, _, _, _), - PINGROUP(78, EAST, ter_mi2s, gcc_gp1, _, _, _, _, _, _, _, _), - PINGROUP(79, NORTH, sec_mi2s, _, _, qdss, _, _, _, _, _, _), - PINGROUP(80, NORTH, sec_mi2s, _, qdss, _, _, _, _, _, _, _), - PINGROUP(81, NORTH, sec_mi2s, qup15, _, _, _, _, _, _, _, _), - PINGROUP(82, NORTH, sec_mi2s, qup15, _, _, _, _, _, _, _, _), - PINGROUP(83, NORTH, sec_mi2s, qup15, _, _, _, _, _, _, _, _), - PINGROUP(84, NORTH, qup15, _, _, _, _, _, _, _, _, _), - PINGROUP(85, EAST, qup5, _, _, _, _, _, _, _, _, _), - PINGROUP(86, EAST, qup5, _, _, _, _, _, _, _, _, _), - PINGROUP(87, EAST, qup5, _, _, _, _, _, _, _, _, _), - PINGROUP(88, EAST, qup5, _, _, _, _, _, _, _, _, _), - PINGROUP(89, SOUTH, tsif1_clk, qup4, qspi_cs, tgu_ch3, phase_flag, _, _, _, _, _), - PINGROUP(90, SOUTH, tsif1_en, mdp_vsync0, qup4, qspi_cs, mdp_vsync1, - mdp_vsync2, mdp_vsync3, tgu_ch0, phase_flag, qdss_cti), - PINGROUP(91, SOUTH, tsif1_data, sdc4_cmd, qup4, qspi_data, tgu_ch1, _, qdss_cti, _, _, _), - PINGROUP(92, SOUTH, tsif2_error, sdc4_data, qup4, qspi_data, vfr_1, tgu_ch2, _, _, _, _), - PINGROUP(93, SOUTH, tsif2_clk, sdc4_clk, qup7, qspi_data, _, qdss, _, _, _, _), - PINGROUP(94, SOUTH, tsif2_en, sdc4_data, qup7, qspi_data, _, _, _, _, _, _), - PINGROUP(95, SOUTH, tsif2_data, sdc4_data, qup7, qspi_clk, _, _, _, _, _, _), - PINGROUP(96, SOUTH, tsif2_sync, sdc4_data, qup7, phase_flag, _, _, _, _, _, _), - PINGROUP(97, NORTH, _, _, mdp_vsync, ldo_en, _, _, _, _, _, _), - PINGROUP(98, NORTH, _, mdp_vsync, ldo_update, _, _, _, _, _, _, _), - PINGROUP(99, NORTH, phase_flag, _, _, _, _, _, _, _, _, _), - PINGROUP(100, NORTH, phase_flag, _, _, _, _, _, _, _, _, _), - PINGROUP(101, NORTH, _, _, _, _, _, _, _, _, _, _), - PINGROUP(102, NORTH, pci_e1, prng_rosc, _, _, _, _, _, _, _, _), - PINGROUP(103, NORTH, pci_e1, phase_flag, _, _, _, _, _, _, _, _), - PINGROUP(104, NORTH, _, _, _, _, _, _, _, _, _, _), - PINGROUP(105, NORTH, uim2_data, qup13, qup_l4, _, _, _, _, _, _, _), - PINGROUP(106, NORTH, uim2_clk, qup13, qup_l5, _, _, _, _, _, _, _), - PINGROUP(107, NORTH, uim2_reset, qup13, qup_l6, _, _, _, _, _, _, _), - PINGROUP(108, NORTH, uim2_present, qup13, _, _, _, _, _, _, _, _), - PINGROUP(109, NORTH, uim1_data, _, _, _, _, _, _, _, _, _), - PINGROUP(110, NORTH, uim1_clk, _, _, _, _, _, _, _, _, _), - PINGROUP(111, NORTH, uim1_reset, _, _, _, _, _, _, _, _, _), - PINGROUP(112, NORTH, uim1_present, _, _, _, _, _, _, _, _, _), - PINGROUP(113, NORTH, uim_batt, edp_hot, _, _, _, _, _, _, _, _), - PINGROUP(114, NORTH, _, nav_pps, nav_pps, _, _, _, _, _, _, _), - PINGROUP(115, NORTH, _, nav_pps, nav_pps, _, _, _, _, _, _, _), - PINGROUP(116, NORTH, _, _, _, _, _, _, _, _, _, _), - PINGROUP(117, NORTH, _, qdss, atest_char, _, _, _, _, _, _, _), - PINGROUP(118, NORTH, adsp_ext, _, qdss, atest_char, _, _, _, _, _, _), - PINGROUP(119, NORTH, _, qdss, atest_char, _, _, _, _, _, _, _), - PINGROUP(120, NORTH, _, qdss, atest_char, _, _, _, _, _, _, _), - PINGROUP(121, NORTH, _, qdss, atest_char, _, _, _, _, _, _, _), - PINGROUP(122, EAST, _, qdss, _, _, _, _, _, _, _, _), - PINGROUP(123, EAST, qup_l4, _, qdss, _, _, _, _, _, _, _), - PINGROUP(124, EAST, qup_l5, _, qdss, _, _, _, _, _, _, _), - PINGROUP(125, EAST, qup_l6, _, _, _, _, _, _, _, _, _), - PINGROUP(126, EAST, _, _, _, _, _, _, _, _, _, _), - PINGROUP(127, NORTH, _, _, _, _, _, _, _, _, _, _), - PINGROUP(128, NORTH, nav_pps, nav_pps, _, _, _, _, _, _, _, _), - PINGROUP(129, NORTH, nav_pps, nav_pps, _, _, _, _, _, _, _, _), - PINGROUP(130, NORTH, qlink_request, _, _, _, _, _, _, _, _, _), - PINGROUP(131, NORTH, qlink_enable, _, _, _, _, _, _, _, _, _), - PINGROUP(132, NORTH, _, _, _, _, _, _, _, _, _, _), - PINGROUP(133, NORTH, _, _, _, _, _, _, _, _, _, _), - PINGROUP(134, NORTH, _, _, _, _, _, _, _, _, _, _), - PINGROUP(135, NORTH, _, pa_indicator, _, _, _, _, _, _, _, _), - PINGROUP(136, NORTH, _, _, _, _, _, _, _, _, _, _), - PINGROUP(137, NORTH, _, _, phase_flag, _, _, _, _, _, _, _), - PINGROUP(138, NORTH, _, _, phase_flag, _, _, _, _, _, _, _), - PINGROUP(139, NORTH, _, phase_flag, _, _, _, _, _, _, _, _), - PINGROUP(140, NORTH, _, _, phase_flag, _, _, _, _, _, _, _), - PINGROUP(141, NORTH, _, phase_flag, _, _, _, _, _, _, _, _), - PINGROUP(142, NORTH, _, phase_flag, _, _, _, _, _, _, _, _), - PINGROUP(143, NORTH, _, nav_pps, nav_pps, _, phase_flag, _, _, _, _, _), - PINGROUP(144, NORTH, mss_lte, _, _, _, _, _, _, _, _, _), - PINGROUP(145, NORTH, mss_lte, _, _, _, _, _, _, _, _, _), - PINGROUP(146, NORTH, _, _, _, _, _, _, _, _, _, _), - PINGROUP(147, NORTH, _, _, _, _, _, _, _, _, _, _), - PINGROUP(148, NORTH, _, _, _, _, _, _, _, _, _, _), - PINGROUP(149, NORTH, _, _, _, _, _, _, _, _, _, _), - SDC_QDSD_PINGROUP(sdc2_clk, 0x99a000, 14, 6), - SDC_QDSD_PINGROUP(sdc2_cmd, 0x99a000, 11, 3), - SDC_QDSD_PINGROUP(sdc2_data, 0x99a000, 9, 0), - UFS_RESET(ufs_reset, 0x99f000), + [0] = PINGROUP(0, NORTH, qup0, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [1] = PINGROUP(1, NORTH, qup0, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [2] = PINGROUP(2, NORTH, qup0, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [3] = PINGROUP(3, NORTH, qup0, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [4] = PINGROUP(4, NORTH, qup9, qdss_cti, NA, NA, NA, NA, NA, NA, NA, + NA), + [5] = PINGROUP(5, NORTH, qup9, qdss_cti, NA, NA, NA, NA, NA, NA, NA, + NA), + [6] = PINGROUP(6, NORTH, qup9, NA, ddr_pxi0, NA, NA, NA, NA, NA, NA, + NA), + [7] = PINGROUP(7, NORTH, qup9, ddr_bist, NA, atest_tsens2, + vsense_trigger, atest_usb1, ddr_pxi0, NA, NA, NA), + [8] = PINGROUP(8, NORTH, qup_l4, NA, ddr_bist, NA, NA, wlan1_adc1, + atest_usb13, ddr_pxi1, NA, NA), + [9] = PINGROUP(9, NORTH, qup_l5, ddr_bist, NA, wlan1_adc0, atest_usb12, + ddr_pxi1, NA, NA, NA, NA), + [10] = PINGROUP(10, NORTH, mdp_vsync, qup_l6, ddr_bist, wlan2_adc1, + atest_usb11, ddr_pxi2, NA, NA, NA, NA), + [11] = PINGROUP(11, NORTH, mdp_vsync, edp_lcd, dbg_out, wlan2_adc0, + atest_usb10, ddr_pxi2, NA, NA, NA, NA), + [12] = PINGROUP(12, SOUTH, mdp_vsync, m_voc, tsif1_sync, ddr_pxi3, NA, + NA, NA, NA, NA, NA), + [13] = PINGROUP(13, SOUTH, cam_mclk, pll_bypassnl, qdss_gpio0, + ddr_pxi3, NA, NA, NA, NA, NA, NA), + [14] = PINGROUP(14, SOUTH, cam_mclk, pll_reset, qdss_gpio1, NA, NA, NA, + NA, NA, NA, NA), + [15] = PINGROUP(15, SOUTH, cam_mclk, qdss_gpio2, NA, NA, NA, NA, NA, + NA, NA, NA), + [16] = PINGROUP(16, SOUTH, cam_mclk, qdss_gpio3, NA, NA, NA, NA, NA, + NA, NA, NA), + [17] = PINGROUP(17, SOUTH, cci_i2c, qup1, qdss_gpio4, NA, NA, NA, NA, + NA, NA, NA), + [18] = PINGROUP(18, SOUTH, cci_i2c, qup1, NA, qdss_gpio5, NA, NA, NA, + NA, NA, NA), + [19] = PINGROUP(19, SOUTH, cci_i2c, qup1, NA, qdss_gpio6, NA, NA, NA, + NA, NA, NA), + [20] = PINGROUP(20, SOUTH, cci_i2c, qup1, NA, qdss_gpio7, NA, NA, NA, + NA, NA, NA), + [21] = PINGROUP(21, SOUTH, cci_timer0, gcc_gp2, qdss_gpio8, NA, NA, NA, + NA, NA, NA, NA), + [22] = PINGROUP(22, SOUTH, cci_timer1, gcc_gp3, qdss_gpio, NA, NA, NA, + NA, NA, NA, NA), + [23] = PINGROUP(23, SOUTH, cci_timer2, qdss_gpio9, NA, NA, NA, NA, NA, + NA, NA, NA), + [24] = PINGROUP(24, SOUTH, cci_timer3, cci_async, qdss_gpio10, NA, NA, + NA, NA, NA, NA, NA), + [25] = PINGROUP(25, SOUTH, cci_timer4, cci_async, qdss_gpio11, NA, NA, + NA, NA, NA, NA, NA), + [26] = PINGROUP(26, SOUTH, cci_async, qdss_gpio12, NA, NA, NA, NA, NA, + NA, NA, NA), + [27] = PINGROUP(27, NORTH, qup2, qdss_gpio13, NA, NA, NA, NA, NA, NA, + NA, NA), + [28] = PINGROUP(28, NORTH, qup2, qdss_gpio14, NA, NA, NA, NA, NA, NA, + NA, NA), + [29] = PINGROUP(29, NORTH, qup2, NA, phase_flag1, qdss_gpio15, NA, NA, + NA, NA, NA, NA), + [30] = PINGROUP(30, NORTH, qup2, phase_flag2, qdss_gpio, NA, NA, NA, + NA, NA, NA, NA), + [31] = PINGROUP(31, NORTH, qup11, qup14, NA, NA, NA, NA, NA, NA, NA, + NA), + [32] = PINGROUP(32, NORTH, qup11, qup14, NA, NA, NA, NA, NA, NA, NA, + NA), + [33] = PINGROUP(33, NORTH, qup11, qup14, NA, NA, NA, NA, NA, NA, NA, + NA), + [34] = PINGROUP(34, NORTH, qup11, qup14, NA, NA, NA, NA, NA, NA, NA, + NA), + [35] = PINGROUP(35, SOUTH, pci_e0, qup_l4, jitter_bist, NA, NA, NA, NA, + NA, NA, NA), + [36] = PINGROUP(36, SOUTH, pci_e0, qup_l5, pll_bist, NA, atest_tsens, + NA, NA, NA, NA, NA), + [37] = PINGROUP(37, SOUTH, qup_l6, agera_pll, NA, NA, NA, NA, NA, NA, + NA, NA), + [38] = PINGROUP(38, NORTH, usb_phy, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [39] = PINGROUP(39, NORTH, lpass_slimbus, NA, NA, NA, NA, NA, NA, NA, + NA, NA), + [40] = PINGROUP(40, SOUTH, sd_write, tsif1_error, NA, NA, NA, NA, NA, + NA, NA, NA), + [41] = PINGROUP(41, SOUTH, qup3, NA, qdss_gpio6, NA, NA, NA, NA, NA, + NA, NA), + [42] = PINGROUP(42, SOUTH, qup3, NA, qdss_gpio7, NA, NA, NA, NA, NA, + NA, NA), + [43] = PINGROUP(43, SOUTH, qup3, NA, qdss_gpio14, NA, NA, NA, NA, NA, + NA, NA), + [44] = PINGROUP(44, SOUTH, qup3, NA, qdss_gpio15, NA, NA, NA, NA, NA, + NA, NA), + [45] = PINGROUP(45, NORTH, qup6, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [46] = PINGROUP(46, NORTH, qup6, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [47] = PINGROUP(47, NORTH, qup6, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [48] = PINGROUP(48, NORTH, qup6, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [49] = PINGROUP(49, NORTH, qup12, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [50] = PINGROUP(50, NORTH, qup12, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [51] = PINGROUP(51, NORTH, qup12, qdss_cti, NA, NA, NA, NA, NA, NA, NA, + NA), + [52] = PINGROUP(52, NORTH, qup12, phase_flag16, qdss_cti, NA, NA, NA, + NA, NA, NA, NA), + [53] = PINGROUP(53, NORTH, qup10, phase_flag11, NA, NA, NA, NA, NA, NA, + NA, NA), + [54] = PINGROUP(54, NORTH, qup10, NA, phase_flag12, NA, NA, NA, NA, NA, + NA, NA), + [55] = PINGROUP(55, NORTH, qup10, phase_flag13, NA, NA, NA, NA, NA, NA, + NA, NA), + [56] = PINGROUP(56, NORTH, qup10, phase_flag17, NA, NA, NA, NA, NA, NA, + NA, NA), + [57] = PINGROUP(57, NORTH, qua_mi2s, gcc_gp1, phase_flag18, NA, NA, NA, + NA, NA, NA, NA), + [58] = PINGROUP(58, NORTH, qua_mi2s, gcc_gp2, phase_flag19, NA, NA, NA, + NA, NA, NA, NA), + [59] = PINGROUP(59, NORTH, qua_mi2s, gcc_gp3, phase_flag20, NA, NA, NA, + NA, NA, NA, NA), + [60] = PINGROUP(60, NORTH, qua_mi2s, cri_trng0, phase_flag21, NA, NA, + NA, NA, NA, NA, NA), + [61] = PINGROUP(61, NORTH, qua_mi2s, cri_trng1, phase_flag22, NA, NA, + NA, NA, NA, NA, NA), + [62] = PINGROUP(62, NORTH, qua_mi2s, cri_trng, phase_flag23, qdss_cti, + NA, NA, NA, NA, NA, NA), + [63] = PINGROUP(63, NORTH, qua_mi2s, NA, phase_flag24, qdss_cti, NA, + NA, NA, NA, NA, NA), + [64] = PINGROUP(64, NORTH, pri_mi2s, sp_cmu, phase_flag25, NA, NA, NA, + NA, NA, NA, NA), + [65] = PINGROUP(65, NORTH, pri_mi2s, qup8, NA, NA, NA, NA, NA, NA, NA, + NA), + [66] = PINGROUP(66, NORTH, pri_mi2s_ws, qup8, NA, NA, NA, NA, NA, NA, + NA, NA), + [67] = PINGROUP(67, NORTH, pri_mi2s, qup8, NA, NA, NA, NA, NA, NA, NA, + NA), + [68] = PINGROUP(68, NORTH, pri_mi2s, qup8, NA, NA, NA, NA, NA, NA, NA, + NA), + [69] = PINGROUP(69, NORTH, spkr_i2s, audio_ref, NA, NA, NA, NA, NA, NA, + NA, NA), + [70] = PINGROUP(70, NORTH, lpass_slimbus, spkr_i2s, NA, NA, NA, NA, NA, + NA, NA, NA), + [71] = PINGROUP(71, NORTH, lpass_slimbus, spkr_i2s, tsense_pwm1, + tsense_pwm2, NA, NA, NA, NA, NA, NA), + [72] = PINGROUP(72, NORTH, lpass_slimbus, spkr_i2s, NA, NA, NA, NA, NA, + NA, NA, NA), + [73] = PINGROUP(73, NORTH, btfm_slimbus, atest_usb2, NA, NA, NA, NA, + NA, NA, NA, NA), + [74] = PINGROUP(74, NORTH, btfm_slimbus, ter_mi2s, phase_flag7, + atest_usb23, NA, NA, NA, NA, NA, NA), + [75] = PINGROUP(75, NORTH, ter_mi2s, phase_flag8, qdss_gpio8, + atest_usb22, NA, NA, NA, NA, NA, NA), + [76] = PINGROUP(76, NORTH, ter_mi2s, phase_flag9, qdss_gpio9, + atest_usb21, NA, NA, NA, NA, NA, NA), + [77] = PINGROUP(77, NORTH, ter_mi2s, phase_flag4, qdss_gpio10, + atest_usb20, NA, NA, NA, NA, NA, NA), + [78] = PINGROUP(78, NORTH, ter_mi2s, gcc_gp1, NA, NA, NA, NA, NA, NA, + NA, NA), + [79] = PINGROUP(79, NORTH, sec_mi2s, NA, NA, qdss_gpio11, NA, NA, NA, + NA, NA, NA), + [80] = PINGROUP(80, NORTH, sec_mi2s, NA, qdss_gpio12, NA, NA, NA, NA, + NA, NA, NA), + [81] = PINGROUP(81, NORTH, sec_mi2s, qup15, NA, NA, NA, NA, NA, NA, NA, + NA), + [82] = PINGROUP(82, NORTH, sec_mi2s, qup15, NA, NA, NA, NA, NA, NA, NA, + NA), + [83] = PINGROUP(83, NORTH, sec_mi2s, qup15, NA, NA, NA, NA, NA, NA, NA, + NA), + [84] = PINGROUP(84, NORTH, qup15, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [85] = PINGROUP(85, SOUTH, qup5, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [86] = PINGROUP(86, SOUTH, qup5, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [87] = PINGROUP(87, SOUTH, qup5, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [88] = PINGROUP(88, SOUTH, qup5, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [89] = PINGROUP(89, SOUTH, tsif1_clk, qup4, tgu_ch3, phase_flag10, NA, + NA, NA, NA, NA, NA), + [90] = PINGROUP(90, SOUTH, tsif1_en, mdp_vsync0, qup4, mdp_vsync1, + mdp_vsync2, mdp_vsync3, tgu_ch0, phase_flag0, qdss_cti, + NA), + [91] = PINGROUP(91, SOUTH, tsif1_data, sdc4_cmd, qup4, tgu_ch1, NA, + qdss_cti, NA, NA, NA, NA), + [92] = PINGROUP(92, SOUTH, tsif2_error, sdc43, qup4, vfr_1, tgu_ch2, + NA, NA, NA, NA, NA), + [93] = PINGROUP(93, SOUTH, tsif2_clk, sdc4_clk, qup7, NA, qdss_gpio13, + NA, NA, NA, NA, NA), + [94] = PINGROUP(94, SOUTH, tsif2_en, sdc42, qup7, NA, NA, NA, NA, NA, + NA, NA), + [95] = PINGROUP(95, SOUTH, tsif2_data, sdc41, qup7, NA, NA, NA, NA, NA, + NA, NA), + [96] = PINGROUP(96, SOUTH, tsif2_sync, sdc40, qup7, phase_flag3, NA, + NA, NA, NA, NA, NA), + [97] = PINGROUP(97, NORTH, NA, NA, mdp_vsync, ldo_en, NA, NA, NA, NA, + NA, NA), + [98] = PINGROUP(98, NORTH, NA, mdp_vsync, ldo_update, NA, NA, NA, NA, + NA, NA, NA), + [99] = PINGROUP(99, NORTH, phase_flag14, NA, NA, NA, NA, NA, NA, NA, + NA, NA), + [100] = PINGROUP(100, NORTH, phase_flag15, NA, NA, NA, NA, NA, NA, NA, + NA, NA), + [101] = PINGROUP(101, NORTH, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [102] = PINGROUP(102, NORTH, pci_e1, prng_rosc, NA, NA, NA, NA, NA, NA, + NA, NA), + [103] = PINGROUP(103, NORTH, pci_e1, phase_flag5, NA, NA, NA, NA, NA, + NA, NA, NA), + [104] = PINGROUP(104, NORTH, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [105] = PINGROUP(105, NORTH, uim2_data, qup13, qup_l4, NA, NA, NA, NA, + NA, NA, NA), + [106] = PINGROUP(106, NORTH, uim2_clk, qup13, qup_l5, NA, NA, NA, NA, + NA, NA, NA), + [107] = PINGROUP(107, NORTH, uim2_reset, qup13, qup_l6, NA, NA, NA, NA, + NA, NA, NA), + [108] = PINGROUP(108, NORTH, uim2_present, qup13, NA, NA, NA, NA, NA, + NA, NA, NA), + [109] = PINGROUP(109, NORTH, uim1_data, NA, NA, NA, NA, NA, NA, NA, NA, + NA), + [110] = PINGROUP(110, NORTH, uim1_clk, NA, NA, NA, NA, NA, NA, NA, NA, + NA), + [111] = PINGROUP(111, NORTH, uim1_reset, NA, NA, NA, NA, NA, NA, NA, + NA, NA), + [112] = PINGROUP(112, NORTH, uim1_present, NA, NA, NA, NA, NA, NA, NA, + NA, NA), + [113] = PINGROUP(113, NORTH, uim_batt, edp_hot, NA, NA, NA, NA, NA, NA, + NA, NA), + [114] = PINGROUP(114, NORTH, NA, nav_pps, nav_pps, NA, NA, NA, NA, NA, + NA, NA), + [115] = PINGROUP(115, NORTH, NA, nav_pps, nav_pps, NA, NA, NA, NA, NA, + NA, NA), + [116] = PINGROUP(116, NORTH, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [117] = PINGROUP(117, NORTH, NA, qdss_gpio0, atest_char, NA, NA, NA, + NA, NA, NA, NA), + [118] = PINGROUP(118, NORTH, adsp_ext, NA, qdss_gpio1, atest_char3, NA, + NA, NA, NA, NA, NA), + [119] = PINGROUP(119, NORTH, NA, qdss_gpio2, atest_char2, NA, NA, NA, + NA, NA, NA, NA), + [120] = PINGROUP(120, NORTH, NA, qdss_gpio3, atest_char1, NA, NA, NA, + NA, NA, NA, NA), + [121] = PINGROUP(121, NORTH, NA, qdss_gpio4, atest_char0, NA, NA, NA, + NA, NA, NA, NA), + [122] = PINGROUP(122, NORTH, NA, qdss_gpio5, NA, NA, NA, NA, NA, NA, + NA, NA), + [123] = PINGROUP(123, NORTH, qup_l4, NA, qdss_gpio, NA, NA, NA, NA, NA, + NA, NA), + [124] = PINGROUP(124, NORTH, qup_l5, NA, qdss_gpio, NA, NA, NA, NA, NA, + NA, NA), + [125] = PINGROUP(125, NORTH, qup_l6, NA, NA, NA, NA, NA, NA, NA, NA, + NA), + [126] = PINGROUP(126, NORTH, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [127] = PINGROUP(127, NORTH, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [128] = PINGROUP(128, NORTH, nav_pps, nav_pps, NA, NA, NA, NA, NA, NA, + NA, NA), + [129] = PINGROUP(129, NORTH, nav_pps, nav_pps, NA, NA, NA, NA, NA, NA, + NA, NA), + [130] = PINGROUP(130, NORTH, qlink_request, NA, NA, NA, NA, NA, NA, NA, + NA, NA), + [131] = PINGROUP(131, NORTH, qlink_enable, NA, NA, NA, NA, NA, NA, NA, + NA, NA), + [132] = PINGROUP(132, NORTH, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [133] = PINGROUP(133, NORTH, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [134] = PINGROUP(134, NORTH, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [135] = PINGROUP(135, NORTH, NA, pa_indicator, NA, NA, NA, NA, NA, NA, + NA, NA), + [136] = PINGROUP(136, NORTH, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [137] = PINGROUP(137, NORTH, NA, NA, phase_flag26, NA, NA, NA, NA, NA, + NA, NA), + [138] = PINGROUP(138, NORTH, NA, NA, phase_flag27, NA, NA, NA, NA, NA, + NA, NA), + [139] = PINGROUP(139, NORTH, NA, phase_flag28, NA, NA, NA, NA, NA, NA, + NA, NA), + [140] = PINGROUP(140, NORTH, NA, NA, phase_flag6, NA, NA, NA, NA, NA, + NA, NA), + [141] = PINGROUP(141, NORTH, NA, phase_flag29, NA, NA, NA, NA, NA, NA, + NA, NA), + [142] = PINGROUP(142, NORTH, NA, phase_flag30, NA, NA, NA, NA, NA, NA, + NA, NA), + [143] = PINGROUP(143, NORTH, NA, nav_pps, nav_pps, NA, phase_flag31, + NA, NA, NA, NA, NA), + [144] = PINGROUP(144, NORTH, mss_lte, NA, NA, NA, NA, NA, NA, NA, NA, + NA), + [145] = PINGROUP(145, NORTH, mss_lte, NA, NA, NA, NA, NA, NA, NA, NA, + NA), + [146] = PINGROUP(146, NORTH, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [147] = PINGROUP(147, NORTH, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [148] = PINGROUP(148, NORTH, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [149] = PINGROUP(149, NORTH, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA), + [150] = SDC_QDSD_PINGROUP(sdc2_clk, 0x99a000, 14, 6), + [151] = SDC_QDSD_PINGROUP(sdc2_cmd, 0x99a000, 11, 3), + [152] = SDC_QDSD_PINGROUP(sdc2_data, 0x99a000, 9, 0), + [153] = UFS_RESET(ufs_reset, 0x99f000), +}; + +static struct msm_dir_conn sdm845_dir_conn[] = { + {1, 510}, + {3, 511}, + {5, 512}, + {10, 513}, + {11, 514}, + {20, 515}, + {22, 516}, + {24, 517}, + {26, 518}, + {30, 519}, + {31, 632}, + {32, 521}, + {34, 522}, + {36, 523}, + {37, 524}, + {38, 525}, + {39, 526}, + {40, 527}, + {41, 630}, + {43, 529}, + {44, 530}, + {46, 531}, + {48, 532}, + {49, 633}, + {52, 534}, + {53, 535}, + {54, 536}, + {56, 537}, + {57, 538}, + {58, 539}, + {59, 540}, + {60, 541}, + {61, 542}, + {62, 543}, + {63, 544}, + {64, 545}, + {66, 546}, + {68, 547}, + {71, 548}, + {73, 549}, + {77, 550}, + {78, 551}, + {79, 552}, + {80, 553}, + {84, 554}, + {85, 555}, + {86, 556}, + {88, 557}, + {89, 631}, + {91, 559}, + {92, 560}, + {95, 561}, + {96, 562}, + {97, 563}, + {101, 564}, + {103, 565}, + {104, 566}, + {115, 570}, + {116, 571}, + {117, 572}, + {118, 573}, + {119, 609}, + {120, 610}, + {121, 611}, + {122, 612}, + {123, 613}, + {124, 614}, + {125, 615}, + {126, 616}, + {127, 617}, + {128, 618}, + {129, 619}, + {130, 620}, + {132, 621}, + {133, 622}, + {145, 623}, + {0, 216}, + {0, 215}, + {0, 214}, + {0, 213}, + {0, 212}, + {0, 211}, + {0, 210}, + {0, 209}, }; static const struct msm_pinctrl_soc_data sdm845_pinctrl = { @@ -1285,6 +1747,9 @@ static const struct msm_pinctrl_soc_data sdm845_pinctrl = { .groups = sdm845_groups, .ngroups = ARRAY_SIZE(sdm845_groups), .ngpios = 150, + .dir_conn = sdm845_dir_conn, + .n_dir_conns = ARRAY_SIZE(sdm845_dir_conn), + .dir_conn_irq_base = 216, }; static int sdm845_pinctrl_probe(struct platform_device *pdev) @@ -1300,6 +1765,7 @@ static const struct of_device_id sdm845_pinctrl_of_match[] = { static struct platform_driver sdm845_pinctrl_driver = { .driver = { .name = "sdm845-pinctrl", + .owner = THIS_MODULE, .of_match_table = sdm845_pinctrl_of_match, }, .probe = sdm845_pinctrl_probe, From 9ea994944e07635df659a82b4eedc77784b4194c Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Sun, 7 Nov 2021 17:03:40 +0200 Subject: [PATCH 075/356] pinctrl: qcom: sdm845: Update msm_pinctrl_soc_data members Remove n_dir_conns and dir_conn_irq_base members because they are not listed in the msm_pinctrl_soc_data structure and not used by the pinctrl driver. Signed-off-by: Pavel Dubrova --- drivers/pinctrl/qcom/pinctrl-sdm845-v2.c | 2 -- drivers/pinctrl/qcom/pinctrl-sdm845.c | 2 -- 2 files changed, 4 deletions(-) diff --git a/drivers/pinctrl/qcom/pinctrl-sdm845-v2.c b/drivers/pinctrl/qcom/pinctrl-sdm845-v2.c index bc8ec394d620..955579a9ed7a 100644 --- a/drivers/pinctrl/qcom/pinctrl-sdm845-v2.c +++ b/drivers/pinctrl/qcom/pinctrl-sdm845-v2.c @@ -1780,8 +1780,6 @@ static const struct msm_pinctrl_soc_data sdm845_pinctrl = { .ngroups = ARRAY_SIZE(sdm845_groups), .ngpios = 150, .dir_conn = sdm845_dir_conn, - .n_dir_conns = ARRAY_SIZE(sdm845_dir_conn), - .dir_conn_irq_base = 216, }; static int sdm845_pinctrl_probe(struct platform_device *pdev) diff --git a/drivers/pinctrl/qcom/pinctrl-sdm845.c b/drivers/pinctrl/qcom/pinctrl-sdm845.c index ee5bd19c2618..d846ea88f87c 100644 --- a/drivers/pinctrl/qcom/pinctrl-sdm845.c +++ b/drivers/pinctrl/qcom/pinctrl-sdm845.c @@ -1748,8 +1748,6 @@ static const struct msm_pinctrl_soc_data sdm845_pinctrl = { .ngroups = ARRAY_SIZE(sdm845_groups), .ngpios = 150, .dir_conn = sdm845_dir_conn, - .n_dir_conns = ARRAY_SIZE(sdm845_dir_conn), - .dir_conn_irq_base = 216, }; static int sdm845_pinctrl_probe(struct platform_device *pdev) From 7789f9b367ef20a8d473e07296ebd92cf1d9e691 Mon Sep 17 00:00:00 2001 From: Veera Vegivada Date: Thu, 28 May 2020 15:56:36 +0530 Subject: [PATCH 076/356] clk: Add prepare lock in clk_populate_clock_opp_table After enabling CONFIG_PROVE_LOCKING, observed dumpstacks in the boot time. Call trace: clk_core_round_rate_nolock+0xd4/0xe0 clk_hw_round_rate+0x4c/0x80 clk_populate_clock_opp_table+0x168/0x318 devm_clk_hw_register+0x88/0x9c devm_clk_register_regmap+0x54/0x60 qcom_cc_really_probe+0x114/0x208 clk_hw_round_rate() required to be called with prepare lock held. So acquire prepare lock before invoking clk_hw_round_rate(). Change-Id: I608e9e7cfe7a5a43fa0e0543b909cefe59030067 Signed-off-by: Veera Vegivada --- drivers/clk/clk.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 6677a88ced77..1ac55361d2e3 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -4685,6 +4685,7 @@ static int clk_add_and_print_opp(struct clk_hw *hw, unsigned long rate, int uv, int n) { struct clk_core *core = hw->core; + unsigned long rrate; int j, ret = 0; for (j = 0; j < count; j++) { @@ -4695,8 +4696,11 @@ static int clk_add_and_print_opp(struct clk_hw *hw, return ret; } - if (n == 0 || n == core->num_rate_max - 1 || - rate == clk_hw_round_rate(hw, INT_MAX)) + clk_prepare_lock(); + rrate = clk_hw_round_rate(hw, INT_MAX); + clk_prepare_unlock(); + + if (n == 0 || n == core->num_rate_max - 1 || rate == rrate) pr_info("%s: set OPP pair(%lu Hz: %u uV) on %s\n", core->name, rate, uv, dev_name(device_list[j])); @@ -4751,7 +4755,9 @@ static void clk_populate_clock_opp_table(struct device_node *np, } for (n = 0; ; n++) { + clk_prepare_lock(); rrate = clk_hw_round_rate(hw, rate + 1); + clk_prepare_unlock(); if (!rrate) { pr_err("clk_round_rate failed for %s\n", core->name); From 4f2a3c4f898bc4b2048def3334694566943de87f Mon Sep 17 00:00:00 2001 From: Odelu Kukatla Date: Mon, 6 Jun 2016 22:19:53 +0530 Subject: [PATCH 077/356] clk: qcom: Add support for gate clocks Add gate clocks support where the clocks could be - Either a branch clock with no branch halt check during enable/disable. - Clocks which have just enable/disable bit. Change-Id: Ia3adcab26f54a4b34a08fec031be5dfb029376c2 Signed-off-by: Odelu Kukatla Signed-off-by: Pavel Dubrova --- drivers/clk/qcom/clk-branch.c | 36 +++++++++++++++++++++++++++++++++++ drivers/clk/qcom/clk-branch.h | 16 ++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/drivers/clk/qcom/clk-branch.c b/drivers/clk/qcom/clk-branch.c index 46e2e1861c99..7cf1d9ac9d76 100644 --- a/drivers/clk/qcom/clk-branch.c +++ b/drivers/clk/qcom/clk-branch.c @@ -452,6 +452,42 @@ const struct clk_ops clk_branch2_hw_ctl_ops = { }; EXPORT_SYMBOL_GPL(clk_branch2_hw_ctl_ops); +static int clk_gate_toggle(struct clk_hw *hw, bool en) +{ + struct clk_gate2 *gt = to_clk_gate2(hw); + int ret = 0; + + if (en) { + ret = clk_enable_regmap(hw); + if (ret) + return ret; + } else { + clk_disable_regmap(hw); + } + + if (gt->udelay) + udelay(gt->udelay); + + return ret; +} + +static int clk_gate2_enable(struct clk_hw *hw) +{ + return clk_gate_toggle(hw, true); +} + +static void clk_gate2_disable(struct clk_hw *hw) +{ + clk_gate_toggle(hw, false); +} + +const struct clk_ops clk_gate2_ops = { + .enable = clk_gate2_enable, + .disable = clk_gate2_disable, + .is_enabled = clk_is_enabled_regmap, +}; +EXPORT_SYMBOL_GPL(clk_gate2_ops); + const struct clk_ops clk_branch_simple_ops = { .enable = clk_enable_regmap, .disable = clk_disable_regmap, diff --git a/drivers/clk/qcom/clk-branch.h b/drivers/clk/qcom/clk-branch.h index 43b6309cdd43..47549b8e0da2 100644 --- a/drivers/clk/qcom/clk-branch.h +++ b/drivers/clk/qcom/clk-branch.h @@ -41,12 +41,28 @@ struct clk_branch { struct clk_regmap clkr; }; +/** + * struct clk_gate2 - gating clock with status bit and dynamic hardware gating + * @udelay: halt delay in microseconds on clock branch Enable/Disable + * @clkr: handle between common and hardware-specific interfaces + * + * Clock which can gate its output. + */ +struct clk_gate2 { + u32 udelay; + struct clk_regmap clkr; +}; + extern const struct clk_ops clk_branch_ops; extern const struct clk_ops clk_branch2_ops; extern const struct clk_ops clk_branch2_hw_ctl_ops; +extern const struct clk_ops clk_gate2_ops; extern const struct clk_ops clk_branch_simple_ops; #define to_clk_branch(_hw) \ container_of(to_clk_regmap(_hw), struct clk_branch, clkr) +#define to_clk_gate2(_hw) \ + container_of(to_clk_regmap(_hw), struct clk_gate2, clkr) + #endif From e38494c047b879eef59fa4701d99b29a9cb5be22 Mon Sep 17 00:00:00 2001 From: Deepak Katragadda Date: Wed, 7 Feb 2018 10:37:41 -0800 Subject: [PATCH 078/356] clk: Add the CLK_CHILD_NO_RATE_PROP flag The voter clock mechanism relies on the rate request propagation to the parent clock to be one-way and not have the clock framework propagate the rate across all its children. Add the CLK_CHILD_NO_RATE_PROP flag for these votable clocks to use in order to avoid the top-down propagation of any scaling requests. Change-Id: Ib264068797e44c7f1712aebe45318ea3e9230a1b Signed-off-by: Deepak Katragadda [ab123321] adapt for msm-4.14 Signed-off-by: Artem Labazov <123321artyom@gmail.com> --- drivers/clk/clk.c | 2 ++ include/linux/clk-provider.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 1ac55361d2e3..cb3b8f31759e 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -2357,6 +2357,8 @@ static int clk_change_rate(struct clk_core *core) if (core->flags & CLK_RECALC_NEW_RATES) (void)clk_calc_new_rates(core, core->new_rate); + if (core->flags & CLK_CHILD_NO_RATE_PROP) + return rc; /* * Use safe iteration, as change_rate can actually swap parents * for certain clock types. diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 7fd4a16426a8..a55bf65e8500 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -48,6 +48,8 @@ * to first consumer that enables clk */ #define CLK_IS_MEASURE BIT(16) /* measure clock */ +/* do not call clk_change_rate on the clock's children */ +#define CLK_CHILD_NO_RATE_PROP BIT(17) struct clk; struct clk_hw; From af9f57d64e5853a7de377fa35701d550d60ad623 Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Fri, 5 Nov 2021 13:57:32 +0200 Subject: [PATCH 079/356] clk: qcom: Add the clock controller drivers for SDM845 Add drivers for global, camera, debug, display, gpu and video clock controller support on SDM845. This snapshot of the camcc-sdm845, debugcc-sdm845, dispcc-sdm845, gcc-sdm845, gpucc-sdm845 and videocc-sdm845 drivers as of https://source.codeaurora.org/quic/la/kernel/msm-4.9 commit 7e5c05f ("Merge "msm: camera: jpeg: Ensure in/out map entries are within allowed range""). Signed-off-by: Pavel Dubrova --- drivers/clk/qcom/Kconfig | 80 +- drivers/clk/qcom/Makefile | 8 + drivers/clk/qcom/camcc-sdm845.c | 2153 +++++++++++++++++ drivers/clk/qcom/debugcc-sdm845.c | 916 +++++++ drivers/clk/qcom/dispcc-sdm845.c | 603 ++++- drivers/clk/qcom/gcc-sdm845.c | 1368 +++++++++-- drivers/clk/qcom/gpucc-sdm845.c | 847 +++++++ drivers/clk/qcom/vdd-level-sdm845.h | 145 ++ drivers/clk/qcom/videocc-sdm845.c | 187 +- include/dt-bindings/clock/qcom,camcc-sdm845.h | 108 + .../dt-bindings/clock/qcom,dispcc-sdm845.h | 68 +- include/dt-bindings/clock/qcom,gcc-sdm845.h | 419 ++-- include/dt-bindings/clock/qcom,gpucc-sdm845.h | 60 + .../dt-bindings/clock/qcom,videocc-sdm845.h | 46 +- 14 files changed, 6333 insertions(+), 675 deletions(-) create mode 100644 drivers/clk/qcom/camcc-sdm845.c create mode 100644 drivers/clk/qcom/debugcc-sdm845.c create mode 100644 drivers/clk/qcom/gpucc-sdm845.c create mode 100644 drivers/clk/qcom/vdd-level-sdm845.h create mode 100644 include/dt-bindings/clock/qcom,camcc-sdm845.h create mode 100644 include/dt-bindings/clock/qcom,gpucc-sdm845.h diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index 61e2df623496..d8d49c07d9e0 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -237,52 +237,76 @@ config MSM_GCC_8998 Say Y if you want to use peripheral devices such as UART, SPI, i2c, USB, UFS, SD/eMMC, PCIe, etc. -config SDM_GCC_845 +config SPMI_PMIC_CLKDIV + tristate "SPMI PMIC clkdiv Support" + depends on (COMMON_CLK_QCOM && SPMI) || COMPILE_TEST + help + This driver supports the clkdiv functionality on the Qualcomm + Technologies, Inc. SPMI PMIC. It configures the frequency of + clkdiv outputs of the PMIC. These clocks are typically wired + through alternate functions on GPIO pins. + +config MSM_CLK_AOP_QMP + tristate "AOP QMP Clock Driver" + depends on COMMON_CLK_QCOM && MSM_QMP + help + Always On Processor manages few shared clocks on some Qualcomm + Technologies, Inc. SoCs. It accepts requests from other hardware + subsystems via QMP mailboxes. + Say Y to support the clocks managed by AOP on platforms such as sdm845. + +config MSM_GCC_SDM845 tristate "SDM845 Global Clock Controller" - select QCOM_GDSC depends on COMMON_CLK_QCOM + select QCOM_GDSC help - Support for the global clock controller on SDM845 devices. + Support for the global clock controller on Qualcomm Technologies, Inc + sdm845 devices. Say Y if you want to use peripheral devices such as UART, SPI, - i2C, USB, UFS, SDDC, PCIe, etc. + i2c, USB, UFS, SD/eMMC, PCIe, etc. -config SDM_VIDEOCC_845 - tristate "SDM845 Video Clock Controller" +config MSM_CAMCC_SDM845 + tristate "SDM845 Camera Clock Controller" depends on COMMON_CLK_QCOM - select SDM_GCC_845 - select QCOM_GDSC help - Support for the video clock controller on SDM845 devices. - Say Y if you want to support video devices and functionality such as - video encode and decode. + Support for the camera clock controller on Qualcomm Technologies, Inc + sdm845 devices. + Say Y if you want to support camera devices and functionality such as + capturing pictures. -config SDM_DISPCC_845 +config MSM_DEBUGCC_SDM845 + tristate "SDM845 Debug Clock Controller" + depends on COMMON_CLK_QCOM + help + Support for the debug clock controller on Qualcomm Technologies, Inc + sdm845 devices. + Say Y if you want to support the clock measurement functionality. + +config MSM_DISPCC_SDM845 tristate "SDM845 Display Clock Controller" - select SDM_GCC_845 depends on COMMON_CLK_QCOM help Support for the display clock controller on Qualcomm Technologies, Inc - SDM845 devices. + sdm845 devices. Say Y if you want to support display devices and functionality such as splash screen. -config SPMI_PMIC_CLKDIV - tristate "SPMI PMIC clkdiv Support" - depends on (COMMON_CLK_QCOM && SPMI) || COMPILE_TEST +config MSM_GPUCC_SDM845 + tristate "SDM845 Graphics Clock Controller" + depends on MSM_GCC_SDM845 help - This driver supports the clkdiv functionality on the Qualcomm - Technologies, Inc. SPMI PMIC. It configures the frequency of - clkdiv outputs of the PMIC. These clocks are typically wired - through alternate functions on GPIO pins. + Support for the graphics clock controller on Qualcomm Technologies, Inc. + sdm845 devices. + Say Y if you want to support graphics controller devices. -config MSM_CLK_AOP_QMP - tristate "AOP QMP Clock Driver" - depends on COMMON_CLK_QCOM && MSM_QMP +config MSM_VIDEOCC_SDM845 + tristate "SDM845 Video Clock Controller" + depends on COMMON_CLK_QCOM help - Always On Processor manages few shared clocks on some Qualcomm - Technologies, Inc. SoCs. It accepts requests from other hardware - subsystems via QMP mailboxes. - Say Y to support the clocks managed by AOP on platforms such as sdm845. + Support for the video clock controller on Qualcomm Technologies, Inc + sdm845 devices. + Say Y if you want to support video devices and functionality such as + video encode/decode. config MSM_GCC_KONA tristate "KONA Global Clock Controller" diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 8834fc9bfc04..4cbe67ffeb5f 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -16,6 +16,14 @@ clk-qcom-y += clk-dummy.o clk-debug.o clk-qcom-y += gdsc-regulator.o clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o +# Ported clock drivers +obj-$(CONFIG_MSM_GCC_SDM845) += gcc-sdm845.o +obj-$(CONFIG_MSM_CAMCC_SDM845) += camcc-sdm845.o +obj-$(CONFIG_MSM_DEBUGCC_SDM845) += debugcc-sdm845.o +obj-$(CONFIG_MSM_DISPCC_SDM845) += dispcc-sdm845.o +obj-$(CONFIG_MSM_GPUCC_SDM845) += gpucc-sdm845.o +obj-$(CONFIG_MSM_VIDEOCC_SDM845) += videocc-sdm845.o + # Keep alphabetically sorted by config obj-$(CONFIG_APQ_GCC_8084) += gcc-apq8084.o obj-$(CONFIG_APQ_MMCC_8084) += mmcc-apq8084.o diff --git a/drivers/clk/qcom/camcc-sdm845.c b/drivers/clk/qcom/camcc-sdm845.c new file mode 100644 index 000000000000..f3f0fbe9bab2 --- /dev/null +++ b/drivers/clk/qcom/camcc-sdm845.c @@ -0,0 +1,2153 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "clk: %s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "common.h" +#include "clk-regmap.h" +#include "clk-pll.h" +#include "clk-rcg.h" +#include "clk-branch.h" +#include "reset.h" +#include "clk-alpha-pll.h" +#include "vdd-level-sdm845.h" + +#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } + +static DEFINE_VDD_REGULATORS(vdd_cx, VDD_CX_NUM, 1, vdd_corner); +static DEFINE_VDD_REGULATORS(vdd_mx, VDD_CX_NUM, 1, vdd_corner); + +enum { + P_BI_TCXO, + P_CAM_CC_PLL0_OUT_EVEN, + P_CAM_CC_PLL1_OUT_EVEN, + P_CAM_CC_PLL2_OUT_EVEN, + P_CAM_CC_PLL2_OUT_ODD, + P_CAM_CC_PLL3_OUT_EVEN, + P_CORE_BI_PLL_TEST_SE, +}; + +static const struct parent_map cam_cc_parent_map_0[] = { + { P_BI_TCXO, 0 }, + { P_CAM_CC_PLL2_OUT_EVEN, 1 }, + { P_CAM_CC_PLL1_OUT_EVEN, 2 }, + { P_CAM_CC_PLL3_OUT_EVEN, 5 }, + { P_CAM_CC_PLL0_OUT_EVEN, 6 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const cam_cc_parent_names_0[] = { + "bi_tcxo", + "cam_cc_pll2_out_even", + "cam_cc_pll1_out_even", + "cam_cc_pll3_out_even", + "cam_cc_pll0_out_even", + "core_bi_pll_test_se", +}; + +static const struct parent_map cam_cc_parent_map_1[] = { + { P_BI_TCXO, 0 }, + { P_CAM_CC_PLL2_OUT_EVEN, 1 }, + { P_CAM_CC_PLL1_OUT_EVEN, 2 }, + { P_CAM_CC_PLL2_OUT_ODD, 4 }, + { P_CAM_CC_PLL3_OUT_EVEN, 5 }, + { P_CAM_CC_PLL0_OUT_EVEN, 6 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const cam_cc_parent_names_1[] = { + "bi_tcxo", + "cam_cc_pll2_out_even", + "cam_cc_pll1_out_even", + "cam_cc_pll2_out_odd", + "cam_cc_pll3_out_even", + "cam_cc_pll0_out_even", + "core_bi_pll_test_se", +}; + +static struct pll_vco fabia_vco[] = { + { 249600000, 2000000000, 0 }, + { 125000000, 1000000000, 1 }, +}; + +static const struct pll_config cam_cc_pll0_config = { + .l = 0x1f, + .frac = 0x4000, +}; + +static struct clk_alpha_pll cam_cc_pll0 = { + .offset = 0x0, + .vco_table = fabia_vco, + .num_vco = ARRAY_SIZE(fabia_vco), + .type = FABIA_PLL, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_pll0", + .parent_names = (const char *[]){ "bi_tcxo" }, + .num_parents = 1, + .ops = &clk_fabia_pll_ops, + VDD_CX_FMAX_MAP4( + MIN, 615000000, + LOW, 1066000000, + LOW_L1, 1600000000, + NOMINAL, 2000000000), + }, + }, +}; + +static const struct clk_div_table post_div_table_fabia_even[] = { + { 0x0, 1 }, + { 0x1, 2 }, + { 0x3, 4 }, + { 0x7, 8 }, + { } +}; + +static struct clk_alpha_pll_postdiv cam_cc_pll0_out_even = { + .offset = 0x0, + .post_div_shift = 8, + .post_div_table = post_div_table_fabia_even, + .num_post_div = ARRAY_SIZE(post_div_table_fabia_even), + .width = 4, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_pll0_out_even", + .parent_names = (const char *[]){ "cam_cc_pll0" }, + .num_parents = 1, + .ops = &clk_generic_pll_postdiv_ops, + }, +}; + +static const struct pll_config cam_cc_pll1_config = { + .l = 0x2a, + .frac = 0x1556, +}; + +static struct clk_alpha_pll cam_cc_pll1 = { + .offset = 0x1000, + .vco_table = fabia_vco, + .num_vco = ARRAY_SIZE(fabia_vco), + .type = FABIA_PLL, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_pll1", + .parent_names = (const char *[]){ "bi_tcxo" }, + .num_parents = 1, + .ops = &clk_fabia_pll_ops, + VDD_CX_FMAX_MAP4( + MIN, 615000000, + LOW, 1066000000, + LOW_L1, 1600000000, + NOMINAL, 2000000000), + }, + }, +}; + +static struct clk_alpha_pll_postdiv cam_cc_pll1_out_even = { + .offset = 0x1000, + .post_div_shift = 8, + .post_div_table = post_div_table_fabia_even, + .num_post_div = ARRAY_SIZE(post_div_table_fabia_even), + .width = 4, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_pll1_out_even", + .parent_names = (const char *[]){ "cam_cc_pll1" }, + .num_parents = 1, + .ops = &clk_generic_pll_postdiv_ops, + }, +}; + +static const struct pll_config cam_cc_pll2_config = { + .l = 0x32, + .frac = 0x0, +}; + +static struct clk_alpha_pll cam_cc_pll2 = { + .offset = 0x2000, + .vco_table = fabia_vco, + .num_vco = ARRAY_SIZE(fabia_vco), + .type = FABIA_PLL, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_pll2", + .parent_names = (const char *[]){ "bi_tcxo" }, + .num_parents = 1, + .ops = &clk_fabia_pll_ops, + VDD_MX_FMAX_MAP4( + MIN, 615000000, + LOW, 1066000000, + LOW_L1, 1600000000, + NOMINAL, 2000000000), + }, + }, +}; + +static struct clk_alpha_pll_postdiv cam_cc_pll2_out_even = { + .offset = 0x2000, + .post_div_shift = 8, + .post_div_table = post_div_table_fabia_even, + .num_post_div = ARRAY_SIZE(post_div_table_fabia_even), + .width = 4, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_pll2_out_even", + .parent_names = (const char *[]){ "cam_cc_pll2" }, + .num_parents = 1, + .ops = &clk_generic_pll_postdiv_ops, + }, +}; + +static const struct clk_div_table post_div_table_fabia_odd[] = { + { 0x0, 1 }, + { 0x3, 3 }, + { 0x5, 5 }, + { 0x7, 7 }, + { } +}; + +static struct clk_alpha_pll_postdiv cam_cc_pll2_out_odd = { + .offset = 0x2000, + .post_div_shift = 12, + .post_div_table = post_div_table_fabia_odd, + .num_post_div = ARRAY_SIZE(post_div_table_fabia_odd), + .width = 4, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_pll2_out_odd", + .parent_names = (const char *[]){ "cam_cc_pll2" }, + .num_parents = 1, + .ops = &clk_generic_pll_postdiv_ops, + }, +}; + +static const struct pll_config cam_cc_pll3_config = { + .l = 0x14, + .frac = 0x0, +}; + +static struct clk_alpha_pll cam_cc_pll3 = { + .offset = 0x3000, + .vco_table = fabia_vco, + .num_vco = ARRAY_SIZE(fabia_vco), + .type = FABIA_PLL, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_pll3", + .parent_names = (const char *[]){ "bi_tcxo" }, + .num_parents = 1, + .ops = &clk_fabia_pll_ops, + VDD_CX_FMAX_MAP4( + MIN, 615000000, + LOW, 1066000000, + LOW_L1, 1600000000, + NOMINAL, 2000000000), + }, + }, +}; + +static struct clk_alpha_pll_postdiv cam_cc_pll3_out_even = { + .offset = 0x3000, + .post_div_shift = 8, + .post_div_table = post_div_table_fabia_even, + .num_post_div = ARRAY_SIZE(post_div_table_fabia_even), + .width = 4, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_pll3_out_even", + .parent_names = (const char *[]){ "cam_cc_pll3" }, + .num_parents = 1, + .ops = &clk_generic_pll_postdiv_ops, + }, +}; + +static const struct freq_tbl ftbl_cam_cc_bps_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(100000000, P_CAM_CC_PLL0_OUT_EVEN, 6, 0, 0), + F(200000000, P_CAM_CC_PLL0_OUT_EVEN, 3, 0, 0), + F(404000000, P_CAM_CC_PLL1_OUT_EVEN, 2, 0, 0), + F(480000000, P_CAM_CC_PLL2_OUT_EVEN, 1, 0, 0), + F(600000000, P_CAM_CC_PLL0_OUT_EVEN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_bps_clk_src = { + .cmd_rcgr = 0x600c, + .mnd_width = 0, + .hid_width = 5, + .enable_safe_config = true, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_bps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_bps_clk_src", + .parent_names = cam_cc_parent_names_0, + .num_parents = 6, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP5( + MIN, 19200000, + LOWER, 200000000, + LOW, 404000000, + LOW_L1, 480000000, + NOMINAL, 600000000), + }, +}; + +static const struct freq_tbl ftbl_cam_cc_cci_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(37500000, P_CAM_CC_PLL0_OUT_EVEN, 16, 0, 0), + F(50000000, P_CAM_CC_PLL0_OUT_EVEN, 12, 0, 0), + F(100000000, P_CAM_CC_PLL0_OUT_EVEN, 6, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_cci_clk_src = { + .cmd_rcgr = 0xb0d8, + .mnd_width = 8, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_cci_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_cci_clk_src", + .parent_names = cam_cc_parent_names_0, + .num_parents = 6, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP4( + MIN, 19200000, + LOWER, 37500000, + LOW, 50000000, + NOMINAL, 100000000), + }, +}; + +static const struct freq_tbl ftbl_cam_cc_cphy_rx_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(300000000, P_CAM_CC_PLL0_OUT_EVEN, 2, 0, 0), + F(320000000, P_CAM_CC_PLL2_OUT_ODD, 3, 0, 0), + F(384000000, P_CAM_CC_PLL3_OUT_EVEN, 1, 0, 0), + { } +}; + +static const struct freq_tbl ftbl_cam_cc_cphy_rx_clk_src_sdm845_v2[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(384000000, P_CAM_CC_PLL3_OUT_EVEN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_cphy_rx_clk_src = { + .cmd_rcgr = 0x9060, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_1, + .freq_tbl = ftbl_cam_cc_cphy_rx_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_cphy_rx_clk_src", + .parent_names = cam_cc_parent_names_1, + .num_parents = 7, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP4( + MIN, 19200000, + LOWER, 300000000, + LOW, 320000000, + HIGH, 384000000), + }, +}; + +static const struct freq_tbl ftbl_cam_cc_csi0phytimer_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(240000000, P_CAM_CC_PLL2_OUT_EVEN, 2, 0, 0), + F(269333333, P_CAM_CC_PLL1_OUT_EVEN, 3, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_csi0phytimer_clk_src = { + .cmd_rcgr = 0x5004, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_csi0phytimer_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_csi0phytimer_clk_src", + .parent_names = cam_cc_parent_names_0, + .num_parents = 6, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 19200000, + LOWER, 240000000, + LOW, 269333333), + }, +}; + +static struct clk_rcg2 cam_cc_csi1phytimer_clk_src = { + .cmd_rcgr = 0x5028, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_csi0phytimer_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_csi1phytimer_clk_src", + .parent_names = cam_cc_parent_names_0, + .num_parents = 6, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 19200000, + LOWER, 240000000, + LOW, 269333333), + }, +}; + +static struct clk_rcg2 cam_cc_csi2phytimer_clk_src = { + .cmd_rcgr = 0x504c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_csi0phytimer_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_csi2phytimer_clk_src", + .parent_names = cam_cc_parent_names_0, + .num_parents = 6, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 19200000, + LOWER, 240000000, + LOW, 269333333), + }, +}; + +static struct clk_rcg2 cam_cc_csi3phytimer_clk_src = { + .cmd_rcgr = 0x5070, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_csi0phytimer_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_csi3phytimer_clk_src", + .parent_names = cam_cc_parent_names_0, + .num_parents = 6, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 19200000, + LOWER, 240000000, + LOW, 269333333), + }, +}; + +static const struct freq_tbl ftbl_cam_cc_fast_ahb_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(50000000, P_CAM_CC_PLL0_OUT_EVEN, 12, 0, 0), + F(100000000, P_CAM_CC_PLL0_OUT_EVEN, 6, 0, 0), + F(200000000, P_CAM_CC_PLL0_OUT_EVEN, 3, 0, 0), + F(300000000, P_CAM_CC_PLL0_OUT_EVEN, 2, 0, 0), + F(400000000, P_CAM_CC_PLL0_OUT_EVEN, 1.5, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_fast_ahb_clk_src = { + .cmd_rcgr = 0x6038, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_fast_ahb_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_fast_ahb_clk_src", + .parent_names = cam_cc_parent_names_0, + .num_parents = 6, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP5( + MIN, 19200000, + LOWER, 100000000, + LOW, 200000000, + LOW_L1, 300000000, + NOMINAL, 400000000), + }, +}; + +static const struct freq_tbl ftbl_cam_cc_fd_core_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(320000000, P_CAM_CC_PLL2_OUT_EVEN, 1.5, 0, 0), + F(400000000, P_CAM_CC_PLL0_OUT_EVEN, 1.5, 0, 0), + F(538666667, P_CAM_CC_PLL1_OUT_EVEN, 1.5, 0, 0), + F(600000000, P_CAM_CC_PLL0_OUT_EVEN, 1, 0, 0), + { } +}; + +static const struct freq_tbl ftbl_cam_cc_fd_core_clk_src_sdm845_v2[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(384000000, P_CAM_CC_PLL3_OUT_EVEN, 1, 0, 0), + F(400000000, P_CAM_CC_PLL0_OUT_EVEN, 1.5, 0, 0), + F(538666667, P_CAM_CC_PLL1_OUT_EVEN, 1.5, 0, 0), + F(600000000, P_CAM_CC_PLL0_OUT_EVEN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_fd_core_clk_src = { + .cmd_rcgr = 0xb0b0, + .mnd_width = 0, + .hid_width = 5, + .enable_safe_config = true, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_fd_core_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_fd_core_clk_src", + .parent_names = cam_cc_parent_names_0, + .num_parents = 6, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP5( + MIN, 19200000, + LOWER, 320000000, + LOW, 400000000, + LOW_L1, 538666667, + NOMINAL, 600000000), + }, +}; + +static const struct freq_tbl ftbl_cam_cc_icp_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(320000000, P_CAM_CC_PLL2_OUT_EVEN, 1.5, 0, 0), + F(400000000, P_CAM_CC_PLL0_OUT_EVEN, 1.5, 0, 0), + F(538666667, P_CAM_CC_PLL1_OUT_EVEN, 1.5, 0, 0), + F(600000000, P_CAM_CC_PLL0_OUT_EVEN, 1, 0, 0), + { } +}; + +static const struct freq_tbl ftbl_cam_cc_icp_clk_src_sdm845_v2[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(384000000, P_CAM_CC_PLL3_OUT_EVEN, 1, 0, 0), + F(400000000, P_CAM_CC_PLL0_OUT_EVEN, 1.5, 0, 0), + F(538666667, P_CAM_CC_PLL1_OUT_EVEN, 1.5, 0, 0), + F(600000000, P_CAM_CC_PLL0_OUT_EVEN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_icp_clk_src = { + .cmd_rcgr = 0xb088, + .mnd_width = 0, + .hid_width = 5, + .enable_safe_config = true, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_icp_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_icp_clk_src", + .parent_names = cam_cc_parent_names_0, + .num_parents = 6, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP5( + MIN, 19200000, + LOWER, 320000000, + LOW, 400000000, + LOW_L1, 538666667, + NOMINAL, 600000000), + }, +}; + +static const struct freq_tbl ftbl_cam_cc_ife_0_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(100000000, P_CAM_CC_PLL0_OUT_EVEN, 6, 0, 0), + F(320000000, P_CAM_CC_PLL2_OUT_EVEN, 1.5, 0, 0), + F(404000000, P_CAM_CC_PLL1_OUT_EVEN, 2, 0, 0), + F(480000000, P_CAM_CC_PLL2_OUT_EVEN, 1, 0, 0), + F(600000000, P_CAM_CC_PLL0_OUT_EVEN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_ife_0_clk_src = { + .cmd_rcgr = 0x900c, + .mnd_width = 0, + .hid_width = 5, + .enable_safe_config = true, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_ife_0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_0_clk_src", + .parent_names = cam_cc_parent_names_0, + .num_parents = 6, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP5( + MIN, 19200000, + LOWER, 320000000, + LOW, 404000000, + LOW_L1, 480000000, + NOMINAL, 600000000), + }, +}; + +static const struct freq_tbl ftbl_cam_cc_ife_0_csid_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(75000000, P_CAM_CC_PLL0_OUT_EVEN, 8, 0, 0), + F(384000000, P_CAM_CC_PLL3_OUT_EVEN, 1, 0, 0), + F(538666667, P_CAM_CC_PLL1_OUT_EVEN, 1.5, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_ife_0_csid_clk_src = { + .cmd_rcgr = 0x9038, + .mnd_width = 0, + .hid_width = 5, + .enable_safe_config = true, + .parent_map = cam_cc_parent_map_1, + .freq_tbl = ftbl_cam_cc_ife_0_csid_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_0_csid_clk_src", + .parent_names = cam_cc_parent_names_1, + .num_parents = 7, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 19200000, + LOWER, 384000000, + NOMINAL, 538666667), + }, +}; + +static struct clk_rcg2 cam_cc_ife_1_clk_src = { + .cmd_rcgr = 0xa00c, + .mnd_width = 0, + .hid_width = 5, + .enable_safe_config = true, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_ife_0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_1_clk_src", + .parent_names = cam_cc_parent_names_0, + .num_parents = 6, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP5( + MIN, 19200000, + LOWER, 320000000, + LOW, 404000000, + LOW_L1, 480000000, + NOMINAL, 600000000), + }, +}; + +static struct clk_rcg2 cam_cc_ife_1_csid_clk_src = { + .cmd_rcgr = 0xa030, + .mnd_width = 0, + .hid_width = 5, + .enable_safe_config = true, + .parent_map = cam_cc_parent_map_1, + .freq_tbl = ftbl_cam_cc_ife_0_csid_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_1_csid_clk_src", + .parent_names = cam_cc_parent_names_1, + .num_parents = 7, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 19200000, + LOWER, 384000000, + NOMINAL, 538666667), + }, +}; + +static struct clk_rcg2 cam_cc_ife_lite_clk_src = { + .cmd_rcgr = 0xb004, + .mnd_width = 0, + .hid_width = 5, + .enable_safe_config = true, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_ife_0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_lite_clk_src", + .parent_names = cam_cc_parent_names_0, + .num_parents = 6, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP5( + MIN, 19200000, + LOWER, 320000000, + LOW, 404000000, + LOW_L1, 480000000, + NOMINAL, 600000000), + }, +}; + +static struct clk_rcg2 cam_cc_ife_lite_csid_clk_src = { + .cmd_rcgr = 0xb024, + .mnd_width = 0, + .hid_width = 5, + .enable_safe_config = true, + .parent_map = cam_cc_parent_map_1, + .freq_tbl = ftbl_cam_cc_ife_0_csid_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_lite_csid_clk_src", + .parent_names = cam_cc_parent_names_1, + .num_parents = 7, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 19200000, + LOWER, 384000000, + NOMINAL, 538666667), + }, +}; + +static const struct freq_tbl ftbl_cam_cc_ipe_0_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(100000000, P_CAM_CC_PLL0_OUT_EVEN, 6, 0, 0), + F(240000000, P_CAM_CC_PLL0_OUT_EVEN, 2.5, 0, 0), + F(404000000, P_CAM_CC_PLL1_OUT_EVEN, 2, 0, 0), + F(480000000, P_CAM_CC_PLL2_OUT_EVEN, 1, 0, 0), + F(538666667, P_CAM_CC_PLL1_OUT_EVEN, 1.5, 0, 0), + F(600000000, P_CAM_CC_PLL0_OUT_EVEN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_ipe_0_clk_src = { + .cmd_rcgr = 0x700c, + .mnd_width = 0, + .hid_width = 5, + .enable_safe_config = true, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_ipe_0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_ipe_0_clk_src", + .parent_names = cam_cc_parent_names_0, + .num_parents = 6, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP6( + MIN, 19200000, + LOWER, 240000000, + LOW, 404000000, + LOW_L1, 480000000, + NOMINAL, 538666667, + HIGH, 600000000), + }, +}; + +static struct clk_rcg2 cam_cc_ipe_1_clk_src = { + .cmd_rcgr = 0x800c, + .mnd_width = 0, + .hid_width = 5, + .enable_safe_config = true, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_ipe_0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_ipe_1_clk_src", + .parent_names = cam_cc_parent_names_0, + .num_parents = 6, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP6( + MIN, 19200000, + LOWER, 240000000, + LOW, 404000000, + LOW_L1, 480000000, + NOMINAL, 538666667, + HIGH, 600000000), + }, +}; + +static struct clk_rcg2 cam_cc_jpeg_clk_src = { + .cmd_rcgr = 0xb04c, + .mnd_width = 0, + .hid_width = 5, + .enable_safe_config = true, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_bps_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_jpeg_clk_src", + .parent_names = cam_cc_parent_names_0, + .num_parents = 6, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP5( + MIN, 19200000, + LOWER, 200000000, + LOW, 404000000, + LOW_L1, 480000000, + NOMINAL, 600000000), + }, +}; + +static const struct freq_tbl ftbl_cam_cc_lrme_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(100000000, P_CAM_CC_PLL0_OUT_EVEN, 6, 0, 0), + F(200000000, P_CAM_CC_PLL0_OUT_EVEN, 3, 0, 0), + F(384000000, P_CAM_CC_PLL2_OUT_ODD, 2.5, 0, 0), + F(480000000, P_CAM_CC_PLL2_OUT_EVEN, 1, 0, 0), + F(600000000, P_CAM_CC_PLL0_OUT_EVEN, 1, 0, 0), + { } +}; + +static const struct freq_tbl ftbl_cam_cc_lrme_clk_src_sdm845_v2[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(100000000, P_CAM_CC_PLL0_OUT_EVEN, 6, 0, 0), + F(200000000, P_CAM_CC_PLL0_OUT_EVEN, 3, 0, 0), + F(269333333, P_CAM_CC_PLL1_OUT_EVEN, 3, 0, 0), + F(320000000, P_CAM_CC_PLL2_OUT_EVEN, 1.5, 0, 0), + F(400000000, P_CAM_CC_PLL0_OUT_EVEN, 1.5, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_lrme_clk_src = { + .cmd_rcgr = 0xb0f8, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_1, + .enable_safe_config = true, + .freq_tbl = ftbl_cam_cc_lrme_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_lrme_clk_src", + .parent_names = cam_cc_parent_names_1, + .num_parents = 7, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP5( + MIN, 19200000, + LOWER, 200000000, + LOW, 384000000, + LOW_L1, 480000000, + NOMINAL, 600000000), + }, +}; + +static const struct freq_tbl ftbl_cam_cc_mclk0_clk_src[] = { + F(8000000, P_CAM_CC_PLL2_OUT_EVEN, 10, 1, 6), + F(19200000, P_BI_TCXO, 1, 0, 0), + F(24000000, P_CAM_CC_PLL2_OUT_EVEN, 10, 1, 2), + F(33333333, P_CAM_CC_PLL0_OUT_EVEN, 2, 1, 9), + F(34285714, P_CAM_CC_PLL2_OUT_EVEN, 14, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_mclk0_clk_src = { + .cmd_rcgr = 0x4004, + .mnd_width = 8, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_mclk0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_mclk0_clk_src", + .parent_names = cam_cc_parent_names_0, + .num_parents = 6, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP2( + MIN, 19200000, + LOWER, 34285714), + }, +}; + +static struct clk_rcg2 cam_cc_mclk1_clk_src = { + .cmd_rcgr = 0x4024, + .mnd_width = 8, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_mclk0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_mclk1_clk_src", + .parent_names = cam_cc_parent_names_0, + .num_parents = 6, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP2( + MIN, 19200000, + LOWER, 34285714), + }, +}; + +static struct clk_rcg2 cam_cc_mclk2_clk_src = { + .cmd_rcgr = 0x4044, + .mnd_width = 8, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_mclk0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_mclk2_clk_src", + .parent_names = cam_cc_parent_names_0, + .num_parents = 6, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP2( + MIN, 19200000, + LOWER, 34285714), + }, +}; + +static struct clk_rcg2 cam_cc_mclk3_clk_src = { + .cmd_rcgr = 0x4064, + .mnd_width = 8, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_mclk0_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_mclk3_clk_src", + .parent_names = cam_cc_parent_names_0, + .num_parents = 6, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP2( + MIN, 19200000, + LOWER, 34285714), + }, +}; + +static const struct freq_tbl ftbl_cam_cc_slow_ahb_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(60000000, P_CAM_CC_PLL0_OUT_EVEN, 10, 0, 0), + F(66666667, P_CAM_CC_PLL0_OUT_EVEN, 9, 0, 0), + F(73846154, P_CAM_CC_PLL2_OUT_EVEN, 6.5, 0, 0), + F(80000000, P_CAM_CC_PLL2_OUT_EVEN, 6, 0, 0), + { } +}; + +static struct clk_rcg2 cam_cc_slow_ahb_clk_src = { + .cmd_rcgr = 0x6054, + .mnd_width = 0, + .hid_width = 5, + .parent_map = cam_cc_parent_map_0, + .freq_tbl = ftbl_cam_cc_slow_ahb_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "cam_cc_slow_ahb_clk_src", + .parent_names = cam_cc_parent_names_0, + .num_parents = 6, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP5( + MIN, 19200000, + LOWER, 60000000, + LOW, 66666667, + LOW_L1, 73846154, + NOMINAL, 80000000), + }, +}; + +static struct clk_branch cam_cc_bps_ahb_clk = { + .halt_reg = 0x606c, + .halt_check = BRANCH_HALT, + .aggr_sibling_rates = true, + .clkr = { + .enable_reg = 0x606c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_bps_ahb_clk", + .parent_names = (const char *[]){ + "cam_cc_slow_ahb_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_bps_areg_clk = { + .halt_reg = 0x6050, + .halt_check = BRANCH_HALT, + .aggr_sibling_rates = true, + .clkr = { + .enable_reg = 0x6050, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_bps_areg_clk", + .parent_names = (const char *[]){ + "cam_cc_fast_ahb_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_bps_axi_clk = { + .halt_reg = 0x6034, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x6034, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_bps_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_bps_clk = { + .halt_reg = 0x6024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x6024, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_bps_clk", + .parent_names = (const char *[]){ + "cam_cc_bps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_camnoc_atb_clk = { + .halt_reg = 0xb12c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb12c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_camnoc_atb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_camnoc_axi_clk = { + .halt_reg = 0xb124, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb124, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_camnoc_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_cci_clk = { + .halt_reg = 0xb0f0, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb0f0, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_cci_clk", + .parent_names = (const char *[]){ + "cam_cc_cci_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_cpas_ahb_clk = { + .halt_reg = 0xb11c, + .halt_check = BRANCH_HALT, + .aggr_sibling_rates = true, + .clkr = { + .enable_reg = 0xb11c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_cpas_ahb_clk", + .parent_names = (const char *[]){ + "cam_cc_slow_ahb_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_csi0phytimer_clk = { + .halt_reg = 0x501c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x501c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_csi0phytimer_clk", + .parent_names = (const char *[]){ + "cam_cc_csi0phytimer_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_csi1phytimer_clk = { + .halt_reg = 0x5040, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x5040, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_csi1phytimer_clk", + .parent_names = (const char *[]){ + "cam_cc_csi1phytimer_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_csi2phytimer_clk = { + .halt_reg = 0x5064, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x5064, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_csi2phytimer_clk", + .parent_names = (const char *[]){ + "cam_cc_csi2phytimer_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_csi3phytimer_clk = { + .halt_reg = 0x5088, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x5088, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_csi3phytimer_clk", + .parent_names = (const char *[]){ + "cam_cc_csi3phytimer_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_csiphy0_clk = { + .halt_reg = 0x5020, + .halt_check = BRANCH_HALT, + .aggr_sibling_rates = true, + .clkr = { + .enable_reg = 0x5020, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_csiphy0_clk", + .parent_names = (const char *[]){ + "cam_cc_cphy_rx_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_csiphy1_clk = { + .halt_reg = 0x5044, + .halt_check = BRANCH_HALT, + .aggr_sibling_rates = true, + .clkr = { + .enable_reg = 0x5044, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_csiphy1_clk", + .parent_names = (const char *[]){ + "cam_cc_cphy_rx_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_csiphy2_clk = { + .halt_reg = 0x5068, + .halt_check = BRANCH_HALT, + .aggr_sibling_rates = true, + .clkr = { + .enable_reg = 0x5068, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_csiphy2_clk", + .parent_names = (const char *[]){ + "cam_cc_cphy_rx_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_csiphy3_clk = { + .halt_reg = 0x508c, + .halt_check = BRANCH_HALT, + .aggr_sibling_rates = true, + .clkr = { + .enable_reg = 0x508c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_csiphy3_clk", + .parent_names = (const char *[]){ + "cam_cc_cphy_rx_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_fd_core_clk = { + .halt_reg = 0xb0c8, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb0c8, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_fd_core_clk", + .parent_names = (const char *[]){ + "cam_cc_fd_core_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_fd_core_uar_clk = { + .halt_reg = 0xb0d0, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb0d0, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_fd_core_uar_clk", + .parent_names = (const char *[]){ + "cam_cc_fd_core_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_icp_apb_clk = { + .halt_reg = 0xb084, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb084, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_icp_apb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_icp_atb_clk = { + .halt_reg = 0xb078, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb078, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_icp_atb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_icp_clk = { + .halt_reg = 0xb0a0, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb0a0, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_icp_clk", + .parent_names = (const char *[]){ + "cam_cc_icp_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_icp_cti_clk = { + .halt_reg = 0xb07c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb07c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_icp_cti_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_icp_ts_clk = { + .halt_reg = 0xb080, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb080, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_icp_ts_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_0_axi_clk = { + .halt_reg = 0x907c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x907c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_0_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_0_clk = { + .halt_reg = 0x9024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9024, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_0_clk", + .parent_names = (const char *[]){ + "cam_cc_ife_0_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_0_cphy_rx_clk = { + .halt_reg = 0x9078, + .halt_check = BRANCH_HALT, + .aggr_sibling_rates = true, + .clkr = { + .enable_reg = 0x9078, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_0_cphy_rx_clk", + .parent_names = (const char *[]){ + "cam_cc_cphy_rx_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_0_csid_clk = { + .halt_reg = 0x9050, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9050, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_0_csid_clk", + .parent_names = (const char *[]){ + "cam_cc_ife_0_csid_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_0_dsp_clk = { + .halt_reg = 0x9034, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x9034, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_0_dsp_clk", + .parent_names = (const char *[]){ + "cam_cc_ife_0_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_1_axi_clk = { + .halt_reg = 0xa054, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa054, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_1_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_1_clk = { + .halt_reg = 0xa024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa024, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_1_clk", + .parent_names = (const char *[]){ + "cam_cc_ife_1_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_1_cphy_rx_clk = { + .halt_reg = 0xa050, + .halt_check = BRANCH_HALT, + .aggr_sibling_rates = true, + .clkr = { + .enable_reg = 0xa050, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_1_cphy_rx_clk", + .parent_names = (const char *[]){ + "cam_cc_cphy_rx_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_1_csid_clk = { + .halt_reg = 0xa048, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa048, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_1_csid_clk", + .parent_names = (const char *[]){ + "cam_cc_ife_1_csid_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_1_dsp_clk = { + .halt_reg = 0xa02c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xa02c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_1_dsp_clk", + .parent_names = (const char *[]){ + "cam_cc_ife_1_clk_src", + }, + .num_parents = 1, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_lite_clk = { + .halt_reg = 0xb01c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb01c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_lite_clk", + .parent_names = (const char *[]){ + "cam_cc_ife_lite_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_lite_cphy_rx_clk = { + .halt_reg = 0xb044, + .halt_check = BRANCH_HALT, + .aggr_sibling_rates = true, + .clkr = { + .enable_reg = 0xb044, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_lite_cphy_rx_clk", + .parent_names = (const char *[]){ + "cam_cc_cphy_rx_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ife_lite_csid_clk = { + .halt_reg = 0xb03c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb03c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ife_lite_csid_clk", + .parent_names = (const char *[]){ + "cam_cc_ife_lite_csid_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ipe_0_ahb_clk = { + .halt_reg = 0x703c, + .halt_check = BRANCH_HALT, + .aggr_sibling_rates = true, + .clkr = { + .enable_reg = 0x703c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ipe_0_ahb_clk", + .parent_names = (const char *[]){ + "cam_cc_slow_ahb_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ipe_0_areg_clk = { + .halt_reg = 0x7038, + .halt_check = BRANCH_HALT, + .aggr_sibling_rates = true, + .clkr = { + .enable_reg = 0x7038, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ipe_0_areg_clk", + .parent_names = (const char *[]){ + "cam_cc_fast_ahb_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ipe_0_axi_clk = { + .halt_reg = 0x7034, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x7034, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ipe_0_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ipe_0_clk = { + .halt_reg = 0x7024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x7024, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ipe_0_clk", + .parent_names = (const char *[]){ + "cam_cc_ipe_0_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ipe_1_ahb_clk = { + .halt_reg = 0x803c, + .halt_check = BRANCH_HALT, + .aggr_sibling_rates = true, + .clkr = { + .enable_reg = 0x803c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ipe_1_ahb_clk", + .parent_names = (const char *[]){ + "cam_cc_slow_ahb_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ipe_1_areg_clk = { + .halt_reg = 0x8038, + .halt_check = BRANCH_HALT, + .aggr_sibling_rates = true, + .clkr = { + .enable_reg = 0x8038, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ipe_1_areg_clk", + .parent_names = (const char *[]){ + "cam_cc_fast_ahb_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ipe_1_axi_clk = { + .halt_reg = 0x8034, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8034, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ipe_1_axi_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_ipe_1_clk = { + .halt_reg = 0x8024, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x8024, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_ipe_1_clk", + .parent_names = (const char *[]){ + "cam_cc_ipe_1_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_jpeg_clk = { + .halt_reg = 0xb064, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb064, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_jpeg_clk", + .parent_names = (const char *[]){ + "cam_cc_jpeg_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_lrme_clk = { + .halt_reg = 0xb110, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb110, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_lrme_clk", + .parent_names = (const char *[]){ + "cam_cc_lrme_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_mclk0_clk = { + .halt_reg = 0x401c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x401c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_mclk0_clk", + .parent_names = (const char *[]){ + "cam_cc_mclk0_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_mclk1_clk = { + .halt_reg = 0x403c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x403c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_mclk1_clk", + .parent_names = (const char *[]){ + "cam_cc_mclk1_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_mclk2_clk = { + .halt_reg = 0x405c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x405c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_mclk2_clk", + .parent_names = (const char *[]){ + "cam_cc_mclk2_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_mclk3_clk = { + .halt_reg = 0x407c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x407c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_mclk3_clk", + .parent_names = (const char *[]){ + "cam_cc_mclk3_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_pll_test_clk = { + .halt_reg = 0xc014, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xc014, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_pll_test_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_soc_ahb_clk = { + .halt_reg = 0xb13c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb13c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_soc_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch cam_cc_sys_tmr_clk = { + .halt_reg = 0xb0a8, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0xb0a8, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "cam_cc_sys_tmr_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_regmap *cam_cc_sdm845_clocks[] = { + [CAM_CC_BPS_AHB_CLK] = &cam_cc_bps_ahb_clk.clkr, + [CAM_CC_BPS_AREG_CLK] = &cam_cc_bps_areg_clk.clkr, + [CAM_CC_BPS_AXI_CLK] = &cam_cc_bps_axi_clk.clkr, + [CAM_CC_BPS_CLK] = &cam_cc_bps_clk.clkr, + [CAM_CC_BPS_CLK_SRC] = &cam_cc_bps_clk_src.clkr, + [CAM_CC_CAMNOC_ATB_CLK] = &cam_cc_camnoc_atb_clk.clkr, + [CAM_CC_CAMNOC_AXI_CLK] = &cam_cc_camnoc_axi_clk.clkr, + [CAM_CC_CCI_CLK] = &cam_cc_cci_clk.clkr, + [CAM_CC_CCI_CLK_SRC] = &cam_cc_cci_clk_src.clkr, + [CAM_CC_CPAS_AHB_CLK] = &cam_cc_cpas_ahb_clk.clkr, + [CAM_CC_CPHY_RX_CLK_SRC] = &cam_cc_cphy_rx_clk_src.clkr, + [CAM_CC_CSI0PHYTIMER_CLK] = &cam_cc_csi0phytimer_clk.clkr, + [CAM_CC_CSI0PHYTIMER_CLK_SRC] = &cam_cc_csi0phytimer_clk_src.clkr, + [CAM_CC_CSI1PHYTIMER_CLK] = &cam_cc_csi1phytimer_clk.clkr, + [CAM_CC_CSI1PHYTIMER_CLK_SRC] = &cam_cc_csi1phytimer_clk_src.clkr, + [CAM_CC_CSI2PHYTIMER_CLK] = &cam_cc_csi2phytimer_clk.clkr, + [CAM_CC_CSI2PHYTIMER_CLK_SRC] = &cam_cc_csi2phytimer_clk_src.clkr, + [CAM_CC_CSI3PHYTIMER_CLK] = NULL, + [CAM_CC_CSI3PHYTIMER_CLK_SRC] = NULL, + [CAM_CC_CSIPHY0_CLK] = &cam_cc_csiphy0_clk.clkr, + [CAM_CC_CSIPHY1_CLK] = &cam_cc_csiphy1_clk.clkr, + [CAM_CC_CSIPHY2_CLK] = &cam_cc_csiphy2_clk.clkr, + [CAM_CC_CSIPHY3_CLK] = NULL, + [CAM_CC_FAST_AHB_CLK_SRC] = &cam_cc_fast_ahb_clk_src.clkr, + [CAM_CC_FD_CORE_CLK] = &cam_cc_fd_core_clk.clkr, + [CAM_CC_FD_CORE_CLK_SRC] = &cam_cc_fd_core_clk_src.clkr, + [CAM_CC_FD_CORE_UAR_CLK] = &cam_cc_fd_core_uar_clk.clkr, + [CAM_CC_ICP_APB_CLK] = &cam_cc_icp_apb_clk.clkr, + [CAM_CC_ICP_ATB_CLK] = &cam_cc_icp_atb_clk.clkr, + [CAM_CC_ICP_CLK] = &cam_cc_icp_clk.clkr, + [CAM_CC_ICP_CLK_SRC] = &cam_cc_icp_clk_src.clkr, + [CAM_CC_ICP_CTI_CLK] = &cam_cc_icp_cti_clk.clkr, + [CAM_CC_ICP_TS_CLK] = &cam_cc_icp_ts_clk.clkr, + [CAM_CC_IFE_0_AXI_CLK] = &cam_cc_ife_0_axi_clk.clkr, + [CAM_CC_IFE_0_CLK] = &cam_cc_ife_0_clk.clkr, + [CAM_CC_IFE_0_CLK_SRC] = &cam_cc_ife_0_clk_src.clkr, + [CAM_CC_IFE_0_CPHY_RX_CLK] = &cam_cc_ife_0_cphy_rx_clk.clkr, + [CAM_CC_IFE_0_CSID_CLK] = &cam_cc_ife_0_csid_clk.clkr, + [CAM_CC_IFE_0_CSID_CLK_SRC] = &cam_cc_ife_0_csid_clk_src.clkr, + [CAM_CC_IFE_0_DSP_CLK] = &cam_cc_ife_0_dsp_clk.clkr, + [CAM_CC_IFE_1_AXI_CLK] = &cam_cc_ife_1_axi_clk.clkr, + [CAM_CC_IFE_1_CLK] = &cam_cc_ife_1_clk.clkr, + [CAM_CC_IFE_1_CLK_SRC] = &cam_cc_ife_1_clk_src.clkr, + [CAM_CC_IFE_1_CPHY_RX_CLK] = &cam_cc_ife_1_cphy_rx_clk.clkr, + [CAM_CC_IFE_1_CSID_CLK] = &cam_cc_ife_1_csid_clk.clkr, + [CAM_CC_IFE_1_CSID_CLK_SRC] = &cam_cc_ife_1_csid_clk_src.clkr, + [CAM_CC_IFE_1_DSP_CLK] = &cam_cc_ife_1_dsp_clk.clkr, + [CAM_CC_IFE_LITE_CLK] = &cam_cc_ife_lite_clk.clkr, + [CAM_CC_IFE_LITE_CLK_SRC] = &cam_cc_ife_lite_clk_src.clkr, + [CAM_CC_IFE_LITE_CPHY_RX_CLK] = &cam_cc_ife_lite_cphy_rx_clk.clkr, + [CAM_CC_IFE_LITE_CSID_CLK] = &cam_cc_ife_lite_csid_clk.clkr, + [CAM_CC_IFE_LITE_CSID_CLK_SRC] = &cam_cc_ife_lite_csid_clk_src.clkr, + [CAM_CC_IPE_0_AHB_CLK] = &cam_cc_ipe_0_ahb_clk.clkr, + [CAM_CC_IPE_0_AREG_CLK] = &cam_cc_ipe_0_areg_clk.clkr, + [CAM_CC_IPE_0_AXI_CLK] = &cam_cc_ipe_0_axi_clk.clkr, + [CAM_CC_IPE_0_CLK] = &cam_cc_ipe_0_clk.clkr, + [CAM_CC_IPE_0_CLK_SRC] = &cam_cc_ipe_0_clk_src.clkr, + [CAM_CC_IPE_1_AHB_CLK] = &cam_cc_ipe_1_ahb_clk.clkr, + [CAM_CC_IPE_1_AREG_CLK] = &cam_cc_ipe_1_areg_clk.clkr, + [CAM_CC_IPE_1_AXI_CLK] = &cam_cc_ipe_1_axi_clk.clkr, + [CAM_CC_IPE_1_CLK] = &cam_cc_ipe_1_clk.clkr, + [CAM_CC_IPE_1_CLK_SRC] = &cam_cc_ipe_1_clk_src.clkr, + [CAM_CC_JPEG_CLK] = &cam_cc_jpeg_clk.clkr, + [CAM_CC_JPEG_CLK_SRC] = &cam_cc_jpeg_clk_src.clkr, + [CAM_CC_LRME_CLK] = &cam_cc_lrme_clk.clkr, + [CAM_CC_LRME_CLK_SRC] = &cam_cc_lrme_clk_src.clkr, + [CAM_CC_MCLK0_CLK] = &cam_cc_mclk0_clk.clkr, + [CAM_CC_MCLK0_CLK_SRC] = &cam_cc_mclk0_clk_src.clkr, + [CAM_CC_MCLK1_CLK] = &cam_cc_mclk1_clk.clkr, + [CAM_CC_MCLK1_CLK_SRC] = &cam_cc_mclk1_clk_src.clkr, + [CAM_CC_MCLK2_CLK] = &cam_cc_mclk2_clk.clkr, + [CAM_CC_MCLK2_CLK_SRC] = &cam_cc_mclk2_clk_src.clkr, + [CAM_CC_MCLK3_CLK] = &cam_cc_mclk3_clk.clkr, + [CAM_CC_MCLK3_CLK_SRC] = &cam_cc_mclk3_clk_src.clkr, + [CAM_CC_PLL0] = &cam_cc_pll0.clkr, + [CAM_CC_PLL0_OUT_EVEN] = &cam_cc_pll0_out_even.clkr, + [CAM_CC_PLL1] = &cam_cc_pll1.clkr, + [CAM_CC_PLL1_OUT_EVEN] = &cam_cc_pll1_out_even.clkr, + [CAM_CC_PLL2] = &cam_cc_pll2.clkr, + [CAM_CC_PLL2_OUT_EVEN] = &cam_cc_pll2_out_even.clkr, + [CAM_CC_PLL2_OUT_ODD] = &cam_cc_pll2_out_odd.clkr, + [CAM_CC_PLL3] = &cam_cc_pll3.clkr, + [CAM_CC_PLL3_OUT_EVEN] = &cam_cc_pll3_out_even.clkr, + [CAM_CC_PLL_TEST_CLK] = &cam_cc_pll_test_clk.clkr, + [CAM_CC_SLOW_AHB_CLK_SRC] = &cam_cc_slow_ahb_clk_src.clkr, + [CAM_CC_SOC_AHB_CLK] = &cam_cc_soc_ahb_clk.clkr, + [CAM_CC_SYS_TMR_CLK] = &cam_cc_sys_tmr_clk.clkr, +}; + +static const struct qcom_reset_map cam_cc_sdm845_resets[] = { + [TITAN_CAM_CC_CCI_BCR] = { 0xb0d4 }, + [TITAN_CAM_CC_CPAS_BCR] = { 0xb118 }, + [TITAN_CAM_CC_CSI0PHY_BCR] = { 0x5000 }, + [TITAN_CAM_CC_CSI1PHY_BCR] = { 0x5024 }, + [TITAN_CAM_CC_CSI2PHY_BCR] = { 0x5048 }, + [TITAN_CAM_CC_MCLK0_BCR] = { 0x4000 }, + [TITAN_CAM_CC_MCLK1_BCR] = { 0x4020 }, + [TITAN_CAM_CC_MCLK2_BCR] = { 0x4040 }, + [TITAN_CAM_CC_MCLK3_BCR] = { 0x4060 }, + [TITAN_CAM_CC_TITAN_TOP_BCR] = { 0xb130 }, +}; + +static const struct regmap_config cam_cc_sdm845_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0xd004, + .fast_io = true, +}; + +static const struct qcom_cc_desc cam_cc_sdm845_desc = { + .config = &cam_cc_sdm845_regmap_config, + .clks = cam_cc_sdm845_clocks, + .num_clks = ARRAY_SIZE(cam_cc_sdm845_clocks), + .resets = cam_cc_sdm845_resets, + .num_resets = ARRAY_SIZE(cam_cc_sdm845_resets), +}; + +static const struct of_device_id cam_cc_sdm845_match_table[] = { + { .compatible = "qcom,cam_cc-sdm845" }, + { .compatible = "qcom,cam_cc-sdm845-v2" }, + { .compatible = "qcom,cam_cc-sdm670" }, + { } +}; +MODULE_DEVICE_TABLE(of, cam_cc_sdm845_match_table); + +static void cam_cc_sdm845_fixup_sdm845v2(void) +{ + cam_cc_sdm845_clocks[CAM_CC_CSI3PHYTIMER_CLK] = + &cam_cc_csi3phytimer_clk.clkr; + cam_cc_sdm845_clocks[CAM_CC_CSIPHY3_CLK] = &cam_cc_csiphy3_clk.clkr; + cam_cc_sdm845_clocks[CAM_CC_CSI3PHYTIMER_CLK_SRC] = + &cam_cc_csi3phytimer_clk_src.clkr; + cam_cc_bps_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = 0; + cam_cc_bps_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 0; + cam_cc_cci_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = 0; + cam_cc_cci_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 0; + cam_cc_cphy_rx_clk_src.freq_tbl = ftbl_cam_cc_cphy_rx_clk_src_sdm845_v2; + cam_cc_cphy_rx_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = 0; + cam_cc_cphy_rx_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 0; + cam_cc_cphy_rx_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = 384000000; + cam_cc_csi0phytimer_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = 0; + cam_cc_csi0phytimer_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 0; + cam_cc_csi1phytimer_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = 0; + cam_cc_csi1phytimer_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 0; + cam_cc_csi2phytimer_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = 0; + cam_cc_csi2phytimer_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 0; + cam_cc_fast_ahb_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = 0; + cam_cc_fast_ahb_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 0; + cam_cc_fd_core_clk_src.freq_tbl = ftbl_cam_cc_fd_core_clk_src_sdm845_v2; + cam_cc_fd_core_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = 0; + cam_cc_fd_core_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 0; + cam_cc_icp_clk_src.freq_tbl = ftbl_cam_cc_icp_clk_src_sdm845_v2; + cam_cc_icp_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = 0; + cam_cc_icp_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 0; + cam_cc_icp_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW_L1] = 600000000; + cam_cc_ife_0_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = 0; + cam_cc_ife_0_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 0; + cam_cc_ife_0_csid_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = 0; + cam_cc_ife_0_csid_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 0; + cam_cc_ife_0_csid_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = + 384000000; + cam_cc_ife_1_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = 0; + cam_cc_ife_1_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 0; + cam_cc_ife_1_csid_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = 0; + cam_cc_ife_1_csid_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 0; + cam_cc_ife_1_csid_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = + 384000000; + cam_cc_ife_lite_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = 0; + cam_cc_ife_lite_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 0; + cam_cc_ife_lite_csid_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = 0; + cam_cc_ife_lite_csid_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 0; + cam_cc_ife_lite_csid_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = + 384000000; + cam_cc_ipe_0_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = 0; + cam_cc_ipe_0_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 0; + cam_cc_ipe_0_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = 600000000; + cam_cc_ipe_1_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = 0; + cam_cc_ipe_1_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 0; + cam_cc_ipe_1_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = 600000000; + cam_cc_jpeg_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = 0; + cam_cc_jpeg_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 0; + cam_cc_lrme_clk_src.freq_tbl = ftbl_cam_cc_lrme_clk_src_sdm845_v2; + cam_cc_lrme_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = 0; + cam_cc_lrme_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 0; + cam_cc_lrme_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = 269333333; + cam_cc_lrme_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW_L1] = 320000000; + cam_cc_lrme_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = 400000000; + cam_cc_mclk0_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = 0; + cam_cc_mclk0_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 0; + cam_cc_mclk0_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = 34285714; + cam_cc_mclk1_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = 0; + cam_cc_mclk1_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 0; + cam_cc_mclk1_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = 34285714; + cam_cc_mclk2_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = 0; + cam_cc_mclk2_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 0; + cam_cc_mclk2_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = 34285714; + cam_cc_mclk3_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = 0; + cam_cc_mclk3_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 0; + cam_cc_mclk3_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = 34285714; + cam_cc_slow_ahb_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = 0; + cam_cc_slow_ahb_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 0; + cam_cc_slow_ahb_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = 80000000; + cam_cc_slow_ahb_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW_L1] = + 80000000; +} + +static void cam_cc_sdm845_fixup_sdm670(void) +{ + cam_cc_sdm845_clocks[CAM_CC_CSI3PHYTIMER_CLK] = + &cam_cc_csi3phytimer_clk.clkr; + cam_cc_sdm845_clocks[CAM_CC_CSIPHY3_CLK] = &cam_cc_csiphy3_clk.clkr; + cam_cc_sdm845_clocks[CAM_CC_CSI3PHYTIMER_CLK_SRC] = + &cam_cc_csi3phytimer_clk_src.clkr; + cam_cc_cphy_rx_clk_src.freq_tbl = ftbl_cam_cc_cphy_rx_clk_src_sdm845_v2; + cam_cc_cphy_rx_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 384000000; + cam_cc_cphy_rx_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = 384000000; + cam_cc_fd_core_clk_src.freq_tbl = ftbl_cam_cc_fd_core_clk_src_sdm845_v2; + cam_cc_fd_core_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 384000000; + cam_cc_icp_clk_src.freq_tbl = ftbl_cam_cc_icp_clk_src_sdm845_v2; + cam_cc_icp_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 384000000; + cam_cc_icp_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW_L1] = 600000000; + cam_cc_ipe_0_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = 600000000; + cam_cc_ipe_1_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = 600000000; + cam_cc_lrme_clk_src.freq_tbl = ftbl_cam_cc_lrme_clk_src_sdm845_v2; + cam_cc_lrme_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = 269333333; + cam_cc_lrme_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW_L1] = 320000000; + cam_cc_lrme_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = 400000000; + cam_cc_slow_ahb_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 80000000; + cam_cc_slow_ahb_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = 80000000; + cam_cc_slow_ahb_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW_L1] = + 80000000; +} + +static int cam_cc_sdm845_fixup(struct platform_device *pdev) +{ + const char *compat = NULL; + int compatlen = 0; + + compat = of_get_property(pdev->dev.of_node, "compatible", &compatlen); + if (!compat || (compatlen <= 0)) + return -EINVAL; + + if (!strcmp(compat, "qcom,cam_cc-sdm845-v2")) + cam_cc_sdm845_fixup_sdm845v2(); + else if (!strcmp(compat, "qcom,cam_cc-sdm670")) + cam_cc_sdm845_fixup_sdm670(); + + return 0; +} + +static int cam_cc_sdm845_probe(struct platform_device *pdev) +{ + struct regmap *regmap; + int ret = 0; + + regmap = qcom_cc_map(pdev, &cam_cc_sdm845_desc); + if (IS_ERR(regmap)) { + pr_err("Failed to map the Camera CC registers\n"); + return PTR_ERR(regmap); + } + + vdd_cx.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_cx"); + if (IS_ERR(vdd_cx.regulator[0])) { + if (!(PTR_ERR(vdd_cx.regulator[0]) == -EPROBE_DEFER)) + dev_err(&pdev->dev, + "Unable to get vdd_cx regulator\n"); + return PTR_ERR(vdd_cx.regulator[0]); + } + + vdd_mx.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_mx"); + if (IS_ERR(vdd_mx.regulator[0])) { + if (!(PTR_ERR(vdd_mx.regulator[0]) == -EPROBE_DEFER)) + dev_err(&pdev->dev, + "Unable to get vdd_mx regulator\n"); + return PTR_ERR(vdd_mx.regulator[0]); + } + + ret = cam_cc_sdm845_fixup(pdev); + if (ret) + return ret; + + clk_fabia_pll_configure(&cam_cc_pll0, regmap, &cam_cc_pll0_config); + clk_fabia_pll_configure(&cam_cc_pll1, regmap, &cam_cc_pll1_config); + clk_fabia_pll_configure(&cam_cc_pll2, regmap, &cam_cc_pll2_config); + clk_fabia_pll_configure(&cam_cc_pll3, regmap, &cam_cc_pll3_config); + + ret = qcom_cc_really_probe(pdev, &cam_cc_sdm845_desc, regmap); + if (ret) { + dev_err(&pdev->dev, "Failed to register Camera CC clocks\n"); + return ret; + } + + dev_info(&pdev->dev, "Registered Camera CC clocks\n"); + return ret; +} + +static struct platform_driver cam_cc_sdm845_driver = { + .probe = cam_cc_sdm845_probe, + .driver = { + .name = "cam_cc-sdm845", + .of_match_table = cam_cc_sdm845_match_table, + }, +}; + +static int __init cam_cc_sdm845_init(void) +{ + return platform_driver_register(&cam_cc_sdm845_driver); +} +subsys_initcall(cam_cc_sdm845_init); + +static void __exit cam_cc_sdm845_exit(void) +{ + platform_driver_unregister(&cam_cc_sdm845_driver); +} +module_exit(cam_cc_sdm845_exit); + +MODULE_DESCRIPTION("QTI CAM_CC SDM845 Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:cam_cc-sdm845"); diff --git a/drivers/clk/qcom/debugcc-sdm845.c b/drivers/clk/qcom/debugcc-sdm845.c new file mode 100644 index 000000000000..3c1121f6a17a --- /dev/null +++ b/drivers/clk/qcom/debugcc-sdm845.c @@ -0,0 +1,916 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "clk: %s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "clk-debug.h" + +static struct measure_clk_data debug_mux_priv = { + .ctl_reg = 0x62024, + .status_reg = 0x62028, + .xo_div4_cbcr = 0x43008, +}; + +static const char *const debug_mux_parent_names[] = { + "cam_cc_bps_ahb_clk", + "cam_cc_bps_areg_clk", + "cam_cc_bps_axi_clk", + "cam_cc_bps_clk", + "cam_cc_camnoc_atb_clk", + "cam_cc_camnoc_axi_clk", + "cam_cc_cci_clk", + "cam_cc_cpas_ahb_clk", + "cam_cc_csi0phytimer_clk", + "cam_cc_csi1phytimer_clk", + "cam_cc_csi2phytimer_clk", + "cam_cc_csiphy0_clk", + "cam_cc_csiphy1_clk", + "cam_cc_csiphy2_clk", + "cam_cc_csiphy3_clk", + "cam_cc_fd_core_clk", + "cam_cc_fd_core_uar_clk", + "cam_cc_icp_apb_clk", + "cam_cc_icp_atb_clk", + "cam_cc_icp_clk", + "cam_cc_icp_cti_clk", + "cam_cc_icp_ts_clk", + "cam_cc_ife_0_axi_clk", + "cam_cc_ife_0_clk", + "cam_cc_ife_0_cphy_rx_clk", + "cam_cc_ife_0_csid_clk", + "cam_cc_ife_0_dsp_clk", + "cam_cc_ife_1_axi_clk", + "cam_cc_ife_1_clk", + "cam_cc_ife_1_cphy_rx_clk", + "cam_cc_ife_1_csid_clk", + "cam_cc_ife_1_dsp_clk", + "cam_cc_ife_lite_clk", + "cam_cc_ife_lite_cphy_rx_clk", + "cam_cc_ife_lite_csid_clk", + "cam_cc_ipe_0_ahb_clk", + "cam_cc_ipe_0_areg_clk", + "cam_cc_ipe_0_axi_clk", + "cam_cc_ipe_0_clk", + "cam_cc_ipe_1_ahb_clk", + "cam_cc_ipe_1_areg_clk", + "cam_cc_ipe_1_axi_clk", + "cam_cc_ipe_1_clk", + "cam_cc_jpeg_clk", + "cam_cc_lrme_clk", + "cam_cc_mclk0_clk", + "cam_cc_mclk1_clk", + "cam_cc_mclk2_clk", + "cam_cc_mclk3_clk", + "cam_cc_soc_ahb_clk", + "cam_cc_sys_tmr_clk", + "disp_cc_mdss_ahb_clk", + "disp_cc_mdss_axi_clk", + "disp_cc_mdss_byte0_clk", + "disp_cc_mdss_byte0_intf_clk", + "disp_cc_mdss_byte1_clk", + "disp_cc_mdss_byte1_intf_clk", + "disp_cc_mdss_dp_aux_clk", + "disp_cc_mdss_dp_crypto_clk", + "disp_cc_mdss_dp_link_clk", + "disp_cc_mdss_dp_link_intf_clk", + "disp_cc_mdss_dp_pixel1_clk", + "disp_cc_mdss_dp_pixel_clk", + "disp_cc_mdss_esc0_clk", + "disp_cc_mdss_esc1_clk", + "disp_cc_mdss_mdp_clk", + "disp_cc_mdss_mdp_lut_clk", + "disp_cc_mdss_pclk0_clk", + "disp_cc_mdss_pclk1_clk", + "disp_cc_mdss_qdss_at_clk", + "disp_cc_mdss_qdss_tsctr_div8_clk", + "disp_cc_mdss_rot_clk", + "disp_cc_mdss_rscc_ahb_clk", + "disp_cc_mdss_rscc_vsync_clk", + "disp_cc_mdss_vsync_clk", + "measure_only_snoc_clk", + "measure_only_cnoc_clk", + "measure_only_bimc_clk", + "measure_only_ipa_2x_clk", + "gcc_aggre_noc_pcie_tbu_clk", + "gcc_aggre_ufs_card_axi_clk", + "gcc_aggre_ufs_phy_axi_clk", + "gcc_aggre_usb3_prim_axi_clk", + "gcc_aggre_usb3_sec_axi_clk", + "gcc_apc_vs_clk", + "gcc_boot_rom_ahb_clk", + "gcc_camera_ahb_clk", + "gcc_camera_axi_clk", + "gcc_camera_xo_clk", + "gcc_ce1_ahb_clk", + "gcc_ce1_axi_clk", + "gcc_ce1_clk", + "gcc_cfg_noc_usb3_prim_axi_clk", + "gcc_cfg_noc_usb3_sec_axi_clk", + "gcc_cpuss_ahb_clk", + "gcc_cpuss_dvm_bus_clk", + "gcc_cpuss_gnoc_clk", + "gcc_cpuss_rbcpr_clk", + "gcc_ddrss_gpu_axi_clk", + "gcc_disp_ahb_clk", + "gcc_disp_axi_clk", + "gcc_disp_gpll0_clk_src", + "gcc_disp_gpll0_div_clk_src", + "gcc_disp_xo_clk", + "gcc_gp1_clk", + "gcc_gp2_clk", + "gcc_gp3_clk", + "gcc_gpu_cfg_ahb_clk", + "gcc_gpu_gpll0_clk_src", + "gcc_gpu_gpll0_div_clk_src", + "gcc_gpu_memnoc_gfx_clk", + "gcc_gpu_snoc_dvm_gfx_clk", + "gcc_gpu_vs_clk", + "gcc_mss_axis2_clk", + "gcc_mss_cfg_ahb_clk", + "gcc_mss_gpll0_div_clk_src", + "gcc_mss_mfab_axis_clk", + "gcc_mss_q6_memnoc_axi_clk", + "gcc_mss_snoc_axi_clk", + "gcc_mss_vs_clk", + "gcc_pcie_0_aux_clk", + "gcc_pcie_0_cfg_ahb_clk", + "gcc_pcie_0_mstr_axi_clk", + "gcc_pcie_0_pipe_clk", + "gcc_pcie_0_slv_axi_clk", + "gcc_pcie_0_slv_q2a_axi_clk", + "gcc_pcie_1_aux_clk", + "gcc_pcie_1_cfg_ahb_clk", + "gcc_pcie_1_mstr_axi_clk", + "gcc_pcie_1_pipe_clk", + "gcc_pcie_1_slv_axi_clk", + "gcc_pcie_1_slv_q2a_axi_clk", + "gcc_pcie_phy_aux_clk", + "gcc_pcie_phy_refgen_clk", + "gcc_pdm2_clk", + "gcc_pdm_ahb_clk", + "gcc_pdm_xo4_clk", + "gcc_prng_ahb_clk", + "gcc_qmip_camera_ahb_clk", + "gcc_qmip_disp_ahb_clk", + "gcc_qmip_video_ahb_clk", + "gcc_qupv3_wrap0_core_2x_clk", + "gcc_qupv3_wrap0_core_clk", + "gcc_qupv3_wrap0_s0_clk", + "gcc_qupv3_wrap0_s1_clk", + "gcc_qupv3_wrap0_s2_clk", + "gcc_qupv3_wrap0_s3_clk", + "gcc_qupv3_wrap0_s4_clk", + "gcc_qupv3_wrap0_s5_clk", + "gcc_qupv3_wrap0_s6_clk", + "gcc_qupv3_wrap0_s7_clk", + "gcc_qupv3_wrap1_core_2x_clk", + "gcc_qupv3_wrap1_core_clk", + "gcc_qupv3_wrap1_s0_clk", + "gcc_qupv3_wrap1_s1_clk", + "gcc_qupv3_wrap1_s2_clk", + "gcc_qupv3_wrap1_s3_clk", + "gcc_qupv3_wrap1_s4_clk", + "gcc_qupv3_wrap1_s5_clk", + "gcc_qupv3_wrap1_s6_clk", + "gcc_qupv3_wrap1_s7_clk", + "gcc_qupv3_wrap_0_m_ahb_clk", + "gcc_qupv3_wrap_0_s_ahb_clk", + "gcc_qupv3_wrap_1_m_ahb_clk", + "gcc_qupv3_wrap_1_s_ahb_clk", + "gcc_sdcc2_ahb_clk", + "gcc_sdcc2_apps_clk", + "gcc_sdcc4_ahb_clk", + "gcc_sdcc4_apps_clk", + "gcc_sys_noc_cpuss_ahb_clk", + "gcc_tsif_ahb_clk", + "gcc_tsif_inactivity_timers_clk", + "gcc_tsif_ref_clk", + "gcc_ufs_card_ahb_clk", + "gcc_ufs_card_axi_clk", + "gcc_ufs_card_ice_core_clk", + "gcc_ufs_card_phy_aux_clk", + "gcc_ufs_card_rx_symbol_0_clk", + "gcc_ufs_card_rx_symbol_1_clk", + "gcc_ufs_card_tx_symbol_0_clk", + "gcc_ufs_card_unipro_core_clk", + "gcc_ufs_phy_ahb_clk", + "gcc_ufs_phy_axi_clk", + "gcc_ufs_phy_ice_core_clk", + "gcc_ufs_phy_phy_aux_clk", + "gcc_ufs_phy_rx_symbol_0_clk", + "gcc_ufs_phy_rx_symbol_1_clk", + "gcc_ufs_phy_tx_symbol_0_clk", + "gcc_ufs_phy_unipro_core_clk", + "gcc_usb30_prim_master_clk", + "gcc_usb30_prim_mock_utmi_clk", + "gcc_usb30_prim_sleep_clk", + "gcc_usb30_sec_master_clk", + "gcc_usb30_sec_mock_utmi_clk", + "gcc_usb30_sec_sleep_clk", + "gcc_usb3_prim_phy_aux_clk", + "gcc_usb3_prim_phy_com_aux_clk", + "gcc_usb3_prim_phy_pipe_clk", + "gcc_usb3_sec_phy_aux_clk", + "gcc_usb3_sec_phy_com_aux_clk", + "gcc_usb3_sec_phy_pipe_clk", + "gcc_usb_phy_cfg_ahb2phy_clk", + "gcc_vdda_vs_clk", + "gcc_vddcx_vs_clk", + "gcc_vddmx_vs_clk", + "gcc_video_ahb_clk", + "gcc_video_axi_clk", + "gcc_video_xo_clk", + "gcc_vs_ctrl_ahb_clk", + "gcc_vs_ctrl_clk", + "gcc_sdcc1_ahb_clk", + "gcc_sdcc1_apps_clk", + "gcc_sdcc1_ice_core_clk", + "gpu_cc_acd_cxo_clk", + "gpu_cc_crc_ahb_clk", + "gpu_cc_cx_apb_clk", + "gpu_cc_cx_gfx3d_clk", + "gpu_cc_cx_gfx3d_slv_clk", + "gpu_cc_cx_gmu_clk", + "gpu_cc_cx_qdss_at_clk", + "gpu_cc_cx_qdss_trig_clk", + "gpu_cc_cx_qdss_tsctr_clk", + "gpu_cc_cx_snoc_dvm_clk", + "gpu_cc_cxo_aon_clk", + "gpu_cc_cxo_clk", + "gpu_cc_gx_gfx3d_clk", + "gpu_cc_gx_gmu_clk", + "gpu_cc_gx_qdss_tsctr_clk", + "gpu_cc_gx_vsense_clk", + "gpu_cc_rbcpr_ahb_clk", + "gpu_cc_rbcpr_clk", + "gpu_cc_sleep_clk", + "video_cc_apb_clk", + "video_cc_at_clk", + "video_cc_qdss_trig_clk", + "video_cc_qdss_tsctr_div8_clk", + "video_cc_vcodec0_axi_clk", + "video_cc_vcodec0_core_clk", + "video_cc_vcodec1_axi_clk", + "video_cc_vcodec1_core_clk", + "video_cc_venus_ahb_clk", + "video_cc_venus_ctl_axi_clk", + "video_cc_venus_ctl_core_clk", + "l3_clk", + "pwrcl_clk", + "perfcl_clk", +}; + +static struct clk_debug_mux gcc_debug_mux = { + .priv = &debug_mux_priv, + .debug_offset = 0x62008, + .post_div_offset = 0x62000, + .cbcr_offset = 0x62004, + .src_sel_mask = 0x3FF, + .src_sel_shift = 0, + .post_div_mask = 0xF, + .post_div_shift = 0, + MUX_SRC_LIST( + { "cam_cc_bps_ahb_clk", 0x46, 4, CAM_CC, + 0xE, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, + { "cam_cc_bps_areg_clk", 0x46, 4, CAM_CC, + 0xD, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, + { "cam_cc_bps_axi_clk", 0x46, 4, CAM_CC, + 0xC, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, + { "cam_cc_bps_clk", 0x46, 4, CAM_CC, + 0xB, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, + { "cam_cc_camnoc_atb_clk", 0x46, 4, CAM_CC, + 0x34, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, + { "cam_cc_camnoc_axi_clk", 0x46, 4, CAM_CC, + 0x2D, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, + { "cam_cc_cci_clk", 0x46, 4, CAM_CC, + 0x2A, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, + { "cam_cc_cpas_ahb_clk", 0x46, 4, CAM_CC, + 0x2C, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, + { "cam_cc_csi0phytimer_clk", 0x46, 4, CAM_CC, + 0x5, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, + { "cam_cc_csi1phytimer_clk", 0x46, 4, CAM_CC, + 0x7, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, + { "cam_cc_csi2phytimer_clk", 0x46, 4, CAM_CC, + 0x9, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, + { "cam_cc_csiphy0_clk", 0x46, 4, CAM_CC, + 0x6, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, + { "cam_cc_csiphy1_clk", 0x46, 4, CAM_CC, + 0x8, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, + { "cam_cc_csiphy2_clk", 0x46, 4, CAM_CC, + 0xA, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, + { "cam_cc_csiphy3_clk", 0x46, 4, CAM_CC, + 0x36, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, + { "cam_cc_fd_core_clk", 0x46, 4, CAM_CC, + 0x28, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, + { "cam_cc_fd_core_uar_clk", 0x46, 4, CAM_CC, + 0x29, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, + { "cam_cc_icp_apb_clk", 0x46, 4, CAM_CC, + 0x32, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, + { "cam_cc_icp_atb_clk", 0x46, 4, CAM_CC, + 0x2F, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, + { "cam_cc_icp_clk", 0x46, 4, CAM_CC, + 0x26, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, + { "cam_cc_icp_cti_clk", 0x46, 4, CAM_CC, + 0x30, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, + { "cam_cc_icp_ts_clk", 0x46, 4, CAM_CC, + 0x31, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, + { "cam_cc_ife_0_axi_clk", 0x46, 4, CAM_CC, + 0x1B, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, + { "cam_cc_ife_0_clk", 0x46, 4, CAM_CC, + 0x17, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, + { "cam_cc_ife_0_cphy_rx_clk", 0x46, 4, CAM_CC, + 0x1A, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, + { "cam_cc_ife_0_csid_clk", 0x46, 4, CAM_CC, + 0x19, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, + { "cam_cc_ife_0_dsp_clk", 0x46, 4, CAM_CC, + 0x18, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, + { "cam_cc_ife_1_axi_clk", 0x46, 4, CAM_CC, + 0x21, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, + { "cam_cc_ife_1_clk", 0x46, 4, CAM_CC, + 0x1D, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, + { "cam_cc_ife_1_cphy_rx_clk", 0x46, 4, CAM_CC, + 0x20, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, + { "cam_cc_ife_1_csid_clk", 0x46, 4, CAM_CC, + 0x1F, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, + { "cam_cc_ife_1_dsp_clk", 0x46, 4, CAM_CC, + 0x1E, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, + { "cam_cc_ife_lite_clk", 0x46, 4, CAM_CC, + 0x22, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, + { "cam_cc_ife_lite_cphy_rx_clk", 0x46, 4, CAM_CC, + 0x24, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, + { "cam_cc_ife_lite_csid_clk", 0x46, 4, CAM_CC, + 0x23, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, + { "cam_cc_ipe_0_ahb_clk", 0x46, 4, CAM_CC, + 0x12, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, + { "cam_cc_ipe_0_areg_clk", 0x46, 4, CAM_CC, + 0x11, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, + { "cam_cc_ipe_0_axi_clk", 0x46, 4, CAM_CC, + 0x10, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, + { "cam_cc_ipe_0_clk", 0x46, 4, CAM_CC, + 0xF, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, + { "cam_cc_ipe_1_ahb_clk", 0x46, 4, CAM_CC, + 0x16, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, + { "cam_cc_ipe_1_areg_clk", 0x46, 4, CAM_CC, + 0x15, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, + { "cam_cc_ipe_1_axi_clk", 0x46, 4, CAM_CC, + 0x14, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, + { "cam_cc_ipe_1_clk", 0x46, 4, CAM_CC, + 0x13, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, + { "cam_cc_jpeg_clk", 0x46, 4, CAM_CC, + 0x25, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, + { "cam_cc_lrme_clk", 0x46, 4, CAM_CC, + 0x2B, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, + { "cam_cc_mclk0_clk", 0x46, 4, CAM_CC, + 0x1, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, + { "cam_cc_mclk1_clk", 0x46, 4, CAM_CC, + 0x2, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, + { "cam_cc_mclk2_clk", 0x46, 4, CAM_CC, + 0x3, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, + { "cam_cc_mclk3_clk", 0x46, 4, CAM_CC, + 0x4, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, + { "cam_cc_soc_ahb_clk", 0x46, 4, CAM_CC, + 0x2E, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, + { "cam_cc_sys_tmr_clk", 0x46, 4, CAM_CC, + 0x33, 0xFF, 0, 0x3, 0, 1, 0xC000, 0xC004, 0xC008 }, + { "disp_cc_mdss_ahb_clk", 0x47, 4, DISP_CC, + 0x13, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C }, + { "disp_cc_mdss_axi_clk", 0x47, 4, DISP_CC, + 0x14, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C }, + { "disp_cc_mdss_byte0_clk", 0x47, 4, DISP_CC, + 0x7, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C }, + { "disp_cc_mdss_byte0_intf_clk", 0x47, 4, DISP_CC, + 0x8, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C }, + { "disp_cc_mdss_byte1_clk", 0x47, 4, DISP_CC, + 0x9, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C }, + { "disp_cc_mdss_byte1_intf_clk", 0x47, 4, DISP_CC, + 0xA, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C }, + { "disp_cc_mdss_dp_aux_clk", 0x47, 4, DISP_CC, + 0x12, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C }, + { "disp_cc_mdss_dp_crypto_clk", 0x47, 4, DISP_CC, + 0xF, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C }, + { "disp_cc_mdss_dp_link_clk", 0x47, 4, DISP_CC, + 0xD, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C }, + { "disp_cc_mdss_dp_link_intf_clk", 0x47, 4, DISP_CC, + 0xE, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C }, + { "disp_cc_mdss_dp_pixel1_clk", 0x47, 4, DISP_CC, + 0x11, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C }, + { "disp_cc_mdss_dp_pixel_clk", 0x47, 4, DISP_CC, + 0x10, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C }, + { "disp_cc_mdss_esc0_clk", 0x47, 4, DISP_CC, + 0xB, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C }, + { "disp_cc_mdss_esc1_clk", 0x47, 4, DISP_CC, + 0xC, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C }, + { "disp_cc_mdss_mdp_clk", 0x47, 4, DISP_CC, + 0x3, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C }, + { "disp_cc_mdss_mdp_lut_clk", 0x47, 4, DISP_CC, + 0x5, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C }, + { "disp_cc_mdss_pclk0_clk", 0x47, 4, DISP_CC, + 0x1, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C }, + { "disp_cc_mdss_pclk1_clk", 0x47, 4, DISP_CC, + 0x2, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C }, + { "disp_cc_mdss_qdss_at_clk", 0x47, 4, DISP_CC, + 0x15, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C }, + { "disp_cc_mdss_qdss_tsctr_div8_clk", 0x47, 4, DISP_CC, + 0x16, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C }, + { "disp_cc_mdss_rot_clk", 0x47, 4, DISP_CC, + 0x4, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C }, + { "disp_cc_mdss_rscc_ahb_clk", 0x47, 4, DISP_CC, + 0x17, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C }, + { "disp_cc_mdss_rscc_vsync_clk", 0x47, 4, DISP_CC, + 0x18, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C }, + { "disp_cc_mdss_vsync_clk", 0x47, 4, DISP_CC, + 0x6, 0xFF, 0, 0x3, 0, 1, 0x6000, 0x6008, 0x600C }, + { "measure_only_snoc_clk", 0x7, 4, GCC, + 0x7, 0x3FFF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "measure_only_cnoc_clk", 0x15, 4, GCC, + 0x7, 0x3FFF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "measure_only_bimc_clk", 0xc2, 4, GCC, + 0x7, 0x3FFF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "measure_only_ipa_2x_clk", 0x128, 4, GCC, + 0x7, 0x3FFF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_aggre_noc_pcie_tbu_clk", 0x2D, 4, GCC, + 0x2D, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_aggre_ufs_card_axi_clk", 0x11E, 4, GCC, + 0x11E, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_aggre_ufs_phy_axi_clk", 0x11D, 4, GCC, + 0x11D, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_aggre_usb3_prim_axi_clk", 0x11B, 4, GCC, + 0x11B, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_aggre_usb3_sec_axi_clk", 0x11C, 4, GCC, + 0x11C, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_apc_vs_clk", 0x113, 4, GCC, + 0x113, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_boot_rom_ahb_clk", 0x94, 4, GCC, + 0x94, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_camera_ahb_clk", 0x3A, 4, GCC, + 0x3A, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_camera_axi_clk", 0x40, 4, GCC, + 0x40, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_camera_xo_clk", 0x43, 4, GCC, + 0x43, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_ce1_ahb_clk", 0xA9, 4, GCC, + 0xA9, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_ce1_axi_clk", 0xA8, 4, GCC, + 0xA8, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_ce1_clk", 0xA7, 4, GCC, + 0xA7, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_cfg_noc_usb3_prim_axi_clk", 0x1D, 4, GCC, + 0x1D, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_cfg_noc_usb3_sec_axi_clk", 0x1E, 4, GCC, + 0x1E, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_cpuss_ahb_clk", 0xCE, 4, GCC, + 0xCE, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_cpuss_dvm_bus_clk", 0xD3, 4, GCC, + 0xD3, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_cpuss_gnoc_clk", 0xCF, 4, GCC, + 0xCF, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_cpuss_rbcpr_clk", 0xD0, 4, GCC, + 0xD0, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_ddrss_gpu_axi_clk", 0xBB, 4, GCC, + 0xBB, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_disp_ahb_clk", 0x3B, 4, GCC, + 0x3B, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_disp_axi_clk", 0x41, 4, GCC, + 0x41, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_disp_gpll0_clk_src", 0x4C, 4, GCC, + 0x4C, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_disp_gpll0_div_clk_src", 0x4D, 4, GCC, + 0x4D, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_disp_xo_clk", 0x44, 4, GCC, + 0x44, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_gp1_clk", 0xDE, 4, GCC, + 0xDE, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_gp2_clk", 0xDF, 4, GCC, + 0xDF, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_gp3_clk", 0xE0, 4, GCC, + 0xE0, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_gpu_cfg_ahb_clk", 0x142, 4, GCC, + 0x142, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_gpu_gpll0_clk_src", 0x148, 4, GCC, + 0x148, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_gpu_gpll0_div_clk_src", 0x149, 4, GCC, + 0x149, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_gpu_memnoc_gfx_clk", 0x145, 4, GCC, + 0x145, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_gpu_snoc_dvm_gfx_clk", 0x147, 4, GCC, + 0x147, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_gpu_vs_clk", 0x112, 4, GCC, + 0x112, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_mss_axis2_clk", 0x12F, 4, GCC, + 0x12F, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_mss_cfg_ahb_clk", 0x12D, 4, GCC, + 0x12D, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_mss_gpll0_div_clk_src", 0x133, 4, GCC, + 0x133, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_mss_mfab_axis_clk", 0x12E, 4, GCC, + 0x12E, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_mss_q6_memnoc_axi_clk", 0x135, 4, GCC, + 0x135, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_mss_snoc_axi_clk", 0x134, 4, GCC, + 0x134, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_mss_vs_clk", 0x111, 4, GCC, + 0x111, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_pcie_0_aux_clk", 0xE5, 4, GCC, + 0xE5, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_pcie_0_cfg_ahb_clk", 0xE4, 4, GCC, + 0xE4, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_pcie_0_mstr_axi_clk", 0xE3, 4, GCC, + 0xE3, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_pcie_0_pipe_clk", 0xE6, 4, GCC, + 0xE6, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_pcie_0_slv_axi_clk", 0xE2, 4, GCC, + 0xE2, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_pcie_0_slv_q2a_axi_clk", 0xE1, 4, GCC, + 0xE1, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_pcie_1_aux_clk", 0xEC, 4, GCC, + 0xEC, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_pcie_1_cfg_ahb_clk", 0xEB, 4, GCC, + 0xEB, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_pcie_1_mstr_axi_clk", 0xEA, 4, GCC, + 0xEA, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_pcie_1_pipe_clk", 0xED, 4, GCC, + 0xED, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_pcie_1_slv_axi_clk", 0xE9, 4, GCC, + 0xE9, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_pcie_1_slv_q2a_axi_clk", 0xE8, 4, GCC, + 0xE8, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_pcie_phy_aux_clk", 0xEF, 4, GCC, + 0xEF, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_pcie_phy_refgen_clk", 0x160, 4, GCC, + 0x160, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_pdm2_clk", 0x8E, 4, GCC, + 0x8E, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_pdm_ahb_clk", 0x8C, 4, GCC, + 0x8C, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_pdm_xo4_clk", 0x8D, 4, GCC, + 0x8D, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_prng_ahb_clk", 0x8F, 4, GCC, + 0x8F, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_qmip_camera_ahb_clk", 0x3D, 4, GCC, + 0x3D, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_qmip_disp_ahb_clk", 0x3E, 4, GCC, + 0x3E, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_qmip_video_ahb_clk", 0x3C, 4, GCC, + 0x3C, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_qupv3_wrap0_core_2x_clk", 0x77, 4, GCC, + 0x77, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_qupv3_wrap0_core_clk", 0x76, 4, GCC, + 0x76, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_qupv3_wrap0_s0_clk", 0x78, 4, GCC, + 0x78, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_qupv3_wrap0_s1_clk", 0x79, 4, GCC, + 0x79, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_qupv3_wrap0_s2_clk", 0x7A, 4, GCC, + 0x7A, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_qupv3_wrap0_s3_clk", 0x7B, 4, GCC, + 0x7B, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_qupv3_wrap0_s4_clk", 0x7C, 4, GCC, + 0x7C, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_qupv3_wrap0_s5_clk", 0x7D, 4, GCC, + 0x7D, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_qupv3_wrap0_s6_clk", 0x7E, 4, GCC, + 0x7E, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_qupv3_wrap0_s7_clk", 0x7F, 4, GCC, + 0x7F, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_qupv3_wrap1_core_2x_clk", 0x80, 4, GCC, + 0x80, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_qupv3_wrap1_core_clk", 0x81, 4, GCC, + 0x81, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_qupv3_wrap1_s0_clk", 0x84, 4, GCC, + 0x84, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_qupv3_wrap1_s1_clk", 0x85, 4, GCC, + 0x85, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_qupv3_wrap1_s2_clk", 0x86, 4, GCC, + 0x86, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_qupv3_wrap1_s3_clk", 0x87, 4, GCC, + 0x87, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_qupv3_wrap1_s4_clk", 0x88, 4, GCC, + 0x88, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_qupv3_wrap1_s5_clk", 0x89, 4, GCC, + 0x89, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_qupv3_wrap1_s6_clk", 0x8A, 4, GCC, + 0x8A, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_qupv3_wrap1_s7_clk", 0x8B, 4, GCC, + 0x8B, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_qupv3_wrap_0_m_ahb_clk", 0x74, 4, GCC, + 0x74, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_qupv3_wrap_0_s_ahb_clk", 0x75, 4, GCC, + 0x75, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_qupv3_wrap_1_m_ahb_clk", 0x82, 4, GCC, + 0x82, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_qupv3_wrap_1_s_ahb_clk", 0x83, 4, GCC, + 0x83, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_sdcc2_ahb_clk", 0x71, 4, GCC, + 0x71, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_sdcc2_apps_clk", 0x70, 4, GCC, + 0x70, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_sdcc4_ahb_clk", 0x73, 4, GCC, + 0x73, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_sdcc4_apps_clk", 0x72, 4, GCC, + 0x72, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_sys_noc_cpuss_ahb_clk", 0xC, 4, GCC, + 0xC, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_tsif_ahb_clk", 0x90, 4, GCC, + 0x90, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_tsif_inactivity_timers_clk", 0x92, 4, GCC, + 0x92, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_tsif_ref_clk", 0x91, 4, GCC, + 0x91, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_ufs_card_ahb_clk", 0xF1, 4, GCC, + 0xF1, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_ufs_card_axi_clk", 0xF0, 4, GCC, + 0xF0, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_ufs_card_ice_core_clk", 0xF7, 4, GCC, + 0xF7, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_ufs_card_phy_aux_clk", 0xF8, 4, GCC, + 0xF8, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_ufs_card_rx_symbol_0_clk", 0xF3, 4, GCC, + 0xF3, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_ufs_card_rx_symbol_1_clk", 0xF9, 4, GCC, + 0xF9, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_ufs_card_tx_symbol_0_clk", 0xF2, 4, GCC, + 0xF2, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_ufs_card_unipro_core_clk", 0xF6, 4, GCC, + 0xF6, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_ufs_phy_ahb_clk", 0xFC, 4, GCC, + 0xFC, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_ufs_phy_axi_clk", 0xFB, 4, GCC, + 0xFB, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_ufs_phy_ice_core_clk", 0x102, 4, GCC, + 0x102, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_ufs_phy_phy_aux_clk", 0x103, 4, GCC, + 0x103, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_ufs_phy_rx_symbol_0_clk", 0xFE, 4, GCC, + 0xFE, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_ufs_phy_rx_symbol_1_clk", 0x104, 4, GCC, + 0x104, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_ufs_phy_tx_symbol_0_clk", 0xFD, 4, GCC, + 0xFD, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_ufs_phy_unipro_core_clk", 0x101, 4, GCC, + 0x101, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_usb30_prim_master_clk", 0x5F, 4, GCC, + 0x5F, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_usb30_prim_mock_utmi_clk", 0x61, 4, GCC, + 0x61, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_usb30_prim_sleep_clk", 0x60, 4, GCC, + 0x60, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_usb30_sec_master_clk", 0x65, 4, GCC, + 0x65, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_usb30_sec_mock_utmi_clk", 0x67, 4, GCC, + 0x67, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_usb30_sec_sleep_clk", 0x66, 4, GCC, + 0x66, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_usb3_prim_phy_aux_clk", 0x62, 4, GCC, + 0x62, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_usb3_prim_phy_com_aux_clk", 0x63, 4, GCC, + 0x63, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_usb3_prim_phy_pipe_clk", 0x64, 4, GCC, + 0x64, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_usb3_sec_phy_aux_clk", 0x68, 4, GCC, + 0x68, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_usb3_sec_phy_com_aux_clk", 0x69, 4, GCC, + 0x69, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_usb3_sec_phy_pipe_clk", 0x6A, 4, GCC, + 0x6A, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_usb_phy_cfg_ahb2phy_clk", 0x6F, 4, GCC, + 0x6F, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_vdda_vs_clk", 0x10E, 4, GCC, + 0x10E, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_vddcx_vs_clk", 0x10C, 4, GCC, + 0x10C, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_vddmx_vs_clk", 0x10D, 4, GCC, + 0x10D, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_video_ahb_clk", 0x39, 4, GCC, + 0x39, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_video_axi_clk", 0x3F, 4, GCC, + 0x3F, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_video_xo_clk", 0x42, 4, GCC, + 0x42, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_vs_ctrl_ahb_clk", 0x110, 4, GCC, + 0x110, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_vs_ctrl_clk", 0x10F, 4, GCC, + 0x10F, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_sdcc1_ahb_clk", 0x15C, 4, GCC, + 0x42, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_sdcc1_apps_clk", 0x15B, 4, GCC, + 0x42, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gcc_sdcc1_ice_core_clk", 0x15D, 4, GCC, + 0x42, 0x3FF, 0, 0xF, 0, 4, 0x62008, 0x62000, 0x62004 }, + { "gpu_cc_acd_cxo_clk", 0x144, 4, GPU_CC, + 0x1F, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 }, + { "gpu_cc_crc_ahb_clk", 0x144, 4, GPU_CC, + 0x12, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 }, + { "gpu_cc_cx_apb_clk", 0x144, 4, GPU_CC, + 0x15, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 }, + { "gpu_cc_cx_gfx3d_clk", 0x144, 4, GPU_CC, + 0x1A, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 }, + { "gpu_cc_cx_gfx3d_slv_clk", 0x144, 4, GPU_CC, + 0x1B, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 }, + { "gpu_cc_cx_gmu_clk", 0x144, 4, GPU_CC, + 0x19, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 }, + { "gpu_cc_cx_qdss_at_clk", 0x144, 4, GPU_CC, + 0x13, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 }, + { "gpu_cc_cx_qdss_trig_clk", 0x144, 4, GPU_CC, + 0x18, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 }, + { "gpu_cc_cx_qdss_tsctr_clk", 0x144, 4, GPU_CC, + 0x14, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 }, + { "gpu_cc_cx_snoc_dvm_clk", 0x144, 4, GPU_CC, + 0x16, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 }, + { "gpu_cc_cxo_aon_clk", 0x144, 4, GPU_CC, + 0xB, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 }, + { "gpu_cc_cxo_clk", 0x144, 4, GPU_CC, + 0xA, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 }, + { "gpu_cc_gx_gfx3d_clk", 0x144, 4, GPU_CC, + 0xC, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 }, + { "gpu_cc_gx_gmu_clk", 0x144, 4, GPU_CC, + 0x10, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 }, + { "gpu_cc_gx_qdss_tsctr_clk", 0x144, 4, GPU_CC, + 0xE, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 }, + { "gpu_cc_gx_vsense_clk", 0x144, 4, GPU_CC, + 0xD, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 }, + { "gpu_cc_rbcpr_ahb_clk", 0x144, 4, GPU_CC, + 0x1D, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 }, + { "gpu_cc_rbcpr_clk", 0x144, 4, GPU_CC, + 0x1C, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 }, + { "gpu_cc_sleep_clk", 0x144, 4, GPU_CC, + 0x17, 0xFF, 0, 0x3, 0, 1, 0x1568, 0x10FC, 0x1100 }, + { "video_cc_apb_clk", 0x48, 4, VIDEO_CC, + 0x8, 0x3F, 0, 0x7, 0, 1, 0xA4C, 0xA50, 0xA58 }, + { "video_cc_at_clk", 0x48, 4, VIDEO_CC, + 0xB, 0x3F, 0, 0x7, 0, 1, 0xA4C, 0xA50, 0xA58 }, + { "video_cc_qdss_trig_clk", 0x48, 4, VIDEO_CC, + 0x7, 0x3F, 0, 0x7, 0, 1, 0xA4C, 0xA50, 0xA58 }, + { "video_cc_qdss_tsctr_div8_clk", 0x48, 4, VIDEO_CC, + 0xA, 0x3F, 0, 0x7, 0, 1, 0xA4C, 0xA50, 0xA58 }, + { "video_cc_vcodec0_axi_clk", 0x48, 4, VIDEO_CC, + 0x5, 0x3F, 0, 0x7, 0, 1, 0xA4C, 0xA50, 0xA58 }, + { "video_cc_vcodec0_core_clk", 0x48, 4, VIDEO_CC, + 0x2, 0x3F, 0, 0x7, 0, 1, 0xA4C, 0xA50, 0xA58 }, + { "video_cc_vcodec1_axi_clk", 0x48, 4, VIDEO_CC, + 0x6, 0x3F, 0, 0x7, 0, 1, 0xA4C, 0xA50, 0xA58 }, + { "video_cc_vcodec1_core_clk", 0x48, 4, VIDEO_CC, + 0x3, 0x3F, 0, 0x7, 0, 1, 0xA4C, 0xA50, 0xA58 }, + { "video_cc_venus_ahb_clk", 0x48, 4, VIDEO_CC, + 0x9, 0x3F, 0, 0x7, 0, 1, 0xA4C, 0xA50, 0xA58 }, + { "video_cc_venus_ctl_axi_clk", 0x48, 4, VIDEO_CC, + 0x4, 0x3F, 0, 0x7, 0, 1, 0xA4C, 0xA50, 0xA58 }, + { "video_cc_venus_ctl_core_clk", 0x48, 4, VIDEO_CC, + 0x1, 0x3F, 0, 0x7, 0, 1, 0xA4C, 0xA50, 0xA58 }, + { "l3_clk", 0xD6, 4, CPU, + 0x46, 0x7F, 4, 0xf, 11, 1, 0x0, 0x0, U32_MAX, 16 }, + { "pwrcl_clk", 0xD6, 4, CPU, + 0x44, 0x7F, 4, 0xf, 11, 1, 0x0, 0x0, U32_MAX, 16 }, + { "perfcl_clk", 0xD6, 4, CPU, + 0x45, 0x7F, 4, 0xf, 11, 1, 0x0, 0x0, U32_MAX, 16 }, + ), + .hw.init = &(struct clk_init_data){ + .name = "gcc_debug_mux", + .ops = &clk_debug_mux_ops, + .parent_names = debug_mux_parent_names, + .num_parents = ARRAY_SIZE(debug_mux_parent_names), + .flags = CLK_IS_MEASURE, + }, +}; + +static const struct of_device_id clk_debug_match_table[] = { + { .compatible = "qcom,debugcc-sdm845" }, + {} +}; + +static int clk_debug_845_probe(struct platform_device *pdev) +{ + struct clk *clk; + int ret = 0, count; + + clk = devm_clk_get(&pdev->dev, "xo_clk_src"); + if (IS_ERR(clk)) { + if (PTR_ERR(clk) != -EPROBE_DEFER) + dev_err(&pdev->dev, "Unable to get xo clock\n"); + return PTR_ERR(clk); + } + + debug_mux_priv.cxo = clk; + + ret = of_property_read_u32(pdev->dev.of_node, "qcom,cc-count", + &count); + if (ret < 0) { + dev_err(&pdev->dev, "Num of debug clock controller not specified\n"); + return ret; + } + + if (!count) { + dev_err(&pdev->dev, "Count of CC cannot be zero\n"); + return -EINVAL; + } + + gcc_debug_mux.regmap = devm_kzalloc(&pdev->dev, + sizeof(struct regmap *) * count, GFP_KERNEL); + if (!gcc_debug_mux.regmap) + return -ENOMEM; + + if (of_get_property(pdev->dev.of_node, "qcom,gcc", NULL)) { + gcc_debug_mux.regmap[GCC] = + syscon_regmap_lookup_by_phandle(pdev->dev.of_node, + "qcom,gcc"); + if (IS_ERR(gcc_debug_mux.regmap[GCC])) { + pr_err("Failed to map qcom,gcc\n"); + return PTR_ERR(gcc_debug_mux.regmap[GCC]); + } + } + + if (of_get_property(pdev->dev.of_node, "qcom,dispcc", NULL)) { + gcc_debug_mux.regmap[DISP_CC] = + syscon_regmap_lookup_by_phandle(pdev->dev.of_node, + "qcom,dispcc"); + if (IS_ERR(gcc_debug_mux.regmap[DISP_CC])) { + pr_err("Failed to map qcom,dispcc\n"); + return PTR_ERR(gcc_debug_mux.regmap[DISP_CC]); + } + } + + if (of_get_property(pdev->dev.of_node, "qcom,videocc", NULL)) { + gcc_debug_mux.regmap[VIDEO_CC] = + syscon_regmap_lookup_by_phandle(pdev->dev.of_node, + "qcom,videocc"); + if (IS_ERR(gcc_debug_mux.regmap[VIDEO_CC])) { + pr_err("Failed to map qcom,videocc\n"); + return PTR_ERR(gcc_debug_mux.regmap[VIDEO_CC]); + } + } + + if (of_get_property(pdev->dev.of_node, "qcom,camcc", NULL)) { + gcc_debug_mux.regmap[CAM_CC] = + syscon_regmap_lookup_by_phandle(pdev->dev.of_node, + "qcom,camcc"); + if (IS_ERR(gcc_debug_mux.regmap[CAM_CC])) { + pr_err("Failed to map qcom,camcc\n"); + return PTR_ERR(gcc_debug_mux.regmap[CAM_CC]); + } + } + + if (of_get_property(pdev->dev.of_node, "qcom,gpucc", NULL)) { + gcc_debug_mux.regmap[GPU_CC] = + syscon_regmap_lookup_by_phandle(pdev->dev.of_node, + "qcom,gpucc"); + if (IS_ERR(gcc_debug_mux.regmap[GPU_CC])) { + pr_err("Failed to map qcom,gpucc\n"); + return PTR_ERR(gcc_debug_mux.regmap[GPU_CC]); + } + } + + if (of_get_property(pdev->dev.of_node, "qcom,cpucc", NULL)) { + gcc_debug_mux.regmap[CPU] = + syscon_regmap_lookup_by_phandle(pdev->dev.of_node, + "qcom,cpucc"); + if (IS_ERR(gcc_debug_mux.regmap[CPU])) { + pr_err("Failed to map qcom,cpucc\n"); + return PTR_ERR(gcc_debug_mux.regmap[CPU]); + } + } + + clk = devm_clk_register(&pdev->dev, &gcc_debug_mux.hw); + if (IS_ERR(clk)) { + dev_err(&pdev->dev, "Unable to register GCC debug mux\n"); + return PTR_ERR(clk); + } + + ret = clk_debug_measure_register(&gcc_debug_mux.hw); + if (ret) + dev_err(&pdev->dev, "Could not register Measure clock\n"); + else + dev_info(&pdev->dev, "Registered debug mux successfully\n"); + + return ret; +} + +static struct platform_driver clk_debug_driver = { + .probe = clk_debug_845_probe, + .driver = { + .name = "debugcc-sdm845", + .of_match_table = clk_debug_match_table, + .owner = THIS_MODULE, + }, +}; + +int __init clk_debug_845_init(void) +{ + return platform_driver_register(&clk_debug_driver); +} +fs_initcall(clk_debug_845_init); + +MODULE_DESCRIPTION("QTI DEBUG CC SDM845 Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:debugcc-sdm845"); diff --git a/drivers/clk/qcom/dispcc-sdm845.c b/drivers/clk/qcom/dispcc-sdm845.c index cb7a2d9247b0..1e4be9871f2f 100644 --- a/drivers/clk/qcom/dispcc-sdm845.c +++ b/drivers/clk/qcom/dispcc-sdm845.c @@ -1,28 +1,46 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. */ -#include -#include +#define pr_fmt(fmt) "clk: %s: " fmt, __func__ + +#include +#include +#include #include +#include +#include +#include +#include +#include #include #include #include -#include "clk-alpha-pll.h" -#include "clk-branch.h" -#include "clk-rcg.h" -#include "clk-regmap-divider.h" #include "common.h" -#include "gdsc.h" +#include "clk-regmap.h" +#include "clk-pll.h" +#include "clk-rcg.h" +#include "clk-branch.h" #include "reset.h" +#include "clk-alpha-pll.h" +#include "vdd-level-sdm845.h" +#include "clk-regmap-divider.h" + +#define DISP_CC_MISC_CMD 0x8000 + +#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } + +static DEFINE_VDD_REGULATORS(vdd_cx, VDD_CX_NUM, 1, vdd_corner); enum { P_BI_TCXO, P_CORE_BI_PLL_TEST_SE, P_DISP_CC_PLL0_OUT_MAIN, + P_DP_PHY_PLL_LINK_CLK, + P_DP_PHY_PLL_VCO_DIV_CLK, P_DSI0_PHY_PLL_OUT_BYTECLK, P_DSI0_PHY_PLL_OUT_DSICLK, P_DSI1_PHY_PLL_OUT_BYTECLK, @@ -45,6 +63,20 @@ static const char * const disp_cc_parent_names_0[] = { "core_bi_pll_test_se", }; +static const struct parent_map disp_cc_parent_map_1[] = { + { P_BI_TCXO, 0 }, + { P_DP_PHY_PLL_LINK_CLK, 1 }, + { P_DP_PHY_PLL_VCO_DIV_CLK, 2 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const disp_cc_parent_names_1[] = { + "bi_tcxo", + "dp_link_clk_divsel_ten", + "dp_vco_divided_clk_src_mux", + "core_bi_pll_test_se", +}; + static const struct parent_map disp_cc_parent_map_2[] = { { P_BI_TCXO, 0 }, { P_CORE_BI_PLL_TEST_SE, 7 }, @@ -85,20 +117,41 @@ static const char * const disp_cc_parent_names_4[] = { "core_bi_pll_test_se", }; +static struct pll_vco fabia_vco[] = { + { 249600000, 2000000000, 0 }, + { 125000000, 1000000000, 1 }, +}; + +static const struct pll_config disp_cc_pll0_config = { + .l = 0x15, + .frac = 0x7c00, +}; + +static const struct pll_config disp_cc_pll0_config_v2 = { + .l = 0x2c, + .frac = 0xcaaa, +}; + static struct clk_alpha_pll disp_cc_pll0 = { .offset = 0x0, - .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], + .vco_table = fabia_vco, + .num_vco = ARRAY_SIZE(fabia_vco), + .type = FABIA_PLL, .clkr = { .hw.init = &(struct clk_init_data){ .name = "disp_cc_pll0", .parent_names = (const char *[]){ "bi_tcxo" }, .num_parents = 1, - .ops = &clk_alpha_pll_fabia_ops, + .ops = &clk_fabia_pll_ops, + VDD_CX_FMAX_MAP4( + MIN, 615000000, + LOW, 1066000000, + LOW_L1, 1600000000, + NOMINAL, 2000000000), }, }, }; -/* Return the HW recalc rate for idle use case */ static struct clk_rcg2 disp_cc_mdss_byte0_clk_src = { .cmd_rcgr = 0x20d0, .mnd_width = 0, @@ -108,12 +161,17 @@ static struct clk_rcg2 disp_cc_mdss_byte0_clk_src = { .name = "disp_cc_mdss_byte0_clk_src", .parent_names = disp_cc_parent_names_0, .num_parents = 4, - .flags = CLK_SET_RATE_PARENT, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, .ops = &clk_byte2_ops, + VDD_CX_FMAX_MAP5( + MIN, 19200000, + LOWER, 150000000, + LOW, 240000000, + LOW_L1, 262500000, + NOMINAL, 358000000), }, }; -/* Return the HW recalc rate for idle use case */ static struct clk_rcg2 disp_cc_mdss_byte1_clk_src = { .cmd_rcgr = 0x20ec, .mnd_width = 0, @@ -123,8 +181,132 @@ static struct clk_rcg2 disp_cc_mdss_byte1_clk_src = { .name = "disp_cc_mdss_byte1_clk_src", .parent_names = disp_cc_parent_names_0, .num_parents = 4, - .flags = CLK_SET_RATE_PARENT, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, .ops = &clk_byte2_ops, + VDD_CX_FMAX_MAP5( + MIN, 19200000, + LOWER, 150000000, + LOW, 240000000, + LOW_L1, 262500000, + NOMINAL, 358000000), + }, +}; + +static const struct freq_tbl ftbl_disp_cc_mdss_dp_aux_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + { } +}; + +static struct clk_rcg2 disp_cc_mdss_dp_aux_clk_src = { + .cmd_rcgr = 0x219c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_2, + .freq_tbl = ftbl_disp_cc_mdss_dp_aux_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_dp_aux_clk_src", + .parent_names = disp_cc_parent_names_2, + .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP1( + MIN, 19200000), + }, +}; + +static const struct freq_tbl ftbl_disp_cc_mdss_dp_crypto_clk_src[] = { + F( 108000, P_DP_PHY_PLL_LINK_CLK, 3, 0, 0), + F( 180000, P_DP_PHY_PLL_LINK_CLK, 3, 0, 0), + F( 360000, P_DP_PHY_PLL_LINK_CLK, 3, 0, 0), + F( 540000, P_DP_PHY_PLL_LINK_CLK, 3, 0, 0), + { } +}; + +static struct clk_rcg2 disp_cc_mdss_dp_crypto_clk_src = { + .cmd_rcgr = 0x2154, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_1, + .freq_tbl = ftbl_disp_cc_mdss_dp_crypto_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_dp_crypto_clk_src", + .parent_names = disp_cc_parent_names_1, + .num_parents = 4, + .flags = CLK_GET_RATE_NOCACHE, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP5( + MIN, 12800, + LOWER, 108000, + LOW, 180000, + LOW_L1, 360000, + NOMINAL, 540000), + }, +}; + +static const struct freq_tbl ftbl_disp_cc_mdss_dp_link_clk_src[] = { + F( 162000, P_DP_PHY_PLL_LINK_CLK, 1, 0, 0), + F( 270000, P_DP_PHY_PLL_LINK_CLK, 1, 0, 0), + F( 540000, P_DP_PHY_PLL_LINK_CLK, 1, 0, 0), + F( 810000, P_DP_PHY_PLL_LINK_CLK, 1, 0, 0), + { } +}; + +static struct clk_rcg2 disp_cc_mdss_dp_link_clk_src = { + .cmd_rcgr = 0x2138, + .mnd_width = 0, + .hid_width = 5, + .parent_map = disp_cc_parent_map_1, + .freq_tbl = ftbl_disp_cc_mdss_dp_link_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_dp_link_clk_src", + .parent_names = disp_cc_parent_names_1, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP5( + MIN, 19200, + LOWER, 162000, + LOW, 270000, + LOW_L1, 540000, + NOMINAL, 810000), + }, +}; + +static struct clk_rcg2 disp_cc_mdss_dp_pixel1_clk_src = { + .cmd_rcgr = 0x2184, + .mnd_width = 16, + .hid_width = 5, + .parent_map = disp_cc_parent_map_1, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_dp_pixel1_clk_src", + .parent_names = disp_cc_parent_names_1, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + .ops = &clk_dp_ops, + VDD_CX_FMAX_MAP4( + MIN, 19200, + LOWER, 202500, + LOW, 296735, + LOW_L1, 675000), + }, +}; + +static struct clk_rcg2 disp_cc_mdss_dp_pixel_clk_src = { + .cmd_rcgr = 0x216c, + .mnd_width = 16, + .hid_width = 5, + .parent_map = disp_cc_parent_map_1, + .clkr.hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_dp_pixel_clk_src", + .parent_names = disp_cc_parent_names_1, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + .ops = &clk_dp_ops, + VDD_CX_FMAX_MAP4( + MIN, 19200, + LOWER, 202500, + LOW, 296735, + LOW_L1, 675000), }, }; @@ -138,12 +320,14 @@ static struct clk_rcg2 disp_cc_mdss_esc0_clk_src = { .mnd_width = 0, .hid_width = 5, .parent_map = disp_cc_parent_map_0, - .freq_tbl = ftbl_disp_cc_mdss_esc0_clk_src, .clkr.hw.init = &(struct clk_init_data){ .name = "disp_cc_mdss_esc0_clk_src", .parent_names = disp_cc_parent_names_0, .num_parents = 4, - .ops = &clk_rcg2_ops, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_esc_ops, + VDD_CX_FMAX_MAP1( + MIN, 19200000), }, }; @@ -152,16 +336,31 @@ static struct clk_rcg2 disp_cc_mdss_esc1_clk_src = { .mnd_width = 0, .hid_width = 5, .parent_map = disp_cc_parent_map_0, - .freq_tbl = ftbl_disp_cc_mdss_esc0_clk_src, .clkr.hw.init = &(struct clk_init_data){ .name = "disp_cc_mdss_esc1_clk_src", .parent_names = disp_cc_parent_names_0, .num_parents = 4, - .ops = &clk_rcg2_ops, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_esc_ops, + VDD_CX_FMAX_MAP1( + MIN, 19200000), }, }; static const struct freq_tbl ftbl_disp_cc_mdss_mdp_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(85714286, P_GPLL0_OUT_MAIN, 7, 0, 0), + F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0), + F(150000000, P_GPLL0_OUT_MAIN, 4, 0, 0), + F(165000000, P_DISP_CC_PLL0_OUT_MAIN, 2.5, 0, 0), + F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0), + F(275000000, P_DISP_CC_PLL0_OUT_MAIN, 1.5, 0, 0), + F(300000000, P_GPLL0_OUT_MAIN, 2, 0, 0), + F(412500000, P_DISP_CC_PLL0_OUT_MAIN, 1, 0, 0), + { } +}; + +static const struct freq_tbl ftbl_disp_cc_mdss_mdp_clk_src_sdm845_v2[] = { F(19200000, P_BI_TCXO, 1, 0, 0), F(85714286, P_GPLL0_OUT_MAIN, 7, 0, 0), F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0), @@ -174,21 +373,41 @@ static const struct freq_tbl ftbl_disp_cc_mdss_mdp_clk_src[] = { { } }; +static const struct freq_tbl ftbl_disp_cc_mdss_mdp_clk_src_sdm670[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(85714286, P_GPLL0_OUT_MAIN, 7, 0, 0), + F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0), + F(150000000, P_GPLL0_OUT_MAIN, 4, 0, 0), + F(171428571, P_GPLL0_OUT_MAIN, 3.5, 0, 0), + F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0), + F(286666667, P_DISP_CC_PLL0_OUT_MAIN, 3, 0, 0), + F(300000000, P_GPLL0_OUT_MAIN, 2, 0, 0), + F(344000000, P_DISP_CC_PLL0_OUT_MAIN, 2.5, 0, 0), + F(430000000, P_DISP_CC_PLL0_OUT_MAIN, 2, 0, 0), + { } +}; + static struct clk_rcg2 disp_cc_mdss_mdp_clk_src = { .cmd_rcgr = 0x2088, .mnd_width = 0, .hid_width = 5, .parent_map = disp_cc_parent_map_3, .freq_tbl = ftbl_disp_cc_mdss_mdp_clk_src, + .enable_safe_config = true, .clkr.hw.init = &(struct clk_init_data){ .name = "disp_cc_mdss_mdp_clk_src", .parent_names = disp_cc_parent_names_3, .num_parents = 5, - .ops = &clk_rcg2_shared_ops, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP4( + MIN, 19200000, + LOWER, 165000000, + LOW, 300000000, + NOMINAL, 412500000), }, }; -/* Return the HW recalc rate for idle use case */ static struct clk_rcg2 disp_cc_mdss_pclk0_clk_src = { .cmd_rcgr = 0x2058, .mnd_width = 8, @@ -198,12 +417,17 @@ static struct clk_rcg2 disp_cc_mdss_pclk0_clk_src = { .name = "disp_cc_mdss_pclk0_clk_src", .parent_names = disp_cc_parent_names_4, .num_parents = 4, - .flags = CLK_SET_RATE_PARENT, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, .ops = &clk_pixel_ops, + VDD_CX_FMAX_MAP5( + MIN, 19200000, + LOWER, 184000000, + LOW, 295000000, + LOW_L1, 350000000, + NOMINAL, 571428571), }, }; -/* Return the HW recalc rate for idle use case */ static struct clk_rcg2 disp_cc_mdss_pclk1_clk_src = { .cmd_rcgr = 0x2070, .mnd_width = 8, @@ -213,12 +437,26 @@ static struct clk_rcg2 disp_cc_mdss_pclk1_clk_src = { .name = "disp_cc_mdss_pclk1_clk_src", .parent_names = disp_cc_parent_names_4, .num_parents = 4, - .flags = CLK_SET_RATE_PARENT, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, .ops = &clk_pixel_ops, + VDD_CX_FMAX_MAP5( + MIN, 19200000, + LOWER, 184000000, + LOW, 295000000, + LOW_L1, 350000000, + NOMINAL, 571428571), }, }; static const struct freq_tbl ftbl_disp_cc_mdss_rot_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(165000000, P_DISP_CC_PLL0_OUT_MAIN, 2.5, 0, 0), + F(300000000, P_GPLL0_OUT_MAIN, 2, 0, 0), + F(412500000, P_DISP_CC_PLL0_OUT_MAIN, 1, 0, 0), + { } +}; + +static const struct freq_tbl ftbl_disp_cc_mdss_rot_clk_src_sdm845_v2[] = { F(19200000, P_BI_TCXO, 1, 0, 0), F(171428571, P_GPLL0_OUT_MAIN, 3.5, 0, 0), F(300000000, P_GPLL0_OUT_MAIN, 2, 0, 0), @@ -233,11 +471,18 @@ static struct clk_rcg2 disp_cc_mdss_rot_clk_src = { .hid_width = 5, .parent_map = disp_cc_parent_map_3, .freq_tbl = ftbl_disp_cc_mdss_rot_clk_src, + .enable_safe_config = true, .clkr.hw.init = &(struct clk_init_data){ .name = "disp_cc_mdss_rot_clk_src", .parent_names = disp_cc_parent_names_3, .num_parents = 5, - .ops = &clk_rcg2_shared_ops, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP4( + MIN, 19200000, + LOWER, 165000000, + LOW, 300000000, + NOMINAL, 412500000), }, }; @@ -251,7 +496,10 @@ static struct clk_rcg2 disp_cc_mdss_vsync_clk_src = { .name = "disp_cc_mdss_vsync_clk_src", .parent_names = disp_cc_parent_names_2, .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP1( + MIN, 19200000), }, }; @@ -281,7 +529,6 @@ static struct clk_branch disp_cc_mdss_axi_clk = { }, }; -/* Return the HW recalc rate for idle use case */ static struct clk_branch disp_cc_mdss_byte0_clk = { .halt_reg = 0x2028, .halt_check = BRANCH_HALT, @@ -294,13 +541,12 @@ static struct clk_branch disp_cc_mdss_byte0_clk = { "disp_cc_mdss_byte0_clk_src", }, .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, .ops = &clk_branch2_ops, }, }, }; -/* Return the HW recalc rate for idle use case */ static struct clk_regmap_div disp_cc_mdss_byte0_div_clk_src = { .reg = 0x20e8, .shift = 0, @@ -312,12 +558,12 @@ static struct clk_regmap_div disp_cc_mdss_byte0_div_clk_src = { "disp_cc_mdss_byte0_clk_src", }, .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, .ops = &clk_regmap_div_ops, }, }, }; -/* Return the HW recalc rate for idle use case */ static struct clk_branch disp_cc_mdss_byte0_intf_clk = { .halt_reg = 0x202c, .halt_check = BRANCH_HALT, @@ -330,13 +576,12 @@ static struct clk_branch disp_cc_mdss_byte0_intf_clk = { "disp_cc_mdss_byte0_div_clk_src", }, .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, .ops = &clk_branch2_ops, }, }, }; -/* Return the HW recalc rate for idle use case */ static struct clk_branch disp_cc_mdss_byte1_clk = { .halt_reg = 0x2030, .halt_check = BRANCH_HALT, @@ -349,13 +594,12 @@ static struct clk_branch disp_cc_mdss_byte1_clk = { "disp_cc_mdss_byte1_clk_src", }, .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, .ops = &clk_branch2_ops, }, }, }; -/* Return the HW recalc rate for idle use case */ static struct clk_regmap_div disp_cc_mdss_byte1_div_clk_src = { .reg = 0x2104, .shift = 0, @@ -367,12 +611,12 @@ static struct clk_regmap_div disp_cc_mdss_byte1_div_clk_src = { "disp_cc_mdss_byte1_clk_src", }, .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, .ops = &clk_regmap_div_ops, }, }, }; -/* Return the HW recalc rate for idle use case */ static struct clk_branch disp_cc_mdss_byte1_intf_clk = { .halt_reg = 0x2034, .halt_check = BRANCH_HALT, @@ -385,12 +629,121 @@ static struct clk_branch disp_cc_mdss_byte1_intf_clk = { "disp_cc_mdss_byte1_div_clk_src", }, .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dp_aux_clk = { + .halt_reg = 0x2054, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2054, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_dp_aux_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_dp_aux_clk_src", + }, + .num_parents = 1, .flags = CLK_SET_RATE_PARENT, .ops = &clk_branch2_ops, }, }, }; +static struct clk_branch disp_cc_mdss_dp_crypto_clk = { + .halt_reg = 0x2048, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2048, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_dp_crypto_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_dp_crypto_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dp_link_clk = { + .halt_reg = 0x2040, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2040, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_dp_link_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_dp_link_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + .ops = &clk_branch2_ops, + }, + }, +}; + +/* reset state of disp_cc_mdss_dp_link_div_clk_src divider is 0x3 (div 4) */ +static struct clk_branch disp_cc_mdss_dp_link_intf_clk = { + .halt_reg = 0x2044, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2044, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_dp_link_intf_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_dp_link_clk_src", + }, + .num_parents = 1, + .flags = CLK_GET_RATE_NOCACHE, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dp_pixel1_clk = { + .halt_reg = 0x2050, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2050, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_dp_pixel1_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_dp_pixel1_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_dp_pixel_clk = { + .halt_reg = 0x204c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x204c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_dp_pixel_clk", + .parent_names = (const char *[]){ + "disp_cc_mdss_dp_pixel_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + .ops = &clk_branch2_ops, + }, + }, +}; + static struct clk_branch disp_cc_mdss_esc0_clk = { .halt_reg = 0x2038, .halt_check = BRANCH_HALT, @@ -462,7 +815,6 @@ static struct clk_branch disp_cc_mdss_mdp_lut_clk = { }, }; -/* Return the HW recalc rate for idle use case */ static struct clk_branch disp_cc_mdss_pclk0_clk = { .halt_reg = 0x2004, .halt_check = BRANCH_HALT, @@ -475,13 +827,12 @@ static struct clk_branch disp_cc_mdss_pclk0_clk = { "disp_cc_mdss_pclk0_clk_src", }, .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, .ops = &clk_branch2_ops, }, }, }; -/* Return the HW recalc rate for idle use case */ static struct clk_branch disp_cc_mdss_pclk1_clk = { .halt_reg = 0x2008, .halt_check = BRANCH_HALT, @@ -494,7 +845,33 @@ static struct clk_branch disp_cc_mdss_pclk1_clk = { "disp_cc_mdss_pclk1_clk_src", }, .num_parents = 1, - .flags = CLK_SET_RATE_PARENT, + .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_qdss_at_clk = { + .halt_reg = 0x4010, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4010, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_qdss_at_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch disp_cc_mdss_qdss_tsctr_div8_clk = { + .halt_reg = 0x4014, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x4014, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "disp_cc_mdss_qdss_tsctr_div8_clk", .ops = &clk_branch2_ops, }, }, @@ -567,17 +944,6 @@ static struct clk_branch disp_cc_mdss_vsync_clk = { }, }; -static struct gdsc mdss_gdsc = { - .gdscr = 0x3000, - .en_few_wait_val = 0x6, - .en_rest_wait_val = 0x5, - .pd = { - .name = "mdss_gdsc", - }, - .pwrsts = PWRSTS_OFF_ON, - .flags = HW_CTRL | POLL_CFG_GDSCR, -}; - static struct clk_regmap *disp_cc_sdm845_clocks[] = { [DISP_CC_MDSS_AHB_CLK] = &disp_cc_mdss_ahb_clk.clkr, [DISP_CC_MDSS_AXI_CLK] = &disp_cc_mdss_axi_clk.clkr, @@ -591,6 +957,19 @@ static struct clk_regmap *disp_cc_sdm845_clocks[] = { [DISP_CC_MDSS_BYTE1_INTF_CLK] = &disp_cc_mdss_byte1_intf_clk.clkr, [DISP_CC_MDSS_BYTE1_DIV_CLK_SRC] = &disp_cc_mdss_byte1_div_clk_src.clkr, + [DISP_CC_MDSS_DP_AUX_CLK] = &disp_cc_mdss_dp_aux_clk.clkr, + [DISP_CC_MDSS_DP_AUX_CLK_SRC] = &disp_cc_mdss_dp_aux_clk_src.clkr, + [DISP_CC_MDSS_DP_CRYPTO_CLK] = &disp_cc_mdss_dp_crypto_clk.clkr, + [DISP_CC_MDSS_DP_CRYPTO_CLK_SRC] = + &disp_cc_mdss_dp_crypto_clk_src.clkr, + [DISP_CC_MDSS_DP_LINK_CLK] = &disp_cc_mdss_dp_link_clk.clkr, + [DISP_CC_MDSS_DP_LINK_CLK_SRC] = &disp_cc_mdss_dp_link_clk_src.clkr, + [DISP_CC_MDSS_DP_LINK_INTF_CLK] = &disp_cc_mdss_dp_link_intf_clk.clkr, + [DISP_CC_MDSS_DP_PIXEL1_CLK] = &disp_cc_mdss_dp_pixel1_clk.clkr, + [DISP_CC_MDSS_DP_PIXEL1_CLK_SRC] = + &disp_cc_mdss_dp_pixel1_clk_src.clkr, + [DISP_CC_MDSS_DP_PIXEL_CLK] = &disp_cc_mdss_dp_pixel_clk.clkr, + [DISP_CC_MDSS_DP_PIXEL_CLK_SRC] = &disp_cc_mdss_dp_pixel_clk_src.clkr, [DISP_CC_MDSS_ESC0_CLK] = &disp_cc_mdss_esc0_clk.clkr, [DISP_CC_MDSS_ESC0_CLK_SRC] = &disp_cc_mdss_esc0_clk_src.clkr, [DISP_CC_MDSS_ESC1_CLK] = &disp_cc_mdss_esc1_clk.clkr, @@ -602,6 +981,9 @@ static struct clk_regmap *disp_cc_sdm845_clocks[] = { [DISP_CC_MDSS_PCLK0_CLK_SRC] = &disp_cc_mdss_pclk0_clk_src.clkr, [DISP_CC_MDSS_PCLK1_CLK] = &disp_cc_mdss_pclk1_clk.clkr, [DISP_CC_MDSS_PCLK1_CLK_SRC] = &disp_cc_mdss_pclk1_clk_src.clkr, + [DISP_CC_MDSS_QDSS_AT_CLK] = &disp_cc_mdss_qdss_at_clk.clkr, + [DISP_CC_MDSS_QDSS_TSCTR_DIV8_CLK] = + &disp_cc_mdss_qdss_tsctr_div8_clk.clkr, [DISP_CC_MDSS_ROT_CLK] = &disp_cc_mdss_rot_clk.clkr, [DISP_CC_MDSS_ROT_CLK_SRC] = &disp_cc_mdss_rot_clk_src.clkr, [DISP_CC_MDSS_RSCC_AHB_CLK] = &disp_cc_mdss_rscc_ahb_clk.clkr, @@ -615,10 +997,6 @@ static const struct qcom_reset_map disp_cc_sdm845_resets[] = { [DISP_CC_MDSS_RSCC_BCR] = { 0x5000 }, }; -static struct gdsc *disp_cc_sdm845_gdscs[] = { - [MDSS_GDSC] = &mdss_gdsc, -}; - static const struct regmap_config disp_cc_sdm845_regmap_config = { .reg_bits = 32, .reg_stride = 4, @@ -633,34 +1011,132 @@ static const struct qcom_cc_desc disp_cc_sdm845_desc = { .num_clks = ARRAY_SIZE(disp_cc_sdm845_clocks), .resets = disp_cc_sdm845_resets, .num_resets = ARRAY_SIZE(disp_cc_sdm845_resets), - .gdscs = disp_cc_sdm845_gdscs, - .num_gdscs = ARRAY_SIZE(disp_cc_sdm845_gdscs), }; static const struct of_device_id disp_cc_sdm845_match_table[] = { - { .compatible = "qcom,sdm845-dispcc" }, + { .compatible = "qcom,dispcc-sdm845" }, + { .compatible = "qcom,dispcc-sdm845-v2" }, + { .compatible = "qcom,dispcc-sdm670" }, { } }; MODULE_DEVICE_TABLE(of, disp_cc_sdm845_match_table); +static void disp_cc_sdm845_fixup_sdm845v2(struct regmap *regmap) +{ + clk_fabia_pll_configure(&disp_cc_pll0, regmap, + &disp_cc_pll0_config_v2); + disp_cc_mdss_byte0_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = + 180000000; + disp_cc_mdss_byte0_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = + 275000000; + disp_cc_mdss_byte0_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW_L1] = + 328580000; + disp_cc_mdss_byte1_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = + 180000000; + disp_cc_mdss_byte1_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = + 275000000; + disp_cc_mdss_byte1_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW_L1] = + 328580000; + disp_cc_mdss_dp_pixel1_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = + 337500; + disp_cc_mdss_dp_pixel_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = + 337500; + disp_cc_mdss_mdp_clk_src.freq_tbl = + ftbl_disp_cc_mdss_mdp_clk_src_sdm845_v2; + disp_cc_mdss_mdp_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = + 171428571; + disp_cc_mdss_mdp_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW_L1] = + 344000000; + disp_cc_mdss_mdp_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = + 430000000; + disp_cc_mdss_pclk0_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = + 280000000; + disp_cc_mdss_pclk0_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = + 430000000; + disp_cc_mdss_pclk0_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW_L1] = + 430000000; + disp_cc_mdss_pclk1_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = + 280000000; + disp_cc_mdss_pclk1_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = + 430000000; + disp_cc_mdss_pclk1_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW_L1] = + 430000000; + disp_cc_mdss_rot_clk_src.freq_tbl = + ftbl_disp_cc_mdss_rot_clk_src_sdm845_v2; + disp_cc_mdss_rot_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = + 171428571; + disp_cc_mdss_rot_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW_L1] = + 344000000; + disp_cc_mdss_rot_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = + 430000000; +} + +static void disp_cc_sdm845_fixup_sdm670(struct regmap *regmap) +{ + disp_cc_sdm845_fixup_sdm845v2(regmap); + + disp_cc_mdss_mdp_clk_src.freq_tbl = + ftbl_disp_cc_mdss_mdp_clk_src_sdm670; + disp_cc_mdss_byte0_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW_L1] = + 358000000; + disp_cc_mdss_byte1_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW_L1] = + 358000000; +} + +static int disp_cc_sdm845_fixup(struct platform_device *pdev, + struct regmap *regmap) +{ + const char *compat = NULL; + int compatlen = 0; + + compat = of_get_property(pdev->dev.of_node, "compatible", &compatlen); + if (!compat || (compatlen <= 0)) + return -EINVAL; + + if (!strcmp(compat, "qcom,dispcc-sdm845-v2")) + disp_cc_sdm845_fixup_sdm845v2(regmap); + else if (!strcmp(compat, "qcom,dispcc-sdm670")) + disp_cc_sdm845_fixup_sdm670(regmap); + + return 0; +} + static int disp_cc_sdm845_probe(struct platform_device *pdev) { struct regmap *regmap; - struct alpha_pll_config disp_cc_pll0_config = {}; + int ret = 0; regmap = qcom_cc_map(pdev, &disp_cc_sdm845_desc); - if (IS_ERR(regmap)) + if (IS_ERR(regmap)) { + pr_err("Failed to map the Display CC registers\n"); return PTR_ERR(regmap); + } - disp_cc_pll0_config.l = 0x2c; - disp_cc_pll0_config.alpha = 0xcaaa; + vdd_cx.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_cx"); + if (IS_ERR(vdd_cx.regulator[0])) { + if (!(PTR_ERR(vdd_cx.regulator[0]) == -EPROBE_DEFER)) + dev_err(&pdev->dev, + "Unable to get vdd_cx regulator\n"); + return PTR_ERR(vdd_cx.regulator[0]); + } clk_fabia_pll_configure(&disp_cc_pll0, regmap, &disp_cc_pll0_config); - /* Enable hardware clock gating for DSI and MDP clocks */ - regmap_update_bits(regmap, 0x8000, 0x7f0, 0x7f0); + /* Enable clock gating for DSI and MDP clocks */ + regmap_update_bits(regmap, DISP_CC_MISC_CMD, 0x7f0, 0x7f0); + + ret = disp_cc_sdm845_fixup(pdev, regmap); + if (ret) + return ret; + + ret = qcom_cc_really_probe(pdev, &disp_cc_sdm845_desc, regmap); + if (ret) { + dev_err(&pdev->dev, "Failed to register Display CC clocks\n"); + return ret; + } - return qcom_cc_really_probe(pdev, &disp_cc_sdm845_desc, regmap); + dev_info(&pdev->dev, "Registered Display CC clocks\n"); + return ret; } static struct platform_driver disp_cc_sdm845_driver = { @@ -683,5 +1159,6 @@ static void __exit disp_cc_sdm845_exit(void) } module_exit(disp_cc_sdm845_exit); +MODULE_DESCRIPTION("QTI DISP_CC SDM845 Driver"); MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("QTI DISPCC SDM845 Driver"); +MODULE_ALIAS("platform:disp_cc-sdm845"); diff --git a/drivers/clk/qcom/gcc-sdm845.c b/drivers/clk/qcom/gcc-sdm845.c index 6bd96ddadbe3..01eade692e2a 100644 --- a/drivers/clk/qcom/gcc-sdm845.c +++ b/drivers/clk/qcom/gcc-sdm845.c @@ -1,8 +1,10 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. */ +#define pr_fmt(fmt) "clk: %s: " fmt, __func__ + #include #include #include @@ -10,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -21,9 +24,18 @@ #include "clk-pll.h" #include "clk-rcg.h" #include "clk-branch.h" -#include "clk-alpha-pll.h" -#include "gdsc.h" #include "reset.h" +#include "clk-alpha-pll.h" +#include "vdd-level-sdm845.h" +#include "clk-voter.h" + +#define GCC_MMSS_MISC 0x09FFC +#define GCC_GPU_MISC 0x71028 + +#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } + +static DEFINE_VDD_REGULATORS(vdd_cx, VDD_CX_NUM, 1, vdd_corner); +static DEFINE_VDD_REGULATORS(vdd_cx_ao, VDD_CX_NUM, 1, vdd_corner); enum { P_BI_TCXO, @@ -31,7 +43,9 @@ enum { P_CORE_BI_PLL_TEST_SE, P_GPLL0_OUT_EVEN, P_GPLL0_OUT_MAIN, + P_GPLL1_OUT_MAIN, P_GPLL4_OUT_MAIN, + P_GPLL6_OUT_MAIN, P_SLEEP_CLK, }; @@ -131,7 +145,7 @@ static const char * const gcc_parent_names_6[] = { "core_bi_pll_test_se", }; -static const char * const gcc_parent_names_7_ao[] = { +static const char * const gcc_parent_names_7[] = { "bi_tcxo_ao", "gpll0", "gpll0_out_even", @@ -139,14 +153,22 @@ static const char * const gcc_parent_names_7_ao[] = { }; static const char * const gcc_parent_names_8[] = { - "bi_tcxo", + "bi_tcxo_ao", "gpll0", "core_bi_pll_test_se", }; -static const char * const gcc_parent_names_8_ao[] = { - "bi_tcxo_ao", +static const struct parent_map gcc_parent_map_9[] = { + { P_BI_TCXO, 0 }, + { P_GPLL0_OUT_MAIN, 1 }, + { P_GPLL1_OUT_MAIN, 4 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const gcc_parent_names_9[] = { + "bi_tcxo", "gpll0", + "gpll1", "core_bi_pll_test_se", }; @@ -166,9 +188,64 @@ static const char * const gcc_parent_names_10[] = { "core_bi_pll_test_se", }; +static const struct parent_map gcc_parent_map_7[] = { + { P_BI_TCXO, 0 }, + { P_GPLL0_OUT_MAIN, 1 }, + { P_GPLL6_OUT_MAIN, 2 }, + { P_GPLL0_OUT_EVEN, 6 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const gcc_parent_names_11[] = { + "bi_tcxo", + "gpll0", + "gpll6", + "gpll0_out_even", + "core_bi_pll_test_se", +}; + +static struct clk_dummy measure_only_snoc_clk = { + .rrate = 1000, + .hw.init = &(struct clk_init_data){ + .name = "measure_only_snoc_clk", + .ops = &clk_dummy_ops, + }, +}; + +static struct clk_dummy measure_only_cnoc_clk = { + .rrate = 1000, + .hw.init = &(struct clk_init_data){ + .name = "measure_only_cnoc_clk", + .ops = &clk_dummy_ops, + }, +}; + +static struct clk_dummy measure_only_bimc_clk = { + .rrate = 1000, + .hw.init = &(struct clk_init_data){ + .name = "measure_only_bimc_clk", + .ops = &clk_dummy_ops, + }, +}; + +static struct clk_dummy measure_only_ipa_2x_clk = { + .rrate = 1000, + .hw.init = &(struct clk_init_data){ + .name = "measure_only_ipa_2x_clk", + .ops = &clk_dummy_ops, + }, +}; + +static struct pll_vco fabia_vco[] = { + { 249600000, 2000000000, 0 }, + { 125000000, 1000000000, 1 }, +}; + static struct clk_alpha_pll gpll0 = { .offset = 0x0, - .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], + .vco_table = fabia_vco, + .num_vco = ARRAY_SIZE(fabia_vco), + .type = FABIA_PLL, .clkr = { .enable_reg = 0x52000, .enable_mask = BIT(0), @@ -176,14 +253,21 @@ static struct clk_alpha_pll gpll0 = { .name = "gpll0", .parent_names = (const char *[]){ "bi_tcxo" }, .num_parents = 1, - .ops = &clk_alpha_pll_fixed_fabia_ops, + .ops = &clk_fabia_fixed_pll_ops, + VDD_CX_FMAX_MAP4( + MIN, 615000000, + LOW, 1066000000, + LOW_L1, 1600000000, + NOMINAL, 2000000000), }, }, }; static struct clk_alpha_pll gpll4 = { .offset = 0x76000, - .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], + .vco_table = fabia_vco, + .num_vco = ARRAY_SIZE(fabia_vco), + .type = FABIA_PLL, .clkr = { .enable_reg = 0x52000, .enable_mask = BIT(4), @@ -191,7 +275,12 @@ static struct clk_alpha_pll gpll4 = { .name = "gpll4", .parent_names = (const char *[]){ "bi_tcxo" }, .num_parents = 1, - .ops = &clk_alpha_pll_fixed_fabia_ops, + .ops = &clk_fabia_fixed_pll_ops, + VDD_CX_FMAX_MAP4( + MIN, 615000000, + LOW, 1066000000, + LOW_L1, 1600000000, + NOMINAL, 2000000000), }, }, }; @@ -210,12 +299,33 @@ static struct clk_alpha_pll_postdiv gpll0_out_even = { .post_div_table = post_div_table_fabia_even, .num_post_div = ARRAY_SIZE(post_div_table_fabia_even), .width = 4, - .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], .clkr.hw.init = &(struct clk_init_data){ .name = "gpll0_out_even", .parent_names = (const char *[]){ "gpll0" }, .num_parents = 1, - .ops = &clk_alpha_pll_postdiv_fabia_ops, + .ops = &clk_generic_pll_postdiv_ops, + }, +}; + +static struct clk_alpha_pll gpll6 = { + .offset = 0x13000, + .vco_table = fabia_vco, + .num_vco = ARRAY_SIZE(fabia_vco), + .type = FABIA_PLL, + .clkr = { + .enable_reg = 0x52000, + .enable_mask = BIT(6), + .hw.init = &(struct clk_init_data){ + .name = "gpll6", + .parent_names = (const char *[]){ "bi_tcxo" }, + .num_parents = 1, + .ops = &clk_fabia_fixed_pll_ops, + VDD_CX_FMAX_MAP4( + MIN, 615000000, + LOW, 1066000000, + LOW_L1, 1600000000, + NOMINAL, 2000000000), + }, }, }; @@ -232,9 +342,14 @@ static struct clk_rcg2 gcc_cpuss_ahb_clk_src = { .freq_tbl = ftbl_gcc_cpuss_ahb_clk_src, .clkr.hw.init = &(struct clk_init_data){ .name = "gcc_cpuss_ahb_clk_src", - .parent_names = gcc_parent_names_7_ao, + .parent_names = gcc_parent_names_7, .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3_AO( + MIN, 19200000, + LOW, 50000000, + NOMINAL, 100000000), }, }; @@ -243,6 +358,12 @@ static const struct freq_tbl ftbl_gcc_cpuss_rbcpr_clk_src[] = { { } }; +static const struct freq_tbl ftbl_gcc_cpuss_rbcpr_clk_src_sdm670[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(50000000, P_GPLL0_OUT_MAIN, 12, 0, 0), + { } +}; + static struct clk_rcg2 gcc_cpuss_rbcpr_clk_src = { .cmd_rcgr = 0x4815c, .mnd_width = 0, @@ -251,9 +372,12 @@ static struct clk_rcg2 gcc_cpuss_rbcpr_clk_src = { .freq_tbl = ftbl_gcc_cpuss_rbcpr_clk_src, .clkr.hw.init = &(struct clk_init_data){ .name = "gcc_cpuss_rbcpr_clk_src", - .parent_names = gcc_parent_names_8_ao, + .parent_names = gcc_parent_names_8, .num_parents = 3, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP1_AO( + MIN, 19200000), }, }; @@ -276,7 +400,13 @@ static struct clk_rcg2 gcc_gp1_clk_src = { .name = "gcc_gp1_clk_src", .parent_names = gcc_parent_names_1, .num_parents = 5, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP4( + MIN, 19200000, + LOWER, 50000000, + LOW, 100000000, + NOMINAL, 200000000), }, }; @@ -290,7 +420,13 @@ static struct clk_rcg2 gcc_gp2_clk_src = { .name = "gcc_gp2_clk_src", .parent_names = gcc_parent_names_1, .num_parents = 5, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP4( + MIN, 19200000, + LOWER, 50000000, + LOW, 100000000, + NOMINAL, 200000000), }, }; @@ -304,7 +440,13 @@ static struct clk_rcg2 gcc_gp3_clk_src = { .name = "gcc_gp3_clk_src", .parent_names = gcc_parent_names_1, .num_parents = 5, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP4( + MIN, 19200000, + LOWER, 50000000, + LOW, 100000000, + NOMINAL, 200000000), }, }; @@ -324,7 +466,11 @@ static struct clk_rcg2 gcc_pcie_0_aux_clk_src = { .name = "gcc_pcie_0_aux_clk_src", .parent_names = gcc_parent_names_2, .num_parents = 3, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP2( + MIN, 9600000, + LOW, 19200000), }, }; @@ -338,7 +484,11 @@ static struct clk_rcg2 gcc_pcie_1_aux_clk_src = { .name = "gcc_pcie_1_aux_clk_src", .parent_names = gcc_parent_names_2, .num_parents = 3, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP2( + MIN, 9600000, + LOW, 19200000), }, }; @@ -358,7 +508,11 @@ static struct clk_rcg2 gcc_pcie_phy_refgen_clk_src = { .name = "gcc_pcie_phy_refgen_clk_src", .parent_names = gcc_parent_names_0, .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP2( + MIN, 19200000, + LOW, 100000000), }, }; @@ -379,11 +533,31 @@ static struct clk_rcg2 gcc_pdm2_clk_src = { .name = "gcc_pdm2_clk_src", .parent_names = gcc_parent_names_0, .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 9600000, + LOWER, 19200000, + LOW, 60000000), }, }; static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s0_clk_src[] = { + F(7372800, P_GPLL0_OUT_EVEN, 1, 384, 15625), + F(14745600, P_GPLL0_OUT_EVEN, 1, 768, 15625), + F(19200000, P_BI_TCXO, 1, 0, 0), + F(29491200, P_GPLL0_OUT_EVEN, 1, 1536, 15625), + F(32000000, P_GPLL0_OUT_EVEN, 1, 8, 75), + F(38400000, P_GPLL0_OUT_EVEN, 1, 16, 125), + F(48000000, P_GPLL0_OUT_EVEN, 1, 4, 25), + F(64000000, P_GPLL0_OUT_EVEN, 1, 16, 75), + F(80000000, P_GPLL0_OUT_EVEN, 1, 4, 15), + F(96000000, P_GPLL0_OUT_EVEN, 1, 8, 25), + F(100000000, P_GPLL0_OUT_EVEN, 3, 0, 0), + { } +}; + +static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s0_clk_src_sdm845_v2[] = { F(7372800, P_GPLL0_OUT_EVEN, 1, 384, 15625), F(14745600, P_GPLL0_OUT_EVEN, 1, 768, 15625), F(19200000, P_BI_TCXO, 1, 0, 0), @@ -408,11 +582,17 @@ static struct clk_rcg2 gcc_qupv3_wrap0_s0_clk_src = { .hid_width = 5, .parent_map = gcc_parent_map_0, .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, + .enable_safe_config = true, .clkr.hw.init = &(struct clk_init_data){ .name = "gcc_qupv3_wrap0_s0_clk_src", .parent_names = gcc_parent_names_0, .num_parents = 4, - .ops = &clk_rcg2_shared_ops, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 19200000, + LOWER, 75000000, + LOW, 100000000), }, }; @@ -422,11 +602,17 @@ static struct clk_rcg2 gcc_qupv3_wrap0_s1_clk_src = { .hid_width = 5, .parent_map = gcc_parent_map_0, .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, + .enable_safe_config = true, .clkr.hw.init = &(struct clk_init_data){ .name = "gcc_qupv3_wrap0_s1_clk_src", .parent_names = gcc_parent_names_0, .num_parents = 4, - .ops = &clk_rcg2_shared_ops, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 19200000, + LOWER, 75000000, + LOW, 100000000), }, }; @@ -436,11 +622,17 @@ static struct clk_rcg2 gcc_qupv3_wrap0_s2_clk_src = { .hid_width = 5, .parent_map = gcc_parent_map_0, .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, + .enable_safe_config = true, .clkr.hw.init = &(struct clk_init_data){ .name = "gcc_qupv3_wrap0_s2_clk_src", .parent_names = gcc_parent_names_0, .num_parents = 4, - .ops = &clk_rcg2_shared_ops, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 19200000, + LOWER, 75000000, + LOW, 100000000), }, }; @@ -450,11 +642,17 @@ static struct clk_rcg2 gcc_qupv3_wrap0_s3_clk_src = { .hid_width = 5, .parent_map = gcc_parent_map_0, .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, + .enable_safe_config = true, .clkr.hw.init = &(struct clk_init_data){ .name = "gcc_qupv3_wrap0_s3_clk_src", .parent_names = gcc_parent_names_0, .num_parents = 4, - .ops = &clk_rcg2_shared_ops, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 19200000, + LOWER, 75000000, + LOW, 100000000), }, }; @@ -464,11 +662,17 @@ static struct clk_rcg2 gcc_qupv3_wrap0_s4_clk_src = { .hid_width = 5, .parent_map = gcc_parent_map_0, .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, + .enable_safe_config = true, .clkr.hw.init = &(struct clk_init_data){ .name = "gcc_qupv3_wrap0_s4_clk_src", .parent_names = gcc_parent_names_0, .num_parents = 4, - .ops = &clk_rcg2_shared_ops, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 19200000, + LOWER, 75000000, + LOW, 100000000), }, }; @@ -478,11 +682,17 @@ static struct clk_rcg2 gcc_qupv3_wrap0_s5_clk_src = { .hid_width = 5, .parent_map = gcc_parent_map_0, .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, + .enable_safe_config = true, .clkr.hw.init = &(struct clk_init_data){ .name = "gcc_qupv3_wrap0_s5_clk_src", .parent_names = gcc_parent_names_0, .num_parents = 4, - .ops = &clk_rcg2_shared_ops, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 19200000, + LOWER, 75000000, + LOW, 100000000), }, }; @@ -492,11 +702,17 @@ static struct clk_rcg2 gcc_qupv3_wrap0_s6_clk_src = { .hid_width = 5, .parent_map = gcc_parent_map_0, .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, + .enable_safe_config = true, .clkr.hw.init = &(struct clk_init_data){ .name = "gcc_qupv3_wrap0_s6_clk_src", .parent_names = gcc_parent_names_0, .num_parents = 4, - .ops = &clk_rcg2_shared_ops, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 19200000, + LOWER, 75000000, + LOW, 100000000), }, }; @@ -506,11 +722,17 @@ static struct clk_rcg2 gcc_qupv3_wrap0_s7_clk_src = { .hid_width = 5, .parent_map = gcc_parent_map_0, .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, + .enable_safe_config = true, .clkr.hw.init = &(struct clk_init_data){ .name = "gcc_qupv3_wrap0_s7_clk_src", .parent_names = gcc_parent_names_0, .num_parents = 4, - .ops = &clk_rcg2_shared_ops, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 19200000, + LOWER, 75000000, + LOW, 100000000), }, }; @@ -520,11 +742,17 @@ static struct clk_rcg2 gcc_qupv3_wrap1_s0_clk_src = { .hid_width = 5, .parent_map = gcc_parent_map_0, .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, + .enable_safe_config = true, .clkr.hw.init = &(struct clk_init_data){ .name = "gcc_qupv3_wrap1_s0_clk_src", .parent_names = gcc_parent_names_0, .num_parents = 4, - .ops = &clk_rcg2_shared_ops, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 19200000, + LOWER, 75000000, + LOW, 100000000), }, }; @@ -534,11 +762,17 @@ static struct clk_rcg2 gcc_qupv3_wrap1_s1_clk_src = { .hid_width = 5, .parent_map = gcc_parent_map_0, .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, + .enable_safe_config = true, .clkr.hw.init = &(struct clk_init_data){ .name = "gcc_qupv3_wrap1_s1_clk_src", .parent_names = gcc_parent_names_0, .num_parents = 4, - .ops = &clk_rcg2_shared_ops, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 19200000, + LOWER, 75000000, + LOW, 100000000), }, }; @@ -548,11 +782,17 @@ static struct clk_rcg2 gcc_qupv3_wrap1_s2_clk_src = { .hid_width = 5, .parent_map = gcc_parent_map_0, .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, + .enable_safe_config = true, .clkr.hw.init = &(struct clk_init_data){ .name = "gcc_qupv3_wrap1_s2_clk_src", .parent_names = gcc_parent_names_0, .num_parents = 4, - .ops = &clk_rcg2_shared_ops, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 19200000, + LOWER, 75000000, + LOW, 100000000), }, }; @@ -562,11 +802,17 @@ static struct clk_rcg2 gcc_qupv3_wrap1_s3_clk_src = { .hid_width = 5, .parent_map = gcc_parent_map_0, .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, + .enable_safe_config = true, .clkr.hw.init = &(struct clk_init_data){ .name = "gcc_qupv3_wrap1_s3_clk_src", .parent_names = gcc_parent_names_0, .num_parents = 4, - .ops = &clk_rcg2_shared_ops, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 19200000, + LOWER, 75000000, + LOW, 100000000), }, }; @@ -576,11 +822,17 @@ static struct clk_rcg2 gcc_qupv3_wrap1_s4_clk_src = { .hid_width = 5, .parent_map = gcc_parent_map_0, .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, + .enable_safe_config = true, .clkr.hw.init = &(struct clk_init_data){ .name = "gcc_qupv3_wrap1_s4_clk_src", .parent_names = gcc_parent_names_0, .num_parents = 4, - .ops = &clk_rcg2_shared_ops, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 19200000, + LOWER, 75000000, + LOW, 100000000), }, }; @@ -590,11 +842,17 @@ static struct clk_rcg2 gcc_qupv3_wrap1_s5_clk_src = { .hid_width = 5, .parent_map = gcc_parent_map_0, .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, + .enable_safe_config = true, .clkr.hw.init = &(struct clk_init_data){ .name = "gcc_qupv3_wrap1_s5_clk_src", .parent_names = gcc_parent_names_0, .num_parents = 4, - .ops = &clk_rcg2_shared_ops, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 19200000, + LOWER, 75000000, + LOW, 100000000), }, }; @@ -604,11 +862,17 @@ static struct clk_rcg2 gcc_qupv3_wrap1_s6_clk_src = { .hid_width = 5, .parent_map = gcc_parent_map_0, .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, + .enable_safe_config = true, .clkr.hw.init = &(struct clk_init_data){ .name = "gcc_qupv3_wrap1_s6_clk_src", .parent_names = gcc_parent_names_0, .num_parents = 4, - .ops = &clk_rcg2_shared_ops, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 19200000, + LOWER, 75000000, + LOW, 100000000), }, }; @@ -618,11 +882,78 @@ static struct clk_rcg2 gcc_qupv3_wrap1_s7_clk_src = { .hid_width = 5, .parent_map = gcc_parent_map_0, .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, + .enable_safe_config = true, .clkr.hw.init = &(struct clk_init_data){ .name = "gcc_qupv3_wrap1_s7_clk_src", .parent_names = gcc_parent_names_0, .num_parents = 4, - .ops = &clk_rcg2_shared_ops, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 19200000, + LOWER, 75000000, + LOW, 100000000), + }, +}; + +static const struct freq_tbl ftbl_gcc_sdcc1_ice_core_clk_src[] = { + F(75000000, P_GPLL0_OUT_EVEN, 4, 0, 0), + F(150000000, P_GPLL0_OUT_MAIN, 4, 0, 0), + F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0), + F(300000000, P_GPLL0_OUT_MAIN, 2, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_sdcc1_ice_core_clk_src = { + .cmd_rcgr = 0x26010, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_0, + .freq_tbl = ftbl_gcc_sdcc1_ice_core_clk_src, + .enable_safe_config = true, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc1_ice_core_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 75000000, + LOW, 150000000, + NOMINAL, 300000000), + }, +}; + +static const struct freq_tbl ftbl_gcc_sdcc1_apps_clk_src[] = { + F(144000, P_BI_TCXO, 16, 3, 25), + F(400000, P_BI_TCXO, 12, 1, 4), + F(20000000, P_GPLL0_OUT_EVEN, 5, 1, 3), + F(25000000, P_GPLL0_OUT_EVEN, 6, 1, 2), + F(50000000, P_GPLL0_OUT_EVEN, 6, 0, 0), + F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0), + F(192000000, P_GPLL6_OUT_MAIN, 2, 0, 0), + F(384000000, P_GPLL6_OUT_MAIN, 1, 0, 0), + { } +}; + +static struct clk_rcg2 gcc_sdcc1_apps_clk_src = { + .cmd_rcgr = 0x26028, + .mnd_width = 8, + .hid_width = 5, + .parent_map = gcc_parent_map_7, + .freq_tbl = ftbl_gcc_sdcc1_apps_clk_src, + .enable_safe_config = true, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc1_apps_clk_src", + .parent_names = gcc_parent_names_11, + .num_parents = 5, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP4( + MIN, 19200000, + LOWER, 50000000, + LOW, 100000000, + NOMINAL, 384000000), }, }; @@ -643,11 +974,18 @@ static struct clk_rcg2 gcc_sdcc2_apps_clk_src = { .hid_width = 5, .parent_map = gcc_parent_map_10, .freq_tbl = ftbl_gcc_sdcc2_apps_clk_src, + .enable_safe_config = true, .clkr.hw.init = &(struct clk_init_data){ .name = "gcc_sdcc2_apps_clk_src", .parent_names = gcc_parent_names_10, .num_parents = 5, - .ops = &clk_rcg2_floor_ops, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP4( + MIN, 9600000, + LOWER, 19200000, + LOW, 100000000, + LOW_L1, 201500000), }, }; @@ -661,17 +999,35 @@ static const struct freq_tbl ftbl_gcc_sdcc4_apps_clk_src[] = { { } }; +static const struct freq_tbl ftbl_gcc_sdcc4_apps_clk_src_sdm670[] = { + F(400000, P_BI_TCXO, 12, 1, 4), + F(9600000, P_BI_TCXO, 2, 0, 0), + F(19200000, P_BI_TCXO, 1, 0, 0), + F(25000000, P_GPLL0_OUT_EVEN, 12, 0, 0), + F(33333333, P_GPLL0_OUT_EVEN, 9, 0, 0), + F(50000000, P_GPLL0_OUT_MAIN, 12, 0, 0), + F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0), + { } +}; + static struct clk_rcg2 gcc_sdcc4_apps_clk_src = { .cmd_rcgr = 0x1600c, .mnd_width = 8, .hid_width = 5, .parent_map = gcc_parent_map_0, .freq_tbl = ftbl_gcc_sdcc4_apps_clk_src, + .enable_safe_config = true, .clkr.hw.init = &(struct clk_init_data){ .name = "gcc_sdcc4_apps_clk_src", .parent_names = gcc_parent_names_0, .num_parents = 4, - .ops = &clk_rcg2_floor_ops, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP4( + MIN, 9600000, + LOWER, 19200000, + LOW, 50000000, + NOMINAL, 100000000), }, }; @@ -690,11 +1046,22 @@ static struct clk_rcg2 gcc_tsif_ref_clk_src = { .name = "gcc_tsif_ref_clk_src", .parent_names = gcc_parent_names_6, .num_parents = 5, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP1( + MIN, 105495), }, }; static const struct freq_tbl ftbl_gcc_ufs_card_axi_clk_src[] = { + F(25000000, P_GPLL0_OUT_EVEN, 12, 0, 0), + F(50000000, P_GPLL0_OUT_EVEN, 6, 0, 0), + F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0), + F(200000000, P_GPLL0_OUT_MAIN, 3, 0, 0), + { } +}; + +static const struct freq_tbl ftbl_gcc_ufs_card_axi_clk_src_sdm845_v2[] = { F(25000000, P_GPLL0_OUT_EVEN, 12, 0, 0), F(50000000, P_GPLL0_OUT_EVEN, 6, 0, 0), F(100000000, P_GPLL0_OUT_MAIN, 6, 0, 0), @@ -709,11 +1076,17 @@ static struct clk_rcg2 gcc_ufs_card_axi_clk_src = { .hid_width = 5, .parent_map = gcc_parent_map_0, .freq_tbl = ftbl_gcc_ufs_card_axi_clk_src, + .flags = FORCE_ENABLE_RCG, .clkr.hw.init = &(struct clk_init_data){ .name = "gcc_ufs_card_axi_clk_src", .parent_names = gcc_parent_names_0, .num_parents = 4, - .ops = &clk_rcg2_shared_ops, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 50000000, + LOW, 100000000, + NOMINAL, 200000000), }, }; @@ -731,11 +1104,17 @@ static struct clk_rcg2 gcc_ufs_card_ice_core_clk_src = { .hid_width = 5, .parent_map = gcc_parent_map_0, .freq_tbl = ftbl_gcc_ufs_card_ice_core_clk_src, + .flags = FORCE_ENABLE_RCG, .clkr.hw.init = &(struct clk_init_data){ .name = "gcc_ufs_card_ice_core_clk_src", .parent_names = gcc_parent_names_0, .num_parents = 4, - .ops = &clk_rcg2_shared_ops, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 75000000, + LOW, 150000000, + NOMINAL, 300000000), }, }; @@ -745,11 +1124,15 @@ static struct clk_rcg2 gcc_ufs_card_phy_aux_clk_src = { .hid_width = 5, .parent_map = gcc_parent_map_4, .freq_tbl = ftbl_gcc_cpuss_rbcpr_clk_src, + .flags = FORCE_ENABLE_RCG, .clkr.hw.init = &(struct clk_init_data){ .name = "gcc_ufs_card_phy_aux_clk_src", .parent_names = gcc_parent_names_4, .num_parents = 2, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP1( + MIN, 19200000), }, }; @@ -766,11 +1149,17 @@ static struct clk_rcg2 gcc_ufs_card_unipro_core_clk_src = { .hid_width = 5, .parent_map = gcc_parent_map_0, .freq_tbl = ftbl_gcc_ufs_card_unipro_core_clk_src, + .flags = FORCE_ENABLE_RCG, .clkr.hw.init = &(struct clk_init_data){ .name = "gcc_ufs_card_unipro_core_clk_src", .parent_names = gcc_parent_names_0, .num_parents = 4, - .ops = &clk_rcg2_shared_ops, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 37500000, + LOW, 75000000, + NOMINAL, 150000000), }, }; @@ -789,11 +1178,18 @@ static struct clk_rcg2 gcc_ufs_phy_axi_clk_src = { .hid_width = 5, .parent_map = gcc_parent_map_0, .freq_tbl = ftbl_gcc_ufs_phy_axi_clk_src, + .flags = FORCE_ENABLE_RCG, .clkr.hw.init = &(struct clk_init_data){ .name = "gcc_ufs_phy_axi_clk_src", .parent_names = gcc_parent_names_0, .num_parents = 4, - .ops = &clk_rcg2_shared_ops, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP4( + MIN, 50000000, + LOW, 100000000, + NOMINAL, 200000000, + HIGH, 240000000), }, }; @@ -803,11 +1199,17 @@ static struct clk_rcg2 gcc_ufs_phy_ice_core_clk_src = { .hid_width = 5, .parent_map = gcc_parent_map_0, .freq_tbl = ftbl_gcc_ufs_card_ice_core_clk_src, + .flags = FORCE_ENABLE_RCG, .clkr.hw.init = &(struct clk_init_data){ .name = "gcc_ufs_phy_ice_core_clk_src", .parent_names = gcc_parent_names_0, .num_parents = 4, - .ops = &clk_rcg2_shared_ops, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 75000000, + LOW, 150000000, + NOMINAL, 300000000), }, }; @@ -817,11 +1219,15 @@ static struct clk_rcg2 gcc_ufs_phy_phy_aux_clk_src = { .hid_width = 5, .parent_map = gcc_parent_map_4, .freq_tbl = ftbl_gcc_pcie_0_aux_clk_src, + .flags = FORCE_ENABLE_RCG, .clkr.hw.init = &(struct clk_init_data){ .name = "gcc_ufs_phy_phy_aux_clk_src", .parent_names = gcc_parent_names_4, .num_parents = 2, - .ops = &clk_rcg2_shared_ops, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP1( + MIN, 19200000), }, }; @@ -831,11 +1237,17 @@ static struct clk_rcg2 gcc_ufs_phy_unipro_core_clk_src = { .hid_width = 5, .parent_map = gcc_parent_map_0, .freq_tbl = ftbl_gcc_ufs_card_unipro_core_clk_src, + .flags = FORCE_ENABLE_RCG, .clkr.hw.init = &(struct clk_init_data){ .name = "gcc_ufs_phy_unipro_core_clk_src", .parent_names = gcc_parent_names_0, .num_parents = 4, - .ops = &clk_rcg2_shared_ops, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 37500000, + LOW, 75000000, + NOMINAL, 150000000), }, }; @@ -854,11 +1266,19 @@ static struct clk_rcg2 gcc_usb30_prim_master_clk_src = { .hid_width = 5, .parent_map = gcc_parent_map_0, .freq_tbl = ftbl_gcc_usb30_prim_master_clk_src, + .enable_safe_config = true, .clkr.hw.init = &(struct clk_init_data){ .name = "gcc_usb30_prim_master_clk_src", .parent_names = gcc_parent_names_0, .num_parents = 4, - .ops = &clk_rcg2_shared_ops, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP5( + MIN, 33333333, + LOWER, 66666667, + LOW, 133333333, + NOMINAL, 200000000, + HIGH, 240000000), }, }; @@ -876,11 +1296,17 @@ static struct clk_rcg2 gcc_usb30_prim_mock_utmi_clk_src = { .hid_width = 5, .parent_map = gcc_parent_map_0, .freq_tbl = ftbl_gcc_usb30_prim_mock_utmi_clk_src, + .enable_safe_config = true, .clkr.hw.init = &(struct clk_init_data){ .name = "gcc_usb30_prim_mock_utmi_clk_src", .parent_names = gcc_parent_names_0, .num_parents = 4, - .ops = &clk_rcg2_shared_ops, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 19200000, + LOWER, 40000000, + LOW, 60000000), }, }; @@ -894,7 +1320,14 @@ static struct clk_rcg2 gcc_usb30_sec_master_clk_src = { .name = "gcc_usb30_sec_master_clk_src", .parent_names = gcc_parent_names_0, .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP5( + MIN, 33333333, + LOWER, 66666667, + LOW, 133333333, + NOMINAL, 200000000, + HIGH, 240000000), }, }; @@ -908,7 +1341,12 @@ static struct clk_rcg2 gcc_usb30_sec_mock_utmi_clk_src = { .name = "gcc_usb30_sec_mock_utmi_clk_src", .parent_names = gcc_parent_names_0, .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 19200000, + LOWER, 40000000, + LOW, 60000000), }, }; @@ -922,7 +1360,10 @@ static struct clk_rcg2 gcc_usb3_prim_phy_aux_clk_src = { .name = "gcc_usb3_prim_phy_aux_clk_src", .parent_names = gcc_parent_names_2, .num_parents = 3, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP1( + MIN, 19200000), }, }; @@ -932,11 +1373,15 @@ static struct clk_rcg2 gcc_usb3_sec_phy_aux_clk_src = { .hid_width = 5, .parent_map = gcc_parent_map_2, .freq_tbl = ftbl_gcc_cpuss_rbcpr_clk_src, + .enable_safe_config = true, .clkr.hw.init = &(struct clk_init_data){ .name = "gcc_usb3_sec_phy_aux_clk_src", .parent_names = gcc_parent_names_2, .num_parents = 3, - .ops = &clk_rcg2_shared_ops, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP1( + MIN, 19200000), }, }; @@ -950,7 +1395,10 @@ static struct clk_rcg2 gcc_vs_ctrl_clk_src = { .name = "gcc_vs_ctrl_clk_src", .parent_names = gcc_parent_names_3, .num_parents = 3, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP1( + MIN, 19200000), }, }; @@ -965,13 +1413,18 @@ static struct clk_rcg2 gcc_vsensor_clk_src = { .cmd_rcgr = 0x7a018, .mnd_width = 0, .hid_width = 5, - .parent_map = gcc_parent_map_3, + .parent_map = gcc_parent_map_9, .freq_tbl = ftbl_gcc_vsensor_clk_src, .clkr.hw.init = &(struct clk_init_data){ .name = "gcc_vsensor_clk_src", - .parent_names = gcc_parent_names_8, - .num_parents = 3, + .parent_names = gcc_parent_names_9, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 19200000, + LOW, 300000000, + LOW_L1, 600000000), }, }; @@ -1008,6 +1461,23 @@ static struct clk_branch gcc_aggre_ufs_card_axi_clk = { }, }; +static struct clk_branch gcc_aggre_ufs_card_axi_hw_ctl_clk = { + .halt_reg = 0x82028, + .clkr = { + .enable_reg = 0x82028, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data){ + .name = "gcc_aggre_ufs_card_axi_hw_ctl_clk", + .parent_names = (const char *[]){ + "gcc_aggre_ufs_card_axi_clk", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_hw_ctl_ops, + }, + }, +}; + static struct clk_branch gcc_aggre_ufs_phy_axi_clk = { .halt_reg = 0x82024, .halt_check = BRANCH_HALT, @@ -1028,6 +1498,28 @@ static struct clk_branch gcc_aggre_ufs_phy_axi_clk = { }, }; +static DEFINE_CLK_VOTER(ufs_phy_axi_emmc_vote_clk, + gcc_aggre_ufs_phy_axi_clk, 0); +static DEFINE_CLK_VOTER(ufs_phy_axi_ufs_vote_clk, + gcc_aggre_ufs_phy_axi_clk, 0); + +static struct clk_branch gcc_aggre_ufs_phy_axi_hw_ctl_clk = { + .halt_reg = 0x82024, + .clkr = { + .enable_reg = 0x82024, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data){ + .name = "gcc_aggre_ufs_phy_axi_hw_ctl_clk", + .parent_names = (const char *[]){ + "gcc_aggre_ufs_phy_axi_clk", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_hw_ctl_ops, + }, + }, +}; + static struct clk_branch gcc_aggre_usb3_prim_axi_clk = { .halt_reg = 0x8201c, .halt_check = BRANCH_HALT, @@ -1235,6 +1727,36 @@ static struct clk_branch gcc_cpuss_ahb_clk = { }, }; +static struct clk_branch gcc_cpuss_dvm_bus_clk = { + .halt_reg = 0x48190, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x48190, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_cpuss_dvm_bus_clk", + .flags = CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_cpuss_gnoc_clk = { + .halt_reg = 0x48004, + .halt_check = BRANCH_HALT_VOTED, + .hwcg_reg = 0x48004, + .hwcg_bit = 1, + .clkr = { + .enable_reg = 0x52004, + .enable_mask = BIT(22), + .hw.init = &(struct clk_init_data){ + .name = "gcc_cpuss_gnoc_clk", + .flags = CLK_IS_CRITICAL, + .ops = &clk_branch2_ops, + }, + }, +}; + static struct clk_branch gcc_cpuss_rbcpr_clk = { .halt_reg = 0x48008, .halt_check = BRANCH_HALT, @@ -1295,8 +1817,8 @@ static struct clk_branch gcc_disp_axi_clk = { }, }; -static struct clk_branch gcc_disp_gpll0_clk_src = { - .halt_check = BRANCH_HALT_DELAY, +static struct clk_gate2 gcc_disp_gpll0_clk_src = { + .udelay = 500, .clkr = { .enable_reg = 0x52004, .enable_mask = BIT(18), @@ -1306,13 +1828,14 @@ static struct clk_branch gcc_disp_gpll0_clk_src = { "gpll0", }, .num_parents = 1, - .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_gate2_ops, }, }, }; -static struct clk_branch gcc_disp_gpll0_div_clk_src = { - .halt_check = BRANCH_HALT_DELAY, +static struct clk_gate2 gcc_disp_gpll0_div_clk_src = { + .udelay = 500, .clkr = { .enable_reg = 0x52004, .enable_mask = BIT(19), @@ -1322,7 +1845,8 @@ static struct clk_branch gcc_disp_gpll0_div_clk_src = { "gpll0_out_even", }, .num_parents = 1, - .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_gate2_ops, }, }, }; @@ -1411,8 +1935,8 @@ static struct clk_branch gcc_gpu_cfg_ahb_clk = { }, }; -static struct clk_branch gcc_gpu_gpll0_clk_src = { - .halt_check = BRANCH_HALT_DELAY, +static struct clk_gate2 gcc_gpu_gpll0_clk_src = { + .udelay = 500, .clkr = { .enable_reg = 0x52004, .enable_mask = BIT(15), @@ -1422,13 +1946,14 @@ static struct clk_branch gcc_gpu_gpll0_clk_src = { "gpll0", }, .num_parents = 1, - .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_gate2_ops, }, }, }; -static struct clk_branch gcc_gpu_gpll0_div_clk_src = { - .halt_check = BRANCH_HALT_DELAY, +static struct clk_gate2 gcc_gpu_gpll0_div_clk_src = { + .udelay = 500, .clkr = { .enable_reg = 0x52004, .enable_mask = BIT(16), @@ -1438,7 +1963,8 @@ static struct clk_branch gcc_gpu_gpll0_div_clk_src = { "gpll0_out_even", }, .num_parents = 1, - .ops = &clk_branch2_ops, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_gate2_ops, }, }, }; @@ -1528,14 +2054,14 @@ static struct clk_branch gcc_mss_cfg_ahb_clk = { }, }; -static struct clk_branch gcc_mss_gpll0_div_clk_src = { - .halt_check = BRANCH_HALT_DELAY, +static struct clk_gate2 gcc_mss_gpll0_div_clk_src = { + .udelay = 500, .clkr = { .enable_reg = 0x52004, .enable_mask = BIT(17), .hw.init = &(struct clk_init_data){ .name = "gcc_mss_gpll0_div_clk_src", - .ops = &clk_branch2_ops, + .ops = &clk_gate2_ops, }, }, }; @@ -1659,7 +2185,8 @@ static struct clk_branch gcc_pcie_0_mstr_axi_clk = { }; static struct clk_branch gcc_pcie_0_pipe_clk = { - .halt_check = BRANCH_HALT_SKIP, + .halt_reg = 0x6b020, + .halt_check = BRANCH_VOTED, .clkr = { .enable_reg = 0x5200c, .enable_mask = BIT(4), @@ -1758,7 +2285,8 @@ static struct clk_branch gcc_pcie_1_mstr_axi_clk = { }; static struct clk_branch gcc_pcie_1_pipe_clk = { - .halt_check = BRANCH_HALT_SKIP, + .halt_reg = 0x8d020, + .halt_check = BRANCH_VOTED, .clkr = { .enable_reg = 0x52004, .enable_mask = BIT(30), @@ -2283,6 +2811,55 @@ static struct clk_branch gcc_qupv3_wrap_1_s_ahb_clk = { }, }; +static struct clk_branch gcc_sdcc1_ice_core_clk = { + .halt_reg = 0x2600c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x2600c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc1_ice_core_clk", + .parent_names = (const char *[]){ + "gcc_sdcc1_ice_core_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc1_ahb_clk = { + .halt_reg = 0x26008, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x26008, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc1_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gcc_sdcc1_apps_clk = { + .halt_reg = 0x26004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x26004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gcc_sdcc1_apps_clk", + .parent_names = (const char *[]){ + "gcc_sdcc1_apps_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + static struct clk_branch gcc_sdcc2_ahb_clk = { .halt_reg = 0x14008, .halt_check = BRANCH_HALT, @@ -2442,6 +3019,23 @@ static struct clk_branch gcc_ufs_card_axi_clk = { }, }; +static struct clk_branch gcc_ufs_card_axi_hw_ctl_clk = { + .halt_reg = 0x7500c, + .clkr = { + .enable_reg = 0x7500c, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_card_axi_hw_ctl_clk", + .parent_names = (const char *[]){ + "gcc_ufs_card_axi_clk", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_hw_ctl_ops, + }, + }, +}; + static struct clk_branch gcc_ufs_card_clkref_clk = { .halt_reg = 0x8c004, .halt_check = BRANCH_HALT, @@ -2475,6 +3069,23 @@ static struct clk_branch gcc_ufs_card_ice_core_clk = { }, }; +static struct clk_branch gcc_ufs_card_ice_core_hw_ctl_clk = { + .halt_reg = 0x75058, + .clkr = { + .enable_reg = 0x75058, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_card_ice_core_hw_ctl_clk", + .parent_names = (const char *[]){ + "gcc_ufs_card_ice_core_clk", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_hw_ctl_ops, + }, + }, +}; + static struct clk_branch gcc_ufs_card_phy_aux_clk = { .halt_reg = 0x7508c, .halt_check = BRANCH_HALT, @@ -2495,38 +3106,55 @@ static struct clk_branch gcc_ufs_card_phy_aux_clk = { }, }; -static struct clk_branch gcc_ufs_card_rx_symbol_0_clk = { - .halt_check = BRANCH_HALT_SKIP, +static struct clk_branch gcc_ufs_card_phy_aux_hw_ctl_clk = { + .halt_reg = 0x7508c, + .clkr = { + .enable_reg = 0x7508c, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_card_phy_aux_hw_ctl_clk", + .parent_names = (const char *[]){ + "gcc_ufs_card_phy_aux_clk", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_hw_ctl_ops, + }, + }, +}; + +static struct clk_gate2 gcc_ufs_card_rx_symbol_0_clk = { + .udelay = 500, .clkr = { .enable_reg = 0x75018, .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_ufs_card_rx_symbol_0_clk", - .ops = &clk_branch2_ops, + .ops = &clk_gate2_ops, }, }, }; -static struct clk_branch gcc_ufs_card_rx_symbol_1_clk = { - .halt_check = BRANCH_HALT_SKIP, +static struct clk_gate2 gcc_ufs_card_rx_symbol_1_clk = { + .udelay = 500, .clkr = { .enable_reg = 0x750a8, .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_ufs_card_rx_symbol_1_clk", - .ops = &clk_branch2_ops, + .ops = &clk_gate2_ops, }, }, }; -static struct clk_branch gcc_ufs_card_tx_symbol_0_clk = { - .halt_check = BRANCH_HALT_SKIP, +static struct clk_gate2 gcc_ufs_card_tx_symbol_0_clk = { + .udelay = 500, .clkr = { .enable_reg = 0x75014, .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_ufs_card_tx_symbol_0_clk", - .ops = &clk_branch2_ops, + .ops = &clk_gate2_ops, }, }, }; @@ -2551,6 +3179,23 @@ static struct clk_branch gcc_ufs_card_unipro_core_clk = { }, }; +static struct clk_branch gcc_ufs_card_unipro_core_hw_ctl_clk = { + .halt_reg = 0x75054, + .clkr = { + .enable_reg = 0x75054, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_card_unipro_core_hw_ctl_clk", + .parent_names = (const char *[]){ + "gcc_ufs_card_unipro_core_clk", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_hw_ctl_ops, + }, + }, +}; + static struct clk_branch gcc_ufs_mem_clkref_clk = { .halt_reg = 0x8c000, .halt_check = BRANCH_HALT, @@ -2599,6 +3244,23 @@ static struct clk_branch gcc_ufs_phy_axi_clk = { }, }; +static struct clk_branch gcc_ufs_phy_axi_hw_ctl_clk = { + .halt_reg = 0x7700c, + .clkr = { + .enable_reg = 0x7700c, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_phy_axi_hw_ctl_clk", + .parent_names = (const char *[]){ + "gcc_ufs_phy_axi_clk", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_hw_ctl_ops, + }, + }, +}; + static struct clk_branch gcc_ufs_phy_ice_core_clk = { .halt_reg = 0x77058, .halt_check = BRANCH_HALT, @@ -2619,6 +3281,23 @@ static struct clk_branch gcc_ufs_phy_ice_core_clk = { }, }; +static struct clk_branch gcc_ufs_phy_ice_core_hw_ctl_clk = { + .halt_reg = 0x77058, + .clkr = { + .enable_reg = 0x77058, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_phy_ice_core_hw_ctl_clk", + .parent_names = (const char *[]){ + "gcc_ufs_phy_ice_core_clk", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_hw_ctl_ops, + }, + }, +}; + static struct clk_branch gcc_ufs_phy_phy_aux_clk = { .halt_reg = 0x7708c, .halt_check = BRANCH_HALT, @@ -2639,38 +3318,55 @@ static struct clk_branch gcc_ufs_phy_phy_aux_clk = { }, }; -static struct clk_branch gcc_ufs_phy_rx_symbol_0_clk = { - .halt_check = BRANCH_HALT_SKIP, +static struct clk_branch gcc_ufs_phy_phy_aux_hw_ctl_clk = { + .halt_reg = 0x7708c, + .clkr = { + .enable_reg = 0x7708c, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_phy_phy_aux_hw_ctl_clk", + .parent_names = (const char *[]){ + "gcc_ufs_phy_phy_aux_clk", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_hw_ctl_ops, + }, + }, +}; + +static struct clk_gate2 gcc_ufs_phy_rx_symbol_0_clk = { + .udelay = 500, .clkr = { .enable_reg = 0x77018, .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_ufs_phy_rx_symbol_0_clk", - .ops = &clk_branch2_ops, + .ops = &clk_gate2_ops, }, }, }; -static struct clk_branch gcc_ufs_phy_rx_symbol_1_clk = { - .halt_check = BRANCH_HALT_SKIP, +static struct clk_gate2 gcc_ufs_phy_rx_symbol_1_clk = { + .udelay = 500, .clkr = { .enable_reg = 0x770a8, .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_ufs_phy_rx_symbol_1_clk", - .ops = &clk_branch2_ops, + .ops = &clk_gate2_ops, }, }, }; -static struct clk_branch gcc_ufs_phy_tx_symbol_0_clk = { - .halt_check = BRANCH_HALT_SKIP, +static struct clk_gate2 gcc_ufs_phy_tx_symbol_0_clk = { + .udelay = 500, .clkr = { .enable_reg = 0x77014, .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_ufs_phy_tx_symbol_0_clk", - .ops = &clk_branch2_ops, + .ops = &clk_gate2_ops, }, }, }; @@ -2695,6 +3391,23 @@ static struct clk_branch gcc_ufs_phy_unipro_core_clk = { }, }; +static struct clk_branch gcc_ufs_phy_unipro_core_hw_ctl_clk = { + .halt_reg = 0x77054, + .clkr = { + .enable_reg = 0x77054, + .enable_mask = BIT(1), + .hw.init = &(struct clk_init_data){ + .name = "gcc_ufs_phy_unipro_core_hw_ctl_clk", + .parent_names = (const char *[]){ + "gcc_ufs_phy_unipro_core_clk", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_hw_ctl_ops, + }, + }, +}; + static struct clk_branch gcc_usb30_prim_master_clk = { .halt_reg = 0xf00c, .halt_check = BRANCH_HALT, @@ -2842,14 +3555,14 @@ static struct clk_branch gcc_usb3_prim_phy_com_aux_clk = { }, }; -static struct clk_branch gcc_usb3_prim_phy_pipe_clk = { - .halt_check = BRANCH_HALT_SKIP, +static struct clk_gate2 gcc_usb3_prim_phy_pipe_clk = { + .udelay = 500, .clkr = { .enable_reg = 0xf054, .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_usb3_prim_phy_pipe_clk", - .ops = &clk_branch2_ops, + .ops = &clk_gate2_ops, }, }, }; @@ -2903,14 +3616,14 @@ static struct clk_branch gcc_usb3_sec_phy_com_aux_clk = { }, }; -static struct clk_branch gcc_usb3_sec_phy_pipe_clk = { - .halt_check = BRANCH_HALT_SKIP, +static struct clk_gate2 gcc_usb3_sec_phy_pipe_clk = { + .udelay = 500, .clkr = { .enable_reg = 0x10054, .enable_mask = BIT(0), .hw.init = &(struct clk_init_data){ .name = "gcc_usb3_sec_phy_pipe_clk", - .ops = &clk_branch2_ops, + .ops = &clk_gate2_ops, }, }, }; @@ -3060,157 +3773,23 @@ static struct clk_branch gcc_vs_ctrl_clk = { }, }; -static struct clk_branch gcc_cpuss_dvm_bus_clk = { - .halt_reg = 0x48190, - .halt_check = BRANCH_HALT, - .clkr = { - .enable_reg = 0x48190, - .enable_mask = BIT(0), - .hw.init = &(struct clk_init_data){ - .name = "gcc_cpuss_dvm_bus_clk", - .flags = CLK_IS_CRITICAL, - .ops = &clk_branch2_ops, - }, - }, -}; - -static struct clk_branch gcc_cpuss_gnoc_clk = { - .halt_reg = 0x48004, - .halt_check = BRANCH_HALT_VOTED, - .hwcg_reg = 0x48004, - .hwcg_bit = 1, - .clkr = { - .enable_reg = 0x52004, - .enable_mask = BIT(22), - .hw.init = &(struct clk_init_data){ - .name = "gcc_cpuss_gnoc_clk", - .flags = CLK_IS_CRITICAL, - .ops = &clk_branch2_ops, - }, - }, -}; - -static struct gdsc pcie_0_gdsc = { - .gdscr = 0x6b004, - .pd = { - .name = "pcie_0_gdsc", - }, - .pwrsts = PWRSTS_OFF_ON, - .flags = POLL_CFG_GDSCR, -}; - -static struct gdsc pcie_1_gdsc = { - .gdscr = 0x8d004, - .pd = { - .name = "pcie_1_gdsc", - }, - .pwrsts = PWRSTS_OFF_ON, - .flags = POLL_CFG_GDSCR, -}; - -static struct gdsc ufs_card_gdsc = { - .gdscr = 0x75004, - .pd = { - .name = "ufs_card_gdsc", - }, - .pwrsts = PWRSTS_OFF_ON, - .flags = POLL_CFG_GDSCR, -}; - -static struct gdsc ufs_phy_gdsc = { - .gdscr = 0x77004, - .pd = { - .name = "ufs_phy_gdsc", - }, - .pwrsts = PWRSTS_OFF_ON, - .flags = POLL_CFG_GDSCR, -}; - -static struct gdsc usb30_prim_gdsc = { - .gdscr = 0xf004, - .pd = { - .name = "usb30_prim_gdsc", - }, - .pwrsts = PWRSTS_OFF_ON, - .flags = POLL_CFG_GDSCR, -}; - -static struct gdsc usb30_sec_gdsc = { - .gdscr = 0x10004, - .pd = { - .name = "usb30_sec_gdsc", - }, - .pwrsts = PWRSTS_OFF_ON, - .flags = POLL_CFG_GDSCR, -}; - -static struct gdsc hlos1_vote_aggre_noc_mmu_audio_tbu_gdsc = { - .gdscr = 0x7d030, - .pd = { - .name = "hlos1_vote_aggre_noc_mmu_audio_tbu_gdsc", - }, - .pwrsts = PWRSTS_OFF_ON, - .flags = VOTABLE, -}; - -static struct gdsc hlos1_vote_aggre_noc_mmu_pcie_tbu_gdsc = { - .gdscr = 0x7d03c, - .pd = { - .name = "hlos1_vote_aggre_noc_mmu_pcie_tbu_gdsc", - }, - .pwrsts = PWRSTS_OFF_ON, - .flags = VOTABLE, -}; - -static struct gdsc hlos1_vote_aggre_noc_mmu_tbu1_gdsc = { - .gdscr = 0x7d034, - .pd = { - .name = "hlos1_vote_aggre_noc_mmu_tbu1_gdsc", - }, - .pwrsts = PWRSTS_OFF_ON, - .flags = VOTABLE, -}; - -static struct gdsc hlos1_vote_aggre_noc_mmu_tbu2_gdsc = { - .gdscr = 0x7d038, - .pd = { - .name = "hlos1_vote_aggre_noc_mmu_tbu2_gdsc", - }, - .pwrsts = PWRSTS_OFF_ON, - .flags = VOTABLE, -}; - -static struct gdsc hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc = { - .gdscr = 0x7d040, - .pd = { - .name = "hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc", - }, - .pwrsts = PWRSTS_OFF_ON, - .flags = VOTABLE, -}; - -static struct gdsc hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc = { - .gdscr = 0x7d048, - .pd = { - .name = "hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc", - }, - .pwrsts = PWRSTS_OFF_ON, - .flags = VOTABLE, -}; - -static struct gdsc hlos1_vote_mmnoc_mmu_tbu_sf_gdsc = { - .gdscr = 0x7d044, - .pd = { - .name = "hlos1_vote_mmnoc_mmu_tbu_sf_gdsc", - }, - .pwrsts = PWRSTS_OFF_ON, - .flags = VOTABLE, +struct clk_hw *gcc_sdm845_hws[] = { + [MEASURE_ONLY_SNOC_CLK] = &measure_only_snoc_clk.hw, + [MEASURE_ONLY_CNOC_CLK] = &measure_only_cnoc_clk.hw, + [MEASURE_ONLY_BIMC_CLK] = &measure_only_bimc_clk.hw, + [MEASURE_ONLY_IPA_2X_CLK] = &measure_only_ipa_2x_clk.hw, + [UFS_PHY_AXI_EMMC_VOTE_CLK] = &ufs_phy_axi_emmc_vote_clk.hw, + [UFS_PHY_AXI_UFS_VOTE_CLK] = &ufs_phy_axi_ufs_vote_clk.hw, }; static struct clk_regmap *gcc_sdm845_clocks[] = { [GCC_AGGRE_NOC_PCIE_TBU_CLK] = &gcc_aggre_noc_pcie_tbu_clk.clkr, [GCC_AGGRE_UFS_CARD_AXI_CLK] = &gcc_aggre_ufs_card_axi_clk.clkr, + [GCC_AGGRE_UFS_CARD_AXI_HW_CTL_CLK] = + &gcc_aggre_ufs_card_axi_hw_ctl_clk.clkr, [GCC_AGGRE_UFS_PHY_AXI_CLK] = &gcc_aggre_ufs_phy_axi_clk.clkr, + [GCC_AGGRE_UFS_PHY_AXI_HW_CTL_CLK] = + &gcc_aggre_ufs_phy_axi_hw_ctl_clk.clkr, [GCC_AGGRE_USB3_PRIM_AXI_CLK] = &gcc_aggre_usb3_prim_axi_clk.clkr, [GCC_AGGRE_USB3_SEC_AXI_CLK] = &gcc_aggre_usb3_sec_axi_clk.clkr, [GCC_APC_VS_CLK] = &gcc_apc_vs_clk.clkr, @@ -3225,6 +3804,8 @@ static struct clk_regmap *gcc_sdm845_clocks[] = { [GCC_CFG_NOC_USB3_SEC_AXI_CLK] = &gcc_cfg_noc_usb3_sec_axi_clk.clkr, [GCC_CPUSS_AHB_CLK] = &gcc_cpuss_ahb_clk.clkr, [GCC_CPUSS_AHB_CLK_SRC] = &gcc_cpuss_ahb_clk_src.clkr, + [GCC_CPUSS_DVM_BUS_CLK] = &gcc_cpuss_dvm_bus_clk.clkr, + [GCC_CPUSS_GNOC_CLK] = &gcc_cpuss_gnoc_clk.clkr, [GCC_CPUSS_RBCPR_CLK] = &gcc_cpuss_rbcpr_clk.clkr, [GCC_CPUSS_RBCPR_CLK_SRC] = &gcc_cpuss_rbcpr_clk_src.clkr, [GCC_DDRSS_GPU_AXI_CLK] = &gcc_ddrss_gpu_axi_clk.clkr, @@ -3330,30 +3911,43 @@ static struct clk_regmap *gcc_sdm845_clocks[] = { [GCC_TSIF_REF_CLK_SRC] = &gcc_tsif_ref_clk_src.clkr, [GCC_UFS_CARD_AHB_CLK] = &gcc_ufs_card_ahb_clk.clkr, [GCC_UFS_CARD_AXI_CLK] = &gcc_ufs_card_axi_clk.clkr, + [GCC_UFS_CARD_AXI_HW_CTL_CLK] = &gcc_ufs_card_axi_hw_ctl_clk.clkr, [GCC_UFS_CARD_AXI_CLK_SRC] = &gcc_ufs_card_axi_clk_src.clkr, [GCC_UFS_CARD_CLKREF_CLK] = &gcc_ufs_card_clkref_clk.clkr, [GCC_UFS_CARD_ICE_CORE_CLK] = &gcc_ufs_card_ice_core_clk.clkr, + [GCC_UFS_CARD_ICE_CORE_HW_CTL_CLK] = + &gcc_ufs_card_ice_core_hw_ctl_clk.clkr, [GCC_UFS_CARD_ICE_CORE_CLK_SRC] = &gcc_ufs_card_ice_core_clk_src.clkr, [GCC_UFS_CARD_PHY_AUX_CLK] = &gcc_ufs_card_phy_aux_clk.clkr, + [GCC_UFS_CARD_PHY_AUX_HW_CTL_CLK] = + &gcc_ufs_card_phy_aux_hw_ctl_clk.clkr, [GCC_UFS_CARD_PHY_AUX_CLK_SRC] = &gcc_ufs_card_phy_aux_clk_src.clkr, [GCC_UFS_CARD_RX_SYMBOL_0_CLK] = &gcc_ufs_card_rx_symbol_0_clk.clkr, [GCC_UFS_CARD_RX_SYMBOL_1_CLK] = &gcc_ufs_card_rx_symbol_1_clk.clkr, [GCC_UFS_CARD_TX_SYMBOL_0_CLK] = &gcc_ufs_card_tx_symbol_0_clk.clkr, [GCC_UFS_CARD_UNIPRO_CORE_CLK] = &gcc_ufs_card_unipro_core_clk.clkr, + [GCC_UFS_CARD_UNIPRO_CORE_HW_CTL_CLK] = + &gcc_ufs_card_unipro_core_hw_ctl_clk.clkr, [GCC_UFS_CARD_UNIPRO_CORE_CLK_SRC] = &gcc_ufs_card_unipro_core_clk_src.clkr, [GCC_UFS_MEM_CLKREF_CLK] = &gcc_ufs_mem_clkref_clk.clkr, [GCC_UFS_PHY_AHB_CLK] = &gcc_ufs_phy_ahb_clk.clkr, [GCC_UFS_PHY_AXI_CLK] = &gcc_ufs_phy_axi_clk.clkr, + [GCC_UFS_PHY_AXI_HW_CTL_CLK] = &gcc_ufs_phy_axi_hw_ctl_clk.clkr, [GCC_UFS_PHY_AXI_CLK_SRC] = &gcc_ufs_phy_axi_clk_src.clkr, [GCC_UFS_PHY_ICE_CORE_CLK] = &gcc_ufs_phy_ice_core_clk.clkr, + [GCC_UFS_PHY_ICE_CORE_HW_CTL_CLK] = + &gcc_ufs_phy_ice_core_hw_ctl_clk.clkr, [GCC_UFS_PHY_ICE_CORE_CLK_SRC] = &gcc_ufs_phy_ice_core_clk_src.clkr, [GCC_UFS_PHY_PHY_AUX_CLK] = &gcc_ufs_phy_phy_aux_clk.clkr, + [GCC_UFS_PHY_PHY_AUX_HW_CTL_CLK] = &gcc_ufs_phy_phy_aux_hw_ctl_clk.clkr, [GCC_UFS_PHY_PHY_AUX_CLK_SRC] = &gcc_ufs_phy_phy_aux_clk_src.clkr, [GCC_UFS_PHY_RX_SYMBOL_0_CLK] = &gcc_ufs_phy_rx_symbol_0_clk.clkr, [GCC_UFS_PHY_RX_SYMBOL_1_CLK] = &gcc_ufs_phy_rx_symbol_1_clk.clkr, [GCC_UFS_PHY_TX_SYMBOL_0_CLK] = &gcc_ufs_phy_tx_symbol_0_clk.clkr, [GCC_UFS_PHY_UNIPRO_CORE_CLK] = &gcc_ufs_phy_unipro_core_clk.clkr, + [GCC_UFS_PHY_UNIPRO_CORE_HW_CTL_CLK] = + &gcc_ufs_phy_unipro_core_hw_ctl_clk.clkr, [GCC_UFS_PHY_UNIPRO_CORE_CLK_SRC] = &gcc_ufs_phy_unipro_core_clk_src.clkr, [GCC_USB30_PRIM_MASTER_CLK] = &gcc_usb30_prim_master_clk.clkr, @@ -3392,8 +3986,12 @@ static struct clk_regmap *gcc_sdm845_clocks[] = { [GPLL0] = &gpll0.clkr, [GPLL0_OUT_EVEN] = &gpll0_out_even.clkr, [GPLL4] = &gpll4.clkr, - [GCC_CPUSS_DVM_BUS_CLK] = &gcc_cpuss_dvm_bus_clk.clkr, - [GCC_CPUSS_GNOC_CLK] = &gcc_cpuss_gnoc_clk.clkr, + [GCC_SDCC1_AHB_CLK] = NULL, + [GCC_SDCC1_APPS_CLK] = NULL, + [GCC_SDCC1_ICE_CORE_CLK] = NULL, + [GCC_SDCC1_APPS_CLK_SRC] = NULL, + [GCC_SDCC1_ICE_CORE_CLK_SRC] = NULL, + [GPLL6] = NULL, }; static const struct qcom_reset_map gcc_sdm845_resets[] = { @@ -3423,28 +4021,32 @@ static const struct qcom_reset_map gcc_sdm845_resets[] = { [GCC_USB_PHY_CFG_AHB2PHY_BCR] = { 0x6a000 }, [GCC_PCIE_0_PHY_BCR] = { 0x6c01c }, [GCC_PCIE_1_PHY_BCR] = { 0x8e01c }, -}; - -static struct gdsc *gcc_sdm845_gdscs[] = { - [PCIE_0_GDSC] = &pcie_0_gdsc, - [PCIE_1_GDSC] = &pcie_1_gdsc, - [UFS_CARD_GDSC] = &ufs_card_gdsc, - [UFS_PHY_GDSC] = &ufs_phy_gdsc, - [USB30_PRIM_GDSC] = &usb30_prim_gdsc, - [USB30_SEC_GDSC] = &usb30_sec_gdsc, - [HLOS1_VOTE_AGGRE_NOC_MMU_AUDIO_TBU_GDSC] = - &hlos1_vote_aggre_noc_mmu_audio_tbu_gdsc, - [HLOS1_VOTE_AGGRE_NOC_MMU_PCIE_TBU_GDSC] = - &hlos1_vote_aggre_noc_mmu_pcie_tbu_gdsc, - [HLOS1_VOTE_AGGRE_NOC_MMU_TBU1_GDSC] = - &hlos1_vote_aggre_noc_mmu_tbu1_gdsc, - [HLOS1_VOTE_AGGRE_NOC_MMU_TBU2_GDSC] = - &hlos1_vote_aggre_noc_mmu_tbu2_gdsc, - [HLOS1_VOTE_MMNOC_MMU_TBU_HF0_GDSC] = - &hlos1_vote_mmnoc_mmu_tbu_hf0_gdsc, - [HLOS1_VOTE_MMNOC_MMU_TBU_HF1_GDSC] = - &hlos1_vote_mmnoc_mmu_tbu_hf1_gdsc, - [HLOS1_VOTE_MMNOC_MMU_TBU_SF_GDSC] = &hlos1_vote_mmnoc_mmu_tbu_sf_gdsc, + [GCC_SDCC1_BCR] = { 0x26000 }, +}; + +/* List of RCG clocks and corresponding flags requested for DFS Mode */ +static struct clk_dfs gcc_dfs_clocks[] = { + { &gcc_qupv3_wrap0_s0_clk_src, DFS_ENABLE_RCG }, + { &gcc_qupv3_wrap0_s1_clk_src, DFS_ENABLE_RCG }, + { &gcc_qupv3_wrap0_s2_clk_src, DFS_ENABLE_RCG }, + { &gcc_qupv3_wrap0_s3_clk_src, DFS_ENABLE_RCG }, + { &gcc_qupv3_wrap0_s4_clk_src, DFS_ENABLE_RCG }, + { &gcc_qupv3_wrap0_s5_clk_src, DFS_ENABLE_RCG }, + { &gcc_qupv3_wrap0_s6_clk_src, DFS_ENABLE_RCG }, + { &gcc_qupv3_wrap0_s7_clk_src, DFS_ENABLE_RCG }, + { &gcc_qupv3_wrap1_s0_clk_src, DFS_ENABLE_RCG }, + { &gcc_qupv3_wrap1_s1_clk_src, DFS_ENABLE_RCG }, + { &gcc_qupv3_wrap1_s2_clk_src, DFS_ENABLE_RCG }, + { &gcc_qupv3_wrap1_s3_clk_src, DFS_ENABLE_RCG }, + { &gcc_qupv3_wrap1_s4_clk_src, DFS_ENABLE_RCG }, + { &gcc_qupv3_wrap1_s5_clk_src, DFS_ENABLE_RCG }, + { &gcc_qupv3_wrap1_s6_clk_src, DFS_ENABLE_RCG }, + { &gcc_qupv3_wrap1_s7_clk_src, DFS_ENABLE_RCG }, +}; + +static const struct qcom_cc_dfs_desc gcc_sdm845_dfs_desc = { + .clks = gcc_dfs_clocks, + .num_clks = ARRAY_SIZE(gcc_dfs_clocks), }; static const struct regmap_config gcc_sdm845_regmap_config = { @@ -3459,31 +4061,274 @@ static const struct qcom_cc_desc gcc_sdm845_desc = { .config = &gcc_sdm845_regmap_config, .clks = gcc_sdm845_clocks, .num_clks = ARRAY_SIZE(gcc_sdm845_clocks), + .hwclks = gcc_sdm845_hws, + .num_hwclks = ARRAY_SIZE(gcc_sdm845_hws), .resets = gcc_sdm845_resets, .num_resets = ARRAY_SIZE(gcc_sdm845_resets), - .gdscs = gcc_sdm845_gdscs, - .num_gdscs = ARRAY_SIZE(gcc_sdm845_gdscs), }; static const struct of_device_id gcc_sdm845_match_table[] = { { .compatible = "qcom,gcc-sdm845" }, + { .compatible = "qcom,gcc-sdm845-v2" }, + { .compatible = "qcom,gcc-sdm845-v2.1" }, + { .compatible = "qcom,gcc-sdm670" }, { } }; MODULE_DEVICE_TABLE(of, gcc_sdm845_match_table); +static void gcc_sdm845_fixup_sdm845v2(void) +{ + gcc_qupv3_wrap0_s0_clk_src.freq_tbl = + ftbl_gcc_qupv3_wrap0_s0_clk_src_sdm845_v2; + gcc_qupv3_wrap0_s0_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = + 50000000; + gcc_qupv3_wrap0_s0_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = + 128000000; + gcc_qupv3_wrap0_s1_clk_src.freq_tbl = + ftbl_gcc_qupv3_wrap0_s0_clk_src_sdm845_v2; + gcc_qupv3_wrap0_s1_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = + 50000000; + gcc_qupv3_wrap0_s1_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = + 128000000; + gcc_qupv3_wrap0_s2_clk_src.freq_tbl = + ftbl_gcc_qupv3_wrap0_s0_clk_src_sdm845_v2; + gcc_qupv3_wrap0_s2_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = + 50000000; + gcc_qupv3_wrap0_s2_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = + 128000000; + gcc_qupv3_wrap0_s3_clk_src.freq_tbl = + ftbl_gcc_qupv3_wrap0_s0_clk_src_sdm845_v2; + gcc_qupv3_wrap0_s3_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = + 50000000; + gcc_qupv3_wrap0_s3_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = + 128000000; + gcc_qupv3_wrap0_s4_clk_src.freq_tbl = + ftbl_gcc_qupv3_wrap0_s0_clk_src_sdm845_v2; + gcc_qupv3_wrap0_s4_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = + 50000000; + gcc_qupv3_wrap0_s4_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = + 128000000; + gcc_qupv3_wrap0_s5_clk_src.freq_tbl = + ftbl_gcc_qupv3_wrap0_s0_clk_src_sdm845_v2; + gcc_qupv3_wrap0_s5_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = + 50000000; + gcc_qupv3_wrap0_s5_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = + 128000000; + gcc_qupv3_wrap0_s6_clk_src.freq_tbl = + ftbl_gcc_qupv3_wrap0_s0_clk_src_sdm845_v2; + gcc_qupv3_wrap0_s6_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = + 50000000; + gcc_qupv3_wrap0_s6_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = + 128000000; + gcc_qupv3_wrap0_s7_clk_src.freq_tbl = + ftbl_gcc_qupv3_wrap0_s0_clk_src_sdm845_v2; + gcc_qupv3_wrap0_s7_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = + 50000000; + gcc_qupv3_wrap0_s7_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = + 128000000; + gcc_qupv3_wrap1_s0_clk_src.freq_tbl = + ftbl_gcc_qupv3_wrap0_s0_clk_src_sdm845_v2; + gcc_qupv3_wrap1_s0_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = + 50000000; + gcc_qupv3_wrap1_s0_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = + 128000000; + gcc_qupv3_wrap1_s1_clk_src.freq_tbl = + ftbl_gcc_qupv3_wrap0_s0_clk_src_sdm845_v2; + gcc_qupv3_wrap1_s1_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = + 50000000; + gcc_qupv3_wrap1_s1_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = + 128000000; + gcc_qupv3_wrap1_s2_clk_src.freq_tbl = + ftbl_gcc_qupv3_wrap0_s0_clk_src_sdm845_v2; + gcc_qupv3_wrap1_s2_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = + 50000000; + gcc_qupv3_wrap1_s2_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = + 128000000; + gcc_qupv3_wrap1_s3_clk_src.freq_tbl = + ftbl_gcc_qupv3_wrap0_s0_clk_src_sdm845_v2; + gcc_qupv3_wrap1_s3_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = + 50000000; + gcc_qupv3_wrap1_s3_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = + 128000000; + gcc_qupv3_wrap1_s4_clk_src.freq_tbl = + ftbl_gcc_qupv3_wrap0_s0_clk_src_sdm845_v2; + gcc_qupv3_wrap1_s4_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = + 50000000; + gcc_qupv3_wrap1_s4_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = + 128000000; + gcc_qupv3_wrap1_s5_clk_src.freq_tbl = + ftbl_gcc_qupv3_wrap0_s0_clk_src_sdm845_v2; + gcc_qupv3_wrap1_s5_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = + 50000000; + gcc_qupv3_wrap1_s5_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = + 128000000; + gcc_qupv3_wrap1_s6_clk_src.freq_tbl = + ftbl_gcc_qupv3_wrap0_s0_clk_src_sdm845_v2; + gcc_qupv3_wrap1_s6_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = + 50000000; + gcc_qupv3_wrap1_s6_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = + 128000000; + gcc_qupv3_wrap1_s7_clk_src.freq_tbl = + ftbl_gcc_qupv3_wrap0_s0_clk_src_sdm845_v2; + gcc_qupv3_wrap1_s7_clk_src.clkr.hw.init->rate_max[VDD_CX_MIN] = + 50000000; + gcc_qupv3_wrap1_s7_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = + 128000000; + gcc_ufs_card_axi_clk_src.freq_tbl = + ftbl_gcc_ufs_card_axi_clk_src_sdm845_v2; + gcc_ufs_card_axi_clk_src.clkr.hw.init->rate_max[VDD_CX_HIGH] = + 240000000; + gcc_ufs_phy_axi_clk_src.freq_tbl = + ftbl_gcc_ufs_card_axi_clk_src_sdm845_v2; + gcc_vsensor_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = 600000000; +} + +static void gcc_sdm845_fixup_sdm670(void) +{ + gcc_sdm845_fixup_sdm845v2(); + + gcc_sdm845_clocks[GCC_SDCC1_AHB_CLK] = &gcc_sdcc1_ahb_clk.clkr; + gcc_sdm845_clocks[GCC_SDCC1_APPS_CLK] = &gcc_sdcc1_apps_clk.clkr; + gcc_sdm845_clocks[GCC_SDCC1_ICE_CORE_CLK] = + &gcc_sdcc1_ice_core_clk.clkr; + gcc_sdm845_clocks[GCC_SDCC1_APPS_CLK_SRC] = + &gcc_sdcc1_apps_clk_src.clkr; + gcc_sdm845_clocks[GCC_SDCC1_ICE_CORE_CLK_SRC] = + &gcc_sdcc1_ice_core_clk_src.clkr; + gcc_sdm845_clocks[GPLL6] = &gpll6.clkr; + gcc_sdm845_clocks[GCC_AGGRE_UFS_CARD_AXI_CLK] = NULL; + gcc_sdm845_clocks[GCC_AGGRE_UFS_CARD_AXI_HW_CTL_CLK] = NULL; + gcc_sdm845_clocks[GCC_AGGRE_USB3_SEC_AXI_CLK] = NULL; + gcc_sdm845_clocks[GCC_AGGRE_NOC_PCIE_TBU_CLK] = NULL; + gcc_sdm845_clocks[GCC_CFG_NOC_USB3_SEC_AXI_CLK] = NULL; + gcc_sdm845_clocks[GCC_PCIE_0_AUX_CLK] = NULL; + gcc_sdm845_clocks[GCC_PCIE_0_AUX_CLK_SRC] = NULL; + gcc_sdm845_clocks[GCC_PCIE_0_CFG_AHB_CLK] = NULL; + gcc_sdm845_clocks[GCC_PCIE_0_CLKREF_CLK] = NULL; + gcc_sdm845_clocks[GCC_PCIE_0_MSTR_AXI_CLK] = NULL; + gcc_sdm845_clocks[GCC_PCIE_0_PIPE_CLK] = NULL; + gcc_sdm845_clocks[GCC_PCIE_0_SLV_AXI_CLK] = NULL; + gcc_sdm845_clocks[GCC_PCIE_0_SLV_Q2A_AXI_CLK] = NULL; + gcc_sdm845_clocks[GCC_PCIE_1_AUX_CLK] = NULL; + gcc_sdm845_clocks[GCC_PCIE_1_AUX_CLK_SRC] = NULL; + gcc_sdm845_clocks[GCC_PCIE_1_CFG_AHB_CLK] = NULL; + gcc_sdm845_clocks[GCC_PCIE_1_CLKREF_CLK] = NULL; + gcc_sdm845_clocks[GCC_PCIE_1_MSTR_AXI_CLK] = NULL; + gcc_sdm845_clocks[GCC_PCIE_1_PIPE_CLK] = NULL; + gcc_sdm845_clocks[GCC_PCIE_1_SLV_AXI_CLK] = NULL; + gcc_sdm845_clocks[GCC_PCIE_1_SLV_Q2A_AXI_CLK] = NULL; + gcc_sdm845_clocks[GCC_PCIE_PHY_AUX_CLK] = NULL; + gcc_sdm845_clocks[GCC_PCIE_PHY_REFGEN_CLK] = NULL; + gcc_sdm845_clocks[GCC_PCIE_PHY_REFGEN_CLK_SRC] = NULL; + gcc_sdm845_clocks[GCC_UFS_CARD_AHB_CLK] = NULL; + gcc_sdm845_clocks[GCC_UFS_CARD_AXI_CLK] = NULL; + gcc_sdm845_clocks[GCC_UFS_CARD_AXI_HW_CTL_CLK] = NULL; + gcc_sdm845_clocks[GCC_UFS_CARD_AXI_CLK_SRC] = NULL; + gcc_sdm845_clocks[GCC_UFS_CARD_CLKREF_CLK] = NULL; + gcc_sdm845_clocks[GCC_UFS_CARD_ICE_CORE_CLK] = NULL; + gcc_sdm845_clocks[GCC_UFS_CARD_ICE_CORE_HW_CTL_CLK] = NULL; + gcc_sdm845_clocks[GCC_UFS_CARD_ICE_CORE_CLK_SRC] = NULL; + gcc_sdm845_clocks[GCC_UFS_CARD_PHY_AUX_CLK] = NULL; + gcc_sdm845_clocks[GCC_UFS_CARD_PHY_AUX_HW_CTL_CLK] = NULL; + gcc_sdm845_clocks[GCC_UFS_CARD_PHY_AUX_CLK_SRC] = NULL; + gcc_sdm845_clocks[GCC_UFS_CARD_RX_SYMBOL_0_CLK] = NULL; + gcc_sdm845_clocks[GCC_UFS_CARD_RX_SYMBOL_1_CLK] = NULL; + gcc_sdm845_clocks[GCC_UFS_CARD_TX_SYMBOL_0_CLK] = NULL; + gcc_sdm845_clocks[GCC_UFS_CARD_UNIPRO_CORE_CLK] = NULL; + gcc_sdm845_clocks[GCC_UFS_CARD_UNIPRO_CORE_HW_CTL_CLK] = NULL; + gcc_sdm845_clocks[GCC_UFS_CARD_UNIPRO_CORE_CLK_SRC] = NULL; + gcc_sdm845_clocks[GCC_UFS_PHY_RX_SYMBOL_1_CLK] = NULL; + gcc_sdm845_clocks[GCC_USB30_SEC_MASTER_CLK] = NULL; + gcc_sdm845_clocks[GCC_USB30_SEC_MASTER_CLK_SRC] = NULL; + gcc_sdm845_clocks[GCC_USB30_SEC_MOCK_UTMI_CLK] = NULL; + gcc_sdm845_clocks[GCC_USB30_SEC_MOCK_UTMI_CLK_SRC] = NULL; + gcc_sdm845_clocks[GCC_USB30_SEC_SLEEP_CLK] = NULL; + gcc_sdm845_clocks[GCC_USB3_SEC_CLKREF_CLK] = NULL; + gcc_sdm845_clocks[GCC_USB3_SEC_PHY_AUX_CLK] = NULL; + gcc_sdm845_clocks[GCC_USB3_SEC_PHY_AUX_CLK_SRC] = NULL; + gcc_sdm845_clocks[GCC_USB3_SEC_PHY_COM_AUX_CLK] = NULL; + gcc_sdm845_clocks[GCC_USB3_SEC_PHY_PIPE_CLK] = NULL; + + gcc_cpuss_rbcpr_clk_src.freq_tbl = ftbl_gcc_cpuss_rbcpr_clk_src_sdm670; + gcc_cpuss_rbcpr_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = + 50000000; + gcc_sdcc2_apps_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 50000000; + gcc_sdcc2_apps_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW_L1] = + 100000000; + gcc_sdcc2_apps_clk_src.clkr.hw.init->rate_max[VDD_CX_NOMINAL] = + 201500000; + gcc_sdcc4_apps_clk_src.freq_tbl = ftbl_gcc_sdcc4_apps_clk_src_sdm670; + gcc_sdcc4_apps_clk_src.clkr.hw.init->rate_max[VDD_CX_LOWER] = 33333333; +} + +static int gcc_sdm845_fixup(struct platform_device *pdev) +{ + const char *compat = NULL; + int compatlen = 0; + + compat = of_get_property(pdev->dev.of_node, "compatible", &compatlen); + if (!compat || (compatlen <= 0)) + return -EINVAL; + + if (!strcmp(compat, "qcom,gcc-sdm845-v2") || + !strcmp(compat, "qcom,gcc-sdm845-v2.1")) + gcc_sdm845_fixup_sdm845v2(); + else if (!strcmp(compat, "qcom,gcc-sdm670")) + gcc_sdm845_fixup_sdm670(); + + return 0; +} + static int gcc_sdm845_probe(struct platform_device *pdev) { struct regmap *regmap; + int ret = 0; regmap = qcom_cc_map(pdev, &gcc_sdm845_desc); if (IS_ERR(regmap)) return PTR_ERR(regmap); + vdd_cx.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_cx"); + if (IS_ERR(vdd_cx.regulator[0])) { + if (!(PTR_ERR(vdd_cx.regulator[0]) == -EPROBE_DEFER)) + dev_err(&pdev->dev, + "Unable to get vdd_cx regulator\n"); + return PTR_ERR(vdd_cx.regulator[0]); + } + + vdd_cx_ao.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_cx_ao"); + if (IS_ERR(vdd_cx_ao.regulator[0])) { + if (!(PTR_ERR(vdd_cx_ao.regulator[0]) == -EPROBE_DEFER)) + dev_err(&pdev->dev, + "Unable to get vdd_cx_ao regulator\n"); + return PTR_ERR(vdd_cx_ao.regulator[0]); + } + + ret = gcc_sdm845_fixup(pdev); + if (ret) + return ret; + + ret = qcom_cc_really_probe(pdev, &gcc_sdm845_desc, regmap); + if (ret) { + dev_err(&pdev->dev, "Failed to register GCC clocks\n"); + return ret; + } + /* Disable the GPLL0 active input to MMSS and GPU via MISC registers */ - regmap_update_bits(regmap, 0x09ffc, 0x3, 0x3); - regmap_update_bits(regmap, 0x71028, 0x3, 0x3); + regmap_update_bits(regmap, GCC_MMSS_MISC, 0x3, 0x3); + regmap_update_bits(regmap, GCC_GPU_MISC, 0x3, 0x3); - return qcom_cc_really_probe(pdev, &gcc_sdm845_desc, regmap); + /* Keep this clock on all the times except on SDM845 v2.1 */ + if (!of_device_is_compatible(pdev->dev.of_node, "qcom,gcc-sdm845-v2.1")) + clk_prepare_enable(gcc_aggre_noc_pcie_tbu_clk.clkr.hw.clk); + + /* DFS clock registration */ + ret = qcom_cc_register_rcg_dfs(pdev, &gcc_sdm845_dfs_desc); + if (ret) + dev_err(&pdev->dev, "Failed to register with DFS!\n"); + + dev_info(&pdev->dev, "Registered GCC clocks\n"); + return ret; } static struct platform_driver gcc_sdm845_driver = { @@ -3509,3 +4354,4 @@ module_exit(gcc_sdm845_exit); MODULE_DESCRIPTION("QTI GCC SDM845 Driver"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:gcc-sdm845"); + diff --git a/drivers/clk/qcom/gpucc-sdm845.c b/drivers/clk/qcom/gpucc-sdm845.c new file mode 100644 index 000000000000..9eec85ecbf5a --- /dev/null +++ b/drivers/clk/qcom/gpucc-sdm845.c @@ -0,0 +1,847 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "clk: %s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "clk-regmap.h" +#include "clk-pll.h" +#include "clk-rcg.h" +#include "clk-branch.h" +#include "reset.h" +#include "clk-alpha-pll.h" +#include "vdd-level-sdm845.h" + +#define CX_GMU_CBCR_SLEEP_MASK 0xF +#define CX_GMU_CBCR_SLEEP_SHIFT 4 +#define CX_GMU_CBCR_WAKE_MASK 0xF +#define CX_GMU_CBCR_WAKE_SHIFT 8 + +#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } + +static int vdd_gx_corner[] = { + RPMH_REGULATOR_LEVEL_OFF, /* VDD_GX_NONE */ + RPMH_REGULATOR_LEVEL_MIN_SVS, /* VDD_GX_MIN */ + RPMH_REGULATOR_LEVEL_LOW_SVS, /* VDD_GX_LOWER */ + RPMH_REGULATOR_LEVEL_SVS, /* VDD_GX_LOW */ + RPMH_REGULATOR_LEVEL_SVS_L1, /* VDD_GX_LOW_L1 */ + RPMH_REGULATOR_LEVEL_NOM, /* VDD_GX_NOMINAL */ + RPMH_REGULATOR_LEVEL_NOM_L1, /* VDD_GX_NOMINAL_L1 */ + RPMH_REGULATOR_LEVEL_TURBO, /* VDD_GX_HIGH */ + RPMH_REGULATOR_LEVEL_TURBO_L1, /* VDD_GX_HIGH_L1 */ + RPMH_REGULATOR_LEVEL_MAX, /* VDD_GX_MAX */ +}; + +static DEFINE_VDD_REGULATORS(vdd_cx, VDD_CX_NUM, 1, vdd_corner); +static DEFINE_VDD_REGULATORS(vdd_mx, VDD_CX_NUM, 1, vdd_corner); +static DEFINE_VDD_REGULATORS(vdd_gfx, VDD_GX_NUM, 1, vdd_gx_corner); + +enum { + P_BI_TCXO, + P_CORE_BI_PLL_TEST_SE, + P_GPLL0_OUT_MAIN, + P_GPLL0_OUT_MAIN_DIV, + P_GPU_CC_PLL0_OUT_EVEN, + P_GPU_CC_PLL0_OUT_MAIN, + P_GPU_CC_PLL0_OUT_ODD, + P_GPU_CC_PLL1_OUT_EVEN, + P_GPU_CC_PLL1_OUT_MAIN, + P_GPU_CC_PLL1_OUT_ODD, + P_CRC_DIV, +}; + +static const struct parent_map gpu_cc_parent_map_0[] = { + { P_BI_TCXO, 0 }, + { P_GPU_CC_PLL0_OUT_MAIN, 1 }, + { P_GPU_CC_PLL1_OUT_MAIN, 3 }, + { P_GPLL0_OUT_MAIN, 5 }, + { P_GPLL0_OUT_MAIN_DIV, 6 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const gpu_cc_parent_names_0[] = { + "bi_tcxo", + "gpu_cc_pll0", + "gpu_cc_pll1", + "gcc_gpu_gpll0_clk_src", + "gcc_gpu_gpll0_div_clk_src", + "core_bi_pll_test_se", +}; + +static const struct parent_map gpu_cc_parent_map_1[] = { + { P_BI_TCXO, 0 }, + { P_GPU_CC_PLL0_OUT_EVEN, 1 }, + { P_GPU_CC_PLL0_OUT_ODD, 2 }, + { P_GPU_CC_PLL1_OUT_EVEN, 3 }, + { P_GPU_CC_PLL1_OUT_ODD, 4 }, + { P_GPLL0_OUT_MAIN, 5 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const gpu_cc_parent_names_1[] = { + "bi_tcxo", + "gpu_cc_pll0_out_even", + "gpu_cc_pll0_out_odd", + "gpu_cc_pll1_out_even", + "gpu_cc_pll1_out_odd", + "gcc_gpu_gpll0_clk_src", + "core_bi_pll_test_se", +}; + +static const struct parent_map gpu_cc_parent_map_2[] = { + { P_BI_TCXO, 0 }, + { P_CRC_DIV, 1 }, + { P_GPU_CC_PLL0_OUT_ODD, 2 }, + { P_GPU_CC_PLL1_OUT_EVEN, 3 }, + { P_GPU_CC_PLL1_OUT_ODD, 4 }, + { P_GPLL0_OUT_MAIN, 5 }, + { P_CORE_BI_PLL_TEST_SE, 7 }, +}; + +static const char * const gpu_cc_parent_names_2[] = { + "bi_tcxo", + "crc_div", + "gpu_cc_pll0_out_odd", + "gpu_cc_pll1_out_even", + "gpu_cc_pll1_out_odd", + "gcc_gpu_gpll0_clk_src", + "core_bi_pll_test_se", +}; + +static struct pll_vco fabia_vco[] = { + { 249600000, 2000000000, 0 }, + { 125000000, 1000000000, 1 }, +}; + +static const struct pll_config gpu_cc_pll0_config = { + .l = 0x1d, + .frac = 0x2aaa, +}; + +static const struct pll_config gpu_cc_pll1_config = { + .l = 0x1a, + .frac = 0xaaaa, +}; + +static struct clk_alpha_pll gpu_cc_pll0 = { + .offset = 0x0, + .vco_table = fabia_vco, + .num_vco = ARRAY_SIZE(fabia_vco), + .type = FABIA_PLL, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_pll0", + .parent_names = (const char *[]){ "bi_tcxo" }, + .num_parents = 1, + .ops = &clk_fabia_pll_ops, + VDD_MX_FMAX_MAP4( + MIN, 615000000, + LOW, 1066000000, + LOW_L1, 1600000000, + NOMINAL, 2000000000), + }, + }, +}; + +static const struct clk_div_table post_div_table_fabia_even[] = { + { 0x0, 1 }, + { 0x1, 2 }, + { 0x3, 4 }, + { 0x7, 8 }, + {}, +}; + +static struct clk_alpha_pll_postdiv gpu_cc_pll0_out_even = { + .offset = 0x0, + .post_div_shift = 8, + .post_div_table = post_div_table_fabia_even, + .num_post_div = ARRAY_SIZE(post_div_table_fabia_even), + .width = 4, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gpu_cc_pll0_out_even", + .parent_names = (const char *[]){ "gpu_cc_pll0" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_generic_pll_postdiv_ops, + }, +}; + +static struct clk_alpha_pll gpu_cc_pll1 = { + .offset = 0x100, + .vco_table = fabia_vco, + .num_vco = ARRAY_SIZE(fabia_vco), + .type = FABIA_PLL, + .clkr = { + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_pll1", + .parent_names = (const char *[]){ "bi_tcxo" }, + .num_parents = 1, + .ops = &clk_fabia_pll_ops, + VDD_MX_FMAX_MAP4( + MIN, 615000000, + LOW, 1066000000, + LOW_L1, 1600000000, + NOMINAL, 2000000000), + }, + }, +}; + +static const struct freq_tbl ftbl_gpu_cc_gmu_clk_src[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(200000000, P_GPLL0_OUT_MAIN_DIV, 1.5, 0, 0), + F(400000000, P_GPLL0_OUT_MAIN, 1.5, 0, 0), + { } +}; + +static const struct freq_tbl ftbl_gpu_cc_gmu_clk_src_sdm845_v2[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(200000000, P_GPLL0_OUT_MAIN_DIV, 1.5, 0, 0), + F(500000000, P_GPU_CC_PLL1_OUT_MAIN, 1, 0, 0), + { } +}; + +static const struct freq_tbl ftbl_gpu_cc_gmu_clk_src_sdm670[] = { + F(19200000, P_BI_TCXO, 1, 0, 0), + F(200000000, P_GPLL0_OUT_MAIN_DIV, 1.5, 0, 0), + { } +}; + +static struct clk_rcg2 gpu_cc_gmu_clk_src = { + .cmd_rcgr = 0x1120, + .mnd_width = 0, + .hid_width = 5, + .enable_safe_config = true, + .parent_map = gpu_cc_parent_map_0, + .freq_tbl = ftbl_gpu_cc_gmu_clk_src, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gpu_cc_gmu_clk_src", + .parent_names = gpu_cc_parent_names_0, + .num_parents = 6, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP2( + MIN, 200000000, + LOW, 400000000), + }, +}; + +static struct clk_fixed_factor crc_div = { + .mult = 1, + .div = 1, + .hw.init = &(struct clk_init_data){ + .name = "crc_div", + .parent_names = (const char *[]){ "gpu_cc_pll0_out_even" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_fixed_factor_ops, + }, +}; + +static const struct freq_tbl ftbl_gpu_cc_gx_gfx3d_clk_src[] = { + F(147000000, P_CRC_DIV, 1, 0, 0), + F(210000000, P_CRC_DIV, 1, 0, 0), + F(280000000, P_CRC_DIV, 1, 0, 0), + F(338000000, P_CRC_DIV, 1, 0, 0), + F(425000000, P_CRC_DIV, 1, 0, 0), + F(487000000, P_CRC_DIV, 1, 0, 0), + F(548000000, P_CRC_DIV, 1, 0, 0), + F(600000000, P_CRC_DIV, 1, 0, 0), + { } +}; + +static const struct freq_tbl ftbl_gpu_cc_gx_gfx3d_clk_src_sdm845_v2[] = { + F(180000000, P_CRC_DIV, 1, 0, 0), + F(257000000, P_CRC_DIV, 1, 0, 0), + F(342000000, P_CRC_DIV, 1, 0, 0), + F(414000000, P_CRC_DIV, 1, 0, 0), + F(520000000, P_CRC_DIV, 1, 0, 0), + F(596000000, P_CRC_DIV, 1, 0, 0), + F(675000000, P_CRC_DIV, 1, 0, 0), + F(710000000, P_CRC_DIV, 1, 0, 0), + { } +}; + +static const struct freq_tbl ftbl_gpu_cc_gx_gfx3d_clk_src_sdm670[] = { + F(180000000, P_CRC_DIV, 1, 0, 0), + F(267000000, P_CRC_DIV, 1, 0, 0), + F(355000000, P_CRC_DIV, 1, 0, 0), + F(430000000, P_CRC_DIV, 1, 0, 0), + F(504000000, P_CRC_DIV, 1, 0, 0), + F(565000000, P_CRC_DIV, 1, 0, 0), + F(610000000, P_CRC_DIV, 1, 0, 0), + F(650000000, P_CRC_DIV, 1, 0, 0), + F(700000000, P_CRC_DIV, 1, 0, 0), + F(750000000, P_CRC_DIV, 1, 0, 0), + F(780000000, P_CRC_DIV, 1, 0, 0), + { } +}; + +static struct clk_rcg2 gpu_cc_gx_gfx3d_clk_src = { + .cmd_rcgr = 0x101c, + .mnd_width = 0, + .hid_width = 5, + .parent_map = gpu_cc_parent_map_2, + .freq_tbl = ftbl_gpu_cc_gx_gfx3d_clk_src, + .flags = FORCE_ENABLE_RCG, + .clkr.hw.init = &(struct clk_init_data){ + .name = "gpu_cc_gx_gfx3d_clk_src", + .parent_names = gpu_cc_parent_names_2, + .num_parents = 7, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_GX_FMAX_MAP8( + MIN, 147000000, + LOWER, 210000000, + LOW, 280000000, + LOW_L1, 338000000, + NOMINAL, 425000000, + NOMINAL_L1, 487000000, + HIGH, 548000000, + HIGH_L1, 600000000), + }, +}; + +static struct clk_branch gpu_cc_acd_ahb_clk = { + .halt_reg = 0x1168, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1168, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_acd_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_acd_cxo_clk = { + .halt_reg = 0x1164, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1164, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_acd_cxo_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_crc_ahb_clk = { + .halt_reg = 0x107c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x107c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_crc_ahb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cx_apb_clk = { + .halt_reg = 0x1088, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1088, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cx_apb_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cx_gfx3d_clk = { + .halt_reg = 0x10a4, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x10a4, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cx_gfx3d_clk", + .parent_names = (const char *[]){ + "gpu_cc_gx_gfx3d_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cx_gfx3d_slv_clk = { + .halt_reg = 0x10a8, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x10a8, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cx_gfx3d_slv_clk", + .parent_names = (const char *[]){ + "gpu_cc_gx_gfx3d_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cx_gmu_clk = { + .halt_reg = 0x1098, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1098, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cx_gmu_clk", + .parent_names = (const char *[]){ + "gpu_cc_gmu_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cx_snoc_dvm_clk = { + .halt_reg = 0x108c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x108c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cx_snoc_dvm_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cxo_aon_clk = { + .halt_reg = 0x1004, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1004, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cxo_aon_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_cxo_clk = { + .halt_reg = 0x109c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x109c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_cxo_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_gx_gfx3d_clk = { + .halt_reg = 0x1054, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1054, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_gx_gfx3d_clk", + .parent_names = (const char *[]){ + "gpu_cc_gx_gfx3d_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_gx_gmu_clk = { + .halt_reg = 0x1064, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1064, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_gx_gmu_clk", + .parent_names = (const char *[]){ + "gpu_cc_gmu_clk_src", + }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_gx_vsense_clk = { + .halt_reg = 0x1058, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x1058, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_gx_vsense_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_branch gpu_cc_pll_test_clk = { + .halt_reg = 0x110c, + .halt_check = BRANCH_HALT, + .clkr = { + .enable_reg = 0x110c, + .enable_mask = BIT(0), + .hw.init = &(struct clk_init_data){ + .name = "gpu_cc_pll_test_clk", + .ops = &clk_branch2_ops, + }, + }, +}; + +static struct clk_regmap *gpu_cc_sdm845_clocks[] = { + [GPU_CC_ACD_AHB_CLK] = &gpu_cc_acd_ahb_clk.clkr, + [GPU_CC_ACD_CXO_CLK] = &gpu_cc_acd_cxo_clk.clkr, + [GPU_CC_CRC_AHB_CLK] = &gpu_cc_crc_ahb_clk.clkr, + [GPU_CC_CX_APB_CLK] = &gpu_cc_cx_apb_clk.clkr, + [GPU_CC_CX_GFX3D_CLK] = &gpu_cc_cx_gfx3d_clk.clkr, + [GPU_CC_CX_GFX3D_SLV_CLK] = &gpu_cc_cx_gfx3d_slv_clk.clkr, + [GPU_CC_CX_GMU_CLK] = &gpu_cc_cx_gmu_clk.clkr, + [GPU_CC_CX_SNOC_DVM_CLK] = &gpu_cc_cx_snoc_dvm_clk.clkr, + [GPU_CC_CXO_AON_CLK] = &gpu_cc_cxo_aon_clk.clkr, + [GPU_CC_CXO_CLK] = &gpu_cc_cxo_clk.clkr, + [GPU_CC_GMU_CLK_SRC] = &gpu_cc_gmu_clk_src.clkr, + [GPU_CC_GX_GMU_CLK] = &gpu_cc_gx_gmu_clk.clkr, + [GPU_CC_GX_VSENSE_CLK] = &gpu_cc_gx_vsense_clk.clkr, + [GPU_CC_PLL_TEST_CLK] = &gpu_cc_pll_test_clk.clkr, + [GPU_CC_PLL0] = &gpu_cc_pll0.clkr, + [GPU_CC_PLL1] = NULL, +}; + +static struct clk_regmap *gpu_cc_gfx_sdm845_clocks[] = { + [GPU_CC_PLL0_OUT_EVEN] = &gpu_cc_pll0_out_even.clkr, + [GPU_CC_GX_GFX3D_CLK_SRC] = &gpu_cc_gx_gfx3d_clk_src.clkr, + [GPU_CC_GX_GFX3D_CLK] = &gpu_cc_gx_gfx3d_clk.clkr, +}; + +static const struct qcom_reset_map gpu_cc_sdm845_resets[] = { + [GPUCC_GPU_CC_ACD_BCR] = { 0x1160 }, + [GPUCC_GPU_CC_CX_BCR] = { 0x1068 }, + [GPUCC_GPU_CC_GFX3D_AON_BCR] = { 0x10a0 }, + [GPUCC_GPU_CC_GMU_BCR] = { 0x111c }, + [GPUCC_GPU_CC_GX_BCR] = { 0x1008 }, + [GPUCC_GPU_CC_SPDM_BCR] = { 0x1110 }, + [GPUCC_GPU_CC_XO_BCR] = { 0x1000 }, +}; + +static const struct regmap_config gpu_cc_sdm845_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x8008, + .fast_io = true, +}; + +static const struct qcom_cc_desc gpu_cc_sdm845_desc = { + .config = &gpu_cc_sdm845_regmap_config, + .clks = gpu_cc_sdm845_clocks, + .num_clks = ARRAY_SIZE(gpu_cc_sdm845_clocks), + .resets = gpu_cc_sdm845_resets, + .num_resets = ARRAY_SIZE(gpu_cc_sdm845_resets), +}; + +static const struct qcom_cc_desc gpu_cc_gfx_sdm845_desc = { + .config = &gpu_cc_sdm845_regmap_config, + .clks = gpu_cc_gfx_sdm845_clocks, + .num_clks = ARRAY_SIZE(gpu_cc_gfx_sdm845_clocks), +}; + +static const struct of_device_id gpu_cc_sdm845_match_table[] = { + { .compatible = "qcom,gpucc-sdm845" }, + { .compatible = "qcom,gpucc-sdm845-v2" }, + { .compatible = "qcom,gpucc-sdm670" }, + { } +}; +MODULE_DEVICE_TABLE(of, gpu_cc_sdm845_match_table); + +static const struct of_device_id gpu_cc_gfx_sdm845_match_table[] = { + { .compatible = "qcom,gfxcc-sdm845" }, + { .compatible = "qcom,gfxcc-sdm845-v2" }, + { .compatible = "qcom,gfxcc-sdm670" }, + {}, +}; +MODULE_DEVICE_TABLE(of, gpu_cc_gfx_sdm845_match_table); + +static void gpu_cc_sdm845_fixup_sdm845v2(struct regmap *regmap) +{ + gpu_cc_sdm845_clocks[GPU_CC_PLL1] = &gpu_cc_pll1.clkr; + clk_fabia_pll_configure(&gpu_cc_pll1, regmap, &gpu_cc_pll1_config); + + gpu_cc_gmu_clk_src.freq_tbl = ftbl_gpu_cc_gmu_clk_src_sdm845_v2; + gpu_cc_gmu_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = 500000000; +} + +static void gpu_cc_sdm845_fixup_sdm670(struct regmap *regmap) +{ + gpu_cc_sdm845_clocks[GPU_CC_PLL1] = &gpu_cc_pll1.clkr; + clk_fabia_pll_configure(&gpu_cc_pll1, regmap, &gpu_cc_pll1_config); + + gpu_cc_gmu_clk_src.freq_tbl = ftbl_gpu_cc_gmu_clk_src_sdm670; + gpu_cc_gmu_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = 200000000; +} + +static void gpu_cc_gfx_sdm845_fixup_sdm845v2(void) +{ + gpu_cc_gx_gfx3d_clk_src.freq_tbl = + ftbl_gpu_cc_gx_gfx3d_clk_src_sdm845_v2; + gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_MIN] = 180000000; + gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_LOWER] = + 257000000; + gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_LOW] = 342000000; + gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_LOW_L1] = + 414000000; + gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_NOMINAL] = + 520000000; + gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_NOMINAL_L1] = + 596000000; + gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_HIGH] = 675000000; + gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_HIGH_L1] = + 710000000; +} + +static void gpu_cc_gfx_sdm845_fixup_sdm670(void) +{ + gpu_cc_gx_gfx3d_clk_src.freq_tbl = + ftbl_gpu_cc_gx_gfx3d_clk_src_sdm670; + gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_MIN] = 180000000; + gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_LOWER] = + 267000000; + gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_LOW] = 355000000; + gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_LOW_L1] = + 430000000; + gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_NOMINAL] = + 565000000; + gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_NOMINAL_L1] = + 650000000; + gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_HIGH] = 750000000; + gpu_cc_gx_gfx3d_clk_src.clkr.hw.init->rate_max[VDD_GX_HIGH_L1] = + 780000000; +} + +static int gpu_cc_gfx_sdm845_fixup(struct platform_device *pdev) +{ + const char *compat = NULL; + int compatlen = 0; + + compat = of_get_property(pdev->dev.of_node, "compatible", &compatlen); + if (!compat || (compatlen <= 0)) + return -EINVAL; + + if (!strcmp(compat, "qcom,gfxcc-sdm845-v2")) + gpu_cc_gfx_sdm845_fixup_sdm845v2(); + else if (!strcmp(compat, "qcom,gfxcc-sdm670")) + gpu_cc_gfx_sdm845_fixup_sdm670(); + + return 0; +} + +static int gpu_cc_sdm845_fixup(struct platform_device *pdev, + struct regmap *regmap) +{ + const char *compat = NULL; + int compatlen = 0; + + compat = of_get_property(pdev->dev.of_node, "compatible", &compatlen); + if (!compat || (compatlen <= 0)) + return -EINVAL; + + if (!strcmp(compat, "qcom,gpucc-sdm845-v2")) + gpu_cc_sdm845_fixup_sdm845v2(regmap); + else if (!strcmp(compat, "qcom,gpucc-sdm670")) + gpu_cc_sdm845_fixup_sdm670(regmap); + + return 0; +} + +static int gpu_cc_gfx_sdm845_probe(struct platform_device *pdev) +{ + struct regmap *regmap; + struct resource *res; + void __iomem *base; + int ret = 0; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) { + dev_err(&pdev->dev, "Failed to get resources for clock_gfxcc\n"); + return -EINVAL; + } + + base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); + if (IS_ERR(base)) { + dev_err(&pdev->dev, "Failed to ioremap the GFX CC base\n"); + return PTR_ERR(base); + } + + /* Register clock fixed factor for CRC divide. */ + ret = devm_clk_hw_register(&pdev->dev, &crc_div.hw); + if (ret) { + dev_err(&pdev->dev, "Failed to register hardware clock\n"); + return ret; + } + + regmap = devm_regmap_init_mmio(&pdev->dev, base, + gpu_cc_gfx_sdm845_desc.config); + if (IS_ERR(regmap)) { + dev_err(&pdev->dev, "Failed to init regmap\n"); + return PTR_ERR(regmap); + } + + /* GFX voltage regulators for GFX3D graphic clock. */ + vdd_gfx.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_gfx"); + if (IS_ERR(vdd_gfx.regulator[0])) { + if (PTR_ERR(vdd_gfx.regulator[0]) != -EPROBE_DEFER) + dev_err(&pdev->dev, "Unable to get vdd_gfx regulator\n"); + return PTR_ERR(vdd_gfx.regulator[0]); + } + + /* Avoid turning on the rail during clock registration */ + vdd_gfx.skip_handoff = true; + + ret = gpu_cc_gfx_sdm845_fixup(pdev); + if (ret) { + dev_err(&pdev->dev, "Failed to do GFX clock fixup\n"); + return ret; + } + + clk_fabia_pll_configure(&gpu_cc_pll0, regmap, &gpu_cc_pll0_config); + + ret = qcom_cc_really_probe(pdev, &gpu_cc_gfx_sdm845_desc, regmap); + if (ret) { + dev_err(&pdev->dev, "Failed to register GFX CC clocks\n"); + return ret; + } + + dev_info(&pdev->dev, "Registered GFX CC clocks\n"); + + return ret; +} + +static struct platform_driver gpu_cc_gfx_sdm845_driver = { + .probe = gpu_cc_gfx_sdm845_probe, + .driver = { + .name = "gfxcc-sdm845", + .of_match_table = gpu_cc_gfx_sdm845_match_table, + }, +}; + +static int __init gpu_cc_gfx_sdm845_init(void) +{ + return platform_driver_register(&gpu_cc_gfx_sdm845_driver); +} +subsys_initcall(gpu_cc_gfx_sdm845_init); + +static void __exit gpu_cc_gfx_sdm845_exit(void) +{ + platform_driver_unregister(&gpu_cc_gfx_sdm845_driver); +} +module_exit(gpu_cc_gfx_sdm845_exit); + +static int gpu_cc_sdm845_probe(struct platform_device *pdev) +{ + struct regmap *regmap; + int ret = 0; + unsigned int value, mask; + + regmap = qcom_cc_map(pdev, &gpu_cc_sdm845_desc); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + /* Get CX voltage regulator for CX and GMU clocks. */ + vdd_cx.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_cx"); + if (IS_ERR(vdd_cx.regulator[0])) { + if (!(PTR_ERR(vdd_cx.regulator[0]) == -EPROBE_DEFER)) + dev_err(&pdev->dev, + "Unable to get vdd_cx regulator\n"); + return PTR_ERR(vdd_cx.regulator[0]); + } + + /* Get MX voltage regulator for GPU PLL graphic clock. */ + vdd_mx.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_mx"); + if (IS_ERR(vdd_mx.regulator[0])) { + if (!(PTR_ERR(vdd_mx.regulator[0]) == -EPROBE_DEFER)) + dev_err(&pdev->dev, + "Unable to get vdd_mx regulator\n"); + return PTR_ERR(vdd_mx.regulator[0]); + } + + ret = gpu_cc_sdm845_fixup(pdev, regmap); + if (ret) { + dev_err(&pdev->dev, "Failed to do GPU CC clock fixup\n"); + return ret; + } + + ret = qcom_cc_really_probe(pdev, &gpu_cc_sdm845_desc, regmap); + if (ret) { + dev_err(&pdev->dev, "Failed to register GPU CC clocks\n"); + return ret; + } + + mask = CX_GMU_CBCR_WAKE_MASK << CX_GMU_CBCR_WAKE_SHIFT; + mask |= CX_GMU_CBCR_SLEEP_MASK << CX_GMU_CBCR_SLEEP_SHIFT; + value = 0xF << CX_GMU_CBCR_WAKE_SHIFT | 0xF << CX_GMU_CBCR_SLEEP_SHIFT; + regmap_update_bits(regmap, gpu_cc_cx_gmu_clk.clkr.enable_reg, + mask, value); + + dev_info(&pdev->dev, "Registered GPU CC clocks\n"); + + return ret; +} + +static struct platform_driver gpu_cc_sdm845_driver = { + .probe = gpu_cc_sdm845_probe, + .driver = { + .name = "gpu_cc-sdm845", + .of_match_table = gpu_cc_sdm845_match_table, + }, +}; + +static int __init gpu_cc_sdm845_init(void) +{ + return platform_driver_register(&gpu_cc_sdm845_driver); +} +subsys_initcall(gpu_cc_sdm845_init); + +static void __exit gpu_cc_sdm845_exit(void) +{ + platform_driver_unregister(&gpu_cc_sdm845_driver); +} +module_exit(gpu_cc_sdm845_exit); + +MODULE_DESCRIPTION("QTI GPU_CC SDM845 Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:gpu_cc-sdm845"); diff --git a/drivers/clk/qcom/vdd-level-sdm845.h b/drivers/clk/qcom/vdd-level-sdm845.h new file mode 100644 index 000000000000..b710b00bc0c7 --- /dev/null +++ b/drivers/clk/qcom/vdd-level-sdm845.h @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. + */ + +#ifndef __DRIVERS_CLK_QCOM_VDD_LEVEL_COBALT_H +#define __DRIVERS_CLK_QCOM_VDD_LEVEL_COBALT_H + +#include +#include + +#define VDD_CX_FMAX_MAP1(l1, f1) \ + .vdd_class = &vdd_cx, \ + .rate_max = (unsigned long[VDD_CX_NUM]) { \ + [VDD_CX_##l1] = (f1), \ + }, \ + .num_rate_max = VDD_CX_NUM + +#define VDD_CX_FMAX_MAP2(l1, f1, l2, f2) \ + .vdd_class = &vdd_cx, \ + .rate_max = (unsigned long[VDD_CX_NUM]) { \ + [VDD_CX_##l1] = (f1), \ + [VDD_CX_##l2] = (f2), \ + }, \ + .num_rate_max = VDD_CX_NUM + +#define VDD_CX_FMAX_MAP3(l1, f1, l2, f2, l3, f3) \ + .vdd_class = &vdd_cx, \ + .rate_max = (unsigned long[VDD_CX_NUM]) { \ + [VDD_CX_##l1] = (f1), \ + [VDD_CX_##l2] = (f2), \ + [VDD_CX_##l3] = (f3), \ + }, \ + .num_rate_max = VDD_CX_NUM + +#define VDD_CX_FMAX_MAP4(l1, f1, l2, f2, l3, f3, l4, f4) \ + .vdd_class = &vdd_cx, \ + .rate_max = (unsigned long[VDD_CX_NUM]) { \ + [VDD_CX_##l1] = (f1), \ + [VDD_CX_##l2] = (f2), \ + [VDD_CX_##l3] = (f3), \ + [VDD_CX_##l4] = (f4), \ + }, \ + .num_rate_max = VDD_CX_NUM + +#define VDD_CX_FMAX_MAP5(l1, f1, l2, f2, l3, f3, l4, f4, l5, f5) \ + .vdd_class = &vdd_cx, \ + .rate_max = (unsigned long[VDD_CX_NUM]) { \ + [VDD_CX_##l1] = (f1), \ + [VDD_CX_##l2] = (f2), \ + [VDD_CX_##l3] = (f3), \ + [VDD_CX_##l4] = (f4), \ + [VDD_CX_##l5] = (f5), \ + }, \ + .num_rate_max = VDD_CX_NUM + +#define VDD_CX_FMAX_MAP6(l1, f1, l2, f2, l3, f3, l4, f4, l5, f5, l6, f6) \ + .vdd_class = &vdd_cx, \ + .rate_max = (unsigned long[VDD_CX_NUM]) { \ + [VDD_CX_##l1] = (f1), \ + [VDD_CX_##l2] = (f2), \ + [VDD_CX_##l3] = (f3), \ + [VDD_CX_##l4] = (f4), \ + [VDD_CX_##l5] = (f5), \ + [VDD_CX_##l6] = (f6), \ + }, \ + .num_rate_max = VDD_CX_NUM + +#define VDD_CX_FMAX_MAP1_AO(l1, f1) \ + .vdd_class = &vdd_cx_ao, \ + .rate_max = (unsigned long[VDD_CX_NUM]) { \ + [VDD_CX_##l1] = (f1), \ + }, \ + .num_rate_max = VDD_CX_NUM + +#define VDD_CX_FMAX_MAP3_AO(l1, f1, l2, f2, l3, f3) \ + .vdd_class = &vdd_cx_ao, \ + .rate_max = (unsigned long[VDD_CX_NUM]) { \ + [VDD_CX_##l1] = (f1), \ + [VDD_CX_##l2] = (f2), \ + [VDD_CX_##l3] = (f3), \ + }, \ + .num_rate_max = VDD_CX_NUM + +#define VDD_MX_FMAX_MAP4(l1, f1, l2, f2, l3, f3, l4, f4) \ + .vdd_class = &vdd_mx, \ + .rate_max = (unsigned long[VDD_CX_NUM]) { \ + [VDD_CX_##l1] = (f1), \ + [VDD_CX_##l2] = (f2), \ + [VDD_CX_##l3] = (f3), \ + [VDD_CX_##l4] = (f4), \ + }, \ + .num_rate_max = VDD_CX_NUM + +#define VDD_GX_FMAX_MAP8(l1, f1, l2, f2, l3, f3, l4, f4, l5, f5, l6, f6, \ + l7, f7, l8, f8) \ + .vdd_class = &vdd_gfx, \ + .rate_max = (unsigned long[VDD_GX_NUM]) { \ + [VDD_GX_##l1] = (f1), \ + [VDD_GX_##l2] = (f2), \ + [VDD_GX_##l3] = (f3), \ + [VDD_GX_##l4] = (f4), \ + [VDD_GX_##l5] = (f5), \ + [VDD_GX_##l6] = (f6), \ + [VDD_GX_##l7] = (f7), \ + [VDD_GX_##l8] = (f8), \ + }, \ + .num_rate_max = VDD_GX_NUM + +enum vdd_cx_levels { + VDD_CX_NONE, + VDD_CX_MIN, /* MIN SVS */ + VDD_CX_LOWER, /* SVS2 */ + VDD_CX_LOW, /* SVS */ + VDD_CX_LOW_L1, /* SVSL1 */ + VDD_CX_NOMINAL, /* NOM */ + VDD_CX_HIGH, /* TURBO */ + VDD_CX_NUM, +}; + +enum vdd_gx_levels { + VDD_GX_NONE, + VDD_GX_MIN, /* MIN SVS */ + VDD_GX_LOWER, /* SVS2 */ + VDD_GX_LOW, /* SVS */ + VDD_GX_LOW_L1, /* SVSL1 */ + VDD_GX_NOMINAL, /* NOM */ + VDD_GX_NOMINAL_L1, /* NOM1 */ + VDD_GX_HIGH, /* TURBO */ + VDD_GX_HIGH_L1, /* TURBO1 */ + VDD_GX_NUM, +}; + +/* Need to use the correct VI/VL mappings */ +static int vdd_corner[] = { + RPMH_REGULATOR_LEVEL_OFF, /* VDD_CX_NONE */ + RPMH_REGULATOR_LEVEL_MIN_SVS, /* VDD_CX_MIN */ + RPMH_REGULATOR_LEVEL_LOW_SVS, /* VDD_CX_LOWER */ + RPMH_REGULATOR_LEVEL_SVS, /* VDD_CX_LOW */ + RPMH_REGULATOR_LEVEL_SVS_L1, /* VDD_CX_LOW_L1 */ + RPMH_REGULATOR_LEVEL_NOM, /* VDD_CX_NOMINAL */ + RPMH_REGULATOR_LEVEL_TURBO, /* VDD_CX_HIGH */ +}; + +#endif diff --git a/drivers/clk/qcom/videocc-sdm845.c b/drivers/clk/qcom/videocc-sdm845.c index 5d6a7724a194..a140af23b2f6 100644 --- a/drivers/clk/qcom/videocc-sdm845.c +++ b/drivers/clk/qcom/videocc-sdm845.c @@ -1,22 +1,36 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. */ -#include -#include +#define pr_fmt(fmt) "clk: %s: " fmt, __func__ + +#include +#include +#include #include +#include +#include +#include +#include +#include #include +#include #include #include "common.h" -#include "clk-alpha-pll.h" -#include "clk-branch.h" -#include "clk-rcg.h" #include "clk-regmap.h" #include "clk-pll.h" -#include "gdsc.h" +#include "clk-rcg.h" +#include "clk-branch.h" +#include "reset.h" +#include "clk-alpha-pll.h" +#include "vdd-level-sdm845.h" + +#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } + +static DEFINE_VDD_REGULATORS(vdd_cx, VDD_CX_NUM, 1, vdd_corner); enum { P_BI_TCXO, @@ -42,25 +56,47 @@ static const char * const video_cc_parent_names_0[] = { "core_bi_pll_test_se", }; -static const struct alpha_pll_config video_pll0_config = { +static struct pll_vco fabia_vco[] = { + { 249600000, 2000000000, 0 }, + { 125000000, 1000000000, 1 }, +}; + +static const struct pll_config video_pll0_config = { .l = 0x10, - .alpha = 0xaaab, + .frac = 0xaaab, }; static struct clk_alpha_pll video_pll0 = { .offset = 0x42c, - .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], + .vco_table = fabia_vco, + .num_vco = ARRAY_SIZE(fabia_vco), + .type = FABIA_PLL, .clkr = { .hw.init = &(struct clk_init_data){ .name = "video_pll0", .parent_names = (const char *[]){ "bi_tcxo" }, .num_parents = 1, - .ops = &clk_alpha_pll_fabia_ops, + .ops = &clk_fabia_pll_ops, + VDD_CX_FMAX_MAP4( + MIN, 615000000, + LOW, 1066000000, + LOW_L1, 1600000000, + NOMINAL, 2000000000), }, }, }; static const struct freq_tbl ftbl_video_cc_venus_clk_src[] = { + F(100000000, P_VIDEO_PLL0_OUT_MAIN, 4, 0, 0), + F(200000000, P_VIDEO_PLL0_OUT_MAIN, 2, 0, 0), + F(320000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0), + F(380000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0), + F(444000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0), + F(533000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0), + { } +}; + +static const struct freq_tbl ftbl_video_cc_venus_clk_src_sdm845_v2[] = { F(100000000, P_VIDEO_PLL0_OUT_MAIN, 4, 0, 0), F(200000000, P_VIDEO_PLL0_OUT_MAIN, 2, 0, 0), F(330000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0), @@ -70,18 +106,37 @@ static const struct freq_tbl ftbl_video_cc_venus_clk_src[] = { { } }; +static const struct freq_tbl ftbl_video_cc_venus_clk_src_sdm670[] = { + F(100000000, P_VIDEO_PLL0_OUT_MAIN, 4, 0, 0), + F(200000000, P_VIDEO_PLL0_OUT_MAIN, 2, 0, 0), + F(330000000, P_VIDEO_PLL0_OUT_MAIN, 2, 0, 0), + F(364700000, P_VIDEO_PLL0_OUT_MAIN, 2, 0, 0), + F(404000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0), + F(444000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0), + F(533000000, P_VIDEO_PLL0_OUT_MAIN, 1, 0, 0), + { } +}; + static struct clk_rcg2 video_cc_venus_clk_src = { .cmd_rcgr = 0x7f0, .mnd_width = 0, .hid_width = 5, .parent_map = video_cc_parent_map_0, .freq_tbl = ftbl_video_cc_venus_clk_src, + .enable_safe_config = true, .clkr.hw.init = &(struct clk_init_data){ .name = "video_cc_venus_clk_src", .parent_names = video_cc_parent_names_0, .num_parents = 5, .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_shared_ops, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP6( + MIN, 100000000, + LOWER, 200000000, + LOW, 320000000, + LOW_L1, 380000000, + NOMINAL, 444000000, + HIGH, 533000000), }, }; @@ -243,39 +298,6 @@ static struct clk_branch video_cc_venus_ctl_core_clk = { }, }; -static struct gdsc venus_gdsc = { - .gdscr = 0x814, - .pd = { - .name = "venus_gdsc", - }, - .cxcs = (unsigned int []){ 0x850, 0x910 }, - .cxc_count = 2, - .pwrsts = PWRSTS_OFF_ON, - .flags = POLL_CFG_GDSCR, -}; - -static struct gdsc vcodec0_gdsc = { - .gdscr = 0x874, - .pd = { - .name = "vcodec0_gdsc", - }, - .cxcs = (unsigned int []){ 0x890, 0x930 }, - .cxc_count = 2, - .flags = HW_CTRL | POLL_CFG_GDSCR, - .pwrsts = PWRSTS_OFF_ON, -}; - -static struct gdsc vcodec1_gdsc = { - .gdscr = 0x8b4, - .pd = { - .name = "vcodec1_gdsc", - }, - .cxcs = (unsigned int []){ 0x8d0, 0x950 }, - .cxc_count = 2, - .flags = HW_CTRL | POLL_CFG_GDSCR, - .pwrsts = PWRSTS_OFF_ON, -}; - static struct clk_regmap *video_cc_sdm845_clocks[] = { [VIDEO_CC_APB_CLK] = &video_cc_apb_clk.clkr, [VIDEO_CC_AT_CLK] = &video_cc_at_clk.clkr, @@ -292,12 +314,6 @@ static struct clk_regmap *video_cc_sdm845_clocks[] = { [VIDEO_PLL0] = &video_pll0.clkr, }; -static struct gdsc *video_cc_sdm845_gdscs[] = { - [VENUS_GDSC] = &venus_gdsc, - [VCODEC0_GDSC] = &vcodec0_gdsc, - [VCODEC1_GDSC] = &vcodec1_gdsc, -}; - static const struct regmap_config video_cc_sdm845_regmap_config = { .reg_bits = 32, .reg_stride = 4, @@ -310,33 +326,88 @@ static const struct qcom_cc_desc video_cc_sdm845_desc = { .config = &video_cc_sdm845_regmap_config, .clks = video_cc_sdm845_clocks, .num_clks = ARRAY_SIZE(video_cc_sdm845_clocks), - .gdscs = video_cc_sdm845_gdscs, - .num_gdscs = ARRAY_SIZE(video_cc_sdm845_gdscs), }; static const struct of_device_id video_cc_sdm845_match_table[] = { - { .compatible = "qcom,sdm845-videocc" }, + { .compatible = "qcom,video_cc-sdm845" }, + { .compatible = "qcom,video_cc-sdm845-v2" }, + { .compatible = "qcom,video_cc-sdm670" }, { } }; MODULE_DEVICE_TABLE(of, video_cc_sdm845_match_table); +static void video_cc_sdm845_fixup_sdm845v2(void) +{ + video_cc_venus_clk_src.freq_tbl = ftbl_video_cc_venus_clk_src_sdm845_v2; + video_cc_venus_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = 330000000; + video_cc_venus_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW_L1] = + 404000000; +} + +static void video_cc_sdm845_fixup_sdm670(void) +{ + video_cc_venus_clk_src.freq_tbl = ftbl_video_cc_venus_clk_src_sdm670; + video_cc_venus_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW] = 330000000; + video_cc_venus_clk_src.clkr.hw.init->rate_max[VDD_CX_LOW_L1] = + 404000000; +} + +static int video_cc_sdm845_fixup(struct platform_device *pdev) +{ + const char *compat = NULL; + int compatlen = 0; + + compat = of_get_property(pdev->dev.of_node, "compatible", &compatlen); + if (!compat || (compatlen <= 0)) + return -EINVAL; + + if (!strcmp(compat, "qcom,video_cc-sdm845-v2")) + video_cc_sdm845_fixup_sdm845v2(); + else if (!strcmp(compat, "qcom,video_cc-sdm670")) + video_cc_sdm845_fixup_sdm670(); + + return 0; +} + static int video_cc_sdm845_probe(struct platform_device *pdev) { struct regmap *regmap; + int ret = 0; regmap = qcom_cc_map(pdev, &video_cc_sdm845_desc); - if (IS_ERR(regmap)) + if (IS_ERR(regmap)) { + pr_err("Failed to map the Video CC registers\n"); return PTR_ERR(regmap); + } + + vdd_cx.regulator[0] = devm_regulator_get(&pdev->dev, "vdd_cx"); + if (IS_ERR(vdd_cx.regulator[0])) { + if (!(PTR_ERR(vdd_cx.regulator[0]) == -EPROBE_DEFER)) + dev_err(&pdev->dev, + "Unable to get vdd_cx regulator\n"); + return PTR_ERR(vdd_cx.regulator[0]); + } + + ret = video_cc_sdm845_fixup(pdev); + if (ret) + return ret; clk_fabia_pll_configure(&video_pll0, regmap, &video_pll0_config); - return qcom_cc_really_probe(pdev, &video_cc_sdm845_desc, regmap); + ret = qcom_cc_really_probe(pdev, &video_cc_sdm845_desc, regmap); + if (ret) { + dev_err(&pdev->dev, "Failed to register Video CC clocks\n"); + return ret; + } + + dev_info(&pdev->dev, "Registered Video CC clocks\n"); + return ret; } static struct platform_driver video_cc_sdm845_driver = { .probe = video_cc_sdm845_probe, .driver = { - .name = "sdm845-videocc", + .name = "video_cc-sdm845", .of_match_table = video_cc_sdm845_match_table, }, }; @@ -353,4 +424,6 @@ static void __exit video_cc_sdm845_exit(void) } module_exit(video_cc_sdm845_exit); +MODULE_DESCRIPTION("QCOM VIDEO_CC SDM845 Driver"); MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:video_cc-sdm845"); diff --git a/include/dt-bindings/clock/qcom,camcc-sdm845.h b/include/dt-bindings/clock/qcom,camcc-sdm845.h new file mode 100644 index 000000000000..35850ef51fda --- /dev/null +++ b/include/dt-bindings/clock/qcom,camcc-sdm845.h @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. + */ + +#ifndef _DT_BINDINGS_CLK_MSM_CAM_CC_SDM845_H +#define _DT_BINDINGS_CLK_MSM_CAM_CC_SDM845_H + +#define CAM_CC_BPS_AHB_CLK 0 +#define CAM_CC_BPS_AREG_CLK 1 +#define CAM_CC_BPS_AXI_CLK 2 +#define CAM_CC_BPS_CLK 3 +#define CAM_CC_BPS_CLK_SRC 4 +#define CAM_CC_CAMNOC_ATB_CLK 5 +#define CAM_CC_CAMNOC_AXI_CLK 6 +#define CAM_CC_CCI_CLK 7 +#define CAM_CC_CCI_CLK_SRC 8 +#define CAM_CC_CPAS_AHB_CLK 9 +#define CAM_CC_CPHY_RX_CLK_SRC 10 +#define CAM_CC_CSI0PHYTIMER_CLK 11 +#define CAM_CC_CSI0PHYTIMER_CLK_SRC 12 +#define CAM_CC_CSI1PHYTIMER_CLK 13 +#define CAM_CC_CSI1PHYTIMER_CLK_SRC 14 +#define CAM_CC_CSI2PHYTIMER_CLK 15 +#define CAM_CC_CSI2PHYTIMER_CLK_SRC 16 +#define CAM_CC_CSI3PHYTIMER_CLK 17 +#define CAM_CC_CSI3PHYTIMER_CLK_SRC 18 +#define CAM_CC_CSIPHY0_CLK 19 +#define CAM_CC_CSIPHY1_CLK 20 +#define CAM_CC_CSIPHY2_CLK 21 +#define CAM_CC_CSIPHY3_CLK 22 +#define CAM_CC_FAST_AHB_CLK_SRC 23 +#define CAM_CC_FD_CORE_CLK 24 +#define CAM_CC_FD_CORE_CLK_SRC 25 +#define CAM_CC_FD_CORE_UAR_CLK 26 +#define CAM_CC_ICP_APB_CLK 27 +#define CAM_CC_ICP_ATB_CLK 28 +#define CAM_CC_ICP_CLK 29 +#define CAM_CC_ICP_CLK_SRC 30 +#define CAM_CC_ICP_CTI_CLK 31 +#define CAM_CC_ICP_TS_CLK 32 +#define CAM_CC_IFE_0_AXI_CLK 33 +#define CAM_CC_IFE_0_CLK 34 +#define CAM_CC_IFE_0_CLK_SRC 35 +#define CAM_CC_IFE_0_CPHY_RX_CLK 36 +#define CAM_CC_IFE_0_CSID_CLK 37 +#define CAM_CC_IFE_0_CSID_CLK_SRC 38 +#define CAM_CC_IFE_0_DSP_CLK 39 +#define CAM_CC_IFE_1_AXI_CLK 40 +#define CAM_CC_IFE_1_CLK 41 +#define CAM_CC_IFE_1_CLK_SRC 42 +#define CAM_CC_IFE_1_CPHY_RX_CLK 43 +#define CAM_CC_IFE_1_CSID_CLK 44 +#define CAM_CC_IFE_1_CSID_CLK_SRC 45 +#define CAM_CC_IFE_1_DSP_CLK 46 +#define CAM_CC_IFE_LITE_CLK 47 +#define CAM_CC_IFE_LITE_CLK_SRC 48 +#define CAM_CC_IFE_LITE_CPHY_RX_CLK 49 +#define CAM_CC_IFE_LITE_CSID_CLK 50 +#define CAM_CC_IFE_LITE_CSID_CLK_SRC 51 +#define CAM_CC_IPE_0_AHB_CLK 52 +#define CAM_CC_IPE_0_AREG_CLK 53 +#define CAM_CC_IPE_0_AXI_CLK 54 +#define CAM_CC_IPE_0_CLK 55 +#define CAM_CC_IPE_0_CLK_SRC 56 +#define CAM_CC_IPE_1_AHB_CLK 57 +#define CAM_CC_IPE_1_AREG_CLK 58 +#define CAM_CC_IPE_1_AXI_CLK 59 +#define CAM_CC_IPE_1_CLK 60 +#define CAM_CC_IPE_1_CLK_SRC 61 +#define CAM_CC_JPEG_CLK 62 +#define CAM_CC_JPEG_CLK_SRC 63 +#define CAM_CC_LRME_CLK 64 +#define CAM_CC_LRME_CLK_SRC 65 +#define CAM_CC_MCLK0_CLK 66 +#define CAM_CC_MCLK0_CLK_SRC 67 +#define CAM_CC_MCLK1_CLK 68 +#define CAM_CC_MCLK1_CLK_SRC 69 +#define CAM_CC_MCLK2_CLK 70 +#define CAM_CC_MCLK2_CLK_SRC 71 +#define CAM_CC_MCLK3_CLK 72 +#define CAM_CC_MCLK3_CLK_SRC 73 +#define CAM_CC_PLL0 74 +#define CAM_CC_PLL0_OUT_EVEN 75 +#define CAM_CC_PLL1 76 +#define CAM_CC_PLL1_OUT_EVEN 77 +#define CAM_CC_PLL2 78 +#define CAM_CC_PLL2_OUT_EVEN 79 +#define CAM_CC_PLL2_OUT_ODD 80 +#define CAM_CC_PLL3 81 +#define CAM_CC_PLL3_OUT_EVEN 82 +#define CAM_CC_PLL_TEST_CLK 83 +#define CAM_CC_SLOW_AHB_CLK_SRC 84 +#define CAM_CC_SOC_AHB_CLK 85 +#define CAM_CC_SYS_TMR_CLK 86 + +#define TITAN_CAM_CC_CCI_BCR 0 +#define TITAN_CAM_CC_CPAS_BCR 1 +#define TITAN_CAM_CC_CSI0PHY_BCR 2 +#define TITAN_CAM_CC_CSI1PHY_BCR 3 +#define TITAN_CAM_CC_CSI2PHY_BCR 4 +#define TITAN_CAM_CC_MCLK0_BCR 5 +#define TITAN_CAM_CC_MCLK1_BCR 6 +#define TITAN_CAM_CC_MCLK2_BCR 7 +#define TITAN_CAM_CC_MCLK3_BCR 8 +#define TITAN_CAM_CC_TITAN_TOP_BCR 9 + +#endif diff --git a/include/dt-bindings/clock/qcom,dispcc-sdm845.h b/include/dt-bindings/clock/qcom,dispcc-sdm845.h index 11eed4bc9646..18db9ba5d022 100644 --- a/include/dt-bindings/clock/qcom,dispcc-sdm845.h +++ b/include/dt-bindings/clock/qcom,dispcc-sdm845.h @@ -1,12 +1,11 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +// SPDX-License-Identifier: GPL-2.0 /* - * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. */ -#ifndef _DT_BINDINGS_CLK_SDM_DISP_CC_SDM845_H -#define _DT_BINDINGS_CLK_SDM_DISP_CC_SDM845_H +#ifndef _DT_BINDINGS_CLK_MSM_DISP_CC_SDM845_H +#define _DT_BINDINGS_CLK_MSM_DISP_CC_SDM845_H -/* DISP_CC clock registers */ #define DISP_CC_MDSS_AHB_CLK 0 #define DISP_CC_MDSS_AXI_CLK 1 #define DISP_CC_MDSS_BYTE0_CLK 2 @@ -15,31 +14,40 @@ #define DISP_CC_MDSS_BYTE1_CLK 5 #define DISP_CC_MDSS_BYTE1_CLK_SRC 6 #define DISP_CC_MDSS_BYTE1_INTF_CLK 7 -#define DISP_CC_MDSS_ESC0_CLK 8 -#define DISP_CC_MDSS_ESC0_CLK_SRC 9 -#define DISP_CC_MDSS_ESC1_CLK 10 -#define DISP_CC_MDSS_ESC1_CLK_SRC 11 -#define DISP_CC_MDSS_MDP_CLK 12 -#define DISP_CC_MDSS_MDP_CLK_SRC 13 -#define DISP_CC_MDSS_MDP_LUT_CLK 14 -#define DISP_CC_MDSS_PCLK0_CLK 15 -#define DISP_CC_MDSS_PCLK0_CLK_SRC 16 -#define DISP_CC_MDSS_PCLK1_CLK 17 -#define DISP_CC_MDSS_PCLK1_CLK_SRC 18 -#define DISP_CC_MDSS_ROT_CLK 19 -#define DISP_CC_MDSS_ROT_CLK_SRC 20 -#define DISP_CC_MDSS_RSCC_AHB_CLK 21 -#define DISP_CC_MDSS_RSCC_VSYNC_CLK 22 -#define DISP_CC_MDSS_VSYNC_CLK 23 -#define DISP_CC_MDSS_VSYNC_CLK_SRC 24 -#define DISP_CC_PLL0 25 -#define DISP_CC_MDSS_BYTE0_DIV_CLK_SRC 26 -#define DISP_CC_MDSS_BYTE1_DIV_CLK_SRC 27 +#define DISP_CC_MDSS_DP_AUX_CLK 8 +#define DISP_CC_MDSS_DP_AUX_CLK_SRC 9 +#define DISP_CC_MDSS_DP_CRYPTO_CLK 10 +#define DISP_CC_MDSS_DP_CRYPTO_CLK_SRC 11 +#define DISP_CC_MDSS_DP_LINK_CLK 12 +#define DISP_CC_MDSS_DP_LINK_CLK_SRC 13 +#define DISP_CC_MDSS_DP_LINK_INTF_CLK 14 +#define DISP_CC_MDSS_DP_PIXEL1_CLK 15 +#define DISP_CC_MDSS_DP_PIXEL1_CLK_SRC 16 +#define DISP_CC_MDSS_DP_PIXEL_CLK 17 +#define DISP_CC_MDSS_DP_PIXEL_CLK_SRC 18 +#define DISP_CC_MDSS_ESC0_CLK 19 +#define DISP_CC_MDSS_ESC0_CLK_SRC 20 +#define DISP_CC_MDSS_ESC1_CLK 21 +#define DISP_CC_MDSS_ESC1_CLK_SRC 22 +#define DISP_CC_MDSS_MDP_CLK 23 +#define DISP_CC_MDSS_MDP_CLK_SRC 24 +#define DISP_CC_MDSS_MDP_LUT_CLK 25 +#define DISP_CC_MDSS_PCLK0_CLK 26 +#define DISP_CC_MDSS_PCLK0_CLK_SRC 27 +#define DISP_CC_MDSS_PCLK1_CLK 28 +#define DISP_CC_MDSS_PCLK1_CLK_SRC 29 +#define DISP_CC_MDSS_QDSS_AT_CLK 30 +#define DISP_CC_MDSS_QDSS_TSCTR_DIV8_CLK 31 +#define DISP_CC_MDSS_ROT_CLK 32 +#define DISP_CC_MDSS_ROT_CLK_SRC 33 +#define DISP_CC_MDSS_RSCC_AHB_CLK 34 +#define DISP_CC_MDSS_RSCC_VSYNC_CLK 35 +#define DISP_CC_MDSS_VSYNC_CLK 36 +#define DISP_CC_MDSS_VSYNC_CLK_SRC 37 +#define DISP_CC_PLL0 38 +#define DISP_CC_MDSS_BYTE0_DIV_CLK_SRC 39 +#define DISP_CC_MDSS_BYTE1_DIV_CLK_SRC 40 -/* DISP_CC Reset */ #define DISP_CC_MDSS_RSCC_BCR 0 -/* DISP_CC GDSCR */ -#define MDSS_GDSC 0 - -#endif +#endif \ No newline at end of file diff --git a/include/dt-bindings/clock/qcom,gcc-sdm845.h b/include/dt-bindings/clock/qcom,gcc-sdm845.h index f96fc2dbf60e..711176bfc2e9 100644 --- a/include/dt-bindings/clock/qcom,gcc-sdm845.h +++ b/include/dt-bindings/clock/qcom,gcc-sdm845.h @@ -1,201 +1,220 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +// SPDX-License-Identifier: GPL-2.0 /* - * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. */ -#ifndef _DT_BINDINGS_CLK_SDM_GCC_SDM845_H -#define _DT_BINDINGS_CLK_SDM_GCC_SDM845_H +#ifndef _DT_BINDINGS_CLK_MSM_GCC_SDM845_H +#define _DT_BINDINGS_CLK_MSM_GCC_SDM845_H + +/* Dummy clocks for rate measurement */ +#define MEASURE_ONLY_SNOC_CLK 0 +#define MEASURE_ONLY_CNOC_CLK 1 +#define MEASURE_ONLY_BIMC_CLK 2 +#define MEASURE_ONLY_IPA_2X_CLK 3 +#define UFS_PHY_AXI_EMMC_VOTE_CLK 4 +#define UFS_PHY_AXI_UFS_VOTE_CLK 5 /* GCC clock registers */ -#define GCC_AGGRE_NOC_PCIE_TBU_CLK 0 -#define GCC_AGGRE_UFS_CARD_AXI_CLK 1 -#define GCC_AGGRE_UFS_PHY_AXI_CLK 2 -#define GCC_AGGRE_USB3_PRIM_AXI_CLK 3 -#define GCC_AGGRE_USB3_SEC_AXI_CLK 4 -#define GCC_BOOT_ROM_AHB_CLK 5 -#define GCC_CAMERA_AHB_CLK 6 -#define GCC_CAMERA_AXI_CLK 7 -#define GCC_CAMERA_XO_CLK 8 -#define GCC_CE1_AHB_CLK 9 -#define GCC_CE1_AXI_CLK 10 -#define GCC_CE1_CLK 11 -#define GCC_CFG_NOC_USB3_PRIM_AXI_CLK 12 -#define GCC_CFG_NOC_USB3_SEC_AXI_CLK 13 -#define GCC_CPUSS_AHB_CLK 14 -#define GCC_CPUSS_AHB_CLK_SRC 15 -#define GCC_CPUSS_RBCPR_CLK 16 -#define GCC_CPUSS_RBCPR_CLK_SRC 17 -#define GCC_DDRSS_GPU_AXI_CLK 18 -#define GCC_DISP_AHB_CLK 19 -#define GCC_DISP_AXI_CLK 20 -#define GCC_DISP_GPLL0_CLK_SRC 21 -#define GCC_DISP_GPLL0_DIV_CLK_SRC 22 -#define GCC_DISP_XO_CLK 23 -#define GCC_GP1_CLK 24 -#define GCC_GP1_CLK_SRC 25 -#define GCC_GP2_CLK 26 -#define GCC_GP2_CLK_SRC 27 -#define GCC_GP3_CLK 28 -#define GCC_GP3_CLK_SRC 29 -#define GCC_GPU_CFG_AHB_CLK 30 -#define GCC_GPU_GPLL0_CLK_SRC 31 -#define GCC_GPU_GPLL0_DIV_CLK_SRC 32 -#define GCC_GPU_MEMNOC_GFX_CLK 33 -#define GCC_GPU_SNOC_DVM_GFX_CLK 34 -#define GCC_MSS_AXIS2_CLK 35 -#define GCC_MSS_CFG_AHB_CLK 36 -#define GCC_MSS_GPLL0_DIV_CLK_SRC 37 -#define GCC_MSS_MFAB_AXIS_CLK 38 -#define GCC_MSS_Q6_MEMNOC_AXI_CLK 39 -#define GCC_MSS_SNOC_AXI_CLK 40 -#define GCC_PCIE_0_AUX_CLK 41 -#define GCC_PCIE_0_AUX_CLK_SRC 42 -#define GCC_PCIE_0_CFG_AHB_CLK 43 -#define GCC_PCIE_0_CLKREF_CLK 44 -#define GCC_PCIE_0_MSTR_AXI_CLK 45 -#define GCC_PCIE_0_PIPE_CLK 46 -#define GCC_PCIE_0_SLV_AXI_CLK 47 -#define GCC_PCIE_0_SLV_Q2A_AXI_CLK 48 -#define GCC_PCIE_1_AUX_CLK 49 -#define GCC_PCIE_1_AUX_CLK_SRC 50 -#define GCC_PCIE_1_CFG_AHB_CLK 51 -#define GCC_PCIE_1_CLKREF_CLK 52 -#define GCC_PCIE_1_MSTR_AXI_CLK 53 -#define GCC_PCIE_1_PIPE_CLK 54 -#define GCC_PCIE_1_SLV_AXI_CLK 55 -#define GCC_PCIE_1_SLV_Q2A_AXI_CLK 56 -#define GCC_PCIE_PHY_AUX_CLK 57 -#define GCC_PCIE_PHY_REFGEN_CLK 58 -#define GCC_PCIE_PHY_REFGEN_CLK_SRC 59 -#define GCC_PDM2_CLK 60 -#define GCC_PDM2_CLK_SRC 61 -#define GCC_PDM_AHB_CLK 62 -#define GCC_PDM_XO4_CLK 63 -#define GCC_PRNG_AHB_CLK 64 -#define GCC_QMIP_CAMERA_AHB_CLK 65 -#define GCC_QMIP_DISP_AHB_CLK 66 -#define GCC_QMIP_VIDEO_AHB_CLK 67 -#define GCC_QUPV3_WRAP0_S0_CLK 68 -#define GCC_QUPV3_WRAP0_S0_CLK_SRC 69 -#define GCC_QUPV3_WRAP0_S1_CLK 70 -#define GCC_QUPV3_WRAP0_S1_CLK_SRC 71 -#define GCC_QUPV3_WRAP0_S2_CLK 72 -#define GCC_QUPV3_WRAP0_S2_CLK_SRC 73 -#define GCC_QUPV3_WRAP0_S3_CLK 74 -#define GCC_QUPV3_WRAP0_S3_CLK_SRC 75 -#define GCC_QUPV3_WRAP0_S4_CLK 76 -#define GCC_QUPV3_WRAP0_S4_CLK_SRC 77 -#define GCC_QUPV3_WRAP0_S5_CLK 78 -#define GCC_QUPV3_WRAP0_S5_CLK_SRC 79 -#define GCC_QUPV3_WRAP0_S6_CLK 80 -#define GCC_QUPV3_WRAP0_S6_CLK_SRC 81 -#define GCC_QUPV3_WRAP0_S7_CLK 82 -#define GCC_QUPV3_WRAP0_S7_CLK_SRC 83 -#define GCC_QUPV3_WRAP1_S0_CLK 84 -#define GCC_QUPV3_WRAP1_S0_CLK_SRC 85 -#define GCC_QUPV3_WRAP1_S1_CLK 86 -#define GCC_QUPV3_WRAP1_S1_CLK_SRC 87 -#define GCC_QUPV3_WRAP1_S2_CLK 88 -#define GCC_QUPV3_WRAP1_S2_CLK_SRC 89 -#define GCC_QUPV3_WRAP1_S3_CLK 90 -#define GCC_QUPV3_WRAP1_S3_CLK_SRC 91 -#define GCC_QUPV3_WRAP1_S4_CLK 92 -#define GCC_QUPV3_WRAP1_S4_CLK_SRC 93 -#define GCC_QUPV3_WRAP1_S5_CLK 94 -#define GCC_QUPV3_WRAP1_S5_CLK_SRC 95 -#define GCC_QUPV3_WRAP1_S6_CLK 96 -#define GCC_QUPV3_WRAP1_S6_CLK_SRC 97 -#define GCC_QUPV3_WRAP1_S7_CLK 98 -#define GCC_QUPV3_WRAP1_S7_CLK_SRC 99 -#define GCC_QUPV3_WRAP_0_M_AHB_CLK 100 -#define GCC_QUPV3_WRAP_0_S_AHB_CLK 101 -#define GCC_QUPV3_WRAP_1_M_AHB_CLK 102 -#define GCC_QUPV3_WRAP_1_S_AHB_CLK 103 -#define GCC_SDCC2_AHB_CLK 104 -#define GCC_SDCC2_APPS_CLK 105 -#define GCC_SDCC2_APPS_CLK_SRC 106 -#define GCC_SDCC4_AHB_CLK 107 -#define GCC_SDCC4_APPS_CLK 108 -#define GCC_SDCC4_APPS_CLK_SRC 109 -#define GCC_SYS_NOC_CPUSS_AHB_CLK 110 -#define GCC_TSIF_AHB_CLK 111 -#define GCC_TSIF_INACTIVITY_TIMERS_CLK 112 -#define GCC_TSIF_REF_CLK 113 -#define GCC_TSIF_REF_CLK_SRC 114 -#define GCC_UFS_CARD_AHB_CLK 115 -#define GCC_UFS_CARD_AXI_CLK 116 -#define GCC_UFS_CARD_AXI_CLK_SRC 117 -#define GCC_UFS_CARD_CLKREF_CLK 118 -#define GCC_UFS_CARD_ICE_CORE_CLK 119 -#define GCC_UFS_CARD_ICE_CORE_CLK_SRC 120 -#define GCC_UFS_CARD_PHY_AUX_CLK 121 -#define GCC_UFS_CARD_PHY_AUX_CLK_SRC 122 -#define GCC_UFS_CARD_RX_SYMBOL_0_CLK 123 -#define GCC_UFS_CARD_RX_SYMBOL_1_CLK 124 -#define GCC_UFS_CARD_TX_SYMBOL_0_CLK 125 -#define GCC_UFS_CARD_UNIPRO_CORE_CLK 126 -#define GCC_UFS_CARD_UNIPRO_CORE_CLK_SRC 127 -#define GCC_UFS_MEM_CLKREF_CLK 128 -#define GCC_UFS_PHY_AHB_CLK 129 -#define GCC_UFS_PHY_AXI_CLK 130 -#define GCC_UFS_PHY_AXI_CLK_SRC 131 -#define GCC_UFS_PHY_ICE_CORE_CLK 132 -#define GCC_UFS_PHY_ICE_CORE_CLK_SRC 133 -#define GCC_UFS_PHY_PHY_AUX_CLK 134 -#define GCC_UFS_PHY_PHY_AUX_CLK_SRC 135 -#define GCC_UFS_PHY_RX_SYMBOL_0_CLK 136 -#define GCC_UFS_PHY_RX_SYMBOL_1_CLK 137 -#define GCC_UFS_PHY_TX_SYMBOL_0_CLK 138 -#define GCC_UFS_PHY_UNIPRO_CORE_CLK 139 -#define GCC_UFS_PHY_UNIPRO_CORE_CLK_SRC 140 -#define GCC_USB30_PRIM_MASTER_CLK 141 -#define GCC_USB30_PRIM_MASTER_CLK_SRC 142 -#define GCC_USB30_PRIM_MOCK_UTMI_CLK 143 -#define GCC_USB30_PRIM_MOCK_UTMI_CLK_SRC 144 -#define GCC_USB30_PRIM_SLEEP_CLK 145 -#define GCC_USB30_SEC_MASTER_CLK 146 -#define GCC_USB30_SEC_MASTER_CLK_SRC 147 -#define GCC_USB30_SEC_MOCK_UTMI_CLK 148 -#define GCC_USB30_SEC_MOCK_UTMI_CLK_SRC 149 -#define GCC_USB30_SEC_SLEEP_CLK 150 -#define GCC_USB3_PRIM_CLKREF_CLK 151 -#define GCC_USB3_PRIM_PHY_AUX_CLK 152 -#define GCC_USB3_PRIM_PHY_AUX_CLK_SRC 153 -#define GCC_USB3_PRIM_PHY_COM_AUX_CLK 154 -#define GCC_USB3_PRIM_PHY_PIPE_CLK 155 -#define GCC_USB3_SEC_CLKREF_CLK 156 -#define GCC_USB3_SEC_PHY_AUX_CLK 157 -#define GCC_USB3_SEC_PHY_AUX_CLK_SRC 158 -#define GCC_USB3_SEC_PHY_PIPE_CLK 159 -#define GCC_USB3_SEC_PHY_COM_AUX_CLK 160 -#define GCC_USB_PHY_CFG_AHB2PHY_CLK 161 -#define GCC_VIDEO_AHB_CLK 162 -#define GCC_VIDEO_AXI_CLK 163 -#define GCC_VIDEO_XO_CLK 164 -#define GPLL0 165 -#define GPLL0_OUT_EVEN 166 -#define GPLL0_OUT_MAIN 167 -#define GCC_GPU_IREF_CLK 168 -#define GCC_SDCC1_AHB_CLK 169 -#define GCC_SDCC1_APPS_CLK 170 -#define GCC_SDCC1_ICE_CORE_CLK 171 -#define GCC_SDCC1_APPS_CLK_SRC 172 -#define GCC_SDCC1_ICE_CORE_CLK_SRC 173 -#define GCC_APC_VS_CLK 174 -#define GCC_GPU_VS_CLK 175 -#define GCC_MSS_VS_CLK 176 -#define GCC_VDDA_VS_CLK 177 -#define GCC_VDDCX_VS_CLK 178 -#define GCC_VDDMX_VS_CLK 179 -#define GCC_VS_CTRL_AHB_CLK 180 -#define GCC_VS_CTRL_CLK 181 -#define GCC_VS_CTRL_CLK_SRC 182 -#define GCC_VSENSOR_CLK_SRC 183 -#define GPLL4 184 -#define GCC_CPUSS_DVM_BUS_CLK 185 -#define GCC_CPUSS_GNOC_CLK 186 +#define GCC_AGGRE_NOC_PCIE_TBU_CLK 6 +#define GCC_AGGRE_UFS_CARD_AXI_CLK 7 +#define GCC_AGGRE_UFS_PHY_AXI_CLK 8 +#define GCC_AGGRE_USB3_PRIM_AXI_CLK 9 +#define GCC_AGGRE_USB3_SEC_AXI_CLK 10 +#define GCC_BOOT_ROM_AHB_CLK 11 +#define GCC_CAMERA_AHB_CLK 12 +#define GCC_CAMERA_AXI_CLK 13 +#define GCC_CAMERA_XO_CLK 14 +#define GCC_CE1_AHB_CLK 15 +#define GCC_CE1_AXI_CLK 16 +#define GCC_CE1_CLK 17 +#define GCC_CFG_NOC_USB3_PRIM_AXI_CLK 18 +#define GCC_CFG_NOC_USB3_SEC_AXI_CLK 19 +#define GCC_CPUSS_AHB_CLK 20 +#define GCC_CPUSS_AHB_CLK_SRC 21 +#define GCC_CPUSS_DVM_BUS_CLK 22 +#define GCC_CPUSS_GNOC_CLK 23 +#define GCC_CPUSS_RBCPR_CLK 24 +#define GCC_CPUSS_RBCPR_CLK_SRC 25 +#define GCC_DDRSS_GPU_AXI_CLK 26 +#define GCC_DISP_AHB_CLK 27 +#define GCC_DISP_AXI_CLK 28 +#define GCC_DISP_GPLL0_CLK_SRC 29 +#define GCC_DISP_GPLL0_DIV_CLK_SRC 30 +#define GCC_DISP_XO_CLK 31 +#define GCC_GP1_CLK 32 +#define GCC_GP1_CLK_SRC 33 +#define GCC_GP2_CLK 34 +#define GCC_GP2_CLK_SRC 35 +#define GCC_GP3_CLK 36 +#define GCC_GP3_CLK_SRC 37 +#define GCC_GPU_CFG_AHB_CLK 38 +#define GCC_GPU_GPLL0_CLK_SRC 39 +#define GCC_GPU_GPLL0_DIV_CLK_SRC 40 +#define GCC_GPU_MEMNOC_GFX_CLK 41 +#define GCC_GPU_SNOC_DVM_GFX_CLK 42 +#define GCC_MSS_AXIS2_CLK 43 +#define GCC_MSS_CFG_AHB_CLK 44 +#define GCC_MSS_GPLL0_DIV_CLK_SRC 45 +#define GCC_MSS_MFAB_AXIS_CLK 46 +#define GCC_MSS_Q6_MEMNOC_AXI_CLK 47 +#define GCC_MSS_SNOC_AXI_CLK 48 +#define GCC_PCIE_0_AUX_CLK 49 +#define GCC_PCIE_0_AUX_CLK_SRC 50 +#define GCC_PCIE_0_CFG_AHB_CLK 51 +#define GCC_PCIE_0_CLKREF_CLK 52 +#define GCC_PCIE_0_MSTR_AXI_CLK 53 +#define GCC_PCIE_0_PIPE_CLK 54 +#define GCC_PCIE_0_SLV_AXI_CLK 55 +#define GCC_PCIE_0_SLV_Q2A_AXI_CLK 56 +#define GCC_PCIE_1_AUX_CLK 57 +#define GCC_PCIE_1_AUX_CLK_SRC 58 +#define GCC_PCIE_1_CFG_AHB_CLK 59 +#define GCC_PCIE_1_CLKREF_CLK 60 +#define GCC_PCIE_1_MSTR_AXI_CLK 61 +#define GCC_PCIE_1_PIPE_CLK 62 +#define GCC_PCIE_1_SLV_AXI_CLK 63 +#define GCC_PCIE_1_SLV_Q2A_AXI_CLK 64 +#define GCC_PCIE_PHY_AUX_CLK 65 +#define GCC_PCIE_PHY_REFGEN_CLK 66 +#define GCC_PCIE_PHY_REFGEN_CLK_SRC 67 +#define GCC_PDM2_CLK 68 +#define GCC_PDM2_CLK_SRC 69 +#define GCC_PDM_AHB_CLK 70 +#define GCC_PDM_XO4_CLK 71 +#define GCC_PRNG_AHB_CLK 72 +#define GCC_QMIP_CAMERA_AHB_CLK 73 +#define GCC_QMIP_DISP_AHB_CLK 74 +#define GCC_QMIP_VIDEO_AHB_CLK 75 +#define GCC_QUPV3_WRAP0_S0_CLK 76 +#define GCC_QUPV3_WRAP0_S0_CLK_SRC 77 +#define GCC_QUPV3_WRAP0_S1_CLK 78 +#define GCC_QUPV3_WRAP0_S1_CLK_SRC 79 +#define GCC_QUPV3_WRAP0_S2_CLK 80 +#define GCC_QUPV3_WRAP0_S2_CLK_SRC 81 +#define GCC_QUPV3_WRAP0_S3_CLK 82 +#define GCC_QUPV3_WRAP0_S3_CLK_SRC 83 +#define GCC_QUPV3_WRAP0_S4_CLK 84 +#define GCC_QUPV3_WRAP0_S4_CLK_SRC 85 +#define GCC_QUPV3_WRAP0_S5_CLK 86 +#define GCC_QUPV3_WRAP0_S5_CLK_SRC 87 +#define GCC_QUPV3_WRAP0_S6_CLK 88 +#define GCC_QUPV3_WRAP0_S6_CLK_SRC 89 +#define GCC_QUPV3_WRAP0_S7_CLK 90 +#define GCC_QUPV3_WRAP0_S7_CLK_SRC 91 +#define GCC_QUPV3_WRAP1_S0_CLK 92 +#define GCC_QUPV3_WRAP1_S0_CLK_SRC 93 +#define GCC_QUPV3_WRAP1_S1_CLK 94 +#define GCC_QUPV3_WRAP1_S1_CLK_SRC 95 +#define GCC_QUPV3_WRAP1_S2_CLK 96 +#define GCC_QUPV3_WRAP1_S2_CLK_SRC 97 +#define GCC_QUPV3_WRAP1_S3_CLK 98 +#define GCC_QUPV3_WRAP1_S3_CLK_SRC 99 +#define GCC_QUPV3_WRAP1_S4_CLK 100 +#define GCC_QUPV3_WRAP1_S4_CLK_SRC 101 +#define GCC_QUPV3_WRAP1_S5_CLK 102 +#define GCC_QUPV3_WRAP1_S5_CLK_SRC 103 +#define GCC_QUPV3_WRAP1_S6_CLK 104 +#define GCC_QUPV3_WRAP1_S6_CLK_SRC 105 +#define GCC_QUPV3_WRAP1_S7_CLK 106 +#define GCC_QUPV3_WRAP1_S7_CLK_SRC 107 +#define GCC_QUPV3_WRAP_0_M_AHB_CLK 108 +#define GCC_QUPV3_WRAP_0_S_AHB_CLK 109 +#define GCC_QUPV3_WRAP_1_M_AHB_CLK 110 +#define GCC_QUPV3_WRAP_1_S_AHB_CLK 111 +#define GCC_SDCC2_AHB_CLK 112 +#define GCC_SDCC2_APPS_CLK 113 +#define GCC_SDCC2_APPS_CLK_SRC 114 +#define GCC_SDCC4_AHB_CLK 115 +#define GCC_SDCC4_APPS_CLK 116 +#define GCC_SDCC4_APPS_CLK_SRC 117 +#define GCC_SYS_NOC_CPUSS_AHB_CLK 118 +#define GCC_TSIF_AHB_CLK 119 +#define GCC_TSIF_INACTIVITY_TIMERS_CLK 120 +#define GCC_TSIF_REF_CLK 121 +#define GCC_TSIF_REF_CLK_SRC 122 +#define GCC_UFS_CARD_AHB_CLK 123 +#define GCC_UFS_CARD_AXI_CLK 124 +#define GCC_UFS_CARD_AXI_CLK_SRC 125 +#define GCC_UFS_CARD_CLKREF_CLK 126 +#define GCC_UFS_CARD_ICE_CORE_CLK 127 +#define GCC_UFS_CARD_ICE_CORE_CLK_SRC 128 +#define GCC_UFS_CARD_PHY_AUX_CLK 129 +#define GCC_UFS_CARD_PHY_AUX_CLK_SRC 130 +#define GCC_UFS_CARD_RX_SYMBOL_0_CLK 131 +#define GCC_UFS_CARD_RX_SYMBOL_1_CLK 132 +#define GCC_UFS_CARD_TX_SYMBOL_0_CLK 133 +#define GCC_UFS_CARD_UNIPRO_CORE_CLK 134 +#define GCC_UFS_CARD_UNIPRO_CORE_CLK_SRC 135 +#define GCC_UFS_MEM_CLKREF_CLK 136 +#define GCC_UFS_PHY_AHB_CLK 137 +#define GCC_UFS_PHY_AXI_CLK 138 +#define GCC_UFS_PHY_AXI_CLK_SRC 139 +#define GCC_UFS_PHY_ICE_CORE_CLK 140 +#define GCC_UFS_PHY_ICE_CORE_CLK_SRC 141 +#define GCC_UFS_PHY_PHY_AUX_CLK 142 +#define GCC_UFS_PHY_PHY_AUX_CLK_SRC 143 +#define GCC_UFS_PHY_RX_SYMBOL_0_CLK 144 +#define GCC_UFS_PHY_RX_SYMBOL_1_CLK 145 +#define GCC_UFS_PHY_TX_SYMBOL_0_CLK 146 +#define GCC_UFS_PHY_UNIPRO_CORE_CLK 147 +#define GCC_UFS_PHY_UNIPRO_CORE_CLK_SRC 148 +#define GCC_USB30_PRIM_MASTER_CLK 149 +#define GCC_USB30_PRIM_MASTER_CLK_SRC 150 +#define GCC_USB30_PRIM_MOCK_UTMI_CLK 151 +#define GCC_USB30_PRIM_MOCK_UTMI_CLK_SRC 152 +#define GCC_USB30_PRIM_SLEEP_CLK 153 +#define GCC_USB30_SEC_MASTER_CLK 154 +#define GCC_USB30_SEC_MASTER_CLK_SRC 155 +#define GCC_USB30_SEC_MOCK_UTMI_CLK 156 +#define GCC_USB30_SEC_MOCK_UTMI_CLK_SRC 157 +#define GCC_USB30_SEC_SLEEP_CLK 158 +#define GCC_USB3_PRIM_CLKREF_CLK 159 +#define GCC_USB3_PRIM_PHY_AUX_CLK 160 +#define GCC_USB3_PRIM_PHY_AUX_CLK_SRC 161 +#define GCC_USB3_PRIM_PHY_COM_AUX_CLK 162 +#define GCC_USB3_PRIM_PHY_PIPE_CLK 163 +#define GCC_USB3_SEC_CLKREF_CLK 164 +#define GCC_USB3_SEC_PHY_AUX_CLK 165 +#define GCC_USB3_SEC_PHY_AUX_CLK_SRC 166 +#define GCC_USB3_SEC_PHY_COM_AUX_CLK 167 +#define GCC_USB3_SEC_PHY_PIPE_CLK 168 +#define GCC_USB_PHY_CFG_AHB2PHY_CLK 169 +#define GCC_VIDEO_AHB_CLK 170 +#define GCC_VIDEO_AXI_CLK 171 +#define GCC_VIDEO_XO_CLK 172 +#define GPLL0 173 +#define GPLL0_OUT_EVEN 174 +#define GPLL0_OUT_MAIN 175 +#define GCC_UFS_CARD_AXI_HW_CTL_CLK 176 +#define GCC_UFS_PHY_AXI_HW_CTL_CLK 177 +#define GCC_UFS_CARD_UNIPRO_CORE_HW_CTL_CLK 178 +#define GCC_UFS_PHY_UNIPRO_CORE_HW_CTL_CLK 179 +#define GCC_UFS_CARD_ICE_CORE_HW_CTL_CLK 180 +#define GCC_UFS_PHY_ICE_CORE_HW_CTL_CLK 181 +#define GCC_AGGRE_UFS_CARD_AXI_HW_CTL_CLK 182 +#define GCC_AGGRE_UFS_PHY_AXI_HW_CTL_CLK 183 +#define GCC_UFS_CARD_PHY_AUX_HW_CTL_CLK 184 +#define GCC_UFS_PHY_PHY_AUX_HW_CTL_CLK 185 +#define GCC_GPU_IREF_CLK 186 +#define GCC_SDCC1_AHB_CLK 187 +#define GCC_SDCC1_APPS_CLK 188 +#define GCC_SDCC1_ICE_CORE_CLK 189 +#define GCC_SDCC1_APPS_CLK_SRC 190 +#define GCC_SDCC1_ICE_CORE_CLK_SRC 191 +#define GCC_APC_VS_CLK 192 +#define GCC_GPU_VS_CLK 193 +#define GCC_MSS_VS_CLK 194 +#define GCC_VDDA_VS_CLK 195 +#define GCC_VDDCX_VS_CLK 196 +#define GCC_VDDMX_VS_CLK 197 +#define GCC_VS_CTRL_AHB_CLK 198 +#define GCC_VS_CTRL_CLK 199 +#define GCC_VS_CTRL_CLK_SRC 200 +#define GCC_VSENSOR_CLK_SRC 201 +#define GPLL4 202 +#define GPLL6 203 -/* GCC Resets */ +/* GCC reset clocks */ #define GCC_MMSS_BCR 0 #define GCC_PCIE_0_BCR 1 #define GCC_PCIE_1_BCR 2 @@ -222,20 +241,6 @@ #define GCC_USB_PHY_CFG_AHB2PHY_BCR 23 #define GCC_PCIE_0_PHY_BCR 24 #define GCC_PCIE_1_PHY_BCR 25 - -/* GCC GDSCRs */ -#define PCIE_0_GDSC 0 -#define PCIE_1_GDSC 1 -#define UFS_CARD_GDSC 2 -#define UFS_PHY_GDSC 3 -#define USB30_PRIM_GDSC 4 -#define USB30_SEC_GDSC 5 -#define HLOS1_VOTE_AGGRE_NOC_MMU_AUDIO_TBU_GDSC 6 -#define HLOS1_VOTE_AGGRE_NOC_MMU_PCIE_TBU_GDSC 7 -#define HLOS1_VOTE_AGGRE_NOC_MMU_TBU1_GDSC 8 -#define HLOS1_VOTE_AGGRE_NOC_MMU_TBU2_GDSC 9 -#define HLOS1_VOTE_MMNOC_MMU_TBU_HF0_GDSC 10 -#define HLOS1_VOTE_MMNOC_MMU_TBU_HF1_GDSC 11 -#define HLOS1_VOTE_MMNOC_MMU_TBU_SF_GDSC 12 +#define GCC_SDCC1_BCR 26 #endif diff --git a/include/dt-bindings/clock/qcom,gpucc-sdm845.h b/include/dt-bindings/clock/qcom,gpucc-sdm845.h new file mode 100644 index 000000000000..a82a630734f2 --- /dev/null +++ b/include/dt-bindings/clock/qcom,gpucc-sdm845.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2016-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. + */ + +#ifndef _DT_BINDINGS_CLK_MSM_GPU_CC_SDM845_H +#define _DT_BINDINGS_CLK_MSM_GPU_CC_SDM845_H + +/* GPUCC clock registers */ +#define GPU_CC_ACD_AHB_CLK 0 +#define GPU_CC_ACD_CXO_CLK 1 +#define GPU_CC_CRC_AHB_CLK 2 +#define GPU_CC_CX_APB_CLK 3 +#define GPU_CC_CX_GMU_CLK 4 +#define GPU_CC_CX_QDSS_AT_CLK 5 +#define GPU_CC_CX_QDSS_TRIG_CLK 6 +#define GPU_CC_CX_QDSS_TSCTR_CLK 7 +#define GPU_CC_CX_SNOC_DVM_CLK 8 +#define GPU_CC_CXO_AON_CLK 9 +#define GPU_CC_CXO_CLK 10 +#define GPU_CC_GX_GMU_CLK 11 +#define GPU_CC_GX_QDSS_TSCTR_CLK 12 +#define GPU_CC_GX_VSENSE_CLK 13 +#define GPU_CC_PLL0_OUT_MAIN 14 +#define GPU_CC_PLL0_OUT_ODD 15 +#define GPU_CC_PLL0_OUT_TEST 16 +#define GPU_CC_PLL1 17 +#define GPU_CC_PLL1_OUT_EVEN 18 +#define GPU_CC_PLL1_OUT_MAIN 19 +#define GPU_CC_PLL1_OUT_ODD 20 +#define GPU_CC_PLL1_OUT_TEST 21 +#define GPU_CC_PLL_TEST_CLK 22 +#define GPU_CC_SLEEP_CLK 23 +#define GPU_CC_GMU_CLK_SRC 24 +#define GPU_CC_CX_GFX3D_CLK 25 +#define GPU_CC_CX_GFX3D_SLV_CLK 26 +#define GPU_CC_PLL0 27 + +/* GPUCC reset clock registers */ +#define GPUCC_GPU_CC_ACD_BCR 0 +#define GPUCC_GPU_CC_CX_BCR 1 +#define GPUCC_GPU_CC_GFX3D_AON_BCR 2 +#define GPUCC_GPU_CC_GMU_BCR 3 +#define GPUCC_GPU_CC_GX_BCR 4 +#define GPUCC_GPU_CC_SPDM_BCR 5 +#define GPUCC_GPU_CC_XO_BCR 6 + +/* GFX3D clock registers */ +#define GPU_CC_PLL0_OUT_EVEN 1 +#define GPU_CC_GX_GFX3D_CLK_SRC 2 +#define GPU_CC_GX_GFX3D_CLK 3 +#endif diff --git a/include/dt-bindings/clock/qcom,videocc-sdm845.h b/include/dt-bindings/clock/qcom,videocc-sdm845.h index 1b868165e8ce..5d25292ad0f7 100644 --- a/include/dt-bindings/clock/qcom,videocc-sdm845.h +++ b/include/dt-bindings/clock/qcom,videocc-sdm845.h @@ -1,35 +1,23 @@ -/* SPDX-License-Identifier: GPL-2.0 */ +// SPDX-License-Identifier: GPL-2.0 /* - * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. */ -#ifndef _DT_BINDINGS_CLK_SDM_VIDEO_CC_SDM845_H -#define _DT_BINDINGS_CLK_SDM_VIDEO_CC_SDM845_H +#ifndef _DT_BINDINGS_CLK_MSM_VIDEO_CC_SDM845_H +#define _DT_BINDINGS_CLK_MSM_VIDEO_CC_SDM845_H -/* VIDEO_CC clock registers */ -#define VIDEO_CC_APB_CLK 0 -#define VIDEO_CC_AT_CLK 1 -#define VIDEO_CC_QDSS_TRIG_CLK 2 -#define VIDEO_CC_QDSS_TSCTR_DIV8_CLK 3 -#define VIDEO_CC_VCODEC0_AXI_CLK 4 -#define VIDEO_CC_VCODEC0_CORE_CLK 5 -#define VIDEO_CC_VCODEC1_AXI_CLK 6 -#define VIDEO_CC_VCODEC1_CORE_CLK 7 -#define VIDEO_CC_VENUS_AHB_CLK 8 -#define VIDEO_CC_VENUS_CLK_SRC 9 -#define VIDEO_CC_VENUS_CTL_AXI_CLK 10 -#define VIDEO_CC_VENUS_CTL_CORE_CLK 11 -#define VIDEO_PLL0 12 - -/* VIDEO_CC Resets */ -#define VIDEO_CC_VENUS_BCR 0 -#define VIDEO_CC_VCODEC0_BCR 1 -#define VIDEO_CC_VCODEC1_BCR 2 -#define VIDEO_CC_INTERFACE_BCR 3 - -/* VIDEO_CC GDSCRs */ -#define VENUS_GDSC 0 -#define VCODEC0_GDSC 1 -#define VCODEC1_GDSC 2 +#define VIDEO_CC_APB_CLK 0 +#define VIDEO_CC_AT_CLK 1 +#define VIDEO_CC_QDSS_TRIG_CLK 2 +#define VIDEO_CC_QDSS_TSCTR_DIV8_CLK 3 +#define VIDEO_CC_VCODEC0_AXI_CLK 4 +#define VIDEO_CC_VCODEC0_CORE_CLK 5 +#define VIDEO_CC_VCODEC1_AXI_CLK 6 +#define VIDEO_CC_VCODEC1_CORE_CLK 7 +#define VIDEO_CC_VENUS_AHB_CLK 8 +#define VIDEO_CC_VENUS_CLK_SRC 9 +#define VIDEO_CC_VENUS_CTL_AXI_CLK 10 +#define VIDEO_CC_VENUS_CTL_CORE_CLK 11 +#define VIDEO_PLL0 12 #endif From cf7084c3d54a0470413d7eb8db3f8bd451fb1cf8 Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Fri, 5 Nov 2021 17:25:20 +0200 Subject: [PATCH 080/356] clk: qcom: sdm845: Update header for voltage levels constants RPMh regulator voltage level constans are now located in qcom,rpmh-regulator-levels.h header. Signed-off-by: Pavel Dubrova --- drivers/clk/qcom/vdd-level-sdm845.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/qcom/vdd-level-sdm845.h b/drivers/clk/qcom/vdd-level-sdm845.h index b710b00bc0c7..b2edfb705598 100644 --- a/drivers/clk/qcom/vdd-level-sdm845.h +++ b/drivers/clk/qcom/vdd-level-sdm845.h @@ -7,7 +7,7 @@ #define __DRIVERS_CLK_QCOM_VDD_LEVEL_COBALT_H #include -#include +#include #define VDD_CX_FMAX_MAP1(l1, f1) \ .vdd_class = &vdd_cx, \ From f1a6e143a1431f03ebf4be786dcd72d7979a899d Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Tue, 9 Nov 2021 17:03:59 +0200 Subject: [PATCH 081/356] clk: qcom: sdm845: Update definition of the OFF voltage level RPMH_REGULATOR_LEVEL_OFF constant is not defined anymore. Signed-off-by: Pavel Dubrova --- drivers/clk/qcom/gpucc-sdm845.c | 2 +- drivers/clk/qcom/vdd-level-sdm845.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/qcom/gpucc-sdm845.c b/drivers/clk/qcom/gpucc-sdm845.c index 9eec85ecbf5a..f94a20dc4359 100644 --- a/drivers/clk/qcom/gpucc-sdm845.c +++ b/drivers/clk/qcom/gpucc-sdm845.c @@ -36,7 +36,7 @@ #define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) } static int vdd_gx_corner[] = { - RPMH_REGULATOR_LEVEL_OFF, /* VDD_GX_NONE */ + 0, /* VDD_GX_NONE */ RPMH_REGULATOR_LEVEL_MIN_SVS, /* VDD_GX_MIN */ RPMH_REGULATOR_LEVEL_LOW_SVS, /* VDD_GX_LOWER */ RPMH_REGULATOR_LEVEL_SVS, /* VDD_GX_LOW */ diff --git a/drivers/clk/qcom/vdd-level-sdm845.h b/drivers/clk/qcom/vdd-level-sdm845.h index b2edfb705598..3eec510f4d8e 100644 --- a/drivers/clk/qcom/vdd-level-sdm845.h +++ b/drivers/clk/qcom/vdd-level-sdm845.h @@ -133,7 +133,7 @@ enum vdd_gx_levels { /* Need to use the correct VI/VL mappings */ static int vdd_corner[] = { - RPMH_REGULATOR_LEVEL_OFF, /* VDD_CX_NONE */ + 0, /* VDD_CX_NONE */ RPMH_REGULATOR_LEVEL_MIN_SVS, /* VDD_CX_MIN */ RPMH_REGULATOR_LEVEL_LOW_SVS, /* VDD_CX_LOWER */ RPMH_REGULATOR_LEVEL_SVS, /* VDD_CX_LOW */ From df964712c86c61a1ed082bd4ce7b35b47960131f Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Fri, 5 Nov 2021 17:41:25 +0200 Subject: [PATCH 082/356] clk: qcom: sdm845: Update Fabia PLL configuration for 4.19 Update Fabia PLL configuration for SDM845 clock controller drivers according to current Alpha PLL driver. Signed-off-by: Pavel Dubrova --- drivers/clk/qcom/camcc-sdm845.c | 47 +++++++++++++++++-------------- drivers/clk/qcom/dispcc-sdm845.c | 12 ++++---- drivers/clk/qcom/gcc-sdm845.c | 15 +++++----- drivers/clk/qcom/gpucc-sdm845.c | 19 +++++++------ drivers/clk/qcom/videocc-sdm845.c | 8 +++--- 5 files changed, 54 insertions(+), 47 deletions(-) diff --git a/drivers/clk/qcom/camcc-sdm845.c b/drivers/clk/qcom/camcc-sdm845.c index f3f0fbe9bab2..5f3e30dc9047 100644 --- a/drivers/clk/qcom/camcc-sdm845.c +++ b/drivers/clk/qcom/camcc-sdm845.c @@ -85,22 +85,22 @@ static struct pll_vco fabia_vco[] = { { 125000000, 1000000000, 1 }, }; -static const struct pll_config cam_cc_pll0_config = { +static const struct alpha_pll_config cam_cc_pll0_config = { .l = 0x1f, - .frac = 0x4000, + .alpha = 0x4000, }; static struct clk_alpha_pll cam_cc_pll0 = { .offset = 0x0, .vco_table = fabia_vco, .num_vco = ARRAY_SIZE(fabia_vco), - .type = FABIA_PLL, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], .clkr = { .hw.init = &(struct clk_init_data){ .name = "cam_cc_pll0", .parent_names = (const char *[]){ "bi_tcxo" }, .num_parents = 1, - .ops = &clk_fabia_pll_ops, + .ops = &clk_alpha_pll_fabia_ops, VDD_CX_FMAX_MAP4( MIN, 615000000, LOW, 1066000000, @@ -124,30 +124,31 @@ static struct clk_alpha_pll_postdiv cam_cc_pll0_out_even = { .post_div_table = post_div_table_fabia_even, .num_post_div = ARRAY_SIZE(post_div_table_fabia_even), .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], .clkr.hw.init = &(struct clk_init_data){ .name = "cam_cc_pll0_out_even", .parent_names = (const char *[]){ "cam_cc_pll0" }, .num_parents = 1, - .ops = &clk_generic_pll_postdiv_ops, + .ops = &clk_alpha_pll_postdiv_fabia_ops, }, }; -static const struct pll_config cam_cc_pll1_config = { +static const struct alpha_pll_config cam_cc_pll1_config = { .l = 0x2a, - .frac = 0x1556, + .alpha = 0x1556, }; static struct clk_alpha_pll cam_cc_pll1 = { .offset = 0x1000, .vco_table = fabia_vco, .num_vco = ARRAY_SIZE(fabia_vco), - .type = FABIA_PLL, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], .clkr = { .hw.init = &(struct clk_init_data){ .name = "cam_cc_pll1", .parent_names = (const char *[]){ "bi_tcxo" }, .num_parents = 1, - .ops = &clk_fabia_pll_ops, + .ops = &clk_alpha_pll_fabia_ops, VDD_CX_FMAX_MAP4( MIN, 615000000, LOW, 1066000000, @@ -163,30 +164,31 @@ static struct clk_alpha_pll_postdiv cam_cc_pll1_out_even = { .post_div_table = post_div_table_fabia_even, .num_post_div = ARRAY_SIZE(post_div_table_fabia_even), .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], .clkr.hw.init = &(struct clk_init_data){ .name = "cam_cc_pll1_out_even", .parent_names = (const char *[]){ "cam_cc_pll1" }, .num_parents = 1, - .ops = &clk_generic_pll_postdiv_ops, + .ops = &clk_alpha_pll_postdiv_fabia_ops, }, }; -static const struct pll_config cam_cc_pll2_config = { +static const struct alpha_pll_config cam_cc_pll2_config = { .l = 0x32, - .frac = 0x0, + .alpha = 0x0, }; static struct clk_alpha_pll cam_cc_pll2 = { .offset = 0x2000, .vco_table = fabia_vco, .num_vco = ARRAY_SIZE(fabia_vco), - .type = FABIA_PLL, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], .clkr = { .hw.init = &(struct clk_init_data){ .name = "cam_cc_pll2", .parent_names = (const char *[]){ "bi_tcxo" }, .num_parents = 1, - .ops = &clk_fabia_pll_ops, + .ops = &clk_alpha_pll_fabia_ops, VDD_MX_FMAX_MAP4( MIN, 615000000, LOW, 1066000000, @@ -202,11 +204,12 @@ static struct clk_alpha_pll_postdiv cam_cc_pll2_out_even = { .post_div_table = post_div_table_fabia_even, .num_post_div = ARRAY_SIZE(post_div_table_fabia_even), .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], .clkr.hw.init = &(struct clk_init_data){ .name = "cam_cc_pll2_out_even", .parent_names = (const char *[]){ "cam_cc_pll2" }, .num_parents = 1, - .ops = &clk_generic_pll_postdiv_ops, + .ops = &clk_alpha_pll_postdiv_fabia_ops, }, }; @@ -224,30 +227,31 @@ static struct clk_alpha_pll_postdiv cam_cc_pll2_out_odd = { .post_div_table = post_div_table_fabia_odd, .num_post_div = ARRAY_SIZE(post_div_table_fabia_odd), .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], .clkr.hw.init = &(struct clk_init_data){ .name = "cam_cc_pll2_out_odd", .parent_names = (const char *[]){ "cam_cc_pll2" }, .num_parents = 1, - .ops = &clk_generic_pll_postdiv_ops, + .ops = &clk_alpha_pll_postdiv_fabia_ops, }, }; -static const struct pll_config cam_cc_pll3_config = { +static const struct alpha_pll_config cam_cc_pll3_config = { .l = 0x14, - .frac = 0x0, + .alpha = 0x0, }; static struct clk_alpha_pll cam_cc_pll3 = { .offset = 0x3000, .vco_table = fabia_vco, .num_vco = ARRAY_SIZE(fabia_vco), - .type = FABIA_PLL, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], .clkr = { .hw.init = &(struct clk_init_data){ .name = "cam_cc_pll3", .parent_names = (const char *[]){ "bi_tcxo" }, .num_parents = 1, - .ops = &clk_fabia_pll_ops, + .ops = &clk_alpha_pll_fabia_ops, VDD_CX_FMAX_MAP4( MIN, 615000000, LOW, 1066000000, @@ -263,11 +267,12 @@ static struct clk_alpha_pll_postdiv cam_cc_pll3_out_even = { .post_div_table = post_div_table_fabia_even, .num_post_div = ARRAY_SIZE(post_div_table_fabia_even), .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], .clkr.hw.init = &(struct clk_init_data){ .name = "cam_cc_pll3_out_even", .parent_names = (const char *[]){ "cam_cc_pll3" }, .num_parents = 1, - .ops = &clk_generic_pll_postdiv_ops, + .ops = &clk_alpha_pll_postdiv_fabia_ops, }, }; diff --git a/drivers/clk/qcom/dispcc-sdm845.c b/drivers/clk/qcom/dispcc-sdm845.c index 1e4be9871f2f..b987f487b1c7 100644 --- a/drivers/clk/qcom/dispcc-sdm845.c +++ b/drivers/clk/qcom/dispcc-sdm845.c @@ -122,27 +122,27 @@ static struct pll_vco fabia_vco[] = { { 125000000, 1000000000, 1 }, }; -static const struct pll_config disp_cc_pll0_config = { +static const struct alpha_pll_config disp_cc_pll0_config = { .l = 0x15, - .frac = 0x7c00, + .alpha = 0x7c00, }; -static const struct pll_config disp_cc_pll0_config_v2 = { +static const struct alpha_pll_config disp_cc_pll0_config_v2 = { .l = 0x2c, - .frac = 0xcaaa, + .alpha = 0xcaaa, }; static struct clk_alpha_pll disp_cc_pll0 = { .offset = 0x0, .vco_table = fabia_vco, .num_vco = ARRAY_SIZE(fabia_vco), - .type = FABIA_PLL, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], .clkr = { .hw.init = &(struct clk_init_data){ .name = "disp_cc_pll0", .parent_names = (const char *[]){ "bi_tcxo" }, .num_parents = 1, - .ops = &clk_fabia_pll_ops, + .ops = &clk_alpha_pll_fabia_ops, VDD_CX_FMAX_MAP4( MIN, 615000000, LOW, 1066000000, diff --git a/drivers/clk/qcom/gcc-sdm845.c b/drivers/clk/qcom/gcc-sdm845.c index 01eade692e2a..206fb5579646 100644 --- a/drivers/clk/qcom/gcc-sdm845.c +++ b/drivers/clk/qcom/gcc-sdm845.c @@ -245,7 +245,7 @@ static struct clk_alpha_pll gpll0 = { .offset = 0x0, .vco_table = fabia_vco, .num_vco = ARRAY_SIZE(fabia_vco), - .type = FABIA_PLL, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], .clkr = { .enable_reg = 0x52000, .enable_mask = BIT(0), @@ -253,7 +253,7 @@ static struct clk_alpha_pll gpll0 = { .name = "gpll0", .parent_names = (const char *[]){ "bi_tcxo" }, .num_parents = 1, - .ops = &clk_fabia_fixed_pll_ops, + .ops = &clk_alpha_pll_fixed_fabia_ops, VDD_CX_FMAX_MAP4( MIN, 615000000, LOW, 1066000000, @@ -267,7 +267,7 @@ static struct clk_alpha_pll gpll4 = { .offset = 0x76000, .vco_table = fabia_vco, .num_vco = ARRAY_SIZE(fabia_vco), - .type = FABIA_PLL, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], .clkr = { .enable_reg = 0x52000, .enable_mask = BIT(4), @@ -275,7 +275,7 @@ static struct clk_alpha_pll gpll4 = { .name = "gpll4", .parent_names = (const char *[]){ "bi_tcxo" }, .num_parents = 1, - .ops = &clk_fabia_fixed_pll_ops, + .ops = &clk_alpha_pll_fixed_fabia_ops, VDD_CX_FMAX_MAP4( MIN, 615000000, LOW, 1066000000, @@ -299,11 +299,12 @@ static struct clk_alpha_pll_postdiv gpll0_out_even = { .post_div_table = post_div_table_fabia_even, .num_post_div = ARRAY_SIZE(post_div_table_fabia_even), .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], .clkr.hw.init = &(struct clk_init_data){ .name = "gpll0_out_even", .parent_names = (const char *[]){ "gpll0" }, .num_parents = 1, - .ops = &clk_generic_pll_postdiv_ops, + .ops = &clk_alpha_pll_postdiv_fabia_ops, }, }; @@ -311,7 +312,7 @@ static struct clk_alpha_pll gpll6 = { .offset = 0x13000, .vco_table = fabia_vco, .num_vco = ARRAY_SIZE(fabia_vco), - .type = FABIA_PLL, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], .clkr = { .enable_reg = 0x52000, .enable_mask = BIT(6), @@ -319,7 +320,7 @@ static struct clk_alpha_pll gpll6 = { .name = "gpll6", .parent_names = (const char *[]){ "bi_tcxo" }, .num_parents = 1, - .ops = &clk_fabia_fixed_pll_ops, + .ops = &clk_alpha_pll_fixed_fabia_ops, VDD_CX_FMAX_MAP4( MIN, 615000000, LOW, 1066000000, diff --git a/drivers/clk/qcom/gpucc-sdm845.c b/drivers/clk/qcom/gpucc-sdm845.c index f94a20dc4359..ad1310a10a86 100644 --- a/drivers/clk/qcom/gpucc-sdm845.c +++ b/drivers/clk/qcom/gpucc-sdm845.c @@ -129,27 +129,27 @@ static struct pll_vco fabia_vco[] = { { 125000000, 1000000000, 1 }, }; -static const struct pll_config gpu_cc_pll0_config = { +static const struct alpha_pll_config gpu_cc_pll0_config = { .l = 0x1d, - .frac = 0x2aaa, + .alpha = 0x2aaa, }; -static const struct pll_config gpu_cc_pll1_config = { +static const struct alpha_pll_config gpu_cc_pll1_config = { .l = 0x1a, - .frac = 0xaaaa, + .alpha = 0xaaaa, }; static struct clk_alpha_pll gpu_cc_pll0 = { .offset = 0x0, .vco_table = fabia_vco, .num_vco = ARRAY_SIZE(fabia_vco), - .type = FABIA_PLL, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], .clkr = { .hw.init = &(struct clk_init_data){ .name = "gpu_cc_pll0", .parent_names = (const char *[]){ "bi_tcxo" }, .num_parents = 1, - .ops = &clk_fabia_pll_ops, + .ops = &clk_alpha_pll_fabia_ops, VDD_MX_FMAX_MAP4( MIN, 615000000, LOW, 1066000000, @@ -173,12 +173,13 @@ static struct clk_alpha_pll_postdiv gpu_cc_pll0_out_even = { .post_div_table = post_div_table_fabia_even, .num_post_div = ARRAY_SIZE(post_div_table_fabia_even), .width = 4, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], .clkr.hw.init = &(struct clk_init_data){ .name = "gpu_cc_pll0_out_even", .parent_names = (const char *[]){ "gpu_cc_pll0" }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, - .ops = &clk_generic_pll_postdiv_ops, + .ops = &clk_alpha_pll_postdiv_fabia_ops, }, }; @@ -186,13 +187,13 @@ static struct clk_alpha_pll gpu_cc_pll1 = { .offset = 0x100, .vco_table = fabia_vco, .num_vco = ARRAY_SIZE(fabia_vco), - .type = FABIA_PLL, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], .clkr = { .hw.init = &(struct clk_init_data){ .name = "gpu_cc_pll1", .parent_names = (const char *[]){ "bi_tcxo" }, .num_parents = 1, - .ops = &clk_fabia_pll_ops, + .ops = &clk_alpha_pll_fabia_ops, VDD_MX_FMAX_MAP4( MIN, 615000000, LOW, 1066000000, diff --git a/drivers/clk/qcom/videocc-sdm845.c b/drivers/clk/qcom/videocc-sdm845.c index a140af23b2f6..6cb12f892e4b 100644 --- a/drivers/clk/qcom/videocc-sdm845.c +++ b/drivers/clk/qcom/videocc-sdm845.c @@ -61,22 +61,22 @@ static struct pll_vco fabia_vco[] = { { 125000000, 1000000000, 1 }, }; -static const struct pll_config video_pll0_config = { +static const struct alpha_pll_config video_pll0_config = { .l = 0x10, - .frac = 0xaaab, + .alpha = 0xaaab, }; static struct clk_alpha_pll video_pll0 = { .offset = 0x42c, .vco_table = fabia_vco, .num_vco = ARRAY_SIZE(fabia_vco), - .type = FABIA_PLL, + .regs = clk_alpha_pll_regs[CLK_ALPHA_PLL_TYPE_FABIA], .clkr = { .hw.init = &(struct clk_init_data){ .name = "video_pll0", .parent_names = (const char *[]){ "bi_tcxo" }, .num_parents = 1, - .ops = &clk_fabia_pll_ops, + .ops = &clk_alpha_pll_fabia_ops, VDD_CX_FMAX_MAP4( MIN, 615000000, LOW, 1066000000, From 6b2180d2c9dd86739fa475ccf7a4cbc501f0fbfa Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Fri, 5 Nov 2021 17:55:10 +0200 Subject: [PATCH 083/356] clk: qcom: gcc-sdm845: Update RCG clocks and DFS registration RCG clocks definition and DFS registration was changed on current kernel version. Update it. Signed-off-by: Pavel Dubrova --- drivers/clk/qcom/gcc-sdm845.c | 426 ++++++++++++++++++---------------- 1 file changed, 227 insertions(+), 199 deletions(-) diff --git a/drivers/clk/qcom/gcc-sdm845.c b/drivers/clk/qcom/gcc-sdm845.c index 206fb5579646..c39070fecb2d 100644 --- a/drivers/clk/qcom/gcc-sdm845.c +++ b/drivers/clk/qcom/gcc-sdm845.c @@ -577,6 +577,18 @@ static const struct freq_tbl ftbl_gcc_qupv3_wrap0_s0_clk_src_sdm845_v2[] = { { } }; +static struct clk_init_data gcc_qupv3_wrap0_s0_clk_src_init = { + .name = "gcc_qupv3_wrap0_s0_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 19200000, + LOWER, 75000000, + LOW, 100000000), +}; + static struct clk_rcg2 gcc_qupv3_wrap0_s0_clk_src = { .cmd_rcgr = 0x17034, .mnd_width = 16, @@ -584,17 +596,19 @@ static struct clk_rcg2 gcc_qupv3_wrap0_s0_clk_src = { .parent_map = gcc_parent_map_0, .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, .enable_safe_config = true, - .clkr.hw.init = &(struct clk_init_data){ - .name = "gcc_qupv3_wrap0_s0_clk_src", - .parent_names = gcc_parent_names_0, - .num_parents = 4, - .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, - VDD_CX_FMAX_MAP3( - MIN, 19200000, - LOWER, 75000000, - LOW, 100000000), - }, + .clkr.hw.init = &gcc_qupv3_wrap0_s0_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap0_s1_clk_src_init = { + .name = "gcc_qupv3_wrap0_s1_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 19200000, + LOWER, 75000000, + LOW, 100000000), }; static struct clk_rcg2 gcc_qupv3_wrap0_s1_clk_src = { @@ -604,17 +618,19 @@ static struct clk_rcg2 gcc_qupv3_wrap0_s1_clk_src = { .parent_map = gcc_parent_map_0, .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, .enable_safe_config = true, - .clkr.hw.init = &(struct clk_init_data){ - .name = "gcc_qupv3_wrap0_s1_clk_src", - .parent_names = gcc_parent_names_0, - .num_parents = 4, - .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, - VDD_CX_FMAX_MAP3( - MIN, 19200000, - LOWER, 75000000, - LOW, 100000000), - }, + .clkr.hw.init = &gcc_qupv3_wrap0_s1_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap0_s2_clk_src_init = { + .name = "gcc_qupv3_wrap0_s2_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 19200000, + LOWER, 75000000, + LOW, 100000000), }; static struct clk_rcg2 gcc_qupv3_wrap0_s2_clk_src = { @@ -624,17 +640,19 @@ static struct clk_rcg2 gcc_qupv3_wrap0_s2_clk_src = { .parent_map = gcc_parent_map_0, .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, .enable_safe_config = true, - .clkr.hw.init = &(struct clk_init_data){ - .name = "gcc_qupv3_wrap0_s2_clk_src", - .parent_names = gcc_parent_names_0, - .num_parents = 4, - .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, - VDD_CX_FMAX_MAP3( - MIN, 19200000, - LOWER, 75000000, - LOW, 100000000), - }, + .clkr.hw.init = &gcc_qupv3_wrap0_s2_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap0_s3_clk_src_init = { + .name = "gcc_qupv3_wrap0_s3_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 19200000, + LOWER, 75000000, + LOW, 100000000), }; static struct clk_rcg2 gcc_qupv3_wrap0_s3_clk_src = { @@ -644,17 +662,19 @@ static struct clk_rcg2 gcc_qupv3_wrap0_s3_clk_src = { .parent_map = gcc_parent_map_0, .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, .enable_safe_config = true, - .clkr.hw.init = &(struct clk_init_data){ - .name = "gcc_qupv3_wrap0_s3_clk_src", - .parent_names = gcc_parent_names_0, - .num_parents = 4, - .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, - VDD_CX_FMAX_MAP3( - MIN, 19200000, - LOWER, 75000000, - LOW, 100000000), - }, + .clkr.hw.init = &gcc_qupv3_wrap0_s3_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap0_s4_clk_src_init = { + .name = "gcc_qupv3_wrap0_s4_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 19200000, + LOWER, 75000000, + LOW, 100000000), }; static struct clk_rcg2 gcc_qupv3_wrap0_s4_clk_src = { @@ -664,17 +684,19 @@ static struct clk_rcg2 gcc_qupv3_wrap0_s4_clk_src = { .parent_map = gcc_parent_map_0, .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, .enable_safe_config = true, - .clkr.hw.init = &(struct clk_init_data){ - .name = "gcc_qupv3_wrap0_s4_clk_src", - .parent_names = gcc_parent_names_0, - .num_parents = 4, - .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, - VDD_CX_FMAX_MAP3( - MIN, 19200000, - LOWER, 75000000, - LOW, 100000000), - }, + .clkr.hw.init = &gcc_qupv3_wrap0_s4_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap0_s5_clk_src_init = { + .name = "gcc_qupv3_wrap0_s5_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 19200000, + LOWER, 75000000, + LOW, 100000000), }; static struct clk_rcg2 gcc_qupv3_wrap0_s5_clk_src = { @@ -684,17 +706,19 @@ static struct clk_rcg2 gcc_qupv3_wrap0_s5_clk_src = { .parent_map = gcc_parent_map_0, .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, .enable_safe_config = true, - .clkr.hw.init = &(struct clk_init_data){ - .name = "gcc_qupv3_wrap0_s5_clk_src", - .parent_names = gcc_parent_names_0, - .num_parents = 4, - .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, - VDD_CX_FMAX_MAP3( - MIN, 19200000, - LOWER, 75000000, - LOW, 100000000), - }, + .clkr.hw.init = &gcc_qupv3_wrap0_s5_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap0_s6_clk_src_init = { + .name = "gcc_qupv3_wrap0_s6_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 19200000, + LOWER, 75000000, + LOW, 100000000), }; static struct clk_rcg2 gcc_qupv3_wrap0_s6_clk_src = { @@ -704,17 +728,19 @@ static struct clk_rcg2 gcc_qupv3_wrap0_s6_clk_src = { .parent_map = gcc_parent_map_0, .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, .enable_safe_config = true, - .clkr.hw.init = &(struct clk_init_data){ - .name = "gcc_qupv3_wrap0_s6_clk_src", - .parent_names = gcc_parent_names_0, - .num_parents = 4, - .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, - VDD_CX_FMAX_MAP3( - MIN, 19200000, - LOWER, 75000000, - LOW, 100000000), - }, + .clkr.hw.init = &gcc_qupv3_wrap0_s6_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap0_s7_clk_src_init = { + .name = "gcc_qupv3_wrap0_s7_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 19200000, + LOWER, 75000000, + LOW, 100000000), }; static struct clk_rcg2 gcc_qupv3_wrap0_s7_clk_src = { @@ -724,17 +750,19 @@ static struct clk_rcg2 gcc_qupv3_wrap0_s7_clk_src = { .parent_map = gcc_parent_map_0, .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, .enable_safe_config = true, - .clkr.hw.init = &(struct clk_init_data){ - .name = "gcc_qupv3_wrap0_s7_clk_src", - .parent_names = gcc_parent_names_0, - .num_parents = 4, - .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, - VDD_CX_FMAX_MAP3( - MIN, 19200000, - LOWER, 75000000, - LOW, 100000000), - }, + .clkr.hw.init = &gcc_qupv3_wrap0_s7_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap1_s0_clk_src_init = { + .name = "gcc_qupv3_wrap1_s0_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 19200000, + LOWER, 75000000, + LOW, 100000000), }; static struct clk_rcg2 gcc_qupv3_wrap1_s0_clk_src = { @@ -744,17 +772,19 @@ static struct clk_rcg2 gcc_qupv3_wrap1_s0_clk_src = { .parent_map = gcc_parent_map_0, .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, .enable_safe_config = true, - .clkr.hw.init = &(struct clk_init_data){ - .name = "gcc_qupv3_wrap1_s0_clk_src", - .parent_names = gcc_parent_names_0, - .num_parents = 4, - .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, - VDD_CX_FMAX_MAP3( - MIN, 19200000, - LOWER, 75000000, - LOW, 100000000), - }, + .clkr.hw.init = &gcc_qupv3_wrap1_s0_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap1_s1_clk_src_init = { + .name = "gcc_qupv3_wrap1_s1_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 19200000, + LOWER, 75000000, + LOW, 100000000), }; static struct clk_rcg2 gcc_qupv3_wrap1_s1_clk_src = { @@ -764,17 +794,19 @@ static struct clk_rcg2 gcc_qupv3_wrap1_s1_clk_src = { .parent_map = gcc_parent_map_0, .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, .enable_safe_config = true, - .clkr.hw.init = &(struct clk_init_data){ - .name = "gcc_qupv3_wrap1_s1_clk_src", - .parent_names = gcc_parent_names_0, - .num_parents = 4, - .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, - VDD_CX_FMAX_MAP3( - MIN, 19200000, - LOWER, 75000000, - LOW, 100000000), - }, + .clkr.hw.init = &gcc_qupv3_wrap1_s1_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap1_s2_clk_src_init = { + .name = "gcc_qupv3_wrap1_s2_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 19200000, + LOWER, 75000000, + LOW, 100000000), }; static struct clk_rcg2 gcc_qupv3_wrap1_s2_clk_src = { @@ -784,17 +816,19 @@ static struct clk_rcg2 gcc_qupv3_wrap1_s2_clk_src = { .parent_map = gcc_parent_map_0, .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, .enable_safe_config = true, - .clkr.hw.init = &(struct clk_init_data){ - .name = "gcc_qupv3_wrap1_s2_clk_src", - .parent_names = gcc_parent_names_0, - .num_parents = 4, - .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, - VDD_CX_FMAX_MAP3( - MIN, 19200000, - LOWER, 75000000, - LOW, 100000000), - }, + .clkr.hw.init = &gcc_qupv3_wrap1_s2_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap1_s3_clk_src_init = { + .name = "gcc_qupv3_wrap1_s3_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 19200000, + LOWER, 75000000, + LOW, 100000000), }; static struct clk_rcg2 gcc_qupv3_wrap1_s3_clk_src = { @@ -804,17 +838,19 @@ static struct clk_rcg2 gcc_qupv3_wrap1_s3_clk_src = { .parent_map = gcc_parent_map_0, .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, .enable_safe_config = true, - .clkr.hw.init = &(struct clk_init_data){ - .name = "gcc_qupv3_wrap1_s3_clk_src", - .parent_names = gcc_parent_names_0, - .num_parents = 4, - .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, - VDD_CX_FMAX_MAP3( - MIN, 19200000, - LOWER, 75000000, - LOW, 100000000), - }, + .clkr.hw.init = &gcc_qupv3_wrap1_s3_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap1_s4_clk_src_init = { + .name = "gcc_qupv3_wrap1_s4_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 19200000, + LOWER, 75000000, + LOW, 100000000), }; static struct clk_rcg2 gcc_qupv3_wrap1_s4_clk_src = { @@ -824,17 +860,19 @@ static struct clk_rcg2 gcc_qupv3_wrap1_s4_clk_src = { .parent_map = gcc_parent_map_0, .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, .enable_safe_config = true, - .clkr.hw.init = &(struct clk_init_data){ - .name = "gcc_qupv3_wrap1_s4_clk_src", - .parent_names = gcc_parent_names_0, - .num_parents = 4, - .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, - VDD_CX_FMAX_MAP3( - MIN, 19200000, - LOWER, 75000000, - LOW, 100000000), - }, + .clkr.hw.init = &gcc_qupv3_wrap1_s4_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap1_s5_clk_src_init = { + .name = "gcc_qupv3_wrap1_s5_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 19200000, + LOWER, 75000000, + LOW, 100000000), }; static struct clk_rcg2 gcc_qupv3_wrap1_s5_clk_src = { @@ -844,17 +882,19 @@ static struct clk_rcg2 gcc_qupv3_wrap1_s5_clk_src = { .parent_map = gcc_parent_map_0, .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, .enable_safe_config = true, - .clkr.hw.init = &(struct clk_init_data){ - .name = "gcc_qupv3_wrap1_s5_clk_src", - .parent_names = gcc_parent_names_0, - .num_parents = 4, - .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, - VDD_CX_FMAX_MAP3( - MIN, 19200000, - LOWER, 75000000, - LOW, 100000000), - }, + .clkr.hw.init = &gcc_qupv3_wrap1_s5_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap1_s6_clk_src_init = { + .name = "gcc_qupv3_wrap1_s6_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 19200000, + LOWER, 75000000, + LOW, 100000000), }; static struct clk_rcg2 gcc_qupv3_wrap1_s6_clk_src = { @@ -864,17 +904,19 @@ static struct clk_rcg2 gcc_qupv3_wrap1_s6_clk_src = { .parent_map = gcc_parent_map_0, .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, .enable_safe_config = true, - .clkr.hw.init = &(struct clk_init_data){ - .name = "gcc_qupv3_wrap1_s6_clk_src", - .parent_names = gcc_parent_names_0, - .num_parents = 4, - .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, - VDD_CX_FMAX_MAP3( - MIN, 19200000, - LOWER, 75000000, - LOW, 100000000), - }, + .clkr.hw.init = &gcc_qupv3_wrap1_s6_clk_src_init, +}; + +static struct clk_init_data gcc_qupv3_wrap1_s7_clk_src_init = { + .name = "gcc_qupv3_wrap1_s7_clk_src", + .parent_names = gcc_parent_names_0, + .num_parents = 4, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_rcg2_ops, + VDD_CX_FMAX_MAP3( + MIN, 19200000, + LOWER, 75000000, + LOW, 100000000), }; static struct clk_rcg2 gcc_qupv3_wrap1_s7_clk_src = { @@ -884,17 +926,7 @@ static struct clk_rcg2 gcc_qupv3_wrap1_s7_clk_src = { .parent_map = gcc_parent_map_0, .freq_tbl = ftbl_gcc_qupv3_wrap0_s0_clk_src, .enable_safe_config = true, - .clkr.hw.init = &(struct clk_init_data){ - .name = "gcc_qupv3_wrap1_s7_clk_src", - .parent_names = gcc_parent_names_0, - .num_parents = 4, - .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, - VDD_CX_FMAX_MAP3( - MIN, 19200000, - LOWER, 75000000, - LOW, 100000000), - }, + .clkr.hw.init = &gcc_qupv3_wrap1_s7_clk_src_init, }; static const struct freq_tbl ftbl_gcc_sdcc1_ice_core_clk_src[] = { @@ -4026,28 +4058,23 @@ static const struct qcom_reset_map gcc_sdm845_resets[] = { }; /* List of RCG clocks and corresponding flags requested for DFS Mode */ -static struct clk_dfs gcc_dfs_clocks[] = { - { &gcc_qupv3_wrap0_s0_clk_src, DFS_ENABLE_RCG }, - { &gcc_qupv3_wrap0_s1_clk_src, DFS_ENABLE_RCG }, - { &gcc_qupv3_wrap0_s2_clk_src, DFS_ENABLE_RCG }, - { &gcc_qupv3_wrap0_s3_clk_src, DFS_ENABLE_RCG }, - { &gcc_qupv3_wrap0_s4_clk_src, DFS_ENABLE_RCG }, - { &gcc_qupv3_wrap0_s5_clk_src, DFS_ENABLE_RCG }, - { &gcc_qupv3_wrap0_s6_clk_src, DFS_ENABLE_RCG }, - { &gcc_qupv3_wrap0_s7_clk_src, DFS_ENABLE_RCG }, - { &gcc_qupv3_wrap1_s0_clk_src, DFS_ENABLE_RCG }, - { &gcc_qupv3_wrap1_s1_clk_src, DFS_ENABLE_RCG }, - { &gcc_qupv3_wrap1_s2_clk_src, DFS_ENABLE_RCG }, - { &gcc_qupv3_wrap1_s3_clk_src, DFS_ENABLE_RCG }, - { &gcc_qupv3_wrap1_s4_clk_src, DFS_ENABLE_RCG }, - { &gcc_qupv3_wrap1_s5_clk_src, DFS_ENABLE_RCG }, - { &gcc_qupv3_wrap1_s6_clk_src, DFS_ENABLE_RCG }, - { &gcc_qupv3_wrap1_s7_clk_src, DFS_ENABLE_RCG }, -}; - -static const struct qcom_cc_dfs_desc gcc_sdm845_dfs_desc = { - .clks = gcc_dfs_clocks, - .num_clks = ARRAY_SIZE(gcc_dfs_clocks), +static struct clk_rcg_dfs_data gcc_dfs_clocks[] = { + DEFINE_RCG_DFS(gcc_qupv3_wrap0_s0_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap0_s1_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap0_s2_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap0_s3_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap0_s4_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap0_s5_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap0_s6_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap0_s7_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s0_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s1_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s2_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s3_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s4_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s5_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s6_clk_src), + DEFINE_RCG_DFS(gcc_qupv3_wrap1_s7_clk_src), }; static const struct regmap_config gcc_sdm845_regmap_config = { @@ -4324,7 +4351,8 @@ static int gcc_sdm845_probe(struct platform_device *pdev) clk_prepare_enable(gcc_aggre_noc_pcie_tbu_clk.clkr.hw.clk); /* DFS clock registration */ - ret = qcom_cc_register_rcg_dfs(pdev, &gcc_sdm845_dfs_desc); + ret = qcom_cc_register_rcg_dfs(regmap, gcc_dfs_clocks, + ARRAY_SIZE(gcc_dfs_clocks)); if (ret) dev_err(&pdev->dev, "Failed to register with DFS!\n"); From d5ffb149a47b58ed0e5b4973e31983c74dcc7365 Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Fri, 5 Nov 2021 18:52:25 +0200 Subject: [PATCH 084/356] clk: qcom: Add the CPU OSM clock driver for SDM845 Add the CPU OSM clock driver for SDM845. This snapshot of the clk-cpu-osm-sdm845 driver as of https://source.codeaurora.org/quic/la/kernel/msm-4.9 commit 7e5c05f ("Merge "msm: camera: jpeg: Ensure in/out map entries are within allowed range""). Signed-off-by: Pavel Dubrova --- drivers/clk/qcom/Kconfig | 12 + drivers/clk/qcom/Makefile | 1 + drivers/clk/qcom/clk-cpu-osm-sdm845.c | 1411 +++++++++++++++++ include/dt-bindings/clock/qcom,cpucc-sdm845.h | 27 + 4 files changed, 1451 insertions(+) create mode 100644 drivers/clk/qcom/clk-cpu-osm-sdm845.c create mode 100644 include/dt-bindings/clock/qcom,cpucc-sdm845.h diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig index d8d49c07d9e0..88b54f367984 100644 --- a/drivers/clk/qcom/Kconfig +++ b/drivers/clk/qcom/Kconfig @@ -308,6 +308,18 @@ config MSM_VIDEOCC_SDM845 Say Y if you want to support video devices and functionality such as video encode/decode. +config CLOCK_CPU_OSM_SDM845 + tristate "OSM CPU Clock Controller for SDM845" + depends on COMMON_CLK_QCOM + help + Support for the OSM clock controller for SDM845. + Operating State Manager (OSM) is a hardware engine used by some + Qualcomm Technologies, Inc. (QTI) SoCs to manage frequency and + voltage scaling in hardware. OSM is capable of controlling + frequency and voltage requests for multiple clusters via the + existence of multiple OSM domains. + Say Y if you want to support OSM clocks. + config MSM_GCC_KONA tristate "KONA Global Clock Controller" depends on COMMON_CLK_QCOM diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile index 4cbe67ffeb5f..665ed6c84cc9 100644 --- a/drivers/clk/qcom/Makefile +++ b/drivers/clk/qcom/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_MSM_DEBUGCC_SDM845) += debugcc-sdm845.o obj-$(CONFIG_MSM_DISPCC_SDM845) += dispcc-sdm845.o obj-$(CONFIG_MSM_GPUCC_SDM845) += gpucc-sdm845.o obj-$(CONFIG_MSM_VIDEOCC_SDM845) += videocc-sdm845.o +obj-$(CONFIG_CLOCK_CPU_OSM_SDM845) += clk-cpu-osm-sdm845.o # Keep alphabetically sorted by config obj-$(CONFIG_APQ_GCC_8084) += gcc-apq8084.o diff --git a/drivers/clk/qcom/clk-cpu-osm-sdm845.c b/drivers/clk/qcom/clk-cpu-osm-sdm845.c new file mode 100644 index 000000000000..470b9d20e66e --- /dev/null +++ b/drivers/clk/qcom/clk-cpu-osm-sdm845.c @@ -0,0 +1,1411 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + */ + +#define pr_fmt(fmt) "clk: %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 "common.h" +#include "clk-regmap.h" +#include "clk-voter.h" +#include "clk-debug.h" + +#define OSM_INIT_RATE 300000000UL +#define XO_RATE 19200000UL +#define OSM_TABLE_SIZE 40 +#define SINGLE_CORE 1 +#define MAX_CLUSTER_CNT 3 +#define MAX_MEM_ACC_VAL_PER_LEVEL 3 +#define CORE_COUNT_VAL(val) ((val & GENMASK(18, 16)) >> 16) +#define CURRENT_LVAL(val) ((val & GENMASK(23, 16)) >> 16) + +#define OSM_REG_SIZE 32 + +#define ENABLE_REG 0x0 +#define FREQ_REG 0x110 +#define VOLT_REG 0x114 +#define CORE_DCVS_CTRL 0xbc +#define PSTATE_STATUS 0x700 + +#define DCVS_PERF_STATE_DESIRED_REG_0_V1 0x780 +#define DCVS_PERF_STATE_DESIRED_REG_0_V2 0x920 +#define DCVS_PERF_STATE_DESIRED_REG(n, v1) \ + (((v1) ? DCVS_PERF_STATE_DESIRED_REG_0_V1 \ + : DCVS_PERF_STATE_DESIRED_REG_0_V2) + 4 * (n)) + +#define OSM_CYCLE_COUNTER_STATUS_REG_0_V1 0x7d0 +#define OSM_CYCLE_COUNTER_STATUS_REG_0_V2 0x9c0 +#define OSM_CYCLE_COUNTER_STATUS_REG(n, v1) \ + (((v1) ? OSM_CYCLE_COUNTER_STATUS_REG_0_V1 \ + : OSM_CYCLE_COUNTER_STATUS_REG_0_V2) + 4 * (n)) + +static DEFINE_VDD_REGS_INIT(vdd_l3_mx_ao, 1); +static DEFINE_VDD_REGS_INIT(vdd_pwrcl_mx_ao, 1); + +struct osm_entry { + u16 virtual_corner; + u16 open_loop_volt; + unsigned long frequency; + u32 lval; + u16 ccount; +}; + +struct clk_osm { + struct clk_hw hw; + struct osm_entry osm_table[OSM_TABLE_SIZE]; + struct dentry *debugfs; + void __iomem *vbase; + phys_addr_t pbase; + spinlock_t lock; + bool per_core_dcvs; + u32 num_entries; + u32 cluster_num; + u32 core_num; + unsigned long rate; + u64 total_cycle_counter; + u32 prev_cycle_counter; + u32 max_core_count; + u32 mx_turbo_freq; +}; + +static bool is_sdm845v1; + +static inline struct clk_osm *to_clk_osm(struct clk_hw *_hw) +{ + return container_of(_hw, struct clk_osm, hw); +} + +static inline void clk_osm_write_reg(struct clk_osm *c, u32 val, u32 offset) +{ + writel_relaxed(val, c->vbase + offset); +} + +static inline int clk_osm_read_reg(struct clk_osm *c, u32 offset) +{ + return readl_relaxed(c->vbase + offset); +} + +static inline int clk_osm_read_reg_no_log(struct clk_osm *c, u32 offset) +{ + return readl_relaxed_no_log(c->vbase + offset); +} + +static inline int clk_osm_mb(struct clk_osm *c) +{ + return readl_relaxed_no_log(c->vbase + ENABLE_REG); +} + +static long clk_osm_list_rate(struct clk_hw *hw, unsigned int n, + unsigned long rate_max) +{ + if (n >= hw->init->num_rate_max) + return -ENXIO; + return hw->init->rate_max[n]; +} + +static inline bool is_better_rate(unsigned long req, unsigned long best, + unsigned long new) +{ + if (IS_ERR_VALUE(new)) + return false; + + return (req <= new && new < best) || (best < req && best < new); +} + +static int clk_osm_search_table(struct osm_entry *table, int entries, + unsigned long rate) +{ + int index; + + for (index = 0; index < entries; index++) { + if (rate == table[index].frequency) + return index; + } + + return -EINVAL; +} + +static int clk_osm_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_osm *c = to_clk_osm(hw); + + c->rate = rate; + + return 0; +} + +static unsigned long clk_osm_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_osm *c = to_clk_osm(hw); + + return c->rate; +} + +static int clk_osm_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + int i; + unsigned long rrate = 0; + unsigned long rate = req->rate; + + /* + * If the rate passed in is 0, return the first frequency in the + * FMAX table. + */ + if (!rate) { + req->rate = hw->init->rate_max[0]; + return 0; + } + + for (i = 0; i < hw->init->num_rate_max; i++) { + if (is_better_rate(rate, rrate, hw->init->rate_max[i])) { + rrate = hw->init->rate_max[i]; + if (rate == rrate) + break; + } + } + + req->rate = rrate; + + pr_debug("clk:%s rate %lu, rrate %lu, Rate max %lu index %u\n", + hw->init->name, rate, rrate, hw->init->rate_max[i], i); + + return 0; +} + +static int clk_cpu_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_osm *c = to_clk_osm(hw); + struct clk_hw *p_hw = clk_hw_get_parent(hw); + struct clk_osm *parent = to_clk_osm(p_hw); + int core_num, index = 0; + + if (!c || !parent) + return -EINVAL; + + index = clk_osm_search_table(parent->osm_table, + parent->num_entries, rate); + if (index < 0) { + pr_err("cannot set %s to %lu\n", clk_hw_get_name(hw), rate); + return -EINVAL; + } + + core_num = parent->per_core_dcvs ? c->core_num : 0; + clk_osm_write_reg(parent, index, + DCVS_PERF_STATE_DESIRED_REG(core_num, + is_sdm845v1)); + + /* Make sure the write goes through before proceeding */ + clk_osm_mb(parent); + + return 0; +} + +static int clk_pwrcl_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_hw *p_hw = clk_hw_get_parent(hw); + struct clk_osm *parent = to_clk_osm(p_hw); + int ret, index = 0, count = 40; + u32 curr_lval; + + ret = clk_cpu_set_rate(hw, rate, parent_rate); + if (ret) + return ret; + + index = clk_osm_search_table(parent->osm_table, + parent->num_entries, rate); + if (index < 0) + return -EINVAL; + + /* + * Poll the CURRENT_FREQUENCY value of the PSTATE_STATUS register to + * check if the L_VAL has been updated. + */ + while (count-- > 0) { + curr_lval = CURRENT_LVAL(clk_osm_read_reg(parent, + PSTATE_STATUS)); + if (curr_lval <= parent->osm_table[index].lval) + return 0; + udelay(50); + } + pr_err("cannot set %s to %lu\n", clk_hw_get_name(hw), rate); + return -ETIMEDOUT; +} + +static unsigned long clk_cpu_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_osm *c = to_clk_osm(hw); + struct clk_hw *p_hw = clk_hw_get_parent(hw); + struct clk_osm *parent = to_clk_osm(p_hw); + int core_num, index = 0; + + if (!c || !parent) + return -EINVAL; + + core_num = parent->per_core_dcvs ? c->core_num : 0; + index = clk_osm_read_reg(parent, + DCVS_PERF_STATE_DESIRED_REG(core_num, + is_sdm845v1)); + return parent->osm_table[index].frequency; +} + +static int clk_cpu_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct clk_hw *parent_hw = clk_hw_get_parent(hw); + unsigned long rate = req->rate; + + req->rate = clk_hw_round_rate(parent_hw, rate); + + return 0; +} + +static int l3_clk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_osm *cpuclk = to_clk_osm(hw); + struct clk_rate_request req; + int index = 0; + int count = 40; + u32 curr_lval; + + if (!cpuclk) + return -EINVAL; + + req.rate = rate; + clk_osm_determine_rate(hw, &req); + + if (rate != req.rate) { + pr_err("invalid requested rate=%ld\n", rate); + return -EINVAL; + } + + /* Convert rate to table index */ + index = clk_osm_search_table(cpuclk->osm_table, + cpuclk->num_entries, req.rate); + if (index < 0) { + pr_err("cannot set %s to %lu\n", clk_hw_get_name(hw), rate); + return -EINVAL; + } + pr_debug("rate: %lu --> index %d\n", rate, index); + + clk_osm_write_reg(cpuclk, index, + DCVS_PERF_STATE_DESIRED_REG(0, is_sdm845v1)); + + /* Make sure the write goes through before proceeding */ + clk_osm_mb(cpuclk); + + /* + * Poll the CURRENT_FREQUENCY value of the PSTATE_STATUS register to + * check if the L_VAL has been updated. + */ + if (cpuclk->rate >= cpuclk->mx_turbo_freq && + rate < cpuclk->mx_turbo_freq) { + while (count-- > 0) { + curr_lval = CURRENT_LVAL(clk_osm_read_reg(cpuclk, + PSTATE_STATUS)); + if (curr_lval <= cpuclk->osm_table[index].lval) { + cpuclk->rate = rate; + return 0; + } + udelay(50); + } + pr_err("cannot set %s to %lu\n", clk_hw_get_name(hw), rate); + return -ETIMEDOUT; + } + cpuclk->rate = rate; + return 0; +} + +static unsigned long l3_clk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_osm *cpuclk = to_clk_osm(hw); + int index = 0; + + if (!cpuclk) + return -EINVAL; + + index = clk_osm_read_reg(cpuclk, + DCVS_PERF_STATE_DESIRED_REG(0, is_sdm845v1)); + + pr_debug("%s: Index %d, freq %ld\n", __func__, index, + cpuclk->osm_table[index].frequency); + + /* Convert index to frequency */ + return cpuclk->osm_table[index].frequency; +} + +static const struct clk_ops clk_ops_l3_osm = { + .determine_rate = clk_osm_determine_rate, + .list_rate = clk_osm_list_rate, + .recalc_rate = l3_clk_recalc_rate, + .set_rate = l3_clk_set_rate, + .debug_init = clk_debug_measure_add, +}; + +static const struct clk_ops clk_ops_pwrcl_core = { + .set_rate = clk_pwrcl_set_rate, + .determine_rate = clk_cpu_determine_rate, + .recalc_rate = clk_cpu_recalc_rate, + .debug_init = clk_debug_measure_add, +}; + +static const struct clk_ops clk_ops_perfcl_core = { + .set_rate = clk_cpu_set_rate, + .determine_rate = clk_cpu_determine_rate, + .recalc_rate = clk_cpu_recalc_rate, + .debug_init = clk_debug_measure_add, +}; + +static const struct clk_ops clk_ops_cpu_osm = { + .set_rate = clk_osm_set_rate, + .recalc_rate = clk_osm_recalc_rate, + .list_rate = clk_osm_list_rate, + .determine_rate = clk_osm_determine_rate, + .debug_init = clk_debug_measure_add, +}; + +static struct clk_init_data osm_clks_init[] = { + [0] = { + .name = "l3_clk", + .parent_names = (const char *[]){ "bi_tcxo_ao" }, + .num_parents = 1, + .flags = CLK_CHILD_NO_RATE_PROP, + .ops = &clk_ops_l3_osm, + .vdd_class = &vdd_l3_mx_ao, + }, + [1] = { + .name = "pwrcl_clk", + .parent_names = (const char *[]){ "bi_tcxo_ao" }, + .num_parents = 1, + .ops = &clk_ops_cpu_osm, + .vdd_class = &vdd_pwrcl_mx_ao, + }, + [2] = { + .name = "perfcl_clk", + .parent_names = (const char *[]){ "bi_tcxo_ao" }, + .num_parents = 1, + .ops = &clk_ops_cpu_osm, + }, +}; + +static struct clk_osm l3_clk = { + .cluster_num = 0, + .max_core_count = 4, + .hw.init = &osm_clks_init[0], +}; + +static DEFINE_CLK_VOTER(l3_cluster0_vote_clk, l3_clk, 0); +static DEFINE_CLK_VOTER(l3_cluster1_vote_clk, l3_clk, 0); +static DEFINE_CLK_VOTER(l3_misc_vote_clk, l3_clk, 0); +static DEFINE_CLK_VOTER(l3_gpu_vote_clk, l3_clk, 0); + +static struct clk_osm pwrcl_clk = { + .cluster_num = 1, + .max_core_count = 4, + .hw.init = &osm_clks_init[1], +}; + +static struct clk_osm cpu0_pwrcl_clk = { + .core_num = 0, + .total_cycle_counter = 0, + .prev_cycle_counter = 0, + .hw.init = &(struct clk_init_data){ + .name = "cpu0_pwrcl_clk", + .parent_names = (const char *[]){ "pwrcl_clk" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_ops_pwrcl_core, + }, +}; + +static struct clk_osm cpu1_pwrcl_clk = { + .core_num = 1, + .total_cycle_counter = 0, + .prev_cycle_counter = 0, + .hw.init = &(struct clk_init_data){ + .name = "cpu1_pwrcl_clk", + .parent_names = (const char *[]){ "pwrcl_clk" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_ops_pwrcl_core, + }, +}; + +static struct clk_osm cpu2_pwrcl_clk = { + .core_num = 2, + .total_cycle_counter = 0, + .prev_cycle_counter = 0, + .hw.init = &(struct clk_init_data){ + .name = "cpu2_pwrcl_clk", + .parent_names = (const char *[]){ "pwrcl_clk" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_ops_pwrcl_core, + }, +}; + +static struct clk_osm cpu3_pwrcl_clk = { + .core_num = 3, + .total_cycle_counter = 0, + .prev_cycle_counter = 0, + .hw.init = &(struct clk_init_data){ + .name = "cpu3_pwrcl_clk", + .parent_names = (const char *[]){ "pwrcl_clk" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_ops_pwrcl_core, + }, +}; + +static struct clk_osm cpu4_pwrcl_clk = { + .core_num = 4, + .total_cycle_counter = 0, + .prev_cycle_counter = 0, + .hw.init = &(struct clk_init_data){ + .name = "cpu4_pwrcl_clk", + .parent_names = (const char *[]){ "pwrcl_clk" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_ops_pwrcl_core, + }, +}; + +static struct clk_osm cpu5_pwrcl_clk = { + .core_num = 5, + .total_cycle_counter = 0, + .prev_cycle_counter = 0, + .hw.init = &(struct clk_init_data){ + .name = "cpu5_pwrcl_clk", + .parent_names = (const char *[]){ "pwrcl_clk" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_ops_pwrcl_core, + }, +}; + +static struct clk_osm perfcl_clk = { + .cluster_num = 2, + .max_core_count = 4, + .hw.init = &osm_clks_init[2], +}; + + +static struct clk_osm cpu4_perfcl_clk = { + .core_num = 0, + .total_cycle_counter = 0, + .prev_cycle_counter = 0, + .hw.init = &(struct clk_init_data){ + .name = "cpu4_perfcl_clk", + .parent_names = (const char *[]){ "perfcl_clk" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_ops_perfcl_core, + }, +}; + +static struct clk_osm cpu5_perfcl_clk = { + .core_num = 1, + .total_cycle_counter = 0, + .prev_cycle_counter = 0, + .hw.init = &(struct clk_init_data){ + .name = "cpu5_perfcl_clk", + .parent_names = (const char *[]){ "perfcl_clk" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_ops_perfcl_core, + }, +}; + +static struct clk_osm cpu6_perfcl_clk = { + .core_num = 2, + .total_cycle_counter = 0, + .prev_cycle_counter = 0, + .hw.init = &(struct clk_init_data){ + .name = "cpu6_perfcl_clk", + .parent_names = (const char *[]){ "perfcl_clk" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_ops_perfcl_core, + }, +}; + +static struct clk_osm cpu7_perfcl_clk = { + .core_num = 3, + .total_cycle_counter = 0, + .prev_cycle_counter = 0, + .hw.init = &(struct clk_init_data){ + .name = "cpu7_perfcl_clk", + .parent_names = (const char *[]){ "perfcl_clk" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + .ops = &clk_ops_perfcl_core, + }, +}; + +static struct clk_hw *osm_qcom_clk_hws[] = { + [L3_CLK] = &l3_clk.hw, + [L3_CLUSTER0_VOTE_CLK] = &l3_cluster0_vote_clk.hw, + [L3_CLUSTER1_VOTE_CLK] = &l3_cluster1_vote_clk.hw, + [L3_MISC_VOTE_CLK] = &l3_misc_vote_clk.hw, + [L3_GPU_VOTE_CLK] = &l3_gpu_vote_clk.hw, + [PWRCL_CLK] = &pwrcl_clk.hw, + [CPU0_PWRCL_CLK] = &cpu0_pwrcl_clk.hw, + [CPU1_PWRCL_CLK] = &cpu1_pwrcl_clk.hw, + [CPU2_PWRCL_CLK] = &cpu2_pwrcl_clk.hw, + [CPU3_PWRCL_CLK] = &cpu3_pwrcl_clk.hw, + [PERFCL_CLK] = &perfcl_clk.hw, + [CPU4_PERFCL_CLK] = &cpu4_perfcl_clk.hw, + [CPU5_PERFCL_CLK] = &cpu5_perfcl_clk.hw, + [CPU6_PERFCL_CLK] = &cpu6_perfcl_clk.hw, + [CPU7_PERFCL_CLK] = &cpu7_perfcl_clk.hw, + [CPU4_PWRCL_CLK] = NULL, + [CPU5_PWRCL_CLK] = NULL, +}; + +static struct clk_osm *clk_cpu_map[] = { + &cpu0_pwrcl_clk, + &cpu1_pwrcl_clk, + &cpu2_pwrcl_clk, + &cpu3_pwrcl_clk, + &cpu4_perfcl_clk, + &cpu5_perfcl_clk, + &cpu6_perfcl_clk, + &cpu7_perfcl_clk, +}; + +static struct clk_osm *logical_cpu_to_clk(int cpu) +{ + struct device_node *cpu_node; + const u32 *cell; + u64 hwid; + static struct clk_osm *cpu_clk_map[NR_CPUS]; + + if (!cpu_clk_map[cpu]) { + cpu_node = of_get_cpu_node(cpu, NULL); + if (!cpu_node) + return NULL; + + cell = of_get_property(cpu_node, "reg", NULL); + if (!cell) { + pr_err("%s: missing reg property\n", + cpu_node->full_name); + of_node_put(cpu_node); + return NULL; + } + + hwid = of_read_number(cell, of_n_addr_cells(cpu_node)); + hwid = (hwid >> 8) & 0xff; + of_node_put(cpu_node); + if (hwid >= ARRAY_SIZE(clk_cpu_map)) { + pr_err("unsupported CPU number - %d (hw_id - %llu)\n", + cpu, hwid); + return NULL; + } + + cpu_clk_map[cpu] = clk_cpu_map[hwid]; + } + + return cpu_clk_map[cpu]; +} + +static struct clk_osm *osm_configure_policy(struct cpufreq_policy *policy) +{ + int cpu; + struct clk_hw *parent, *c_parent; + struct clk_osm *first; + struct clk_osm *c, *n; + + c = logical_cpu_to_clk(policy->cpu); + if (!c) + return NULL; + + c_parent = clk_hw_get_parent(&c->hw); + if (!c_parent) + return NULL; + + /* + * Don't put any other CPUs into the policy if we're doing + * per_core_dcvs + */ + if (to_clk_osm(c_parent)->per_core_dcvs) + return c; + + first = c; + /* Find CPUs that share the same clock domain */ + for_each_possible_cpu(cpu) { + n = logical_cpu_to_clk(cpu); + if (!n) + continue; + + parent = clk_hw_get_parent(&n->hw); + if (!parent) + return NULL; + if (parent != c_parent) + continue; + + cpumask_set_cpu(cpu, policy->cpus); + if (n->core_num == 0) + first = n; + } + + return first; +} + +static void +osm_set_index(struct clk_osm *c, unsigned int index) +{ + struct clk_hw *p_hw = clk_hw_get_parent(&c->hw); + struct clk_osm *parent = to_clk_osm(p_hw); + unsigned long rate = 0; + + if (index >= OSM_TABLE_SIZE) { + pr_err("Passing an index (%u) that's greater than max (%d)\n", + index, OSM_TABLE_SIZE - 1); + return; + } + + rate = parent->osm_table[index].frequency; + if (!rate) + return; + + clk_set_rate(c->hw.clk, clk_round_rate(c->hw.clk, rate)); +} + +static int +osm_cpufreq_target_index(struct cpufreq_policy *policy, unsigned int index) +{ + struct clk_osm *c = policy->driver_data; + + osm_set_index(c, index); + return 0; +} + +static unsigned int osm_cpufreq_get(unsigned int cpu) +{ + struct cpufreq_policy *policy = cpufreq_cpu_get_raw(cpu); + struct clk_osm *c; + u32 index; + + if (!policy) + return 0; + + c = policy->driver_data; + index = clk_osm_read_reg(c, + DCVS_PERF_STATE_DESIRED_REG(c->core_num, is_sdm845v1)); + return policy->freq_table[index].frequency; +} + +static int osm_cpufreq_cpu_init(struct cpufreq_policy *policy) +{ + struct cpufreq_frequency_table *table; + struct clk_osm *c, *parent; + struct clk_hw *p_hw; + int ret; + unsigned int i, prev_cc = 0; + unsigned int xo_kHz; + + c = osm_configure_policy(policy); + if (!c) { + pr_err("no clock for CPU%d\n", policy->cpu); + return -ENODEV; + } + + p_hw = clk_hw_get_parent(&c->hw); + if (!p_hw) { + pr_err("no parent clock for CPU%d\n", policy->cpu); + return -ENODEV; + } + + parent = to_clk_osm(p_hw); + c->vbase = parent->vbase; + + p_hw = clk_hw_get_parent(p_hw); + if (!p_hw) { + pr_err("no xo clock for CPU%d\n", policy->cpu); + return -ENODEV; + } + xo_kHz = clk_hw_get_rate(p_hw) / 1000; + + table = kcalloc(OSM_TABLE_SIZE + 1, sizeof(*table), GFP_KERNEL); + if (!table) + return -ENOMEM; + + for (i = 0; i < OSM_TABLE_SIZE; i++) { + u32 data, src, div, lval, core_count; + + data = clk_osm_read_reg(c, FREQ_REG + i * OSM_REG_SIZE); + src = (data & GENMASK(31, 30)) >> 30; + div = (data & GENMASK(29, 28)) >> 28; + lval = data & GENMASK(7, 0); + core_count = CORE_COUNT_VAL(data); + + if (!src) + table[i].frequency = OSM_INIT_RATE / 1000; + else + table[i].frequency = xo_kHz * lval; + table[i].driver_data = table[i].frequency; + + if (core_count != parent->max_core_count) + table[i].frequency = CPUFREQ_ENTRY_INVALID; + + /* + * Two of the same frequencies with the same core counts means + * end of table. + */ + if (i > 0 && table[i - 1].driver_data == table[i].driver_data + && prev_cc == core_count) { + struct cpufreq_frequency_table *prev = &table[i - 1]; + + if (prev->frequency == CPUFREQ_ENTRY_INVALID) { + prev->flags = CPUFREQ_BOOST_FREQ; + prev->frequency = prev->driver_data; + } + + break; + } + prev_cc = core_count; + } + table[i].frequency = CPUFREQ_TABLE_END; + + ret = cpufreq_table_validate_and_show(policy, table); + if (ret) { + pr_err("%s: invalid frequency table: %d\n", __func__, ret); + goto err; + } + + policy->driver_data = c; + return 0; + +err: + kfree(table); + return ret; +} + +static int osm_cpufreq_cpu_exit(struct cpufreq_policy *policy) +{ + kfree(policy->freq_table); + policy->freq_table = NULL; + return 0; +} + +static struct freq_attr *osm_cpufreq_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, + &cpufreq_freq_attr_scaling_boost_freqs, + NULL +}; + +static struct cpufreq_driver qcom_osm_cpufreq_driver = { + .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK | + CPUFREQ_HAVE_GOVERNOR_PER_POLICY, + .verify = cpufreq_generic_frequency_table_verify, + .target_index = osm_cpufreq_target_index, + .get = osm_cpufreq_get, + .init = osm_cpufreq_cpu_init, + .exit = osm_cpufreq_cpu_exit, + .name = "osm-cpufreq", + .attr = osm_cpufreq_attr, + .boost_enabled = true, +}; + +static u32 find_voltage(struct clk_osm *c, unsigned long rate) +{ + struct osm_entry *table = c->osm_table; + int entries = c->num_entries, i; + + for (i = 0; i < entries; i++) { + if (rate == table[i].frequency) { + /* OPP table voltages have units of mV */ + return table[i].open_loop_volt * 1000; + } + } + + return -EINVAL; +} + +static int add_opp(struct clk_osm *c, struct device **device_list, int count) +{ + unsigned long rate = 0; + u32 uv; + long rc; + int i, j = 0; + unsigned long min_rate = c->hw.init->rate_max[0]; + unsigned long max_rate = + c->hw.init->rate_max[c->hw.init->num_rate_max - 1]; + + while (1) { + rate = c->hw.init->rate_max[j++]; + uv = find_voltage(c, rate); + if (uv <= 0) { + pr_warn("No voltage for %lu.\n", rate); + return -EINVAL; + } + + for (i = 0; i < count; i++) { + rc = dev_pm_opp_add(device_list[i], rate, uv); + if (rc) { + pr_warn("failed to add OPP for %lu\n", rate); + return rc; + } + } + + /* + * Print the OPP pair for the lowest and highest frequency for + * each device that we're populating. This is important since + * this information will be used by thermal mitigation and the + * scheduler. + */ + if (rate == min_rate) { + for (i = 0; i < count; i++) { + pr_info("Set OPP pair (%lu Hz, %d uv) on %s\n", + rate, uv, dev_name(device_list[i])); + } + } + + if (rate == max_rate && max_rate != min_rate) { + for (i = 0; i < count; i++) { + pr_info("Set OPP pair (%lu Hz, %d uv) on %s\n", + rate, uv, dev_name(device_list[i])); + } + break; + } + + if (min_rate == max_rate) + break; + } + return 0; +} + +static int derive_device_list(struct device **device_list, + struct device_node *np, + char *phandle_name, int count) +{ + int i; + struct platform_device *pdev; + struct device_node *dev_node; + + for (i = 0; i < count; i++) { + dev_node = of_parse_phandle(np, phandle_name, i); + if (!dev_node) { + pr_err("Unable to get device_node pointer for opp-handle (%s)\n", + phandle_name); + return -ENODEV; + } + + pdev = of_find_device_by_node(dev_node); + if (!pdev) { + pr_err("Unable to find platform_device node for opp-handle (%s)\n", + phandle_name); + return -ENODEV; + } + device_list[i] = &pdev->dev; + } + return 0; +} + +static void populate_l3_opp_table(struct device_node *np, char *phandle_name) +{ + struct device **device_list; + int len, count, ret = 0; + + if (of_find_property(np, phandle_name, &len)) { + count = len / sizeof(u32); + + device_list = kcalloc(count, sizeof(struct device *), + GFP_KERNEL); + if (!device_list) + return; + + ret = derive_device_list(device_list, np, phandle_name, count); + if (ret < 0) { + pr_err("Failed to fill device_list for %s\n", + phandle_name); + return; + } + } else { + pr_debug("Unable to find %s\n", phandle_name); + return; + } + + if (add_opp(&l3_clk, device_list, count)) + pr_err("Failed to add OPP levels for %s\n", phandle_name); + + kfree(device_list); +} + +static void populate_opp_table(struct platform_device *pdev) +{ + int cpu; + struct device *cpu_dev; + struct clk_osm *c, *parent; + struct clk_hw *hw_parent; + struct device_node *np = pdev->dev.of_node; + + for_each_possible_cpu(cpu) { + c = logical_cpu_to_clk(cpu); + if (!c) { + pr_err("no clock device for CPU=%d\n", cpu); + return; + } + + hw_parent = clk_hw_get_parent(&c->hw); + parent = to_clk_osm(hw_parent); + cpu_dev = get_cpu_device(cpu); + if (cpu_dev) + if (add_opp(parent, &cpu_dev, 1)) + pr_err("Failed to add OPP levels for %s\n", + dev_name(cpu_dev)); + } + + populate_l3_opp_table(np, "l3-devs"); +} + +static u64 clk_osm_get_cpu_cycle_counter(int cpu) +{ + u32 val; + int core_num; + unsigned long flags; + u64 cycle_counter_ret; + struct clk_osm *parent, *c = logical_cpu_to_clk(cpu); + + if (IS_ERR_OR_NULL(c)) { + pr_err("no clock device for CPU=%d\n", cpu); + return 0; + } + + parent = to_clk_osm(clk_hw_get_parent(&c->hw)); + + spin_lock_irqsave(&parent->lock, flags); + /* + * Use core 0's copy as proxy for the whole cluster when per + * core DCVS is disabled. + */ + core_num = parent->per_core_dcvs ? c->core_num : 0; + val = clk_osm_read_reg_no_log(parent, + OSM_CYCLE_COUNTER_STATUS_REG(core_num, is_sdm845v1)); + + if (val < c->prev_cycle_counter) { + /* Handle counter overflow */ + c->total_cycle_counter += UINT_MAX - + c->prev_cycle_counter + val; + c->prev_cycle_counter = val; + } else { + c->total_cycle_counter += val - c->prev_cycle_counter; + c->prev_cycle_counter = val; + } + cycle_counter_ret = c->total_cycle_counter; + spin_unlock_irqrestore(&parent->lock, flags); + + return cycle_counter_ret; +} + +static int clk_osm_read_lut(struct platform_device *pdev, struct clk_osm *c) +{ + u32 data, src, lval, i, j = OSM_TABLE_SIZE; + struct clk_vdd_class *vdd = osm_clks_init[c->cluster_num].vdd_class; + + for (i = 0; i < OSM_TABLE_SIZE; i++) { + data = clk_osm_read_reg(c, FREQ_REG + i * OSM_REG_SIZE); + src = ((data & GENMASK(31, 30)) >> 30); + lval = (data & GENMASK(7, 0)); + c->osm_table[i].ccount = CORE_COUNT_VAL(data); + c->osm_table[i].lval = lval; + + if (!src) + c->osm_table[i].frequency = OSM_INIT_RATE; + else + c->osm_table[i].frequency = XO_RATE * lval; + + data = clk_osm_read_reg(c, VOLT_REG + i * OSM_REG_SIZE); + c->osm_table[i].virtual_corner = + ((data & GENMASK(21, 16)) >> 16); + c->osm_table[i].open_loop_volt = (data & GENMASK(11, 0)); + + pr_debug("index=%d freq=%ld virtual_corner=%d open_loop_voltage=%u\n", + i, c->osm_table[i].frequency, + c->osm_table[i].virtual_corner, + c->osm_table[i].open_loop_volt); + + if (i > 0 && j == OSM_TABLE_SIZE && + c->osm_table[i].frequency == + c->osm_table[i - 1].frequency && + c->osm_table[i].ccount == c->osm_table[i - 1].ccount) + j = i; + } + + osm_clks_init[c->cluster_num].rate_max = devm_kcalloc(&pdev->dev, + j, sizeof(unsigned long), + GFP_KERNEL); + if (!osm_clks_init[c->cluster_num].rate_max) + return -ENOMEM; + + if (vdd) { + vdd->level_votes = devm_kcalloc(&pdev->dev, j, + sizeof(*vdd->level_votes), GFP_KERNEL); + if (!vdd->level_votes) + return -ENOMEM; + + vdd->vdd_uv = devm_kcalloc(&pdev->dev, j, sizeof(*vdd->vdd_uv), + GFP_KERNEL); + if (!vdd->vdd_uv) + return -ENOMEM; + + for (i = 0; i < j; i++) { + if (c->osm_table[i].frequency < c->mx_turbo_freq) + vdd->vdd_uv[i] = RPMH_REGULATOR_LEVEL_NOM; + else + vdd->vdd_uv[i] = RPMH_REGULATOR_LEVEL_TURBO; + } + vdd->num_levels = j; + vdd->cur_level = j; + vdd->use_max_uV = true; + } + + for (i = 0; i < j; i++) + osm_clks_init[c->cluster_num].rate_max[i] = + c->osm_table[i].frequency; + + c->num_entries = osm_clks_init[c->cluster_num].num_rate_max = j; + return 0; +} + +static int clk_osm_resources_init(struct platform_device *pdev) +{ + struct resource *res; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "osm_l3_base"); + if (!res) { + dev_err(&pdev->dev, + "Unable to get platform resource for osm_l3_base"); + return -ENOMEM; + } + + l3_clk.pbase = (unsigned long)res->start; + l3_clk.vbase = devm_ioremap(&pdev->dev, res->start, resource_size(res)); + + if (!l3_clk.vbase) { + dev_err(&pdev->dev, "Unable to map osm_l3_base base\n"); + return -ENOMEM; + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "osm_pwrcl_base"); + if (!res) { + dev_err(&pdev->dev, + "Unable to get platform resource for osm_pwrcl_base"); + return -ENOMEM; + } + + pwrcl_clk.pbase = (unsigned long)res->start; + pwrcl_clk.vbase = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + if (!pwrcl_clk.vbase) { + dev_err(&pdev->dev, "Unable to map osm_pwrcl_base base\n"); + return -ENOMEM; + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "osm_perfcl_base"); + if (!res) { + dev_err(&pdev->dev, + "Unable to get platform resource for osm_perfcl_base"); + return -ENOMEM; + } + + perfcl_clk.pbase = (unsigned long)res->start; + perfcl_clk.vbase = devm_ioremap(&pdev->dev, res->start, + resource_size(res)); + + if (!perfcl_clk.vbase) { + dev_err(&pdev->dev, "Unable to map osm_perfcl_base base\n"); + return -ENOMEM; + } + + return 0; +} + +static void clk_cpu_osm_driver_sdm670_fixup(void) +{ + osm_qcom_clk_hws[CPU4_PERFCL_CLK] = NULL; + osm_qcom_clk_hws[CPU5_PERFCL_CLK] = NULL; + osm_qcom_clk_hws[CPU4_PWRCL_CLK] = &cpu4_pwrcl_clk.hw; + osm_qcom_clk_hws[CPU5_PWRCL_CLK] = &cpu5_pwrcl_clk.hw; + + clk_cpu_map[4] = &cpu4_pwrcl_clk; + clk_cpu_map[5] = &cpu5_pwrcl_clk; + + cpu6_perfcl_clk.core_num = 0; + cpu7_perfcl_clk.core_num = 1; + + pwrcl_clk.max_core_count = 6; + perfcl_clk.max_core_count = 2; +} + +/* Request MX supply if configured in device tree */ +static int clk_cpu_osm_request_mx_supply(struct device *dev) +{ + u32 *array; + int rc; + + if (!of_find_property(dev->of_node, "qcom,mx-turbo-freq", NULL)) { + osm_clks_init[l3_clk.cluster_num].vdd_class = NULL; + osm_clks_init[pwrcl_clk.cluster_num].vdd_class = NULL; + return 0; + } + + vdd_l3_mx_ao.regulator[0] = devm_regulator_get(dev, "vdd_l3_mx_ao"); + if (IS_ERR(vdd_l3_mx_ao.regulator[0])) { + rc = PTR_ERR(vdd_l3_mx_ao.regulator[0]); + if (rc != -EPROBE_DEFER) + dev_err(dev, "Unable to get vdd_l3_mx_ao regulator, rc=%d\n", + rc); + return rc; + } + + vdd_pwrcl_mx_ao.regulator[0] = devm_regulator_get(dev, + "vdd_pwrcl_mx_ao"); + if (IS_ERR(vdd_pwrcl_mx_ao.regulator[0])) { + rc = PTR_ERR(vdd_pwrcl_mx_ao.regulator[0]); + if (rc != -EPROBE_DEFER) + dev_err(dev, "Unable to get vdd_pwrcl_mx_ao regulator, rc=%d\n", + rc); + return rc; + } + + array = kcalloc(MAX_CLUSTER_CNT, sizeof(*array), GFP_KERNEL); + if (!array) + return -ENOMEM; + + rc = of_property_read_u32_array(dev->of_node, "qcom,mx-turbo-freq", + array, MAX_CLUSTER_CNT); + if (rc) { + dev_err(dev, "unable to read qcom,mx-turbo-freq property, rc=%d\n", + rc); + kfree(array); + return rc; + } + + l3_clk.mx_turbo_freq = array[l3_clk.cluster_num]; + pwrcl_clk.mx_turbo_freq = array[pwrcl_clk.cluster_num]; + perfcl_clk.mx_turbo_freq = array[perfcl_clk.cluster_num]; + + kfree(array); + + return 0; +} + +static int clk_cpu_osm_driver_probe(struct platform_device *pdev) +{ + int rc = 0, i, cpu; + u32 val; + int num_clks = ARRAY_SIZE(osm_qcom_clk_hws); + struct clk *ext_xo_clk, *clk; + struct clk_osm *osm_clk; + struct device *dev = &pdev->dev; + struct clk_onecell_data *clk_data; + struct cpu_cycle_counter_cb cb = { + .get_cpu_cycle_counter = clk_osm_get_cpu_cycle_counter, + }; + + /* + * Require the RPM-XO clock to be registered before OSM. + * The cpuss_gpll0_clk_src is listed to be configured by BL. + */ + ext_xo_clk = devm_clk_get(dev, "xo_ao"); + if (IS_ERR(ext_xo_clk)) { + if (PTR_ERR(ext_xo_clk) != -EPROBE_DEFER) + dev_err(dev, "Unable to get xo clock\n"); + return PTR_ERR(ext_xo_clk); + } + + is_sdm845v1 = of_device_is_compatible(pdev->dev.of_node, + "qcom,clk-cpu-osm"); + + if (of_device_is_compatible(pdev->dev.of_node, + "qcom,clk-cpu-osm-sdm670")) + clk_cpu_osm_driver_sdm670_fixup(); + + rc = clk_cpu_osm_request_mx_supply(dev); + if (rc) + return rc; + + clk_data = devm_kzalloc(&pdev->dev, sizeof(struct clk_onecell_data), + GFP_KERNEL); + if (!clk_data) + goto exit; + + clk_data->clks = devm_kzalloc(&pdev->dev, (num_clks * + sizeof(struct clk *)), GFP_KERNEL); + if (!clk_data->clks) + goto clk_err; + + clk_data->clk_num = num_clks; + + rc = clk_osm_resources_init(pdev); + if (rc) { + if (rc != -EPROBE_DEFER) + dev_err(&pdev->dev, "OSM resources init failed, rc=%d\n", + rc); + return rc; + } + + /* Check if per-core DCVS is enabled/not */ + val = clk_osm_read_reg(&pwrcl_clk, CORE_DCVS_CTRL); + if (val & BIT(0)) + pwrcl_clk.per_core_dcvs = true; + + val = clk_osm_read_reg(&perfcl_clk, CORE_DCVS_CTRL); + if (val & BIT(0)) + perfcl_clk.per_core_dcvs = true; + + rc = clk_osm_read_lut(pdev, &l3_clk); + if (rc) { + dev_err(&pdev->dev, "Unable to read OSM LUT for L3, rc=%d\n", + rc); + return rc; + } + + rc = clk_osm_read_lut(pdev, &pwrcl_clk); + if (rc) { + dev_err(&pdev->dev, "Unable to read OSM LUT for power cluster, rc=%d\n", + rc); + return rc; + } + + rc = clk_osm_read_lut(pdev, &perfcl_clk); + if (rc) { + dev_err(&pdev->dev, "Unable to read OSM LUT for perf cluster, rc=%d\n", + rc); + return rc; + } + + spin_lock_init(&l3_clk.lock); + spin_lock_init(&pwrcl_clk.lock); + spin_lock_init(&perfcl_clk.lock); + + /* Register OSM l3, pwr and perf clocks with Clock Framework */ + for (i = 0; i < num_clks; i++) { + if (!osm_qcom_clk_hws[i]) + continue; + + clk = devm_clk_register(&pdev->dev, osm_qcom_clk_hws[i]); + if (IS_ERR(clk)) { + dev_err(&pdev->dev, "Unable to register CPU clock at index %d\n", + i); + return PTR_ERR(clk); + } + clk_data->clks[i] = clk; + } + + rc = of_clk_add_provider(pdev->dev.of_node, of_clk_src_onecell_get, + clk_data); + if (rc) { + dev_err(&pdev->dev, "Unable to register CPU clocks\n"); + goto provider_err; + } + + get_online_cpus(); + + WARN(clk_prepare_enable(l3_cluster0_vote_clk.hw.clk), + "clk: Failed to enable cluster0 clock for L3\n"); + WARN(clk_prepare_enable(l3_cluster1_vote_clk.hw.clk), + "clk: Failed to enable cluster1 clock for L3\n"); + WARN(clk_prepare_enable(l3_misc_vote_clk.hw.clk), + "clk: Failed to enable misc clock for L3\n"); + WARN(clk_prepare_enable(l3_gpu_vote_clk.hw.clk), + "clk: Failed to enable iocoherent bwmon clock for L3\n"); + + /* + * Call clk_prepare_enable for the silver clock explicitly in order to + * place an implicit vote on MX + */ + for_each_online_cpu(cpu) { + osm_clk = logical_cpu_to_clk(cpu); + if (!osm_clk) + return -EINVAL; + clk_prepare_enable(osm_clk->hw.clk); + } + populate_opp_table(pdev); + + of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); + register_cpu_cycle_counter_cb(&cb); + put_online_cpus(); + + rc = cpufreq_register_driver(&qcom_osm_cpufreq_driver); + if (rc) + goto provider_err; + + pr_info("OSM CPUFreq driver inited\n"); + return 0; + +provider_err: + if (clk_data) + devm_kfree(&pdev->dev, clk_data->clks); +clk_err: + devm_kfree(&pdev->dev, clk_data); +exit: + dev_err(&pdev->dev, "OSM CPUFreq driver failed to initialize, rc=%d\n", + rc); + panic("Unable to Setup OSM CPUFreq"); +} + +static const struct of_device_id match_table[] = { + { .compatible = "qcom,clk-cpu-osm" }, + { .compatible = "qcom,clk-cpu-osm-v2" }, + { .compatible = "qcom,clk-cpu-osm-sdm670" }, + {} +}; + +static struct platform_driver clk_cpu_osm_driver = { + .probe = clk_cpu_osm_driver_probe, + .driver = { + .name = "clk-cpu-osm", + .of_match_table = match_table, + .owner = THIS_MODULE, + }, +}; + +static int __init clk_cpu_osm_init(void) +{ + return platform_driver_register(&clk_cpu_osm_driver); +} +subsys_initcall(clk_cpu_osm_init); + +static void __exit clk_cpu_osm_exit(void) +{ + platform_driver_unregister(&clk_cpu_osm_driver); +} +module_exit(clk_cpu_osm_exit); + +MODULE_DESCRIPTION("QTI CPU clock driver for OSM"); +MODULE_LICENSE("GPL v2"); diff --git a/include/dt-bindings/clock/qcom,cpucc-sdm845.h b/include/dt-bindings/clock/qcom,cpucc-sdm845.h new file mode 100644 index 000000000000..f694c222c2b9 --- /dev/null +++ b/include/dt-bindings/clock/qcom,cpucc-sdm845.h @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2017, The Linux Foundation. All rights reserved. + */ + +#ifndef _DT_BINDINGS_CLK_MSM_CPU_CC_SDM845_H +#define _DT_BINDINGS_CLK_MSM_CPU_CC_SDM845_H + +#define L3_CLK 0 +#define PWRCL_CLK 1 +#define PERFCL_CLK 2 +#define L3_CLUSTER0_VOTE_CLK 3 +#define L3_CLUSTER1_VOTE_CLK 4 +#define CPU0_PWRCL_CLK 5 +#define CPU1_PWRCL_CLK 6 +#define CPU2_PWRCL_CLK 7 +#define CPU3_PWRCL_CLK 8 +#define CPU4_PERFCL_CLK 9 +#define CPU5_PERFCL_CLK 10 +#define CPU6_PERFCL_CLK 11 +#define CPU7_PERFCL_CLK 12 +#define L3_MISC_VOTE_CLK 13 +#define CPU4_PWRCL_CLK 14 +#define CPU5_PWRCL_CLK 15 +#define L3_GPU_VOTE_CLK 16 + +#endif From 045ef867c94debc1952a4204da811770ddf5957c Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Fri, 5 Nov 2021 21:36:31 +0200 Subject: [PATCH 085/356] clk: qcom: cpu-osm-sdm845: Update header for voltage levels constants RPMh regulator voltage level constans are now located in qcom,rpmh-regulator-levels.h header. Signed-off-by: Pavel Dubrova --- drivers/clk/qcom/clk-cpu-osm-sdm845.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/qcom/clk-cpu-osm-sdm845.c b/drivers/clk/qcom/clk-cpu-osm-sdm845.c index 470b9d20e66e..c8cc9008f85f 100644 --- a/drivers/clk/qcom/clk-cpu-osm-sdm845.c +++ b/drivers/clk/qcom/clk-cpu-osm-sdm845.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include "common.h" #include "clk-regmap.h" From 699098a5c799eea71c22eaf3eeb111b23a5e64bd Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Fri, 5 Nov 2021 21:37:37 +0200 Subject: [PATCH 086/356] clk: qcom: cpu-osm-sdm845: Remove use_max_uV for voting The clock framework always vote INT_MAX as the max corner for any voltage rail. Signed-off-by: Pavel Dubrova --- drivers/clk/qcom/clk-cpu-osm-sdm845.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/clk/qcom/clk-cpu-osm-sdm845.c b/drivers/clk/qcom/clk-cpu-osm-sdm845.c index c8cc9008f85f..2483b53dd910 100644 --- a/drivers/clk/qcom/clk-cpu-osm-sdm845.c +++ b/drivers/clk/qcom/clk-cpu-osm-sdm845.c @@ -1087,7 +1087,6 @@ static int clk_osm_read_lut(struct platform_device *pdev, struct clk_osm *c) } vdd->num_levels = j; vdd->cur_level = j; - vdd->use_max_uV = true; } for (i = 0; i < j; i++) From 20ccaa5ccf5f6db2e136e2f9516d3ae276e5c6b8 Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Fri, 5 Nov 2021 21:42:46 +0200 Subject: [PATCH 087/356] clk: qcom: cpu-osm-sdm845: Don't validate the frequency table twice The cpufreq core is already validating the CPU frequency table after calling the ->init() callback of the cpufreq drivers and the drivers don't need to do the same anymore. Though they need to set the policy->freq_table field directly from the ->init() callback now. Signed-off-by: Pavel Dubrova --- drivers/clk/qcom/clk-cpu-osm-sdm845.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/drivers/clk/qcom/clk-cpu-osm-sdm845.c b/drivers/clk/qcom/clk-cpu-osm-sdm845.c index 2483b53dd910..b1afa58cf851 100644 --- a/drivers/clk/qcom/clk-cpu-osm-sdm845.c +++ b/drivers/clk/qcom/clk-cpu-osm-sdm845.c @@ -730,7 +730,6 @@ static int osm_cpufreq_cpu_init(struct cpufreq_policy *policy) struct cpufreq_frequency_table *table; struct clk_osm *c, *parent; struct clk_hw *p_hw; - int ret; unsigned int i, prev_cc = 0; unsigned int xo_kHz; @@ -797,18 +796,9 @@ static int osm_cpufreq_cpu_init(struct cpufreq_policy *policy) } table[i].frequency = CPUFREQ_TABLE_END; - ret = cpufreq_table_validate_and_show(policy, table); - if (ret) { - pr_err("%s: invalid frequency table: %d\n", __func__, ret); - goto err; - } - + policy->freq_table = table; policy->driver_data = c; return 0; - -err: - kfree(table); - return ret; } static int osm_cpufreq_cpu_exit(struct cpufreq_policy *policy) From 88c95a7323ce578c5240700d35c2e348bb3313b0 Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Sun, 7 Nov 2021 00:21:20 +0200 Subject: [PATCH 088/356] clk: qcom: dispcc-sdm845: Update dp phy pll clock names Clock names have been changed as of https://source.codeaurora.org/quic/la/platform/vendor/opensource/display-drivers commit cbe6ebb ("disp: pll: update clk names for lagoon target"). dp_link_clk_divsel_ten -> dp_phy_pll_link_clk dp_vco_divided_clk_src_mux -> dp_phy_pll_vco_div_clk Signed-off-by: Pavel Dubrova --- drivers/clk/qcom/dispcc-sdm845.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/qcom/dispcc-sdm845.c b/drivers/clk/qcom/dispcc-sdm845.c index b987f487b1c7..0c9709da7297 100644 --- a/drivers/clk/qcom/dispcc-sdm845.c +++ b/drivers/clk/qcom/dispcc-sdm845.c @@ -72,8 +72,8 @@ static const struct parent_map disp_cc_parent_map_1[] = { static const char * const disp_cc_parent_names_1[] = { "bi_tcxo", - "dp_link_clk_divsel_ten", - "dp_vco_divided_clk_src_mux", + "dp_phy_pll_link_clk", + "dp_phy_pll_vco_div_clk", "core_bi_pll_test_se", }; From adf42a408c959c34b47a0f8c8ca9d8263464a3d8 Mon Sep 17 00:00:00 2001 From: Deepak Katragadda Date: Fri, 11 Nov 2016 11:37:10 -0800 Subject: [PATCH 089/356] clk: qcom: gdsc-regulator: Add the qcom,poll-cfg-gdscr flag The default behavior of the GDSC enable/disable sequence is to poll the status bits of either the actual GDSCR or the corresponding HW_CTRL registers. On targets which have support for a CFG_GDSCR register, the status bits might not show the correct state of the GDSC, especially in the disable sequence, where the status bit will be cleared even before the core is completely power collapsed. On targets with this issue, poll the power on/off bits in the CFG_GDSCR register instead to correctly determine the GDSC state. Change-Id: If41f3f1cea25c001938f28bbb94af3310860d60f Signed-off-by: Deepak Katragadda Signed-off-by: Pavel Dubrova --- drivers/clk/qcom/gdsc-regulator.c | 75 +++++++++++++++++++++++++++---- 1 file changed, 66 insertions(+), 9 deletions(-) diff --git a/drivers/clk/qcom/gdsc-regulator.c b/drivers/clk/qcom/gdsc-regulator.c index ee8b6a2cde89..8e174a13b87a 100644 --- a/drivers/clk/qcom/gdsc-regulator.c +++ b/drivers/clk/qcom/gdsc-regulator.c @@ -34,6 +34,10 @@ #define HW_CONTROL_MASK BIT(1) #define SW_COLLAPSE_MASK BIT(0) +/* CFG_GDSCR */ +#define GDSC_POWER_UP_COMPLETE BIT(16) +#define GDSC_POWER_DOWN_COMPLETE BIT(15) + /* Domain Address */ #define GMEM_CLAMP_IO_MASK BIT(0) #define GMEM_RESET_MASK BIT(4) @@ -43,6 +47,7 @@ /* Register Offset */ #define REG_OFFSET 0x0 +#define CFG_GDSCR_OFFSET 0x4 /* Timeout Delay */ #define TIMEOUT_US 100 @@ -72,6 +77,7 @@ struct gdsc { bool allow_clear; bool reset_aon; bool is_bus_enabled; + bool poll_cfg_gdscr; int clock_count; int reset_count; int root_clk_idx; @@ -138,6 +144,31 @@ static int poll_gdsc_status(struct gdsc *sc, enum gdscr_status status) return -ETIMEDOUT; } +static int poll_cfg_gdsc_status(struct gdsc *sc, enum gdscr_status status) +{ + struct regmap *regmap = sc->regmap; + int count = sc->gds_timeout; + u32 val; + + for (; count > 0; count--) { + regmap_read(regmap, CFG_GDSCR_OFFSET, &val); + + switch (status) { + case ENABLED: + if (val & GDSC_POWER_UP_COMPLETE) + return 0; + break; + case DISABLED: + if (val & GDSC_POWER_DOWN_COMPLETE) + return 0; + break; + } + udelay(1); + } + + return -ETIMEDOUT; +} + static int gdsc_is_enabled(struct regulator_dev *rdev) { struct gdsc *sc = rdev_get_drvdata(rdev); @@ -211,7 +242,7 @@ static int gdsc_is_enabled(struct regulator_dev *rdev) static int gdsc_enable(struct regulator_dev *rdev) { struct gdsc *sc = rdev_get_drvdata(rdev); - uint32_t regval, hw_ctrl_regval = 0x0; + uint32_t regval, cfg_regval, hw_ctrl_regval = 0x0; int i, ret = 0; if (sc->skip_disable_before_enable) @@ -305,7 +336,10 @@ static int gdsc_enable(struct regulator_dev *rdev) gdsc_mb(sc); udelay(1); - ret = poll_gdsc_status(sc, ENABLED); + if (sc->poll_cfg_gdscr) + ret = poll_cfg_gdsc_status(sc, ENABLED); + else + ret = poll_gdsc_status(sc, ENABLED); if (ret) { regmap_read(sc->regmap, REG_OFFSET, ®val); @@ -333,10 +367,21 @@ static int gdsc_enable(struct regulator_dev *rdev) regval); udelay(sc->gds_timeout); - regmap_read(sc->regmap, REG_OFFSET, ®val); - dev_err(&rdev->dev, "%s final state: 0x%x (%d us after timeout)\n", - sc->rdesc.name, regval, - sc->gds_timeout); + if (sc->poll_cfg_gdscr) { + regmap_read(sc->regmap, REG_OFFSET, + ®val); + regmap_read(sc->regmap, + CFG_GDSCR_OFFSET, &cfg_regval); + dev_err(&rdev->dev, "%s final state: gdscr - 0x%x, cfg_gdscr - 0x%x (%d us after timeout)\n", + sc->rdesc.name, regval, + cfg_regval, sc->gds_timeout); + } else { + regmap_read(sc->regmap, REG_OFFSET, + ®val); + dev_err(&rdev->dev, "%s final state: 0x%x (%d us after timeout)\n", + sc->rdesc.name, regval, + sc->gds_timeout); + } goto end; } } @@ -425,7 +470,10 @@ static int gdsc_disable(struct regulator_dev *rdev) */ udelay(TIMEOUT_US); } else { - ret = poll_gdsc_status(sc, DISABLED); + if (sc->poll_cfg_gdscr) + ret = poll_cfg_gdsc_status(sc, DISABLED); + else + ret = poll_gdsc_status(sc, DISABLED); if (ret) dev_err(&rdev->dev, "%s disable timed out: 0x%x\n", sc->rdesc.name, regval); @@ -587,7 +635,10 @@ static int gdsc_set_mode(struct regulator_dev *rdev, unsigned int mode) * starts to use SW mode. */ if (sc->is_gdsc_enabled) { - ret = poll_gdsc_status(sc, ENABLED); + if (sc->poll_cfg_gdscr) + ret = poll_cfg_gdsc_status(sc, ENABLED); + else + ret = poll_gdsc_status(sc, ENABLED); if (ret) dev_err(&rdev->dev, "%s enable timed out\n", sc->rdesc.name); @@ -687,6 +738,9 @@ static int gdsc_parse_dt_data(struct gdsc *sc, struct device *dev, return PTR_ERR(sc->hw_ctrl); } + sc->poll_cfg_gdscr = of_property_read_bool(dev->of_node, + "qcom,poll-cfg-gdscr"); + sc->gds_timeout = TIMEOUT_US; of_property_read_u32(dev->of_node, "qcom,gds-timeout", &sc->gds_timeout); @@ -914,7 +968,10 @@ static int gdsc_probe(struct platform_device *pdev) regval &= ~SW_COLLAPSE_MASK; regmap_write(sc->regmap, REG_OFFSET, regval); - ret = poll_gdsc_status(sc, ENABLED); + if (sc->poll_cfg_gdscr) + ret = poll_cfg_gdsc_status(sc, ENABLED); + else + ret = poll_gdsc_status(sc, ENABLED); if (ret) { dev_err(&pdev->dev, "%s enable timed out: 0x%x\n", sc->rdesc.name, regval); From 32e3afe35f9892d81849d540378e3d8eee08877b Mon Sep 17 00:00:00 2001 From: Amit Nischal Date: Thu, 14 Jun 2018 13:30:04 +0530 Subject: [PATCH 090/356] clk: qcom: gdsc: Add support to configure en_few/rest wait values The EN_FEW_WAIT and EN_REST_WAIT bits value may differ from the default value of 0x2. Allow the value to be taken as input from device tree as parameter 'qcom,en-few-wait-val' and 'qcom,en-rest-wait-val'. Change-Id: I319c8cf5322713e2cb00c9e662084ec6b930b6a7 Signed-off-by: Amit Nischal Signed-off-by: Pavel Dubrova --- drivers/clk/qcom/gdsc-regulator.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/clk/qcom/gdsc-regulator.c b/drivers/clk/qcom/gdsc-regulator.c index 8e174a13b87a..08f056dfecfe 100644 --- a/drivers/clk/qcom/gdsc-regulator.c +++ b/drivers/clk/qcom/gdsc-regulator.c @@ -30,6 +30,10 @@ #define CLK_DIS_WAIT_MASK (0xF << 12) #define CLK_DIS_WAIT_SHIFT (12) #define RETAIN_FF_ENABLE_MASK BIT(11) +#define EN_FEW_WAIT_MASK (0xF << 16) +#define EN_FEW_WAIT_SHIFT (16) +#define EN_REST_WAIT_MASK (0xF << 20) +#define EN_REST_WAIT_SHIFT (20) #define SW_OVERRIDE_MASK BIT(2) #define HW_CONTROL_MASK BIT(1) #define SW_COLLAPSE_MASK BIT(0) @@ -917,6 +921,7 @@ static int gdsc_probe(struct platform_device *pdev) struct regulator_init_data *init_data = NULL; struct gdsc *sc; uint32_t regval, clk_dis_wait_val = 0; + uint32_t en_few_wait_val, en_rest_wait_val; int i, ret; sc = devm_kzalloc(&pdev->dev, sizeof(*sc), GFP_KERNEL); @@ -962,6 +967,22 @@ static int gdsc_probe(struct platform_device *pdev) regval |= clk_dis_wait_val; } + if (!of_property_read_u32(pdev->dev.of_node, "qcom,en-few-wait-val", + &en_few_wait_val)) { + en_few_wait_val <<= EN_FEW_WAIT_SHIFT; + + regval &= ~(EN_FEW_WAIT_MASK); + regval |= en_few_wait_val; + } + + if (!of_property_read_u32(pdev->dev.of_node, "qcom,en-rest-wait-val", + &en_rest_wait_val)) { + en_rest_wait_val <<= EN_REST_WAIT_SHIFT; + + regval &= ~(EN_REST_WAIT_MASK); + regval |= en_rest_wait_val; + } + regmap_write(sc->regmap, REG_OFFSET, regval); if (!sc->toggle_logic) { From bc88c05427a03ffa6f8dd1a4c798d9193df3e12c Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Mon, 20 Dec 2021 22:06:53 +0200 Subject: [PATCH 091/356] clk: qcom: gcc-sdm845: Reorder DFS clock registration DFS wrap0/1 SE clock registration must be done before qcom_cc_really_probe() is executed to properly initialize their child branch clocks. Signed-off-by: Pavel Dubrova --- drivers/clk/qcom/gcc-sdm845.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/clk/qcom/gcc-sdm845.c b/drivers/clk/qcom/gcc-sdm845.c index c39070fecb2d..aeca2812675b 100644 --- a/drivers/clk/qcom/gcc-sdm845.c +++ b/drivers/clk/qcom/gcc-sdm845.c @@ -4336,6 +4336,14 @@ static int gcc_sdm845_probe(struct platform_device *pdev) if (ret) return ret; + /* DFS clock registration */ + ret = qcom_cc_register_rcg_dfs(regmap, gcc_dfs_clocks, + ARRAY_SIZE(gcc_dfs_clocks)); + if (ret) { + dev_err(&pdev->dev, "Failed to register with DFS!\n"); + return ret; + } + ret = qcom_cc_really_probe(pdev, &gcc_sdm845_desc, regmap); if (ret) { dev_err(&pdev->dev, "Failed to register GCC clocks\n"); @@ -4350,13 +4358,8 @@ static int gcc_sdm845_probe(struct platform_device *pdev) if (!of_device_is_compatible(pdev->dev.of_node, "qcom,gcc-sdm845-v2.1")) clk_prepare_enable(gcc_aggre_noc_pcie_tbu_clk.clkr.hw.clk); - /* DFS clock registration */ - ret = qcom_cc_register_rcg_dfs(regmap, gcc_dfs_clocks, - ARRAY_SIZE(gcc_dfs_clocks)); - if (ret) - dev_err(&pdev->dev, "Failed to register with DFS!\n"); - dev_info(&pdev->dev, "Registered GCC clocks\n"); + return ret; } From 2e3f2dc189f440c1727894783ef68fe89ada8ca2 Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Mon, 15 Nov 2021 23:04:55 +0200 Subject: [PATCH 092/356] iommu: arm-smmu: Implement qsmmuv500 workaround While a tlb flush is in progress, clients may experience suboptimal performance. To mitigate this, add a minimum delay between tlb operations for real-time clients. This is implemented using a global lock between HLOS and other execution enviroments. Signed-off-by: Patrick Daly Signed-off-by: Pavel Dubrova --- drivers/iommu/arm-smmu.c | 190 +++++++++++++++++++++++++++++++++++ include/trace/events/iommu.h | 14 +++ 2 files changed, 204 insertions(+) diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 469649eb78e7..51fa7d753ab4 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -52,6 +52,7 @@ #include #include #include +#include #include #include #include @@ -268,6 +269,7 @@ struct arm_smmu_device { #define ARM_SMMU_OPT_DISABLE_ATOS (1 << 7) #define ARM_SMMU_OPT_NO_DYNAMIC_ASID (1 << 8) #define ARM_SMMU_OPT_HALT (1 << 9) +#define ARM_SMMU_OPT_MMU500_ERRATA1 (1 << 10) u32 options; enum arm_smmu_arch_version version; enum arm_smmu_implementation model; @@ -401,6 +403,9 @@ struct arm_smmu_domain { struct list_head nonsecure_pool; struct iommu_debug_attachment *logger; struct iommu_domain domain; + + bool qsmmuv500_errata1_init; + bool qsmmuv500_errata1_client; }; struct arm_smmu_option_prop { @@ -420,6 +425,10 @@ struct qsmmuv500_archdata { struct actlr_setting *actlrs; u32 actlr_tbl_size; u32 testbus_version; + struct arm_smmu_smr *errata1_clients; + u32 num_errata1_clients; + struct hwspinlock *errata1_lock; + ktime_t last_tlbi_ktime; }; #define get_qsmmuv500_archdata(smmu) \ ((struct qsmmuv500_archdata *)(smmu->archdata)) @@ -455,6 +464,7 @@ static struct arm_smmu_option_prop arm_smmu_options[] = { { ARM_SMMU_OPT_DISABLE_ATOS, "qcom,disable-atos" }, { ARM_SMMU_OPT_NO_DYNAMIC_ASID, "qcom,no-dynamic-asid" }, { ARM_SMMU_OPT_HALT, "qcom,enable-smmu-halt"}, + { ARM_SMMU_OPT_MMU500_ERRATA1, "qcom,mmu500-errata-1" }, { 0, NULL}, }; @@ -477,6 +487,7 @@ static int arm_smmu_enable_s1_translations(struct arm_smmu_domain *smmu_domain); static int arm_smmu_alloc_cb(struct iommu_domain *domain, struct arm_smmu_device *smmu, struct device *dev); +static struct iommu_gather_ops qsmmuv500_errata1_smmu_gather_ops; static bool arm_smmu_is_static_cb(struct arm_smmu_device *smmu); static bool arm_smmu_is_master_side_secure(struct arm_smmu_domain *smmu_domain); @@ -2597,6 +2608,9 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain, (smmu->model == QCOM_SMMUV500)) quirks |= IO_PGTABLE_QUIRK_QSMMUV500_NON_SHAREABLE; + if (smmu->options & ARM_SMMU_OPT_MMU500_ERRATA1) + smmu_domain->tlb_ops = &qsmmuv500_errata1_smmu_gather_ops; + if (arm_smmu_is_slave_side_secure(smmu_domain)) smmu_domain->tlb_ops = &msm_smmu_gather_ops; @@ -6028,6 +6042,136 @@ static bool arm_smmu_fwspec_match_smr(struct iommu_fwspec *fwspec, return false; } +static bool qsmmuv500_errata1_required(struct arm_smmu_domain *smmu_domain, + struct qsmmuv500_archdata *data) +{ + bool ret = false; + int j; + struct arm_smmu_smr *smr; + struct iommu_fwspec *fwspec; + + if (smmu_domain->qsmmuv500_errata1_init) + return smmu_domain->qsmmuv500_errata1_client; + + fwspec = smmu_domain->dev->iommu_fwspec; + for (j = 0; j < data->num_errata1_clients; j++) { + smr = &data->errata1_clients[j]; + if (arm_smmu_fwspec_match_smr(fwspec, smr)) { + ret = true; + break; + } + } + + smmu_domain->qsmmuv500_errata1_init = true; + smmu_domain->qsmmuv500_errata1_client = ret; + return ret; +} + +#define SCM_CONFIG_ERRATA1_CLIENT_ALL 0x2 +#define SCM_CONFIG_ERRATA1 0x3 +static void __qsmmuv500_errata1_tlbiall(struct arm_smmu_domain *smmu_domain) +{ + struct arm_smmu_device *smmu = smmu_domain->smmu; + struct device *dev = smmu_domain->dev; + struct arm_smmu_cfg *cfg = &smmu_domain->cfg; + void __iomem *base; + int ret; + ktime_t cur; + u32 val; + struct scm_desc desc = { + .args[0] = SCM_CONFIG_ERRATA1_CLIENT_ALL, + .args[1] = false, + .arginfo = SCM_ARGS(2, SCM_VAL, SCM_VAL), + }; + + base = ARM_SMMU_CB(smmu, cfg->cbndx); + writel_relaxed(0, base + ARM_SMMU_CB_S1_TLBIALL); + writel_relaxed(0, base + ARM_SMMU_CB_TLBSYNC); + if (!readl_poll_timeout_atomic(base + ARM_SMMU_CB_TLBSTATUS, val, + !(val & TLBSTATUS_SACTIVE), 0, 100)) + return; + + ret = scm_call2_atomic(SCM_SIP_FNID(SCM_SVC_SMMU_PROGRAM, + SCM_CONFIG_ERRATA1), + &desc); + if (ret) { + dev_err(smmu->dev, "Calling into TZ to disable ERRATA1 failed - IOMMU hardware in bad state\n"); + BUG(); + return; + } + + cur = ktime_get(); + trace_tlbi_throttle_start(dev, 0); + msm_bus_noc_throttle_wa(true); + + if (readl_poll_timeout_atomic(base + ARM_SMMU_CB_TLBSTATUS, val, + !(val & TLBSTATUS_SACTIVE), 0, 10000)) { + dev_err(smmu->dev, "ERRATA1 TLBSYNC timeout - IOMMU hardware in bad state"); + trace_tlbsync_timeout(dev, 0); + BUG(); + } + + msm_bus_noc_throttle_wa(false); + trace_tlbi_throttle_end(dev, ktime_us_delta(ktime_get(), cur)); + + desc.args[1] = true; + ret = scm_call2_atomic(SCM_SIP_FNID(SCM_SVC_SMMU_PROGRAM, + SCM_CONFIG_ERRATA1), + &desc); + if (ret) { + dev_err(smmu->dev, "Calling into TZ to reenable ERRATA1 failed - IOMMU hardware in bad state\n"); + BUG(); + } +} + +/* Must be called with clocks/regulators enabled */ +#define ERRATA1_TLBI_INTERVAL_US 10 +/* Timeout (ms) for the trylock of remote spinlocks */ +#define HWSPINLOCK_TIMEOUT 1000 +static void qsmmuv500_errata1_tlb_inv_context(void *cookie) +{ + struct arm_smmu_domain *smmu_domain = cookie; + struct device *dev = smmu_domain->dev; + struct qsmmuv500_archdata *data = + get_qsmmuv500_archdata(smmu_domain->smmu); + ktime_t cur; + unsigned long flags; + bool errata; + int ret; + + cur = ktime_get(); + trace_tlbi_start(dev, 0); + + errata = qsmmuv500_errata1_required(smmu_domain, data); + ret = hwspin_lock_timeout_irqsave(data->errata1_lock, + HWSPINLOCK_TIMEOUT, &flags); + if (ret) + WARN(1, "%s: get the hw lock failed", dev_name(dev)); + + if (errata) { + s64 delta; + + delta = ktime_us_delta(ktime_get(), data->last_tlbi_ktime); + if (delta < ERRATA1_TLBI_INTERVAL_US) + udelay(ERRATA1_TLBI_INTERVAL_US - delta); + + __qsmmuv500_errata1_tlbiall(smmu_domain); + + data->last_tlbi_ktime = ktime_get(); + } else { + __qsmmuv500_errata1_tlbiall(smmu_domain); + } + hwspin_unlock_irqrestore(data->errata1_lock, &flags); + + trace_tlbi_end(dev, ktime_us_delta(ktime_get(), cur)); +} + +static struct iommu_gather_ops qsmmuv500_errata1_smmu_gather_ops = { + .tlb_flush_all = qsmmuv500_errata1_tlb_inv_context, + .alloc_pages_exact = arm_smmu_alloc_pages_exact, + .free_pages_exact = arm_smmu_free_pages_exact, +}; + static int qsmmuv500_tbu_halt(struct qsmmuv500_tbu_device *tbu, struct arm_smmu_domain *smmu_domain) { @@ -6460,6 +6604,48 @@ static int qsmmuv500_tbu_register(struct device *dev, void *cookie) return 0; } +static int qsmmuv500_parse_errata1(struct arm_smmu_device *smmu) +{ + int len, i, hwlock_id; + struct device *dev = smmu->dev; + struct qsmmuv500_archdata *data = get_qsmmuv500_archdata(smmu); + struct arm_smmu_smr *smrs; + const __be32 *cell; + + cell = of_get_property(dev->of_node, "qcom,mmu500-errata-1", NULL); + if (!cell) + return 0; + + hwlock_id = of_hwspin_lock_get_id(dev->of_node, 0); + if (hwlock_id < 0) { + if (hwlock_id != -EPROBE_DEFER) + dev_err(dev, "failed to retrieve hwlock\n"); + return hwlock_id; + } + + data->errata1_lock = hwspin_lock_request_specific(hwlock_id); + if (!data->errata1_lock) + return -ENXIO; + + len = of_property_count_elems_of_size( + dev->of_node, "qcom,mmu500-errata-1", sizeof(u32) * 2); + if (len < 0) + return 0; + + smrs = devm_kzalloc(dev, sizeof(*smrs) * len, GFP_KERNEL); + if (!smrs) + return -ENOMEM; + + for (i = 0; i < len; i++) { + smrs[i].id = of_read_number(cell++, 1); + smrs[i].mask = of_read_number(cell++, 1); + } + + data->errata1_clients = smrs; + data->num_errata1_clients = len; + return 0; +} + static int qsmmuv500_read_actlr_tbl(struct arm_smmu_device *smmu) { int len, i; @@ -7110,6 +7296,10 @@ static int qsmmuv500_arch_init(struct arm_smmu_device *smmu) if (arm_smmu_is_static_cb(smmu)) return 0; + ret = qsmmuv500_parse_errata1(smmu); + if (ret) + return ret; + ret = qsmmuv500_read_actlr_tbl(smmu); if (ret) return ret; diff --git a/include/trace/events/iommu.h b/include/trace/events/iommu.h index 0db6f7f86270..dea920328a70 100644 --- a/include/trace/events/iommu.h +++ b/include/trace/events/iommu.h @@ -243,6 +243,20 @@ DEFINE_EVENT(iommu_tlbi, tlbsync_timeout, TP_ARGS(dev, time) ); +DEFINE_EVENT(iommu_tlbi, tlbi_throttle_start, + + TP_PROTO(struct device *dev, u64 time), + + TP_ARGS(dev, time) +); + +DEFINE_EVENT(iommu_tlbi, tlbi_throttle_end, + + TP_PROTO(struct device *dev, u64 time), + + TP_ARGS(dev, time) +); + TRACE_EVENT(smmu_init, TP_PROTO(u64 time), From 94630fd94f29661e774eaab9ce5aa42fcd5d1d76 Mon Sep 17 00:00:00 2001 From: David Dai Date: Thu, 7 Sep 2017 13:26:04 -0700 Subject: [PATCH 093/356] msm: msm_bus: API to throttle GPU/APPS ports Artifically limit APPS and GPU ports to workaround QSMMU hardware limitations. Change-Id: I2a9f70e64b6e0cbc5fb3b09958124921ef6b07e8 Signed-off-by: David Dai Signed-off-by: Pavel Dubrova --- .../soc/qcom/msm_bus/msm_bus_fabric_rpmh.c | 1 + drivers/soc/qcom/msm_bus/msm_bus_noc_rpmh.c | 142 +++++++++++++++--- drivers/soc/qcom/msm_bus/msm_bus_rpmh.h | 1 + include/linux/msm-bus.h | 15 ++ 4 files changed, 139 insertions(+), 20 deletions(-) diff --git a/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c b/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c index 3a48c03a8be7..aefca337be75 100644 --- a/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c +++ b/drivers/soc/qcom/msm_bus/msm_bus_fabric_rpmh.c @@ -1000,6 +1000,7 @@ static int msm_bus_dev_init_qos(struct device *dev, void *data) bus_node_info->fabdev->noc_ops.qos_init( node_dev, + bus_node_info, bus_node_info->fabdev->qos_base, bus_node_info->fabdev->base_offset, bus_node_info->fabdev->qos_off, diff --git a/drivers/soc/qcom/msm_bus/msm_bus_noc_rpmh.c b/drivers/soc/qcom/msm_bus/msm_bus_noc_rpmh.c index b3bc943008f8..657c716bec39 100644 --- a/drivers/soc/qcom/msm_bus/msm_bus_noc_rpmh.c +++ b/drivers/soc/qcom/msm_bus/msm_bus_noc_rpmh.c @@ -11,10 +11,14 @@ #include #include #include +#include +#include #include "msm_bus_core.h" #include "msm_bus_noc.h" #include "msm_bus_rpmh.h" +static DEFINE_SPINLOCK(noc_lock); + /* NOC_QOS generic */ #define __CLZ(x) ((8 * sizeof(uint32_t)) - 1 - __fls(x)) #define SAT_SCALE 16 /* 16 bytes minimum for saturation */ @@ -27,6 +31,7 @@ #define MIN_BW_FIELD 1 #define READ_TIMEOUT_MS msecs_to_jiffies(1) #define READ_DELAY_US 10 +#define MSM_BUS_FAB_MEM_NOC 6152 #define NOC_QOS_REG_BASE(b, o) ((b) + (o)) @@ -112,6 +117,8 @@ enum noc_qos_id_saturationn { NOC_QOS_SATn_SAT_SHFT = 0x0, }; +static void __iomem *memnoc_qos_base; + static int noc_div(uint64_t *a, uint32_t b) { if ((*a > 0) && (*a < b)) { @@ -179,48 +186,59 @@ static void noc_set_qos_dflt_prio(void __iomem *base, uint32_t qos_off, wmb(); } -static void noc_set_qos_limiter(void __iomem *base, uint32_t qos_off, - uint32_t mport, uint32_t qos_delta, - struct msm_bus_noc_limiter *lim, uint32_t lim_en) +static void noc_enable_qos_limiter(void __iomem *base, uint32_t qos_off, + uint32_t mport, uint32_t qos_delta, uint32_t lim_en) { uint32_t reg_val, val; - reg_val = readl_relaxed(NOC_QOS_MAINCTL_LOWn_ADDR(base, qos_off, mport, qos_delta)); - - writel_relaxed((reg_val & (~(NOC_QOS_MCTL_LIMIT_ENn_BMSK))), + val = lim_en << NOC_QOS_MCTL_LIMIT_ENn_SHFT; + writel_relaxed(((reg_val & (~(NOC_QOS_MCTL_LIMIT_ENn_BMSK))) | + (val & NOC_QOS_MCTL_LIMIT_ENn_BMSK)), NOC_QOS_MAINCTL_LOWn_ADDR(base, qos_off, mport, qos_delta)); - /* Ensure we disable limiter before config*/ + /* Ensure we disable/enable limiter before exiting*/ wmb(); +} +static void noc_set_qos_limit_bw(void __iomem *base, uint32_t qos_off, + uint32_t mport, uint32_t qos_delta, uint32_t bw) +{ + uint32_t reg_val, val; reg_val = readl_relaxed(NOC_QOS_LIMITBWn_ADDR(base, qos_off, mport, qos_delta)); - val = lim->bw << NOC_QOS_LIMITBW_BWn_SHFT; + val = bw << NOC_QOS_LIMITBW_BWn_SHFT; writel_relaxed(((reg_val & (~(NOC_QOS_LIMITBW_BWn_BMSK))) | (val & NOC_QOS_LIMITBW_BWn_BMSK)), NOC_QOS_LIMITBWn_ADDR(base, qos_off, mport, qos_delta)); + /* Ensure we set limiter bw before exiting*/ + wmb(); +} + +static void noc_set_qos_limit_sat(void __iomem *base, uint32_t qos_off, + uint32_t mport, uint32_t qos_delta, uint32_t sat) +{ + uint32_t reg_val, val; reg_val = readl_relaxed(NOC_QOS_LIMITBWn_ADDR(base, qos_off, mport, qos_delta)); - val = lim->sat << NOC_QOS_LIMITBW_SATn_SHFT; + val = sat << NOC_QOS_LIMITBW_SATn_SHFT; writel_relaxed(((reg_val & (~(NOC_QOS_LIMITBW_SATn_BMSK))) | (val & NOC_QOS_LIMITBW_SATn_BMSK)), NOC_QOS_LIMITBWn_ADDR(base, qos_off, mport, qos_delta)); - /* Ensure qos limiter settings in place before possibly enabling */ - wmb(); - - reg_val = readl_relaxed(NOC_QOS_MAINCTL_LOWn_ADDR(base, qos_off, mport, - qos_delta)); - val = lim_en << NOC_QOS_MCTL_LIMIT_ENn_SHFT; - writel_relaxed(((reg_val & (~(NOC_QOS_MCTL_LIMIT_ENn_BMSK))) | - (val & NOC_QOS_MCTL_LIMIT_ENn_BMSK)), - NOC_QOS_MAINCTL_LOWn_ADDR(base, qos_off, mport, qos_delta)); - - /* Ensure qos limiter writes take place before exiting*/ + /* Ensure we set limiter sat before exiting*/ wmb(); } +static void noc_set_qos_limiter(void __iomem *base, uint32_t qos_off, + uint32_t mport, uint32_t qos_delta, + struct msm_bus_noc_limiter *lim, uint32_t lim_en) +{ + noc_enable_qos_limiter(base, qos_off, mport, qos_delta, 0); + noc_set_qos_limit_bw(base, qos_off, mport, qos_delta, lim->bw); + noc_set_qos_limit_sat(base, qos_off, mport, qos_delta, lim->sat); + noc_enable_qos_limiter(base, qos_off, mport, qos_delta, lim_en); +} static void noc_set_qos_regulator(void __iomem *base, uint32_t qos_off, uint32_t mport, uint32_t qos_delta, @@ -328,6 +346,7 @@ void msm_bus_noc_get_qos_bw(void __iomem *base, uint32_t qos_off, } static int msm_bus_noc_qos_init(struct msm_bus_node_device_type *info, + struct msm_bus_node_device_type *fabdev, void __iomem *qos_base, uint32_t qos_off, uint32_t qos_delta, uint32_t qos_freq) @@ -335,6 +354,7 @@ static int msm_bus_noc_qos_init(struct msm_bus_node_device_type *info, struct msm_bus_noc_qos_params *qos_params; int ret = 0; int i; + unsigned long flags; qos_params = &info->node_info->qos_params; @@ -344,6 +364,11 @@ static int msm_bus_noc_qos_init(struct msm_bus_node_device_type *info, goto err_qos_init; } + spin_lock_irqsave(&noc_lock, flags); + + if (fabdev->node_info->id == MSM_BUS_FAB_MEM_NOC) + memnoc_qos_base = qos_base; + for (i = 0; i < info->node_info->num_qports; i++) { noc_set_qos_dflt_prio(qos_base, qos_off, info->node_info->qport[i], @@ -367,6 +392,8 @@ static int msm_bus_noc_qos_init(struct msm_bus_node_device_type *info, qos_delta, qos_params->urg_fwd_en); } + spin_unlock_irqrestore(&noc_lock, flags); + err_qos_init: return ret; } @@ -456,3 +483,78 @@ int msm_bus_noc_set_ops(struct msm_bus_node_device_type *bus_dev) return 0; } EXPORT_SYMBOL(msm_bus_noc_set_ops); + +int msm_bus_noc_throttle_wa(bool enable) +{ + unsigned long flags; + + spin_lock_irqsave(&noc_lock, flags); + + if (!memnoc_qos_base) { + MSM_BUS_ERR("Memnoc QoS Base address not found!"); + goto noc_throttle_exit; + } + + if (enable) { + noc_set_qos_limit_bw(memnoc_qos_base, 0x10000, 2, + 0x1000, 0x1B); + noc_set_qos_limit_bw(memnoc_qos_base, 0x10000, 3, + 0x1000, 0x1B); + noc_set_qos_limit_bw(memnoc_qos_base, 0x10000, 10, + 0x1000, 0x30); + noc_set_qos_limit_bw(memnoc_qos_base, 0x10000, 11, + 0x1000, 0x30); + noc_enable_qos_limiter(memnoc_qos_base, 0x10000, 10, + 0x1000, 1); + noc_enable_qos_limiter(memnoc_qos_base, 0x10000, 11, + 0x1000, 1); + noc_enable_qos_limiter(memnoc_qos_base, 0x10000, 2, + 0x1000, 1); + noc_enable_qos_limiter(memnoc_qos_base, 0x10000, 3, + 0x1000, 1); + } else { + noc_enable_qos_limiter(memnoc_qos_base, 0x10000, 2, + 0x1000, 0); + noc_enable_qos_limiter(memnoc_qos_base, 0x10000, 3, + 0x1000, 0); + noc_enable_qos_limiter(memnoc_qos_base, 0x10000, 10, + 0x1000, 0); + noc_enable_qos_limiter(memnoc_qos_base, 0x10000, 11, + 0x1000, 0); + noc_set_qos_limit_bw(memnoc_qos_base, 0x10000, 2, + 0x1000, 0); + noc_set_qos_limit_bw(memnoc_qos_base, 0x10000, 3, + 0x1000, 0); + noc_set_qos_limit_bw(memnoc_qos_base, 0x10000, 10, + 0x1000, 0); + noc_set_qos_limit_bw(memnoc_qos_base, 0x10000, 11, + 0x1000, 0); + } + +noc_throttle_exit: + spin_unlock_irqrestore(&noc_lock, flags); + return 0; +} +EXPORT_SYMBOL(msm_bus_noc_throttle_wa); + +int msm_bus_noc_priority_wa(bool enable) +{ + unsigned long flags; + + spin_lock_irqsave(&noc_lock, flags); + if (!memnoc_qos_base) { + MSM_BUS_ERR("Memnoc QoS Base address not found!"); + goto noc_priority_exit; + } + + if (enable) + noc_set_qos_dflt_prio(memnoc_qos_base, 0x10000, 0, + 0x1000, 7); + else + noc_set_qos_dflt_prio(memnoc_qos_base, 0x10000, 0, + 0x1000, 6); +noc_priority_exit: + spin_unlock_irqrestore(&noc_lock, flags); + return 0; +} +EXPORT_SYMBOL(msm_bus_noc_priority_wa); diff --git a/drivers/soc/qcom/msm_bus/msm_bus_rpmh.h b/drivers/soc/qcom/msm_bus/msm_bus_rpmh.h index 351902b0fabc..dbc8b1296563 100644 --- a/drivers/soc/qcom/msm_bus/msm_bus_rpmh.h +++ b/drivers/soc/qcom/msm_bus/msm_bus_rpmh.h @@ -35,6 +35,7 @@ struct link_node { /* New types introduced for adhoc topology */ struct msm_bus_noc_ops { int (*qos_init)(struct msm_bus_node_device_type *dev, + struct msm_bus_node_device_type *fabdev, void __iomem *qos_base, uint32_t qos_off, uint32_t qos_delta, uint32_t qos_freq); int (*set_bw)(struct msm_bus_node_device_type *dev, diff --git a/include/linux/msm-bus.h b/include/linux/msm-bus.h index 9d376a4e89f5..07754c26f9eb 100644 --- a/include/linux/msm-bus.h +++ b/include/linux/msm-bus.h @@ -206,6 +206,21 @@ static inline int msm_bus_scale_query_tcs_cmd_all(struct msm_bus_tcs_handle #endif +#if defined(CONFIG_QCOM_BUS_SCALING) && defined(CONFIG_QCOM_BUS_CONFIG_RPMH) +int msm_bus_noc_throttle_wa(bool enable); +int msm_bus_noc_priority_wa(bool enable); +#else +static inline int msm_bus_noc_throttle_wa(bool enable) +{ + return 0; +} + +static inline int msm_bus_noc_priority_wa(bool enable) +{ + return 0; +} +#endif + #if defined(CONFIG_OF) && defined(CONFIG_QCOM_BUS_SCALING) struct msm_bus_scale_pdata *msm_bus_pdata_from_node( struct platform_device *pdev, struct device_node *of_node); From 20860d485d9a87ed59b43c22a49738d2925ca82b Mon Sep 17 00:00:00 2001 From: David Dai Date: Wed, 11 Oct 2017 17:44:06 -0700 Subject: [PATCH 094/356] msm: msm_bus: Change Throttle Methodology Change throttle functionality from using NOC throttles to QM throttles. Change-Id: I05c95c0047472fa98973f3632495fcf3688ceb3b Signed-off-by: David Dai Signed-off-by: Pavel Dubrova --- drivers/soc/qcom/msm_bus/msm_bus_noc_rpmh.c | 73 +++++++++++---------- 1 file changed, 39 insertions(+), 34 deletions(-) diff --git a/drivers/soc/qcom/msm_bus/msm_bus_noc_rpmh.c b/drivers/soc/qcom/msm_bus/msm_bus_noc_rpmh.c index 657c716bec39..37b91a0348c4 100644 --- a/drivers/soc/qcom/msm_bus/msm_bus_noc_rpmh.c +++ b/drivers/soc/qcom/msm_bus/msm_bus_noc_rpmh.c @@ -31,6 +31,7 @@ static DEFINE_SPINLOCK(noc_lock); #define MIN_BW_FIELD 1 #define READ_TIMEOUT_MS msecs_to_jiffies(1) #define READ_DELAY_US 10 +#define QM_BASE 0x010B8000 #define MSM_BUS_FAB_MEM_NOC 6152 #define NOC_QOS_REG_BASE(b, o) ((b) + (o)) @@ -117,6 +118,16 @@ enum noc_qos_id_saturationn { NOC_QOS_SATn_SAT_SHFT = 0x0, }; +#define QM_CLn_TH_LVL_MUX_ADDR(b, o, n, d) \ + (NOC_QOS_REG_BASE(b, o) + 0x8C0 + (d) * (n)) +enum qm_cl_id_th_lvl_mux_cfg { + QM_CLn_TH_LVL_SW_OVERRD_BMSK = 0x80000000, + QM_CLn_TH_LVL_SW_OVERRD_SHFT = 0x1F, + QM_CLn_TH_LVL_SW_BMSK = 0x00000007, + QM_CLn_TH_LVL_SW_SHFT = 0x0, +}; + +static void __iomem *qm_base; static void __iomem *memnoc_qos_base; static int noc_div(uint64_t *a, uint32_t b) @@ -169,6 +180,18 @@ static uint32_t noc_ws(uint64_t bw, uint32_t sat, uint32_t qos_freq) } #define MAX_WS(bw, timebase) noc_ws((bw), MAX_SAT_FIELD, (timebase)) +static void noc_set_qm_th_lvl_cfg(void __iomem *base, uint32_t off, + uint32_t n, uint32_t delta, + uint32_t override_val, uint32_t override) +{ + writel_relaxed(((override << QM_CLn_TH_LVL_SW_OVERRD_SHFT) | + (override_val & QM_CLn_TH_LVL_SW_BMSK)), + QM_CLn_TH_LVL_MUX_ADDR(base, off, n, delta)); + + /* Ensure QM CFG is set before exiting */ + wmb(); +} + static void noc_set_qos_dflt_prio(void __iomem *base, uint32_t qos_off, uint32_t mport, uint32_t qos_delta, uint32_t prio) @@ -364,6 +387,16 @@ static int msm_bus_noc_qos_init(struct msm_bus_node_device_type *info, goto err_qos_init; } + if (!qm_base) { + qm_base = ioremap_nocache(QM_BASE, 0x4000); + if (!qm_base) { + MSM_BUS_ERR("%s: Error remapping address 0x%zx", + __func__, (size_t)QM_BASE); + ret = -ENOMEM; + goto err_qos_init; + } + } + spin_lock_irqsave(&noc_lock, flags); if (fabdev->node_info->id == MSM_BUS_FAB_MEM_NOC) @@ -490,45 +523,17 @@ int msm_bus_noc_throttle_wa(bool enable) spin_lock_irqsave(&noc_lock, flags); - if (!memnoc_qos_base) { - MSM_BUS_ERR("Memnoc QoS Base address not found!"); + if (!qm_base) { + MSM_BUS_ERR("QM CFG base address not found!"); goto noc_throttle_exit; } if (enable) { - noc_set_qos_limit_bw(memnoc_qos_base, 0x10000, 2, - 0x1000, 0x1B); - noc_set_qos_limit_bw(memnoc_qos_base, 0x10000, 3, - 0x1000, 0x1B); - noc_set_qos_limit_bw(memnoc_qos_base, 0x10000, 10, - 0x1000, 0x30); - noc_set_qos_limit_bw(memnoc_qos_base, 0x10000, 11, - 0x1000, 0x30); - noc_enable_qos_limiter(memnoc_qos_base, 0x10000, 10, - 0x1000, 1); - noc_enable_qos_limiter(memnoc_qos_base, 0x10000, 11, - 0x1000, 1); - noc_enable_qos_limiter(memnoc_qos_base, 0x10000, 2, - 0x1000, 1); - noc_enable_qos_limiter(memnoc_qos_base, 0x10000, 3, - 0x1000, 1); + noc_set_qm_th_lvl_cfg(qm_base, 0x1000, 8, 0x4, 0x3, 0x1); + noc_set_qm_th_lvl_cfg(qm_base, 0x1000, 9, 0x4, 0x3, 0x1); } else { - noc_enable_qos_limiter(memnoc_qos_base, 0x10000, 2, - 0x1000, 0); - noc_enable_qos_limiter(memnoc_qos_base, 0x10000, 3, - 0x1000, 0); - noc_enable_qos_limiter(memnoc_qos_base, 0x10000, 10, - 0x1000, 0); - noc_enable_qos_limiter(memnoc_qos_base, 0x10000, 11, - 0x1000, 0); - noc_set_qos_limit_bw(memnoc_qos_base, 0x10000, 2, - 0x1000, 0); - noc_set_qos_limit_bw(memnoc_qos_base, 0x10000, 3, - 0x1000, 0); - noc_set_qos_limit_bw(memnoc_qos_base, 0x10000, 10, - 0x1000, 0); - noc_set_qos_limit_bw(memnoc_qos_base, 0x10000, 11, - 0x1000, 0); + noc_set_qm_th_lvl_cfg(qm_base, 0x1000, 8, 0x4, 0, 0); + noc_set_qm_th_lvl_cfg(qm_base, 0x1000, 9, 0x4, 0, 0); } noc_throttle_exit: From 738d5403a92e8cabf2131c594cbac865352b8231 Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Tue, 14 Dec 2021 03:35:04 +0200 Subject: [PATCH 095/356] soc: qcom: shmbridge: Disable shared memory bridge for SDM845 Disable shared memory bridge mechanism and fallback to default hypervisor based mechanism due to some issues with secure world communication. This commit is temporary. Signed-off-by: Pavel Dubrova --- drivers/soc/qcom/qtee_shmbridge.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/soc/qcom/qtee_shmbridge.c b/drivers/soc/qcom/qtee_shmbridge.c index d064860c11a8..c34a1cec1086 100644 --- a/drivers/soc/qcom/qtee_shmbridge.c +++ b/drivers/soc/qcom/qtee_shmbridge.c @@ -123,6 +123,10 @@ static int32_t qtee_shmbridge_enable(bool enable) return ret; } +#ifdef CONFIG_ARCH_SDM845 + return ret; +#endif + desc.arginfo = TZ_SHM_BRIDGE_ENABLE_PARAM_ID; ret = scm_call2(TZ_SHM_BRIDGE_ENABLE, &desc); if (ret || desc.ret[0]) { From b01f4cf3b9b114c1028f8b685f2ee9709cf04e1b Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Tue, 16 Nov 2021 18:09:33 +0200 Subject: [PATCH 096/356] power: qpnp-fg-gen3: Use module_platform_driver The qpnp-fg-gen3 driver init and exit functions are calling platform_driver_register and platform_driver_unregister and doing nothing else. This same as that of the module_platform_driver, remove this init and exit functions and use the module_platform_driver instead. Signed-off-by: Pavel Dubrova --- drivers/power/supply/qcom/qpnp-fg-gen3.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c index f23f36d1b749..e255a0abdbca 100644 --- a/drivers/power/supply/qcom/qpnp-fg-gen3.c +++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c @@ -5727,18 +5727,7 @@ static struct platform_driver fg_gen3_driver = { .shutdown = fg_gen3_shutdown, }; -static int __init fg_gen3_init(void) -{ - return platform_driver_register(&fg_gen3_driver); -} - -static void __exit fg_gen3_exit(void) -{ - return platform_driver_unregister(&fg_gen3_driver); -} - -module_init(fg_gen3_init); -module_exit(fg_gen3_exit); +module_platform_driver(fg_gen3_driver); MODULE_DESCRIPTION("QPNP Fuel gauge GEN3 driver"); MODULE_LICENSE("GPL v2"); From 532602125d15298d332ed44688d5a7079541bef6 Mon Sep 17 00:00:00 2001 From: "Angelo G. Del Regno" Date: Sun, 1 Jul 2018 22:03:37 +0200 Subject: [PATCH 097/356] thermal: qcom: msm_lmh_dcvs: Never initialize LMH TZ more than once The LMH DCVS initialization consists in enabling the LMH thermal, outer loop, reliability and BCL algorithms on a per-cluster basis, but the command that kickstarts it is "PROFILE_CHANGE" with parameter '1' sent to the TZ LMH Service. Sending it more than one time is rendundant, but the critical issue is that - if we send it more than once - the CPUs will deadlock! --- drivers/thermal/qcom/msm_lmh_dcvs.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/thermal/qcom/msm_lmh_dcvs.c b/drivers/thermal/qcom/msm_lmh_dcvs.c index efdde7742cd4..01aa176df2b5 100644 --- a/drivers/thermal/qcom/msm_lmh_dcvs.c +++ b/drivers/thermal/qcom/msm_lmh_dcvs.c @@ -80,6 +80,8 @@ struct __limits_cdev_data { u32 min_freq; }; +static bool lmh_enabled = false; + struct limits_dcvs_hw { char sensor_name[THERMAL_NAME_LENGTH]; uint32_t affinity; @@ -349,6 +351,9 @@ static int enable_lmh(void) int ret = 0; struct scm_desc desc_arg; + if (lmh_enabled) + return 0; + desc_arg.args[0] = 1; desc_arg.arginfo = SCM_ARGS(1, SCM_VAL); ret = scm_call2(SCM_SIP_FNID(SCM_SVC_LMH, LIMITS_PROFILE_CHANGE), @@ -358,6 +363,8 @@ static int enable_lmh(void) return ret; } + lmh_enabled = true; + return ret; } From 8678ba89dbe809ea977edc63b08344f3d692871c Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Tue, 7 Dec 2021 04:02:32 +0200 Subject: [PATCH 098/356] thermal: msm_lmh_dcvs: Protect lmh_enabled with qcom,legacy-lmh-enable Initialize LMH TZ only once only on legacy targets with defined qcom,legacy-lmh-enable property. Signed-off-by: Pavel Dubrova --- drivers/thermal/qcom/msm_lmh_dcvs.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/thermal/qcom/msm_lmh_dcvs.c b/drivers/thermal/qcom/msm_lmh_dcvs.c index 01aa176df2b5..9d5f2c7e74c7 100644 --- a/drivers/thermal/qcom/msm_lmh_dcvs.c +++ b/drivers/thermal/qcom/msm_lmh_dcvs.c @@ -346,7 +346,7 @@ static struct limits_dcvs_hw *get_dcvsh_hw_from_cpu(int cpu) return NULL; } -static int enable_lmh(void) +static int enable_lmh(struct device_node *dn) { int ret = 0; struct scm_desc desc_arg; @@ -363,7 +363,8 @@ static int enable_lmh(void) return ret; } - lmh_enabled = true; + if (of_property_read_bool(dn, "qcom,legacy-lmh-enable")) + lmh_enabled = true; return ret; } @@ -656,7 +657,7 @@ static int limits_dcvs_probe(struct platform_device *pdev) affinity); return ret; } - ret = enable_lmh(); + ret = enable_lmh(dn); if (ret) return ret; } From 2592d4121f5bce6b4ad773fc590e3e1cfd243e56 Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Sun, 12 Dec 2021 05:35:28 +0200 Subject: [PATCH 099/356] staging: ion: Add support for ion CMA heap to allocate from carveouts Because of an XPU errata we need to temporarily have the ION CMA heap support allocating from a careveout which isn't mapped into the kernel. Once the errata is fixed this change can be reverted. This patch is written with reference from commit "a568a844adc" in msm-4.14. [Pavel Dubrova] Adapted for 4.19 kernel. Original commit: https://source.codeaurora.org/quic/la/kernel/msm-5.4/commit/?h=LA.UM.9.16.r1-08500-MANNAR.0&id=b97c60442af50434b493901e956bac63b4d40c04 Change-Id: Id2bbb81644be514bdb90e743a028e65a05ebd55e Signed-off-by: Liam Mark Signed-off-by: Vivek Kumar Signed-off-by: Zhiqiang Tu Signed-off-by: Pavel Dubrova --- drivers/staging/android/ion/ion_cma_heap.c | 128 ++++++++++++++------- 1 file changed, 88 insertions(+), 40 deletions(-) diff --git a/drivers/staging/android/ion/ion_cma_heap.c b/drivers/staging/android/ion/ion_cma_heap.c index 2591a451e20a..46a8b5a152c5 100644 --- a/drivers/staging/android/ion/ion_cma_heap.c +++ b/drivers/staging/android/ion/ion_cma_heap.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "ion.h" #include "ion_secure_util.h" @@ -23,6 +24,12 @@ struct ion_cma_heap { struct cma *cma; }; +struct ion_cma_buffer_info { + void *cpu_addr; + dma_addr_t handle; + struct page *pages; +}; + #define to_cma_heap(x) container_of(x, struct ion_cma_heap, heap) static bool ion_heap_is_cma_heap_type(enum ion_heap_type type) @@ -30,90 +37,137 @@ static bool ion_heap_is_cma_heap_type(enum ion_heap_type type) return type == ION_HEAP_TYPE_DMA; } +static bool ion_cma_has_kernel_mapping(struct ion_heap *heap) +{ + struct device *dev = heap->priv; + struct device_node *mem_region; + + mem_region = of_parse_phandle(dev->of_node, "memory-region", 0); + if (!mem_region) + return false; + + return !of_property_read_bool(mem_region, "no-map"); +} + /* ION CMA heap operations functions */ static int ion_cma_allocate(struct ion_heap *heap, struct ion_buffer *buffer, unsigned long len, unsigned long flags) { struct ion_cma_heap *cma_heap = to_cma_heap(heap); + struct ion_cma_buffer_info *info; struct sg_table *table; - struct page *pages; + struct page *pages = NULL; unsigned long size = PAGE_ALIGN(len); unsigned long nr_pages = size >> PAGE_SHIFT; unsigned long align = get_order(size); int ret; struct device *dev = heap->priv; + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + if (ion_heap_is_cma_heap_type(buffer->heap->type) && is_secure_allocation(buffer->flags)) { pr_err("%s: CMA heap doesn't support secure allocations\n", __func__); - return -EINVAL; + goto free_info; } if (align > CONFIG_CMA_ALIGNMENT) align = CONFIG_CMA_ALIGNMENT; - pages = cma_alloc(cma_heap->cma, nr_pages, align, false); - if (!pages) - return -ENOMEM; - - if (hlos_accessible_buffer(buffer)) { - if (PageHighMem(pages)) { - unsigned long nr_clear_pages = nr_pages; - struct page *page = pages; - - while (nr_clear_pages > 0) { - void *vaddr = kmap_atomic(page); + if (!ion_cma_has_kernel_mapping(heap)) { + flags &= ~((unsigned long)ION_FLAG_CACHED); + buffer->flags = flags; - memset(vaddr, 0, PAGE_SIZE); - kunmap_atomic(vaddr); - page++; - nr_clear_pages--; + info->cpu_addr = dma_alloc_wc(dev, size, &info->handle, + GFP_KERNEL); + if (!info->cpu_addr) { + dev_err(dev, "failed to allocate buffer\n"); + goto free_info; + } + pages = pfn_to_page(PFN_DOWN(info->handle)); + } else { + pages = cma_alloc(cma_heap->cma, nr_pages, align, false); + if (!pages) + goto free_info; + + if (hlos_accessible_buffer(buffer)) { + if (PageHighMem(pages)) { + unsigned long nr_clear_pages = nr_pages; + struct page *page = pages; + + while (nr_clear_pages > 0) { + void *vaddr = kmap_atomic(page); + + memset(vaddr, 0, PAGE_SIZE); + kunmap_atomic(vaddr); + page++; + nr_clear_pages--; + } + } else { + memset(page_address(pages), 0, size); } - } else { - memset(page_address(pages), 0, size); } - } - if (MAKE_ION_ALLOC_DMA_READY || - (!hlos_accessible_buffer(buffer)) || - (!ion_buffer_cached(buffer))) - ion_pages_sync_for_device(dev, pages, size, - DMA_BIDIRECTIONAL); + if (MAKE_ION_ALLOC_DMA_READY || + (!hlos_accessible_buffer(buffer)) || + (!ion_buffer_cached(buffer))) + ion_pages_sync_for_device(dev, pages, size, + DMA_BIDIRECTIONAL); + } table = kmalloc(sizeof(*table), GFP_KERNEL); if (!table) - goto err; + goto err_alloc; ret = sg_alloc_table(table, 1, GFP_KERNEL); if (ret) - goto free_mem; + goto free_table; sg_set_page(table->sgl, pages, size, 0); buffer->priv_virt = pages; + info->pages = pages; + buffer->priv_virt = info; buffer->sg_table = table; return 0; -free_mem: +free_table: kfree(table); -err: - cma_release(cma_heap->cma, pages, nr_pages); +err_alloc: + if (info->cpu_addr) + dma_free_attrs(dev, size, info->cpu_addr, info->handle, 0); + else + cma_release(cma_heap->cma, pages, nr_pages); +free_info: + kfree(info); return -ENOMEM; } static void ion_cma_free(struct ion_buffer *buffer) { struct ion_cma_heap *cma_heap = to_cma_heap(buffer->heap); - struct page *pages = buffer->priv_virt; - unsigned long nr_pages = PAGE_ALIGN(buffer->size) >> PAGE_SHIFT; + struct ion_cma_buffer_info *info = buffer->priv_virt; + + if (info->cpu_addr) { + struct device *dev = buffer->heap->priv; + + dma_free_attrs(dev, PAGE_ALIGN(buffer->size), info->cpu_addr, + info->handle, 0); + } else { + struct page *pages = sg_page(buffer->sg_table->sgl); + unsigned long nr_pages = PAGE_ALIGN(buffer->size) >> PAGE_SHIFT; - /* release memory */ - cma_release(cma_heap->cma, pages, nr_pages); + /* release memory */ + cma_release(cma_heap->cma, pages, nr_pages); + } /* release sg table */ sg_free_table(buffer->sg_table); kfree(buffer->sg_table); + kfree(info); } static struct ion_heap_ops ion_cma_ops = { @@ -129,9 +183,6 @@ struct ion_heap *ion_cma_heap_create(struct ion_platform_heap *data) struct ion_cma_heap *cma_heap; struct device *dev = (struct device *)data->priv; - if (!dev->cma_area) - return ERR_PTR(-EINVAL); - cma_heap = kzalloc(sizeof(*cma_heap), GFP_KERNEL); if (!cma_heap) @@ -225,9 +276,6 @@ struct ion_heap *ion_cma_secure_heap_create(struct ion_platform_heap *data) struct ion_cma_heap *cma_heap; struct device *dev = (struct device *)data->priv; - if (!dev->cma_area) - return ERR_PTR(-EINVAL); - cma_heap = kzalloc(sizeof(*cma_heap), GFP_KERNEL); if (!cma_heap) From a2f8c3f2c6135270eb1b74e085aee9bc4f1aa688 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Wed, 6 Nov 2019 17:39:00 +0100 Subject: [PATCH 100/356] gpu: msm: adreno_coresight: Disable coresight code if !CONFIG_CORESIGHT This permits us to disable CONFIG_CORESIGHT for production devices. --- drivers/gpu/msm/adreno_coresight.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/msm/adreno_coresight.c b/drivers/gpu/msm/adreno_coresight.c index 5a4d93545c23..4c0e90db086d 100644 --- a/drivers/gpu/msm/adreno_coresight.c +++ b/drivers/gpu/msm/adreno_coresight.c @@ -393,6 +393,7 @@ static const struct coresight_ops adreno_coresight_ops = { void adreno_coresight_remove(struct adreno_device *adreno_dev) { +#ifdef CONFIG_CORESIGHT int i, adreno_dev_flag = -EINVAL; for (i = 0; i < GPU_CORESIGHT_MAX; ++i) { @@ -408,10 +409,14 @@ void adreno_coresight_remove(struct adreno_device *adreno_dev) adreno_dev->csdev[i] = NULL; } } +#else + return; +#endif } int adreno_coresight_init(struct adreno_device *adreno_dev) { +#ifdef CONFIG_CORESIGHT int ret = 0; struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); struct kgsl_device *device = KGSL_DEVICE(adreno_dev); @@ -464,4 +469,7 @@ int adreno_coresight_init(struct adreno_device *adreno_dev) of_node_put(node); return ret; +#else + return 0; +#endif } From 71fae237e4e6c5e5ca27415a611c1ea62bb485db Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Sun, 19 Dec 2021 14:20:14 +0200 Subject: [PATCH 101/356] msm: ipa3: Add IPAv3.5.1 S/W SRAM mapping Add IPA S/W SRAM mapping for IPAv3.5.1. SRAM is internal IPA memory used by IPA for different use-cases. The mapping maps different sections to different use-cases. Signed-off-by: Pavel Dubrova --- drivers/platform/msm/ipa/ipa_v3/ipa_utils.c | 77 ++++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c index fa6fa393fc23..6ef607e74cdf 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c @@ -2883,6 +2883,79 @@ static const struct ipa_ep_configuration ipa3_ep_mapping }; +static struct ipa3_mem_partition ipa_3_5_1_mem_part = { + .ofst_start = 0x280, + .v4_flt_hash_ofst = 0x288, + .v4_flt_hash_size = 0x78, + .v4_flt_hash_size_ddr = 0x4000, + .v4_flt_nhash_ofst = 0x308, + .v4_flt_nhash_size = 0x78, + .v4_flt_nhash_size_ddr = 0x4000, + .v6_flt_hash_ofst = 0x388, + .v6_flt_hash_size = 0x78, + .v6_flt_hash_size_ddr = 0x4000, + .v6_flt_nhash_ofst = 0x408, + .v6_flt_nhash_size = 0x78, + .v6_flt_nhash_size_ddr = 0x4000, + .v4_rt_num_index = 0xf, + .v4_modem_rt_index_lo = 0x0, + .v4_modem_rt_index_hi = 0x7, + .v4_apps_rt_index_lo = 0x8, + .v4_apps_rt_index_hi = 0xe, + .v4_rt_hash_ofst = 0x488, + .v4_rt_hash_size = 0x78, + .v4_rt_hash_size_ddr = 0x4000, + .v4_rt_nhash_ofst = 0x508, + .v4_rt_nhash_size = 0x78, + .v4_rt_nhash_size_ddr = 0x4000, + .v6_rt_num_index = 0xf, + .v6_modem_rt_index_lo = 0x0, + .v6_modem_rt_index_hi = 0x7, + .v6_apps_rt_index_lo = 0x8, + .v6_apps_rt_index_hi = 0xe, + .v6_rt_hash_ofst = 0x588, + .v6_rt_hash_size = 0x78, + .v6_rt_hash_size_ddr = 0x4000, + .v6_rt_nhash_ofst = 0x608, + .v6_rt_nhash_size = 0x78, + .v6_rt_nhash_size_ddr = 0x4000, + .modem_hdr_ofst = 0x688, + .modem_hdr_size = 0x140, + .apps_hdr_ofst = 0x7c8, + .apps_hdr_size = 0x0, + .apps_hdr_size_ddr = 0x800, + .modem_hdr_proc_ctx_ofst = 0x7d0, + .modem_hdr_proc_ctx_size = 0x200, + .apps_hdr_proc_ctx_ofst = 0x9d0, + .apps_hdr_proc_ctx_size = 0x200, + .apps_hdr_proc_ctx_size_ddr = 0x0, + .modem_comp_decomp_ofst = 0x0, + .modem_comp_decomp_size = 0x0, + .modem_ofst = 0xbd8, + .modem_size = 0x1024, + .apps_v4_flt_hash_ofst = 0x2000, + .apps_v4_flt_hash_size = 0x0, + .apps_v4_flt_nhash_ofst = 0x2000, + .apps_v4_flt_nhash_size = 0x0, + .apps_v6_flt_hash_ofst = 0x2000, + .apps_v6_flt_hash_size = 0x0, + .apps_v6_flt_nhash_ofst = 0x2000, + .apps_v6_flt_nhash_size = 0x0, + .uc_info_ofst = 0x80, + .uc_info_size = 0x200, + .end_ofst = 0x2000, + .apps_v4_rt_hash_ofst = 0x2000, + .apps_v4_rt_hash_size = 0x0, + .apps_v4_rt_nhash_ofst = 0x2000, + .apps_v4_rt_nhash_size = 0x0, + .apps_v6_rt_hash_ofst = 0x2000, + .apps_v6_rt_hash_size = 0x0, + .apps_v6_rt_nhash_ofst = 0x2000, + .apps_v6_rt_nhash_size = 0x0, + .uc_descriptor_ram_ofst = 0x1c00, + .uc_descriptor_ram_size = 0x400, +}; + static struct ipa3_mem_partition ipa_4_1_mem_part = { .ofst_start = 0x280, .v4_flt_hash_ofst = 0x288, @@ -5623,6 +5696,9 @@ int ipa3_straddle_boundary(u32 start, u32 end, u32 boundary) int ipa3_init_mem_partition(enum ipa_hw_type type) { switch (type) { + case IPA_HW_v3_5_1: + ipa3_ctx->ctrl->mem_partition = &ipa_3_5_1_mem_part; + break; case IPA_HW_v4_1: ipa3_ctx->ctrl->mem_partition = &ipa_4_1_mem_part; break; @@ -5645,7 +5721,6 @@ int ipa3_init_mem_partition(enum ipa_hw_type type) case IPA_HW_v3_0: case IPA_HW_v3_1: case IPA_HW_v3_5: - case IPA_HW_v3_5_1: case IPA_HW_v4_0: IPAERR("unsupported version %d\n", type); return -EPERM; From 6fa9c60735bd41eaaf214124032a02824024af37 Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Fri, 24 Dec 2021 04:34:42 +0200 Subject: [PATCH 102/356] msm: ipa3: rmnet_ipa: Protect ADPL over ODL for pre IPAv4.1 Do not call ipa3_odl_pipe_open/cleanup() functions for pre IPAv4.1 because ADPL over ODL functionality is not supported on earlier IPA HW versions. Signed-off-by: Pavel Dubrova --- drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c index 8a52d823ca63..93cff5708f73 100644 --- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c @@ -2767,7 +2767,8 @@ static int ipa3_lcl_mdm_ssr_notifier_cb(struct notifier_block *this, if (atomic_read(&rmnet_ipa3_ctx->is_ssr) && ipa3_ctx->ipa_hw_type >= IPA_HW_v4_0) ipa3_q6_post_shutdown_cleanup(); - ipa3_odl_pipe_cleanup(true); + if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_1) + ipa3_odl_pipe_cleanup(true); IPAWANINFO("IPA BEFORE_SHUTDOWN handling is complete\n"); break; case SUBSYS_AFTER_SHUTDOWN: @@ -2807,7 +2808,8 @@ static int ipa3_lcl_mdm_ssr_notifier_cb(struct notifier_block *this, if (!atomic_read(&rmnet_ipa3_ctx->is_initialized) && atomic_read(&rmnet_ipa3_ctx->is_ssr)) platform_driver_register(&rmnet_ipa_driver); - ipa3_odl_pipe_open(); + if (ipa3_ctx->ipa_hw_type >= IPA_HW_v4_1) + ipa3_odl_pipe_open(); IPAWANINFO("IPA AFTER_POWERUP handling is complete\n"); break; default: From c787263d61413e52fc092dcbdcf1e6b52eb9429d Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Wed, 26 Jan 2022 21:35:37 +0200 Subject: [PATCH 103/356] msm: ipa3: Remove barrier for IPAv3 for pipe suspend/resume Remove barrier for IPA targets under IPAv4 for pipe suspend/resume. Signed-off-by: Pavel Dubrova --- drivers/platform/msm/ipa/ipa_v3/ipa_utils.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c index 6ef607e74cdf..dfb17dda7a1b 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c @@ -7845,11 +7845,6 @@ static int _ipa_suspend_resume_pipe(enum ipa_client_type client, bool suspend) struct ipa3_ep_context *ep; int res; - if (ipa3_ctx->ipa_hw_type < IPA_HW_v4_0) { - IPAERR("not supported\n"); - return -EPERM; - } - ipa_ep_idx = ipa3_get_ep_mapping(client); if (ipa_ep_idx < 0) { IPADBG("client %d not configued\n", client); From 3b0622c529f14164fa5a59898473f90d28d05541 Mon Sep 17 00:00:00 2001 From: Neeraj Upadhyay Date: Tue, 20 Mar 2018 10:15:53 +0530 Subject: [PATCH 104/356] irqchip: gic-v3: provide save and restore api Provide api to save/restore GICD state for SPIs. SPI configuration is restored for GICD_ICFGR, GICD_ISENABLER, GICD_IPRIORITYR, GICD_IROUTER registers. Following is the sequence for restore: 1. For SPIs, check whether any of GICD_ICFGR, GICD_ISENABLER, GICD_IPRIORITYR, GICD_IROUTER, current configuration is different from saved configuration. For all irqs, with mismatched configurations, 2. Set GICD_ICENABLER and wait for its completion. 3. Restore any changed GICD_ICFGR, GICD_IPRIORITYR, GICD_IROUTER configurations. 4. Set GICD_ICACTIVER. 5. Set pending for the interrupt. 6. Enable interrupt and wait for its completion. [Pavel Dubrova] Adapted for 4.19 kernel. Original commit: https://source.codeaurora.org/quic/la/kernel/msm-4.9/commit/drivers/irqchip/irq-gic-v3.c?h=LA.UM.10.3.r1-00600-sdm845.0&id=b179a8e1e9f8c085f64fb0b60f1244a882fad01e Change-Id: I31cd5eb8c3226dcdfd474bc88b91c1cb5ca909e6 Signed-off-by: Neeraj Upadhyay Signed-off-by: Channagoud Kadabi Signed-off-by: Pavel Dubrova --- arch/arm/include/asm/arch_gicv3.h | 1 + arch/arm64/include/asm/arch_gicv3.h | 1 + drivers/irqchip/irq-gic-v3.c | 324 +++++++++++++++++++++++++++- include/linux/irqchip/arm-gic-v3.h | 2 + 4 files changed, 327 insertions(+), 1 deletion(-) diff --git a/arch/arm/include/asm/arch_gicv3.h b/arch/arm/include/asm/arch_gicv3.h index 0bd530702118..b414b6ad4b33 100644 --- a/arch/arm/include/asm/arch_gicv3.h +++ b/arch/arm/include/asm/arch_gicv3.h @@ -276,6 +276,7 @@ static inline u64 __gic_readq_nonatomic(const volatile void __iomem *addr) * The upper-word (aff3) will always be 0, so there is no need for a lock. */ #define gic_write_irouter(v, c) __gic_writeq_nonatomic(v, c) +#define gic_read_irouter(c) __gic_readq_nonatomic(c) /* * GICR_TYPER is an ID register and doesn't need atomicity. diff --git a/arch/arm64/include/asm/arch_gicv3.h b/arch/arm64/include/asm/arch_gicv3.h index cd2040d48a4c..ad561e5f8b64 100644 --- a/arch/arm64/include/asm/arch_gicv3.h +++ b/arch/arm64/include/asm/arch_gicv3.h @@ -115,6 +115,7 @@ static inline void gic_write_bpr1(u32 val) } #define gic_read_typer(c) readq_relaxed_no_log(c) +#define gic_read_irouter(c) readq_relaxed_no_log(c) #define gic_write_irouter(v, c) writeq_relaxed_no_log(v, c) #define gic_read_lpir(c) readq_relaxed_no_log(c) #define gic_write_lpir(v, c) writeq_relaxed_no_log(v, c) diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index cd5e3285a01a..c3fc6dc111a4 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -45,6 +45,34 @@ #include "irq-gic-common.h" +#define MAX_IRQ 1020U /* Max number of SGI+PPI+SPI */ +#define SPI_START_IRQ 32 /* SPI start irq number */ +#define GICD_ICFGR_BITS 2 /* 2 bits per irq in GICD_ICFGR */ +#define GICD_ISENABLER_BITS 1 /* 1 bit per irq in GICD_ISENABLER */ +#define GICD_IPRIORITYR_BITS 8 /* 8 bits per irq in GICD_IPRIORITYR */ + +/* 32 bit mask with lower n bits set */ +#define UMASK_LOW(n) (~0U >> (32 - (n))) + +/* Number of 32-bit words required to store all irqs, for + * registers where each word stores configuration for each irq + * in bits_per_irq bits. + */ +#define NUM_IRQ_WORDS(bits_per_irq) (DIV_ROUND_UP(MAX_IRQ, \ + 32 / (bits_per_irq))) +#define MAX_IRQS_IGNORE 10 + +#define IRQ_NR_BOUND(nr) min((nr), MAX_IRQ) + +/* Bitmap to irqs, which are restored */ +static DECLARE_BITMAP(irqs_restore, MAX_IRQ); + +/* Bitmap to irqs, for which restore is ignored. + * Presently, only GICD_IROUTER mismatches are + * ignored. + */ +static DECLARE_BITMAP(irqs_ignore_restore, MAX_IRQ); + struct redist_region { void __iomem *redist_base; phys_addr_t phys_base; @@ -62,6 +90,16 @@ struct gic_chip_data { bool has_rss; unsigned int irq_nr; struct partition_desc *ppi_descs[16]; + + u64 saved_spi_router[MAX_IRQ]; + u32 saved_spi_enable[NUM_IRQ_WORDS(GICD_ISENABLER_BITS)]; + u32 saved_spi_cfg[NUM_IRQ_WORDS(GICD_ICFGR_BITS)]; + u32 saved_spi_priority[NUM_IRQ_WORDS(GICD_IPRIORITYR_BITS)]; + + u64 changed_spi_router[MAX_IRQ]; + u32 changed_spi_enable[NUM_IRQ_WORDS(GICD_ISENABLER_BITS)]; + u32 changed_spi_cfg[NUM_IRQ_WORDS(GICD_ICFGR_BITS)]; + u32 changed_spi_priority[NUM_IRQ_WORDS(GICD_IPRIORITYR_BITS)]; }; static struct gic_chip_data gic_data __read_mostly; @@ -70,6 +108,58 @@ static DEFINE_STATIC_KEY_TRUE(supports_deactivate_key); static struct gic_kvm_info gic_v3_kvm_info; static DEFINE_PER_CPU(bool, has_rss); +enum gicd_save_restore_reg { + SAVED_ICFGR, + SAVED_IS_ENABLER, + SAVED_IPRIORITYR, + NUM_SAVED_GICD_REGS, +}; + +/* Stores start address of spi config for saved gicd regs */ +static u32 *saved_spi_regs_start[NUM_SAVED_GICD_REGS] = { + [SAVED_ICFGR] = gic_data.saved_spi_cfg, + [SAVED_IS_ENABLER] = gic_data.saved_spi_enable, + [SAVED_IPRIORITYR] = gic_data.saved_spi_priority, +}; + +/* Stores start address of spi config for changed gicd regs */ +static u32 *changed_spi_regs_start[NUM_SAVED_GICD_REGS] = { + [SAVED_ICFGR] = gic_data.changed_spi_cfg, + [SAVED_IS_ENABLER] = gic_data.changed_spi_enable, + [SAVED_IPRIORITYR] = gic_data.changed_spi_priority, +}; + +/* GICD offset for saved registers */ +static u32 gicd_offset[NUM_SAVED_GICD_REGS] = { + [SAVED_ICFGR] = GICD_ICFGR, + [SAVED_IS_ENABLER] = GICD_ISENABLER, + [SAVED_IPRIORITYR] = GICD_IPRIORITYR, +}; + +/* Bits per irq word, for gicd saved registers */ +static u32 gicd_reg_bits_per_irq[NUM_SAVED_GICD_REGS] = { + [SAVED_ICFGR] = GICD_ICFGR_BITS, + [SAVED_IS_ENABLER] = GICD_ISENABLER_BITS, + [SAVED_IPRIORITYR] = GICD_IPRIORITYR_BITS, +}; + +#define for_each_spi_irq_word(i, reg) \ + for (i = 0; \ + i < DIV_ROUND_UP(IRQ_NR_BOUND(gic_data.irq_nr) - SPI_START_IRQ, \ + 32 / gicd_reg_bits_per_irq[reg]); \ + i++) + +#define read_spi_word_offset(base, reg, i) \ + readl_relaxed_no_log( \ + base + gicd_offset[reg] + i * 4 + \ + SPI_START_IRQ * gicd_reg_bits_per_irq[reg] / 8) + +#define restore_spi_word_offset(base, reg, i) \ + writel_relaxed_no_log( \ + saved_spi_regs_start[reg][i],\ + base + gicd_offset[reg] + i * 4 + \ + SPI_START_IRQ * gicd_reg_bits_per_irq[reg] / 8) + #define MPIDR_RS(mpidr) (((mpidr) & 0xF0UL) >> 4) #define gic_data_rdist() (this_cpu_ptr(gic_data.rdists.rdist)) #define gic_data_rdist_rd_base() (gic_data_rdist()->rd_base) @@ -137,6 +227,229 @@ static u64 __maybe_unused gic_read_iar(void) } #endif +void gic_v3_dist_save(void) +{ + void __iomem *base = gic_data.dist_base; + int reg, i; + + for (reg = SAVED_ICFGR; reg < NUM_SAVED_GICD_REGS; reg++) { + for_each_spi_irq_word(i, reg) { + saved_spi_regs_start[reg][i] = + read_spi_word_offset(base, reg, i); + } + } + + for (i = 32; i < IRQ_NR_BOUND(gic_data.irq_nr); i++) + gic_data.saved_spi_router[i] = + gic_read_irouter(base + GICD_IROUTER + i * 8); +} + +static void _gicd_check_reg(enum gicd_save_restore_reg reg) +{ + void __iomem *base = gic_data.dist_base; + u32 *saved_spi_cfg = saved_spi_regs_start[reg]; + u32 *changed_spi_cfg = changed_spi_regs_start[reg]; + u32 bits_per_irq = gicd_reg_bits_per_irq[reg]; + u32 current_cfg = 0; + int i, j = SPI_START_IRQ, l; + u32 k; + + for_each_spi_irq_word(i, reg) { + current_cfg = read_spi_word_offset(base, reg, i); + if (current_cfg != saved_spi_cfg[i]) { + for (k = current_cfg ^ saved_spi_cfg[i], + l = 0; k ; k >>= bits_per_irq, l++) { + if (k & UMASK_LOW(bits_per_irq)) + set_bit(j+l, irqs_restore); + } + changed_spi_cfg[i] = current_cfg ^ saved_spi_cfg[i]; + } + j += 32 / bits_per_irq; + } +} + +#define _gic_v3_dist_check_icfgr() \ + _gicd_check_reg(SAVED_ICFGR) +#define _gic_v3_dist_check_ipriorityr() \ + _gicd_check_reg(SAVED_IPRIORITYR) +#define _gic_v3_dist_check_isenabler() \ + _gicd_check_reg(SAVED_IS_ENABLER) + +static void _gic_v3_dist_check_irouter(void) +{ + void __iomem *base = gic_data.dist_base; + u64 current_irouter_cfg = 0; + int i; + + for (i = 32; i < IRQ_NR_BOUND(gic_data.irq_nr); i++) { + if (test_bit(i, irqs_ignore_restore)) + continue; + current_irouter_cfg = gic_read_irouter( + base + GICD_IROUTER + i * 8); + if (current_irouter_cfg != gic_data.saved_spi_router[i]) { + set_bit(i, irqs_restore); + gic_data.changed_spi_router[i] = + current_irouter_cfg ^ gic_data.saved_spi_router[i]; + } + } +} + +static void _gic_v3_dist_restore_reg(enum gicd_save_restore_reg reg) +{ + void __iomem *base = gic_data.dist_base; + int i; + + for_each_spi_irq_word(i, reg) { + if (changed_spi_regs_start[reg][i]) + restore_spi_word_offset(base, reg, i); + } + + /* Commit all restored configurations before subsequent writes */ + wmb(); +} + +#define _gic_v3_dist_restore_icfgr() _gic_v3_dist_restore_reg(SAVED_ICFGR) +#define _gic_v3_dist_restore_ipriorityr() \ + _gic_v3_dist_restore_reg(SAVED_IPRIORITYR) + +static void _gic_v3_dist_restore_set_reg(u32 offset) +{ + void __iomem *base = gic_data.dist_base; + int i, j = SPI_START_IRQ, l; + int irq_nr = IRQ_NR_BOUND(gic_data.irq_nr) - SPI_START_IRQ; + + for (i = 0; i < DIV_ROUND_UP(irq_nr, 32); i++, j += 32) { + u32 reg_val = readl_relaxed_no_log(base + offset + i * 4 + 4); + bool irqs_restore_updated = 0; + + for (l = 0; l < 32; l++) { + if (test_bit(j+l, irqs_restore)) { + reg_val |= BIT(l); + irqs_restore_updated = 1; + } + } + + if (irqs_restore_updated) { + writel_relaxed_no_log( + reg_val, base + offset + i * 4 + 4); + } + } + + /* Commit restored configuration updates before subsequent writes */ + wmb(); +} + +#define _gic_v3_dist_restore_isenabler() \ + _gic_v3_dist_restore_set_reg(GICD_ISENABLER) + +#define _gic_v3_dist_restore_ispending() \ + _gic_v3_dist_restore_set_reg(GICD_ISPENDR) + +static void _gic_v3_dist_restore_irouter(void) +{ + void __iomem *base = gic_data.dist_base; + int i; + + for (i = 32; i < IRQ_NR_BOUND(gic_data.irq_nr); i++) { + if (test_bit(i, irqs_ignore_restore)) + continue; + if (gic_data.changed_spi_router[i]) { + gic_write_irouter(gic_data.saved_spi_router[i], + base + GICD_IROUTER + i * 8); + } + } + + /* Commit GICD_IROUTER writes before subsequent writes */ + wmb(); +} + +static void _gic_v3_dist_clear_reg(u32 offset) +{ + void __iomem *base = gic_data.dist_base; + int i, j = SPI_START_IRQ, l; + int irq_nr = IRQ_NR_BOUND(gic_data.irq_nr) - SPI_START_IRQ; + + for (i = 0; i < DIV_ROUND_UP(irq_nr, 32); i++, j += 32) { + u32 clear = 0; + bool irqs_restore_updated = 0; + + for (l = 0; l < 32; l++) { + if (test_bit(j+l, irqs_restore)) { + clear |= BIT(l); + irqs_restore_updated = 1; + } + } + + if (irqs_restore_updated) { + writel_relaxed_no_log( + clear, base + offset + i * 4 + 4); + } + } + + /* Commit clearing of irq config before subsequent writes */ + wmb(); +} + +#define _gic_v3_dist_set_icenabler() \ + _gic_v3_dist_clear_reg(GICD_ICENABLER) + +#define _gic_v3_dist_set_icpending() \ + _gic_v3_dist_clear_reg(GICD_ICPENDR) + +#define _gic_v3_dist_set_icactive() \ + _gic_v3_dist_clear_reg(GICD_ICACTIVER) + +/* Restore GICD state for SPIs. SPI configuration is restored + * for GICD_ICFGR, GICD_ISENABLER, GICD_IPRIORITYR, GICD_IROUTER + * registers. Following is the sequence for restore: + * + * 1. For SPIs, check whether any of GICD_ICFGR, GICD_ISENABLER, + * GICD_IPRIORITYR, GICD_IROUTER, current configuration is + * different from saved configuration. + * + * For all irqs, with mismatched configurations, + * + * 2. Set GICD_ICENABLER and wait for its completion. + * + * 3. Restore any changed GICD_ICFGR, GICD_IPRIORITYR, GICD_IROUTER + * configurations. + * + * 4. Set GICD_ICACTIVER. + * + * 5. Set pending for the interrupt. + * + * 6. Enable interrupt and wait for its completion. + * + */ +void gic_v3_dist_restore(void) +{ + _gic_v3_dist_check_icfgr(); + _gic_v3_dist_check_ipriorityr(); + _gic_v3_dist_check_isenabler(); + _gic_v3_dist_check_irouter(); + + if (bitmap_empty(irqs_restore, IRQ_NR_BOUND(gic_data.irq_nr))) + return; + + _gic_v3_dist_set_icenabler(); + gic_dist_wait_for_rwp(); + + _gic_v3_dist_restore_icfgr(); + _gic_v3_dist_restore_ipriorityr(); + _gic_v3_dist_restore_irouter(); + + _gic_v3_dist_set_icactive(); + + _gic_v3_dist_set_icpending(); + _gic_v3_dist_restore_ispending(); + + _gic_v3_dist_restore_isenabler(); + gic_dist_wait_for_rwp(); + + /* Commit all writes before proceeding */ + wmb(); +} + static void gic_enable_redist(bool enable) { void __iomem *rbase; @@ -1382,7 +1695,8 @@ static int __init gicv3_of_init(struct device_node *node, struct device_node *pa struct redist_region *rdist_regs; u64 redist_stride; u32 nr_redist_regions; - int err, i; + int err, i, ignore_irqs_len; + u32 ignore_restore_irqs[MAX_IRQS_IGNORE] = {0}; dist_base = of_iomap(node, 0); if (!dist_base) { @@ -1432,6 +1746,14 @@ static int __init gicv3_of_init(struct device_node *node, struct device_node *pa if (static_branch_likely(&supports_deactivate_key)) gic_of_setup_kvm_info(node); + + ignore_irqs_len = of_property_read_variable_u32_array(node, + "ignored-save-restore-irqs", + ignore_restore_irqs, + 0, MAX_IRQS_IGNORE); + for (i = 0; i < ignore_irqs_len; i++) + set_bit(ignore_restore_irqs[i], irqs_ignore_restore); + return 0; out_unmap_rdist: diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h index db71f25ad793..304d9fa9657a 100644 --- a/include/linux/irqchip/arm-gic-v3.h +++ b/include/linux/irqchip/arm-gic-v3.h @@ -616,6 +616,8 @@ static inline bool gic_enable_sre(void) return !!(val & ICC_SRE_EL1_SRE); } +void gic_v3_dist_save(void); +void gic_v3_dist_restore(void); #endif #endif From 7945465c290605ab53f081657b9e65c6aa7fc4d5 Mon Sep 17 00:00:00 2001 From: Neeraj Upadhyay Date: Sun, 10 Jun 2018 20:29:52 +0530 Subject: [PATCH 105/356] irqchip: gic-v3: Clear restore configuration across save/restore Clear all saved restore configuration, and changed spi configuration, from prior save/restore. Change-Id: Ic750b39d95d074d911406cf44b295c251532e40e Signed-off-by: Neeraj Upadhyay --- drivers/irqchip/irq-gic-v3.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index c3fc6dc111a4..3ec90125ff01 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -232,16 +232,21 @@ void gic_v3_dist_save(void) void __iomem *base = gic_data.dist_base; int reg, i; + bitmap_zero(irqs_restore, MAX_IRQ); + for (reg = SAVED_ICFGR; reg < NUM_SAVED_GICD_REGS; reg++) { for_each_spi_irq_word(i, reg) { saved_spi_regs_start[reg][i] = read_spi_word_offset(base, reg, i); + changed_spi_regs_start[reg][i] = 0; } } - for (i = 32; i < IRQ_NR_BOUND(gic_data.irq_nr); i++) + for (i = 32; i < IRQ_NR_BOUND(gic_data.irq_nr); i++) { gic_data.saved_spi_router[i] = gic_read_irouter(base + GICD_IROUTER + i * 8); + gic_data.changed_spi_router[i] = 0; + } } static void _gicd_check_reg(enum gicd_save_restore_reg reg) From 18185faf217e6bdaaf677d18d8929737a35ec40b Mon Sep 17 00:00:00 2001 From: Gaurav Kohli Date: Wed, 27 Jun 2018 12:14:53 +0530 Subject: [PATCH 106/356] irqchip: gic-v3: Restore enable bit of spi interrupts While setting enable bit of spi interrupt, there is chance of enabling spurious interrupt which is by default disabled for soc. So instead of setting restore the previous state of enable bit. Change-Id: Ie6e363f04864fc6e36be83ebd20b19b5e6b45f54 Signed-off-by: Gaurav Kohli --- drivers/irqchip/irq-gic-v3.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 3ec90125ff01..12a2bdaf0d61 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -345,7 +345,7 @@ static void _gic_v3_dist_restore_set_reg(u32 offset) } #define _gic_v3_dist_restore_isenabler() \ - _gic_v3_dist_restore_set_reg(GICD_ISENABLER) + _gic_v3_dist_restore_reg(SAVED_IS_ENABLER) #define _gic_v3_dist_restore_ispending() \ _gic_v3_dist_restore_set_reg(GICD_ISPENDR) @@ -423,7 +423,7 @@ static void _gic_v3_dist_clear_reg(u32 offset) * * 5. Set pending for the interrupt. * - * 6. Enable interrupt and wait for its completion. + * 6. Restore Enable bit of interrupt and wait for its completion. * */ void gic_v3_dist_restore(void) From 0efe73b4caa7f4051cb123a111b494f8e2f39096 Mon Sep 17 00:00:00 2001 From: Neeraj Upadhyay Date: Thu, 2 Aug 2018 11:13:46 +0530 Subject: [PATCH 107/356] irqchip: gic-v3: Skip save/restore when gic is uninitialized Skip save and restore of GIC SPI configuration, if the GICV3 drivers hasn't been initialized. Change-Id: I1bc32f58eef349487b2096ea2c26d491ee45a433 Signed-off-by: Neeraj Upadhyay --- drivers/irqchip/irq-gic-v3.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 12a2bdaf0d61..baad4c87ec2f 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -232,6 +232,9 @@ void gic_v3_dist_save(void) void __iomem *base = gic_data.dist_base; int reg, i; + if (!base) + return; + bitmap_zero(irqs_restore, MAX_IRQ); for (reg = SAVED_ICFGR; reg < NUM_SAVED_GICD_REGS; reg++) { @@ -428,6 +431,9 @@ static void _gic_v3_dist_clear_reg(u32 offset) */ void gic_v3_dist_restore(void) { + if (!gic_data.dist_base) + return; + _gic_v3_dist_check_icfgr(); _gic_v3_dist_check_ipriorityr(); _gic_v3_dist_check_isenabler(); From 35dee5068cd2a56480f2494da8822f7e25474460 Mon Sep 17 00:00:00 2001 From: Mahesh Sivasubramanian Date: Tue, 20 Mar 2018 08:43:19 -0600 Subject: [PATCH 108/356] soc: qcom: system_pm: Save/restore GICD registers at system sleep Some of the GICD registers could be read in and stored as zeros if an intterupt is triggered around the same time as the system sleep. The pending state of the interrupt would be latched but the configuration registers for the interrupt is reset. To ensure that the interrupt triggers, restore the interrupts configuration around System sleep notification. Change-Id: Ib04720241e8fa4382383bd08897c4e19aaaded8c Signed-off-by: Mahesh Sivasubramanian Signed-off-by: Pavel Dubrova --- drivers/soc/qcom/system_pm.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/soc/qcom/system_pm.c b/drivers/soc/qcom/system_pm.c index 198f0e9f146e..4ad97d7ca6e7 100644 --- a/drivers/soc/qcom/system_pm.c +++ b/drivers/soc/qcom/system_pm.c @@ -16,6 +16,13 @@ #define PDC_TIME_VALID_SHIFT 31 #define PDC_TIME_UPPER_MASK 0xFFFFFF +#if defined(CONFIG_ARM_GIC_V3) && defined(CONFIG_ARCH_SDM845) +#include +#else +static inline void gic_v3_dist_restore(void) {} +static inline void gic_v3_dist_save(void) {} +#endif + static struct device *dev; static int setup_wakeup(uint32_t lo, uint32_t hi) @@ -55,6 +62,7 @@ static bool system_sleep_allowed(void) */ static int system_sleep_enter(struct cpumask *mask) { + gic_v3_dist_save(); return rpmh_flush(dev); } @@ -65,6 +73,7 @@ static void system_sleep_exit(bool success) { if (success) msm_rpmh_master_stats_update(); + gic_v3_dist_restore(); } static struct system_pm_ops pm_ops = { From a05910b5fa59901ac6695c14f178ac500b830d96 Mon Sep 17 00:00:00 2001 From: "Angelo G. Del Regno" Date: Thu, 6 Jun 2019 18:05:44 +0200 Subject: [PATCH 109/356] soc: qcom: spss_utils: Ignore emulation type register if not present This register is present only on new SoCs and shouldn't be present on older ones like MSM8998 or SDM630. For this reason, warn the user, but do not fail if this register is not found, as it's used only there and it's not necessary for core driver functionality. --- drivers/soc/qcom/spss_utils.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/soc/qcom/spss_utils.c b/drivers/soc/qcom/spss_utils.c index e3ab1c4b28e5..be6c08b8bc5b 100644 --- a/drivers/soc/qcom/spss_utils.c +++ b/drivers/soc/qcom/spss_utils.c @@ -805,8 +805,8 @@ static int spss_parse_dt(struct device_node *node) ret = of_property_read_u32(node, "qcom,spss-emul-type-reg-addr", &spss_emul_type_reg_addr); if (ret < 0) { - pr_err("can't get spss-emulation-type-reg addr\n"); - return -EINVAL; + pr_warn("can't get spss-emulation-type-reg addr\n"); + goto end; } spss_emul_type_reg = ioremap_nocache(spss_emul_type_reg_addr, @@ -825,6 +825,7 @@ static int spss_parse_dt(struct device_node *node) firmware_type = SPSS_FW_TYPE_NONE; } iounmap(spss_emul_type_reg); +end: /* PIL-SPSS area */ np = of_parse_phandle(node, "pil-mem", 0); From 388eb3e01526470aced262ebac13f96fc6187182 Mon Sep 17 00:00:00 2001 From: Santosh Dronamraju Date: Thu, 1 Oct 2020 20:56:58 +0530 Subject: [PATCH 110/356] soc: qcom: spss_utils: Add support for legacy SPSS The spss-util driver provides utilities required for the Secure Processor Subsystem (SPSS). It provides the fuse state for key selection and the SPSS HW version. Legacy spss not support load spss by UEFI and also not support CMAC/IAR feature. Change-Id: Iea0d66ed66a2817850f99f74bf716d33db956812 Signed-off-by: Santosh Dronamraju --- drivers/soc/qcom/spss_utils.c | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/drivers/soc/qcom/spss_utils.c b/drivers/soc/qcom/spss_utils.c index be6c08b8bc5b..47e8df7c1294 100644 --- a/drivers/soc/qcom/spss_utils.c +++ b/drivers/soc/qcom/spss_utils.c @@ -64,6 +64,8 @@ static u32 spss_emul_type_reg_addr; /* TCSR_SOC_EMULATION_TYPE */ static void *iar_notif_handle; static struct notifier_block *iar_nb; static bool is_iar_active; +/* To differentiate legacy and new generation of hardware supported features*/ +static bool is_cmac_and_iar_feature_supported = true; #define CMAC_SIZE_IN_BYTES (128/8) /* 128 bit = 16 bytes */ #define CMAC_SIZE_IN_DWORDS (CMAC_SIZE_IN_BYTES/sizeof(u32)) /* 4 dwords */ @@ -330,6 +332,9 @@ static int spss_create_sysfs(struct device *dev) goto remove_test_fuse_state; } + if (!is_cmac_and_iar_feature_supported) + goto out; + ret = device_create_file(dev, &dev_attr_cmac_buf); if (ret < 0) { pr_err("failed to create sysfs file for cmac_buf.\n"); @@ -360,7 +365,7 @@ static int spss_create_sysfs(struct device *dev) goto remove_pbl_cmac; } - +out: return 0; remove_pbl_cmac: @@ -525,6 +530,11 @@ static long spss_utils_ioctl(struct file *file, return -EINVAL; } + if (!is_cmac_and_iar_feature_supported) { + pr_err("legacy SPSS not support cmac,iar feature.\n"); + return -EINVAL; + } + /* spdaemon uses this ioctl only when IAR is active */ is_iar_active = true; @@ -827,6 +837,11 @@ static int spss_parse_dt(struct device_node *node) iounmap(spss_emul_type_reg); end: + if (!is_cmac_and_iar_feature_supported) { + pr_info("legacy SPSS not support cmac & iar feature.\n"); + goto out; + } + /* PIL-SPSS area */ np = of_parse_phandle(node, "pil-mem", 0); if (!np) { @@ -922,7 +937,7 @@ static int spss_parse_dt(struct device_node *node) iar_state = val1; pr_debug("iar_state [%d]\n", iar_state); - +out: return 0; } @@ -1114,6 +1129,10 @@ static int spss_utils_pil_callback(struct notifier_block *nb, pr_debug("[SUBSYS_PROXY_UNVOTE] event.\n"); break; case SUBSYS_BEFORE_AUTH_AND_RESET: + if (!is_cmac_and_iar_feature_supported) { + pr_info("legacy SPSS not support cmac,iar feature.\n"); + break; + } /* do nothing if IAR is not active */ if (!is_iar_active) return NOTIFY_OK; @@ -1165,6 +1184,14 @@ static int spss_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, dev); + /* Based on flag will differentiate legacy spss + * supported features + */ + if (of_property_read_bool(pdev->dev.of_node, + "qcom,no-cmac-and-iar-feature-support")) { + pr_info("legacy SPSS not support cmac & iar feature.\n"); + is_cmac_and_iar_feature_supported = false; + } ret = spss_parse_dt(np); if (ret < 0) From 31deea48015767030d1ec40c84e0a615fa777c25 Mon Sep 17 00:00:00 2001 From: MrArtemSid Date: Mon, 4 Jul 2022 15:05:00 +0400 Subject: [PATCH 111/356] arm64: dts: qcom: sdm845: Update spss_utility configuration Legacy spss not support load spss by UEFI and also not support CMAC/IAR feature. --- arch/arm64/boot/dts/qcom/sdm845.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index 340e498f126b..c12573352478 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -2558,6 +2558,7 @@ 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,no-cmac-and-iar-feature-support; status = "ok"; }; From 3eaf868c218ab8599c8bca73131538a1aa646b44 Mon Sep 17 00:00:00 2001 From: MrArtemSid Date: Thu, 4 Nov 2021 23:14:44 +0400 Subject: [PATCH 112/356] techpack: display: Makefile: use kona configs for sdm845 --- techpack/display/Makefile | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/techpack/display/Makefile b/techpack/display/Makefile index b2829628ff13..ce00931b0903 100644 --- a/techpack/display/Makefile +++ b/techpack/display/Makefile @@ -25,6 +25,14 @@ ifeq ($(CONFIG_ARCH_BENGAL), y) LINUXINCLUDE += -include $(srctree)/techpack/display/config/bengaldispconf.h endif +ifeq ($(CONFIG_ARCH_SDM845), y) +include $(srctree)/techpack/display/config/konadisp.conf +endif + +ifeq ($(CONFIG_ARCH_SDM845), y) +LINUXINCLUDE += -include $(srctree)/techpack/display/config/konadispconf.h +endif + obj-$(CONFIG_DRM_MSM) += msm/ obj-$(CONFIG_MSM_SDE_ROTATOR) += rotator/ obj-$(CONFIG_QCOM_MDSS_PLL) += pll/ From d049717dc7fc3ffeef7e17f474df9b17a017f5b4 Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Wed, 8 Dec 2021 14:11:00 +0200 Subject: [PATCH 113/356] msm: Add debug support for sdm845 target Add debug support for sdm845 target for sde driver. Signed-off-by: Pavel Dubrova --- techpack/display/msm/sde_dbg.c | 1026 +++++++++++++++++++++++++++++++- 1 file changed, 1025 insertions(+), 1 deletion(-) diff --git a/techpack/display/msm/sde_dbg.c b/techpack/display/msm/sde_dbg.c index 04037d5c5f20..8f57219941f7 100644 --- a/techpack/display/msm/sde_dbg.c +++ b/techpack/display/msm/sde_dbg.c @@ -301,6 +301,1015 @@ static void _sde_debug_bus_ppb1_dump(void __iomem *mem_base, entry->wr_addr, entry->block_id, entry->test_id, val); } +static void _sde_debug_bus_axi_dump_sdm845(void __iomem *mem_base, + struct sde_debug_bus_entry *entry, u32 val) +{ + u32 status, i; + + if (!mem_base || !entry) + return; + + for (i = 0; i <= RSC_DEBUG_MUX_SEL_SDM845; i++) { + sde_rsc_debug_dump(i); + + /* make sure that mux_sel updated */ + wmb(); + + /* read status again after rsc routes the debug bus */ + status = readl_relaxed(mem_base + DBGBUS_DSPP_STATUS); + + dev_err(sde_dbg_base.dev, "rsc mux_sel:%d 0x%x %d %d 0x%x\n", + i, entry->wr_addr, entry->block_id, + entry->test_id, status); + } +} + +static struct sde_debug_bus_entry dbg_bus_sde_sdm845[] = { + + /* Unpack 0 sspp 0*/ + { DBGBUS_SSPP0, 50, 2 }, + { DBGBUS_SSPP0, 60, 2 }, + { DBGBUS_SSPP0, 70, 2 }, + + /* Upack 0 sspp 1*/ + { DBGBUS_SSPP1, 50, 2 }, + { DBGBUS_SSPP1, 60, 2 }, + { DBGBUS_SSPP1, 70, 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 }, + + /* qseed */ + { DBGBUS_SSPP0, 6, 0}, + { DBGBUS_SSPP0, 6, 1}, + { DBGBUS_SSPP0, 26, 0}, + { DBGBUS_SSPP0, 26, 1}, + { DBGBUS_SSPP1, 6, 0}, + { DBGBUS_SSPP1, 6, 1}, + { DBGBUS_SSPP1, 26, 0}, + { DBGBUS_SSPP1, 26, 1}, + + /* scale */ + { DBGBUS_SSPP0, 16, 0}, + { DBGBUS_SSPP0, 16, 1}, + { DBGBUS_SSPP0, 36, 0}, + { DBGBUS_SSPP0, 36, 1}, + { DBGBUS_SSPP1, 16, 0}, + { DBGBUS_SSPP1, 16, 1}, + { DBGBUS_SSPP1, 36, 0}, + { DBGBUS_SSPP1, 36, 1}, + + /* 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 }, + + { DBGBUS_SSPP0, 35, 0 }, + { DBGBUS_SSPP0, 35, 1 }, + { DBGBUS_SSPP0, 35, 2 }, + { DBGBUS_SSPP0, 35, 3 }, + + /* 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 }, + + { DBGBUS_SSPP1, 35, 0 }, + { DBGBUS_SSPP1, 35, 1 }, + { DBGBUS_SSPP1, 35, 2 }, + + /* 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 }, + + /* dspp */ + { DBGBUS_DSPP, 13, 0 }, + { DBGBUS_DSPP, 19, 0 }, + { DBGBUS_DSPP, 14, 0 }, + { DBGBUS_DSPP, 14, 1 }, + { DBGBUS_DSPP, 14, 3 }, + { DBGBUS_DSPP, 20, 0 }, + { DBGBUS_DSPP, 20, 1 }, + { DBGBUS_DSPP, 20, 3 }, + + /* 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 }, + + /* 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 }, + + /* lm_lut */ + { DBGBUS_DSPP, 109, 0 }, + { DBGBUS_DSPP, 105, 0 }, + { DBGBUS_DSPP, 103, 0 }, + + /* 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 }, + + /* LM5 */ + { 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 }, + + /* csc */ + { DBGBUS_SSPP0, 7, 0}, + { DBGBUS_SSPP0, 7, 1}, + { DBGBUS_SSPP0, 27, 0}, + { DBGBUS_SSPP0, 27, 1}, + { DBGBUS_SSPP1, 7, 0}, + { DBGBUS_SSPP1, 7, 1}, + { DBGBUS_SSPP1, 27, 0}, + { DBGBUS_SSPP1, 27, 1}, + + /* pcc */ + { DBGBUS_SSPP0, 3, 3}, + { DBGBUS_SSPP0, 23, 3}, + { DBGBUS_SSPP0, 33, 3}, + { DBGBUS_SSPP0, 43, 3}, + { DBGBUS_SSPP1, 3, 3}, + { DBGBUS_SSPP1, 23, 3}, + { DBGBUS_SSPP1, 33, 3}, + { DBGBUS_SSPP1, 43, 3}, + + /* spa */ + { DBGBUS_SSPP0, 8, 0}, + { DBGBUS_SSPP0, 28, 0}, + { DBGBUS_SSPP1, 8, 0}, + { DBGBUS_SSPP1, 28, 0}, + { DBGBUS_DSPP, 13, 0}, + { DBGBUS_DSPP, 19, 0}, + + /* igc */ + { DBGBUS_SSPP0, 17, 0}, + { DBGBUS_SSPP0, 17, 1}, + { DBGBUS_SSPP0, 17, 3}, + { DBGBUS_SSPP0, 37, 0}, + { DBGBUS_SSPP0, 37, 1}, + { DBGBUS_SSPP0, 37, 3}, + { DBGBUS_SSPP0, 46, 0}, + { DBGBUS_SSPP0, 46, 1}, + { DBGBUS_SSPP0, 46, 3}, + + { DBGBUS_SSPP1, 17, 0}, + { DBGBUS_SSPP1, 17, 1}, + { DBGBUS_SSPP1, 17, 3}, + { DBGBUS_SSPP1, 37, 0}, + { DBGBUS_SSPP1, 37, 1}, + { DBGBUS_SSPP1, 37, 3}, + { DBGBUS_SSPP1, 46, 0}, + { DBGBUS_SSPP1, 46, 1}, + { DBGBUS_SSPP1, 46, 3}, + + { DBGBUS_DSPP, 14, 0}, + { DBGBUS_DSPP, 14, 1}, + { DBGBUS_DSPP, 14, 3}, + { DBGBUS_DSPP, 20, 0}, + { DBGBUS_DSPP, 20, 1}, + { DBGBUS_DSPP, 20, 3}, + + /* intf0-3 */ + { DBGBUS_PERIPH, 0, 0}, + { DBGBUS_PERIPH, 1, 0}, + { DBGBUS_PERIPH, 2, 0}, + { DBGBUS_PERIPH, 3, 0}, + + /* te counter wrapper */ + { DBGBUS_PERIPH, 60, 0}, + + /* 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, 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}, + + /* dsc3 */ + { 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}, + + /* tear-check */ + { DBGBUS_PERIPH, 63, 0 }, + { DBGBUS_PERIPH, 64, 0 }, + { DBGBUS_PERIPH, 65, 0 }, + { DBGBUS_PERIPH, 73, 0 }, + { DBGBUS_PERIPH, 74, 0 }, + + /* 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}, + + /* hdmi */ + { DBGBUS_PERIPH, 68, 0}, + { DBGBUS_PERIPH, 68, 1}, + { DBGBUS_PERIPH, 68, 2}, + { DBGBUS_PERIPH, 68, 3}, + { DBGBUS_PERIPH, 68, 4}, + { DBGBUS_PERIPH, 68, 5}, + + /* edp */ + { 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}, + + /* axi - should be last entry */ + { DBGBUS_AXI_INTF, 62, 0, _sde_debug_bus_axi_dump_sdm845}, +}; + static struct sde_debug_bus_entry dbg_bus_sde_sm8150[] = { /* Unpack 0 sspp 0*/ @@ -4693,7 +5702,22 @@ void sde_dbg_init_dbg_buses(u32 hwversion) 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) || + if (IS_SDM845_TARGET(hwversion)) { + dbg->dbgbus_sde.entries = dbg_bus_sde_sdm845; + dbg->dbgbus_sde.cmn.entries_size = + ARRAY_SIZE(dbg_bus_sde_sdm845); + 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 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; From 306ce001b081a1cfafa29963553b74b62b2d6bc4 Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Sun, 5 Sep 2021 16:40:05 +0300 Subject: [PATCH 114/356] msm: sde: Do not fail if SID register is not found SID register may not be declared on the legacy SoCs (SDM660, SDM845, etc.), which will lead to the SDE driver fail, prevent this by adding the appropriate checks. Signed-off-by: Pavel Dubrova --- techpack/display/msm/sde/sde_hw_top.c | 5 +++++ techpack/display/msm/sde/sde_kms.c | 18 +++++++++--------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/techpack/display/msm/sde/sde_hw_top.c b/techpack/display/msm/sde/sde_hw_top.c index b02cd17cbb28..d275224e61a2 100644 --- a/techpack/display/msm/sde/sde_hw_top.c +++ b/techpack/display/msm/sde/sde_hw_top.c @@ -457,6 +457,11 @@ struct sde_hw_sid *sde_hw_sid_init(void __iomem *addr, { struct sde_hw_sid *c; + if (!addr) { + SDE_DEBUG("Invalid addr\n"); + return NULL; + } + c = kzalloc(sizeof(*c), GFP_KERNEL); if (!c) return ERR_PTR(-ENOMEM); diff --git a/techpack/display/msm/sde/sde_kms.c b/techpack/display/msm/sde/sde_kms.c index ba5b2bc38fdb..fda79db32a3a 100644 --- a/techpack/display/msm/sde/sde_kms.c +++ b/techpack/display/msm/sde/sde_kms.c @@ -3225,7 +3225,8 @@ static void sde_kms_init_shared_hw(struct sde_kms *sde_kms) sde_kms->hw_mdp->ops.reset_ubwc(sde_kms->hw_mdp, sde_kms->catalog); - sde_hw_sid_rotator_set(sde_kms->hw_sid); + if (sde_kms->hw_sid) + sde_hw_sid_rotator_set(sde_kms->hw_sid); } static void _sde_kms_set_lutdma_vbif_remap(struct sde_kms *sde_kms) @@ -3541,17 +3542,16 @@ static int _sde_kms_hw_init_ioremap(struct sde_kms *sde_kms, 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_DEBUG("SID_PHYS is not defined\n"); + } else { + 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); } - 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; } From 571bab1d11a76d8d3b8a3f116c2b8959504a99f6 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Wed, 8 Dec 2021 14:26:10 +0200 Subject: [PATCH 115/356] msm: sde_hw_catalog: Exclude interface tear 1/2 irqs on SDM845's MDP manages the tear interrupts inside the MDP interrupt itself, so there's no external tear interrupt. --- techpack/display/msm/sde/sde_hw_catalog.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/techpack/display/msm/sde/sde_hw_catalog.c b/techpack/display/msm/sde/sde_hw_catalog.c index 6a20a15c55d0..b9678f7f35ab 100644 --- a/techpack/display/msm/sde/sde_hw_catalog.c +++ b/techpack/display/msm/sde/sde_hw_catalog.c @@ -4246,6 +4246,8 @@ static int _sde_hardware_pre_caps(struct sde_mdss_cfg *sde_cfg, uint32_t hw_rev) sde_cfg->ts_prefill_rev = 2; sde_cfg->sui_misr_supported = true; sde_cfg->sui_block_xin_mask = 0x3F71; + clear_bit(MDSS_INTF_TEAR_1_INTR, sde_cfg->mdss_irqs); + clear_bit(MDSS_INTF_TEAR_2_INTR, sde_cfg->mdss_irqs); 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; From c682b55c3574486304dd62fa99d4509da81788a7 Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Wed, 8 Dec 2021 17:05:01 +0200 Subject: [PATCH 116/356] msm: sde: Fix intf_sel for SDM845/SDM660 targets In 4.14 kernel the definition of the active interface for cont splash was changed[1], which is invalid for older SoCs (SDM845/660), for them a different bit[2] must be used to check the active interface. Hence add a proper check for these legacy SoCs to the get_ctl_intf function and protect it by checking the SDE HW revision. [1] https://source.codeaurora.org/quic/la/kernel/msm-4.14/commit/?h=LA.UM.9.1.r1-11400-SMxxx0.0&id=75cc47bfa5f8ffb8ee43d6597ac2e8c74093cd91 [2] https://source.codeaurora.org/quic/la/kernel/msm-4.9/tree/drivers/gpu/drm/msm/sde/sde_rm.c?h=LA.UM.10.3.r1-00500-sdm845.0#n1433 Signed-off-by: Pavel Dubrova --- techpack/display/msm/sde/sde_hw_ctl.c | 13 +++++++++---- techpack/display/msm/sde/sde_hw_ctl.h | 3 ++- techpack/display/msm/sde/sde_rm.c | 2 +- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/techpack/display/msm/sde/sde_hw_ctl.c b/techpack/display/msm/sde/sde_hw_ctl.c index a06b52b24f17..d0c2f523c22e 100644 --- a/techpack/display/msm/sde/sde_hw_ctl.c +++ b/techpack/display/msm/sde/sde_hw_ctl.c @@ -619,7 +619,7 @@ static inline int sde_hw_ctl_trigger_flush_v1(struct sde_hw_ctl *ctx) return 0; } -static inline u32 sde_hw_ctl_get_intf_v1(struct sde_hw_ctl *ctx) +static inline u32 sde_hw_ctl_get_intf_v1(struct sde_hw_ctl *ctx, u32 hwversion) { struct sde_hw_blk_reg_map *c; u32 intf_active; @@ -635,7 +635,7 @@ static inline u32 sde_hw_ctl_get_intf_v1(struct sde_hw_ctl *ctx) return intf_active; } -static inline u32 sde_hw_ctl_get_intf(struct sde_hw_ctl *ctx) +static inline u32 sde_hw_ctl_get_intf(struct sde_hw_ctl *ctx, u32 hwversion) { struct sde_hw_blk_reg_map *c; u32 ctl_top; @@ -648,10 +648,15 @@ static inline u32 sde_hw_ctl_get_intf(struct sde_hw_ctl *ctx) c = &ctx->hw; ctl_top = SDE_REG_READ(c, CTL_TOP); + if (!ctl_top) + goto end; - intf_active = (ctl_top > 0) ? - BIT(ctl_top - 1) : 0; + if (IS_SDM845_TARGET(hwversion)) + intf_active = (ctl_top >> 4) & 0xf; + else + intf_active = BIT(ctl_top - 1); +end: return intf_active; } diff --git a/techpack/display/msm/sde/sde_hw_ctl.h b/techpack/display/msm/sde/sde_hw_ctl.h index 0c90f1156232..f95aa451cd98 100644 --- a/techpack/display/msm/sde/sde_hw_ctl.h +++ b/techpack/display/msm/sde/sde_hw_ctl.h @@ -422,9 +422,10 @@ struct sde_hw_ctl_ops { /** * get interfaces for the active CTL . * @ctx : ctl path ctx pointer + * @hwversion : mdss hw version number * @return : bit mask with the active interfaces for the CTL */ - u32 (*get_ctl_intf)(struct sde_hw_ctl *ctx); + u32 (*get_ctl_intf)(struct sde_hw_ctl *ctx, u32 hwversion); /** * read CTL layers register value and return diff --git a/techpack/display/msm/sde/sde_rm.c b/techpack/display/msm/sde/sde_rm.c index e77f9905ce3c..9e8a02f9eee9 100644 --- a/techpack/display/msm/sde/sde_rm.c +++ b/techpack/display/msm/sde/sde_rm.c @@ -1778,7 +1778,7 @@ int sde_rm_cont_splash_res_init(struct msm_drm_private *priv, return -EINVAL; } - intf_sel = ctl->ops.get_ctl_intf(ctl); + intf_sel = ctl->ops.get_ctl_intf(ctl, cat->hwversion); if (intf_sel) { splash_display = &splash_data->splash_display[index]; SDE_DEBUG("finding resources for display=%d ctl=%d\n", From 57cad3d307db7b6c62bef1844a961950b487ac3d Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Sun, 6 Aug 2023 16:07:11 +0000 Subject: [PATCH 117/356] techpack: display: sde: Fix build with debugfs disabled --- techpack/display/msm/sde_dbg.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/techpack/display/msm/sde_dbg.c b/techpack/display/msm/sde_dbg.c index 8f57219941f7..016e038ed1cc 100644 --- a/techpack/display/msm/sde_dbg.c +++ b/techpack/display/msm/sde_dbg.c @@ -301,6 +301,7 @@ static void _sde_debug_bus_ppb1_dump(void __iomem *mem_base, entry->wr_addr, entry->block_id, entry->test_id, val); } +#if defined(CONFIG_DEBUG_FS) static void _sde_debug_bus_axi_dump_sdm845(void __iomem *mem_base, struct sde_debug_bus_entry *entry, u32 val) { @@ -323,6 +324,7 @@ static void _sde_debug_bus_axi_dump_sdm845(void __iomem *mem_base, entry->test_id, status); } } +#endif static struct sde_debug_bus_entry dbg_bus_sde_sdm845[] = { @@ -1306,8 +1308,10 @@ static struct sde_debug_bus_entry dbg_bus_sde_sdm845[] = { { DBGBUS_PERIPH, 71, 4}, { DBGBUS_PERIPH, 71, 5}, +#if defined(CONFIG_DEBUG_FS) /* axi - should be last entry */ { DBGBUS_AXI_INTF, 62, 0, _sde_debug_bus_axi_dump_sdm845}, +#endif }; static struct sde_debug_bus_entry dbg_bus_sde_sm8150[] = { From 8abd624bc788ece569e31a7b511bdd889081beb8 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Sat, 19 Oct 2019 18:41:59 +0200 Subject: [PATCH 118/356] asoc: wcd-mbhc-v2: Handle analog audio over TypeC without FSA4480 Legacy ways use no FSA4480 MUX chip: there you just pull GPIOs and call it a day. Handle this usecase. [Pavel Dubrova] Update snd_soc_codec to snd_soc_component API. Signed-off-by: Pavel Dubrova --- techpack/audio/asoc/codecs/wcd-mbhc-v2.c | 282 +++++++++++++++++++++- techpack/audio/include/asoc/wcd-mbhc-v2.h | 17 ++ 2 files changed, 288 insertions(+), 11 deletions(-) diff --git a/techpack/audio/asoc/codecs/wcd-mbhc-v2.c b/techpack/audio/asoc/codecs/wcd-mbhc-v2.c index 1fd3f96a20a9..b74ca861c904 100644 --- a/techpack/audio/asoc/codecs/wcd-mbhc-v2.c +++ b/techpack/audio/asoc/codecs/wcd-mbhc-v2.c @@ -1022,10 +1022,14 @@ static void wcd_mbhc_swch_irq_handler(struct wcd_mbhc *mbhc) wcd_mbhc_report_plug(mbhc, 0, jack_type); if (mbhc->mbhc_cfg->enable_usbc_analog) { - WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_L_DET_EN, 0); - if (mbhc->mbhc_cb->clk_setup) - mbhc->mbhc_cb->clk_setup( - mbhc->component, false); + if (mbhc->mbhc_cfg->usbc_analog_legacy) { + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_L_DET_EN, 1); + } else { + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_L_DET_EN, 0); + if (mbhc->mbhc_cb->clk_setup) + mbhc->mbhc_cb->clk_setup( + mbhc->component, false); + } } if (mbhc->mbhc_cfg->moisture_en || @@ -1382,6 +1386,11 @@ static int wcd_mbhc_initialise(struct wcd_mbhc *mbhc) * by an external source */ if (mbhc->mbhc_cfg->enable_usbc_analog) { + if (mbhc->mbhc_cfg->usbc_analog_legacy) { + mbhc->hphl_swh = 1; + mbhc->gnd_swh = 1; + } + if (mbhc->mbhc_cb->hph_pull_up_control_v2) mbhc->mbhc_cb->hph_pull_up_control_v2(component, HS_PULLUP_I_OFF); @@ -1404,7 +1413,7 @@ static int wcd_mbhc_initialise(struct wcd_mbhc *mbhc) * when a non-audio accessory is inserted. L_DET_EN sets to 1 when FSA * I2C driver notifies that ANALOG_AUDIO_ADAPTER is inserted */ - if (mbhc->mbhc_cfg->enable_usbc_analog) + if (mbhc->mbhc_cfg->enable_usbc_analog && !mbhc->mbhc_cfg->usbc_analog_legacy) WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_L_DET_EN, 0); else WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_L_DET_EN, 1); @@ -1424,7 +1433,8 @@ static int wcd_mbhc_initialise(struct wcd_mbhc *mbhc) mbhc->mbhc_cb->mbhc_bias(component, true); /* enable MBHC clock */ if (mbhc->mbhc_cb->clk_setup) { - if (mbhc->mbhc_cfg->enable_usbc_analog) + if (mbhc->mbhc_cfg->enable_usbc_analog && + !mbhc->mbhc_cfg->usbc_analog_legacy) mbhc->mbhc_cb->clk_setup(component, false); else mbhc->mbhc_cb->clk_setup(component, true); @@ -1598,6 +1608,204 @@ static int wcd_mbhc_usbc_ana_event_handler(struct notifier_block *nb, return 0; } +static int wcd_mbhc_usb_c_analog_setup_gpios(struct wcd_mbhc *mbhc, + bool active) +{ + int rc = 0; + struct snd_soc_component *component = mbhc->component; + struct usbc_ana_audio_config *config = + &mbhc->mbhc_cfg->usbc_analog_cfg; + union power_supply_propval pval; + + dev_dbg(component->dev, "%s: setting GPIOs active = %d\n", + __func__, active); + + memset(&pval, 0, sizeof(pval)); + + if (active) { + pval.intval = POWER_SUPPLY_TYPEC_PR_SOURCE; + if (power_supply_set_property(mbhc->usb_psy, + POWER_SUPPLY_PROP_TYPEC_POWER_ROLE, &pval)) + dev_info(component->dev, "%s: force PR_SOURCE mode unsuccessful\n", + __func__); + else + mbhc->usbc_force_pr_mode = true; + + if (config->usbc_en1_gpio_p) + rc = msm_cdc_pinctrl_select_active_state( + config->usbc_en1_gpio_p); + if (rc == 0 && config->usbc_force_gpio_p) + rc = msm_cdc_pinctrl_select_active_state( + config->usbc_force_gpio_p); + mbhc->usbc_mode = POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER; + } else { + /* no delay is required when disabling GPIOs */ + if (config->usbc_en1_gpio_p) + msm_cdc_pinctrl_select_sleep_state( + config->usbc_en1_gpio_p); + if (config->usbc_force_gpio_p) + msm_cdc_pinctrl_select_sleep_state( + config->usbc_force_gpio_p); + + if (mbhc->usbc_force_pr_mode) { + pval.intval = POWER_SUPPLY_TYPEC_PR_DUAL; + if (power_supply_set_property(mbhc->usb_psy, + POWER_SUPPLY_PROP_TYPEC_POWER_ROLE, &pval)) + dev_info(component->dev, "%s: force PR_DUAL mode unsuccessful\n", + __func__); + + mbhc->usbc_force_pr_mode = false; + } + + mbhc->usbc_mode = POWER_SUPPLY_TYPEC_NONE; + if (mbhc->mbhc_cfg->swap_gnd_mic) + mbhc->mbhc_cfg->swap_gnd_mic(component, false); + } + + return rc; +} + +/* workqueue */ +static void wcd_mbhc_usbc_analog_work_fn(struct work_struct *work) +{ + struct wcd_mbhc *mbhc = + container_of(work, struct wcd_mbhc, usbc_analog_work); + + wcd_mbhc_usb_c_analog_setup_gpios(mbhc, + mbhc->usbc_mode != POWER_SUPPLY_TYPEC_NONE); +} + +/* this callback function is used to process PMI notification */ +static int wcd_mbhc_usb_c_event_changed(struct notifier_block *nb, + unsigned long evt, void *ptr) +{ + int ret; + union power_supply_propval mode; + struct wcd_mbhc *mbhc = container_of(nb, struct wcd_mbhc, psy_nb); + struct snd_soc_component *component = mbhc->component; + + if (ptr != mbhc->usb_psy || evt != PSY_EVENT_PROP_CHANGED) + return 0; + + ret = power_supply_get_property(mbhc->usb_psy, + POWER_SUPPLY_PROP_TYPEC_MODE, &mode); + if (ret) { + dev_err(component->dev, "%s: Unable to read USB TYPEC_MODE: %d\n", + __func__, ret); + return ret; + } + + dev_dbg(component->dev, "%s: USB change event received\n", + __func__); + dev_dbg(component->dev, "%s: supply mode %d, expected %d\n", __func__, + mode.intval, POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER); + + switch (mode.intval) { + case POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER: + case POWER_SUPPLY_TYPEC_NONE: + dev_dbg(component->dev, "%s: usbc_mode: %d; mode.intval: %d\n", + __func__, mbhc->usbc_mode, mode.intval); + + if (mbhc->usbc_mode == mode.intval) + break; /* filter notifications received before */ + mbhc->usbc_mode = mode.intval; + + dev_dbg(component->dev, "%s: queueing usbc_analog_work\n", + __func__); + schedule_work(&mbhc->usbc_analog_work); + break; + default: + break; + } + return ret; +} + +/* PMI registration code */ +static int wcd_mbhc_usb_c_analog_init(struct wcd_mbhc *mbhc) +{ + int ret = 0; + struct snd_soc_component *component = mbhc->component; + + dev_dbg(component->dev, "%s: usb-c analog setup start\n", __func__); + INIT_WORK(&mbhc->usbc_analog_work, wcd_mbhc_usbc_analog_work_fn); + + mbhc->usb_psy = power_supply_get_by_name("usb"); + if (IS_ERR_OR_NULL(mbhc->usb_psy)) { + dev_err(component->dev, "%s: could not get USB psy info\n", + __func__); + ret = -EPROBE_DEFER; + if (IS_ERR(mbhc->usb_psy)) + ret = PTR_ERR(mbhc->usb_psy); + mbhc->usb_psy = NULL; + goto err; + } + + ret = wcd_mbhc_usb_c_analog_setup_gpios(mbhc, false); + if (ret) { + dev_err(component->dev, "%s: error while setting USBC ana gpios\n", + __func__); + goto err; + } + + mbhc->psy_nb.notifier_call = wcd_mbhc_usb_c_event_changed; + mbhc->psy_nb.priority = 0; + ret = power_supply_reg_notifier(&mbhc->psy_nb); + if (ret) { + dev_err(component->dev, "%s: power supply registration failed\n", + __func__); + goto err; + } + + /* + * as part of the init sequence check if there is a connected + * USB C analog adapter + */ + dev_dbg(component->dev, "%s: verify if USB adapter is already inserted\n", + __func__); + ret = wcd_mbhc_usb_c_event_changed(&mbhc->psy_nb, + PSY_EVENT_PROP_CHANGED, + mbhc->usb_psy); + +err: + return ret; +} + +static int wcd_mbhc_usb_c_analog_deinit(struct wcd_mbhc *mbhc) +{ + wcd_mbhc_usb_c_analog_setup_gpios(mbhc, false); + + /* deregister from PMI */ + power_supply_unreg_notifier(&mbhc->psy_nb); + + return 0; +} + +static int wcd_mbhc_init_gpio(struct wcd_mbhc *mbhc, + struct wcd_mbhc_config *mbhc_cfg, + const char *gpio_dt_str, + int *gpio, struct device_node **gpio_dn) +{ + int rc = 0; + struct snd_soc_component *component = mbhc->component; + struct snd_soc_card *card = component->card; + + dev_dbg(component->dev, "%s: gpio %s\n", __func__, gpio_dt_str); + + *gpio_dn = of_parse_phandle(card->dev->of_node, gpio_dt_str, 0); + + if (!(*gpio_dn)) { + *gpio = of_get_named_gpio(card->dev->of_node, gpio_dt_str, 0); + if (!gpio_is_valid(*gpio)) { + dev_err(card->dev, "%s, property %s not in node %s", + __func__, gpio_dt_str, + card->dev->of_node->full_name); + rc = -EINVAL; + } + } + + return rc; +} + int wcd_mbhc_start(struct wcd_mbhc *mbhc, struct wcd_mbhc_config *mbhc_cfg) { int rc = 0; @@ -1638,9 +1846,43 @@ int wcd_mbhc_start(struct wcd_mbhc *mbhc, struct wcd_mbhc_config *mbhc_cfg) mbhc->fsa_np = of_parse_phandle(card->dev->of_node, "fsa4480-i2c-handle", 0); if (!mbhc->fsa_np) { - dev_err(card->dev, "%s: fsa4480 i2c node not found\n", + dev_err(card->dev, "%s: fsa4480 i2c node not found, " + "trying legacy Type-C analog audio\n", __func__); - rc = -EINVAL; + + mbhc_cfg->usbc_analog_legacy = true; + /* goto err; */ + } + } + + if (mbhc_cfg->enable_usbc_analog && mbhc_cfg->usbc_analog_legacy) { + struct usbc_ana_audio_config *config = + &mbhc_cfg->usbc_analog_cfg; + + rc = wcd_mbhc_init_gpio(mbhc, mbhc_cfg, + "qcom,usbc-analog-en1-gpio", + &config->usbc_en1_gpio, + &config->usbc_en1_gpio_p); + if (rc) + goto err; + + if (of_find_property(card->dev->of_node, + "qcom,usbc-analog-force_detect_gpio", + NULL)) { + rc = wcd_mbhc_init_gpio(mbhc, mbhc_cfg, + "qcom,usbc-analog-force_detect_gpio", + &config->usbc_force_gpio, + &config->usbc_force_gpio_p); + if (rc) + goto err; + } + + dev_dbg(component->dev, "%s: calling usb_c_analog_init\n", + __func__); + /* init PMI notifier */ + rc = wcd_mbhc_usb_c_analog_init(mbhc); + if (rc) { + rc = -EPROBE_DEFER; goto err; } } @@ -1667,7 +1909,7 @@ int wcd_mbhc_start(struct wcd_mbhc *mbhc, struct wcd_mbhc_config *mbhc_cfg) __func__, mbhc->mbhc_fw, mbhc->mbhc_cal); } - if (mbhc_cfg->enable_usbc_analog) { + if (mbhc_cfg->enable_usbc_analog && !mbhc_cfg->usbc_analog_legacy) { mbhc->fsa_nb.notifier_call = wcd_mbhc_usbc_ana_event_handler; mbhc->fsa_nb.priority = 0; rc = fsa4480_reg_notifier(&mbhc->fsa_nb, mbhc->fsa_np); @@ -1706,8 +1948,26 @@ void wcd_mbhc_stop(struct wcd_mbhc *mbhc) mbhc->mbhc_cal = NULL; } - if (mbhc->mbhc_cfg->enable_usbc_analog) - fsa4480_unreg_notifier(&mbhc->fsa_nb, mbhc->fsa_np); + if (mbhc->mbhc_cfg->enable_usbc_analog) { + if (mbhc->mbhc_cfg->usbc_analog_legacy) { + struct usbc_ana_audio_config *config = + &mbhc->mbhc_cfg->usbc_analog_cfg; + + wcd_mbhc_usb_c_analog_deinit(mbhc); + /* free GPIOs */ + if (config->usbc_en1_gpio > 0) + gpio_free(config->usbc_en1_gpio); + if (config->usbc_force_gpio) + gpio_free(config->usbc_force_gpio); + + if (config->usbc_en1_gpio_p) + of_node_put(config->usbc_en1_gpio_p); + if (config->usbc_force_gpio_p) + of_node_put(config->usbc_force_gpio_p); + } else { + fsa4480_unreg_notifier(&mbhc->fsa_nb, mbhc->fsa_np); + } + } pr_debug("%s: leave\n", __func__); } diff --git a/techpack/audio/include/asoc/wcd-mbhc-v2.h b/techpack/audio/include/asoc/wcd-mbhc-v2.h index 340d68cee76e..da972eb7ffed 100644 --- a/techpack/audio/include/asoc/wcd-mbhc-v2.h +++ b/techpack/audio/include/asoc/wcd-mbhc-v2.h @@ -416,6 +416,15 @@ enum mbhc_moisture_rref { R_184_KOHM, }; +struct usbc_ana_audio_config { + int usbc_en1_gpio; + int usbc_en2_gpio; + int usbc_force_gpio; + struct device_node *usbc_en1_gpio_p; /* used by pinctrl API */ + struct device_node *usbc_en2_gpio_p; /* used by pinctrl API */ + struct device_node *usbc_force_gpio_p; /* used by pinctrl API */ +}; + struct wcd_mbhc_config { bool read_fw_bin; void *calibration; @@ -431,7 +440,9 @@ struct wcd_mbhc_config { int anc_micbias; bool enable_anc_mic_detect; u32 enable_usbc_analog; + bool usbc_analog_legacy; bool moisture_duty_cycle_en; + struct usbc_ana_audio_config usbc_analog_cfg; }; struct wcd_mbhc_intr { @@ -612,6 +623,12 @@ struct wcd_mbhc { unsigned long intr_status; bool is_hph_ocp_pending; + bool usbc_force_pr_mode; + int usbc_mode; + struct notifier_block psy_nb; + struct power_supply *usb_psy; + struct work_struct usbc_analog_work; + struct wcd_mbhc_fn *mbhc_fn; bool force_linein; struct device_node *fsa_np; From 7adf48316d522e11b3d04d92866ab078e6f089de Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Tue, 3 Dec 2019 13:11:11 +0100 Subject: [PATCH 119/356] dsp: q6voice: Force channel info command for some v2 firmwares Some SoCs were released with a DSP firmware using CVP v2.0 and CVD v2.3, but the same versions got a modification on later firmwares found on, for example, SM8150. Unfortunately, the new firmware doesn't declare a different version for CVP nor CVD, but the old one does not support the device_channels command, with the channel_info command being the only option to set the CVP channels right: this is found to happen on SDM845's DSP firmware. For this reason, check if the current machine is SDM845 and force sending the CVP channel info command on there: this way, the DSP doesn't return any error and we're able to use advanced features, like AEC and (A)ANC. --- techpack/audio/dsp/q6voice.c | 7 ++++++- techpack/audio/include/dsp/q6voice.h | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/techpack/audio/dsp/q6voice.c b/techpack/audio/dsp/q6voice.c index 9022251481a9..71fa562afdde 100644 --- a/techpack/audio/dsp/q6voice.c +++ b/techpack/audio/dsp/q6voice.c @@ -4680,7 +4680,8 @@ static int voice_send_cvp_media_fmt_info_cmd(struct voice_data *v) { int ret = 0; - if (common.cvp_version < CVP_VERSION_2) + if (common.cvp_version < CVP_VERSION_2 || + common.is_legacy_dsp_v2_firmware) ret = voice_send_cvp_device_channels_cmd(v); else ret = voice_send_cvp_channel_info_cmd(v); @@ -10131,6 +10132,10 @@ int __init voice_init(void) */ common.rec_channel_count = NUM_CHANNELS_MONO; + /* Support legacy DSP firmware with CVPv2.0+CVD2.3 */ + common.is_legacy_dsp_v2_firmware = + of_machine_is_compatible("qcom,sdm845"); + mutex_init(&common.common_lock); common.uevent_data = kzalloc(sizeof(*(common.uevent_data)), GFP_KERNEL); diff --git a/techpack/audio/include/dsp/q6voice.h b/techpack/audio/include/dsp/q6voice.h index 35ace4eed388..ea72010233b8 100644 --- a/techpack/audio/include/dsp/q6voice.h +++ b/techpack/audio/include/dsp/q6voice.h @@ -1991,6 +1991,7 @@ struct common_data { bool is_destroy_cvd; char cvd_version[CVD_VERSION_STRING_MAX_SIZE]; int cvp_version; + bool is_legacy_dsp_v2_firmware; bool is_avcs_version_queried; bool is_per_vocoder_cal_enabled; bool is_sound_focus_resp_success; From 07a97abaa9dafff391edf96d204240329e8aa49e Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Thu, 23 Dec 2021 04:12:07 +0200 Subject: [PATCH 120/356] ASoC: Add machine driver for SDM845 audio support Add ALSA based machine driver for SDM845 target to provide initial audio support. Add audio config files and change Android.mk, Makefile and Kbuild to enable audio modules for SDM845 target. Signed-off-by: Pavel Dubrova --- techpack/audio/Android.mk | 2 +- techpack/audio/Makefile | 7 + techpack/audio/Makefile.am | 5 +- techpack/audio/asoc/Android.mk | 7 +- techpack/audio/asoc/Kbuild | 12 + techpack/audio/asoc/codecs/Android.mk | 6 +- techpack/audio/asoc/codecs/Kbuild | 5 + techpack/audio/asoc/codecs/wcd934x/Android.mk | 6 +- techpack/audio/asoc/codecs/wcd934x/Kbuild | 4 + techpack/audio/asoc/sdm845.c | 7388 +++++++++++++++++ techpack/audio/config/sdm845auto.conf | 37 + techpack/audio/config/sdm845autoconf.h | 41 + techpack/audio/dsp/Android.mk | 6 +- techpack/audio/dsp/Kbuild | 4 + techpack/audio/dsp/codecs/Android.mk | 6 +- techpack/audio/dsp/codecs/Kbuild | 4 + techpack/audio/ipc/Android.mk | 6 +- techpack/audio/ipc/Kbuild | 4 + techpack/audio/soc/Android.mk | 6 +- techpack/audio/soc/Kbuild | 4 + 20 files changed, 7551 insertions(+), 9 deletions(-) create mode 100644 techpack/audio/asoc/sdm845.c create mode 100644 techpack/audio/config/sdm845auto.conf create mode 100644 techpack/audio/config/sdm845autoconf.h diff --git a/techpack/audio/Android.mk b/techpack/audio/Android.mk index ab2e37355bea..9bd1aa27015f 100644 --- a/techpack/audio/Android.mk +++ b/techpack/audio/Android.mk @@ -3,7 +3,7 @@ MY_LOCAL_PATH := $(call my-dir) UAPI_OUT := $(PRODUCT_OUT)/obj/vendor/qcom/opensource/audio-kernel/include -ifeq ($(call is-board-platform-in-list,msmnile $(MSMSTEPPE) $(TRINKET) kona lito bengal sdmshrike sdm660 msm8953 msm8937),true) +ifeq ($(call is-board-platform-in-list,msmnile $(MSMSTEPPE) $(TRINKET) kona lito bengal sdmshrike sdm660 msm8953 msm8937 sdm845),true) $(shell mkdir -p $(UAPI_OUT)/linux;) $(shell mkdir -p $(UAPI_OUT)/sound;) $(shell rm -rf $(PRODUCT_OUT)/obj/vendor/qcom/opensource/audio-kernel/ipc/Module.symvers) diff --git a/techpack/audio/Makefile b/techpack/audio/Makefile index 357525074003..245c746b8e03 100644 --- a/techpack/audio/Makefile +++ b/techpack/audio/Makefile @@ -27,6 +27,9 @@ ifeq ($(CONFIG_ARCH_SDM660), y) include $(srctree)/techpack/audio/config/sdm660auto.conf export $(shell sed 's/=.*//' $(srctree)/techpack/audio/config/sdm660auto.conf) endif +ifeq ($(CONFIG_ARCH_SDM845), y) +include $(srctree)/techpack/audio/config/sdm845auto.conf +endif # Use USERINCLUDE when you must reference the UAPI directories only. USERINCLUDE += \ @@ -67,6 +70,10 @@ ifeq ($(CONFIG_ARCH_SDM660), y) LINUXINCLUDE += \ -include $(srctree)/techpack/audio/config/sdm660autoconf.h endif +ifeq ($(CONFIG_ARCH_SDM845), y) +LINUXINCLUDE += \ + -include $(srctree)/techpack/audio/config/sdm845autoconf.h +endif obj-y += soc/ obj-y += dsp/ obj-y += ipc/ diff --git a/techpack/audio/Makefile.am b/techpack/audio/Makefile.am index b10cd8720b23..32dec894e26c 100644 --- a/techpack/audio/Makefile.am +++ b/techpack/audio/Makefile.am @@ -23,6 +23,9 @@ endif ifeq ($(TARGET_SUPPORT),apq8053 msm8953 msm8937) KBUILD_OPTIONS += CONFIG_ARCH_SDM450=y endif +ifeq ($(TARGET_SUPPORT),sdm845) +KBUILD_OPTIONS += CONFIG_ARCH_SDM845=y +endif obj-m := ipc/ obj-m += dsp/ @@ -30,7 +33,7 @@ obj-m += dsp/codecs/ obj-m += soc/ obj-m += asoc/ obj-m += asoc/codecs/ -ifeq ($(TARGET_SUPPORT), $(filter $(TARGET_SUPPORT), sdmsteppe, sdm660)) +ifeq ($(TARGET_SUPPORT), $(filter $(TARGET_SUPPORT), sdmsteppe, sdm660 sdm845)) obj-m += asoc/codecs/wcd934x/ endif ifeq ($(TARGET_SUPPORT), $(filter $(TARGET_SUPPORT), qcs40x)) diff --git a/techpack/audio/asoc/Android.mk b/techpack/audio/asoc/Android.mk index b2cac8fe7e05..de4f8db2f38e 100644 --- a/techpack/audio/asoc/Android.mk +++ b/techpack/audio/asoc/Android.mk @@ -52,9 +52,14 @@ AUDIO_SELECT += CONFIG_SND_SOC_SDM450=m AUDIO_SELECT += CONFIG_SND_SOC_EXT_CODEC_SDM450=m endif +ifeq ($(call is-board-platform,sdm845),true) +TARGET := sdm845 +AUDIO_SELECT := CONFIG_SND_SOC_SDM845=m +endif + AUDIO_CHIPSET := audio # Build/Package only in case of supported target -ifeq ($(call is-board-platform-in-list,msmnile $(MSMSTEPPE) $(TRINKET) kona lito bengal sdmshrike sdm660 msm8953 msm8937),true) +ifeq ($(call is-board-platform-in-list,msmnile $(MSMSTEPPE) $(TRINKET) kona lito bengal sdmshrike sdm660 msm8953 msm8937 sdm845),true) LOCAL_PATH := $(call my-dir) diff --git a/techpack/audio/asoc/Kbuild b/techpack/audio/asoc/Kbuild index dddfd1440a83..97344fc9e2ba 100644 --- a/techpack/audio/asoc/Kbuild +++ b/techpack/audio/asoc/Kbuild @@ -14,6 +14,10 @@ ifeq ($(KERNEL_BUILD), 1) endif ifeq ($(KERNEL_BUILD), 0) + ifeq ($(CONFIG_ARCH_SDM845), y) + include $(AUDIO_ROOT)/config/sdm845auto.conf + INCS += -include $(AUDIO_ROOT)/config/sdm845autoconf.h + endif ifeq ($(CONFIG_ARCH_SM8150), y) ifdef CONFIG_SND_SOC_SA8155 include $(AUDIO_ROOT)/config/sa8155auto.conf @@ -124,6 +128,11 @@ COMMON_INC := -I$(AUDIO_ROOT)/$(COMMON_DIR) ############ ASoC Drivers ############ +# for SDM845 sound card driver +ifdef CONFIG_SND_SOC_SDM845 + MACHINE_OBJS += sdm845.o +endif + # for SM8150 sound card driver ifdef CONFIG_SND_SOC_SM8150 MACHINE_OBJS += sm8150.o @@ -286,6 +295,9 @@ machine_dlkm-y := $(MACHINE_OBJS) obj-$(CONFIG_SND_SOC_EXT_CODEC_SDM450) += machine_ext_dlkm.o machine_ext_dlkm-y := $(MACHINE_EXT_OBJS) +obj-$(CONFIG_SND_SOC_SDM845) += machine_dlkm.o +machine_dlkm-y := $(MACHINE_OBJS) + obj-$(CONFIG_SND_SOC_SM8150) += machine_dlkm.o machine_dlkm-y := $(MACHINE_OBJS) diff --git a/techpack/audio/asoc/codecs/Android.mk b/techpack/audio/asoc/codecs/Android.mk index 08c555b53a13..996fb69465f3 100644 --- a/techpack/audio/asoc/codecs/Android.mk +++ b/techpack/audio/asoc/codecs/Android.mk @@ -3,6 +3,10 @@ # Assume no targets will be supported # Check if this driver needs be built for current target +ifeq ($(call is-board-platform,sdm845),true) +AUDIO_SELECT := CONFIG_SND_SOC_SDM845=m +endif + ifeq ($(call is-board-platform-in-list,msmnile sdmshrike),true) ifeq ($(TARGET_BOARD_AUTO),true) AUDIO_SELECT := CONFIG_SND_SOC_SA8155=m @@ -46,7 +50,7 @@ endif AUDIO_CHIPSET := audio # Build/Package only in case of supported target -ifeq ($(call is-board-platform-in-list,msmnile $(MSMSTEPPE) $(TRINKET) kona lito bengal sdmshrike sdm660 msm8953 msm8937),true) +ifeq ($(call is-board-platform-in-list,msmnile $(MSMSTEPPE) $(TRINKET) kona lito bengal sdmshrike sdm660 msm8953 msm8937 sdm845),true) LOCAL_PATH := $(call my-dir) diff --git a/techpack/audio/asoc/codecs/Kbuild b/techpack/audio/asoc/codecs/Kbuild index 19e374e43045..63215b3c497d 100644 --- a/techpack/audio/asoc/codecs/Kbuild +++ b/techpack/audio/asoc/codecs/Kbuild @@ -14,6 +14,11 @@ ifeq ($(KERNEL_BUILD), 1) endif ifeq ($(KERNEL_BUILD), 0) + ifeq ($(CONFIG_ARCH_SDM845), y) + include $(AUDIO_ROOT)/config/sdm845auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sdm845autoconf.h + endif ifeq ($(CONFIG_ARCH_SM8150), y) ifdef CONFIG_SND_SOC_SA8155 include $(AUDIO_ROOT)/config/sa8155auto.conf diff --git a/techpack/audio/asoc/codecs/wcd934x/Android.mk b/techpack/audio/asoc/codecs/wcd934x/Android.mk index 18170f404cb8..787298c1a2a3 100644 --- a/techpack/audio/asoc/codecs/wcd934x/Android.mk +++ b/techpack/audio/asoc/codecs/wcd934x/Android.mk @@ -3,6 +3,10 @@ # Assume no targets will be supported # Check if this driver needs be built for current target +ifeq ($(call is-board-platform,sdm845),true) +AUDIO_SELECT := CONFIG_SND_SOC_SDM845=m +endif + ifeq ($(call is-board-platform,msmnile),true) AUDIO_SELECT := CONFIG_SND_SOC_SM8150=m endif @@ -17,7 +21,7 @@ endif AUDIO_CHIPSET := audio # Build/Package only in case of supported target -ifeq ($(call is-board-platform-in-list,msmnile $(MSMSTEPPE) $(TRINKET) sdm660),true) +ifeq ($(call is-board-platform-in-list,msmnile $(MSMSTEPPE) $(TRINKET) sdm660 sdm845),true) LOCAL_PATH := $(call my-dir) diff --git a/techpack/audio/asoc/codecs/wcd934x/Kbuild b/techpack/audio/asoc/codecs/wcd934x/Kbuild index 404cc8dca141..18b28c466896 100644 --- a/techpack/audio/asoc/codecs/wcd934x/Kbuild +++ b/techpack/audio/asoc/codecs/wcd934x/Kbuild @@ -16,6 +16,10 @@ ifeq ($(KERNEL_BUILD), 1) endif ifeq ($(KERNEL_BUILD), 0) + ifeq ($(CONFIG_ARCH_SDM845), y) + include $(AUDIO_ROOT)/config/sdm845auto.conf + INCS += -include $(AUDIO_ROOT)/config/sdm845autoconf.h + endif ifeq ($(CONFIG_ARCH_SM6150), y) include $(AUDIO_ROOT)/config/sm6150auto.conf export diff --git a/techpack/audio/asoc/sdm845.c b/techpack/audio/asoc/sdm845.c new file mode 100644 index 000000000000..883c06509ea5 --- /dev/null +++ b/techpack/audio/asoc/sdm845.c @@ -0,0 +1,7388 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2016-2019, 2021, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "msm-pcm-routing-v2.h" +#include +#include "codecs/wcd934x/wcd934x.h" +#include "codecs/wcd934x/wcd934x-mbhc.h" +#include "codecs/wsa881x.h" + +#define DRV_NAME "sdm845-asoc-snd" + +#define __CHIPSET__ "SDM845 " +#define MSM_DAILINK_NAME(name) (__CHIPSET__#name) + +#define SAMPLING_RATE_8KHZ 8000 +#define SAMPLING_RATE_11P025KHZ 11025 +#define SAMPLING_RATE_16KHZ 16000 +#define SAMPLING_RATE_22P05KHZ 22050 +#define SAMPLING_RATE_32KHZ 32000 +#define SAMPLING_RATE_44P1KHZ 44100 +#define SAMPLING_RATE_48KHZ 48000 +#define SAMPLING_RATE_88P2KHZ 88200 +#define SAMPLING_RATE_96KHZ 96000 +#define SAMPLING_RATE_176P4KHZ 176400 +#define SAMPLING_RATE_192KHZ 192000 +#define SAMPLING_RATE_352P8KHZ 352800 +#define SAMPLING_RATE_384KHZ 384000 + +#define WCD9XXX_MBHC_DEF_BUTTONS 8 +#define WCD9XXX_MBHC_DEF_RLOADS 5 +#define CODEC_EXT_CLK_RATE 9600000 +#define ADSP_STATE_READY_TIMEOUT_MS 3000 +#define DEV_NAME_STR_LEN 32 + +#define WSA8810_NAME_1 "wsa881x.20170211" +#define WSA8810_NAME_2 "wsa881x.20170212" + +#define WCN_CDC_SLIM_RX_CH_MAX 2 +#define WCN_CDC_SLIM_TX_CH_MAX 3 + +#define TDM_CHANNEL_MAX 8 + +#define MSM_HIFI_ON 1 +#define MSM_LL_QOS_VALUE 300 /* time in us to ensure LPM doesn't go in C3/C4 */ + +#define TDM_MAX_SLOTS 8 +#define TDM_SLOT_WIDTH_BITS 32 + +enum { + SLIM_RX_0 = 0, + SLIM_RX_1, + SLIM_RX_2, + SLIM_RX_3, + SLIM_RX_4, + SLIM_RX_5, + SLIM_RX_6, + SLIM_RX_7, + SLIM_RX_MAX, +}; + +enum { + SLIM_TX_0 = 0, + SLIM_TX_1, + SLIM_TX_2, + SLIM_TX_3, + SLIM_TX_4, + SLIM_TX_5, + SLIM_TX_6, + SLIM_TX_7, + SLIM_TX_8, + SLIM_TX_MAX, +}; + +enum { + PRIM_MI2S = 0, + SEC_MI2S, + TERT_MI2S, + QUAT_MI2S, + MI2S_MAX, +}; + +enum { + PRIM_AUX_PCM = 0, + SEC_AUX_PCM, + TERT_AUX_PCM, + QUAT_AUX_PCM, + AUX_PCM_MAX, +}; + +struct mi2s_conf { + struct mutex lock; + u32 ref_cnt; + u32 msm_is_mi2s_master; +}; + +static u32 mi2s_ebit_clk[MI2S_MAX] = { + Q6AFE_LPASS_CLK_ID_PRI_MI2S_EBIT, + Q6AFE_LPASS_CLK_ID_SEC_MI2S_EBIT, + Q6AFE_LPASS_CLK_ID_TER_MI2S_EBIT, + Q6AFE_LPASS_CLK_ID_QUAD_MI2S_EBIT +}; + +struct dev_config { + u32 sample_rate; + u32 bit_format; + u32 channels; +}; + +struct tdm_dev_config { + unsigned int tdm_slot_offset[TDM_MAX_SLOTS]; +}; + +enum { + DP_RX_IDX = 0, + EXT_DISP_RX_IDX_MAX, +}; + +struct msm_wsa881x_dev_info { + struct device_node *of_node; + u32 index; +}; + +enum pinctrl_pin_state { + STATE_DISABLE = 0, /* All pins are in sleep state */ + STATE_MI2S_ACTIVE, /* IS2 = active, TDM = sleep */ + STATE_TDM_ACTIVE, /* IS2 = sleep, TDM = active */ +}; + +struct msm_pinctrl_info { + struct pinctrl *pinctrl; + struct pinctrl_state *mi2s_disable; + struct pinctrl_state *tdm_disable; + struct pinctrl_state *mi2s_active; + struct pinctrl_state *tdm_active; + enum pinctrl_pin_state curr_state; +}; + +static atomic_t pinctrl_ref_count; + +struct msm_asoc_mach_data { + u32 mclk_freq; + int us_euro_gpio; /* used by gpio driver API */ + int usbc_en2_gpio; /* used by gpio driver API */ + struct device_node *us_euro_gpio_p; /* used by pinctrl API */ + struct pinctrl *usbc_en2_gpio_p; /* used by pinctrl API */ + struct device_node *hph_en1_gpio_p; /* used by pinctrl API */ + struct device_node *hph_en0_gpio_p; /* used by pinctrl API */ + struct snd_info_entry *codec_root; + struct msm_pinctrl_info pinctrl_info; + struct snd_soc_component *component; + struct work_struct adsp_power_up_work; +}; + +struct msm_asoc_wcd93xx_codec { + void* (*get_afe_config_fn)(struct snd_soc_component *component, + enum afe_config_type config_type); + void (*mbhc_hs_detect_exit)(struct snd_soc_component *component); +}; + +static const char *const pin_states[] = {"sleep", "i2s-active", + "tdm-active"}; + +enum { + TDM_0 = 0, + TDM_1, + TDM_2, + TDM_3, + TDM_4, + TDM_5, + TDM_6, + TDM_7, + TDM_PORT_MAX, +}; + +enum { + TDM_PRI = 0, + TDM_SEC, + TDM_TERT, + TDM_QUAT, + TDM_INTERFACE_MAX, +}; + +struct tdm_port { + u32 mode; + u32 channel; +}; + +/* TDM default config */ +static struct dev_config tdm_rx_cfg[TDM_INTERFACE_MAX][TDM_PORT_MAX] = { + { /* PRI TDM */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_0 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_1 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_2 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_3 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_4 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_5 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_6 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_7 */ + }, + { /* SEC TDM */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_0 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_1 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_2 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_3 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_4 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_5 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_6 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_7 */ + }, + { /* TERT TDM */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_0 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_1 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_2 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_3 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_4 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_5 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_6 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_7 */ + }, + { /* QUAT TDM */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_0 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_1 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_2 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_3 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_4 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_5 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_6 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* RX_7 */ + } +}; + +/* TDM default config */ +static struct dev_config tdm_tx_cfg[TDM_INTERFACE_MAX][TDM_PORT_MAX] = { + { /* PRI TDM */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_0 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_1 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_2 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_3 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_4 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_5 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_6 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_7 */ + }, + { /* SEC TDM */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_0 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_1 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_2 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_3 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_4 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_5 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_6 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_7 */ + }, + { /* TERT TDM */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_0 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_1 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_2 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_3 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_4 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_5 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_6 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_7 */ + }, + { /* QUAT TDM */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_0 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_1 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_2 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_3 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_4 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_5 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_6 */ + {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_7 */ + } +}; + +static struct tdm_dev_config tdm_cfg[TDM_INTERFACE_MAX * 2] + [TDM_PORT_MAX] = { + { /* PRI TDM */ + { {0, 4, 0xFFFF} }, /* RX_0 */ + { {8, 12, 0xFFFF} }, /* RX_1 */ + { {16, 20, 0xFFFF} }, /* RX_2 */ + { {24, 28, 0xFFFF} }, /* RX_3 */ + { {0xFFFF} }, /* RX_4 */ + { {0xFFFF} }, /* RX_5 */ + { {0xFFFF} }, /* RX_6 */ + { {0xFFFF} }, /* RX_7 */ + }, + { + { {0, 4, 0xFFFF} }, /* TX_0 */ + { {8, 12, 0xFFFF} }, /* TX_1 */ + { {16, 20, 0xFFFF} }, /* TX_2 */ + { {24, 28, 0xFFFF} }, /* TX_3 */ + { {0xFFFF} }, /* TX_4 */ + { {0xFFFF} }, /* TX_5 */ + { {0xFFFF} }, /* TX_6 */ + { {0xFFFF} }, /* TX_7 */ + }, + { /* SEC TDM */ + { {0, 4, 0xFFFF} }, /* RX_0 */ + { {8, 12, 0xFFFF} }, /* RX_1 */ + { {16, 20, 0xFFFF} }, /* RX_2 */ + { {24, 28, 0xFFFF} }, /* RX_3 */ + { {0xFFFF} }, /* RX_4 */ + { {0xFFFF} }, /* RX_5 */ + { {0xFFFF} }, /* RX_6 */ + { {0xFFFF} }, /* RX_7 */ + }, + { + { {0, 4, 0xFFFF} }, /* TX_0 */ + { {8, 12, 0xFFFF} }, /* TX_1 */ + { {16, 20, 0xFFFF} }, /* TX_2 */ + { {24, 28, 0xFFFF} }, /* TX_3 */ + { {0xFFFF} }, /* TX_4 */ + { {0xFFFF} }, /* TX_5 */ + { {0xFFFF} }, /* TX_6 */ + { {0xFFFF} }, /* TX_7 */ + }, + { /* TERT TDM */ + { {0, 4, 0xFFFF} }, /* RX_0 */ + { {8, 12, 0xFFFF} }, /* RX_1 */ + { {16, 20, 0xFFFF} }, /* RX_2 */ + { {24, 28, 0xFFFF} }, /* RX_3 */ + { {0xFFFF} }, /* RX_4 */ + { {0xFFFF} }, /* RX_5 */ + { {0xFFFF} }, /* RX_6 */ + { {0xFFFF} }, /* RX_7 */ + }, + { + { {0, 4, 0xFFFF} }, /* TX_0 */ + { {8, 12, 0xFFFF} }, /* TX_1 */ + { {16, 20, 0xFFFF} }, /* TX_2 */ + { {24, 28, 0xFFFF} }, /* TX_3 */ + { {0xFFFF} }, /* TX_4 */ + { {0xFFFF} }, /* TX_5 */ + { {0xFFFF} }, /* TX_6 */ + { {0xFFFF} }, /* TX_7 */ + }, + { /* QUAT TDM */ + { {0, 4, 0xFFFF} }, /* RX_0 */ + { {8, 12, 0xFFFF} }, /* RX_1 */ + { {16, 20, 0xFFFF} }, /* RX_2 */ + { {24, 28, 0xFFFF} }, /* RX_3 */ + { {0xFFFF} }, /* RX_4 */ + { {0xFFFF} }, /* RX_5 */ + { {0xFFFF} }, /* RX_6 */ + { {0xFFFF} }, /* RX_7 */ + }, + { + { {0, 4, 0xFFFF} }, /* TX_0 */ + { {8, 12, 0xFFFF} }, /* TX_1 */ + { {16, 20, 0xFFFF} }, /* TX_2 */ + { {24, 28, 0xFFFF} }, /* TX_3 */ + { {0xFFFF} }, /* TX_4 */ + { {0xFFFF} }, /* TX_5 */ + { {0xFFFF} }, /* TX_6 */ + { {0xFFFF} }, /* TX_7 */ + }, +}; + +/* Default configuration of slimbus channels */ +static struct dev_config slim_rx_cfg[] = { + [SLIM_RX_0] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, + [SLIM_RX_1] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, + [SLIM_RX_2] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, + [SLIM_RX_3] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, + [SLIM_RX_4] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, + [SLIM_RX_5] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, + [SLIM_RX_6] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, + [SLIM_RX_7] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, +}; + +static struct dev_config slim_tx_cfg[] = { + [SLIM_TX_0] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, + [SLIM_TX_1] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, + [SLIM_TX_2] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, + [SLIM_TX_3] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, + [SLIM_TX_4] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, + [SLIM_TX_5] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, + [SLIM_TX_6] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, + [SLIM_TX_7] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, + [SLIM_TX_8] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, +}; + + +/* Default configuration of external display BE */ +static struct dev_config ext_disp_rx_cfg[] = { + [DP_RX_IDX] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, +}; + +static struct dev_config usb_rx_cfg = { + .sample_rate = SAMPLING_RATE_48KHZ, + .bit_format = SNDRV_PCM_FORMAT_S16_LE, + .channels = 2, +}; + +static struct dev_config usb_tx_cfg = { + .sample_rate = SAMPLING_RATE_48KHZ, + .bit_format = SNDRV_PCM_FORMAT_S16_LE, + .channels = 1, +}; + +static struct dev_config proxy_rx_cfg = { + .sample_rate = SAMPLING_RATE_48KHZ, + .bit_format = SNDRV_PCM_FORMAT_S16_LE, + .channels = 2, +}; + +/* Default configuration of MI2S channels */ +static struct dev_config mi2s_rx_cfg[] = { + [PRIM_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, + [SEC_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, + [TERT_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, + [QUAT_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, +}; + +static struct dev_config mi2s_tx_cfg[] = { + [PRIM_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, + [SEC_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, + [TERT_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, + [QUAT_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, +}; + +static struct dev_config aux_pcm_rx_cfg[] = { + [PRIM_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, + [SEC_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, + [TERT_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, + [QUAT_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, +}; + +static struct dev_config aux_pcm_tx_cfg[] = { + [PRIM_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, + [SEC_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, + [TERT_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, + [QUAT_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, +}; + +static int msm_vi_feed_tx_ch = 2; +static const char *const slim_rx_ch_text[] = {"One", "Two"}; +static const char *const slim_tx_ch_text[] = {"One", "Two", "Three", "Four", + "Five", "Six", "Seven", + "Eight"}; +static const char *const vi_feed_ch_text[] = {"One", "Two"}; +static char const *bit_format_text[] = {"S16_LE", "S24_LE", "S24_3LE", + "S32_LE"}; +static char const *ext_disp_bit_format_text[] = {"S16_LE", "S24_LE", + "S24_3LE"}; +static char const *slim_sample_rate_text[] = {"KHZ_8", "KHZ_16", + "KHZ_32", "KHZ_44P1", "KHZ_48", + "KHZ_88P2", "KHZ_96", "KHZ_176P4", + "KHZ_192", "KHZ_352P8", "KHZ_384"}; +static char const *bt_sample_rate_text[] = {"KHZ_8", "KHZ_16", + "KHZ_44P1", "KHZ_48", + "KHZ_88P2", "KHZ_96"}; +static char const *bt_sample_rate_rx_text[] = {"KHZ_8", "KHZ_16", + "KHZ_44P1", "KHZ_48", + "KHZ_88P2", "KHZ_96"}; +static char const *bt_sample_rate_tx_text[] = {"KHZ_8", "KHZ_16", + "KHZ_44P1", "KHZ_48", + "KHZ_88P2", "KHZ_96"}; +static const char *const usb_ch_text[] = {"One", "Two", "Three", "Four", + "Five", "Six", "Seven", + "Eight"}; +static char const *ch_text[] = {"Two", "Three", "Four", "Five", + "Six", "Seven", "Eight"}; +static char const *usb_sample_rate_text[] = {"KHZ_8", "KHZ_11P025", + "KHZ_16", "KHZ_22P05", + "KHZ_32", "KHZ_44P1", "KHZ_48", + "KHZ_88P2", "KHZ_96", "KHZ_176P4", + "KHZ_192", "KHZ_352P8", "KHZ_384"}; +static char const *ext_disp_sample_rate_text[] = {"KHZ_48", "KHZ_96", + "KHZ_192", "KHZ_32", "KHZ_44P1", + "KHZ_88P2", "KHZ_176P4" }; +static char const *tdm_ch_text[] = {"One", "Two", "Three", "Four", + "Five", "Six", "Seven", "Eight"}; +static char const *tdm_bit_format_text[] = {"S16_LE", "S24_LE", "S32_LE"}; +static char const *tdm_sample_rate_text[] = {"KHZ_8", "KHZ_16", "KHZ_32", + "KHZ_48", "KHZ_176P4", + "KHZ_352P8"}; +static const char *const auxpcm_rate_text[] = {"KHZ_8", "KHZ_16"}; +static char const *mi2s_rate_text[] = {"KHZ_8", "KHZ_11P025", "KHZ_16", + "KHZ_22P05", "KHZ_32", "KHZ_44P1", + "KHZ_48", "KHZ_96", "KHZ_192"}; +static const char *const mi2s_ch_text[] = {"One", "Two", "Three", "Four", + "Five", "Six", "Seven", + "Eight"}; +static const char *const hifi_text[] = {"Off", "On"}; +static const char *const qos_text[] = {"Disable", "Enable"}; + +static SOC_ENUM_SINGLE_EXT_DECL(slim_0_rx_chs, slim_rx_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(slim_2_rx_chs, slim_rx_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(slim_0_tx_chs, slim_tx_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(slim_1_tx_chs, slim_tx_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(slim_5_rx_chs, slim_rx_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(slim_6_rx_chs, slim_rx_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_chs, usb_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_chs, usb_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(vi_feed_tx_chs, vi_feed_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(ext_disp_rx_chs, ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(proxy_rx_chs, ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(slim_0_rx_format, bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(slim_5_rx_format, bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(slim_6_rx_format, bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(slim_0_tx_format, bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_format, bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_format, bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(ext_disp_rx_format, ext_disp_bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(slim_0_rx_sample_rate, slim_sample_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(slim_2_rx_sample_rate, slim_sample_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(slim_0_tx_sample_rate, slim_sample_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(slim_5_rx_sample_rate, slim_sample_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(slim_6_rx_sample_rate, slim_sample_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(bt_sample_rate, bt_sample_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(bt_sample_rate_rx, bt_sample_rate_rx_text); +static SOC_ENUM_SINGLE_EXT_DECL(bt_sample_rate_tx, bt_sample_rate_tx_text); +static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_sample_rate, usb_sample_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_sample_rate, usb_sample_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(ext_disp_rx_sample_rate, + ext_disp_sample_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(tdm_tx_chs, tdm_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(tdm_tx_format, tdm_bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(tdm_tx_sample_rate, tdm_sample_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(tdm_rx_chs, tdm_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(tdm_rx_format, tdm_bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(tdm_rx_sample_rate, tdm_sample_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(prim_aux_pcm_rx_sample_rate, auxpcm_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(sec_aux_pcm_rx_sample_rate, auxpcm_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(tert_aux_pcm_rx_sample_rate, auxpcm_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(quat_aux_pcm_rx_sample_rate, auxpcm_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(prim_aux_pcm_tx_sample_rate, auxpcm_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(sec_aux_pcm_tx_sample_rate, auxpcm_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(tert_aux_pcm_tx_sample_rate, auxpcm_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(quat_aux_pcm_tx_sample_rate, auxpcm_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(prim_mi2s_rx_sample_rate, mi2s_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(sec_mi2s_rx_sample_rate, mi2s_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(tert_mi2s_rx_sample_rate, mi2s_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(quat_mi2s_rx_sample_rate, mi2s_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(prim_mi2s_tx_sample_rate, mi2s_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(sec_mi2s_tx_sample_rate, mi2s_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(tert_mi2s_tx_sample_rate, mi2s_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(quat_mi2s_tx_sample_rate, mi2s_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(prim_mi2s_rx_chs, mi2s_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(prim_mi2s_tx_chs, mi2s_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(sec_mi2s_rx_chs, mi2s_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(sec_mi2s_tx_chs, mi2s_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(tert_mi2s_rx_chs, mi2s_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(tert_mi2s_tx_chs, mi2s_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(quat_mi2s_rx_chs, mi2s_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(quat_mi2s_tx_chs, mi2s_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(mi2s_rx_format, bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(mi2s_tx_format, bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(aux_pcm_rx_format, bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(aux_pcm_tx_format, bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(hifi_function, hifi_text); +static SOC_ENUM_SINGLE_EXT_DECL(qos_vote, qos_text); + +static struct platform_device *spdev; +static int msm_hifi_control; +static int qos_vote_status; + +static bool is_initial_boot; +static bool codec_reg_done; +static struct snd_soc_aux_dev *msm_aux_dev; +static struct snd_soc_codec_conf *msm_codec_conf; +static struct msm_asoc_wcd93xx_codec msm_codec_fn; + +static void *def_tavil_mbhc_cal(void); +static int msm_snd_enable_codec_ext_clk(struct snd_soc_component *component, + int enable, bool dapm); +static int msm_wsa881x_init(struct snd_soc_component *component); + +/* + * Need to report LINEIN + * if R/L channel impedance is larger than 5K ohm + */ +static struct wcd_mbhc_config wcd_mbhc_cfg = { + .read_fw_bin = false, + .calibration = NULL, + .detect_extn_cable = true, + .mono_stero_detection = false, + .swap_gnd_mic = NULL, + .hs_ext_micbias = true, + .key_code[0] = KEY_MEDIA, + .key_code[1] = KEY_VOICECOMMAND, + .key_code[2] = KEY_VOLUMEUP, + .key_code[3] = KEY_VOLUMEDOWN, + .key_code[4] = 0, + .key_code[5] = 0, + .key_code[6] = 0, + .key_code[7] = 0, + .linein_th = 5000, + .moisture_en = true, + .mbhc_micbias = MIC_BIAS_2, + .anc_micbias = MIC_BIAS_2, + .enable_anc_mic_detect = false, +}; + +static struct snd_soc_dapm_route wcd_audio_paths[] = { + {"MIC BIAS1", NULL, "MCLK TX"}, + {"MIC BIAS2", NULL, "MCLK TX"}, + {"MIC BIAS3", NULL, "MCLK TX"}, + {"MIC BIAS4", NULL, "MCLK TX"}, +}; + +static struct afe_clk_set mi2s_clk[MI2S_MAX] = { + { + AFE_API_VERSION_I2S_CONFIG, + Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT, + Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ, + Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO, + Q6AFE_LPASS_CLK_ROOT_DEFAULT, + 0, + }, + { + AFE_API_VERSION_I2S_CONFIG, + Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT, + Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ, + Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO, + Q6AFE_LPASS_CLK_ROOT_DEFAULT, + 0, + }, + { + AFE_API_VERSION_I2S_CONFIG, + Q6AFE_LPASS_CLK_ID_TER_MI2S_IBIT, + Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ, + Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO, + Q6AFE_LPASS_CLK_ROOT_DEFAULT, + 0, + }, + { + AFE_API_VERSION_I2S_CONFIG, + Q6AFE_LPASS_CLK_ID_QUAD_MI2S_IBIT, + Q6AFE_LPASS_IBIT_CLK_1_P536_MHZ, + Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO, + Q6AFE_LPASS_CLK_ROOT_DEFAULT, + 0, + } +}; + +static struct mi2s_conf mi2s_intf_conf[MI2S_MAX]; + +static int slim_get_sample_rate_val(int sample_rate) +{ + int sample_rate_val = 0; + + switch (sample_rate) { + case SAMPLING_RATE_8KHZ: + sample_rate_val = 0; + break; + case SAMPLING_RATE_16KHZ: + sample_rate_val = 1; + break; + case SAMPLING_RATE_32KHZ: + sample_rate_val = 2; + break; + case SAMPLING_RATE_44P1KHZ: + sample_rate_val = 3; + break; + case SAMPLING_RATE_48KHZ: + sample_rate_val = 4; + break; + case SAMPLING_RATE_88P2KHZ: + sample_rate_val = 5; + break; + case SAMPLING_RATE_96KHZ: + sample_rate_val = 6; + break; + case SAMPLING_RATE_176P4KHZ: + sample_rate_val = 7; + break; + case SAMPLING_RATE_192KHZ: + sample_rate_val = 8; + break; + case SAMPLING_RATE_352P8KHZ: + sample_rate_val = 9; + break; + case SAMPLING_RATE_384KHZ: + sample_rate_val = 10; + break; + default: + sample_rate_val = 4; + break; + } + return sample_rate_val; +} + +static int slim_get_sample_rate(int value) +{ + int sample_rate = 0; + + switch (value) { + case 0: + sample_rate = SAMPLING_RATE_8KHZ; + break; + case 1: + sample_rate = SAMPLING_RATE_16KHZ; + break; + case 2: + sample_rate = SAMPLING_RATE_32KHZ; + break; + case 3: + sample_rate = SAMPLING_RATE_44P1KHZ; + break; + case 4: + sample_rate = SAMPLING_RATE_48KHZ; + break; + case 5: + sample_rate = SAMPLING_RATE_88P2KHZ; + break; + case 6: + sample_rate = SAMPLING_RATE_96KHZ; + break; + case 7: + sample_rate = SAMPLING_RATE_176P4KHZ; + break; + case 8: + sample_rate = SAMPLING_RATE_192KHZ; + break; + case 9: + sample_rate = SAMPLING_RATE_352P8KHZ; + break; + case 10: + sample_rate = SAMPLING_RATE_384KHZ; + break; + default: + sample_rate = SAMPLING_RATE_48KHZ; + break; + } + return sample_rate; +} + +static int slim_get_bit_format_val(int bit_format) +{ + int val = 0; + + switch (bit_format) { + case SNDRV_PCM_FORMAT_S32_LE: + val = 3; + break; + case SNDRV_PCM_FORMAT_S24_3LE: + val = 2; + break; + case SNDRV_PCM_FORMAT_S24_LE: + val = 1; + break; + case SNDRV_PCM_FORMAT_S16_LE: + default: + val = 0; + break; + } + return val; +} + +static int slim_get_bit_format(int val) +{ + int bit_fmt = SNDRV_PCM_FORMAT_S16_LE; + + switch (val) { + case 0: + bit_fmt = SNDRV_PCM_FORMAT_S16_LE; + break; + case 1: + bit_fmt = SNDRV_PCM_FORMAT_S24_LE; + break; + case 2: + bit_fmt = SNDRV_PCM_FORMAT_S24_3LE; + break; + case 3: + bit_fmt = SNDRV_PCM_FORMAT_S32_LE; + break; + default: + bit_fmt = SNDRV_PCM_FORMAT_S16_LE; + break; + } + return bit_fmt; +} + +static int slim_get_port_idx(struct snd_kcontrol *kcontrol) +{ + int port_id = 0; + + if (strnstr(kcontrol->id.name, "SLIM_0_RX", sizeof("SLIM_0_RX"))) + port_id = SLIM_RX_0; + else if (strnstr(kcontrol->id.name, "SLIM_2_RX", sizeof("SLIM_2_RX"))) + port_id = SLIM_RX_2; + else if (strnstr(kcontrol->id.name, "SLIM_5_RX", sizeof("SLIM_5_RX"))) + port_id = SLIM_RX_5; + else if (strnstr(kcontrol->id.name, "SLIM_6_RX", sizeof("SLIM_6_RX"))) + port_id = SLIM_RX_6; + else if (strnstr(kcontrol->id.name, "SLIM_0_TX", sizeof("SLIM_0_TX"))) + port_id = SLIM_TX_0; + else if (strnstr(kcontrol->id.name, "SLIM_1_TX", sizeof("SLIM_1_TX"))) + port_id = SLIM_TX_1; + else { + pr_err("%s: unsupported channel: %s", + __func__, kcontrol->id.name); + return -EINVAL; + } + + return port_id; +} + +static int slim_rx_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ch_num = slim_get_port_idx(kcontrol); + + if (ch_num < 0) + return ch_num; + + ucontrol->value.enumerated.item[0] = + slim_get_sample_rate_val(slim_rx_cfg[ch_num].sample_rate); + + pr_debug("%s: slim[%d]_rx_sample_rate = %d, item = %d\n", __func__, + ch_num, slim_rx_cfg[ch_num].sample_rate, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int slim_rx_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ch_num = slim_get_port_idx(kcontrol); + + if (ch_num < 0) + return ch_num; + + slim_rx_cfg[ch_num].sample_rate = + slim_get_sample_rate(ucontrol->value.enumerated.item[0]); + + pr_debug("%s: slim[%d]_rx_sample_rate = %d, item = %d\n", __func__, + ch_num, slim_rx_cfg[ch_num].sample_rate, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int slim_tx_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ch_num = slim_get_port_idx(kcontrol); + + if (ch_num < 0) + return ch_num; + + ucontrol->value.enumerated.item[0] = + slim_get_sample_rate_val(slim_tx_cfg[ch_num].sample_rate); + + pr_debug("%s: slim[%d]_tx_sample_rate = %d, item = %d\n", __func__, + ch_num, slim_tx_cfg[ch_num].sample_rate, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int slim_tx_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int sample_rate = 0; + int ch_num = slim_get_port_idx(kcontrol); + + if (ch_num < 0) + return ch_num; + + sample_rate = slim_get_sample_rate(ucontrol->value.enumerated.item[0]); + if (sample_rate == SAMPLING_RATE_44P1KHZ) { + pr_err("%s: Unsupported sample rate %d: for Tx path\n", + __func__, sample_rate); + return -EINVAL; + } + slim_tx_cfg[ch_num].sample_rate = sample_rate; + + pr_debug("%s: slim[%d]_tx_sample_rate = %d, value = %d\n", __func__, + ch_num, slim_tx_cfg[ch_num].sample_rate, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int slim_rx_bit_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ch_num = slim_get_port_idx(kcontrol); + + if (ch_num < 0) + return ch_num; + + ucontrol->value.enumerated.item[0] = + slim_get_bit_format_val(slim_rx_cfg[ch_num].bit_format); + + pr_debug("%s: slim[%d]_rx_bit_format = %d, ucontrol value = %d\n", + __func__, ch_num, slim_rx_cfg[ch_num].bit_format, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int slim_rx_bit_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ch_num = slim_get_port_idx(kcontrol); + + if (ch_num < 0) + return ch_num; + + slim_rx_cfg[ch_num].bit_format = + slim_get_bit_format(ucontrol->value.enumerated.item[0]); + + pr_debug("%s: slim[%d]_rx_bit_format = %d, ucontrol value = %d\n", + __func__, ch_num, slim_rx_cfg[ch_num].bit_format, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int slim_tx_bit_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ch_num = slim_get_port_idx(kcontrol); + + if (ch_num < 0) + return ch_num; + + ucontrol->value.enumerated.item[0] = + slim_get_bit_format_val(slim_tx_cfg[ch_num].bit_format); + + pr_debug("%s: slim[%d]_tx_bit_format = %d, ucontrol value = %d\n", + __func__, ch_num, slim_tx_cfg[ch_num].bit_format, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int slim_tx_bit_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ch_num = slim_get_port_idx(kcontrol); + + if (ch_num < 0) + return ch_num; + + slim_tx_cfg[ch_num].bit_format = + slim_get_bit_format(ucontrol->value.enumerated.item[0]); + + pr_debug("%s: slim[%d]_tx_bit_format = %d, ucontrol value = %d\n", + __func__, ch_num, slim_tx_cfg[ch_num].bit_format, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int msm_slim_rx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ch_num = slim_get_port_idx(kcontrol); + + if (ch_num < 0) + return ch_num; + + pr_debug("%s: msm_slim_[%d]_rx_ch = %d\n", __func__, + ch_num, slim_rx_cfg[ch_num].channels); + ucontrol->value.enumerated.item[0] = slim_rx_cfg[ch_num].channels - 1; + + return 0; +} + +static int msm_slim_rx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ch_num = slim_get_port_idx(kcontrol); + + if (ch_num < 0) + return ch_num; + + slim_rx_cfg[ch_num].channels = ucontrol->value.enumerated.item[0] + 1; + pr_debug("%s: msm_slim_[%d]_rx_ch = %d\n", __func__, + ch_num, slim_rx_cfg[ch_num].channels); + + return 1; +} + +static int msm_slim_tx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ch_num = slim_get_port_idx(kcontrol); + + if (ch_num < 0) + return ch_num; + + pr_debug("%s: msm_slim_[%d]_tx_ch = %d\n", __func__, + ch_num, slim_tx_cfg[ch_num].channels); + ucontrol->value.enumerated.item[0] = slim_tx_cfg[ch_num].channels - 1; + + return 0; +} + +static int msm_slim_tx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ch_num = slim_get_port_idx(kcontrol); + + if (ch_num < 0) + return ch_num; + + slim_tx_cfg[ch_num].channels = ucontrol->value.enumerated.item[0] + 1; + pr_debug("%s: msm_slim_[%d]_tx_ch = %d\n", __func__, + ch_num, slim_tx_cfg[ch_num].channels); + + return 1; +} + +static int msm_vi_feed_tx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = msm_vi_feed_tx_ch - 1; + pr_debug("%s: msm_vi_feed_tx_ch = %ld\n", __func__, + ucontrol->value.integer.value[0]); + return 0; +} + +static int msm_vi_feed_tx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + msm_vi_feed_tx_ch = ucontrol->value.integer.value[0] + 1; + + pr_debug("%s: msm_vi_feed_tx_ch = %d\n", __func__, msm_vi_feed_tx_ch); + return 1; +} + +static int msm_bt_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + /* + * Slimbus_7_Rx/Tx sample rate values should always be in sync (same) + * when used for BT_SCO use case. Return either Rx or Tx sample rate + * value. + */ + switch (slim_rx_cfg[SLIM_RX_7].sample_rate) { + case SAMPLING_RATE_96KHZ: + ucontrol->value.integer.value[0] = 5; + break; + case SAMPLING_RATE_88P2KHZ: + ucontrol->value.integer.value[0] = 4; + break; + case SAMPLING_RATE_48KHZ: + ucontrol->value.integer.value[0] = 3; + break; + case SAMPLING_RATE_44P1KHZ: + ucontrol->value.integer.value[0] = 2; + break; + case SAMPLING_RATE_16KHZ: + ucontrol->value.integer.value[0] = 1; + break; + case SAMPLING_RATE_8KHZ: + default: + ucontrol->value.integer.value[0] = 0; + break; + } + pr_debug("%s: sample rate = %d", __func__, + slim_rx_cfg[SLIM_RX_7].sample_rate); + + return 0; +} + +static int msm_bt_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (ucontrol->value.integer.value[0]) { + case 1: + slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_16KHZ; + slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_16KHZ; + break; + case 2: + slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_44P1KHZ; + slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_44P1KHZ; + break; + case 3: + slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_48KHZ; + slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_48KHZ; + break; + case 4: + slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_88P2KHZ; + slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_88P2KHZ; + break; + case 5: + slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_96KHZ; + slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_96KHZ; + break; + case 0: + default: + slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_8KHZ; + slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_8KHZ; + break; + } + pr_debug("%s: sample rates: slim7_rx = %d, slim7_tx = %d, value = %d\n", + __func__, + slim_rx_cfg[SLIM_RX_7].sample_rate, + slim_tx_cfg[SLIM_TX_7].sample_rate, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int msm_bt_sample_rate_rx_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (slim_rx_cfg[SLIM_RX_7].sample_rate) { + case SAMPLING_RATE_96KHZ: + ucontrol->value.integer.value[0] = 5; + break; + case SAMPLING_RATE_88P2KHZ: + ucontrol->value.integer.value[0] = 4; + break; + case SAMPLING_RATE_48KHZ: + ucontrol->value.integer.value[0] = 3; + break; + case SAMPLING_RATE_44P1KHZ: + ucontrol->value.integer.value[0] = 2; + break; + case SAMPLING_RATE_16KHZ: + ucontrol->value.integer.value[0] = 1; + break; + case SAMPLING_RATE_8KHZ: + default: + ucontrol->value.integer.value[0] = 0; + break; + } + pr_debug("%s: sample rate = %d", __func__, + slim_rx_cfg[SLIM_RX_7].sample_rate); + + return 0; +} + +static int msm_bt_sample_rate_rx_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (ucontrol->value.integer.value[0]) { + case 1: + slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_16KHZ; + break; + case 2: + slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_44P1KHZ; + break; + case 3: + slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_48KHZ; + break; + case 4: + slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_88P2KHZ; + break; + case 5: + slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_96KHZ; + break; + case 0: + default: + slim_rx_cfg[SLIM_RX_7].sample_rate = SAMPLING_RATE_8KHZ; + break; + } + pr_debug("%s: sample rates: slim7_rx = %d, value = %d\n", + __func__, + slim_rx_cfg[SLIM_RX_7].sample_rate, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int msm_bt_sample_rate_tx_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (slim_tx_cfg[SLIM_TX_7].sample_rate) { + case SAMPLING_RATE_96KHZ: + ucontrol->value.integer.value[0] = 5; + break; + case SAMPLING_RATE_88P2KHZ: + ucontrol->value.integer.value[0] = 4; + break; + case SAMPLING_RATE_48KHZ: + ucontrol->value.integer.value[0] = 3; + break; + case SAMPLING_RATE_44P1KHZ: + ucontrol->value.integer.value[0] = 2; + break; + case SAMPLING_RATE_16KHZ: + ucontrol->value.integer.value[0] = 1; + break; + case SAMPLING_RATE_8KHZ: + default: + ucontrol->value.integer.value[0] = 0; + break; + } + pr_debug("%s: sample rate = %d", __func__, + slim_tx_cfg[SLIM_TX_7].sample_rate); + + return 0; +} + +static int msm_bt_sample_rate_tx_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (ucontrol->value.integer.value[0]) { + case 1: + slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_16KHZ; + break; + case 2: + slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_44P1KHZ; + break; + case 3: + slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_48KHZ; + break; + case 4: + slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_88P2KHZ; + break; + case 5: + slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_96KHZ; + break; + case 0: + default: + slim_tx_cfg[SLIM_TX_7].sample_rate = SAMPLING_RATE_8KHZ; + break; + } + pr_debug("%s: sample rates: slim7_tx = %d, value = %d\n", + __func__, + slim_tx_cfg[SLIM_TX_7].sample_rate, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int usb_audio_rx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: usb_audio_rx_ch = %d\n", __func__, + usb_rx_cfg.channels); + ucontrol->value.integer.value[0] = usb_rx_cfg.channels - 1; + return 0; +} + +static int usb_audio_rx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + usb_rx_cfg.channels = ucontrol->value.integer.value[0] + 1; + + pr_debug("%s: usb_audio_rx_ch = %d\n", __func__, usb_rx_cfg.channels); + return 1; +} + +static int usb_audio_rx_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int sample_rate_val; + + switch (usb_rx_cfg.sample_rate) { + case SAMPLING_RATE_384KHZ: + sample_rate_val = 12; + break; + case SAMPLING_RATE_352P8KHZ: + sample_rate_val = 11; + break; + case SAMPLING_RATE_192KHZ: + sample_rate_val = 10; + break; + case SAMPLING_RATE_176P4KHZ: + sample_rate_val = 9; + break; + case SAMPLING_RATE_96KHZ: + sample_rate_val = 8; + break; + case SAMPLING_RATE_88P2KHZ: + sample_rate_val = 7; + break; + case SAMPLING_RATE_48KHZ: + sample_rate_val = 6; + break; + case SAMPLING_RATE_44P1KHZ: + sample_rate_val = 5; + break; + case SAMPLING_RATE_32KHZ: + sample_rate_val = 4; + break; + case SAMPLING_RATE_22P05KHZ: + sample_rate_val = 3; + break; + case SAMPLING_RATE_16KHZ: + sample_rate_val = 2; + break; + case SAMPLING_RATE_11P025KHZ: + sample_rate_val = 1; + break; + case SAMPLING_RATE_8KHZ: + default: + sample_rate_val = 0; + break; + } + + ucontrol->value.integer.value[0] = sample_rate_val; + pr_debug("%s: usb_audio_rx_sample_rate = %d\n", __func__, + usb_rx_cfg.sample_rate); + return 0; +} + +static int usb_audio_rx_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (ucontrol->value.integer.value[0]) { + case 12: + usb_rx_cfg.sample_rate = SAMPLING_RATE_384KHZ; + break; + case 11: + usb_rx_cfg.sample_rate = SAMPLING_RATE_352P8KHZ; + break; + case 10: + usb_rx_cfg.sample_rate = SAMPLING_RATE_192KHZ; + break; + case 9: + usb_rx_cfg.sample_rate = SAMPLING_RATE_176P4KHZ; + break; + case 8: + usb_rx_cfg.sample_rate = SAMPLING_RATE_96KHZ; + break; + case 7: + usb_rx_cfg.sample_rate = SAMPLING_RATE_88P2KHZ; + break; + case 6: + usb_rx_cfg.sample_rate = SAMPLING_RATE_48KHZ; + break; + case 5: + usb_rx_cfg.sample_rate = SAMPLING_RATE_44P1KHZ; + break; + case 4: + usb_rx_cfg.sample_rate = SAMPLING_RATE_32KHZ; + break; + case 3: + usb_rx_cfg.sample_rate = SAMPLING_RATE_22P05KHZ; + break; + case 2: + usb_rx_cfg.sample_rate = SAMPLING_RATE_16KHZ; + break; + case 1: + usb_rx_cfg.sample_rate = SAMPLING_RATE_11P025KHZ; + break; + case 0: + usb_rx_cfg.sample_rate = SAMPLING_RATE_8KHZ; + break; + default: + usb_rx_cfg.sample_rate = SAMPLING_RATE_48KHZ; + break; + } + + pr_debug("%s: control value = %ld, usb_audio_rx_sample_rate = %d\n", + __func__, ucontrol->value.integer.value[0], + usb_rx_cfg.sample_rate); + return 0; +} + +static int usb_audio_rx_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (usb_rx_cfg.bit_format) { + case SNDRV_PCM_FORMAT_S32_LE: + ucontrol->value.integer.value[0] = 3; + break; + case SNDRV_PCM_FORMAT_S24_3LE: + ucontrol->value.integer.value[0] = 2; + break; + case SNDRV_PCM_FORMAT_S24_LE: + ucontrol->value.integer.value[0] = 1; + break; + case SNDRV_PCM_FORMAT_S16_LE: + default: + ucontrol->value.integer.value[0] = 0; + break; + } + + pr_debug("%s: usb_audio_rx_format = %d, ucontrol value = %ld\n", + __func__, usb_rx_cfg.bit_format, + ucontrol->value.integer.value[0]); + return 0; +} + +static int usb_audio_rx_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int rc = 0; + + switch (ucontrol->value.integer.value[0]) { + case 3: + usb_rx_cfg.bit_format = SNDRV_PCM_FORMAT_S32_LE; + break; + case 2: + usb_rx_cfg.bit_format = SNDRV_PCM_FORMAT_S24_3LE; + break; + case 1: + usb_rx_cfg.bit_format = SNDRV_PCM_FORMAT_S24_LE; + break; + case 0: + default: + usb_rx_cfg.bit_format = SNDRV_PCM_FORMAT_S16_LE; + break; + } + pr_debug("%s: usb_audio_rx_format = %d, ucontrol value = %ld\n", + __func__, usb_rx_cfg.bit_format, + ucontrol->value.integer.value[0]); + + return rc; +} + +static int usb_audio_tx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: usb_audio_tx_ch = %d\n", __func__, + usb_tx_cfg.channels); + ucontrol->value.integer.value[0] = usb_tx_cfg.channels - 1; + return 0; +} + +static int usb_audio_tx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + usb_tx_cfg.channels = ucontrol->value.integer.value[0] + 1; + + pr_debug("%s: usb_audio_tx_ch = %d\n", __func__, usb_tx_cfg.channels); + return 1; +} + +static int usb_audio_tx_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int sample_rate_val; + + switch (usb_tx_cfg.sample_rate) { + case SAMPLING_RATE_384KHZ: + sample_rate_val = 12; + break; + case SAMPLING_RATE_352P8KHZ: + sample_rate_val = 11; + break; + case SAMPLING_RATE_192KHZ: + sample_rate_val = 10; + break; + case SAMPLING_RATE_176P4KHZ: + sample_rate_val = 9; + break; + case SAMPLING_RATE_96KHZ: + sample_rate_val = 8; + break; + case SAMPLING_RATE_88P2KHZ: + sample_rate_val = 7; + break; + case SAMPLING_RATE_48KHZ: + sample_rate_val = 6; + break; + case SAMPLING_RATE_44P1KHZ: + sample_rate_val = 5; + break; + case SAMPLING_RATE_32KHZ: + sample_rate_val = 4; + break; + case SAMPLING_RATE_22P05KHZ: + sample_rate_val = 3; + break; + case SAMPLING_RATE_16KHZ: + sample_rate_val = 2; + break; + case SAMPLING_RATE_11P025KHZ: + sample_rate_val = 1; + break; + case SAMPLING_RATE_8KHZ: + sample_rate_val = 0; + break; + default: + sample_rate_val = 6; + break; + } + + ucontrol->value.integer.value[0] = sample_rate_val; + pr_debug("%s: usb_audio_tx_sample_rate = %d\n", __func__, + usb_tx_cfg.sample_rate); + return 0; +} + +static int usb_audio_tx_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (ucontrol->value.integer.value[0]) { + case 12: + usb_tx_cfg.sample_rate = SAMPLING_RATE_384KHZ; + break; + case 11: + usb_tx_cfg.sample_rate = SAMPLING_RATE_352P8KHZ; + break; + case 10: + usb_tx_cfg.sample_rate = SAMPLING_RATE_192KHZ; + break; + case 9: + usb_tx_cfg.sample_rate = SAMPLING_RATE_176P4KHZ; + break; + case 8: + usb_tx_cfg.sample_rate = SAMPLING_RATE_96KHZ; + break; + case 7: + usb_tx_cfg.sample_rate = SAMPLING_RATE_88P2KHZ; + break; + case 6: + usb_tx_cfg.sample_rate = SAMPLING_RATE_48KHZ; + break; + case 5: + usb_tx_cfg.sample_rate = SAMPLING_RATE_44P1KHZ; + break; + case 4: + usb_tx_cfg.sample_rate = SAMPLING_RATE_32KHZ; + break; + case 3: + usb_tx_cfg.sample_rate = SAMPLING_RATE_22P05KHZ; + break; + case 2: + usb_tx_cfg.sample_rate = SAMPLING_RATE_16KHZ; + break; + case 1: + usb_tx_cfg.sample_rate = SAMPLING_RATE_11P025KHZ; + break; + case 0: + usb_tx_cfg.sample_rate = SAMPLING_RATE_8KHZ; + break; + default: + usb_tx_cfg.sample_rate = SAMPLING_RATE_48KHZ; + break; + } + + pr_debug("%s: control value = %ld, usb_audio_tx_sample_rate = %d\n", + __func__, ucontrol->value.integer.value[0], + usb_tx_cfg.sample_rate); + return 0; +} + +static int usb_audio_tx_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + switch (usb_tx_cfg.bit_format) { + case SNDRV_PCM_FORMAT_S32_LE: + ucontrol->value.integer.value[0] = 3; + break; + case SNDRV_PCM_FORMAT_S24_3LE: + ucontrol->value.integer.value[0] = 2; + break; + case SNDRV_PCM_FORMAT_S24_LE: + ucontrol->value.integer.value[0] = 1; + break; + case SNDRV_PCM_FORMAT_S16_LE: + default: + ucontrol->value.integer.value[0] = 0; + break; + } + + pr_debug("%s: usb_audio_tx_format = %d, ucontrol value = %ld\n", + __func__, usb_tx_cfg.bit_format, + ucontrol->value.integer.value[0]); + return 0; +} + +static int usb_audio_tx_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int rc = 0; + + switch (ucontrol->value.integer.value[0]) { + case 3: + usb_tx_cfg.bit_format = SNDRV_PCM_FORMAT_S32_LE; + break; + case 2: + usb_tx_cfg.bit_format = SNDRV_PCM_FORMAT_S24_3LE; + break; + case 1: + usb_tx_cfg.bit_format = SNDRV_PCM_FORMAT_S24_LE; + break; + case 0: + default: + usb_tx_cfg.bit_format = SNDRV_PCM_FORMAT_S16_LE; + break; + } + pr_debug("%s: usb_audio_tx_format = %d, ucontrol value = %ld\n", + __func__, usb_tx_cfg.bit_format, + ucontrol->value.integer.value[0]); + + return rc; +} + +static int ext_disp_get_port_idx(struct snd_kcontrol *kcontrol) +{ + int idx; + + if (strnstr(kcontrol->id.name, "Display Port RX", + sizeof("Display Port RX"))) { + idx = DP_RX_IDX; + } else { + pr_err("%s: unsupported BE: %s", + __func__, kcontrol->id.name); + idx = -EINVAL; + } + + return idx; +} + +static int ext_disp_rx_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = ext_disp_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + switch (ext_disp_rx_cfg[idx].bit_format) { + case SNDRV_PCM_FORMAT_S24_3LE: + ucontrol->value.integer.value[0] = 2; + break; + case SNDRV_PCM_FORMAT_S24_LE: + ucontrol->value.integer.value[0] = 1; + break; + case SNDRV_PCM_FORMAT_S16_LE: + default: + ucontrol->value.integer.value[0] = 0; + break; + } + + pr_debug("%s: ext_disp_rx[%d].format = %d, ucontrol value = %ld\n", + __func__, idx, ext_disp_rx_cfg[idx].bit_format, + ucontrol->value.integer.value[0]); + return 0; +} + +static int ext_disp_rx_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = ext_disp_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + switch (ucontrol->value.integer.value[0]) { + case 2: + ext_disp_rx_cfg[idx].bit_format = SNDRV_PCM_FORMAT_S24_3LE; + break; + case 1: + ext_disp_rx_cfg[idx].bit_format = SNDRV_PCM_FORMAT_S24_LE; + break; + case 0: + default: + ext_disp_rx_cfg[idx].bit_format = SNDRV_PCM_FORMAT_S16_LE; + break; + } + pr_debug("%s: ext_disp_rx[%d].format = %d, ucontrol value = %ld\n", + __func__, idx, ext_disp_rx_cfg[idx].bit_format, + ucontrol->value.integer.value[0]); + + return 0; +} + +static int ext_disp_rx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = ext_disp_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + ucontrol->value.integer.value[0] = + ext_disp_rx_cfg[idx].channels - 2; + + pr_debug("%s: ext_disp_rx[%d].ch = %d\n", __func__, + idx, ext_disp_rx_cfg[idx].channels); + + return 0; +} + +static int ext_disp_rx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = ext_disp_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + ext_disp_rx_cfg[idx].channels = + ucontrol->value.integer.value[0] + 2; + + pr_debug("%s: ext_disp_rx[%d].ch = %d\n", __func__, + idx, ext_disp_rx_cfg[idx].channels); + return 1; +} + +static int ext_disp_rx_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int sample_rate_val; + int idx = ext_disp_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + switch (ext_disp_rx_cfg[idx].sample_rate) { + case SAMPLING_RATE_176P4KHZ: + sample_rate_val = 6; + break; + + case SAMPLING_RATE_88P2KHZ: + sample_rate_val = 5; + break; + + case SAMPLING_RATE_44P1KHZ: + sample_rate_val = 4; + break; + + case SAMPLING_RATE_32KHZ: + sample_rate_val = 3; + break; + + case SAMPLING_RATE_192KHZ: + sample_rate_val = 2; + break; + + case SAMPLING_RATE_96KHZ: + sample_rate_val = 1; + break; + + case SAMPLING_RATE_48KHZ: + default: + sample_rate_val = 0; + break; + } + + ucontrol->value.integer.value[0] = sample_rate_val; + pr_debug("%s: ext_disp_rx[%d].sample_rate = %d\n", __func__, + idx, ext_disp_rx_cfg[idx].sample_rate); + + return 0; +} + +static int ext_disp_rx_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = ext_disp_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + switch (ucontrol->value.integer.value[0]) { + case 6: + ext_disp_rx_cfg[idx].sample_rate = SAMPLING_RATE_176P4KHZ; + break; + case 5: + ext_disp_rx_cfg[idx].sample_rate = SAMPLING_RATE_88P2KHZ; + break; + case 4: + ext_disp_rx_cfg[idx].sample_rate = SAMPLING_RATE_44P1KHZ; + break; + case 3: + ext_disp_rx_cfg[idx].sample_rate = SAMPLING_RATE_32KHZ; + break; + case 2: + ext_disp_rx_cfg[idx].sample_rate = SAMPLING_RATE_192KHZ; + break; + case 1: + ext_disp_rx_cfg[idx].sample_rate = SAMPLING_RATE_96KHZ; + break; + case 0: + default: + ext_disp_rx_cfg[idx].sample_rate = SAMPLING_RATE_48KHZ; + break; + } + + pr_debug("%s: control value = %ld, ext_disp_rx[%d].sample_rate = %d\n", + __func__, ucontrol->value.integer.value[0], idx, + ext_disp_rx_cfg[idx].sample_rate); + return 0; +} + +static int proxy_rx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: proxy_rx channels = %d\n", + __func__, proxy_rx_cfg.channels); + ucontrol->value.integer.value[0] = proxy_rx_cfg.channels - 2; + + return 0; +} + +static int proxy_rx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + proxy_rx_cfg.channels = ucontrol->value.integer.value[0] + 2; + pr_debug("%s: proxy_rx channels = %d\n", + __func__, proxy_rx_cfg.channels); + + return 1; +} + +static int tdm_get_sample_rate(int value) +{ + int sample_rate = 0; + + switch (value) { + case 0: + sample_rate = SAMPLING_RATE_8KHZ; + break; + case 1: + sample_rate = SAMPLING_RATE_16KHZ; + break; + case 2: + sample_rate = SAMPLING_RATE_32KHZ; + break; + case 3: + sample_rate = SAMPLING_RATE_48KHZ; + break; + case 4: + sample_rate = SAMPLING_RATE_176P4KHZ; + break; + case 5: + sample_rate = SAMPLING_RATE_352P8KHZ; + break; + default: + sample_rate = SAMPLING_RATE_48KHZ; + break; + } + return sample_rate; +} + +static int aux_pcm_get_sample_rate(int value) +{ + int sample_rate; + + switch (value) { + case 1: + sample_rate = SAMPLING_RATE_16KHZ; + break; + case 0: + default: + sample_rate = SAMPLING_RATE_8KHZ; + break; + } + return sample_rate; +} + +static int tdm_get_sample_rate_val(int sample_rate) +{ + int sample_rate_val = 0; + + switch (sample_rate) { + case SAMPLING_RATE_8KHZ: + sample_rate_val = 0; + break; + case SAMPLING_RATE_16KHZ: + sample_rate_val = 1; + break; + case SAMPLING_RATE_32KHZ: + sample_rate_val = 2; + break; + case SAMPLING_RATE_48KHZ: + sample_rate_val = 3; + break; + case SAMPLING_RATE_176P4KHZ: + sample_rate_val = 4; + break; + case SAMPLING_RATE_352P8KHZ: + sample_rate_val = 5; + break; + default: + sample_rate_val = 3; + break; + } + return sample_rate_val; +} + +static int aux_pcm_get_sample_rate_val(int sample_rate) +{ + int sample_rate_val; + + switch (sample_rate) { + case SAMPLING_RATE_16KHZ: + sample_rate_val = 1; + break; + case SAMPLING_RATE_8KHZ: + default: + sample_rate_val = 0; + break; + } + return sample_rate_val; +} + +static int tdm_get_port_idx(struct snd_kcontrol *kcontrol, + struct tdm_port *port) +{ + if (port) { + if (strnstr(kcontrol->id.name, "PRI", + sizeof(kcontrol->id.name))) { + port->mode = TDM_PRI; + } else if (strnstr(kcontrol->id.name, "SEC", + sizeof(kcontrol->id.name))) { + port->mode = TDM_SEC; + } else if (strnstr(kcontrol->id.name, "TERT", + sizeof(kcontrol->id.name))) { + port->mode = TDM_TERT; + } else if (strnstr(kcontrol->id.name, "QUAT", + sizeof(kcontrol->id.name))) { + port->mode = TDM_QUAT; + } else { + pr_err("%s: unsupported mode in: %s", + __func__, kcontrol->id.name); + return -EINVAL; + } + + if (strnstr(kcontrol->id.name, "RX_0", + sizeof(kcontrol->id.name)) || + strnstr(kcontrol->id.name, "TX_0", + sizeof(kcontrol->id.name))) { + port->channel = TDM_0; + } else if (strnstr(kcontrol->id.name, "RX_1", + sizeof(kcontrol->id.name)) || + strnstr(kcontrol->id.name, "TX_1", + sizeof(kcontrol->id.name))) { + port->channel = TDM_1; + } else if (strnstr(kcontrol->id.name, "RX_2", + sizeof(kcontrol->id.name)) || + strnstr(kcontrol->id.name, "TX_2", + sizeof(kcontrol->id.name))) { + port->channel = TDM_2; + } else if (strnstr(kcontrol->id.name, "RX_3", + sizeof(kcontrol->id.name)) || + strnstr(kcontrol->id.name, "TX_3", + sizeof(kcontrol->id.name))) { + port->channel = TDM_3; + } else if (strnstr(kcontrol->id.name, "RX_4", + sizeof(kcontrol->id.name)) || + strnstr(kcontrol->id.name, "TX_4", + sizeof(kcontrol->id.name))) { + port->channel = TDM_4; + } else if (strnstr(kcontrol->id.name, "RX_5", + sizeof(kcontrol->id.name)) || + strnstr(kcontrol->id.name, "TX_5", + sizeof(kcontrol->id.name))) { + port->channel = TDM_5; + } else if (strnstr(kcontrol->id.name, "RX_6", + sizeof(kcontrol->id.name)) || + strnstr(kcontrol->id.name, "TX_6", + sizeof(kcontrol->id.name))) { + port->channel = TDM_6; + } else if (strnstr(kcontrol->id.name, "RX_7", + sizeof(kcontrol->id.name)) || + strnstr(kcontrol->id.name, "TX_7", + sizeof(kcontrol->id.name))) { + port->channel = TDM_7; + } else { + pr_err("%s: unsupported channel in: %s", + __func__, kcontrol->id.name); + return -EINVAL; + } + } else + return -EINVAL; + return 0; +} + +static int tdm_rx_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tdm_port port; + int ret = tdm_get_port_idx(kcontrol, &port); + + if (ret) { + pr_err("%s: unsupported control: %s", + __func__, kcontrol->id.name); + } else { + ucontrol->value.enumerated.item[0] = tdm_get_sample_rate_val( + tdm_rx_cfg[port.mode][port.channel].sample_rate); + + pr_debug("%s: tdm_rx_sample_rate = %d, item = %d\n", __func__, + tdm_rx_cfg[port.mode][port.channel].sample_rate, + ucontrol->value.enumerated.item[0]); + } + return ret; +} + +static int tdm_rx_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tdm_port port; + int ret = tdm_get_port_idx(kcontrol, &port); + + if (ret) { + pr_err("%s: unsupported control: %s", + __func__, kcontrol->id.name); + } else { + tdm_rx_cfg[port.mode][port.channel].sample_rate = + tdm_get_sample_rate(ucontrol->value.enumerated.item[0]); + + pr_debug("%s: tdm_rx_sample_rate = %d, item = %d\n", __func__, + tdm_rx_cfg[port.mode][port.channel].sample_rate, + ucontrol->value.enumerated.item[0]); + } + return ret; +} + +static int tdm_tx_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tdm_port port; + int ret = tdm_get_port_idx(kcontrol, &port); + + if (ret) { + pr_err("%s: unsupported control: %s", + __func__, kcontrol->id.name); + } else { + ucontrol->value.enumerated.item[0] = tdm_get_sample_rate_val( + tdm_tx_cfg[port.mode][port.channel].sample_rate); + + pr_debug("%s: tdm_tx_sample_rate = %d, item = %d\n", __func__, + tdm_tx_cfg[port.mode][port.channel].sample_rate, + ucontrol->value.enumerated.item[0]); + } + return ret; +} + +static int tdm_tx_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tdm_port port; + int ret = tdm_get_port_idx(kcontrol, &port); + + if (ret) { + pr_err("%s: unsupported control: %s", + __func__, kcontrol->id.name); + } else { + tdm_tx_cfg[port.mode][port.channel].sample_rate = + tdm_get_sample_rate(ucontrol->value.enumerated.item[0]); + + pr_debug("%s: tdm_tx_sample_rate = %d, item = %d\n", __func__, + tdm_tx_cfg[port.mode][port.channel].sample_rate, + ucontrol->value.enumerated.item[0]); + } + return ret; +} + +static int tdm_get_format(int value) +{ + int format = 0; + + switch (value) { + case 0: + format = SNDRV_PCM_FORMAT_S16_LE; + break; + case 1: + format = SNDRV_PCM_FORMAT_S24_LE; + break; + case 2: + format = SNDRV_PCM_FORMAT_S32_LE; + break; + default: + format = SNDRV_PCM_FORMAT_S16_LE; + break; + } + return format; +} + +static int tdm_get_format_val(int format) +{ + int value = 0; + + switch (format) { + case SNDRV_PCM_FORMAT_S16_LE: + value = 0; + break; + case SNDRV_PCM_FORMAT_S24_LE: + value = 1; + break; + case SNDRV_PCM_FORMAT_S32_LE: + value = 2; + break; + default: + value = 0; + break; + } + return value; +} + +static int tdm_rx_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tdm_port port; + int ret = tdm_get_port_idx(kcontrol, &port); + + if (ret) { + pr_err("%s: unsupported control: %s", + __func__, kcontrol->id.name); + } else { + ucontrol->value.enumerated.item[0] = tdm_get_format_val( + tdm_rx_cfg[port.mode][port.channel].bit_format); + + pr_debug("%s: tdm_rx_bit_format = %d, item = %d\n", __func__, + tdm_rx_cfg[port.mode][port.channel].bit_format, + ucontrol->value.enumerated.item[0]); + } + return ret; +} + +static int tdm_rx_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tdm_port port; + int ret = tdm_get_port_idx(kcontrol, &port); + + if (ret) { + pr_err("%s: unsupported control: %s", + __func__, kcontrol->id.name); + } else { + tdm_rx_cfg[port.mode][port.channel].bit_format = + tdm_get_format(ucontrol->value.enumerated.item[0]); + + pr_debug("%s: tdm_rx_bit_format = %d, item = %d\n", __func__, + tdm_rx_cfg[port.mode][port.channel].bit_format, + ucontrol->value.enumerated.item[0]); + } + return ret; +} + +static int tdm_tx_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tdm_port port; + int ret = tdm_get_port_idx(kcontrol, &port); + + if (ret) { + pr_err("%s: unsupported control: %s", + __func__, kcontrol->id.name); + } else { + ucontrol->value.enumerated.item[0] = tdm_get_format_val( + tdm_tx_cfg[port.mode][port.channel].bit_format); + + pr_debug("%s: tdm_tx_bit_format = %d, item = %d\n", __func__, + tdm_tx_cfg[port.mode][port.channel].bit_format, + ucontrol->value.enumerated.item[0]); + } + return ret; +} + +static int tdm_tx_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tdm_port port; + int ret = tdm_get_port_idx(kcontrol, &port); + + if (ret) { + pr_err("%s: unsupported control: %s", + __func__, kcontrol->id.name); + } else { + tdm_tx_cfg[port.mode][port.channel].bit_format = + tdm_get_format(ucontrol->value.enumerated.item[0]); + + pr_debug("%s: tdm_tx_bit_format = %d, item = %d\n", __func__, + tdm_tx_cfg[port.mode][port.channel].bit_format, + ucontrol->value.enumerated.item[0]); + } + return ret; +} + +static int tdm_rx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tdm_port port; + int ret = tdm_get_port_idx(kcontrol, &port); + + if (ret) { + pr_err("%s: unsupported control: %s", + __func__, kcontrol->id.name); + } else { + + ucontrol->value.enumerated.item[0] = + tdm_rx_cfg[port.mode][port.channel].channels - 1; + + pr_debug("%s: tdm_rx_ch = %d, item = %d\n", __func__, + tdm_rx_cfg[port.mode][port.channel].channels - 1, + ucontrol->value.enumerated.item[0]); + } + return ret; +} + +static int tdm_rx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tdm_port port; + int ret = tdm_get_port_idx(kcontrol, &port); + + if (ret) { + pr_err("%s: unsupported control: %s", + __func__, kcontrol->id.name); + } else { + tdm_rx_cfg[port.mode][port.channel].channels = + ucontrol->value.enumerated.item[0] + 1; + + pr_debug("%s: tdm_rx_ch = %d, item = %d\n", __func__, + tdm_rx_cfg[port.mode][port.channel].channels, + ucontrol->value.enumerated.item[0] + 1); + } + return ret; +} + +static int tdm_tx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tdm_port port; + int ret = tdm_get_port_idx(kcontrol, &port); + + if (ret) { + pr_err("%s: unsupported control: %s", + __func__, kcontrol->id.name); + } else { + ucontrol->value.enumerated.item[0] = + tdm_tx_cfg[port.mode][port.channel].channels - 1; + + pr_debug("%s: tdm_tx_ch = %d, item = %d\n", __func__, + tdm_tx_cfg[port.mode][port.channel].channels - 1, + ucontrol->value.enumerated.item[0]); + } + return ret; +} + +static int tdm_tx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tdm_port port; + int ret = tdm_get_port_idx(kcontrol, &port); + + if (ret) { + pr_err("%s: unsupported control: %s", + __func__, kcontrol->id.name); + } else { + tdm_tx_cfg[port.mode][port.channel].channels = + ucontrol->value.enumerated.item[0] + 1; + + pr_debug("%s: tdm_tx_ch = %d, item = %d\n", __func__, + tdm_tx_cfg[port.mode][port.channel].channels, + ucontrol->value.enumerated.item[0] + 1); + } + return ret; +} + +static int tdm_slot_map_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int interface = ucontrol->value.integer.value[0]; + int channel = ucontrol->value.integer.value[1]; + unsigned int offset_val; + unsigned int *slot_offset; + + if (interface < 0 || interface >= (TDM_INTERFACE_MAX * 2)) { + pr_err("%s: incorrect interface = %d", __func__, interface); + return -EINVAL; + } + if (channel < 0 || channel >= TDM_PORT_MAX) { + pr_err("%s: incorrect channel = %d", __func__, channel); + return -EINVAL; + } + + pr_debug("%s: interface = %d, channel = %d", __func__, + interface, channel); + + slot_offset = tdm_cfg[interface][channel].tdm_slot_offset; + + /* Currenly can configure only two slots */ + offset_val = ucontrol->value.integer.value[2]; + /* Offset value can only be 0, 4, 8, ..28 */ + if (offset_val % 4 == 0 && offset_val <= 28) + slot_offset[0] = offset_val; + pr_debug("%s: slot offset[0] = %d\n", __func__, slot_offset[0]); + + offset_val = ucontrol->value.integer.value[3]; + if (offset_val % 4 == 0 && offset_val <= 28) + slot_offset[1] = offset_val; + pr_debug("%s: slot offset[1] = %d\n", __func__, slot_offset[1]); + + return 0; +} + +static int aux_pcm_get_port_idx(struct snd_kcontrol *kcontrol) +{ + int idx; + + if (strnstr(kcontrol->id.name, "PRIM_AUX_PCM", + sizeof("PRIM_AUX_PCM"))) + idx = PRIM_AUX_PCM; + else if (strnstr(kcontrol->id.name, "SEC_AUX_PCM", + sizeof("SEC_AUX_PCM"))) + idx = SEC_AUX_PCM; + else if (strnstr(kcontrol->id.name, "TERT_AUX_PCM", + sizeof("TERT_AUX_PCM"))) + idx = TERT_AUX_PCM; + else if (strnstr(kcontrol->id.name, "QUAT_AUX_PCM", + sizeof("QUAT_AUX_PCM"))) + idx = QUAT_AUX_PCM; + else { + pr_err("%s: unsupported port: %s", + __func__, kcontrol->id.name); + idx = -EINVAL; + } + + return idx; +} + +static int aux_pcm_rx_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = aux_pcm_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + aux_pcm_rx_cfg[idx].sample_rate = + aux_pcm_get_sample_rate(ucontrol->value.enumerated.item[0]); + + pr_debug("%s: idx[%d]_rx_sample_rate = %d, item = %d\n", __func__, + idx, aux_pcm_rx_cfg[idx].sample_rate, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int aux_pcm_rx_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = aux_pcm_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + ucontrol->value.enumerated.item[0] = + aux_pcm_get_sample_rate_val(aux_pcm_rx_cfg[idx].sample_rate); + + pr_debug("%s: idx[%d]_rx_sample_rate = %d, item = %d\n", __func__, + idx, aux_pcm_rx_cfg[idx].sample_rate, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int aux_pcm_tx_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = aux_pcm_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + aux_pcm_tx_cfg[idx].sample_rate = + aux_pcm_get_sample_rate(ucontrol->value.enumerated.item[0]); + + pr_debug("%s: idx[%d]_tx_sample_rate = %d, item = %d\n", __func__, + idx, aux_pcm_tx_cfg[idx].sample_rate, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int aux_pcm_tx_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = aux_pcm_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + ucontrol->value.enumerated.item[0] = + aux_pcm_get_sample_rate_val(aux_pcm_tx_cfg[idx].sample_rate); + + pr_debug("%s: idx[%d]_tx_sample_rate = %d, item = %d\n", __func__, + idx, aux_pcm_tx_cfg[idx].sample_rate, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int mi2s_get_port_idx(struct snd_kcontrol *kcontrol) +{ + int idx; + + if (strnstr(kcontrol->id.name, "PRIM_MI2S_RX", + sizeof("PRIM_MI2S_RX"))) + idx = PRIM_MI2S; + else if (strnstr(kcontrol->id.name, "SEC_MI2S_RX", + sizeof("SEC_MI2S_RX"))) + idx = SEC_MI2S; + else if (strnstr(kcontrol->id.name, "TERT_MI2S_RX", + sizeof("TERT_MI2S_RX"))) + idx = TERT_MI2S; + else if (strnstr(kcontrol->id.name, "QUAT_MI2S_RX", + sizeof("QUAT_MI2S_RX"))) + idx = QUAT_MI2S; + else if (strnstr(kcontrol->id.name, "PRIM_MI2S_TX", + sizeof("PRIM_MI2S_TX"))) + idx = PRIM_MI2S; + else if (strnstr(kcontrol->id.name, "SEC_MI2S_TX", + sizeof("SEC_MI2S_TX"))) + idx = SEC_MI2S; + else if (strnstr(kcontrol->id.name, "TERT_MI2S_TX", + sizeof("TERT_MI2S_TX"))) + idx = TERT_MI2S; + else if (strnstr(kcontrol->id.name, "QUAT_MI2S_TX", + sizeof("QUAT_MI2S_TX"))) + idx = QUAT_MI2S; + else { + pr_err("%s: unsupported channel: %s", + __func__, kcontrol->id.name); + idx = -EINVAL; + } + + return idx; +} + +static int mi2s_get_sample_rate_val(int sample_rate) +{ + int sample_rate_val; + + switch (sample_rate) { + case SAMPLING_RATE_8KHZ: + sample_rate_val = 0; + break; + case SAMPLING_RATE_11P025KHZ: + sample_rate_val = 1; + break; + case SAMPLING_RATE_16KHZ: + sample_rate_val = 2; + break; + case SAMPLING_RATE_22P05KHZ: + sample_rate_val = 3; + break; + case SAMPLING_RATE_32KHZ: + sample_rate_val = 4; + break; + case SAMPLING_RATE_44P1KHZ: + sample_rate_val = 5; + break; + case SAMPLING_RATE_48KHZ: + sample_rate_val = 6; + break; + case SAMPLING_RATE_96KHZ: + sample_rate_val = 7; + break; + case SAMPLING_RATE_192KHZ: + sample_rate_val = 8; + break; + default: + sample_rate_val = 6; + break; + } + return sample_rate_val; +} + +static int mi2s_get_sample_rate(int value) +{ + int sample_rate; + + switch (value) { + case 0: + sample_rate = SAMPLING_RATE_8KHZ; + break; + case 1: + sample_rate = SAMPLING_RATE_11P025KHZ; + break; + case 2: + sample_rate = SAMPLING_RATE_16KHZ; + break; + case 3: + sample_rate = SAMPLING_RATE_22P05KHZ; + break; + case 4: + sample_rate = SAMPLING_RATE_32KHZ; + break; + case 5: + sample_rate = SAMPLING_RATE_44P1KHZ; + break; + case 6: + sample_rate = SAMPLING_RATE_48KHZ; + break; + case 7: + sample_rate = SAMPLING_RATE_96KHZ; + break; + case 8: + sample_rate = SAMPLING_RATE_192KHZ; + break; + default: + sample_rate = SAMPLING_RATE_48KHZ; + break; + } + return sample_rate; +} + +static int mi2s_auxpcm_get_format(int value) +{ + int format; + + switch (value) { + case 0: + format = SNDRV_PCM_FORMAT_S16_LE; + break; + case 1: + format = SNDRV_PCM_FORMAT_S24_LE; + break; + case 2: + format = SNDRV_PCM_FORMAT_S24_3LE; + break; + case 3: + format = SNDRV_PCM_FORMAT_S32_LE; + break; + default: + format = SNDRV_PCM_FORMAT_S16_LE; + break; + } + return format; +} + +static int mi2s_auxpcm_get_format_value(int format) +{ + int value; + + switch (format) { + case SNDRV_PCM_FORMAT_S16_LE: + value = 0; + break; + case SNDRV_PCM_FORMAT_S24_LE: + value = 1; + break; + case SNDRV_PCM_FORMAT_S24_3LE: + value = 2; + break; + case SNDRV_PCM_FORMAT_S32_LE: + value = 3; + break; + default: + value = 0; + break; + } + return value; +} + +static int mi2s_rx_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = mi2s_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + mi2s_rx_cfg[idx].sample_rate = + mi2s_get_sample_rate(ucontrol->value.enumerated.item[0]); + + pr_debug("%s: idx[%d]_rx_sample_rate = %d, item = %d\n", __func__, + idx, mi2s_rx_cfg[idx].sample_rate, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int mi2s_rx_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = mi2s_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + ucontrol->value.enumerated.item[0] = + mi2s_get_sample_rate_val(mi2s_rx_cfg[idx].sample_rate); + + pr_debug("%s: idx[%d]_rx_sample_rate = %d, item = %d\n", __func__, + idx, mi2s_rx_cfg[idx].sample_rate, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int mi2s_tx_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = mi2s_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + mi2s_tx_cfg[idx].sample_rate = + mi2s_get_sample_rate(ucontrol->value.enumerated.item[0]); + + pr_debug("%s: idx[%d]_tx_sample_rate = %d, item = %d\n", __func__, + idx, mi2s_tx_cfg[idx].sample_rate, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int mi2s_tx_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = mi2s_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + ucontrol->value.enumerated.item[0] = + mi2s_get_sample_rate_val(mi2s_tx_cfg[idx].sample_rate); + + pr_debug("%s: idx[%d]_tx_sample_rate = %d, item = %d\n", __func__, + idx, mi2s_tx_cfg[idx].sample_rate, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int msm_mi2s_rx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = mi2s_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + pr_debug("%s: msm_mi2s_[%d]_rx_ch = %d\n", __func__, + idx, mi2s_rx_cfg[idx].channels); + ucontrol->value.enumerated.item[0] = mi2s_rx_cfg[idx].channels - 1; + + return 0; +} + +static int msm_mi2s_rx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = mi2s_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + mi2s_rx_cfg[idx].channels = ucontrol->value.enumerated.item[0] + 1; + pr_debug("%s: msm_mi2s_[%d]_rx_ch = %d\n", __func__, + idx, mi2s_rx_cfg[idx].channels); + + return 1; +} + +static int msm_mi2s_tx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = mi2s_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + pr_debug("%s: msm_mi2s_[%d]_tx_ch = %d\n", __func__, + idx, mi2s_tx_cfg[idx].channels); + ucontrol->value.enumerated.item[0] = mi2s_tx_cfg[idx].channels - 1; + + return 0; +} + +static int msm_mi2s_tx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = mi2s_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + mi2s_tx_cfg[idx].channels = ucontrol->value.enumerated.item[0] + 1; + pr_debug("%s: msm_mi2s_[%d]_tx_ch = %d\n", __func__, + idx, mi2s_tx_cfg[idx].channels); + + return 1; +} + +static int msm_mi2s_rx_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = mi2s_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + ucontrol->value.enumerated.item[0] = + mi2s_auxpcm_get_format_value(mi2s_rx_cfg[idx].bit_format); + + pr_debug("%s: idx[%d]_rx_format = %d, item = %d\n", __func__, + idx, mi2s_rx_cfg[idx].bit_format, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int msm_mi2s_rx_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = mi2s_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + mi2s_rx_cfg[idx].bit_format = + mi2s_auxpcm_get_format(ucontrol->value.enumerated.item[0]); + + pr_debug("%s: idx[%d]_rx_format = %d, item = %d\n", __func__, + idx, mi2s_rx_cfg[idx].bit_format, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int msm_mi2s_tx_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = mi2s_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + ucontrol->value.enumerated.item[0] = + mi2s_auxpcm_get_format_value(mi2s_tx_cfg[idx].bit_format); + + pr_debug("%s: idx[%d]_tx_format = %d, item = %d\n", __func__, + idx, mi2s_tx_cfg[idx].bit_format, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int msm_mi2s_tx_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = mi2s_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + mi2s_tx_cfg[idx].bit_format = + mi2s_auxpcm_get_format(ucontrol->value.enumerated.item[0]); + + pr_debug("%s: idx[%d]_tx_format = %d, item = %d\n", __func__, + idx, mi2s_tx_cfg[idx].bit_format, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int msm_aux_pcm_rx_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = aux_pcm_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + ucontrol->value.enumerated.item[0] = + mi2s_auxpcm_get_format_value(aux_pcm_rx_cfg[idx].bit_format); + + pr_debug("%s: idx[%d]_rx_format = %d, item = %d\n", __func__, + idx, aux_pcm_rx_cfg[idx].bit_format, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int msm_aux_pcm_rx_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = aux_pcm_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + aux_pcm_rx_cfg[idx].bit_format = + mi2s_auxpcm_get_format(ucontrol->value.enumerated.item[0]); + + pr_debug("%s: idx[%d]_rx_format = %d, item = %d\n", __func__, + idx, aux_pcm_rx_cfg[idx].bit_format, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int msm_aux_pcm_tx_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = aux_pcm_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + ucontrol->value.enumerated.item[0] = + mi2s_auxpcm_get_format_value(aux_pcm_tx_cfg[idx].bit_format); + + pr_debug("%s: idx[%d]_tx_format = %d, item = %d\n", __func__, + idx, aux_pcm_tx_cfg[idx].bit_format, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int msm_aux_pcm_tx_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = aux_pcm_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + aux_pcm_tx_cfg[idx].bit_format = + mi2s_auxpcm_get_format(ucontrol->value.enumerated.item[0]); + + pr_debug("%s: idx[%d]_tx_format = %d, item = %d\n", __func__, + idx, aux_pcm_tx_cfg[idx].bit_format, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int msm_hifi_ctrl(struct snd_soc_component *component) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + struct snd_soc_card *card = component->card; + struct msm_asoc_mach_data *pdata = + snd_soc_card_get_drvdata(card); + + pr_debug("%s: msm_hifi_control = %d", __func__, + msm_hifi_control); + + if (!pdata || !pdata->hph_en1_gpio_p) { + pr_err("%s: hph_en1_gpio is invalid\n", __func__); + return -EINVAL; + } + if (msm_hifi_control == MSM_HIFI_ON) { + msm_cdc_pinctrl_select_active_state(pdata->hph_en1_gpio_p); + /* 5msec delay needed as per HW requirement */ + usleep_range(5000, 5010); + } else { + msm_cdc_pinctrl_select_sleep_state(pdata->hph_en1_gpio_p); + } + snd_soc_dapm_sync(dapm); + + return 0; +} + +static int msm_hifi_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: msm_hifi_control = %d\n", + __func__, msm_hifi_control); + ucontrol->value.integer.value[0] = msm_hifi_control; + + return 0; +} + +static int msm_hifi_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + + pr_debug("%s() ucontrol->value.integer.value[0] = %ld\n", + __func__, ucontrol->value.integer.value[0]); + + msm_hifi_control = ucontrol->value.integer.value[0]; + msm_hifi_ctrl(component); + + return 0; +} + +static int msm_qos_ctl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.enumerated.item[0] = qos_vote_status; + + return 0; +} + +static int msm_qos_ctl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct snd_soc_card *card = component->card; + const char *be_name = MSM_DAILINK_NAME(LowLatency); + struct snd_soc_pcm_runtime *rtd; + struct snd_pcm_substream *substream; + s32 usecs; + + rtd = snd_soc_get_pcm_runtime(card, be_name); + if (!rtd) { + pr_err("%s: fail to get pcm runtime for %s\n", + __func__, be_name); + return -EINVAL; + } + + substream = rtd->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; + if (!substream) { + pr_err("%s: substream is null\n", __func__); + return -EINVAL; + } + + qos_vote_status = ucontrol->value.enumerated.item[0]; + if (qos_vote_status) { + if (pm_qos_request_active(&substream->latency_pm_qos_req)) + pm_qos_remove_request(&substream->latency_pm_qos_req); + if (!substream->runtime) { + pr_err("%s: runtime is null\n", __func__); + return -EINVAL; + } + usecs = MSM_LL_QOS_VALUE; + if (usecs >= 0) + pm_qos_add_request(&substream->latency_pm_qos_req, + PM_QOS_CPU_DMA_LATENCY, usecs); + } else { + if (pm_qos_request_active(&substream->latency_pm_qos_req)) + pm_qos_remove_request(&substream->latency_pm_qos_req); + } + + return 0; +} + +static const struct snd_kcontrol_new msm_snd_controls[] = { + SOC_ENUM_EXT("SLIM_0_RX Channels", slim_0_rx_chs, + msm_slim_rx_ch_get, msm_slim_rx_ch_put), + SOC_ENUM_EXT("SLIM_2_RX Channels", slim_2_rx_chs, + msm_slim_rx_ch_get, msm_slim_rx_ch_put), + SOC_ENUM_EXT("SLIM_0_TX Channels", slim_0_tx_chs, + msm_slim_tx_ch_get, msm_slim_tx_ch_put), + SOC_ENUM_EXT("SLIM_1_TX Channels", slim_1_tx_chs, + msm_slim_tx_ch_get, msm_slim_tx_ch_put), + SOC_ENUM_EXT("SLIM_5_RX Channels", slim_5_rx_chs, + msm_slim_rx_ch_get, msm_slim_rx_ch_put), + SOC_ENUM_EXT("SLIM_6_RX Channels", slim_6_rx_chs, + msm_slim_rx_ch_get, msm_slim_rx_ch_put), + SOC_ENUM_EXT("VI_FEED_TX Channels", vi_feed_tx_chs, + msm_vi_feed_tx_ch_get, msm_vi_feed_tx_ch_put), + SOC_ENUM_EXT("USB_AUDIO_RX Channels", usb_rx_chs, + usb_audio_rx_ch_get, usb_audio_rx_ch_put), + SOC_ENUM_EXT("USB_AUDIO_TX Channels", usb_tx_chs, + usb_audio_tx_ch_get, usb_audio_tx_ch_put), + SOC_ENUM_EXT("Display Port RX Channels", ext_disp_rx_chs, + ext_disp_rx_ch_get, ext_disp_rx_ch_put), + SOC_ENUM_EXT("PROXY_RX Channels", proxy_rx_chs, + proxy_rx_ch_get, proxy_rx_ch_put), + SOC_ENUM_EXT("SLIM_0_RX Format", slim_0_rx_format, + slim_rx_bit_format_get, slim_rx_bit_format_put), + SOC_ENUM_EXT("SLIM_5_RX Format", slim_5_rx_format, + slim_rx_bit_format_get, slim_rx_bit_format_put), + SOC_ENUM_EXT("SLIM_6_RX Format", slim_6_rx_format, + slim_rx_bit_format_get, slim_rx_bit_format_put), + SOC_ENUM_EXT("SLIM_0_TX Format", slim_0_tx_format, + slim_tx_bit_format_get, slim_tx_bit_format_put), + SOC_ENUM_EXT("USB_AUDIO_RX Format", usb_rx_format, + usb_audio_rx_format_get, usb_audio_rx_format_put), + SOC_ENUM_EXT("USB_AUDIO_TX Format", usb_tx_format, + usb_audio_tx_format_get, usb_audio_tx_format_put), + SOC_ENUM_EXT("Display Port RX Bit Format", ext_disp_rx_format, + ext_disp_rx_format_get, ext_disp_rx_format_put), + SOC_ENUM_EXT("SLIM_0_RX SampleRate", slim_0_rx_sample_rate, + slim_rx_sample_rate_get, slim_rx_sample_rate_put), + SOC_ENUM_EXT("SLIM_2_RX SampleRate", slim_2_rx_sample_rate, + slim_rx_sample_rate_get, slim_rx_sample_rate_put), + SOC_ENUM_EXT("SLIM_0_TX SampleRate", slim_0_tx_sample_rate, + slim_tx_sample_rate_get, slim_tx_sample_rate_put), + SOC_ENUM_EXT("SLIM_5_RX SampleRate", slim_5_rx_sample_rate, + slim_rx_sample_rate_get, slim_rx_sample_rate_put), + SOC_ENUM_EXT("SLIM_6_RX SampleRate", slim_6_rx_sample_rate, + slim_rx_sample_rate_get, slim_rx_sample_rate_put), + SOC_ENUM_EXT("BT SampleRate", bt_sample_rate, + msm_bt_sample_rate_get, + msm_bt_sample_rate_put), + SOC_ENUM_EXT("BT SampleRate RX", bt_sample_rate_rx, + msm_bt_sample_rate_rx_get, + msm_bt_sample_rate_rx_put), + SOC_ENUM_EXT("BT SampleRate TX", bt_sample_rate_tx, + msm_bt_sample_rate_tx_get, + msm_bt_sample_rate_tx_put), + SOC_ENUM_EXT("USB_AUDIO_RX SampleRate", usb_rx_sample_rate, + usb_audio_rx_sample_rate_get, + usb_audio_rx_sample_rate_put), + SOC_ENUM_EXT("USB_AUDIO_TX SampleRate", usb_tx_sample_rate, + usb_audio_tx_sample_rate_get, + usb_audio_tx_sample_rate_put), + SOC_ENUM_EXT("Display Port RX SampleRate", ext_disp_rx_sample_rate, + ext_disp_rx_sample_rate_get, + ext_disp_rx_sample_rate_put), + SOC_ENUM_EXT("PRI_TDM_RX_0 SampleRate", tdm_rx_sample_rate, + tdm_rx_sample_rate_get, + tdm_rx_sample_rate_put), + SOC_ENUM_EXT("PRI_TDM_TX_0 SampleRate", tdm_tx_sample_rate, + tdm_tx_sample_rate_get, + tdm_tx_sample_rate_put), + SOC_ENUM_EXT("PRI_TDM_RX_0 Format", tdm_rx_format, + tdm_rx_format_get, + tdm_rx_format_put), + SOC_ENUM_EXT("PRI_TDM_TX_0 Format", tdm_tx_format, + tdm_tx_format_get, + tdm_tx_format_put), + SOC_ENUM_EXT("PRI_TDM_RX_0 Channels", tdm_rx_chs, + tdm_rx_ch_get, + tdm_rx_ch_put), + SOC_ENUM_EXT("PRI_TDM_TX_0 Channels", tdm_tx_chs, + tdm_tx_ch_get, + tdm_tx_ch_put), + SOC_ENUM_EXT("SEC_TDM_RX_0 SampleRate", tdm_rx_sample_rate, + tdm_rx_sample_rate_get, + tdm_rx_sample_rate_put), + SOC_ENUM_EXT("SEC_TDM_TX_0 SampleRate", tdm_tx_sample_rate, + tdm_tx_sample_rate_get, + tdm_tx_sample_rate_put), + SOC_ENUM_EXT("SEC_TDM_RX_0 Format", tdm_rx_format, + tdm_rx_format_get, + tdm_rx_format_put), + SOC_ENUM_EXT("SEC_TDM_TX_0 Format", tdm_tx_format, + tdm_tx_format_get, + tdm_tx_format_put), + SOC_ENUM_EXT("SEC_TDM_RX_0 Channels", tdm_rx_chs, + tdm_rx_ch_get, + tdm_rx_ch_put), + SOC_ENUM_EXT("SEC_TDM_TX_0 Channels", tdm_tx_chs, + tdm_tx_ch_get, + tdm_tx_ch_put), + SOC_ENUM_EXT("TERT_TDM_RX_0 SampleRate", tdm_rx_sample_rate, + tdm_rx_sample_rate_get, + tdm_rx_sample_rate_put), + SOC_ENUM_EXT("TERT_TDM_TX_0 SampleRate", tdm_tx_sample_rate, + tdm_tx_sample_rate_get, + tdm_tx_sample_rate_put), + SOC_ENUM_EXT("TERT_TDM_RX_0 Format", tdm_rx_format, + tdm_rx_format_get, + tdm_rx_format_put), + SOC_ENUM_EXT("TERT_TDM_TX_0 Format", tdm_tx_format, + tdm_tx_format_get, + tdm_tx_format_put), + SOC_ENUM_EXT("TERT_TDM_RX_0 Channels", tdm_rx_chs, + tdm_rx_ch_get, + tdm_rx_ch_put), + SOC_ENUM_EXT("TERT_TDM_TX_0 Channels", tdm_tx_chs, + tdm_tx_ch_get, + tdm_tx_ch_put), + SOC_ENUM_EXT("QUAT_TDM_RX_0 SampleRate", tdm_rx_sample_rate, + tdm_rx_sample_rate_get, + tdm_rx_sample_rate_put), + SOC_ENUM_EXT("QUAT_TDM_RX_1 SampleRate", tdm_rx_sample_rate, + tdm_rx_sample_rate_get, + tdm_rx_sample_rate_put), + SOC_ENUM_EXT("QUAT_TDM_TX_0 SampleRate", tdm_tx_sample_rate, + tdm_tx_sample_rate_get, + tdm_tx_sample_rate_put), + SOC_ENUM_EXT("QUAT_TDM_RX_0 Format", tdm_rx_format, + tdm_rx_format_get, + tdm_rx_format_put), + SOC_ENUM_EXT("QUAT_TDM_RX_1 Format", tdm_rx_format, + tdm_rx_format_get, + tdm_rx_format_put), + SOC_ENUM_EXT("QUAT_TDM_TX_0 Format", tdm_tx_format, + tdm_tx_format_get, + tdm_tx_format_put), + SOC_ENUM_EXT("QUAT_TDM_RX_0 Channels", tdm_rx_chs, + tdm_rx_ch_get, + tdm_rx_ch_put), + SOC_ENUM_EXT("QUAT_TDM_RX_1 Channels", tdm_rx_chs, + tdm_rx_ch_get, + tdm_rx_ch_put), + SOC_ENUM_EXT("QUAT_TDM_TX_0 Channels", tdm_tx_chs, + tdm_tx_ch_get, + tdm_tx_ch_put), + SOC_ENUM_EXT("PRIM_AUX_PCM_RX SampleRate", prim_aux_pcm_rx_sample_rate, + aux_pcm_rx_sample_rate_get, + aux_pcm_rx_sample_rate_put), + SOC_ENUM_EXT("SEC_AUX_PCM_RX SampleRate", sec_aux_pcm_rx_sample_rate, + aux_pcm_rx_sample_rate_get, + aux_pcm_rx_sample_rate_put), + SOC_ENUM_EXT("TERT_AUX_PCM_RX SampleRate", tert_aux_pcm_rx_sample_rate, + aux_pcm_rx_sample_rate_get, + aux_pcm_rx_sample_rate_put), + SOC_ENUM_EXT("QUAT_AUX_PCM_RX SampleRate", quat_aux_pcm_rx_sample_rate, + aux_pcm_rx_sample_rate_get, + aux_pcm_rx_sample_rate_put), + SOC_ENUM_EXT("PRIM_AUX_PCM_TX SampleRate", prim_aux_pcm_tx_sample_rate, + aux_pcm_tx_sample_rate_get, + aux_pcm_tx_sample_rate_put), + SOC_ENUM_EXT("SEC_AUX_PCM_TX SampleRate", sec_aux_pcm_tx_sample_rate, + aux_pcm_tx_sample_rate_get, + aux_pcm_tx_sample_rate_put), + SOC_ENUM_EXT("TERT_AUX_PCM_TX SampleRate", tert_aux_pcm_tx_sample_rate, + aux_pcm_tx_sample_rate_get, + aux_pcm_tx_sample_rate_put), + SOC_ENUM_EXT("QUAT_AUX_PCM_TX SampleRate", quat_aux_pcm_tx_sample_rate, + aux_pcm_tx_sample_rate_get, + aux_pcm_tx_sample_rate_put), + SOC_ENUM_EXT("PRIM_MI2S_RX SampleRate", prim_mi2s_rx_sample_rate, + mi2s_rx_sample_rate_get, + mi2s_rx_sample_rate_put), + SOC_ENUM_EXT("SEC_MI2S_RX SampleRate", sec_mi2s_rx_sample_rate, + mi2s_rx_sample_rate_get, + mi2s_rx_sample_rate_put), + SOC_ENUM_EXT("TERT_MI2S_RX SampleRate", tert_mi2s_rx_sample_rate, + mi2s_rx_sample_rate_get, + mi2s_rx_sample_rate_put), + SOC_ENUM_EXT("QUAT_MI2S_RX SampleRate", quat_mi2s_rx_sample_rate, + mi2s_rx_sample_rate_get, + mi2s_rx_sample_rate_put), + SOC_ENUM_EXT("PRIM_MI2S_TX SampleRate", prim_mi2s_tx_sample_rate, + mi2s_tx_sample_rate_get, + mi2s_tx_sample_rate_put), + SOC_ENUM_EXT("SEC_MI2S_TX SampleRate", sec_mi2s_tx_sample_rate, + mi2s_tx_sample_rate_get, + mi2s_tx_sample_rate_put), + SOC_ENUM_EXT("TERT_MI2S_TX SampleRate", tert_mi2s_tx_sample_rate, + mi2s_tx_sample_rate_get, + mi2s_tx_sample_rate_put), + SOC_ENUM_EXT("QUAT_MI2S_TX SampleRate", quat_mi2s_tx_sample_rate, + mi2s_tx_sample_rate_get, + mi2s_tx_sample_rate_put), + SOC_ENUM_EXT("PRIM_MI2S_RX Channels", prim_mi2s_rx_chs, + msm_mi2s_rx_ch_get, msm_mi2s_rx_ch_put), + SOC_ENUM_EXT("PRIM_MI2S_TX Channels", prim_mi2s_tx_chs, + msm_mi2s_tx_ch_get, msm_mi2s_tx_ch_put), + SOC_ENUM_EXT("SEC_MI2S_RX Channels", sec_mi2s_rx_chs, + msm_mi2s_rx_ch_get, msm_mi2s_rx_ch_put), + SOC_ENUM_EXT("SEC_MI2S_TX Channels", sec_mi2s_tx_chs, + msm_mi2s_tx_ch_get, msm_mi2s_tx_ch_put), + SOC_ENUM_EXT("TERT_MI2S_RX Channels", tert_mi2s_rx_chs, + msm_mi2s_rx_ch_get, msm_mi2s_rx_ch_put), + SOC_ENUM_EXT("TERT_MI2S_TX Channels", tert_mi2s_tx_chs, + msm_mi2s_tx_ch_get, msm_mi2s_tx_ch_put), + SOC_ENUM_EXT("QUAT_MI2S_RX Channels", quat_mi2s_rx_chs, + msm_mi2s_rx_ch_get, msm_mi2s_rx_ch_put), + SOC_ENUM_EXT("QUAT_MI2S_TX Channels", quat_mi2s_tx_chs, + msm_mi2s_tx_ch_get, msm_mi2s_tx_ch_put), + SOC_ENUM_EXT("PRIM_MI2S_RX Format", mi2s_rx_format, + msm_mi2s_rx_format_get, msm_mi2s_rx_format_put), + SOC_ENUM_EXT("PRIM_MI2S_TX Format", mi2s_tx_format, + msm_mi2s_tx_format_get, msm_mi2s_tx_format_put), + SOC_ENUM_EXT("SEC_MI2S_RX Format", mi2s_rx_format, + msm_mi2s_rx_format_get, msm_mi2s_rx_format_put), + SOC_ENUM_EXT("SEC_MI2S_TX Format", mi2s_tx_format, + msm_mi2s_tx_format_get, msm_mi2s_tx_format_put), + SOC_ENUM_EXT("TERT_MI2S_RX Format", mi2s_rx_format, + msm_mi2s_rx_format_get, msm_mi2s_rx_format_put), + SOC_ENUM_EXT("TERT_MI2S_TX Format", mi2s_tx_format, + msm_mi2s_tx_format_get, msm_mi2s_tx_format_put), + SOC_ENUM_EXT("QUAT_MI2S_RX Format", mi2s_rx_format, + msm_mi2s_rx_format_get, msm_mi2s_rx_format_put), + SOC_ENUM_EXT("QUAT_MI2S_TX Format", mi2s_tx_format, + msm_mi2s_tx_format_get, msm_mi2s_tx_format_put), + SOC_ENUM_EXT("PRIM_AUX_PCM_RX Format", aux_pcm_rx_format, + msm_aux_pcm_rx_format_get, msm_aux_pcm_rx_format_put), + SOC_ENUM_EXT("PRIM_AUX_PCM_TX Format", aux_pcm_tx_format, + msm_aux_pcm_tx_format_get, msm_aux_pcm_tx_format_put), + SOC_ENUM_EXT("SEC_AUX_PCM_RX Format", aux_pcm_rx_format, + msm_aux_pcm_rx_format_get, msm_aux_pcm_rx_format_put), + SOC_ENUM_EXT("SEC_AUX_PCM_TX Format", aux_pcm_tx_format, + msm_aux_pcm_tx_format_get, msm_aux_pcm_tx_format_put), + SOC_ENUM_EXT("TERT_AUX_PCM_RX Format", aux_pcm_rx_format, + msm_aux_pcm_rx_format_get, msm_aux_pcm_rx_format_put), + SOC_ENUM_EXT("TERT_AUX_PCM_TX Format", aux_pcm_tx_format, + msm_aux_pcm_tx_format_get, msm_aux_pcm_tx_format_put), + SOC_ENUM_EXT("QUAT_AUX_PCM_RX Format", aux_pcm_rx_format, + msm_aux_pcm_rx_format_get, msm_aux_pcm_rx_format_put), + SOC_ENUM_EXT("QUAT_AUX_PCM_TX Format", aux_pcm_tx_format, + msm_aux_pcm_tx_format_get, msm_aux_pcm_tx_format_put), + SOC_ENUM_EXT("HiFi Function", hifi_function, msm_hifi_get, + msm_hifi_put), + SOC_ENUM_EXT("MultiMedia5_RX QOS Vote", qos_vote, msm_qos_ctl_get, + msm_qos_ctl_put), + SOC_SINGLE_MULTI_EXT("TDM Slot Map", SND_SOC_NOPM, 0, 255, 0, 4, + NULL, tdm_slot_map_put), +}; + +static int msm_snd_enable_codec_ext_clk(struct snd_soc_component *component, + int enable, bool dapm) +{ + int ret = 0; + + if (!strcmp(component->name, "tavil_codec")) { + ret = tavil_cdc_mclk_enable(component, enable); + } else { + dev_err(component->dev, "%s: unknown codec to enable ext clk\n", + __func__); + ret = -EINVAL; + } + return ret; +} + +static int msm_snd_enable_codec_ext_tx_clk(struct snd_soc_component *component, + int enable, bool dapm) +{ + int ret = 0; + + if (!strcmp(component->name, "tavil_codec")) { + ret = tavil_cdc_mclk_tx_enable(component, enable); + } else { + dev_err(component->dev, "%s: unknown codec to enable TX ext clk\n", + __func__); + ret = -EINVAL; + } + + return ret; +} + +static int msm_mclk_tx_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + + pr_debug("%s: event = %d\n", __func__, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + return msm_snd_enable_codec_ext_tx_clk(component, 1, true); + case SND_SOC_DAPM_POST_PMD: + return msm_snd_enable_codec_ext_tx_clk(component, 0, true); + } + return 0; +} + +static int msm_mclk_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + + pr_debug("%s: event = %d\n", __func__, event); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + return msm_snd_enable_codec_ext_clk(component, 1, true); + case SND_SOC_DAPM_POST_PMD: + return msm_snd_enable_codec_ext_clk(component, 0, true); + } + return 0; +} + +static int msm_hifi_ctrl_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_soc_component *component = + snd_soc_dapm_to_component(w->dapm); + struct snd_soc_card *card = component->card; + struct msm_asoc_mach_data *pdata = + snd_soc_card_get_drvdata(card); + + pr_debug("%s: msm_hifi_control = %d", __func__, msm_hifi_control); + + if (!pdata || !pdata->hph_en0_gpio_p) { + pr_err("%s: hph_en0_gpio is invalid\n", __func__); + return -EINVAL; + } + + if (msm_hifi_control != MSM_HIFI_ON) { + pr_debug("%s: HiFi mixer control is not set\n", + __func__); + return 0; + } + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + msm_cdc_pinctrl_select_active_state(pdata->hph_en0_gpio_p); + break; + case SND_SOC_DAPM_PRE_PMD: + msm_cdc_pinctrl_select_sleep_state(pdata->hph_en0_gpio_p); + break; + } + + return 0; +} + +static const struct snd_soc_dapm_widget msm_dapm_widgets[] = { + + SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0, + msm_mclk_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY("MCLK TX", SND_SOC_NOPM, 0, 0, + msm_mclk_tx_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SPK("Lineout_1 amp", NULL), + SND_SOC_DAPM_SPK("Lineout_2 amp", NULL), + SND_SOC_DAPM_SPK("hifi amp", msm_hifi_ctrl_event), + SND_SOC_DAPM_MIC("Handset Mic", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_MIC("ANCRight Headset Mic", NULL), + SND_SOC_DAPM_MIC("ANCLeft Headset Mic", NULL), + SND_SOC_DAPM_MIC("Analog Mic5", NULL), + + SND_SOC_DAPM_MIC("Digital Mic0", NULL), + SND_SOC_DAPM_MIC("Digital Mic1", NULL), + SND_SOC_DAPM_MIC("Digital Mic2", NULL), + SND_SOC_DAPM_MIC("Digital Mic3", NULL), + SND_SOC_DAPM_MIC("Digital Mic4", NULL), + SND_SOC_DAPM_MIC("Digital Mic5", NULL), +}; + +static inline int param_is_mask(int p) +{ + return (p >= SNDRV_PCM_HW_PARAM_FIRST_MASK) && + (p <= SNDRV_PCM_HW_PARAM_LAST_MASK); +} + +static inline struct snd_mask *param_to_mask(struct snd_pcm_hw_params *p, + int n) +{ + return &(p->masks[n - SNDRV_PCM_HW_PARAM_FIRST_MASK]); +} + +static void param_set_mask(struct snd_pcm_hw_params *p, int n, + unsigned int bit) +{ + if (bit >= SNDRV_MASK_MAX) + return; + if (param_is_mask(n)) { + struct snd_mask *m = param_to_mask(p, n); + + m->bits[0] = 0; + m->bits[1] = 0; + m->bits[bit >> 5] |= (1 << (bit & 31)); + } +} + +static int msm_slim_get_ch_from_beid(int32_t be_id) +{ + int ch_id = 0; + + switch (be_id) { + case MSM_BACKEND_DAI_SLIMBUS_0_RX: + ch_id = SLIM_RX_0; + break; + case MSM_BACKEND_DAI_SLIMBUS_1_RX: + ch_id = SLIM_RX_1; + break; + case MSM_BACKEND_DAI_SLIMBUS_2_RX: + ch_id = SLIM_RX_2; + break; + case MSM_BACKEND_DAI_SLIMBUS_3_RX: + ch_id = SLIM_RX_3; + break; + case MSM_BACKEND_DAI_SLIMBUS_4_RX: + ch_id = SLIM_RX_4; + break; + case MSM_BACKEND_DAI_SLIMBUS_6_RX: + ch_id = SLIM_RX_6; + break; + case MSM_BACKEND_DAI_SLIMBUS_0_TX: + ch_id = SLIM_TX_0; + break; + case MSM_BACKEND_DAI_SLIMBUS_3_TX: + ch_id = SLIM_TX_3; + break; + default: + ch_id = SLIM_RX_0; + break; + } + + return ch_id; +} + +static int msm_ext_disp_get_idx_from_beid(int32_t be_id) +{ + int idx; + + switch (be_id) { + case MSM_BACKEND_DAI_DISPLAY_PORT_RX: + idx = DP_RX_IDX; + break; + default: + pr_err("%s: Incorrect ext_disp BE id %d\n", __func__, be_id); + idx = -EINVAL; + break; + } + + return idx; +} + +static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_dai_link *dai_link = rtd->dai_link; + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + int rc = 0; + int idx; + void *config = NULL; + struct snd_soc_component *component = NULL; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + + pr_debug("%s: dai_id= %d, format = %d, rate = %d\n", + __func__, dai_link->id, params_format(params), + params_rate(params)); + + switch (dai_link->id) { + case MSM_BACKEND_DAI_SLIMBUS_0_RX: + case MSM_BACKEND_DAI_SLIMBUS_1_RX: + case MSM_BACKEND_DAI_SLIMBUS_2_RX: + case MSM_BACKEND_DAI_SLIMBUS_3_RX: + case MSM_BACKEND_DAI_SLIMBUS_4_RX: + case MSM_BACKEND_DAI_SLIMBUS_6_RX: + idx = msm_slim_get_ch_from_beid(dai_link->id); + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + slim_rx_cfg[idx].bit_format); + rate->min = rate->max = slim_rx_cfg[idx].sample_rate; + channels->min = channels->max = slim_rx_cfg[idx].channels; + break; + + case MSM_BACKEND_DAI_SLIMBUS_0_TX: + case MSM_BACKEND_DAI_SLIMBUS_3_TX: + idx = msm_slim_get_ch_from_beid(dai_link->id); + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + slim_tx_cfg[idx].bit_format); + rate->min = rate->max = slim_tx_cfg[idx].sample_rate; + channels->min = channels->max = slim_tx_cfg[idx].channels; + break; + + case MSM_BACKEND_DAI_SLIMBUS_1_TX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + slim_tx_cfg[1].bit_format); + rate->min = rate->max = slim_tx_cfg[1].sample_rate; + channels->min = channels->max = slim_tx_cfg[1].channels; + break; + + case MSM_BACKEND_DAI_SLIMBUS_4_TX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + SNDRV_PCM_FORMAT_S32_LE); + rate->min = rate->max = SAMPLING_RATE_8KHZ; + channels->min = channels->max = msm_vi_feed_tx_ch; + break; + + case MSM_BACKEND_DAI_SLIMBUS_5_RX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + slim_rx_cfg[5].bit_format); + rate->min = rate->max = slim_rx_cfg[5].sample_rate; + channels->min = channels->max = slim_rx_cfg[5].channels; + break; + + case MSM_BACKEND_DAI_SLIMBUS_5_TX: + if (!strcmp(dev_name(codec_dai->dev), "tavil_codec")) + component = snd_soc_rtdcom_lookup(rtd, "tavil_codec"); + + rate->min = rate->max = SAMPLING_RATE_16KHZ; + channels->min = channels->max = 1; + + config = msm_codec_fn.get_afe_config_fn(component, + AFE_SLIMBUS_SLAVE_PORT_CONFIG); + if (config) { + rc = afe_set_config(AFE_SLIMBUS_SLAVE_PORT_CONFIG, + config, SLIMBUS_5_TX); + if (rc) + pr_err("%s: Failed to set slimbus slave port config %d\n", + __func__, rc); + } + break; + + case MSM_BACKEND_DAI_SLIMBUS_7_RX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + slim_rx_cfg[SLIM_RX_7].bit_format); + rate->min = rate->max = slim_rx_cfg[SLIM_RX_7].sample_rate; + channels->min = channels->max = + slim_rx_cfg[SLIM_RX_7].channels; + break; + + case MSM_BACKEND_DAI_SLIMBUS_7_TX: + rate->min = rate->max = slim_tx_cfg[SLIM_TX_7].sample_rate; + channels->min = channels->max = + slim_tx_cfg[SLIM_TX_7].channels; + break; + + case MSM_BACKEND_DAI_SLIMBUS_8_TX: + rate->min = rate->max = slim_tx_cfg[SLIM_TX_8].sample_rate; + channels->min = channels->max = + slim_tx_cfg[SLIM_TX_8].channels; + break; + + case MSM_BACKEND_DAI_USB_RX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + usb_rx_cfg.bit_format); + rate->min = rate->max = usb_rx_cfg.sample_rate; + channels->min = channels->max = usb_rx_cfg.channels; + break; + + case MSM_BACKEND_DAI_USB_TX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + usb_tx_cfg.bit_format); + rate->min = rate->max = usb_tx_cfg.sample_rate; + channels->min = channels->max = usb_tx_cfg.channels; + break; + + case MSM_BACKEND_DAI_DISPLAY_PORT_RX: + idx = msm_ext_disp_get_idx_from_beid(dai_link->id); + if (idx < 0) { + pr_err("%s: Incorrect ext disp idx %d\n", + __func__, idx); + rc = idx; + goto done; + } + + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + ext_disp_rx_cfg[idx].bit_format); + rate->min = rate->max = ext_disp_rx_cfg[idx].sample_rate; + channels->min = channels->max = ext_disp_rx_cfg[idx].channels; + break; + + case MSM_BACKEND_DAI_AFE_PCM_RX: + channels->min = channels->max = proxy_rx_cfg.channels; + rate->min = rate->max = SAMPLING_RATE_48KHZ; + break; + + case MSM_BACKEND_DAI_PRI_TDM_RX_0: + channels->min = channels->max = + tdm_rx_cfg[TDM_PRI][TDM_0].channels; + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + tdm_rx_cfg[TDM_PRI][TDM_0].bit_format); + rate->min = rate->max = tdm_rx_cfg[TDM_PRI][TDM_0].sample_rate; + break; + + case MSM_BACKEND_DAI_PRI_TDM_TX_0: + channels->min = channels->max = + tdm_tx_cfg[TDM_PRI][TDM_0].channels; + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + tdm_tx_cfg[TDM_PRI][TDM_0].bit_format); + rate->min = rate->max = tdm_tx_cfg[TDM_PRI][TDM_0].sample_rate; + break; + + case MSM_BACKEND_DAI_SEC_TDM_RX_0: + channels->min = channels->max = + tdm_rx_cfg[TDM_SEC][TDM_0].channels; + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + tdm_rx_cfg[TDM_SEC][TDM_0].bit_format); + rate->min = rate->max = tdm_rx_cfg[TDM_SEC][TDM_0].sample_rate; + break; + + case MSM_BACKEND_DAI_SEC_TDM_TX_0: + channels->min = channels->max = + tdm_tx_cfg[TDM_SEC][TDM_0].channels; + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + tdm_tx_cfg[TDM_SEC][TDM_0].bit_format); + rate->min = rate->max = tdm_tx_cfg[TDM_SEC][TDM_0].sample_rate; + break; + + case MSM_BACKEND_DAI_TERT_TDM_RX_0: + channels->min = channels->max = + tdm_rx_cfg[TDM_TERT][TDM_0].channels; + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + tdm_rx_cfg[TDM_TERT][TDM_0].bit_format); + rate->min = rate->max = tdm_rx_cfg[TDM_TERT][TDM_0].sample_rate; + break; + + case MSM_BACKEND_DAI_TERT_TDM_TX_0: + channels->min = channels->max = + tdm_tx_cfg[TDM_TERT][TDM_0].channels; + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + tdm_tx_cfg[TDM_TERT][TDM_0].bit_format); + rate->min = rate->max = tdm_tx_cfg[TDM_TERT][TDM_0].sample_rate; + break; + + case MSM_BACKEND_DAI_QUAT_TDM_RX_0: + channels->min = channels->max = + tdm_rx_cfg[TDM_QUAT][TDM_0].channels; + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + tdm_rx_cfg[TDM_QUAT][TDM_0].bit_format); + rate->min = rate->max = tdm_rx_cfg[TDM_QUAT][TDM_0].sample_rate; + break; + + case MSM_BACKEND_DAI_QUAT_TDM_TX_0: + channels->min = channels->max = + tdm_tx_cfg[TDM_QUAT][TDM_0].channels; + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + tdm_tx_cfg[TDM_QUAT][TDM_0].bit_format); + rate->min = rate->max = tdm_tx_cfg[TDM_QUAT][TDM_0].sample_rate; + break; + + case MSM_BACKEND_DAI_AUXPCM_RX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + aux_pcm_rx_cfg[PRIM_AUX_PCM].bit_format); + rate->min = rate->max = + aux_pcm_rx_cfg[PRIM_AUX_PCM].sample_rate; + channels->min = channels->max = + aux_pcm_rx_cfg[PRIM_AUX_PCM].channels; + break; + + case MSM_BACKEND_DAI_AUXPCM_TX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + aux_pcm_tx_cfg[PRIM_AUX_PCM].bit_format); + rate->min = rate->max = + aux_pcm_tx_cfg[PRIM_AUX_PCM].sample_rate; + channels->min = channels->max = + aux_pcm_tx_cfg[PRIM_AUX_PCM].channels; + break; + + case MSM_BACKEND_DAI_SEC_AUXPCM_RX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + aux_pcm_rx_cfg[SEC_AUX_PCM].bit_format); + rate->min = rate->max = + aux_pcm_rx_cfg[SEC_AUX_PCM].sample_rate; + channels->min = channels->max = + aux_pcm_rx_cfg[SEC_AUX_PCM].channels; + break; + + case MSM_BACKEND_DAI_SEC_AUXPCM_TX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + aux_pcm_tx_cfg[SEC_AUX_PCM].bit_format); + rate->min = rate->max = + aux_pcm_tx_cfg[SEC_AUX_PCM].sample_rate; + channels->min = channels->max = + aux_pcm_tx_cfg[SEC_AUX_PCM].channels; + break; + + case MSM_BACKEND_DAI_TERT_AUXPCM_RX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + aux_pcm_rx_cfg[TERT_AUX_PCM].bit_format); + rate->min = rate->max = + aux_pcm_rx_cfg[TERT_AUX_PCM].sample_rate; + channels->min = channels->max = + aux_pcm_rx_cfg[TERT_AUX_PCM].channels; + break; + + case MSM_BACKEND_DAI_TERT_AUXPCM_TX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + aux_pcm_tx_cfg[TERT_AUX_PCM].bit_format); + rate->min = rate->max = + aux_pcm_tx_cfg[TERT_AUX_PCM].sample_rate; + channels->min = channels->max = + aux_pcm_tx_cfg[TERT_AUX_PCM].channels; + break; + + case MSM_BACKEND_DAI_QUAT_AUXPCM_RX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + aux_pcm_rx_cfg[QUAT_AUX_PCM].bit_format); + rate->min = rate->max = + aux_pcm_rx_cfg[QUAT_AUX_PCM].sample_rate; + channels->min = channels->max = + aux_pcm_rx_cfg[QUAT_AUX_PCM].channels; + break; + + case MSM_BACKEND_DAI_QUAT_AUXPCM_TX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + aux_pcm_tx_cfg[QUAT_AUX_PCM].bit_format); + rate->min = rate->max = + aux_pcm_tx_cfg[QUAT_AUX_PCM].sample_rate; + channels->min = channels->max = + aux_pcm_tx_cfg[QUAT_AUX_PCM].channels; + break; + + case MSM_BACKEND_DAI_PRI_MI2S_RX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + mi2s_rx_cfg[PRIM_MI2S].bit_format); + rate->min = rate->max = mi2s_rx_cfg[PRIM_MI2S].sample_rate; + channels->min = channels->max = + mi2s_rx_cfg[PRIM_MI2S].channels; + break; + + case MSM_BACKEND_DAI_PRI_MI2S_TX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + mi2s_tx_cfg[PRIM_MI2S].bit_format); + rate->min = rate->max = mi2s_tx_cfg[PRIM_MI2S].sample_rate; + channels->min = channels->max = + mi2s_tx_cfg[PRIM_MI2S].channels; + break; + + case MSM_BACKEND_DAI_SECONDARY_MI2S_RX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + mi2s_rx_cfg[SEC_MI2S].bit_format); + rate->min = rate->max = mi2s_rx_cfg[SEC_MI2S].sample_rate; + channels->min = channels->max = + mi2s_rx_cfg[SEC_MI2S].channels; + break; + + case MSM_BACKEND_DAI_SECONDARY_MI2S_TX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + mi2s_tx_cfg[SEC_MI2S].bit_format); + rate->min = rate->max = mi2s_tx_cfg[SEC_MI2S].sample_rate; + channels->min = channels->max = + mi2s_tx_cfg[SEC_MI2S].channels; + break; + + case MSM_BACKEND_DAI_TERTIARY_MI2S_RX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + mi2s_rx_cfg[TERT_MI2S].bit_format); + rate->min = rate->max = mi2s_rx_cfg[TERT_MI2S].sample_rate; + channels->min = channels->max = + mi2s_rx_cfg[TERT_MI2S].channels; + break; + + case MSM_BACKEND_DAI_TERTIARY_MI2S_TX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + mi2s_tx_cfg[TERT_MI2S].bit_format); + rate->min = rate->max = mi2s_tx_cfg[TERT_MI2S].sample_rate; + channels->min = channels->max = + mi2s_tx_cfg[TERT_MI2S].channels; + break; + + case MSM_BACKEND_DAI_QUATERNARY_MI2S_RX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + mi2s_rx_cfg[QUAT_MI2S].bit_format); + rate->min = rate->max = mi2s_rx_cfg[QUAT_MI2S].sample_rate; + channels->min = channels->max = + mi2s_rx_cfg[QUAT_MI2S].channels; + break; + + case MSM_BACKEND_DAI_QUATERNARY_MI2S_TX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + mi2s_tx_cfg[QUAT_MI2S].bit_format); + rate->min = rate->max = mi2s_tx_cfg[QUAT_MI2S].sample_rate; + channels->min = channels->max = + mi2s_tx_cfg[QUAT_MI2S].channels; + break; + + default: + rate->min = rate->max = SAMPLING_RATE_48KHZ; + break; + } + +done: + return rc; +} + +static bool msm_usbc_swap_gnd_mic(struct snd_soc_component *component, bool active) +{ + int value = 0; + bool ret = 0; + struct snd_soc_card *card = component->card; + struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); + struct pinctrl_state *en2_pinctrl_active; + struct pinctrl_state *en2_pinctrl_sleep; + + if (!pdata->usbc_en2_gpio_p) { + if (active) { + /* if active and usbc_en2_gpio undefined, get pin */ + pdata->usbc_en2_gpio_p = devm_pinctrl_get(card->dev); + if (IS_ERR_OR_NULL(pdata->usbc_en2_gpio_p)) { + dev_err(card->dev, + "%s: Can't get EN2 gpio pinctrl:%ld\n", + __func__, + PTR_ERR(pdata->usbc_en2_gpio_p)); + pdata->usbc_en2_gpio_p = NULL; + return false; + } + } else + /* if not active and usbc_en2_gpio undefined, return */ + return false; + } + + pdata->usbc_en2_gpio = of_get_named_gpio(card->dev->of_node, + "qcom,usbc-analog-en2-gpio", 0); + if (!gpio_is_valid(pdata->usbc_en2_gpio)) { + dev_err(card->dev, "%s, property %s not in node %s", + __func__, "qcom,usbc-analog-en2-gpio", + card->dev->of_node->full_name); + return false; + } + + en2_pinctrl_active = pinctrl_lookup_state( + pdata->usbc_en2_gpio_p, "aud_active"); + if (IS_ERR_OR_NULL(en2_pinctrl_active)) { + dev_err(card->dev, + "%s: Cannot get aud_active pinctrl state:%ld\n", + __func__, PTR_ERR(en2_pinctrl_active)); + ret = false; + goto err_lookup_state; + } + + en2_pinctrl_sleep = pinctrl_lookup_state( + pdata->usbc_en2_gpio_p, "aud_sleep"); + if (IS_ERR_OR_NULL(en2_pinctrl_sleep)) { + dev_err(card->dev, + "%s: Cannot get aud_sleep pinctrl state:%ld\n", + __func__, PTR_ERR(en2_pinctrl_sleep)); + ret = false; + goto err_lookup_state; + } + + /* if active and usbc_en2_gpio_p defined, swap using usbc_en2_gpio_p */ + if (active) { + dev_dbg(component->dev, "%s: enter\n", __func__); + if (pdata->usbc_en2_gpio_p) { + value = gpio_get_value_cansleep(pdata->usbc_en2_gpio); + if (value) + pinctrl_select_state(pdata->usbc_en2_gpio_p, + en2_pinctrl_sleep); + else + pinctrl_select_state(pdata->usbc_en2_gpio_p, + en2_pinctrl_active); + } else if (pdata->usbc_en2_gpio >= 0) { + value = gpio_get_value_cansleep(pdata->usbc_en2_gpio); + gpio_set_value_cansleep(pdata->usbc_en2_gpio, !value); + } + pr_debug("%s: swap select switch %d to %d\n", __func__, + value, !value); + ret = true; + } else { + /* if not active, release usbc_en2_gpio_p pin */ + pinctrl_select_state(pdata->usbc_en2_gpio_p, + en2_pinctrl_sleep); + } + +err_lookup_state: + devm_pinctrl_put(pdata->usbc_en2_gpio_p); + pdata->usbc_en2_gpio_p = NULL; + return ret; +} + +static bool msm_swap_gnd_mic(struct snd_soc_component *component, bool active) +{ + int value = 0; + int ret = 0; + struct snd_soc_card *card = component->card; + struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); + + if (!pdata) + return false; + + if (!wcd_mbhc_cfg.enable_usbc_analog) { + /* if usbc is not defined, swap using us_euro_gpio_p */ + if (pdata->us_euro_gpio_p) { + value = msm_cdc_pinctrl_get_state( + pdata->us_euro_gpio_p); + if (value) + msm_cdc_pinctrl_select_sleep_state( + pdata->us_euro_gpio_p); + else + msm_cdc_pinctrl_select_active_state( + pdata->us_euro_gpio_p); + } else if (pdata->us_euro_gpio >= 0) { + value = gpio_get_value_cansleep( + pdata->us_euro_gpio); + gpio_set_value_cansleep( + pdata->us_euro_gpio, !value); + } + pr_debug("%s: swap select switch %d to %d\n", __func__, + value, !value); + ret = true; + } else { + /* if usbc is defined, swap using usbc_en2 */ + ret = msm_usbc_swap_gnd_mic(component, active); + } + return ret; +} + +static int msm_afe_set_config(struct snd_soc_component *component) +{ + int ret = 0; + void *config_data = NULL; + + if (!msm_codec_fn.get_afe_config_fn) { + dev_err(component->dev, "%s: codec get afe config not init'ed\n", + __func__); + return -EINVAL; + } + + config_data = msm_codec_fn.get_afe_config_fn(component, + AFE_CDC_REGISTERS_CONFIG); + if (config_data) { + ret = afe_set_config(AFE_CDC_REGISTERS_CONFIG, config_data, 0); + if (ret) { + dev_err(component->dev, + "%s: Failed to set codec registers config %d\n", + __func__, ret); + return ret; + } + } + + config_data = msm_codec_fn.get_afe_config_fn(component, + AFE_CDC_REGISTER_PAGE_CONFIG); + if (config_data) { + ret = afe_set_config(AFE_CDC_REGISTER_PAGE_CONFIG, config_data, + 0); + if (ret) + dev_err(component->dev, + "%s: Failed to set cdc register page config\n", + __func__); + } + + config_data = msm_codec_fn.get_afe_config_fn(component, + AFE_SLIMBUS_SLAVE_CONFIG); + if (config_data) { + ret = afe_set_config(AFE_SLIMBUS_SLAVE_CONFIG, config_data, 0); + if (ret) { + dev_err(component->dev, + "%s: Failed to set slimbus slave config %d\n", + __func__, ret); + return ret; + } + } + + return 0; +} + +static void msm_afe_clear_config(void) +{ + afe_clear_config(AFE_CDC_REGISTERS_CONFIG); + afe_clear_config(AFE_SLIMBUS_SLAVE_CONFIG); +} + +static int msm_adsp_power_up_config(struct snd_soc_component *component, + struct snd_card *card) +{ + int ret = 0; + unsigned long timeout; + int adsp_ready = 0; + bool snd_card_online = 0; + + timeout = jiffies + + msecs_to_jiffies(ADSP_STATE_READY_TIMEOUT_MS); + + do { + if (!snd_card_online) { + snd_card_online = snd_card_is_online_state(card); + pr_debug("%s: Sound card is %s\n", __func__, + snd_card_online ? "Online" : "Offline"); + } + if (!adsp_ready) { + adsp_ready = q6core_is_adsp_ready(); + pr_debug("%s: ADSP Audio is %s\n", __func__, + adsp_ready ? "ready" : "not ready"); + } + if (snd_card_online && adsp_ready) + break; + + /* + * Sound card/ADSP will be coming up after subsystem restart and + * it might not be fully up when the control reaches + * here. So, wait for 50msec before checking ADSP state + */ + msleep(50); + } while (time_after(timeout, jiffies)); + + if (!snd_card_online || !adsp_ready) { + pr_err("%s: Timeout. Sound card is %s, ADSP Audio is %s\n", + __func__, + snd_card_online ? "Online" : "Offline", + adsp_ready ? "ready" : "not ready"); + ret = -ETIMEDOUT; + goto err; + } + + ret = msm_afe_set_config(component); + if (ret) + pr_err("%s: Failed to set AFE config. err %d\n", + __func__, ret); + + return 0; + +err: + return ret; +} + +static void msm_adsp_power_up_config_work(struct work_struct *work) +{ + struct msm_asoc_mach_data *pdata; + struct snd_soc_component *component; + struct snd_card *card; + + pdata = container_of(work, struct msm_asoc_mach_data, + adsp_power_up_work); + component = pdata->component; + card = component->card->snd_card; + msm_adsp_power_up_config(component, card); +} + +static int sdm845_notifier_service_cb(struct notifier_block *this, + unsigned long opcode, void *ptr) +{ + int ret; + struct snd_soc_card *card = NULL; + const char *be_dl_name = LPASS_BE_SLIMBUS_0_RX; + struct snd_soc_pcm_runtime *rtd; + struct snd_soc_component *component; + struct snd_soc_dai *codec_dai; + struct msm_asoc_mach_data *pdata; + + pr_debug("%s: Service opcode 0x%lx\n", __func__, opcode); + + switch (opcode) { + case AUDIO_NOTIFIER_SERVICE_DOWN: + /* + * Use flag to ignore initial boot notifications + * On initial boot msm_adsp_power_up_config is + * called on init. There is no need to clear + * and set the config again on initial boot. + */ + if (is_initial_boot) + break; + msm_afe_clear_config(); + break; + case AUDIO_NOTIFIER_SERVICE_UP: + if (is_initial_boot) { + is_initial_boot = false; + break; + } + if (!spdev) + return -EINVAL; + + card = platform_get_drvdata(spdev); + rtd = snd_soc_get_pcm_runtime(card, be_dl_name); + if (!rtd) { + dev_err(card->dev, + "%s: snd_soc_get_pcm_runtime for %s failed!\n", + __func__, be_dl_name); + ret = -EINVAL; + goto err; + } + codec_dai = rtd->codec_dai; + if (!strcmp(dev_name(codec_dai->dev), "tavil_codec")) + component = snd_soc_rtdcom_lookup(rtd, "tavil_codec"); + + pdata = snd_soc_card_get_drvdata(card); + pdata->component = component; + schedule_work(&pdata->adsp_power_up_work); + break; + default: + break; + } +err: + return NOTIFY_OK; +} + +static struct notifier_block service_nb = { + .notifier_call = sdm845_notifier_service_cb, + .priority = -INT_MAX, +}; + +static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd) +{ + int ret = 0; + void *config_data; + struct snd_soc_component *component; + struct snd_soc_dapm_context *dapm; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_component *aux_comp; + struct snd_card *card; + struct snd_info_entry *entry; + struct msm_asoc_mach_data *pdata = + snd_soc_card_get_drvdata(rtd->card); + + /* Codec SLIMBUS configuration + * RX1, RX2, RX3, RX4, RX5, RX6, RX7, RX8 + * TX1, TX2, TX3, TX4, TX5, TX6, TX7, TX8, TX9, TX10, TX11, TX12, TX13 + * TX14, TX15, TX16 + */ + unsigned int rx_ch[WCD934X_RX_MAX] = {144, 145, 146, 147, 148, 149, + 150, 151}; + unsigned int tx_ch[WCD934X_TX_MAX] = {128, 129, 130, 131, 132, 133, + 134, 135, 136, 137, 138, 139, + 140, 141, 142, 143}; + + pr_info("%s: dev_name%s\n", __func__, dev_name(cpu_dai->dev)); + + rtd->pmdown_time = 0; + + component = snd_soc_rtdcom_lookup(rtd, "tavil_codec"); + if (!component) { + pr_err("%s: component is NULL\n", __func__); + return -EINVAL; + } + dapm = snd_soc_component_get_dapm(component); + + ret = snd_soc_add_component_controls(component, msm_snd_controls, + ARRAY_SIZE(msm_snd_controls)); + if (ret < 0) { + pr_err("%s: add_codec_controls failed, err %d\n", + __func__, ret); + return ret; + } + + snd_soc_dapm_new_controls(dapm, msm_dapm_widgets, + ARRAY_SIZE(msm_dapm_widgets)); + + snd_soc_dapm_add_routes(dapm, wcd_audio_paths, + ARRAY_SIZE(wcd_audio_paths)); + + snd_soc_dapm_ignore_suspend(dapm, "Handset Mic"); + snd_soc_dapm_ignore_suspend(dapm, "Headset Mic"); + snd_soc_dapm_ignore_suspend(dapm, "ANCRight Headset Mic"); + snd_soc_dapm_ignore_suspend(dapm, "ANCLeft Headset Mic"); + snd_soc_dapm_ignore_suspend(dapm, "Digital Mic0"); + snd_soc_dapm_ignore_suspend(dapm, "Digital Mic1"); + snd_soc_dapm_ignore_suspend(dapm, "Digital Mic2"); + snd_soc_dapm_ignore_suspend(dapm, "Digital Mic3"); + snd_soc_dapm_ignore_suspend(dapm, "Digital Mic4"); + snd_soc_dapm_ignore_suspend(dapm, "Digital Mic5"); + snd_soc_dapm_ignore_suspend(dapm, "Analog Mic5"); + snd_soc_dapm_ignore_suspend(dapm, "MADINPUT"); + snd_soc_dapm_ignore_suspend(dapm, "MAD_CPE_INPUT"); + snd_soc_dapm_ignore_suspend(dapm, "MAD_CPE_OUT1"); + snd_soc_dapm_ignore_suspend(dapm, "MAD_CPE_OUT2"); + snd_soc_dapm_ignore_suspend(dapm, "EAR"); + snd_soc_dapm_ignore_suspend(dapm, "LINEOUT1"); + snd_soc_dapm_ignore_suspend(dapm, "LINEOUT2"); + snd_soc_dapm_ignore_suspend(dapm, "ANC EAR"); + snd_soc_dapm_ignore_suspend(dapm, "SPK1 OUT"); + snd_soc_dapm_ignore_suspend(dapm, "SPK2 OUT"); + snd_soc_dapm_ignore_suspend(dapm, "HPHL"); + snd_soc_dapm_ignore_suspend(dapm, "HPHR"); + snd_soc_dapm_ignore_suspend(dapm, "AIF4 VI"); + snd_soc_dapm_ignore_suspend(dapm, "VIINPUT"); + snd_soc_dapm_ignore_suspend(dapm, "ANC HPHL"); + snd_soc_dapm_ignore_suspend(dapm, "ANC HPHR"); + + snd_soc_dapm_sync(dapm); + + snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch), + tx_ch, ARRAY_SIZE(rx_ch), rx_ch); + + msm_codec_fn.get_afe_config_fn = tavil_get_afe_config; + + ret = msm_adsp_power_up_config(component, rtd->card->snd_card); + if (ret) { + pr_err("%s: Failed to set AFE config %d\n", __func__, ret); + goto err; + } + + config_data = msm_codec_fn.get_afe_config_fn(component, + AFE_AANC_VERSION); + if (config_data) { + ret = afe_set_config(AFE_AANC_VERSION, config_data, 0); + if (ret) { + pr_err("%s: Failed to set aanc version %d\n", + __func__, ret); + goto err; + } + } + + /* + * Send speaker configuration only for WSA8810. + * Default configuration is for WSA8815. + */ + pr_debug("%s: Number of aux devices: %d\n", + __func__, rtd->card->num_aux_devs); + if (rtd->card->num_aux_devs && + !list_empty(&rtd->card->aux_comp_list)) { + aux_comp = list_first_entry( + &rtd->card->component_dev_list, + struct snd_soc_component, + card_aux_list); + if (!strcmp(aux_comp->name, WSA8810_NAME_1) || + !strcmp(aux_comp->name, WSA8810_NAME_2)) { + tavil_set_spkr_mode(component, WCD934X_SPKR_MODE_1); + tavil_set_spkr_gain_offset(component, + WCD934X_RX_GAIN_OFFSET_M1P5_DB); + } + } + card = rtd->card->snd_card; + entry = snd_info_create_subdir(card->module, "codecs", + card->proc_root); + if (!entry) { + pr_debug("%s: Cannot create codecs module entry\n", + __func__); + pdata->codec_root = NULL; + goto done; + } + pdata->codec_root = entry; + tavil_codec_info_create_codec_entry(pdata->codec_root, component); + +done: + codec_reg_done = true; + return 0; + +err: + return ret; +} + +static int msm_wcn_init(struct snd_soc_pcm_runtime *rtd) +{ + unsigned int rx_ch[WCN_CDC_SLIM_RX_CH_MAX] = {157, 158}; + unsigned int tx_ch[WCN_CDC_SLIM_TX_CH_MAX] = {159, 160, 161}; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + + return snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch), + tx_ch, ARRAY_SIZE(rx_ch), rx_ch); +} + +static void *def_tavil_mbhc_cal(void) +{ + void *tavil_wcd_cal; + struct wcd_mbhc_btn_detect_cfg *btn_cfg; + u16 *btn_high; + + tavil_wcd_cal = kzalloc(WCD_MBHC_CAL_SIZE(WCD_MBHC_DEF_BUTTONS, + WCD9XXX_MBHC_DEF_RLOADS), GFP_KERNEL); + if (!tavil_wcd_cal) + return NULL; + +#define S(X, Y) ((WCD_MBHC_CAL_PLUG_TYPE_PTR(tavil_wcd_cal)->X) = (Y)) + S(v_hs_max, 1600); +#undef S +#define S(X, Y) ((WCD_MBHC_CAL_BTN_DET_PTR(tavil_wcd_cal)->X) = (Y)) + S(num_btn, WCD_MBHC_DEF_BUTTONS); +#undef S + + btn_cfg = WCD_MBHC_CAL_BTN_DET_PTR(tavil_wcd_cal); + btn_high = ((void *)&btn_cfg->_v_btn_low) + + (sizeof(btn_cfg->_v_btn_low[0]) * btn_cfg->num_btn); + + btn_high[0] = 75; + btn_high[1] = 150; + btn_high[2] = 237; + btn_high[3] = 500; + btn_high[4] = 500; + btn_high[5] = 500; + btn_high[6] = 500; + btn_high[7] = 500; + + return tavil_wcd_cal; +} + +static int msm_snd_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai_link *dai_link = rtd->dai_link; + + int ret = 0; + u32 rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS]; + u32 rx_ch_cnt = 0, tx_ch_cnt = 0; + u32 user_set_tx_ch = 0; + u32 rx_ch_count; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + ret = snd_soc_dai_get_channel_map(codec_dai, + &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch); + if (ret < 0) { + pr_err("%s: failed to get codec chan map, err:%d\n", + __func__, ret); + goto err; + } + if (dai_link->id == MSM_BACKEND_DAI_SLIMBUS_5_RX) { + pr_debug("%s: rx_5_ch=%d\n", __func__, + slim_rx_cfg[5].channels); + rx_ch_count = slim_rx_cfg[5].channels; + } else if (dai_link->id == MSM_BACKEND_DAI_SLIMBUS_2_RX) { + pr_debug("%s: rx_2_ch=%d\n", __func__, + slim_rx_cfg[2].channels); + rx_ch_count = slim_rx_cfg[2].channels; + } else if (dai_link->id == MSM_BACKEND_DAI_SLIMBUS_6_RX) { + pr_debug("%s: rx_6_ch=%d\n", __func__, + slim_rx_cfg[6].channels); + rx_ch_count = slim_rx_cfg[6].channels; + } else { + pr_debug("%s: rx_0_ch=%d\n", __func__, + slim_rx_cfg[0].channels); + rx_ch_count = slim_rx_cfg[0].channels; + } + ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0, + rx_ch_count, rx_ch); + if (ret < 0) { + pr_err("%s: failed to set cpu chan map, err:%d\n", + __func__, ret); + goto err; + } + } else { + + pr_debug("%s: %s_tx_dai_id_%d_ch=%d\n", __func__, + codec_dai->name, codec_dai->id, user_set_tx_ch); + ret = snd_soc_dai_get_channel_map(codec_dai, + &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch); + if (ret < 0) { + pr_err("%s: failed to get codec chan map\n, err:%d\n", + __func__, ret); + goto err; + } + /* For _tx1 case */ + if (dai_link->id == MSM_BACKEND_DAI_SLIMBUS_0_TX) + user_set_tx_ch = slim_tx_cfg[0].channels; + /* For _tx3 case */ + else if (dai_link->id == MSM_BACKEND_DAI_SLIMBUS_1_TX) + user_set_tx_ch = slim_tx_cfg[1].channels; + else if (dai_link->id == MSM_BACKEND_DAI_SLIMBUS_4_TX) + user_set_tx_ch = msm_vi_feed_tx_ch; + else + user_set_tx_ch = tx_ch_cnt; + + pr_debug("%s: msm_slim_0_tx_ch(%d) user_set_tx_ch(%d) tx_ch_cnt(%d), BE id (%d)\n", + __func__, slim_tx_cfg[0].channels, user_set_tx_ch, + tx_ch_cnt, dai_link->id); + + ret = snd_soc_dai_set_channel_map(cpu_dai, + user_set_tx_ch, tx_ch, 0, 0); + if (ret < 0) + pr_err("%s: failed to set cpu chan map, err:%d\n", + __func__, ret); + } + +err: + return ret; +} + +static int msm_slimbus_2_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + unsigned int rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS]; + unsigned int rx_ch_cnt = 0, tx_ch_cnt = 0; + unsigned int num_tx_ch = 0; + unsigned int num_rx_ch = 0; + int ret = 0; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + num_rx_ch = params_channels(params); + pr_debug("%s: %s rx_dai_id = %d num_ch = %d\n", __func__, + codec_dai->name, codec_dai->id, num_rx_ch); + ret = snd_soc_dai_get_channel_map(codec_dai, + &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch); + if (ret < 0) { + pr_err("%s: failed to get codec chan map, err:%d\n", + __func__, ret); + goto err; + } + ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0, + num_rx_ch, rx_ch); + if (ret < 0) { + pr_err("%s: failed to set cpu chan map, err:%d\n", + __func__, ret); + goto err; + } + } else { + num_tx_ch = params_channels(params); + pr_debug("%s: %s tx_dai_id = %d num_ch = %d\n", __func__, + codec_dai->name, codec_dai->id, num_tx_ch); + ret = snd_soc_dai_get_channel_map(codec_dai, + &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch); + if (ret < 0) { + pr_err("%s: failed to get codec chan map, err:%d\n", + __func__, ret); + goto err; + } + ret = snd_soc_dai_set_channel_map(cpu_dai, + num_tx_ch, tx_ch, 0, 0); + if (ret < 0) { + pr_err("%s: failed to set cpu chan map, err:%d\n", + __func__, ret); + goto err; + } + } + +err: + return ret; +} + +static int msm_wcn_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai_link *dai_link = rtd->dai_link; + u32 rx_ch[WCN_CDC_SLIM_RX_CH_MAX], tx_ch[WCN_CDC_SLIM_TX_CH_MAX]; + u32 rx_ch_cnt = 0, tx_ch_cnt = 0; + int ret; + + dev_dbg(rtd->dev, "%s: %s_tx_dai_id_%d\n", __func__, + codec_dai->name, codec_dai->id); + ret = snd_soc_dai_get_channel_map(codec_dai, + &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch); + if (ret) { + dev_err(rtd->dev, + "%s: failed to get BTFM codec chan map\n, err:%d\n", + __func__, ret); + goto err; + } + + dev_dbg(rtd->dev, "%s: tx_ch_cnt(%d) BE id %d\n", + __func__, tx_ch_cnt, dai_link->id); + + ret = snd_soc_dai_set_channel_map(cpu_dai, + tx_ch_cnt, tx_ch, rx_ch_cnt, rx_ch); + if (ret) + dev_err(rtd->dev, "%s: failed to set cpu chan map, err:%d\n", + __func__, ret); + +err: + return ret; +} + +static int msm_get_port_id(int be_id) +{ + int afe_port_id; + + switch (be_id) { + case MSM_BACKEND_DAI_PRI_MI2S_RX: + afe_port_id = AFE_PORT_ID_PRIMARY_MI2S_RX; + break; + case MSM_BACKEND_DAI_PRI_MI2S_TX: + afe_port_id = AFE_PORT_ID_PRIMARY_MI2S_TX; + break; + case MSM_BACKEND_DAI_SECONDARY_MI2S_RX: + afe_port_id = AFE_PORT_ID_SECONDARY_MI2S_RX; + break; + case MSM_BACKEND_DAI_SECONDARY_MI2S_TX: + afe_port_id = AFE_PORT_ID_SECONDARY_MI2S_TX; + break; + case MSM_BACKEND_DAI_TERTIARY_MI2S_RX: + afe_port_id = AFE_PORT_ID_TERTIARY_MI2S_RX; + break; + case MSM_BACKEND_DAI_TERTIARY_MI2S_TX: + afe_port_id = AFE_PORT_ID_TERTIARY_MI2S_TX; + break; + case MSM_BACKEND_DAI_QUATERNARY_MI2S_RX: + afe_port_id = AFE_PORT_ID_QUATERNARY_MI2S_RX; + break; + case MSM_BACKEND_DAI_QUATERNARY_MI2S_TX: + afe_port_id = AFE_PORT_ID_QUATERNARY_MI2S_TX; + break; + default: + pr_err("%s: Invalid BE id: %d\n", __func__, be_id); + afe_port_id = -EINVAL; + } + + return afe_port_id; +} + +static u32 get_mi2s_bits_per_sample(u32 bit_format) +{ + u32 bit_per_sample; + + switch (bit_format) { + case SNDRV_PCM_FORMAT_S32_LE: + case SNDRV_PCM_FORMAT_S24_3LE: + case SNDRV_PCM_FORMAT_S24_LE: + bit_per_sample = 32; + break; + case SNDRV_PCM_FORMAT_S16_LE: + default: + bit_per_sample = 16; + break; + } + + return bit_per_sample; +} + +static void update_mi2s_clk_val(int dai_id, int stream) +{ + u32 bit_per_sample; + + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + bit_per_sample = + get_mi2s_bits_per_sample(mi2s_rx_cfg[dai_id].bit_format); + mi2s_clk[dai_id].clk_freq_in_hz = + mi2s_rx_cfg[dai_id].sample_rate * 2 * bit_per_sample; + } else { + bit_per_sample = + get_mi2s_bits_per_sample(mi2s_tx_cfg[dai_id].bit_format); + mi2s_clk[dai_id].clk_freq_in_hz = + mi2s_tx_cfg[dai_id].sample_rate * 2 * bit_per_sample; + } +} + +static int msm_mi2s_set_sclk(struct snd_pcm_substream *substream, bool enable) +{ + int ret = 0; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + int port_id = 0; + int index = cpu_dai->id; + + port_id = msm_get_port_id(rtd->dai_link->id); + if (port_id < 0) { + dev_err(rtd->card->dev, "%s: Invalid port_id\n", __func__); + ret = port_id; + goto err; + } + + if (enable) { + update_mi2s_clk_val(index, substream->stream); + dev_dbg(rtd->card->dev, "%s: clock rate %ul\n", __func__, + mi2s_clk[index].clk_freq_in_hz); + } + + mi2s_clk[index].enable = enable; + ret = afe_set_lpass_clock_v2(port_id, + &mi2s_clk[index]); + if (ret < 0) { + dev_err(rtd->card->dev, + "%s: afe lpass clock failed for port 0x%x , err:%d\n", + __func__, port_id, ret); + goto err; + } + +err: + return ret; +} + +static int msm_set_pinctrl(struct msm_pinctrl_info *pinctrl_info, + enum pinctrl_pin_state new_state) +{ + int ret = 0; + int curr_state = 0; + + if (pinctrl_info == NULL) { + pr_err("%s: pinctrl_info is NULL\n", __func__); + ret = -EINVAL; + goto err; + } + + if (pinctrl_info->pinctrl == NULL) { + pr_err("%s: pinctrl_info->pinctrl is NULL\n", __func__); + ret = -EINVAL; + goto err; + } + + curr_state = pinctrl_info->curr_state; + pinctrl_info->curr_state = new_state; + pr_debug("%s: curr_state = %s new_state = %s\n", __func__, + pin_states[curr_state], pin_states[pinctrl_info->curr_state]); + + if (curr_state == pinctrl_info->curr_state) { + pr_debug("%s: Already in same state\n", __func__); + goto err; + } + + if (curr_state != STATE_DISABLE && + pinctrl_info->curr_state != STATE_DISABLE) { + pr_debug("%s: state already active cannot switch\n", __func__); + ret = -EIO; + goto err; + } + + switch (pinctrl_info->curr_state) { + case STATE_MI2S_ACTIVE: + ret = pinctrl_select_state(pinctrl_info->pinctrl, + pinctrl_info->mi2s_active); + if (ret) { + pr_err("%s: MI2S state select failed with %d\n", + __func__, ret); + ret = -EIO; + goto err; + } + break; + case STATE_TDM_ACTIVE: + ret = pinctrl_select_state(pinctrl_info->pinctrl, + pinctrl_info->tdm_active); + if (ret) { + pr_err("%s: TDM state select failed with %d\n", + __func__, ret); + ret = -EIO; + goto err; + } + break; + case STATE_DISABLE: + if (curr_state == STATE_MI2S_ACTIVE) { + ret = pinctrl_select_state(pinctrl_info->pinctrl, + pinctrl_info->mi2s_disable); + } else { + ret = pinctrl_select_state(pinctrl_info->pinctrl, + pinctrl_info->tdm_disable); + } + if (ret) { + pr_err("%s: state disable failed with %d\n", + __func__, ret); + ret = -EIO; + goto err; + } + break; + default: + pr_err("%s: TLMM pin state is invalid\n", __func__); + return -EINVAL; + } + +err: + return ret; +} + +static void msm_release_pinctrl(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); + struct msm_pinctrl_info *pinctrl_info = &pdata->pinctrl_info; + + if (pinctrl_info->pinctrl) { + devm_pinctrl_put(pinctrl_info->pinctrl); + pinctrl_info->pinctrl = NULL; + } +} + +static int msm_get_pinctrl(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); + struct msm_pinctrl_info *pinctrl_info = NULL; + struct pinctrl *pinctrl; + int ret; + + pinctrl_info = &pdata->pinctrl_info; + + if (pinctrl_info == NULL) { + pr_err("%s: pinctrl_info is NULL\n", __func__); + return -EINVAL; + } + + pinctrl = devm_pinctrl_get(&pdev->dev); + if (IS_ERR_OR_NULL(pinctrl)) { + pr_err("%s: Unable to get pinctrl handle\n", __func__); + return -EINVAL; + } + pinctrl_info->pinctrl = pinctrl; + + /* get all the states handles from Device Tree */ + pinctrl_info->mi2s_disable = pinctrl_lookup_state(pinctrl, + "quat_mi2s_disable"); + if (IS_ERR(pinctrl_info->mi2s_disable)) { + pr_err("%s: could not get mi2s_disable pinstate\n", __func__); + goto err; + } + pinctrl_info->mi2s_active = pinctrl_lookup_state(pinctrl, + "quat_mi2s_enable"); + if (IS_ERR(pinctrl_info->mi2s_active)) { + pr_err("%s: could not get mi2s_active pinstate\n", __func__); + goto err; + } + pinctrl_info->tdm_disable = pinctrl_lookup_state(pinctrl, + "quat_tdm_disable"); + if (IS_ERR(pinctrl_info->tdm_disable)) { + pr_err("%s: could not get tdm_disable pinstate\n", __func__); + goto err; + } + pinctrl_info->tdm_active = pinctrl_lookup_state(pinctrl, + "quat_tdm_enable"); + if (IS_ERR(pinctrl_info->tdm_active)) { + pr_err("%s: could not get tdm_active pinstate\n", + __func__); + goto err; + } + /* Reset the TLMM pins to a default state */ + ret = pinctrl_select_state(pinctrl_info->pinctrl, + pinctrl_info->mi2s_disable); + if (ret != 0) { + pr_err("%s: Disable TLMM pins failed with %d\n", + __func__, ret); + ret = -EIO; + goto err; + } + pinctrl_info->curr_state = STATE_DISABLE; + atomic_set(&pinctrl_ref_count, 0); + + return 0; + +err: + devm_pinctrl_put(pinctrl); + pinctrl_info->pinctrl = NULL; + return -EINVAL; +} + +static int msm_tdm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + + if (cpu_dai->id == AFE_PORT_ID_QUATERNARY_TDM_RX) { + channels->min = channels->max = + tdm_rx_cfg[TDM_QUAT][TDM_0].channels; + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + tdm_rx_cfg[TDM_QUAT][TDM_0].bit_format); + rate->min = rate->max = + tdm_rx_cfg[TDM_QUAT][TDM_0].sample_rate; + } else if (cpu_dai->id == AFE_PORT_ID_QUATERNARY_TDM_RX_1) { + channels->min = channels->max = + tdm_rx_cfg[TDM_QUAT][TDM_1].channels; + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + tdm_rx_cfg[TDM_QUAT][TDM_1].bit_format); + rate->min = rate->max = + tdm_rx_cfg[TDM_QUAT][TDM_1].sample_rate; + } else if (cpu_dai->id == AFE_PORT_ID_SECONDARY_TDM_RX) { + channels->min = channels->max = + tdm_rx_cfg[TDM_SEC][TDM_0].channels; + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + tdm_rx_cfg[TDM_SEC][TDM_0].bit_format); + rate->min = rate->max = tdm_rx_cfg[TDM_SEC][TDM_0].sample_rate; + } else { + pr_err("%s: dai id 0x%x not supported\n", + __func__, cpu_dai->id); + return -EINVAL; + } + + pr_debug("%s: dai id = 0x%x channels = %d rate = %d format = 0x%x\n", + __func__, cpu_dai->id, channels->max, rate->max, + params_format(params)); + + return 0; +} + +static int sdm845_tdm_snd_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + int ret = 0; + int slot_width = TDM_SLOT_WIDTH_BITS; + int channels, slots = TDM_MAX_SLOTS; + unsigned int slot_mask, rate, clk_freq; + unsigned int *slot_offset; + unsigned int path_dir = 0, interface = 0, channel_interface = 0; + + pr_debug("%s: dai id = 0x%x\n", __func__, cpu_dai->id); + + if (cpu_dai->id < AFE_PORT_ID_TDM_PORT_RANGE_START) { + pr_err("%s: dai id 0x%x not supported\n", + __func__, cpu_dai->id); + return -EINVAL; + } + + /* RX or TX */ + path_dir = cpu_dai->id % 2; + + /* PRI, SEC, TERT, QUAT, QUIN */ + interface = (cpu_dai->id - AFE_PORT_ID_TDM_PORT_RANGE_START) + / (2 * TDM_PORT_MAX); + + /* 0, 1, 2, .. 7 */ + channel_interface = + ((cpu_dai->id - AFE_PORT_ID_TDM_PORT_RANGE_START) / 2) + % TDM_PORT_MAX; + + pr_debug("%s: interface %u, channel interface %u\n", __func__, + interface, channel_interface); + + slot_offset = tdm_cfg[(interface * 2) + path_dir][channel_interface] + .tdm_slot_offset; + + if (path_dir) + channels = tdm_tx_cfg[interface][channel_interface].channels; + else + channels = tdm_rx_cfg[interface][channel_interface].channels; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + /*2 slot config - bits 0 and 1 set for the first two slots */ + slot_mask = 0x0000FFFF >> (16-slots); + + pr_debug("%s: tdm rx slot_width %d slots %d slot_mask %x\n", + __func__, slot_width, slots, slot_mask); + + ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0, slot_mask, + slots, slot_width); + if (ret < 0) { + pr_err("%s: failed to set tdm rx slot, err:%d\n", + __func__, ret); + goto end; + } + + pr_debug("%s: tdm rx slot_offset[0]: %d, slot_offset[1]: %d\n", + __func__, slot_offset[0], slot_offset[1]); + ret = snd_soc_dai_set_channel_map(cpu_dai, + 0, NULL, channels, slot_offset); + if (ret < 0) { + pr_err("%s: failed to set tdm rx channel map, err:%d\n", + __func__, ret); + goto end; + } + } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + /*2 slot config - bits 0 and 1 set for the first two slots */ + slot_mask = 0x0000FFFF >> (16-slots); + + pr_debug("%s: tdm tx slot_width %d slots %d\n", + __func__, slot_width, slots); + + ret = snd_soc_dai_set_tdm_slot(cpu_dai, slot_mask, 0, + slots, slot_width); + if (ret < 0) { + pr_err("%s: failed to set tdm tx slot, err:%d\n", + __func__, ret); + goto end; + } + + ret = snd_soc_dai_set_channel_map(cpu_dai, + channels, slot_offset, 0, NULL); + if (ret < 0) { + pr_err("%s: failed to set tdm tx channel map, err:%d\n", + __func__, ret); + goto end; + } + } else { + ret = -EINVAL; + pr_err("%s: invalid use case, err:%d\n", + __func__, ret); + goto end; + } + + rate = params_rate(params); + clk_freq = rate * slot_width * slots; + ret = snd_soc_dai_set_sysclk(cpu_dai, 0, clk_freq, SND_SOC_CLOCK_OUT); + if (ret < 0) + pr_err("%s: failed to set tdm clk, err:%d\n", + __func__, ret); + +end: + return ret; +} + +static int sdm845_tdm_snd_startup(struct snd_pcm_substream *substream) +{ + int ret = 0; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_card *card = rtd->card; + struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); + struct msm_pinctrl_info *pinctrl_info = &pdata->pinctrl_info; + + /* currently only supporting TDM_RX_0/TDM_RX_1 and TDM_TX_0 */ + if ((cpu_dai->id == AFE_PORT_ID_QUATERNARY_TDM_RX) || + (cpu_dai->id == AFE_PORT_ID_QUATERNARY_TDM_TX) || + (cpu_dai->id == AFE_PORT_ID_QUATERNARY_TDM_RX_1)) { + if (atomic_read(&pinctrl_ref_count) == 0) { + ret = msm_set_pinctrl(pinctrl_info, STATE_TDM_ACTIVE); + if (ret) + pr_err("%s: TDM TLMM pinctrl set failed with %d\n", + __func__, ret); + } + atomic_inc(&pinctrl_ref_count); + } + + return ret; +} + +static void sdm845_tdm_snd_shutdown(struct snd_pcm_substream *substream) +{ + int ret = 0; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_card *card = rtd->card; + struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); + struct msm_pinctrl_info *pinctrl_info = &pdata->pinctrl_info; + + /* currently only supporting TDM_RX_0/TDM_RX_1 and TDM_TX_0 */ + if ((cpu_dai->id == AFE_PORT_ID_QUATERNARY_TDM_RX) || + (cpu_dai->id == AFE_PORT_ID_QUATERNARY_TDM_TX) || + (cpu_dai->id == AFE_PORT_ID_QUATERNARY_TDM_RX_1)) { + atomic_dec(&pinctrl_ref_count); + if (atomic_read(&pinctrl_ref_count) == 0) { + ret = msm_set_pinctrl(pinctrl_info, STATE_DISABLE); + if (ret) + pr_err("%s: TDM TLMM pinctrl set failed with %d\n", + __func__, ret); + } + } +} + +static struct snd_soc_ops sdm845_tdm_be_ops = { + .hw_params = sdm845_tdm_snd_hw_params, + .startup = sdm845_tdm_snd_startup, + .shutdown = sdm845_tdm_snd_shutdown +}; + +static int msm_fe_qos_prepare(struct snd_pcm_substream *substream) +{ + cpumask_t mask; + + if (pm_qos_request_active(&substream->latency_pm_qos_req)) + pm_qos_remove_request(&substream->latency_pm_qos_req); + + cpumask_clear(&mask); + cpumask_set_cpu(1, &mask); /* affine to core 1 */ + cpumask_set_cpu(2, &mask); /* affine to core 2 */ + cpumask_copy(&substream->latency_pm_qos_req.cpus_affine, &mask); + + substream->latency_pm_qos_req.type = PM_QOS_REQ_AFFINE_CORES; + + pm_qos_add_request(&substream->latency_pm_qos_req, + PM_QOS_CPU_DMA_LATENCY, + MSM_LL_QOS_VALUE); + return 0; +} + +static struct snd_soc_ops msm_fe_qos_ops = { + .prepare = msm_fe_qos_prepare, +}; + +static int msm_mi2s_snd_startup(struct snd_pcm_substream *substream) +{ + int ret = 0; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + int index = cpu_dai->id; + unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS; + struct snd_soc_card *card = rtd->card; + struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); + struct msm_pinctrl_info *pinctrl_info = &pdata->pinctrl_info; + int ret_pinctrl = 0; + + dev_dbg(rtd->card->dev, + "%s: substream = %s stream = %d, dai name %s, dai ID %d\n", + __func__, substream->name, substream->stream, + cpu_dai->name, cpu_dai->id); + + if (index < PRIM_MI2S || index > QUAT_MI2S) { + ret = -EINVAL; + dev_err(rtd->card->dev, + "%s: CPU DAI id (%d) out of range\n", + __func__, cpu_dai->id); + goto err; + } + /* + * Muxtex protection in case the same MI2S + * interface using for both TX and RX so + * that the same clock won't be enable twice. + */ + mutex_lock(&mi2s_intf_conf[index].lock); + if (++mi2s_intf_conf[index].ref_cnt == 1) { + /* Check if msm needs to provide the clock to the interface */ + if (!mi2s_intf_conf[index].msm_is_mi2s_master) { + mi2s_clk[index].clk_id = mi2s_ebit_clk[index]; + fmt = SND_SOC_DAIFMT_CBM_CFM; + } + ret = msm_mi2s_set_sclk(substream, true); + if (ret < 0) { + dev_err(rtd->card->dev, + "%s: afe lpass clock failed to enable MI2S clock, err:%d\n", + __func__, ret); + goto clean_up; + } + + ret = snd_soc_dai_set_fmt(cpu_dai, fmt); + if (ret < 0) { + pr_err("%s: set fmt cpu dai failed for MI2S (%d), err:%d\n", + __func__, index, ret); + goto clk_off; + } + if (index == QUAT_MI2S) { + ret_pinctrl = msm_set_pinctrl(pinctrl_info, + STATE_MI2S_ACTIVE); + if (ret_pinctrl) + pr_err("%s: MI2S TLMM pinctrl set failed with %d\n", + __func__, ret_pinctrl); + } + } +clk_off: + if (ret < 0) + msm_mi2s_set_sclk(substream, false); +clean_up: + if (ret < 0) + mi2s_intf_conf[index].ref_cnt--; + mutex_unlock(&mi2s_intf_conf[index].lock); +err: + return ret; +} + +static void msm_mi2s_snd_shutdown(struct snd_pcm_substream *substream) +{ + int ret; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + int index = rtd->cpu_dai->id; + struct snd_soc_card *card = rtd->card; + struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); + struct msm_pinctrl_info *pinctrl_info = &pdata->pinctrl_info; + int ret_pinctrl = 0; + + pr_debug("%s(): substream = %s stream = %d\n", __func__, + substream->name, substream->stream); + if (index < PRIM_MI2S || index > QUAT_MI2S) { + pr_err("%s:invalid MI2S DAI(%d)\n", __func__, index); + return; + } + + mutex_lock(&mi2s_intf_conf[index].lock); + if (--mi2s_intf_conf[index].ref_cnt == 0) { + ret = msm_mi2s_set_sclk(substream, false); + if (ret < 0) + pr_err("%s:clock disable failed for MI2S (%d); ret=%d\n", + __func__, index, ret); + if (index == QUAT_MI2S) { + ret_pinctrl = msm_set_pinctrl(pinctrl_info, + STATE_DISABLE); + if (ret_pinctrl) + pr_err("%s: MI2S TLMM pinctrl set failed with %d\n", + __func__, ret_pinctrl); + } + } + mutex_unlock(&mi2s_intf_conf[index].lock); + +} + +static struct snd_soc_ops msm_mi2s_be_ops = { + .startup = msm_mi2s_snd_startup, + .shutdown = msm_mi2s_snd_shutdown, +}; + +static struct snd_soc_ops msm_be_ops = { + .hw_params = msm_snd_hw_params, +}; + +static struct snd_soc_ops msm_slimbus_2_be_ops = { + .hw_params = msm_slimbus_2_hw_params, +}; + +static struct snd_soc_ops msm_wcn_ops = { + .hw_params = msm_wcn_hw_params, +}; + + +/* Digital audio interface glue - connects codec <---> CPU */ +static struct snd_soc_dai_link msm_common_dai_links[] = { + /* FrontEnd DAI Links */ + { + .name = MSM_DAILINK_NAME(Media1), + .stream_name = "MultiMedia1", + .cpu_dai_name = "MultiMedia1", + .platform_name = "msm-pcm-dsp.0", + .dynamic = 1, + .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, + .dpcm_playback = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .id = MSM_FRONTEND_DAI_MULTIMEDIA1 + }, + { + .name = MSM_DAILINK_NAME(Media2), + .stream_name = "MultiMedia2", + .cpu_dai_name = "MultiMedia2", + .platform_name = "msm-pcm-dsp.0", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .id = MSM_FRONTEND_DAI_MULTIMEDIA2, + }, + { + .name = "VoiceMMode1", + .stream_name = "VoiceMMode1", + .cpu_dai_name = "VoiceMMode1", + .platform_name = "msm-pcm-voice", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .id = MSM_FRONTEND_DAI_VOICEMMODE1, + }, + { + .name = "MSM VoIP", + .stream_name = "VoIP", + .cpu_dai_name = "VoIP", + .platform_name = "msm-voip-dsp", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .id = MSM_FRONTEND_DAI_VOIP, + }, + { + .name = MSM_DAILINK_NAME(ULL), + .stream_name = "MultiMedia3", + .cpu_dai_name = "MultiMedia3", + .platform_name = "msm-pcm-dsp.2", + .dynamic = 1, + .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .id = MSM_FRONTEND_DAI_MULTIMEDIA3, + }, + /* Hostless PCM purpose */ + { + .name = "SLIMBUS_0 Hostless", + .stream_name = "SLIMBUS_0 Hostless", + .cpu_dai_name = "SLIMBUS0_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + /* this dailink has playback support */ + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, + { + .name = "MSM AFE-PCM RX", + .stream_name = "AFE-PROXY RX", + .cpu_dai_name = "msm-dai-q6-dev.241", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .platform_name = "msm-pcm-afe", + .dpcm_playback = 1, + .ignore_suspend = 1, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + }, + { + .name = "MSM AFE-PCM TX", + .stream_name = "AFE-PROXY TX", + .cpu_dai_name = "msm-dai-q6-dev.240", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .platform_name = "msm-pcm-afe", + .dpcm_capture = 1, + .ignore_suspend = 1, + }, + { + .name = MSM_DAILINK_NAME(Compress1), + .stream_name = "Compress1", + .cpu_dai_name = "MultiMedia4", + .platform_name = "msm-compress-dsp", + .dynamic = 1, + .async_ops = ASYNC_DPCM_SND_SOC_HW_PARAMS, + .dpcm_playback = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + /* this dainlink has playback support */ + .id = MSM_FRONTEND_DAI_MULTIMEDIA4, + }, + { + .name = "AUXPCM Hostless", + .stream_name = "AUXPCM Hostless", + .cpu_dai_name = "AUXPCM_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, + { + .name = "SLIMBUS_1 Hostless", + .stream_name = "SLIMBUS_1 Hostless", + .cpu_dai_name = "SLIMBUS1_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + /* this dailink has playback support */ + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, + { + .name = "SLIMBUS_3 Hostless", + .stream_name = "SLIMBUS_3 Hostless", + .cpu_dai_name = "SLIMBUS3_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + /* this dailink has playback support */ + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, + { + .name = "SLIMBUS_4 Hostless", + .stream_name = "SLIMBUS_4 Hostless", + .cpu_dai_name = "SLIMBUS4_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + /* this dailink has playback support */ + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, + { + .name = MSM_DAILINK_NAME(LowLatency), + .stream_name = "MultiMedia5", + .cpu_dai_name = "MultiMedia5", + .platform_name = "msm-pcm-dsp.1", + .dynamic = 1, + .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, + .dpcm_playback = 1, + .dpcm_capture = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .id = MSM_FRONTEND_DAI_MULTIMEDIA5, + .ops = &msm_fe_qos_ops, + }, + { + .name = "Listen 1 Audio Service", + .stream_name = "Listen 1 Audio Service", + .cpu_dai_name = "LSM1", + .platform_name = "msm-lsm-client", + .dynamic = 1, + .dpcm_capture = 1, + .trigger = { SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST }, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .id = MSM_FRONTEND_DAI_LSM1, + }, + /* Multiple Tunnel instances */ + { + .name = MSM_DAILINK_NAME(Compress2), + .stream_name = "Compress2", + .cpu_dai_name = "MultiMedia7", + .platform_name = "msm-compress-dsp", + .dynamic = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + /* this dainlink has playback support */ + .id = MSM_FRONTEND_DAI_MULTIMEDIA7, + }, + { + .name = MSM_DAILINK_NAME(MultiMedia10), + .stream_name = "MultiMedia10", + .cpu_dai_name = "MultiMedia10", + .platform_name = "msm-pcm-dsp.1", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + /* this dainlink has playback support */ + .id = MSM_FRONTEND_DAI_MULTIMEDIA10, + }, + { + .name = MSM_DAILINK_NAME(ULL_NOIRQ), + .stream_name = "MM_NOIRQ", + .cpu_dai_name = "MultiMedia8", + .platform_name = "msm-pcm-dsp-noirq", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + /* this dainlink has playback support */ + .id = MSM_FRONTEND_DAI_MULTIMEDIA8, + .ops = &msm_fe_qos_ops, + }, + /* HDMI Hostless */ + { + .name = "HDMI_RX_HOSTLESS", + .stream_name = "HDMI_RX_HOSTLESS", + .cpu_dai_name = "HDMI_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, + { + .name = "VoiceMMode2", + .stream_name = "VoiceMMode2", + .cpu_dai_name = "VoiceMMode2", + .platform_name = "msm-pcm-voice", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .id = MSM_FRONTEND_DAI_VOICEMMODE2, + }, + /* LSM FE */ + { + .name = "Listen 2 Audio Service", + .stream_name = "Listen 2 Audio Service", + .cpu_dai_name = "LSM2", + .platform_name = "msm-lsm-client", + .dynamic = 1, + .dpcm_capture = 1, + .trigger = { SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST }, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .id = MSM_FRONTEND_DAI_LSM2, + }, + { + .name = "Listen 3 Audio Service", + .stream_name = "Listen 3 Audio Service", + .cpu_dai_name = "LSM3", + .platform_name = "msm-lsm-client", + .dynamic = 1, + .dpcm_capture = 1, + .trigger = { SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST }, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .id = MSM_FRONTEND_DAI_LSM3, + }, + { + .name = "Listen 4 Audio Service", + .stream_name = "Listen 4 Audio Service", + .cpu_dai_name = "LSM4", + .platform_name = "msm-lsm-client", + .dynamic = 1, + .dpcm_capture = 1, + .trigger = { SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST }, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .id = MSM_FRONTEND_DAI_LSM4, + }, + { + .name = "Listen 5 Audio Service", + .stream_name = "Listen 5 Audio Service", + .cpu_dai_name = "LSM5", + .platform_name = "msm-lsm-client", + .dynamic = 1, + .dpcm_capture = 1, + .trigger = { SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST }, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .id = MSM_FRONTEND_DAI_LSM5, + }, + { + .name = "Listen 6 Audio Service", + .stream_name = "Listen 6 Audio Service", + .cpu_dai_name = "LSM6", + .platform_name = "msm-lsm-client", + .dynamic = 1, + .dpcm_capture = 1, + .trigger = { SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST }, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .id = MSM_FRONTEND_DAI_LSM6, + }, + { + .name = "Listen 7 Audio Service", + .stream_name = "Listen 7 Audio Service", + .cpu_dai_name = "LSM7", + .platform_name = "msm-lsm-client", + .dynamic = 1, + .dpcm_capture = 1, + .trigger = { SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST }, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .id = MSM_FRONTEND_DAI_LSM7, + }, + { + .name = "Listen 8 Audio Service", + .stream_name = "Listen 8 Audio Service", + .cpu_dai_name = "LSM8", + .platform_name = "msm-lsm-client", + .dynamic = 1, + .dpcm_capture = 1, + .trigger = { SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST }, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .id = MSM_FRONTEND_DAI_LSM8, + }, + { + .name = MSM_DAILINK_NAME(Media9), + .stream_name = "MultiMedia9", + .cpu_dai_name = "MultiMedia9", + .platform_name = "msm-pcm-dsp.0", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .id = MSM_FRONTEND_DAI_MULTIMEDIA9, + }, + { + .name = MSM_DAILINK_NAME(Compress4), + .stream_name = "Compress4", + .cpu_dai_name = "MultiMedia11", + .platform_name = "msm-compress-dsp", + .dynamic = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + /* this dainlink has playback support */ + .id = MSM_FRONTEND_DAI_MULTIMEDIA11, + }, + { + .name = MSM_DAILINK_NAME(Compress5), + .stream_name = "Compress5", + .cpu_dai_name = "MultiMedia12", + .platform_name = "msm-compress-dsp", + .dynamic = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + /* this dainlink has playback support */ + .id = MSM_FRONTEND_DAI_MULTIMEDIA12, + }, + { + .name = MSM_DAILINK_NAME(Compress6), + .stream_name = "Compress6", + .cpu_dai_name = "MultiMedia13", + .platform_name = "msm-compress-dsp", + .dynamic = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + /* this dainlink has playback support */ + .id = MSM_FRONTEND_DAI_MULTIMEDIA13, + }, + { + .name = MSM_DAILINK_NAME(Compress7), + .stream_name = "Compress7", + .cpu_dai_name = "MultiMedia14", + .platform_name = "msm-compress-dsp", + .dynamic = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + /* this dainlink has playback support */ + .id = MSM_FRONTEND_DAI_MULTIMEDIA14, + }, + { + .name = MSM_DAILINK_NAME(Compress8), + .stream_name = "Compress8", + .cpu_dai_name = "MultiMedia15", + .platform_name = "msm-compress-dsp", + .dynamic = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + /* this dainlink has playback support */ + .id = MSM_FRONTEND_DAI_MULTIMEDIA15, + }, + { + .name = MSM_DAILINK_NAME(ULL_NOIRQ_2), + .stream_name = "MM_NOIRQ_2", + .cpu_dai_name = "MultiMedia16", + .platform_name = "msm-pcm-dsp-noirq", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + /* this dainlink has playback support */ + .id = MSM_FRONTEND_DAI_MULTIMEDIA16, + }, + { + .name = "SLIMBUS_8 Hostless", + .stream_name = "SLIMBUS8_HOSTLESS Capture", + .cpu_dai_name = "SLIMBUS8_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, +}; + +static struct snd_soc_dai_link msm_tavil_fe_dai_links[] = { + { + .name = LPASS_BE_SLIMBUS_4_TX, + .stream_name = "Slimbus4 Capture", + .cpu_dai_name = "msm-dai-q6-dev.16393", + .platform_name = "msm-pcm-hostless", + .codec_name = "tavil_codec", + .codec_dai_name = "tavil_vifeedback", + .id = MSM_BACKEND_DAI_SLIMBUS_4_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_be_ops, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + }, + /* Ultrasound RX DAI Link */ + { + .name = "SLIMBUS_2 Hostless Playback", + .stream_name = "SLIMBUS_2 Hostless Playback", + .cpu_dai_name = "msm-dai-q6-dev.16388", + .platform_name = "msm-pcm-hostless", + .codec_name = "tavil_codec", + .codec_dai_name = "tavil_rx2", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ops = &msm_slimbus_2_be_ops, + }, + /* Ultrasound TX DAI Link */ + { + .name = "SLIMBUS_2 Hostless Capture", + .stream_name = "SLIMBUS_2 Hostless Capture", + .cpu_dai_name = "msm-dai-q6-dev.16389", + .platform_name = "msm-pcm-hostless", + .codec_name = "tavil_codec", + .codec_dai_name = "tavil_tx2", + .ignore_suspend = 1, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ops = &msm_slimbus_2_be_ops, + }, +}; + +static struct snd_soc_dai_link msm_common_misc_fe_dai_links[] = { + { + .name = MSM_DAILINK_NAME(ASM Loopback), + .stream_name = "MultiMedia6", + .cpu_dai_name = "MultiMedia6", + .platform_name = "msm-pcm-loopback", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_suspend = 1, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_pmdown_time = 1, + .id = MSM_FRONTEND_DAI_MULTIMEDIA6, + }, + { + .name = "USB Audio Hostless", + .stream_name = "USB Audio Hostless", + .cpu_dai_name = "USBAUDIO_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, + { + .name = "SLIMBUS_7 Hostless", + .stream_name = "SLIMBUS_7 Hostless", + .cpu_dai_name = "SLIMBUS7_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_capture = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, + { + .name = "MultiMedia21 Playback", + .stream_name = "MultiMedia21", + .cpu_dai_name = "MultiMedia21", + .platform_name = "msm-pcm-dsp.1", + .dynamic = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .id = MSM_FRONTEND_DAI_MULTIMEDIA21, + }, + { + .name = "MultiMedia22 Playback", + .stream_name = "MultiMedia22", + .cpu_dai_name = "MultiMedia22", + .platform_name = "msm-pcm-dsp.1", + .dynamic = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .id = MSM_FRONTEND_DAI_MULTIMEDIA22, + }, +}; + +static struct snd_soc_dai_link msm_common_be_dai_links[] = { + /* Backend AFE DAI Links */ + { + .name = LPASS_BE_AFE_PCM_RX, + .stream_name = "AFE Playback", + .cpu_dai_name = "msm-dai-q6-dev.224", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_AFE_PCM_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_AFE_PCM_TX, + .stream_name = "AFE Capture", + .cpu_dai_name = "msm-dai-q6-dev.225", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_AFE_PCM_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_suspend = 1, + }, + /* Incall Record Uplink BACK END DAI Link */ + { + .name = LPASS_BE_INCALL_RECORD_TX, + .stream_name = "Voice Uplink Capture", + .cpu_dai_name = "msm-dai-q6-dev.32772", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_INCALL_RECORD_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_suspend = 1, + }, + /* Incall Record Downlink BACK END DAI Link */ + { + .name = LPASS_BE_INCALL_RECORD_RX, + .stream_name = "Voice Downlink Capture", + .cpu_dai_name = "msm-dai-q6-dev.32771", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_INCALL_RECORD_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_suspend = 1, + }, + /* Incall Music BACK END DAI Link */ + { + .name = LPASS_BE_VOICE_PLAYBACK_TX, + .stream_name = "Voice Farend Playback", + .cpu_dai_name = "msm-dai-q6-dev.32773", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_VOICE_PLAYBACK_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_suspend = 1, + }, + /* Incall Music 2 BACK END DAI Link */ + { + .name = LPASS_BE_VOICE2_PLAYBACK_TX, + .stream_name = "Voice2 Farend Playback", + .cpu_dai_name = "msm-dai-q6-dev.32770", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_VOICE2_PLAYBACK_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_suspend = 1, + }, + /* Proxy Tx BACK END DAI Link */ + { + .name = LPASS_BE_PROXY_TX, + .stream_name = "Proxy Capture", + .cpu_dai_name = "msm-dai-q6-dev.8195", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_PROXY_TX, + .ignore_suspend = 1, + }, + /* Proxy Rx BACK END DAI Link */ + { + .name = LPASS_BE_PROXY_RX, + .stream_name = "Proxy Playback", + .cpu_dai_name = "msm-dai-q6-dev.8194", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_PROXY_RX, + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_USB_AUDIO_RX, + .stream_name = "USB Audio Playback", + .cpu_dai_name = "msm-dai-q6-dev.28672", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_USB_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_USB_AUDIO_TX, + .stream_name = "USB Audio Capture", + .cpu_dai_name = "msm-dai-q6-dev.28673", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_USB_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_PRI_TDM_RX_0, + .stream_name = "Primary TDM0 Playback", + .cpu_dai_name = "msm-dai-q6-tdm.36864", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_PRI_TDM_RX_0, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &sdm845_tdm_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_PRI_TDM_TX_0, + .stream_name = "Primary TDM0 Capture", + .cpu_dai_name = "msm-dai-q6-tdm.36865", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_PRI_TDM_TX_0, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &sdm845_tdm_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_SEC_TDM_RX_0, + .stream_name = "Secondary TDM0 Playback", + .cpu_dai_name = "msm-dai-q6-tdm.36880", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_SEC_TDM_RX_0, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &sdm845_tdm_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_SEC_TDM_TX_0, + .stream_name = "Secondary TDM0 Capture", + .cpu_dai_name = "msm-dai-q6-tdm.36881", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_SEC_TDM_TX_0, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &sdm845_tdm_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_TERT_TDM_RX_0, + .stream_name = "Tertiary TDM0 Playback", + .cpu_dai_name = "msm-dai-q6-tdm.36896", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_TERT_TDM_RX_0, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &sdm845_tdm_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_TERT_TDM_TX_0, + .stream_name = "Tertiary TDM0 Capture", + .cpu_dai_name = "msm-dai-q6-tdm.36897", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_TERT_TDM_TX_0, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &sdm845_tdm_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_QUAT_TDM_RX_0, + .stream_name = "Quaternary TDM0 Playback", + .cpu_dai_name = "msm-dai-q6-tdm.36912", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_QUAT_TDM_RX_0, + .be_hw_params_fixup = msm_tdm_be_hw_params_fixup, + .ops = &sdm845_tdm_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_QUAT_TDM_TX_0, + .stream_name = "Quaternary TDM0 Capture", + .cpu_dai_name = "msm-dai-q6-tdm.36913", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_QUAT_TDM_TX_0, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &sdm845_tdm_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_QUAT_TDM_RX_1, + .stream_name = "Quaternary TDM1 Playback", + .cpu_dai_name = "msm-dai-q6-tdm.36914", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_QUAT_TDM_RX_1, + .be_hw_params_fixup = msm_tdm_be_hw_params_fixup, + .ops = &sdm845_tdm_be_ops, + .ignore_suspend = 1, + }, +}; + +static struct snd_soc_dai_link msm_tavil_be_dai_links[] = { + { + .name = LPASS_BE_SLIMBUS_0_RX, + .stream_name = "Slimbus Playback", + .cpu_dai_name = "msm-dai-q6-dev.16384", + .platform_name = "msm-pcm-routing", + .codec_name = "tavil_codec", + .codec_dai_name = "tavil_rx1", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_SLIMBUS_0_RX, + .init = &msm_audrx_init, + .be_hw_params_fixup = msm_be_hw_params_fixup, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + .ops = &msm_be_ops, + }, + { + .name = LPASS_BE_SLIMBUS_0_TX, + .stream_name = "Slimbus Capture", + .cpu_dai_name = "msm-dai-q6-dev.16385", + .platform_name = "msm-pcm-routing", + .codec_name = "tavil_codec", + .codec_dai_name = "tavil_tx1", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_SLIMBUS_0_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_suspend = 1, + .ops = &msm_be_ops, + }, + { + .name = LPASS_BE_SLIMBUS_1_RX, + .stream_name = "Slimbus1 Playback", + .cpu_dai_name = "msm-dai-q6-dev.16386", + .platform_name = "msm-pcm-routing", + .codec_name = "tavil_codec", + .codec_dai_name = "tavil_rx1", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_SLIMBUS_1_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_be_ops, + /* dai link has playback support */ + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_SLIMBUS_1_TX, + .stream_name = "Slimbus1 Capture", + .cpu_dai_name = "msm-dai-q6-dev.16387", + .platform_name = "msm-pcm-routing", + .codec_name = "tavil_codec", + .codec_dai_name = "tavil_tx3", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_SLIMBUS_1_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_SLIMBUS_2_RX, + .stream_name = "Slimbus2 Playback", + .cpu_dai_name = "msm-dai-q6-dev.16388", + .platform_name = "msm-pcm-routing", + .codec_name = "tavil_codec", + .codec_dai_name = "tavil_rx2", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_SLIMBUS_2_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_be_ops, + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_SLIMBUS_3_RX, + .stream_name = "Slimbus3 Playback", + .cpu_dai_name = "msm-dai-q6-dev.16390", + .platform_name = "msm-pcm-routing", + .codec_name = "tavil_codec", + .codec_dai_name = "tavil_rx1", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_SLIMBUS_3_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_be_ops, + /* dai link has playback support */ + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_SLIMBUS_3_TX, + .stream_name = "Slimbus3 Capture", + .cpu_dai_name = "msm-dai-q6-dev.16391", + .platform_name = "msm-pcm-routing", + .codec_name = "tavil_codec", + .codec_dai_name = "tavil_tx1", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_SLIMBUS_3_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_SLIMBUS_4_RX, + .stream_name = "Slimbus4 Playback", + .cpu_dai_name = "msm-dai-q6-dev.16392", + .platform_name = "msm-pcm-routing", + .codec_name = "tavil_codec", + .codec_dai_name = "tavil_rx1", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_SLIMBUS_4_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_be_ops, + /* dai link has playback support */ + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_SLIMBUS_5_RX, + .stream_name = "Slimbus5 Playback", + .cpu_dai_name = "msm-dai-q6-dev.16394", + .platform_name = "msm-pcm-routing", + .codec_name = "tavil_codec", + .codec_dai_name = "tavil_rx3", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_SLIMBUS_5_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_be_ops, + /* dai link has playback support */ + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, + /* MAD BE */ + { + .name = LPASS_BE_SLIMBUS_5_TX, + .stream_name = "Slimbus5 Capture", + .cpu_dai_name = "msm-dai-q6-dev.16395", + .platform_name = "msm-pcm-routing", + .codec_name = "tavil_codec", + .codec_dai_name = "tavil_mad1", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_SLIMBUS_5_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_SLIMBUS_6_RX, + .stream_name = "Slimbus6 Playback", + .cpu_dai_name = "msm-dai-q6-dev.16396", + .platform_name = "msm-pcm-routing", + .codec_name = "tavil_codec", + .codec_dai_name = "tavil_rx4", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_SLIMBUS_6_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_be_ops, + /* dai link has playback support */ + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, + /* Slimbus VI Recording */ + { + .name = LPASS_BE_SLIMBUS_TX_VI, + .stream_name = "Slimbus4 Capture", + .cpu_dai_name = "msm-dai-q6-dev.16393", + .platform_name = "msm-pcm-routing", + .codec_name = "tavil_codec", + .codec_dai_name = "tavil_vifeedback", + .id = MSM_BACKEND_DAI_SLIMBUS_4_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_be_ops, + .ignore_suspend = 1, + .no_pcm = 1, + .dpcm_capture = 1, + .ignore_pmdown_time = 1, + }, +}; + +static struct snd_soc_dai_link msm_wcn_be_dai_links[] = { + { + .name = LPASS_BE_SLIMBUS_7_RX, + .stream_name = "Slimbus7 Playback", + .cpu_dai_name = "msm-dai-q6-dev.16398", + .platform_name = "msm-pcm-routing", + .codec_name = "btfmslim_slave", + /* BT codec driver determines capabilities based on + * dai name, bt codecdai name should always contains + * supported usecase information + */ + .codec_dai_name = "btfm_bt_sco_a2dp_slim_rx", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_SLIMBUS_7_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_wcn_ops, + /* dai link has playback support */ + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_SLIMBUS_7_TX, + .stream_name = "Slimbus7 Capture", + .cpu_dai_name = "msm-dai-q6-dev.16399", + .platform_name = "msm-pcm-routing", + .codec_name = "btfmslim_slave", + .codec_dai_name = "btfm_bt_sco_slim_tx", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_SLIMBUS_7_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_wcn_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_SLIMBUS_8_TX, + .stream_name = "Slimbus8 Capture", + .cpu_dai_name = "msm-dai-q6-dev.16401", + .platform_name = "msm-pcm-routing", + .codec_name = "btfmslim_slave", + .codec_dai_name = "btfm_fm_slim_tx", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_SLIMBUS_8_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .init = &msm_wcn_init, + .ops = &msm_wcn_ops, + .ignore_suspend = 1, + }, +}; + +static struct snd_soc_dai_link ext_disp_be_dai_link[] = { + /* DISP PORT BACK END DAI Link */ + { + .name = LPASS_BE_DISPLAY_PORT, + .stream_name = "Display Port Playback", + .cpu_dai_name = "msm-dai-q6-dp.0", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-ext-disp-audio-codec-rx", + .codec_dai_name = "msm_dp_audio_codec_rx_dai", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_DISPLAY_PORT_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, +}; + +static struct snd_soc_dai_link msm_mi2s_be_dai_links[] = { + { + .name = LPASS_BE_PRI_MI2S_RX, + .stream_name = "Primary MI2S Playback", + .cpu_dai_name = "msm-dai-q6-mi2s.0", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_PRI_MI2S_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_mi2s_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + }, + { + .name = LPASS_BE_PRI_MI2S_TX, + .stream_name = "Primary MI2S Capture", + .cpu_dai_name = "msm-dai-q6-mi2s.0", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_PRI_MI2S_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_mi2s_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_SEC_MI2S_RX, + .stream_name = "Secondary MI2S Playback", + .cpu_dai_name = "msm-dai-q6-mi2s.1", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_mi2s_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + }, + { + .name = LPASS_BE_SEC_MI2S_TX, + .stream_name = "Secondary MI2S Capture", + .cpu_dai_name = "msm-dai-q6-mi2s.1", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_SECONDARY_MI2S_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_mi2s_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_TERT_MI2S_RX, + .stream_name = "Tertiary MI2S Playback", + .cpu_dai_name = "msm-dai-q6-mi2s.2", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_mi2s_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + }, + { + .name = LPASS_BE_TERT_MI2S_TX, + .stream_name = "Tertiary MI2S Capture", + .cpu_dai_name = "msm-dai-q6-mi2s.2", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_TERTIARY_MI2S_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_mi2s_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_QUAT_MI2S_RX, + .stream_name = "Quaternary MI2S Playback", + .cpu_dai_name = "msm-dai-q6-mi2s.3", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_mi2s_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + }, + { + .name = LPASS_BE_QUAT_MI2S_TX, + .stream_name = "Quaternary MI2S Capture", + .cpu_dai_name = "msm-dai-q6-mi2s.3", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_mi2s_be_ops, + .ignore_suspend = 1, + }, +}; + +static struct snd_soc_dai_link msm_auxpcm_be_dai_links[] = { + /* Primary AUX PCM Backend DAI Links */ + { + .name = LPASS_BE_AUXPCM_RX, + .stream_name = "AUX PCM Playback", + .cpu_dai_name = "msm-dai-q6-auxpcm.1", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_AUXPCM_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_AUXPCM_TX, + .stream_name = "AUX PCM Capture", + .cpu_dai_name = "msm-dai-q6-auxpcm.1", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_AUXPCM_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, + /* Secondary AUX PCM Backend DAI Links */ + { + .name = LPASS_BE_SEC_AUXPCM_RX, + .stream_name = "Sec AUX PCM Playback", + .cpu_dai_name = "msm-dai-q6-auxpcm.2", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_SEC_AUXPCM_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_SEC_AUXPCM_TX, + .stream_name = "Sec AUX PCM Capture", + .cpu_dai_name = "msm-dai-q6-auxpcm.2", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_SEC_AUXPCM_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + }, + /* Tertiary AUX PCM Backend DAI Links */ + { + .name = LPASS_BE_TERT_AUXPCM_RX, + .stream_name = "Tert AUX PCM Playback", + .cpu_dai_name = "msm-dai-q6-auxpcm.3", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_TERT_AUXPCM_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_TERT_AUXPCM_TX, + .stream_name = "Tert AUX PCM Capture", + .cpu_dai_name = "msm-dai-q6-auxpcm.3", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_TERT_AUXPCM_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + }, + /* Quaternary AUX PCM Backend DAI Links */ + { + .name = LPASS_BE_QUAT_AUXPCM_RX, + .stream_name = "Quat AUX PCM Playback", + .cpu_dai_name = "msm-dai-q6-auxpcm.4", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_QUAT_AUXPCM_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_QUAT_AUXPCM_TX, + .stream_name = "Quat AUX PCM Capture", + .cpu_dai_name = "msm-dai-q6-auxpcm.4", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_QUAT_AUXPCM_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + }, +}; + +static struct snd_soc_dai_link msm_tavil_snd_card_dai_links[ + ARRAY_SIZE(msm_common_dai_links) + + ARRAY_SIZE(msm_tavil_fe_dai_links) + + ARRAY_SIZE(msm_common_misc_fe_dai_links) + + ARRAY_SIZE(msm_common_be_dai_links) + + ARRAY_SIZE(msm_tavil_be_dai_links) + + ARRAY_SIZE(msm_wcn_be_dai_links) + + ARRAY_SIZE(ext_disp_be_dai_link) + + ARRAY_SIZE(msm_mi2s_be_dai_links) + + ARRAY_SIZE(msm_auxpcm_be_dai_links)]; + +static int msm_snd_card_tavil_late_probe(struct snd_soc_card *card) +{ + const char *be_dl_name = LPASS_BE_SLIMBUS_0_RX; + struct snd_soc_pcm_runtime *rtd; + struct snd_soc_component *component; + int ret = 0; + void *mbhc_calibration; + + rtd = snd_soc_get_pcm_runtime(card, be_dl_name); + if (!rtd) { + dev_err(card->dev, + "%s: snd_soc_get_pcm_runtime for %s failed!\n", + __func__, be_dl_name); + ret = -EINVAL; + goto err; + } + + component = snd_soc_rtdcom_lookup(rtd, "tavil_codec"); + if (!component) { + dev_err(card->dev, + "%s: component is NULL\n", __func__); + ret = -EINVAL; + goto err; + } + + mbhc_calibration = def_tavil_mbhc_cal(); + if (!mbhc_calibration) { + ret = -ENOMEM; + goto err; + } + wcd_mbhc_cfg.calibration = mbhc_calibration; + ret = tavil_mbhc_hs_detect(component, &wcd_mbhc_cfg); + if (ret) { + dev_err(card->dev, "%s: mbhc hs detect failed, err:%d\n", + __func__, ret); + goto err_free_mbhc_cal; + } + return 0; + +err_free_mbhc_cal: + kfree(mbhc_calibration); +err: + return ret; +} + +struct snd_soc_card snd_soc_card_tavil_msm = { + .name = "sdm845-tavil-snd-card", + .late_probe = msm_snd_card_tavil_late_probe, +}; + +static int msm_populate_dai_link_component_of_node( + struct snd_soc_card *card) +{ + int i, index, ret = 0; + struct device *cdev = card->dev; + struct snd_soc_dai_link *dai_link = card->dai_link; + struct device_node *np; + + if (!cdev) { + pr_err("%s: Sound card device memory NULL\n", __func__); + return -ENODEV; + } + + for (i = 0; i < card->num_links; i++) { + if (dai_link[i].platform_of_node && dai_link[i].cpu_of_node) + continue; + + /* populate platform_of_node for snd card dai links */ + if (dai_link[i].platform_name && + !dai_link[i].platform_of_node) { + index = of_property_match_string(cdev->of_node, + "asoc-platform-names", + dai_link[i].platform_name); + if (index < 0) { + pr_err("%s: No match found for platform name: %s\n", + __func__, dai_link[i].platform_name); + ret = index; + goto err; + } + np = of_parse_phandle(cdev->of_node, "asoc-platform", + index); + if (!np) { + pr_err("%s: retrieving phandle for platform %s, index %d failed\n", + __func__, dai_link[i].platform_name, + index); + ret = -ENODEV; + goto err; + } + dai_link[i].platform_of_node = np; + dai_link[i].platform_name = NULL; + } + + /* populate cpu_of_node for snd card dai links */ + if (dai_link[i].cpu_dai_name && !dai_link[i].cpu_of_node) { + index = of_property_match_string(cdev->of_node, + "asoc-cpu-names", + dai_link[i].cpu_dai_name); + if (index >= 0) { + np = of_parse_phandle(cdev->of_node, "asoc-cpu", + index); + if (!np) { + pr_err("%s: retrieving phandle for cpu dai %s failed\n", + __func__, + dai_link[i].cpu_dai_name); + ret = -ENODEV; + goto err; + } + dai_link[i].cpu_of_node = np; + dai_link[i].cpu_dai_name = NULL; + } + } + + /* populate codec_of_node for snd card dai links */ + if (dai_link[i].codec_name && !dai_link[i].codec_of_node) { + index = of_property_match_string(cdev->of_node, + "asoc-codec-names", + dai_link[i].codec_name); + if (index < 0) + continue; + np = of_parse_phandle(cdev->of_node, "asoc-codec", + index); + if (!np) { + pr_err("%s: retrieving phandle for codec %s failed\n", + __func__, dai_link[i].codec_name); + ret = -ENODEV; + goto err; + } + dai_link[i].codec_of_node = np; + dai_link[i].codec_name = NULL; + } + } + +err: + return ret; +} + +static int msm_prepare_us_euro(struct snd_soc_card *card) +{ + struct msm_asoc_mach_data *pdata = + snd_soc_card_get_drvdata(card); + int ret = 0; + + if (pdata->us_euro_gpio >= 0) { + dev_dbg(card->dev, "%s: us_euro gpio request %d", __func__, + pdata->us_euro_gpio); + ret = gpio_request(pdata->us_euro_gpio, "TAVIL_CODEC_US_EURO"); + if (ret) { + dev_err(card->dev, + "%s: Failed to request codec US/EURO gpio %d error %d\n", + __func__, pdata->us_euro_gpio, ret); + } + } + + return ret; +} + +static int msm_audrx_stub_init(struct snd_soc_pcm_runtime *rtd) +{ + int ret = 0; + struct snd_soc_component *component = + snd_soc_rtdcom_lookup(rtd, "msm-stub-codec"); + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + + if (!component) { + pr_err("%s: component is NULL\n", __func__); + return -EINVAL; + } + + ret = snd_soc_add_component_controls(component, msm_snd_controls, + ARRAY_SIZE(msm_snd_controls)); + if (ret < 0) { + dev_err(component->dev, + "%s: add_codec_controls failed, err = %d\n", + __func__, ret); + return ret; + } + + snd_soc_dapm_new_controls(dapm, msm_dapm_widgets, + ARRAY_SIZE(msm_dapm_widgets)); + + return 0; +} + +static int msm_snd_stub_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + + int ret = 0; + unsigned int rx_ch[] = {144, 145, 146, 147, 148, 149, 150, + 151}; + unsigned int tx_ch[] = {128, 129, 130, 131, 132, 133, + 134, 135, 136, 137, 138, 139, + 140, 141, 142, 143}; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0, + slim_rx_cfg[0].channels, + rx_ch); + if (ret < 0) + pr_err("%s: RX failed to set cpu chan map error %d\n", + __func__, ret); + } else { + ret = snd_soc_dai_set_channel_map(cpu_dai, + slim_tx_cfg[0].channels, + tx_ch, 0, 0); + if (ret < 0) + pr_err("%s: TX failed to set cpu chan map error %d\n", + __func__, ret); + } + + return ret; +} + +static struct snd_soc_ops msm_stub_be_ops = { + .hw_params = msm_snd_stub_hw_params, +}; + +static struct snd_soc_dai_link msm_stub_fe_dai_links[] = { + + /* FrontEnd DAI Links */ + { + .name = "MSMSTUB Media1", + .stream_name = "MultiMedia1", + .cpu_dai_name = "MultiMedia1", + .platform_name = "msm-pcm-dsp.0", + .dynamic = 1, + .async_ops = ASYNC_DPCM_SND_SOC_PREPARE, + .dpcm_playback = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .ignore_suspend = 1, + /* this dainlink has playback support */ + .ignore_pmdown_time = 1, + .id = MSM_FRONTEND_DAI_MULTIMEDIA1 + }, +}; + +static struct snd_soc_dai_link msm_stub_be_dai_links[] = { + + /* Backend DAI Links */ + { + .name = LPASS_BE_SLIMBUS_0_RX, + .stream_name = "Slimbus Playback", + .cpu_dai_name = "msm-dai-q6-dev.16384", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_SLIMBUS_0_RX, + .init = &msm_audrx_stub_init, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_pmdown_time = 1, /* dai link has playback support */ + .ignore_suspend = 1, + .ops = &msm_stub_be_ops, + }, + { + .name = LPASS_BE_SLIMBUS_0_TX, + .stream_name = "Slimbus Capture", + .cpu_dai_name = "msm-dai-q6-dev.16385", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_SLIMBUS_0_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_suspend = 1, + .ops = &msm_stub_be_ops, + }, +}; + +static struct snd_soc_dai_link msm_stub_dai_links[ + ARRAY_SIZE(msm_stub_fe_dai_links) + + ARRAY_SIZE(msm_stub_be_dai_links)]; + +struct snd_soc_card snd_soc_card_stub_msm = { + .name = "sdm845-stub-snd-card", +}; + +static const struct of_device_id sdm845_asoc_machine_of_match[] = { + { .compatible = "qcom,sdm845-asoc-snd-tavil", + .data = "tavil_codec"}, + { .compatible = "qcom,sdm845-asoc-snd-stub", + .data = "stub_codec"}, + {}, +}; + +static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev) +{ + struct snd_soc_card *card = NULL; + struct snd_soc_dai_link *dailink; + int len_1, len_2, len_3, len_4; + int total_links; + const struct of_device_id *match; + + match = of_match_node(sdm845_asoc_machine_of_match, dev->of_node); + if (!match) { + dev_err(dev, "%s: No DT match found for sound card\n", + __func__); + return NULL; + } + + if (!strcmp(match->data, "tavil_codec")) { + card = &snd_soc_card_tavil_msm; + len_1 = ARRAY_SIZE(msm_common_dai_links); + len_2 = len_1 + ARRAY_SIZE(msm_tavil_fe_dai_links); + len_3 = len_2 + ARRAY_SIZE(msm_common_misc_fe_dai_links); + len_4 = len_3 + ARRAY_SIZE(msm_common_be_dai_links); + total_links = len_4 + ARRAY_SIZE(msm_tavil_be_dai_links); + memcpy(msm_tavil_snd_card_dai_links, + msm_common_dai_links, + sizeof(msm_common_dai_links)); + memcpy(msm_tavil_snd_card_dai_links + len_1, + msm_tavil_fe_dai_links, + sizeof(msm_tavil_fe_dai_links)); + memcpy(msm_tavil_snd_card_dai_links + len_2, + msm_common_misc_fe_dai_links, + sizeof(msm_common_misc_fe_dai_links)); + memcpy(msm_tavil_snd_card_dai_links + len_3, + msm_common_be_dai_links, + sizeof(msm_common_be_dai_links)); + memcpy(msm_tavil_snd_card_dai_links + len_4, + msm_tavil_be_dai_links, + sizeof(msm_tavil_be_dai_links)); + + if (of_property_read_bool(dev->of_node, "qcom,wcn-btfm")) { + dev_dbg(dev, "%s(): WCN BTFM support present\n", + __func__); + memcpy(msm_tavil_snd_card_dai_links + total_links, + msm_wcn_be_dai_links, + sizeof(msm_wcn_be_dai_links)); + total_links += ARRAY_SIZE(msm_wcn_be_dai_links); + } + + if (of_property_read_bool(dev->of_node, + "qcom,ext-disp-audio-rx")) { + dev_dbg(dev, "%s(): ext disp audio support present\n", + __func__); + memcpy(msm_tavil_snd_card_dai_links + total_links, + ext_disp_be_dai_link, + sizeof(ext_disp_be_dai_link)); + total_links += ARRAY_SIZE(ext_disp_be_dai_link); + } + if (of_property_read_bool(dev->of_node, + "qcom,mi2s-audio-intf")) { + memcpy(msm_tavil_snd_card_dai_links + total_links, + msm_mi2s_be_dai_links, + sizeof(msm_mi2s_be_dai_links)); + total_links += ARRAY_SIZE(msm_mi2s_be_dai_links); + } + if (of_property_read_bool(dev->of_node, + "qcom,auxpcm-audio-intf")) { + memcpy(msm_tavil_snd_card_dai_links + total_links, + msm_auxpcm_be_dai_links, + sizeof(msm_auxpcm_be_dai_links)); + total_links += ARRAY_SIZE(msm_auxpcm_be_dai_links); + } + dailink = msm_tavil_snd_card_dai_links; + } else if (!strcmp(match->data, "stub_codec")) { + card = &snd_soc_card_stub_msm; + len_1 = ARRAY_SIZE(msm_stub_fe_dai_links); + len_2 = len_1 + ARRAY_SIZE(msm_stub_be_dai_links); + + memcpy(msm_stub_dai_links, + msm_stub_fe_dai_links, + sizeof(msm_stub_fe_dai_links)); + memcpy(msm_stub_dai_links + len_1, + msm_stub_be_dai_links, + sizeof(msm_stub_be_dai_links)); + + dailink = msm_stub_dai_links; + total_links = len_2; + } + + if (card) { + card->dai_link = dailink; + card->num_links = total_links; + } + + return card; +} + +static int msm_wsa881x_init(struct snd_soc_component *component) +{ + u8 spkleft_ports[WSA881X_MAX_SWR_PORTS] = {100, 101, 102, 106}; + u8 spkright_ports[WSA881X_MAX_SWR_PORTS] = {103, 104, 105, 107}; + unsigned int ch_rate[WSA881X_MAX_SWR_PORTS] = {2400, 600, 300, 1200}; + unsigned int ch_mask[WSA881X_MAX_SWR_PORTS] = {0x1, 0xF, 0x3, 0x3}; + struct msm_asoc_mach_data *pdata; + struct snd_soc_dapm_context *dapm; + int ret = 0; + + if (!component) { + pr_err("%s codec is NULL\n", __func__); + return -EINVAL; + } + + dapm = snd_soc_component_get_dapm(component); + + if (!strcmp(component->name_prefix, "SpkrLeft")) { + dev_dbg(component->dev, "%s: setting left ch map to codec %s\n", + __func__, component->name); + wsa881x_set_channel_map(component, &spkleft_ports[0], + WSA881X_MAX_SWR_PORTS, &ch_mask[0], + &ch_rate[0], NULL); + if (dapm->component) { + snd_soc_dapm_ignore_suspend(dapm, "SpkrLeft IN"); + snd_soc_dapm_ignore_suspend(dapm, "SpkrLeft SPKR"); + } + } else if (!strcmp(component->name_prefix, "SpkrRight")) { + dev_dbg(component->dev, "%s: setting right ch map to codec %s\n", + __func__, component->name); + wsa881x_set_channel_map(component, &spkright_ports[0], + WSA881X_MAX_SWR_PORTS, &ch_mask[0], + &ch_rate[0], NULL); + if (dapm->component) { + snd_soc_dapm_ignore_suspend(dapm, "SpkrRight IN"); + snd_soc_dapm_ignore_suspend(dapm, "SpkrRight SPKR"); + } + } else { + dev_err(component->dev, "%s: wrong codec name %s\n", __func__, + component->name); + ret = -EINVAL; + goto err; + } + pdata = snd_soc_card_get_drvdata(component->card); + if (pdata && pdata->codec_root) + wsa881x_codec_info_create_codec_entry(pdata->codec_root, + component); + +err: + return ret; +} + +static int msm_init_wsa_dev(struct platform_device *pdev, + struct snd_soc_card *card) +{ + struct device_node *wsa_of_node; + u32 wsa_max_devs; + u32 wsa_dev_cnt; + int i; + struct msm_wsa881x_dev_info *wsa881x_dev_info; + const char *wsa_auxdev_name_prefix[1]; + char *dev_name_str = NULL; + int found = 0; + int ret = 0; + + /* Get maximum WSA device count for this platform */ + ret = of_property_read_u32(pdev->dev.of_node, + "qcom,wsa-max-devs", &wsa_max_devs); + if (ret) { + dev_info(&pdev->dev, + "%s: wsa-max-devs property missing in DT %s, ret = %d\n", + __func__, pdev->dev.of_node->full_name, ret); + card->num_aux_devs = 0; + return 0; + } + if (wsa_max_devs == 0) { + dev_warn(&pdev->dev, + "%s: Max WSA devices is 0 for this target?\n", + __func__); + card->num_aux_devs = 0; + return 0; + } + + /* Get count of WSA device phandles for this platform */ + wsa_dev_cnt = of_count_phandle_with_args(pdev->dev.of_node, + "qcom,wsa-devs", NULL); + if (wsa_dev_cnt == -ENOENT) { + dev_warn(&pdev->dev, "%s: No wsa device defined in DT.\n", + __func__); + goto err; + } else if (wsa_dev_cnt <= 0) { + dev_err(&pdev->dev, + "%s: Error reading wsa device from DT. wsa_dev_cnt = %d\n", + __func__, wsa_dev_cnt); + ret = -EINVAL; + goto err; + } + + /* + * Expect total phandles count to be NOT less than maximum possible + * WSA count. However, if it is less, then assign same value to + * max count as well. + */ + if (wsa_dev_cnt < wsa_max_devs) { + dev_dbg(&pdev->dev, + "%s: wsa_max_devs = %d cannot exceed wsa_dev_cnt = %d\n", + __func__, wsa_max_devs, wsa_dev_cnt); + wsa_max_devs = wsa_dev_cnt; + } + + /* Make sure prefix string passed for each WSA device */ + ret = of_property_count_strings(pdev->dev.of_node, + "qcom,wsa-aux-dev-prefix"); + if (ret != wsa_dev_cnt) { + dev_err(&pdev->dev, + "%s: expecting %d wsa prefix. Defined only %d in DT\n", + __func__, wsa_dev_cnt, ret); + ret = -EINVAL; + goto err; + } + + /* + * Alloc mem to store phandle and index info of WSA device, if already + * registered with ALSA core + */ + wsa881x_dev_info = devm_kcalloc(&pdev->dev, wsa_max_devs, + sizeof(struct msm_wsa881x_dev_info), + GFP_KERNEL); + if (!wsa881x_dev_info) { + ret = -ENOMEM; + goto err; + } + + /* + * search and check whether all WSA devices are already + * registered with ALSA core or not. If found a node, store + * the node and the index in a local array of struct for later + * use. + */ + for (i = 0; i < wsa_dev_cnt; i++) { + wsa_of_node = of_parse_phandle(pdev->dev.of_node, + "qcom,wsa-devs", i); + if (unlikely(!wsa_of_node)) { + /* we should not be here */ + dev_err(&pdev->dev, + "%s: wsa dev node is not present\n", + __func__); + ret = -EINVAL; + goto err_free_dev_info; + } + if (soc_find_component_locked(wsa_of_node, NULL)) { + /* WSA device registered with ALSA core */ + wsa881x_dev_info[found].of_node = wsa_of_node; + wsa881x_dev_info[found].index = i; + found++; + if (found == wsa_max_devs) + break; + } + } + + if (found < wsa_max_devs) { + dev_dbg(&pdev->dev, + "%s: failed to find %d components. Found only %d\n", + __func__, wsa_max_devs, found); + return -EPROBE_DEFER; + } + dev_info(&pdev->dev, + "%s: found %d wsa881x devices registered with ALSA core\n", + __func__, found); + + card->num_aux_devs = wsa_max_devs; + card->num_configs = wsa_max_devs; + + /* Alloc array of AUX devs struct */ + msm_aux_dev = devm_kcalloc(&pdev->dev, card->num_aux_devs, + sizeof(struct snd_soc_aux_dev), + GFP_KERNEL); + if (!msm_aux_dev) { + ret = -ENOMEM; + goto err_free_dev_info; + } + + /* Alloc array of codec conf struct */ + msm_codec_conf = devm_kcalloc(&pdev->dev, card->num_aux_devs, + sizeof(struct snd_soc_codec_conf), + GFP_KERNEL); + if (!msm_codec_conf) { + ret = -ENOMEM; + goto err_free_aux_dev; + } + + for (i = 0; i < card->num_aux_devs; i++) { + dev_name_str = devm_kzalloc(&pdev->dev, DEV_NAME_STR_LEN, + GFP_KERNEL); + if (!dev_name_str) { + ret = -ENOMEM; + goto err_free_cdc_conf; + } + + ret = of_property_read_string_index(pdev->dev.of_node, + "qcom,wsa-aux-dev-prefix", + wsa881x_dev_info[i].index, + wsa_auxdev_name_prefix); + if (ret) { + dev_err(&pdev->dev, + "%s: failed to read wsa aux dev prefix, ret = %d\n", + __func__, ret); + ret = -EINVAL; + goto err_free_dev_name_str; + } + + snprintf(dev_name_str, strlen("wsa881x.%d"), "wsa881x.%d", i); + msm_aux_dev[i].name = dev_name_str; + msm_aux_dev[i].codec_name = NULL; + msm_aux_dev[i].codec_of_node = + wsa881x_dev_info[i].of_node; + msm_aux_dev[i].init = msm_wsa881x_init; + msm_codec_conf[i].dev_name = NULL; + msm_codec_conf[i].name_prefix = wsa_auxdev_name_prefix[0]; + msm_codec_conf[i].of_node = + wsa881x_dev_info[i].of_node; + } + card->codec_conf = msm_codec_conf; + card->aux_dev = msm_aux_dev; + + return 0; + +err_free_dev_name_str: + devm_kfree(&pdev->dev, dev_name_str); +err_free_cdc_conf: + devm_kfree(&pdev->dev, msm_codec_conf); +err_free_aux_dev: + devm_kfree(&pdev->dev, msm_aux_dev); +err_free_dev_info: + devm_kfree(&pdev->dev, wsa881x_dev_info); +err: + return ret; +} + +static void msm_i2s_auxpcm_init(struct platform_device *pdev) +{ + int count; + u32 mi2s_master_slave[MI2S_MAX]; + int ret; + + for (count = 0; count < MI2S_MAX; count++) { + mutex_init(&mi2s_intf_conf[count].lock); + mi2s_intf_conf[count].ref_cnt = 0; + } + + ret = of_property_read_u32_array(pdev->dev.of_node, + "qcom,msm-mi2s-master", + mi2s_master_slave, MI2S_MAX); + if (ret) { + dev_dbg(&pdev->dev, "%s: no qcom,msm-mi2s-master in DT node\n", + __func__); + } else { + for (count = 0; count < MI2S_MAX; count++) { + mi2s_intf_conf[count].msm_is_mi2s_master = + mi2s_master_slave[count]; + } + } +} + +static void msm_i2s_auxpcm_deinit(void) +{ + int count; + + for (count = 0; count < MI2S_MAX; count++) { + mutex_destroy(&mi2s_intf_conf[count].lock); + mi2s_intf_conf[count].ref_cnt = 0; + mi2s_intf_conf[count].msm_is_mi2s_master = 0; + } +} + +static int msm_asoc_machine_probe(struct platform_device *pdev) +{ + struct snd_soc_card *card; + struct msm_asoc_mach_data *pdata; + const char *mbhc_audio_jack_type = NULL; + char *mclk_freq_prop_name; + const struct of_device_id *match; + int ret; + const char *usb_c_dt = "qcom,msm-mbhc-usbc-audio-supported"; + + if (!pdev->dev.of_node) { + dev_err(&pdev->dev, "No platform supplied from device tree\n"); + return -EINVAL; + } + + pdata = devm_kzalloc(&pdev->dev, + sizeof(struct msm_asoc_mach_data), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + card = populate_snd_card_dailinks(&pdev->dev); + if (!card) { + dev_err(&pdev->dev, "%s: Card uninitialized\n", __func__); + ret = -EINVAL; + goto err; + } + card->dev = &pdev->dev; + platform_set_drvdata(pdev, card); + snd_soc_card_set_drvdata(card, pdata); + + ret = snd_soc_of_parse_card_name(card, "qcom,model"); + if (ret) { + dev_err(&pdev->dev, "parse card name failed, err:%d\n", + ret); + goto err; + } + + ret = snd_soc_of_parse_audio_routing(card, "qcom,audio-routing"); + if (ret) { + dev_err(&pdev->dev, "parse audio routing failed, err:%d\n", + ret); + goto err; + } + + match = of_match_node(sdm845_asoc_machine_of_match, + pdev->dev.of_node); + if (!match) { + dev_err(&pdev->dev, "%s: no matched codec is found.\n", + __func__); + goto err; + } + + mclk_freq_prop_name = "qcom,tavil-mclk-clk-freq"; + + ret = of_property_read_u32(pdev->dev.of_node, + mclk_freq_prop_name, &pdata->mclk_freq); + if (ret) { + dev_err(&pdev->dev, + "Looking up %s property in node %s failed, err%d\n", + mclk_freq_prop_name, + pdev->dev.of_node->full_name, ret); + goto err; + } + + if (pdata->mclk_freq != CODEC_EXT_CLK_RATE) { + dev_err(&pdev->dev, "unsupported mclk freq %u\n", + pdata->mclk_freq); + ret = -EINVAL; + goto err; + } + + ret = msm_populate_dai_link_component_of_node(card); + if (ret) { + ret = -EPROBE_DEFER; + goto err; + } + ret = msm_init_wsa_dev(pdev, card); + if (ret) + goto err; + + ret = devm_snd_soc_register_card(&pdev->dev, card); + if (ret == -EPROBE_DEFER) { + if (codec_reg_done) + ret = -EINVAL; + goto err; + } else if (ret) { + dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", + ret); + goto err; + } + dev_info(&pdev->dev, "Sound card %s registered\n", card->name); + spdev = pdev; + + INIT_WORK(&pdata->adsp_power_up_work, msm_adsp_power_up_config_work); + + ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); + if (ret) { + dev_dbg(&pdev->dev, "%s: failed to add child nodes, ret=%d\n", + __func__, ret); + } else { + pdata->hph_en1_gpio_p = of_parse_phandle(pdev->dev.of_node, + "qcom,hph-en1-gpio", 0); + if (!pdata->hph_en1_gpio_p) { + dev_dbg(&pdev->dev, "property %s not detected in node %s", + "qcom,hph-en1-gpio", + pdev->dev.of_node->full_name); + } + + pdata->hph_en0_gpio_p = of_parse_phandle(pdev->dev.of_node, + "qcom,hph-en0-gpio", 0); + if (!pdata->hph_en0_gpio_p) { + dev_dbg(&pdev->dev, "property %s not detected in node %s", + "qcom,hph-en0-gpio", + pdev->dev.of_node->full_name); + } + } + + ret = of_property_read_string(pdev->dev.of_node, + "qcom,mbhc-audio-jack-type", &mbhc_audio_jack_type); + if (ret) { + dev_dbg(&pdev->dev, "Looking up %s property in node %s failed", + "qcom,mbhc-audio-jack-type", + pdev->dev.of_node->full_name); + dev_dbg(&pdev->dev, "Jack type properties set to default"); + } else { + if (!strcmp(mbhc_audio_jack_type, "4-pole-jack")) { + wcd_mbhc_cfg.enable_anc_mic_detect = false; + dev_dbg(&pdev->dev, "This hardware has 4 pole jack"); + } else if (!strcmp(mbhc_audio_jack_type, "5-pole-jack")) { + wcd_mbhc_cfg.enable_anc_mic_detect = true; + dev_dbg(&pdev->dev, "This hardware has 5 pole jack"); + } else if (!strcmp(mbhc_audio_jack_type, "6-pole-jack")) { + wcd_mbhc_cfg.enable_anc_mic_detect = true; + dev_dbg(&pdev->dev, "This hardware has 6 pole jack"); + } else { + wcd_mbhc_cfg.enable_anc_mic_detect = false; + dev_dbg(&pdev->dev, "Unknown value, set to default"); + } + } + /* + * Parse US-Euro gpio info from DT. Report no error if us-euro + * entry is not found in DT file as some targets do not support + * US-Euro detection + */ + pdata->us_euro_gpio = of_get_named_gpio(pdev->dev.of_node, + "qcom,us-euro-gpios", 0); + if (!gpio_is_valid(pdata->us_euro_gpio)) + pdata->us_euro_gpio_p = of_parse_phandle(pdev->dev.of_node, + "qcom,us-euro-gpios", 0); + if (!gpio_is_valid(pdata->us_euro_gpio) && (!pdata->us_euro_gpio_p)) { + dev_dbg(&pdev->dev, "property %s not detected in node %s", + "qcom,us-euro-gpios", pdev->dev.of_node->full_name); + } else { + dev_dbg(&pdev->dev, "%s detected", + "qcom,us-euro-gpios"); + wcd_mbhc_cfg.swap_gnd_mic = msm_swap_gnd_mic; + } + + if (of_find_property(pdev->dev.of_node, usb_c_dt, NULL)) + wcd_mbhc_cfg.swap_gnd_mic = msm_swap_gnd_mic; + + ret = msm_prepare_us_euro(card); + if (ret) + dev_dbg(&pdev->dev, "msm_prepare_us_euro failed (%d)\n", + ret); + + /* Parse pinctrl info from devicetree */ + ret = msm_get_pinctrl(pdev); + if (!ret) { + pr_debug("%s: pinctrl parsing successful\n", __func__); + } else { + dev_dbg(&pdev->dev, + "%s: Parsing pinctrl failed with %d. Cannot use Ports\n", + __func__, ret); + ret = 0; + } + + msm_i2s_auxpcm_init(pdev); + + is_initial_boot = true; + ret = audio_notifier_register("sdm845", AUDIO_NOTIFIER_ADSP_DOMAIN, + &service_nb); + if (ret < 0) + pr_err("%s: Audio notifier register failed ret = %d\n", + __func__, ret); + + return 0; +err: + msm_release_pinctrl(pdev); + devm_kfree(&pdev->dev, pdata); + return ret; +} + +static int msm_asoc_machine_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + struct msm_asoc_mach_data *pdata = + snd_soc_card_get_drvdata(card); + + audio_notifier_deregister("sdm845"); + if (pdata->us_euro_gpio > 0) { + gpio_free(pdata->us_euro_gpio); + pdata->us_euro_gpio = 0; + } + msm_i2s_auxpcm_deinit(); + + msm_release_pinctrl(pdev); + snd_soc_unregister_card(card); + return 0; +} + +static struct platform_driver sdm845_asoc_machine_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + .pm = &snd_soc_pm_ops, + .of_match_table = sdm845_asoc_machine_of_match, + .suppress_bind_attrs = true, + }, + .probe = msm_asoc_machine_probe, + .remove = msm_asoc_machine_remove, +}; +module_platform_driver(sdm845_asoc_machine_driver); + +MODULE_DESCRIPTION("ALSA SoC msm"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRV_NAME); +MODULE_DEVICE_TABLE(of, sdm845_asoc_machine_of_match); diff --git a/techpack/audio/config/sdm845auto.conf b/techpack/audio/config/sdm845auto.conf new file mode 100644 index 000000000000..b3457a42064d --- /dev/null +++ b/techpack/audio/config/sdm845auto.conf @@ -0,0 +1,37 @@ +export CONFIG_PINCTRL_WCD=y +export CONFIG_SND_SOC_WCD934X=y +export CONFIG_SND_SOC_WCD9XXX_V2=y +export CONFIG_SND_SOC_WCD_CPE=y +export CONFIG_SND_SOC_WCD_MBHC=y +export CONFIG_SND_SOC_WSA881X=y +export CONFIG_SND_SOC_WCD_SPI=y +export CONFIG_SND_SOC_WCD934X_MBHC=y +export CONFIG_SND_SOC_WCD934X_DSD=y +export CONFIG_MSM_QDSP6V2_CODECS=y +export CONFIG_MSM_ULTRASOUND=y +export CONFIG_MSM_QDSP6_APRV2_RPMSG=y +export CONFIG_SND_SOC_MSM_QDSP6V2_INTF=y +export CONFIG_MSM_ADSP_LOADER=y +export CONFIG_REGMAP_SWR=y +export CONFIG_MSM_QDSP6_SSR=y +export CONFIG_MSM_QDSP6_PDR=y +export CONFIG_MSM_QDSP6_NOTIFIER=y +export CONFIG_SND_SOC_MSM_HOSTLESS_PCM=y +export CONFIG_SND_SOC_SDM845=y +export CONFIG_MSM_GLINK_SPI_XPRT=y +export CONFIG_SOUNDWIRE=y +export CONFIG_SOUNDWIRE_WCD_CTRL=y +export CONFIG_SND_SOC_WCD_MBHC_ADC=y +export CONFIG_SND_SOC_QDSP6V2=y +export CONFIG_MSM_CDC_PINCTRL=y +export CONFIG_QTI_PP=y +export CONFIG_SND_HWDEP_ROUTING=y +export CONFIG_DTS_EAGLE=y +export CONFIG_DOLBY_DS2=y +export CONFIG_DOLBY_LICENSE=y +export CONFIG_DTS_SRS_TM=y +export CONFIG_WCD9XXX_CODEC_CORE=y +export CONFIG_SND_SOC_MSM_STUB=y +export CONFIG_WCD_DSP_GLINK=y +export CONFIG_MSM_AVTIMER=y +export CONFIG_SND_SOC_MSM_HDMI_CODEC_RX=y diff --git a/techpack/audio/config/sdm845autoconf.h b/techpack/audio/config/sdm845autoconf.h new file mode 100644 index 000000000000..8c00cfebe514 --- /dev/null +++ b/techpack/audio/config/sdm845autoconf.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2021, The Linux Foundation. All rights reserved. + */ + +#define CONFIG_PINCTRL_WCD 1 +#define CONFIG_SND_SOC_WCD934X 1 +#define CONFIG_SND_SOC_WCD9XXX_V2 1 +#define CONFIG_SND_SOC_WCD_CPE 1 +#define CONFIG_SND_SOC_WCD_MBHC 1 +#define CONFIG_SND_SOC_WSA881X 1 +#define CONFIG_SND_SOC_WCD_SPI 1 +#define CONFIG_SND_SOC_WCD934X_MBHC 1 +#define CONFIG_SND_SOC_WCD934X_DSD 1 +#define CONFIG_MSM_QDSP6V2_CODECS 1 +#define CONFIG_MSM_ULTRASOUND 1 +#define CONFIG_MSM_QDSP6_APRV2_RPMSG 1 +#define CONFIG_SND_SOC_MSM_QDSP6V2_INTF 1 +#define CONFIG_MSM_ADSP_LOADER 1 +#define CONFIG_REGMAP_SWR 1 +#define CONFIG_MSM_QDSP6_SSR 1 +#define CONFIG_MSM_QDSP6_PDR 1 +#define CONFIG_MSM_QDSP6_NOTIFIER 1 +#define CONFIG_SND_SOC_MSM_HOSTLESS_PCM 1 +#define CONFIG_SND_SOC_SDM845 1 +#define CONFIG_MSM_GLINK_SPI_XPRT 1 +#define CONFIG_SOUNDWIRE 1 +#define CONFIG_SOUNDWIRE_WCD_CTRL 1 +#define CONFIG_SND_SOC_WCD_MBHC_ADC 1 +#define CONFIG_SND_SOC_QDSP6V2 1 +#define CONFIG_MSM_CDC_PINCTRL 1 +#define CONFIG_QTI_PP 1 +#define CONFIG_SND_HWDEP_ROUTING 1 +#define CONFIG_DTS_EAGLE 1 +#define CONFIG_DOLBY_DS2 1 +#define CONFIG_DOLBY_LICENSE 1 +#define CONFIG_DTS_SRS_TM 1 +#define CONFIG_WCD9XXX_CODEC_CORE 1 +#define CONFIG_SND_SOC_MSM_STUB 1 +#define CONFIG_WCD_DSP_GLINK 1 +#define CONFIG_MSM_AVTIMER 1 +#define CONFIG_SND_SOC_MSM_HDMI_CODEC_RX 1 diff --git a/techpack/audio/dsp/Android.mk b/techpack/audio/dsp/Android.mk index 699b1c91b5cb..29ce598f86d5 100644 --- a/techpack/audio/dsp/Android.mk +++ b/techpack/audio/dsp/Android.mk @@ -3,6 +3,10 @@ # Assume no targets will be supported # Check if this driver needs be built for current target +ifeq ($(call is-board-platform,sdm845),true) +AUDIO_SELECT := CONFIG_SND_SOC_SDM845=m +endif + ifeq ($(call is-board-platform-in-list,msmnile sdmshrike),true) ifeq ($(TARGET_BOARD_AUTO),true) AUDIO_SELECT := CONFIG_SND_SOC_SA8155=m @@ -41,7 +45,7 @@ endif AUDIO_CHIPSET := audio # Build/Package only in case of supported target -ifeq ($(call is-board-platform-in-list,msmnile $(MSMSTEPPE) $(TRINKET) kona lito bengal sdmshrike sdm660 msm8953 msm8937),true) +ifeq ($(call is-board-platform-in-list,msmnile $(MSMSTEPPE) $(TRINKET) kona lito bengal sdmshrike sdm660 msm8953 msm8937 sdm845),true) LOCAL_PATH := $(call my-dir) diff --git a/techpack/audio/dsp/Kbuild b/techpack/audio/dsp/Kbuild index aaa293697ad1..eef3189b42c5 100644 --- a/techpack/audio/dsp/Kbuild +++ b/techpack/audio/dsp/Kbuild @@ -14,6 +14,10 @@ ifeq ($(KERNEL_BUILD), 1) endif ifeq ($(KERNEL_BUILD), 0) + ifeq ($(CONFIG_ARCH_SDM845), y) + include $(AUDIO_ROOT)/config/sdm845auto.conf + INCS += -include $(AUDIO_ROOT)/config/sdm845autoconf.h + endif ifeq ($(CONFIG_ARCH_SM6150), y) ifdef CONFIG_SND_SOC_SA6155 include $(AUDIO_ROOT)/config/sa6155auto.conf diff --git a/techpack/audio/dsp/codecs/Android.mk b/techpack/audio/dsp/codecs/Android.mk index ceb1c8f2490b..0833b840c4dc 100644 --- a/techpack/audio/dsp/codecs/Android.mk +++ b/techpack/audio/dsp/codecs/Android.mk @@ -3,6 +3,10 @@ # Assume no targets will be supported # Check if this driver needs be built for current target +ifeq ($(call is-board-platform,sdm845),true) +AUDIO_SELECT := CONFIG_SND_SOC_SDM845=m +endif + ifeq ($(call is-board-platform-in-list,msmnile sdmshrike),true) AUDIO_SELECT := CONFIG_SND_SOC_SM8150=m endif @@ -33,7 +37,7 @@ endif AUDIO_CHIPSET := audio # Build/Package only in case of supported target -ifeq ($(call is-board-platform-in-list,msmnile $(MSMSTEPPE) $(TRINKET) kona lito bengal sdmshrike sdm660 msm8953 msm8937),true) +ifeq ($(call is-board-platform-in-list,msmnile $(MSMSTEPPE) $(TRINKET) kona lito bengal sdmshrike sdm660 msm8953 msm8937 sdm845),true) LOCAL_PATH := $(call my-dir) diff --git a/techpack/audio/dsp/codecs/Kbuild b/techpack/audio/dsp/codecs/Kbuild index 89aeab7fdcd3..3db3e7c152a3 100644 --- a/techpack/audio/dsp/codecs/Kbuild +++ b/techpack/audio/dsp/codecs/Kbuild @@ -14,6 +14,10 @@ ifeq ($(KERNEL_BUILD), 1) endif ifeq ($(KERNEL_BUILD), 0) + ifeq ($(CONFIG_ARCH_SDM845), y) + include $(AUDIO_ROOT)/config/sdm845auto.conf + INCS += -include $(AUDIO_ROOT)/config/sdm845autoconf.h + endif ifeq ($(CONFIG_ARCH_SM6150), y) include $(AUDIO_ROOT)/config/sm6150auto.conf export diff --git a/techpack/audio/ipc/Android.mk b/techpack/audio/ipc/Android.mk index 6364ed7d8102..96a8b1d0d5c2 100644 --- a/techpack/audio/ipc/Android.mk +++ b/techpack/audio/ipc/Android.mk @@ -3,6 +3,10 @@ # Assume no targets will be supported # Check if this driver needs be built for current target +ifeq ($(call is-board-platform,sdm845),true) +AUDIO_SELECT := CONFIG_SND_SOC_SDM845=m +endif + ifeq ($(call is-board-platform-in-list,msmnile sdmshrike),true) ifeq ($(TARGET_BOARD_AUTO),true) AUDIO_SELECT := CONFIG_SND_SOC_SA8155=m @@ -41,7 +45,7 @@ endif AUDIO_CHIPSET := audio # Build/Package only in case of supported target -ifeq ($(call is-board-platform-in-list,msmnile $(MSMSTEPPE) $(TRINKET) kona lito bengal sdmshrike sdm660 msm8953 msm8937),true) +ifeq ($(call is-board-platform-in-list,msmnile $(MSMSTEPPE) $(TRINKET) kona lito bengal sdmshrike sdm660 msm8953 msm8937 sdm845),true) LOCAL_PATH := $(call my-dir) diff --git a/techpack/audio/ipc/Kbuild b/techpack/audio/ipc/Kbuild index 14c53d97279b..96ced6d770b1 100644 --- a/techpack/audio/ipc/Kbuild +++ b/techpack/audio/ipc/Kbuild @@ -15,6 +15,10 @@ ifeq ($(KERNEL_BUILD), 1) endif ifeq ($(KERNEL_BUILD), 0) + ifeq ($(CONFIG_ARCH_SDM845), y) + include $(AUDIO_ROOT)/config/sdm845auto.conf + INCS += -include $(AUDIO_ROOT)/config/sdm845autoconf.h + endif ifeq ($(CONFIG_ARCH_SM6150), y) ifdef CONFIG_SND_SOC_SA6155 include $(AUDIO_ROOT)/config/sa6155auto.conf diff --git a/techpack/audio/soc/Android.mk b/techpack/audio/soc/Android.mk index 858be88c455b..4eade15f6b7d 100644 --- a/techpack/audio/soc/Android.mk +++ b/techpack/audio/soc/Android.mk @@ -3,6 +3,10 @@ # Assume no targets will be supported # Check if this driver needs be built for current target +ifeq ($(call is-board-platform,sdm845),true) +AUDIO_SELECT := CONFIG_SND_SOC_SDM845=m +endif + ifeq ($(call is-board-platform-in-list,msmnile sdmshrike),true) ifeq ($(TARGET_BOARD_AUTO),true) AUDIO_SELECT := CONFIG_SND_SOC_SA8155=m @@ -41,7 +45,7 @@ endif AUDIO_CHIPSET := audio # Build/Package only in case of supported target -ifeq ($(call is-board-platform-in-list,msmnile $(MSMSTEPPE) $(TRINKET) kona lito bengal sdmshrike sdm660 msm8953 msm8937),true) +ifeq ($(call is-board-platform-in-list,msmnile $(MSMSTEPPE) $(TRINKET) kona lito bengal sdmshrike sdm660 msm8953 msm8937 sdm845),true) LOCAL_PATH := $(call my-dir) diff --git a/techpack/audio/soc/Kbuild b/techpack/audio/soc/Kbuild index 9beb8e839cc3..cb168336dafc 100644 --- a/techpack/audio/soc/Kbuild +++ b/techpack/audio/soc/Kbuild @@ -14,6 +14,10 @@ ifeq ($(KERNEL_BUILD), 1) endif ifeq ($(KERNEL_BUILD), 0) + ifeq ($(CONFIG_ARCH_SDM845), y) + include $(AUDIO_ROOT)/config/sdm845auto.conf + INCS += -include $(AUDIO_ROOT)/config/sdm845autoconf.h + endif ifeq ($(CONFIG_ARCH_SM8150), y) ifdef CONFIG_SND_SOC_SA8155 include $(AUDIO_ROOT)/config/sa8155auto.conf From 75c56ff18dfa627fb5fc09653d8e290d09464c40 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Sat, 5 Aug 2023 05:32:28 +0000 Subject: [PATCH 121/356] ARM64: dts: qcom: Add SLIMbus device IDs --- arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi b/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi index 0c3421f67f00..4d3b8d9681fb 100644 --- a/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi +++ b/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi @@ -197,21 +197,25 @@ sb_7_rx: qcom,msm-dai-q6-sb-7-rx { compatible = "qcom,msm-dai-q6-dev"; qcom,msm-dai-q6-dev-id = <16398>; + qcom,msm-dai-q6-slim-dev-id = <1>; }; sb_7_tx: qcom,msm-dai-q6-sb-7-tx { compatible = "qcom,msm-dai-q6-dev"; qcom,msm-dai-q6-dev-id = <16399>; + qcom,msm-dai-q6-slim-dev-id = <1>; }; sb_8_rx: qcom,msm-dai-q6-sb-8-rx { compatible = "qcom,msm-dai-q6-dev"; qcom,msm-dai-q6-dev-id = <16400>; + qcom,msm-dai-q6-slim-dev-id = <1>; }; sb_8_tx: qcom,msm-dai-q6-sb-8-tx { compatible = "qcom,msm-dai-q6-dev"; qcom,msm-dai-q6-dev-id = <16401>; + qcom,msm-dai-q6-slim-dev-id = <1>; }; bt_sco_rx: qcom,msm-dai-q6-bt-sco-rx { From abe86f6841c7c47b47ae12fd2eeb520fb819f9df Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Wed, 7 Jun 2023 00:49:21 +0000 Subject: [PATCH 122/356] media: Import legacy vidc driver From msm-4.14 as of commit "msm: vidc: Release cvp buffer lock in invalid buffer case". --- drivers/media/platform/msm/Kconfig | 1 + drivers/media/platform/msm/Makefile | 1 + drivers/media/platform/msm/vidc/Kconfig | 10 + drivers/media/platform/msm/vidc/Makefile | 23 + .../media/platform/msm/vidc/governors/Kconfig | 6 + .../platform/msm/vidc/governors/Makefile | 9 + .../platform/msm/vidc/governors/fixedpoint.h | 72 + .../vidc/governors/msm_vidc_ar50_dyn_gov.c | 978 +++ .../msm/vidc/governors/msm_vidc_dyn_gov.c | 1020 +++ .../platform/msm/vidc/hfi_packetization.c | 2206 +++++ .../platform/msm/vidc/hfi_packetization.h | 103 + .../platform/msm/vidc/hfi_response_handler.c | 2150 +++++ drivers/media/platform/msm/vidc/msm_cvp.c | 631 ++ drivers/media/platform/msm/vidc/msm_cvp.h | 33 + drivers/media/platform/msm/vidc/msm_smem.c | 606 ++ .../platform/msm/vidc/msm_v4l2_private.c | 234 + .../platform/msm/vidc/msm_v4l2_private.h | 22 + .../media/platform/msm/vidc/msm_v4l2_vidc.c | 932 +++ drivers/media/platform/msm/vidc/msm_vdec.c | 1455 ++++ drivers/media/platform/msm/vidc/msm_vdec.h | 29 + drivers/media/platform/msm/vidc/msm_venc.c | 2957 +++++++ drivers/media/platform/msm/vidc/msm_venc.h | 28 + drivers/media/platform/msm/vidc/msm_vidc.c | 2254 +++++ drivers/media/platform/msm/vidc/msm_vidc.h | 136 + .../media/platform/msm/vidc/msm_vidc_clocks.c | 1774 ++++ .../media/platform/msm/vidc/msm_vidc_clocks.h | 48 + .../media/platform/msm/vidc/msm_vidc_common.c | 7261 +++++++++++++++++ .../media/platform/msm/vidc/msm_vidc_common.h | 264 + .../media/platform/msm/vidc/msm_vidc_debug.c | 605 ++ .../media/platform/msm/vidc/msm_vidc_debug.h | 216 + .../platform/msm/vidc/msm_vidc_internal.h | 581 ++ .../platform/msm/vidc/msm_vidc_platform.c | 1128 +++ .../platform/msm/vidc/msm_vidc_res_parse.c | 1433 ++++ .../platform/msm/vidc/msm_vidc_res_parse.h | 39 + .../platform/msm/vidc/msm_vidc_resources.h | 265 + drivers/media/platform/msm/vidc/venus_boot.c | 470 ++ drivers/media/platform/msm/vidc/venus_boot.h | 22 + drivers/media/platform/msm/vidc/venus_hfi.c | 5347 ++++++++++++ drivers/media/platform/msm/vidc/venus_hfi.h | 296 + drivers/media/platform/msm/vidc/vidc_hfi.c | 73 + drivers/media/platform/msm/vidc/vidc_hfi.h | 869 ++ .../media/platform/msm/vidc/vidc_hfi_api.h | 1523 ++++ .../media/platform/msm/vidc/vidc_hfi_helper.h | 1169 +++ drivers/media/platform/msm/vidc/vidc_hfi_io.h | 196 + include/uapi/linux/v4l2-controls.h | 187 +- include/uapi/media/msm_media_info.h | 12 + include/uapi/media/msm_vidc_utils.h | 488 +- 47 files changed, 39808 insertions(+), 354 deletions(-) create mode 100644 drivers/media/platform/msm/vidc/Kconfig create mode 100644 drivers/media/platform/msm/vidc/Makefile create mode 100644 drivers/media/platform/msm/vidc/governors/Kconfig create mode 100644 drivers/media/platform/msm/vidc/governors/Makefile create mode 100644 drivers/media/platform/msm/vidc/governors/fixedpoint.h create mode 100644 drivers/media/platform/msm/vidc/governors/msm_vidc_ar50_dyn_gov.c create mode 100644 drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c create mode 100644 drivers/media/platform/msm/vidc/hfi_packetization.c create mode 100644 drivers/media/platform/msm/vidc/hfi_packetization.h create mode 100644 drivers/media/platform/msm/vidc/hfi_response_handler.c create mode 100644 drivers/media/platform/msm/vidc/msm_cvp.c create mode 100644 drivers/media/platform/msm/vidc/msm_cvp.h create mode 100644 drivers/media/platform/msm/vidc/msm_smem.c create mode 100644 drivers/media/platform/msm/vidc/msm_v4l2_private.c create mode 100644 drivers/media/platform/msm/vidc/msm_v4l2_private.h create mode 100644 drivers/media/platform/msm/vidc/msm_v4l2_vidc.c create mode 100644 drivers/media/platform/msm/vidc/msm_vdec.c create mode 100644 drivers/media/platform/msm/vidc/msm_vdec.h create mode 100644 drivers/media/platform/msm/vidc/msm_venc.c create mode 100644 drivers/media/platform/msm/vidc/msm_venc.h create mode 100644 drivers/media/platform/msm/vidc/msm_vidc.c create mode 100644 drivers/media/platform/msm/vidc/msm_vidc.h create mode 100644 drivers/media/platform/msm/vidc/msm_vidc_clocks.c create mode 100644 drivers/media/platform/msm/vidc/msm_vidc_clocks.h create mode 100644 drivers/media/platform/msm/vidc/msm_vidc_common.c create mode 100644 drivers/media/platform/msm/vidc/msm_vidc_common.h create mode 100644 drivers/media/platform/msm/vidc/msm_vidc_debug.c create mode 100644 drivers/media/platform/msm/vidc/msm_vidc_debug.h create mode 100644 drivers/media/platform/msm/vidc/msm_vidc_internal.h create mode 100644 drivers/media/platform/msm/vidc/msm_vidc_platform.c create mode 100644 drivers/media/platform/msm/vidc/msm_vidc_res_parse.c create mode 100644 drivers/media/platform/msm/vidc/msm_vidc_res_parse.h create mode 100644 drivers/media/platform/msm/vidc/msm_vidc_resources.h create mode 100644 drivers/media/platform/msm/vidc/venus_boot.c create mode 100644 drivers/media/platform/msm/vidc/venus_boot.h create mode 100644 drivers/media/platform/msm/vidc/venus_hfi.c create mode 100644 drivers/media/platform/msm/vidc/venus_hfi.h create mode 100644 drivers/media/platform/msm/vidc/vidc_hfi.c create mode 100644 drivers/media/platform/msm/vidc/vidc_hfi.h create mode 100644 drivers/media/platform/msm/vidc/vidc_hfi_api.h create mode 100644 drivers/media/platform/msm/vidc/vidc_hfi_helper.h create mode 100644 drivers/media/platform/msm/vidc/vidc_hfi_io.h diff --git a/drivers/media/platform/msm/Kconfig b/drivers/media/platform/msm/Kconfig index 9de7fb2b9de1..8130c34d05e3 100644 --- a/drivers/media/platform/msm/Kconfig +++ b/drivers/media/platform/msm/Kconfig @@ -60,3 +60,4 @@ source "drivers/media/platform/msm/synx/Kconfig" source "drivers/media/platform/msm/dvb/Kconfig" source "drivers/media/platform/msm/broadcast/Kconfig" source "drivers/media/platform/msm/sde/Kconfig" +source "drivers/media/platform/msm/vidc/Kconfig" diff --git a/drivers/media/platform/msm/Makefile b/drivers/media/platform/msm/Makefile index 042de7015758..b86dd83e9292 100644 --- a/drivers/media/platform/msm/Makefile +++ b/drivers/media/platform/msm/Makefile @@ -12,3 +12,4 @@ obj-$(CONFIG_MSM_GLOBAL_SYNX) += synx/ obj-$(CONFIG_TSPP) += broadcast/ obj-$(CONFIG_DVB_MPQ) += dvb/ obj-$(CONFIG_MSMB_CAMERA) += camera_v2/ +obj-$(CONFIG_MSM_VIDC_LEGACY_V4L2) += vidc/ diff --git a/drivers/media/platform/msm/vidc/Kconfig b/drivers/media/platform/msm/vidc/Kconfig new file mode 100644 index 000000000000..7d31ba880b62 --- /dev/null +++ b/drivers/media/platform/msm/vidc/Kconfig @@ -0,0 +1,10 @@ +# +# VIDEO CORE +# + +menuconfig MSM_VIDC_LEGACY_V4L2 + tristate "Qualcomm Technologies, Inc. MSM V4L2 based video driver" + depends on ARCH_QCOM && VIDEO_V4L2 + select VIDEOBUF2_CORE + +source "drivers/media/platform/msm/vidc/governors/Kconfig" diff --git a/drivers/media/platform/msm/vidc/Makefile b/drivers/media/platform/msm/vidc/Makefile new file mode 100644 index 000000000000..5cb9d0c8920c --- /dev/null +++ b/drivers/media/platform/msm/vidc/Makefile @@ -0,0 +1,23 @@ +ccflags-y += -I$(srctree)/drivers/media/platform/msm/vidc/ + +msm-vidc-objs := msm_v4l2_vidc.o \ + msm_v4l2_private.o \ + msm_vidc_platform.o \ + msm_vidc_common.o \ + msm_vidc.o \ + msm_vdec.o \ + msm_venc.o \ + msm_cvp.o \ + msm_smem.o \ + msm_vidc_debug.o \ + msm_vidc_res_parse.o \ + venus_hfi.o \ + hfi_response_handler.o \ + hfi_packetization.o \ + vidc_hfi.o \ + venus_boot.o \ + msm_vidc_clocks.o + +obj-$(CONFIG_MSM_VIDC_LEGACY_V4L2) := msm-vidc.o + +obj-$(CONFIG_MSM_VIDC_LEGACY_V4L2) += governors/ diff --git a/drivers/media/platform/msm/vidc/governors/Kconfig b/drivers/media/platform/msm/vidc/governors/Kconfig new file mode 100644 index 000000000000..a8526c4441c9 --- /dev/null +++ b/drivers/media/platform/msm/vidc/governors/Kconfig @@ -0,0 +1,6 @@ +menuconfig MSM_VIDC_LEGACY_GOVERNORS + tristate "Clock and bandwidth governors for QTI MSM V4L2 based video driver" + depends on MSM_VIDC_LEGACY_V4L2 && PM_DEVFREQ + help + Chooses a set of devfreq governors aimed at providing accurate bandwidth + or clock frequency values for MSM V4L2 video driver. diff --git a/drivers/media/platform/msm/vidc/governors/Makefile b/drivers/media/platform/msm/vidc/governors/Makefile new file mode 100644 index 000000000000..f8ae4549e1a9 --- /dev/null +++ b/drivers/media/platform/msm/vidc/governors/Makefile @@ -0,0 +1,9 @@ +ccflags-y := -I$(srctree)/drivers/devfreq/ \ + -I$(srctree)/drivers/media/platform/msm/vidc/ \ + -I$(srctree)/drivers/media/platform/msm/vidc/governors/ + +msm-vidc-dyn-gov-objs := msm_vidc_dyn_gov.o + +msm-vidc-ar50-dyn-gov-objs := msm_vidc_ar50_dyn_gov.o + +obj-$(CONFIG_MSM_VIDC_LEGACY_GOVERNORS) := msm-vidc-dyn-gov.o msm-vidc-ar50-dyn-gov.o diff --git a/drivers/media/platform/msm/vidc/governors/fixedpoint.h b/drivers/media/platform/msm/vidc/governors/fixedpoint.h new file mode 100644 index 000000000000..da0781f14c4b --- /dev/null +++ b/drivers/media/platform/msm/vidc/governors/fixedpoint.h @@ -0,0 +1,72 @@ +/* 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. + */ + +#ifdef _FIXP_ARITH_H +#error "This implementation is meant to override fixp-arith.h, don't use both" +#endif + +#ifndef __FP_H__ +#define __FP_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/drivers/media/platform/msm/vidc/governors/msm_vidc_ar50_dyn_gov.c b/drivers/media/platform/msm/vidc/governors/msm_vidc_ar50_dyn_gov.c new file mode 100644 index 000000000000..fdf2b7ef0651 --- /dev/null +++ b/drivers/media/platform/msm/vidc/governors/msm_vidc_ar50_dyn_gov.c @@ -0,0 +1,978 @@ +/* Copyright (c) 2015-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. + */ + +#include +#include "governor.h" +#include "fixedpoint.h" +#include "msm_vidc_internal.h" +#include "msm_vidc_debug.h" +#include "vidc_hfi_api.h" +#define COMPRESSION_RATIO_MAX 5 + +static bool debug; +module_param(debug, bool, 0644); + +enum governor_mode { + GOVERNOR_DDR, + GOVERNOR_LLCC, +}; + +struct governor { + enum governor_mode mode; + struct devfreq_governor devfreq_gov; +}; + +/* + * Minimum dimensions that the governor is willing to calculate + * bandwidth for. 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, +}; + +/* + * These are hardcoded AB values that the governor votes for in certain + * situations, where a certain bus frequency is desired. It isn't exactly + * scalable since different platforms have different bus widths, but we'll + * deal with that in the future. + */ +static const unsigned long NOMINAL_BW_MBPS = 6000 /* ideally 320 Mhz */, + SVS_BW_MBPS = 2000 /* ideally 100 Mhz */; + +/* 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 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]; +} + +static 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 */ +} + +#define DUMP_HEADER_MAGIC 0xdeadbeef +#define DUMP_FP_FMT "%FP" /* special format for fp_t */ +struct dump { + char *key; + char *format; + size_t val; +}; + +static void __dump(struct dump dump[], int len) +{ + 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()); + + + } + } + + dprintk(VIDC_DBG, "%s", formatted_line); + } +} + +static unsigned long __calculate_vpe(struct vidc_bus_vote_data *d, + enum governor_mode gm) +{ + return 0; +} + +static 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 int __bpp(enum hal_uncompressed_format f) +{ + 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: + dprintk(VIDC_ERR, + "What's this? We don't support this colorformat (%x)", + f); + return INT_MAX; + } +} + +static unsigned long __calculate_decoder(struct vidc_bus_vote_data *d, + enum governor_mode gm) +{ + /* + * 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, dpb_bpp, opb_bpp, fps, opb_factor; + bool unified_dpb_opb, dpb_compression_enabled, opb_compression_enabled, + llc_ref_read_l2_cache_enabled = false, + llc_vpss_ds_line_buf_enabled = false; + fp_t dpb_opb_scaling_ratio, dpb_read_compression_factor, + dpb_write_compression_factor, opb_compression_factor, + qsmmu_bw_overhead_factor, height_ratio; + + /* Derived parameters */ + int lcu_per_frame, tnbr_per_lcu, colocated_bytes_per_lcu; + unsigned long bitrate; + + fp_t bins_to_bit_factor, dpb_write_factor, ten_bpc_packing_factor, + ten_bpc_bpp_factor, vsp_read_factor, vsp_write_factor, + bw_for_1x_8bpc, dpb_bw_for_1x, + motion_vector_complexity = 0, row_cache_penalty = 0, opb_bw = 0, + dpb_total = 0; + + /* Output parameters */ + struct { + fp_t vsp_read, vsp_write, collocated_read, collocated_write, + line_buffer_read, line_buffer_write, recon_read, + recon_write, opb_read, opb_write, dpb_read, dpb_write, + total; + } ddr = {0}; + + struct { + fp_t dpb_read, opb_read, 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); + + lcu_size = d->lcu_size; + + dpb_bpp = d->num_formats >= 1 ? __bpp(d->color_formats[0]) : INT_MAX; + opb_bpp = d->num_formats >= 2 ? __bpp(d->color_formats[1]) : dpb_bpp; + + fps = d->fps; + + unified_dpb_opb = d->num_formats == 1; + + dpb_opb_scaling_ratio = fp_div(FP_INT( + (int)(d->input_width * d->input_height)), + FP_INT((int)(d->output_width * d->output_height))); + height_ratio = fp_div(d->input_height, d->output_height); + + dpb_compression_enabled = d->num_formats >= 1 && + __ubwc(d->color_formats[0]); + 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_compression_factor = !opb_compression_enabled ? FP_ONE : + dpb_write_compression_factor; + + llc_ref_read_l2_cache_enabled = llc_vpss_ds_line_buf_enabled = false; + if (d->use_sys_cache) { + llc_ref_read_l2_cache_enabled = true; + llc_vpss_ds_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 = d->work_mode == VIDC_WORK_MODE_1 ? + FP_INT(0) : FP_INT(4); + + vsp_read_factor = bins_to_bit_factor + FP_INT(2); + + dpb_write_factor = FP(1, 5, 100); + + ten_bpc_packing_factor = FP(1, 67, 1000); + ten_bpc_bpp_factor = FP(1, 1, 4); + + vsp_write_factor = bins_to_bit_factor; + + tnbr_per_lcu = lcu_size == 16 ? 128 : + lcu_size == 32 ? 64 : 128; + + colocated_bytes_per_lcu = lcu_size == 16 ? 16 : + lcu_size == 32 ? 64 : 256; + + /* ........................................ for DDR */ + 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_INT(lcu_per_frame * + colocated_bytes_per_lcu * fps / bps(1)); + ddr.collocated_write = FP_INT(lcu_per_frame * + colocated_bytes_per_lcu * fps / bps(1)); + + ddr.line_buffer_read = FP_INT(tnbr_per_lcu * + lcu_per_frame * fps / bps(1)); + ddr.line_buffer_write = ddr.line_buffer_read; + + bw_for_1x_8bpc = fp_div(FP_INT((int)(width * height)), FP_INT(32 * 8)); + + bw_for_1x_8bpc = fp_mult(bw_for_1x_8bpc, + fp_div(FP_INT(((int)(256 * fps))), FP_INT(1000 * 1000))); + + dpb_bw_for_1x = dpb_bpp == 8 ? bw_for_1x_8bpc : + fp_mult(bw_for_1x_8bpc, fp_mult(ten_bpc_packing_factor, + ten_bpc_bpp_factor)); + + ddr.dpb_read = fp_div(fp_mult(fp_mult(dpb_bw_for_1x, + motion_vector_complexity), dpb_write_factor), + dpb_read_compression_factor); + + ddr.dpb_write = fp_div(fp_mult(dpb_bw_for_1x, dpb_write_factor), + dpb_write_compression_factor); + dpb_total = ddr.dpb_read + ddr.dpb_write; + if (llc_ref_read_l2_cache_enabled) { + row_cache_penalty = FP(1, 30, 100); + ddr.dpb_read = fp_div(ddr.dpb_read, row_cache_penalty); + llc.dpb_read = dpb_total - ddr.dpb_write - ddr.dpb_read; + } + + opb_factor = dpb_bpp == 8 ? 8 : 4; + + ddr.opb_read = unified_dpb_opb ? 0 : opb_compression_enabled ? + fp_div(fp_mult(fp_div(dpb_bw_for_1x, dpb_opb_scaling_ratio), + FP_INT(opb_factor)), height_ratio) : 0; + ddr.opb_write = unified_dpb_opb ? 0 : opb_compression_enabled ? + ddr.dpb_read : fp_div(fp_div(fp_mult(dpb_bw_for_1x, + FP(1, 50, 100)), dpb_opb_scaling_ratio), + opb_compression_factor); + + if (llc_vpss_ds_line_buf_enabled) { + llc.opb_read = ddr.opb_read; + ddr.opb_write -= ddr.opb_read; + ddr.opb_read = 0; + } + ddr.total = ddr.vsp_read + ddr.vsp_write + + ddr.collocated_read + ddr.collocated_write + + ddr.line_buffer_read + ddr.line_buffer_write + + ddr.opb_read + ddr.opb_write + + ddr.dpb_read + ddr.dpb_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.opb_read + ddr.total; + + /* Dump all the variables for easier debugging */ + if (debug) { + 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}, + {"OPB compression factor", DUMP_FP_FMT, + opb_compression_factor}, + {"frame width", "%d", width}, + {"frame height", "%d", height}, + + {"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}, + {"10bpc packing factor", DUMP_FP_FMT, + ten_bpc_packing_factor}, + {"10bpc,BPP factor", DUMP_FP_FMT, ten_bpc_bpp_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}, + {"colocated bytes/LCU", "%d", colocated_bytes_per_lcu}, + {"B/W for 1x (NV12 8bpc)", DUMP_FP_FMT, bw_for_1x_8bpc}, + {"DPB B/W For 1x (NV12)", DUMP_FP_FMT, dpb_bw_for_1x}, + + {"DERIVED PARAMETERS (2)", "", DUMP_HEADER_MAGIC}, + {"MV complexity", DUMP_FP_FMT, motion_vector_complexity}, + {"row cache penalty", DUMP_FP_FMT, row_cache_penalty}, + {"qsmmu_bw_overhead_factor", DUMP_FP_FMT, + qsmmu_bw_overhead_factor}, + {"OPB B/W (single instance)", DUMP_FP_FMT, opb_bw}, + + {"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}, + {"recon read", DUMP_FP_FMT, ddr.recon_read}, + {"recon write", DUMP_FP_FMT, ddr.recon_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}, + {"LLC DPB read", DUMP_FP_FMT, llc.dpb_read}, + {"LLC OPB read", DUMP_FP_FMT, llc.opb_read}, + + }; + __dump(dump, ARRAY_SIZE(dump)); + } + + switch (gm) { + case GOVERNOR_DDR: + ret = kbps(fp_round(ddr.total)); + break; + case GOVERNOR_LLCC: + ret = kbps(fp_round(llc.total)); + break; + default: + dprintk(VIDC_ERR, "%s - Unknown governor\n", __func__); + } + + return ret; +} + +static unsigned long __calculate_encoder(struct vidc_bus_vote_data *d, + enum governor_mode gm) +{ + /* + * 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, dpb_bpp, lcu_per_frame, lcu_size, + vertical_tile_width, colocated_bytes_per_lcu, bitrate, + ref_overlap_bw_factor; + enum hal_uncompressed_format dpb_color_format, original_color_format; + bool dpb_compression_enabled, original_compression_enabled, + work_mode_1, low_power, rotation, cropping_or_scaling, + b_frames_enabled = false, + llc_dual_core_ref_read_buf_enabled = false, + llc_top_line_buf_enabled = false, + llc_ref_chroma_cache_enabled = false; + fp_t dpb_compression_factor, original_compression_factor, + input_compression_factor, qsmmu_bw_overhead_factor, + ref_y_bw_factor, ref_cb_cr_bw_factor, ten_bpc_bpp_factor, + bw_for_1x_8bpc, dpb_bw_for_1x, ref_cb_cr_read, + bins_to_bit_factor, ref_y_read, ten_bpc_packing_factor, + dpb_write_factor, ref_overlap_bw, llc_ref_y_read, + llc_ref_cb_cr_read; + fp_t integer_part, frac_part; + unsigned long ret = 0; + + /* Output parameters */ + struct { + fp_t vsp_read, vsp_write, collocated_read, collocated_write, + line_buffer_read, line_buffer_write, original_read, + original_write, dpb_read, dpb_write, total; + } ddr = {0}; + + struct { + fp_t dpb_read, line_buffer, total; + } llc = {0}; + + /* Encoder Parameters setup */ + ten_bpc_packing_factor = FP(1, 67, 1000); + ten_bpc_bpp_factor = FP(1, 1, 4); + rotation = false; + cropping_or_scaling = false; + vertical_tile_width = 960; + ref_y_bw_factor = FP(1, 30, 100); + ref_cb_cr_bw_factor = FP(1, 50, 100); + dpb_write_factor = FP(1, 8, 100); + + + /* Derived Parameters */ + lcu_size = d->lcu_size; + fps = d->fps; + b_frames_enabled = d->b_frames_enabled; + width = max(d->input_width, BASELINE_DIMENSIONS.width); + height = max(d->input_height, BASELINE_DIMENSIONS.height); + bitrate = d->bitrate > 0 ? d->bitrate / 1000000 : + __lut(width, height, fps)->bitrate; + lcu_per_frame = DIV_ROUND_UP(width, lcu_size) * + DIV_ROUND_UP(height, lcu_size); + + dpb_color_format = HAL_COLOR_FORMAT_NV12_UBWC; + 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]) : INT_MAX; + + dpb_compression_enabled = __ubwc(dpb_color_format); + original_compression_enabled = __ubwc(original_color_format); + + work_mode_1 = d->work_mode == VIDC_WORK_MODE_1; + low_power = d->power_mode == VIDC_POWER_LOW; + bins_to_bit_factor = work_mode_1 ? + FP_INT(0) : FP_INT(4); + + if (d->use_sys_cache) { + llc_dual_core_ref_read_buf_enabled = true; + llc_ref_chroma_cache_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); + + /* use input cr if it is valid (not 1), otherwise use lut */ + original_compression_factor = + !original_compression_enabled ? FP_ONE : + input_compression_factor != FP_ONE ? input_compression_factor : + __compression_ratio(__lut(width, height, fps), dpb_bpp); + + ddr.vsp_read = fp_mult(fp_div(FP_INT(bitrate), FP_INT(8)), + bins_to_bit_factor); + ddr.vsp_write = ddr.vsp_read + fp_div(FP_INT(bitrate), FP_INT(8)); + + colocated_bytes_per_lcu = lcu_size == 16 ? 16 : + lcu_size == 32 ? 64 : 256; + + ddr.collocated_read = FP_INT(lcu_per_frame * + colocated_bytes_per_lcu * fps / bps(1)); + + ddr.collocated_write = ddr.collocated_read; + + ddr.line_buffer_read = FP_INT(16 * lcu_per_frame * fps / bps(1)); + + ddr.line_buffer_write = ddr.line_buffer_read; + + llc.line_buffer = ddr.line_buffer_read + ddr.line_buffer_write; + if (llc_top_line_buf_enabled) + ddr.line_buffer_read = ddr.line_buffer_write = FP_INT(0); + + llc.line_buffer -= (ddr.line_buffer_read + ddr.line_buffer_write); + + bw_for_1x_8bpc = fp_div(FP_INT((int)(width * height)), FP_INT(32 * 8)); + + bw_for_1x_8bpc = fp_mult(bw_for_1x_8bpc, + fp_div(FP_INT(((int)(256 * fps))), FP_INT(1000 * 1000))); + + dpb_bw_for_1x = dpb_bpp == 8 ? bw_for_1x_8bpc : + fp_mult(bw_for_1x_8bpc, fp_mult(ten_bpc_packing_factor, + ten_bpc_bpp_factor)); + + ddr.original_read = fp_div(fp_mult(FP(1, 50, 100), dpb_bw_for_1x), + input_compression_factor); + + ddr.original_write = FP_ZERO; + + ref_y_bw_factor = + width == vertical_tile_width ? FP_INT(1) : ref_y_bw_factor; + + ref_y_read = fp_mult(ref_y_bw_factor, dpb_bw_for_1x); + + ref_y_read = fp_div(ref_y_read, dpb_compression_factor); + + ref_y_read = + b_frames_enabled ? fp_mult(ref_y_read, FP_INT(2)) : ref_y_read; + + llc_ref_y_read = ref_y_read; + if (llc_dual_core_ref_read_buf_enabled) + ref_y_read = fp_div(ref_y_read, FP_INT(2)); + + llc_ref_y_read -= ref_y_read; + + ref_cb_cr_read = fp_mult(ref_cb_cr_bw_factor, dpb_bw_for_1x) / 2; + + ref_cb_cr_read = fp_div(ref_cb_cr_read, dpb_compression_factor); + + ref_cb_cr_read = + b_frames_enabled ? fp_mult(ref_cb_cr_read, FP_INT(2)) : + ref_cb_cr_read; + + llc_ref_cb_cr_read = ref_cb_cr_read; + + if (llc_ref_chroma_cache_enabled) + ref_cb_cr_read = fp_div(ref_cb_cr_read, ref_cb_cr_bw_factor); + + if (llc_dual_core_ref_read_buf_enabled) + ref_cb_cr_read = fp_div(ref_cb_cr_read, FP_INT(2)); + + llc_ref_cb_cr_read -= ref_cb_cr_read; + + ddr.dpb_write = fp_mult(dpb_write_factor, dpb_bw_for_1x); + + ddr.dpb_write = fp_mult(ddr.dpb_write, FP(1, 50, 100)); + + ddr.dpb_write = fp_div(ddr.dpb_write, dpb_compression_factor); + + ref_overlap_bw_factor = + width <= vertical_tile_width ? FP_INT(0) : FP_INT(1); + + ref_overlap_bw = fp_mult(ddr.dpb_write, ref_overlap_bw_factor); + + ref_overlap_bw = fp_div(ref_overlap_bw, dpb_write_factor); + + ref_overlap_bw = fp_mult(ref_overlap_bw, + (dpb_write_factor - FP_INT(1))); + + ddr.dpb_read = ref_y_read + ref_cb_cr_read + ref_overlap_bw; + + llc.dpb_read = llc_ref_y_read + llc_ref_cb_cr_read; + + ddr.total = ddr.vsp_read + ddr.vsp_write + + ddr.collocated_read + ddr.collocated_write + + ddr.line_buffer_read + ddr.line_buffer_write + + ddr.original_read + ddr.original_write + + ddr.dpb_read + ddr.dpb_write; + + llc.total = llc.dpb_read + llc.line_buffer + ddr.total; + + qsmmu_bw_overhead_factor = FP(1, 3, 100); + ddr.total = fp_mult(ddr.total, qsmmu_bw_overhead_factor); + + if (debug) { + struct dump dump[] = { + {"ENCODER PARAMETERS", "", DUMP_HEADER_MAGIC}, + {"width", "%d", width}, + {"height", "%d", height}, + {"DPB format", "%#x", dpb_color_format}, + {"original frame format", "%#x", original_color_format}, + {"fps", "%d", fps}, + {"DPB compression enable", "%d", dpb_compression_enabled}, + {"original compression enable", "%d", + original_compression_enabled}, + {"low power mode", "%d", low_power}, + {"Work Mode", "%d", work_mode_1}, + {"DPB compression factor", DUMP_FP_FMT, + dpb_compression_factor}, + {"original compression factor", DUMP_FP_FMT, + original_compression_factor}, + {"rotation", "%d", rotation}, + {"cropping or scaling", "%d", cropping_or_scaling}, + + {"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}, + {"qsmmu_bw_overhead_factor", + DUMP_FP_FMT, qsmmu_bw_overhead_factor}, + + {"INTERMEDIATE B/W DDR", "", DUMP_HEADER_MAGIC}, + {"ref_y_read", DUMP_FP_FMT, ref_y_read}, + {"ref_cb_cr_read", DUMP_FP_FMT, ref_cb_cr_read}, + {"ref_overlap_bw", DUMP_FP_FMT, ref_overlap_bw}, + {"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}, + {"original read", DUMP_FP_FMT, ddr.original_read}, + {"original write", DUMP_FP_FMT, ddr.original_write}, + {"DPB read", DUMP_FP_FMT, ddr.dpb_read}, + {"DPB write", DUMP_FP_FMT, ddr.dpb_write}, + {"LLC DPB read", DUMP_FP_FMT, llc.dpb_read}, + {"LLC Line buffer", DUMP_FP_FMT, llc.line_buffer}, + }; + __dump(dump, ARRAY_SIZE(dump)); + } + + switch (gm) { + case GOVERNOR_DDR: + ret = kbps(fp_round(ddr.total)); + break; + case GOVERNOR_LLCC: + ret = kbps(fp_round(llc.total)); + break; + default: + dprintk(VIDC_ERR, "%s - Unknown governor\n", __func__); + } + + return ret; +} + +static unsigned long __calculate(struct vidc_bus_vote_data *d, + enum governor_mode gm) +{ + unsigned long (*calc[])(struct vidc_bus_vote_data *, + enum governor_mode) = { + [HAL_VIDEO_DOMAIN_VPE] = __calculate_vpe, + [HAL_VIDEO_DOMAIN_ENCODER] = __calculate_encoder, + [HAL_VIDEO_DOMAIN_DECODER] = __calculate_decoder, + }; + + if (d->domain >= ARRAY_SIZE(calc)) { + dprintk(VIDC_ERR, "%s: invalid domain %d\n", + __func__, d->domain); + return 0; + } + return calc[d->domain](d, gm); +} + + +static int __get_target_freq(struct devfreq *dev, unsigned long *freq) +{ + unsigned long ab_kbps = 0, c = 0; + struct devfreq_dev_status stats = {0}; + struct msm_vidc_gov_data *vidc_data = NULL; + struct governor *gov = NULL; + + if (!dev || !freq) + return -EINVAL; + + gov = container_of(dev->governor, + struct governor, devfreq_gov); + dev->profile->get_dev_status(dev->dev.parent, &stats); + vidc_data = (struct msm_vidc_gov_data *)stats.private_data; + + if (!vidc_data || !vidc_data->data_count) + goto exit; + + for (c = 0; c < vidc_data->data_count; ++c) { + if (vidc_data->data->power_mode == VIDC_POWER_TURBO) { + ab_kbps = INT_MAX; + goto exit; + } + } + + for (c = 0; c < vidc_data->data_count; ++c) + ab_kbps += __calculate(&vidc_data->data[c], gov->mode); + +exit: + *freq = clamp(ab_kbps, dev->min_freq, dev->max_freq ?: UINT_MAX); + trace_msm_vidc_perf_bus_vote(gov->devfreq_gov.name, *freq); + return 0; +} + +static int __event_handler(struct devfreq *devfreq, unsigned int event, + void *data) +{ + int rc = 0; + + if (!devfreq) + return -EINVAL; + + switch (event) { + case DEVFREQ_GOV_START: + mutex_lock(&devfreq->lock); + rc = update_devfreq(devfreq); + mutex_unlock(&devfreq->lock); + break; + } + + return rc; +} + +static struct governor governors[] = { + { + .mode = GOVERNOR_DDR, + .devfreq_gov = { + .name = "vidc-ar50-ddr", + .get_target_freq = __get_target_freq, + .event_handler = __event_handler, + }, + }, + { + .mode = GOVERNOR_LLCC, + .devfreq_gov = { + .name = "vidc-ar50-llcc", + .get_target_freq = __get_target_freq, + .event_handler = __event_handler, + }, + }, +}; + +static int __init msm_vidc_ar50_bw_gov_init(void) +{ + int c = 0, rc = 0; + + for (c = 0; c < ARRAY_SIZE(governors); ++c) { + dprintk(VIDC_DBG, "Adding governor %s\n", + governors[c].devfreq_gov.name); + + rc = devfreq_add_governor(&governors[c].devfreq_gov); + if (rc) { + dprintk(VIDC_ERR, "Error adding governor %s: %d\n", + governors[c].devfreq_gov.name, rc); + break; + } + } + + return rc; +} +module_init(msm_vidc_ar50_bw_gov_init); + +static void __exit msm_vidc_ar50_bw_gov_exit(void) +{ + int c = 0; + + for (c = 0; c < ARRAY_SIZE(governors); ++c) { + dprintk(VIDC_DBG, "Removing governor %s\n", + governors[c].devfreq_gov.name); + devfreq_remove_governor(&governors[c].devfreq_gov); + } +} +module_exit(msm_vidc_ar50_bw_gov_exit); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c b/drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c new file mode 100644 index 000000000000..c434e864d6da --- /dev/null +++ b/drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c @@ -0,0 +1,1020 @@ +/* Copyright (c) 2015-2020, 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 "governor.h" +#include "fixedpoint.h" +#include "msm_vidc_internal.h" +#include "msm_vidc_debug.h" +#include "vidc_hfi_api.h" +#define COMPRESSION_RATIO_MAX 5 + +static bool debug; +module_param(debug, bool, 0644); + +enum governor_mode { + GOVERNOR_DDR, + GOVERNOR_LLCC, +}; + +struct governor { + enum governor_mode mode; + struct devfreq_governor devfreq_gov; +}; + +/* + * Minimum dimensions that the governor is willing to calculate + * bandwidth for. 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, +}; + +/* + * These are hardcoded AB values that the governor votes for in certain + * situations, where a certain bus frequency is desired. It isn't exactly + * scalable since different platforms have different bus widths, but we'll + * deal with that in the future. + */ +const unsigned long NOMINAL_BW_MBPS = 6000 /* ideally 320 Mhz */, + SVS_BW_MBPS = 2000 /* ideally 100 Mhz */; + +/* 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 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]; +} + +static 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 */ +} + +#define DUMP_HEADER_MAGIC 0xdeadbeef +#define DUMP_FP_FMT "%FP" /* special format for fp_t */ +struct dump { + char *key; + char *format; + size_t val; +}; + +static void __dump(struct dump dump[], int len) +{ + 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()); + + + } + } + + dprintk(VIDC_DBG, "%s", formatted_line); + } +} + +static unsigned long __calculate_vpe(struct vidc_bus_vote_data *d, + enum governor_mode gm) +{ + return 0; +} + +static unsigned long __calculate_cvp(struct vidc_bus_vote_data *d, + enum governor_mode gm) +{ + unsigned long ret = 0; + + switch (gm) { + case GOVERNOR_DDR: + ret = d->ddr_bw; + break; + case GOVERNOR_LLCC: + ret = d->sys_cache_bw; + break; + default: + dprintk(VIDC_ERR, "%s - Unknown governor\n", __func__); + break; + } + + return ret; +} + +static 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 int __bpp(enum hal_uncompressed_format f) +{ + 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: + dprintk(VIDC_ERR, + "What's this? We don't support this colorformat (%x)", + f); + return INT_MAX; + } +} + +static unsigned long __calculate_decoder(struct vidc_bus_vote_data *d, + enum governor_mode gm) +{ + /* + * 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]) : 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, 15, 100) : FP(1, 30, 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 (debug) { + 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)); + } + + switch (gm) { + case GOVERNOR_DDR: + ret = kbps(fp_round(ddr.total)); + break; + case GOVERNOR_LLCC: + ret = kbps(fp_round(llc.total)); + break; + default: + dprintk(VIDC_ERR, "%s - Unknown governor\n", __func__); + } + + return ret; +} + +static unsigned long __calculate_encoder(struct vidc_bus_vote_data *d, + enum governor_mode gm) +{ + /* + * 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; + + 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]) : INT_MAX; + + original_compression_enabled = __ubwc(original_color_format); + + work_mode_1 = d->work_mode == VIDC_WORK_MODE_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 (debug) { + 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)); + } + + switch (gm) { + case GOVERNOR_DDR: + ret = kbps(fp_round(ddr.total)); + break; + case GOVERNOR_LLCC: + ret = kbps(fp_round(llc.total)); + break; + default: + dprintk(VIDC_ERR, "%s - Unknown governor\n", __func__); + } + + return ret; +} + +static unsigned long __calculate(struct vidc_bus_vote_data *d, + enum governor_mode gm) +{ + unsigned long (*calc[])(struct vidc_bus_vote_data *, + enum governor_mode) = { + [HAL_VIDEO_DOMAIN_VPE] = __calculate_vpe, + [HAL_VIDEO_DOMAIN_ENCODER] = __calculate_encoder, + [HAL_VIDEO_DOMAIN_DECODER] = __calculate_decoder, + [HAL_VIDEO_DOMAIN_CVP] = __calculate_cvp, + }; + + if (d->domain >= ARRAY_SIZE(calc)) { + dprintk(VIDC_ERR, "%s: invalid domain %d\n", + __func__, d->domain); + return 0; + } + return calc[d->domain](d, gm); +} + + +static int __get_target_freq(struct devfreq *dev, unsigned long *freq) +{ + unsigned long ab_kbps = 0, c = 0; + struct devfreq_dev_status stats = {0}; + struct msm_vidc_gov_data *vidc_data = NULL; + struct governor *gov = NULL; + + if (!dev || !freq) + return -EINVAL; + + gov = container_of(dev->governor, + struct governor, devfreq_gov); + dev->profile->get_dev_status(dev->dev.parent, &stats); + vidc_data = (struct msm_vidc_gov_data *)stats.private_data; + + if (!vidc_data || !vidc_data->data_count) + goto exit; + + for (c = 0; c < vidc_data->data_count; ++c) { + if (vidc_data->data->power_mode == VIDC_POWER_TURBO) { + ab_kbps = INT_MAX; + goto exit; + } + } + + for (c = 0; c < vidc_data->data_count; ++c) + ab_kbps += __calculate(&vidc_data->data[c], gov->mode); + +exit: + *freq = clamp(ab_kbps, dev->min_freq, dev->max_freq ?: UINT_MAX); + trace_msm_vidc_perf_bus_vote(gov->devfreq_gov.name, *freq); + return 0; +} + +static int __event_handler(struct devfreq *devfreq, unsigned int event, + void *data) +{ + int rc = 0; + + if (!devfreq) + return -EINVAL; + + switch (event) { + case DEVFREQ_GOV_START: + mutex_lock(&devfreq->lock); + rc = update_devfreq(devfreq); + mutex_unlock(&devfreq->lock); + break; + } + + return rc; +} + +static struct governor governors[] = { + { + .mode = GOVERNOR_DDR, + .devfreq_gov = { + .name = "msm-vidc-ddr", + .get_target_freq = __get_target_freq, + .event_handler = __event_handler, + }, + }, + { + .mode = GOVERNOR_LLCC, + .devfreq_gov = { + .name = "msm-vidc-llcc", + .get_target_freq = __get_target_freq, + .event_handler = __event_handler, + }, + }, +}; + +static int __init msm_vidc_bw_gov_init(void) +{ + int c = 0, rc = 0; + + for (c = 0; c < ARRAY_SIZE(governors); ++c) { + dprintk(VIDC_DBG, "Adding governor %s\n", + governors[c].devfreq_gov.name); + + rc = devfreq_add_governor(&governors[c].devfreq_gov); + if (rc) { + dprintk(VIDC_ERR, "Error adding governor %s: %d\n", + governors[c].devfreq_gov.name, rc); + break; + } + } + + return rc; +} +module_init(msm_vidc_bw_gov_init); + +static void __exit msm_vidc_bw_gov_exit(void) +{ + int c = 0; + + for (c = 0; c < ARRAY_SIZE(governors); ++c) { + dprintk(VIDC_DBG, "Removing governor %s\n", + governors[c].devfreq_gov.name); + devfreq_remove_governor(&governors[c].devfreq_gov); + } +} +module_exit(msm_vidc_bw_gov_exit); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c new file mode 100644 index 000000000000..fc51f6ddd5f1 --- /dev/null +++ b/drivers/media/platform/msm/vidc/hfi_packetization.c @@ -0,0 +1,2206 @@ +/* Copyright (c) 2012-2020, 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 "hfi_packetization.h" +#include "msm_vidc_debug.h" + +/* Set up look-up tables to convert HAL_* to HFI_*. + * + * The tables below mostly take advantage of the fact that most + * HAL_* types are defined bitwise. So if we index them normally + * when declaring the tables, we end up with huge arrays with wasted + * space. So before indexing them, we apply log2 to use a more + * sensible index. + */ + +static int entropy_mode[] = { + [ilog2(HAL_H264_ENTROPY_CAVLC)] = HFI_H264_ENTROPY_CAVLC, + [ilog2(HAL_H264_ENTROPY_CABAC)] = HFI_H264_ENTROPY_CABAC, +}; + +static int statistics_mode[] = { + [ilog2(HAL_STATISTICS_MODE_DEFAULT)] = HFI_STATISTICS_MODE_DEFAULT, + [ilog2(HAL_STATISTICS_MODE_1)] = HFI_STATISTICS_MODE_1, + [ilog2(HAL_STATISTICS_MODE_2)] = HFI_STATISTICS_MODE_2, + [ilog2(HAL_STATISTICS_MODE_3)] = HFI_STATISTICS_MODE_3, +}; + +static int color_format[] = { + [ilog2(HAL_COLOR_FORMAT_MONOCHROME)] = HFI_COLOR_FORMAT_MONOCHROME, + [ilog2(HAL_COLOR_FORMAT_NV12)] = HFI_COLOR_FORMAT_NV12, + [ilog2(HAL_COLOR_FORMAT_NV21)] = HFI_COLOR_FORMAT_NV21, + [ilog2(HAL_COLOR_FORMAT_NV12_4x4TILE)] = HFI_COLOR_FORMAT_NV12_4x4TILE, + [ilog2(HAL_COLOR_FORMAT_NV21_4x4TILE)] = HFI_COLOR_FORMAT_NV21_4x4TILE, + [ilog2(HAL_COLOR_FORMAT_YUYV)] = HFI_COLOR_FORMAT_YUYV, + [ilog2(HAL_COLOR_FORMAT_YVYU)] = HFI_COLOR_FORMAT_YVYU, + [ilog2(HAL_COLOR_FORMAT_UYVY)] = HFI_COLOR_FORMAT_UYVY, + [ilog2(HAL_COLOR_FORMAT_VYUY)] = HFI_COLOR_FORMAT_VYUY, + [ilog2(HAL_COLOR_FORMAT_RGB565)] = HFI_COLOR_FORMAT_RGB565, + [ilog2(HAL_COLOR_FORMAT_BGR565)] = HFI_COLOR_FORMAT_BGR565, + [ilog2(HAL_COLOR_FORMAT_RGB888)] = HFI_COLOR_FORMAT_RGB888, + [ilog2(HAL_COLOR_FORMAT_BGR888)] = HFI_COLOR_FORMAT_BGR888, + /* UBWC Color formats*/ + [ilog2(HAL_COLOR_FORMAT_NV12_UBWC)] = HFI_COLOR_FORMAT_NV12_UBWC, + [ilog2(HAL_COLOR_FORMAT_NV12_TP10_UBWC)] = + HFI_COLOR_FORMAT_YUV420_TP10_UBWC, + /*P010 10bit format*/ + [ilog2(HAL_COLOR_FORMAT_P010)] = HFI_COLOR_FORMAT_P010, + [ilog2(HAL_COLOR_FORMAT_NV12_512)] = HFI_COLOR_FORMAT_NV12, +}; + +static int nal_type[] = { + [ilog2(HAL_NAL_FORMAT_STARTCODES)] = HFI_NAL_FORMAT_STARTCODES, + [ilog2(HAL_NAL_FORMAT_ONE_NAL_PER_BUFFER)] = + HFI_NAL_FORMAT_ONE_NAL_PER_BUFFER, + [ilog2(HAL_NAL_FORMAT_ONE_BYTE_LENGTH)] = + HFI_NAL_FORMAT_ONE_BYTE_LENGTH, + [ilog2(HAL_NAL_FORMAT_TWO_BYTE_LENGTH)] = + HFI_NAL_FORMAT_TWO_BYTE_LENGTH, + [ilog2(HAL_NAL_FORMAT_FOUR_BYTE_LENGTH)] = + HFI_NAL_FORMAT_FOUR_BYTE_LENGTH, +}; + +static inline int hal_to_hfi_type(int property, int hal_type) +{ + if (hal_type <= 0 || roundup_pow_of_two(hal_type) != hal_type) { + /* + * Not a power of 2, it's not going + * to be in any of the tables anyway + */ + return -EINVAL; + } + + if (hal_type) + hal_type = ilog2(hal_type); + + switch (property) { + case HAL_PARAM_VENC_H264_ENTROPY_CONTROL: + return (hal_type >= ARRAY_SIZE(entropy_mode)) ? + -ENOTSUPP : entropy_mode[hal_type]; + case HAL_PARAM_UNCOMPRESSED_FORMAT_SELECT: + return (hal_type >= ARRAY_SIZE(color_format)) ? + -ENOTSUPP : color_format[hal_type]; + case HAL_PARAM_NAL_STREAM_FORMAT_SELECT: + return (hal_type >= ARRAY_SIZE(nal_type)) ? + -ENOTSUPP : nal_type[hal_type]; + case HAL_PARAM_VENC_MBI_STATISTICS_MODE: + return (hal_type >= ARRAY_SIZE(statistics_mode)) ? + -ENOTSUPP : statistics_mode[hal_type]; + default: + return -ENOTSUPP; + } +} + +enum hal_domain vidc_get_hal_domain(u32 hfi_domain) +{ + enum hal_domain hal_domain = 0; + + switch (hfi_domain) { + case HFI_VIDEO_DOMAIN_VPE: + hal_domain = HAL_VIDEO_DOMAIN_VPE; + break; + case HFI_VIDEO_DOMAIN_ENCODER: + hal_domain = HAL_VIDEO_DOMAIN_ENCODER; + break; + case HFI_VIDEO_DOMAIN_DECODER: + hal_domain = HAL_VIDEO_DOMAIN_DECODER; + break; + case HFI_VIDEO_DOMAIN_CVP: + hal_domain = HAL_VIDEO_DOMAIN_CVP; + break; + default: + dprintk(VIDC_ERR, "%s: invalid domain %x\n", + __func__, hfi_domain); + hal_domain = 0; + break; + } + return hal_domain; +} + +enum hal_video_codec vidc_get_hal_codec(u32 hfi_codec) +{ + enum hal_video_codec hal_codec = 0; + + switch (hfi_codec) { + case HFI_VIDEO_CODEC_H264: + hal_codec = HAL_VIDEO_CODEC_H264; + break; + case HFI_VIDEO_CODEC_MPEG1: + hal_codec = HAL_VIDEO_CODEC_MPEG1; + break; + case HFI_VIDEO_CODEC_MPEG2: + hal_codec = HAL_VIDEO_CODEC_MPEG2; + break; + case HFI_VIDEO_CODEC_VP8: + hal_codec = HAL_VIDEO_CODEC_VP8; + break; + case HFI_VIDEO_CODEC_HEVC: + hal_codec = HAL_VIDEO_CODEC_HEVC; + break; + case HFI_VIDEO_CODEC_VP9: + hal_codec = HAL_VIDEO_CODEC_VP9; + break; + case HFI_VIDEO_CODEC_TME: + hal_codec = HAL_VIDEO_CODEC_TME; + break; + case HFI_VIDEO_CODEC_CVP: + hal_codec = HAL_VIDEO_CODEC_CVP; + break; + default: + dprintk(VIDC_INFO, "%s: invalid codec 0x%x\n", + __func__, hfi_codec); + hal_codec = 0; + break; + } + return hal_codec; +} + + +u32 vidc_get_hfi_domain(enum hal_domain hal_domain) +{ + 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: + dprintk(VIDC_ERR, "%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 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: + dprintk(VIDC_INFO, "%s: invalid codec 0x%x\n", + __func__, hal_codec); + hfi_codec = 0; + break; + } + return hfi_codec; +} + +static void create_pkt_enable(void *pkt, u32 type, bool enable) +{ + u32 *pkt_header = pkt; + u32 *pkt_type = &pkt_header[0]; + struct hfi_enable *hfi_enable = (struct hfi_enable *)&pkt_header[1]; + + *pkt_type = type; + hfi_enable->enable = enable; +} + +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) +{ + if (!pkt) { + dprintk(VIDC_ERR, "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; + dprintk(VIDC_DBG, "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) { + dprintk(VIDC_ERR, + "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]; + dprintk(VIDC_DBG, "entry hfi#%d, sc_id %d, size %d\n", + i, hfi_sc[i].sc_id, hfi_sc[i].size); + } + break; + } + default: + dprintk(VIDC_ERR, + "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) { + dprintk(VIDC_ERR, + "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: + dprintk(VIDC_ERR, + "Invalid resource_id %d\n", res_hdr->resource_id); + rc = -ENOTSUPP; + } + + dprintk(VIDC_DBG, + "rel_res: pkt_type 0x%x res_type 0x%x prepared\n", + pkt->packet_type, pkt->resource_type); + + return rc; +} + +int create_pkt_cmd_sys_ping(struct hfi_cmd_sys_ping_packet *pkt) +{ + int rc = 0; + + if (!pkt) + return -EINVAL; + + pkt->size = sizeof(struct hfi_cmd_sys_ping_packet); + pkt->packet_type = HFI_CMD_SYS_PING; + + return rc; +} + +inline int create_pkt_cmd_sys_session_init( + struct hfi_cmd_sys_session_init_packet *pkt, + struct hal_session *session, + 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->session_id = hash32_ptr(session); + pkt->session_domain = vidc_get_hfi_domain(session_domain); + pkt->session_codec = vidc_get_hfi_codec(session_codec); + if (!pkt->session_codec) + return -EINVAL; + + return rc; +} + +int create_pkt_cmd_session_cmd(struct vidc_hal_session_cmd_pkt *pkt, + int pkt_type, struct hal_session *session) +{ + int rc = 0; + + if (!pkt) + return -EINVAL; + + pkt->size = sizeof(struct vidc_hal_session_cmd_pkt); + pkt->packet_type = pkt_type; + pkt->session_id = hash32_ptr(session); + + 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) { + dprintk(VIDC_ERR, "No input packet\n"); + 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 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: + dprintk(VIDC_ERR, "Invalid buffer: %#x\n", + hal_buffer); + buffer = 0; + break; + } + return buffer; +} + +static int get_hfi_extradata_index(enum hal_extradata_id index) +{ + int ret = 0; + + switch (index) { + case HAL_EXTRADATA_INTERLACE_VIDEO: + ret = HFI_PROPERTY_PARAM_VDEC_INTERLACE_VIDEO_EXTRADATA; + break; + case HAL_EXTRADATA_TIMESTAMP: + ret = HFI_PROPERTY_PARAM_VDEC_TIMESTAMP_EXTRADATA; + break; + case HAL_EXTRADATA_S3D_FRAME_PACKING: + ret = HFI_PROPERTY_PARAM_S3D_FRAME_PACKING_EXTRADATA; + break; + case HAL_EXTRADATA_FRAME_RATE: + ret = HFI_PROPERTY_PARAM_VDEC_FRAME_RATE_EXTRADATA; + break; + case HAL_EXTRADATA_PANSCAN_WINDOW: + ret = HFI_PROPERTY_PARAM_VDEC_PANSCAN_WNDW_EXTRADATA; + break; + case HAL_EXTRADATA_RECOVERY_POINT_SEI: + ret = HFI_PROPERTY_PARAM_VDEC_RECOVERY_POINT_SEI_EXTRADATA; + break; + case HAL_EXTRADATA_NUM_CONCEALED_MB: + ret = HFI_PROPERTY_PARAM_VDEC_NUM_CONCEALED_MB; + break; + case HAL_EXTRADATA_ASPECT_RATIO: + case HAL_EXTRADATA_OUTPUT_CROP: + case HAL_EXTRADATA_INPUT_CROP: + ret = HFI_PROPERTY_PARAM_INDEX_EXTRADATA; + break; + case HAL_EXTRADATA_MPEG2_SEQDISP: + ret = HFI_PROPERTY_PARAM_VDEC_MPEG2_SEQDISP_EXTRADATA; + break; + case HAL_EXTRADATA_STREAM_USERDATA: + ret = HFI_PROPERTY_PARAM_VDEC_STREAM_USERDATA_EXTRADATA; + break; + case HAL_EXTRADATA_DEC_FRAME_QP: + ret = HFI_PROPERTY_PARAM_VDEC_FRAME_QP_EXTRADATA; + break; + case HAL_EXTRADATA_ENC_FRAME_QP: + ret = HFI_PROPERTY_PARAM_VENC_FRAME_QP_EXTRADATA; + break; + case HAL_EXTRADATA_LTR_INFO: + ret = HFI_PROPERTY_PARAM_VENC_LTR_INFO; + break; + case HAL_EXTRADATA_ROI_QP: + ret = HFI_PROPERTY_PARAM_VENC_ROI_QP_EXTRADATA; + break; + case HAL_EXTRADATA_MASTERING_DISPLAY_COLOUR_SEI: + ret = + HFI_PROPERTY_PARAM_VDEC_MASTERING_DISPLAY_COLOUR_SEI_EXTRADATA; + break; + case HAL_EXTRADATA_CONTENT_LIGHT_LEVEL_SEI: + ret = HFI_PROPERTY_PARAM_VDEC_CONTENT_LIGHT_LEVEL_SEI_EXTRADATA; + break; + case HAL_EXTRADATA_VUI_DISPLAY_INFO: + ret = HFI_PROPERTY_PARAM_VUI_DISPLAY_INFO_EXTRADATA; + break; + case HAL_EXTRADATA_VPX_COLORSPACE: + ret = HFI_PROPERTY_PARAM_VDEC_VPX_COLORSPACE_EXTRADATA; + break; + case HAL_EXTRADATA_UBWC_CR_STATS_INFO: + ret = HFI_PROPERTY_PARAM_VDEC_UBWC_CR_STAT_INFO_EXTRADATA; + break; + case HAL_EXTRADATA_HDR10PLUS_METADATA: + ret = HFI_PROPERTY_PARAM_VENC_HDR10PLUS_METADATA_EXTRADATA; + break; + case HAL_EXTRADATA_ENC_DTS_METADATA: + ret = HFI_PROPERTY_PARAM_VENC_DTS_INFO; + break; + default: + dprintk(VIDC_WARN, "Extradata index not found: %d\n", index); + break; + } + return ret; +} + +static int get_hfi_extradata_id(enum hal_extradata_id index) +{ + int ret = 0; + + switch (index) { + case HAL_EXTRADATA_ASPECT_RATIO: + ret = MSM_VIDC_EXTRADATA_ASPECT_RATIO; + break; + case HAL_EXTRADATA_OUTPUT_CROP: + ret = MSM_VIDC_EXTRADATA_OUTPUT_CROP; + break; + case HAL_EXTRADATA_INPUT_CROP: + ret = MSM_VIDC_EXTRADATA_INPUT_CROP; + break; + default: + ret = get_hfi_extradata_index(index); + break; + } + return ret; +} + +static u32 get_hfi_ltr_mode(enum ltr_mode ltr_mode_type) +{ + u32 ltrmode; + + switch (ltr_mode_type) { + case HAL_LTR_MODE_DISABLE: + ltrmode = HFI_LTR_MODE_DISABLE; + break; + case HAL_LTR_MODE_MANUAL: + ltrmode = HFI_LTR_MODE_MANUAL; + break; + default: + dprintk(VIDC_ERR, "Invalid ltr mode: %#x\n", + ltr_mode_type); + ltrmode = HFI_LTR_MODE_DISABLE; + break; + } + return ltrmode; +} + +static u32 get_hfi_work_mode(enum hal_work_mode work_mode) +{ + u32 hfi_work_mode; + + switch (work_mode) { + case VIDC_WORK_MODE_1: + hfi_work_mode = HFI_WORKMODE_1; + break; + case VIDC_WORK_MODE_2: + hfi_work_mode = HFI_WORKMODE_2; + break; + default: + dprintk(VIDC_ERR, "Invalid work mode: %#x\n", + work_mode); + hfi_work_mode = HFI_WORKMODE_2; + break; + } + return hfi_work_mode; +} + +int create_pkt_cmd_session_set_buffers( + struct hfi_cmd_session_set_buffers_packet *pkt, + struct hal_session *session, + struct vidc_buffer_addr_info *buffer_info) +{ + int rc = 0; + int i = 0; + + if (!pkt || !session) + return -EINVAL; + + pkt->packet_type = HFI_CMD_SESSION_SET_BUFFERS; + pkt->session_id = hash32_ptr(session); + 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); + if (!pkt->buffer_type) + return -EINVAL; + + return rc; +} + +int create_pkt_cmd_session_release_buffers( + struct hfi_cmd_session_release_buffer_packet *pkt, + struct hal_session *session, + struct vidc_buffer_addr_info *buffer_info) +{ + int rc = 0; + int i = 0; + + if (!pkt || !session) + return -EINVAL; + + pkt->packet_type = HFI_CMD_SESSION_RELEASE_BUFFERS; + pkt->session_id = hash32_ptr(session); + 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); + if (!pkt->buffer_type) + return -EINVAL; + return rc; +} + +int create_pkt_cmd_session_register_buffer( + struct hfi_cmd_session_register_buffers_packet *pkt, + struct hal_session *session, + struct vidc_register_buffer *buffer) +{ + int rc = 0, i; + struct hfi_buffer_mapping_type *buf; + + if (!pkt || !session) { + dprintk(VIDC_ERR, "%s: invalid params\n", __func__); + return -EINVAL; + } + + pkt->packet_type = HFI_CMD_SESSION_REGISTER_BUFFERS; + pkt->session_id = hash32_ptr(session); + 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, + struct hal_session *session, + struct vidc_unregister_buffer *buffer) +{ + int rc = 0, i; + struct hfi_buffer_mapping_type *buf; + + if (!pkt || !session) { + dprintk(VIDC_ERR, "%s: invalid params\n", __func__); + return -EINVAL; + } + + pkt->packet_type = HFI_CMD_SESSION_UNREGISTER_BUFFERS; + pkt->session_id = hash32_ptr(session); + 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, + struct hal_session *session, struct vidc_frame_data *input_frame) +{ + int rc = 0; + + if (!pkt || !session) + return -EINVAL; + + pkt->size = + sizeof(struct hfi_cmd_session_empty_buffer_compressed_packet); + pkt->packet_type = HFI_CMD_SESSION_EMPTY_BUFFER; + pkt->session_id = hash32_ptr(session); + 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->mark_target = input_frame->mark_target; + pkt->mark_data = input_frame->mark_data; + 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, + struct hal_session *session, struct vidc_frame_data *input_frame) +{ + int rc = 0; + + if (!pkt || !session) + return -EINVAL; + + pkt->size = sizeof(struct + hfi_cmd_session_empty_buffer_uncompressed_plane0_packet); + pkt->packet_type = HFI_CMD_SESSION_EMPTY_BUFFER; + pkt->session_id = hash32_ptr(session); + 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->mark_target = input_frame->mark_target; + pkt->mark_data = input_frame->mark_data; + 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, + struct hal_session *session, + struct vidc_frame_data *output_frame) +{ + int rc = 0; + + if (!pkt || !session || !output_frame) + return -EINVAL; + + pkt->size = sizeof(struct hfi_cmd_session_fill_buffer_packet); + pkt->packet_type = HFI_CMD_SESSION_FILL_BUFFER; + pkt->session_id = hash32_ptr(session); + + 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->output_tag = output_frame->output_tag; + 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, + struct hal_session *session) +{ + int rc = 0; + + if (!pkt || !session) + return -EINVAL; + + pkt->size = sizeof(struct hfi_cmd_session_get_property_packet); + pkt->packet_type = HFI_CMD_SESSION_GET_PROPERTY; + pkt->session_id = hash32_ptr(session); + 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, + struct hal_session *session, enum hal_flush flush_mode) +{ + int rc = 0; + + if (!pkt || !session) + return -EINVAL; + + pkt->size = sizeof(struct hfi_cmd_session_flush_packet); + pkt->packet_type = HFI_CMD_SESSION_FLUSH; + pkt->session_id = hash32_ptr(session); + 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: + dprintk(VIDC_ERR, "Invalid flush mode: %#x\n", flush_mode); + return -EINVAL; + } + return rc; +} + +int create_pkt_cmd_session_get_property( + struct hfi_cmd_session_get_property_packet *pkt, + struct hal_session *session, enum hal_property ptype) +{ + /* Currently no get property is supported */ + dprintk(VIDC_ERR, "%s cmd:%#x not supported\n", __func__, + ptype); + return -EINVAL; +} + +int create_pkt_cmd_session_set_property( + struct hfi_cmd_session_set_property_packet *pkt, + struct hal_session *session, + enum hal_property ptype, void *pdata) +{ + int rc = 0; + + if (!pkt || !session) + return -EINVAL; + + pkt->size = sizeof(struct hfi_cmd_session_set_property_packet); + pkt->packet_type = HFI_CMD_SESSION_SET_PROPERTY; + pkt->session_id = hash32_ptr(session); + pkt->num_properties = 1; + + dprintk(VIDC_DBG, "Setting HAL Property = 0x%x\n", ptype); + + switch (ptype) { + case HAL_CONFIG_FRAME_RATE: + { + u32 buffer_type; + struct hfi_frame_rate *hfi; + struct hal_frame_rate *prop = (struct hal_frame_rate *) pdata; + + pkt->rg_property_data[0] = HFI_PROPERTY_CONFIG_FRAME_RATE; + hfi = (struct hfi_frame_rate *) &pkt->rg_property_data[1]; + buffer_type = get_hfi_buffer(prop->buffer_type); + if (buffer_type) + hfi->buffer_type = buffer_type; + else + return -EINVAL; + + hfi->frame_rate = prop->frame_rate; + pkt->size += sizeof(struct hfi_frame_rate); + break; + } + case HAL_CONFIG_OPERATING_RATE: + { + struct hfi_operating_rate *hfi; + struct hal_operating_rate *prop = + (struct hal_operating_rate *) pdata; + + pkt->rg_property_data[0] = HFI_PROPERTY_CONFIG_OPERATING_RATE; + hfi = (struct hfi_operating_rate *) &pkt->rg_property_data[1]; + hfi->operating_rate = prop->operating_rate; + pkt->size += sizeof(struct hfi_operating_rate); + break; + } + case HAL_PARAM_UNCOMPRESSED_FORMAT_SELECT: + { + u32 buffer_type; + struct hfi_uncompressed_format_select *hfi; + struct hal_uncompressed_format_select *prop = + (struct hal_uncompressed_format_select *) pdata; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SELECT; + + hfi = (struct hfi_uncompressed_format_select *) + &pkt->rg_property_data[1]; + buffer_type = get_hfi_buffer(prop->buffer_type); + if (buffer_type) + hfi->buffer_type = buffer_type; + else + return -EINVAL; + hfi->format = hal_to_hfi_type( + HAL_PARAM_UNCOMPRESSED_FORMAT_SELECT, + prop->format); + pkt->size += sizeof(struct hfi_uncompressed_format_select); + break; + } + case HAL_PARAM_UNCOMPRESSED_PLANE_ACTUAL_CONSTRAINTS_INFO: + { + struct hfi_uncompressed_plane_actual_constraints_info *hfi; + struct hal_uncompressed_plane_actual_constraints_info *prop = + (struct hal_uncompressed_plane_actual_constraints_info *) pdata; + u32 buffer_type; + u32 num_plane = prop->num_planes; + u32 hfi_pkt_size = + 2 * sizeof(u32) + + num_plane + * sizeof(struct hal_uncompressed_plane_constraints); + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_CONSTRAINTS_INFO; + + hfi = (struct hfi_uncompressed_plane_actual_constraints_info *) + &pkt->rg_property_data[1]; + buffer_type = get_hfi_buffer(prop->buffer_type); + if (buffer_type) + hfi->buffer_type = buffer_type; + else + return -EINVAL; + + hfi->num_planes = prop->num_planes; + memcpy(hfi->rg_plane_format, prop->rg_plane_format, + hfi->num_planes + *sizeof(struct hal_uncompressed_plane_constraints)); + pkt->size += hfi_pkt_size; + break; + } + case HAL_PARAM_UNCOMPRESSED_PLANE_ACTUAL_INFO: + break; + case HAL_PARAM_FRAME_SIZE: + { + struct hfi_frame_size *hfi; + struct hal_frame_size *prop = (struct hal_frame_size *) pdata; + u32 buffer_type; + + pkt->rg_property_data[0] = HFI_PROPERTY_PARAM_FRAME_SIZE; + hfi = (struct hfi_frame_size *) &pkt->rg_property_data[1]; + buffer_type = get_hfi_buffer(prop->buffer_type); + if (buffer_type) + hfi->buffer_type = buffer_type; + else + return -EINVAL; + + hfi->height = prop->height; + hfi->width = prop->width; + pkt->size += sizeof(struct hfi_frame_size); + break; + } + case HAL_CONFIG_REALTIME: + { + create_pkt_enable(pkt->rg_property_data, + HFI_PROPERTY_CONFIG_REALTIME, + (((struct hal_enable *) pdata)->enable)); + pkt->size += sizeof(u32); + break; + } + case HAL_PARAM_BUFFER_COUNT_ACTUAL: + { + struct hfi_buffer_count_actual *hfi; + struct hal_buffer_count_actual *prop = + (struct hal_buffer_count_actual *) pdata; + u32 buffer_type; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_BUFFER_COUNT_ACTUAL; + hfi = (struct hfi_buffer_count_actual *) + &pkt->rg_property_data[1]; + hfi->buffer_count_actual = prop->buffer_count_actual; + hfi->buffer_count_min_host = prop->buffer_count_min_host; + + buffer_type = get_hfi_buffer(prop->buffer_type); + if (buffer_type) + hfi->buffer_type = buffer_type; + else + return -EINVAL; + + pkt->size += sizeof(struct hfi_buffer_count_actual); + + break; + } + case HAL_PARAM_NAL_STREAM_FORMAT_SELECT: + { + struct hfi_nal_stream_format_select *hfi; + struct hal_nal_stream_format_select *prop = + (struct hal_nal_stream_format_select *)pdata; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SELECT; + hfi = (struct hfi_nal_stream_format_select *) + &pkt->rg_property_data[1]; + dprintk(VIDC_DBG, "data is :%d\n", + prop->nal_stream_format_select); + hfi->nal_stream_format_select = hal_to_hfi_type( + HAL_PARAM_NAL_STREAM_FORMAT_SELECT, + prop->nal_stream_format_select); + pkt->size += sizeof(struct hfi_nal_stream_format_select); + break; + } + case HAL_PARAM_VDEC_OUTPUT_ORDER: + { + int *data = (int *) pdata; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VDEC_OUTPUT_ORDER; + switch (*data) { + case HAL_OUTPUT_ORDER_DECODE: + pkt->rg_property_data[1] = HFI_OUTPUT_ORDER_DECODE; + break; + case HAL_OUTPUT_ORDER_DISPLAY: + pkt->rg_property_data[1] = HFI_OUTPUT_ORDER_DISPLAY; + break; + default: + dprintk(VIDC_ERR, "invalid output order: %#x\n", + *data); + break; + } + pkt->size += sizeof(u32); + break; + } + case HAL_PARAM_VDEC_PICTURE_TYPE_DECODE: + { + struct hfi_enable_picture *hfi; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VDEC_PICTURE_TYPE_DECODE; + hfi = (struct hfi_enable_picture *) &pkt->rg_property_data[1]; + hfi->picture_type = + ((struct hfi_enable_picture *)pdata)->picture_type; + pkt->size += sizeof(u32); + break; + } + case HAL_PARAM_VDEC_OUTPUT2_KEEP_ASPECT_RATIO: + { + create_pkt_enable(pkt->rg_property_data, + HFI_PROPERTY_PARAM_VDEC_OUTPUT2_KEEP_ASPECT_RATIO, + ((struct hal_enable *)pdata)->enable); + pkt->size += sizeof(u32); + break; + } + case HAL_PARAM_VDEC_MULTI_STREAM: + { + struct hfi_multi_stream *hfi; + struct hal_multi_stream *prop = + (struct hal_multi_stream *) pdata; + u32 buffer_type; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VDEC_MULTI_STREAM; + hfi = (struct hfi_multi_stream *) &pkt->rg_property_data[1]; + + buffer_type = get_hfi_buffer(prop->buffer_type); + if (buffer_type) + hfi->buffer_type = buffer_type; + else + return -EINVAL; + hfi->enable = prop->enable; + pkt->size += sizeof(struct hfi_multi_stream); + break; + } + case HAL_CONFIG_VDEC_MB_ERROR_MAP_REPORTING: + { + create_pkt_enable(pkt->rg_property_data, + HFI_PROPERTY_CONFIG_VDEC_MB_ERROR_MAP_REPORTING, + ((struct hal_enable *)pdata)->enable); + pkt->size += sizeof(u32); + break; + } + case HAL_PARAM_VDEC_SYNC_FRAME_DECODE: + { + create_pkt_enable(pkt->rg_property_data, + HFI_PROPERTY_PARAM_VDEC_THUMBNAIL_MODE, + ((struct hal_enable *)pdata)->enable); + pkt->size += sizeof(u32); + break; + } + case HAL_PARAM_SECURE: + { + create_pkt_enable(pkt->rg_property_data, + HFI_PROPERTY_PARAM_SECURE_SESSION, + ((struct hal_enable *)pdata)->enable); + pkt->size += sizeof(u32); + break; + } + case HAL_PARAM_VENC_SYNC_FRAME_SEQUENCE_HEADER: + { + create_pkt_enable(pkt->rg_property_data, + HFI_PROPERTY_CONFIG_VENC_SYNC_FRAME_SEQUENCE_HEADER, + ((struct hal_enable *)pdata)->enable); + pkt->size += sizeof(u32); + break; + } + case HAL_CONFIG_VENC_REQUEST_IFRAME: + pkt->rg_property_data[0] = + HFI_PROPERTY_CONFIG_VENC_REQUEST_SYNC_FRAME; + break; + case HAL_CONFIG_HEIC_FRAME_QUALITY: + { + struct hfi_heic_frame_quality *hfi; + + pkt->rg_property_data[0] = + HFI_PROPERTY_CONFIG_HEIC_FRAME_QUALITY; + hfi = + (struct hfi_heic_frame_quality *) &pkt->rg_property_data[1]; + hfi->frame_quality = + ((struct hal_heic_frame_quality *)pdata)->frame_quality; + pkt->size += sizeof(u32) + + sizeof(struct hfi_heic_frame_quality); + break; + } + case HAL_CONFIG_HEIC_GRID_ENABLE: + { + struct hfi_heic_grid_enable *hfi; + + pkt->rg_property_data[0] = + HFI_PROPERTY_CONFIG_HEIC_GRID_ENABLE; + hfi = (struct hfi_heic_grid_enable *) &pkt->rg_property_data[1]; + hfi->grid_enable = + ((struct hal_heic_grid_enable *)pdata)->grid_enable; + pkt->size += sizeof(u32) + sizeof(struct hfi_heic_grid_enable); + break; + } + case HAL_CONFIG_VENC_TARGET_BITRATE: + { + struct hfi_bitrate *hfi; + + pkt->rg_property_data[0] = + HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE; + hfi = (struct hfi_bitrate *) &pkt->rg_property_data[1]; + hfi->bit_rate = ((struct hal_bitrate *)pdata)->bit_rate; + hfi->layer_id = ((struct hal_bitrate *)pdata)->layer_id; + pkt->size += sizeof(struct hfi_bitrate); + break; + } + case HAL_PARAM_PROFILE_LEVEL_CURRENT: + { + struct hfi_profile_level *hfi; + struct hal_profile_level *prop = + (struct hal_profile_level *) pdata; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT; + hfi = (struct hfi_profile_level *) + &pkt->rg_property_data[1]; + + /* There is an assumption here that HAL level is same as + * HFI level + */ + hfi->level = prop->level; + hfi->profile = prop->profile; + if (hfi->profile <= 0) { + hfi->profile = HFI_H264_PROFILE_HIGH; + dprintk(VIDC_WARN, + "Profile %d not supported, falling back to high\n", + prop->profile); + } + + pkt->size += sizeof(struct hfi_profile_level); + break; + } + case HAL_PARAM_VENC_H264_ENTROPY_CONTROL: + { + struct hfi_h264_entropy_control *hfi; + struct hal_h264_entropy_control *prop = + (struct hal_h264_entropy_control *) pdata; + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VENC_H264_ENTROPY_CONTROL; + hfi = (struct hfi_h264_entropy_control *) + &pkt->rg_property_data[1]; + hfi->entropy_mode = hal_to_hfi_type( + HAL_PARAM_VENC_H264_ENTROPY_CONTROL, + prop->entropy_mode); + + hfi->cabac_model = HFI_H264_CABAC_MODEL_0; + pkt->size += sizeof(struct hfi_h264_entropy_control); + break; + } + case HAL_PARAM_VENC_RATE_CONTROL: + { + u32 *rc; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VENC_RATE_CONTROL; + rc = (u32 *)pdata; + switch ((enum hal_rate_control) *rc) { + case HAL_RATE_CONTROL_OFF: + pkt->rg_property_data[1] = HFI_RATE_CONTROL_OFF; + break; + case HAL_RATE_CONTROL_CBR: + pkt->rg_property_data[1] = HFI_RATE_CONTROL_CBR_CFR; + break; + case HAL_RATE_CONTROL_VBR: + pkt->rg_property_data[1] = HFI_RATE_CONTROL_VBR_CFR; + break; + case HAL_RATE_CONTROL_MBR: + pkt->rg_property_data[1] = HFI_RATE_CONTROL_MBR_CFR; + break; + case HAL_RATE_CONTROL_CBR_VFR: + pkt->rg_property_data[1] = HFI_RATE_CONTROL_CBR_VFR; + break; + case HAL_RATE_CONTROL_MBR_VFR: + pkt->rg_property_data[1] = HFI_RATE_CONTROL_MBR_VFR; + break; + case HAL_RATE_CONTROL_CQ: + pkt->rg_property_data[1] = HFI_RATE_CONTROL_CQ; + break; + default: + dprintk(VIDC_ERR, + "Invalid Rate control setting: %pK\n", + pdata); + break; + } + pkt->size += sizeof(u32); + break; + } + case HAL_PARAM_VENC_BITRATE_SAVINGS: + { + create_pkt_enable(pkt->rg_property_data, + HFI_PROPERTY_PARAM_VENC_BITRATE_SAVINGS, + ((struct hal_enable *)pdata)->enable); + pkt->size += sizeof(u32); + break; + } + case HAL_PARAM_VENC_H264_DEBLOCK_CONTROL: + { + struct hfi_h264_db_control *hfi; + struct hal_h264_db_control *prop = + (struct hal_h264_db_control *) pdata; + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VENC_H264_DEBLOCK_CONTROL; + hfi = (struct hfi_h264_db_control *) &pkt->rg_property_data[1]; + switch (prop->mode) { + case HAL_H264_DB_MODE_DISABLE: + hfi->mode = HFI_H264_DB_MODE_DISABLE; + break; + case HAL_H264_DB_MODE_SKIP_SLICE_BOUNDARY: + hfi->mode = HFI_H264_DB_MODE_SKIP_SLICE_BOUNDARY; + break; + case HAL_H264_DB_MODE_ALL_BOUNDARY: + hfi->mode = HFI_H264_DB_MODE_ALL_BOUNDARY; + break; + default: + dprintk(VIDC_ERR, "Invalid deblocking mode: %#x\n", + prop->mode); + break; + } + hfi->slice_alpha_offset = prop->slice_alpha_offset; + hfi->slice_beta_offset = prop->slice_beta_offset; + pkt->size += sizeof(struct hfi_h264_db_control); + break; + } + case HAL_CONFIG_VENC_FRAME_QP: + { + struct hfi_quantization *hfi; + struct hal_quantization *hal_quant = + (struct hal_quantization *) pdata; + pkt->rg_property_data[0] = + HFI_PROPERTY_CONFIG_VENC_FRAME_QP; + hfi = (struct hfi_quantization *) &pkt->rg_property_data[1]; + hfi->qp_packed = hal_quant->qpi | hal_quant->qpp << 8 | + hal_quant->qpb << 16; + hfi->layer_id = hal_quant->layer_id; + hfi->enable = hal_quant->enable; + pkt->size += sizeof(struct hfi_quantization); + break; + } + case HAL_PARAM_VENC_SESSION_QP_RANGE: + { + struct hfi_quantization_range *hfi; + struct hal_quantization_range *hal_range = + (struct hal_quantization_range *) pdata; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE; + hfi = (struct hfi_quantization_range *) + &pkt->rg_property_data[1]; + + /* + * When creating the packet, pack the qp value as + * 0xbbppii, where ii = qp range for I-frames, + * pp = qp range for P-frames, etc. + */ + hfi->min_qp.qp_packed = hal_range->qpi_min | + hal_range->qpp_min << 8 | + hal_range->qpb_min << 16; + hfi->max_qp.qp_packed = hal_range->qpi_max | + hal_range->qpp_max << 8 | + hal_range->qpb_max << 16; + hfi->max_qp.layer_id = hal_range->layer_id; + hfi->min_qp.layer_id = hal_range->layer_id; + + pkt->size += sizeof(struct hfi_quantization_range); + break; + } + case HAL_CONFIG_VENC_INTRA_PERIOD: + { + struct hfi_intra_period *hfi; + + pkt->rg_property_data[0] = + HFI_PROPERTY_CONFIG_VENC_INTRA_PERIOD; + hfi = (struct hfi_intra_period *) &pkt->rg_property_data[1]; + memcpy(hfi, (struct hfi_intra_period *) pdata, + sizeof(struct hfi_intra_period)); + pkt->size += sizeof(struct hfi_intra_period); + + if (hfi->bframes) { + struct hfi_enable *hfi_enable; + u32 *prop_type; + + prop_type = (u32 *)((u8 *)&pkt->rg_property_data[0] + + sizeof(u32) + sizeof(struct hfi_intra_period)); + *prop_type = HFI_PROPERTY_PARAM_VENC_ADAPTIVE_B; + hfi_enable = (struct hfi_enable *)(prop_type + 1); + hfi_enable->enable = true; + pkt->num_properties = 2; + pkt->size += sizeof(struct hfi_enable) + sizeof(u32); + } + break; + } + case HAL_CONFIG_VENC_IDR_PERIOD: + { + struct hfi_idr_period *hfi; + + pkt->rg_property_data[0] = HFI_PROPERTY_CONFIG_VENC_IDR_PERIOD; + hfi = (struct hfi_idr_period *) &pkt->rg_property_data[1]; + hfi->idr_period = ((struct hfi_idr_period *) pdata)->idr_period; + pkt->size += sizeof(u32); + break; + } + case HAL_PARAM_VENC_ADAPTIVE_B: + { + create_pkt_enable(pkt->rg_property_data, + HFI_PROPERTY_PARAM_VENC_ADAPTIVE_B, + ((struct hal_enable *)pdata)->enable); + pkt->size += sizeof(struct hfi_enable); + break; + } + case HAL_PARAM_VDEC_CONCEAL_COLOR: + { + struct hfi_conceal_color *hfi; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VDEC_CONCEAL_COLOR; + hfi = (struct hfi_conceal_color *) &pkt->rg_property_data[1]; + if (hfi) { + hfi->conceal_color_8bit = + ((struct hfi_conceal_color *) pdata)-> + conceal_color_8bit; + hfi->conceal_color_10bit = + ((struct hfi_conceal_color *) pdata)-> + conceal_color_10bit; + } + pkt->size += sizeof(struct hfi_conceal_color); + break; + } + case HAL_PARAM_VPE_ROTATION: + { + struct hfi_vpe_rotation_type *hfi; + struct hal_vpe_rotation *prop = + (struct hal_vpe_rotation *) pdata; + pkt->rg_property_data[0] = HFI_PROPERTY_PARAM_VPE_ROTATION; + hfi = (struct hfi_vpe_rotation_type *)&pkt->rg_property_data[1]; + switch (prop->rotate) { + case 0: + hfi->rotation = HFI_ROTATE_NONE; + break; + case 90: + hfi->rotation = HFI_ROTATE_90; + break; + case 180: + hfi->rotation = HFI_ROTATE_180; + break; + case 270: + hfi->rotation = HFI_ROTATE_270; + break; + default: + dprintk(VIDC_ERR, "Invalid rotation setting: %#x\n", + prop->rotate); + rc = -EINVAL; + break; + } + switch (prop->flip) { + case HAL_FLIP_NONE: + hfi->flip = HFI_FLIP_NONE; + break; + case HAL_FLIP_HORIZONTAL: + hfi->flip = HFI_FLIP_HORIZONTAL; + break; + case HAL_FLIP_VERTICAL: + hfi->flip = HFI_FLIP_VERTICAL; + break; + case HAL_FLIP_BOTH: + hfi->flip = HFI_FLIP_HORIZONTAL | HFI_FLIP_VERTICAL; + break; + default: + dprintk(VIDC_ERR, "Invalid flip setting: %#x\n", + prop->flip); + rc = -EINVAL; + break; + } + pkt->size += sizeof(struct hfi_vpe_rotation_type); + break; + } + case HAL_PARAM_VENC_INTRA_REFRESH: + { + struct hfi_intra_refresh *hfi; + struct hal_intra_refresh *prop = + (struct hal_intra_refresh *) pdata; + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VENC_INTRA_REFRESH; + hfi = (struct hfi_intra_refresh *) &pkt->rg_property_data[1]; + hfi->mbs = 0; + switch (prop->mode) { + case HAL_INTRA_REFRESH_NONE: + hfi->mode = HFI_INTRA_REFRESH_NONE; + break; + case HAL_INTRA_REFRESH_CYCLIC: + hfi->mode = HFI_INTRA_REFRESH_CYCLIC; + hfi->mbs = prop->ir_mbs; + break; + case HAL_INTRA_REFRESH_RANDOM: + hfi->mode = HFI_INTRA_REFRESH_RANDOM; + hfi->mbs = prop->ir_mbs; + break; + default: + dprintk(VIDC_ERR, + "Invalid intra refresh setting: %#x\n", + prop->mode); + break; + } + pkt->size += sizeof(struct hfi_intra_refresh); + break; + } + case HAL_PARAM_VENC_MULTI_SLICE_CONTROL: + { + struct hfi_multi_slice_control *hfi; + struct hal_multi_slice_control *prop = + (struct hal_multi_slice_control *) pdata; + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VENC_MULTI_SLICE_CONTROL; + hfi = (struct hfi_multi_slice_control *) + &pkt->rg_property_data[1]; + switch (prop->multi_slice) { + case HAL_MULTI_SLICE_OFF: + hfi->multi_slice = HFI_MULTI_SLICE_OFF; + break; + case HAL_MULTI_SLICE_BY_MB_COUNT: + hfi->multi_slice = HFI_MULTI_SLICE_BY_MB_COUNT; + break; + case HAL_MULTI_SLICE_BY_BYTE_COUNT: + hfi->multi_slice = HFI_MULTI_SLICE_BY_BYTE_COUNT; + break; + default: + dprintk(VIDC_ERR, "Invalid slice settings: %#x\n", + prop->multi_slice); + break; + } + hfi->slice_size = prop->slice_size; + pkt->size += sizeof(struct + hfi_multi_slice_control); + break; + } + case HAL_PARAM_INDEX_EXTRADATA: + { + struct hfi_index_extradata_config *hfi; + struct hal_extradata_enable *extra = pdata; + int id = 0; + + pkt->rg_property_data[0] = + get_hfi_extradata_index(extra->index); + hfi = (struct hfi_index_extradata_config *) + &pkt->rg_property_data[1]; + hfi->enable = extra->enable; + id = get_hfi_extradata_id(extra->index); + if (id) + hfi->index_extra_data_id = id; + else { + dprintk(VIDC_WARN, + "Failed to find extradata id: %d\n", + id); + rc = -EINVAL; + } + pkt->size += sizeof(struct hfi_index_extradata_config); + break; + } + case HAL_PARAM_VENC_SLICE_DELIVERY_MODE: + { + create_pkt_enable(pkt->rg_property_data, + HFI_PROPERTY_PARAM_VENC_SLICE_DELIVERY_MODE, + ((struct hal_enable *)pdata)->enable); + pkt->size += sizeof(struct hfi_enable); + break; + } + case HAL_PARAM_VENC_VUI_TIMING_INFO: + { + struct hfi_vui_timing_info *hfi; + struct hal_vui_timing_info *timing_info = pdata; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VENC_VUI_TIMING_INFO; + + hfi = (struct hfi_vui_timing_info *)&pkt->rg_property_data[1]; + hfi->enable = timing_info->enable; + hfi->fixed_frame_rate = timing_info->fixed_frame_rate; + hfi->time_scale = timing_info->time_scale; + + pkt->size += sizeof(struct hfi_vui_timing_info); + break; + } + case HAL_PARAM_VENC_GENERATE_AUDNAL: + { + create_pkt_enable(pkt->rg_property_data, + HFI_PROPERTY_PARAM_VENC_GENERATE_AUDNAL, + ((struct hal_enable *)pdata)->enable); + pkt->size += sizeof(struct hfi_enable); + break; + } + case HAL_PARAM_VENC_PRESERVE_TEXT_QUALITY: + { + create_pkt_enable(pkt->rg_property_data, + HFI_PROPERTY_PARAM_VENC_PRESERVE_TEXT_QUALITY, + ((struct hal_enable *)pdata)->enable); + pkt->size += sizeof(struct hfi_enable); + break; + } + case HAL_PARAM_VENC_LTRMODE: + { + struct hfi_ltr_mode *hfi; + struct hal_ltr_mode *hal = pdata; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VENC_LTRMODE; + hfi = (struct hfi_ltr_mode *) &pkt->rg_property_data[1]; + hfi->ltr_mode = get_hfi_ltr_mode(hal->mode); + hfi->ltr_count = hal->count; + hfi->trust_mode = hal->trust_mode; + pkt->size += sizeof(struct hfi_ltr_mode); + break; + } + case HAL_CONFIG_VENC_USELTRFRAME: + { + struct hfi_ltr_use *hfi; + struct hal_ltr_use *hal = pdata; + + pkt->rg_property_data[0] = + HFI_PROPERTY_CONFIG_VENC_USELTRFRAME; + hfi = (struct hfi_ltr_use *) &pkt->rg_property_data[1]; + hfi->frames = hal->frames; + hfi->ref_ltr = hal->ref_ltr; + hfi->use_constrnt = hal->use_constraint; + pkt->size += sizeof(struct hfi_ltr_use); + break; + } + case HAL_CONFIG_VENC_MARKLTRFRAME: + { + struct hfi_ltr_mark *hfi; + struct hal_ltr_mark *hal = pdata; + + pkt->rg_property_data[0] = + HFI_PROPERTY_CONFIG_VENC_MARKLTRFRAME; + hfi = (struct hfi_ltr_mark *) &pkt->rg_property_data[1]; + hfi->mark_frame = hal->mark_frame; + pkt->size += sizeof(struct hfi_ltr_mark); + break; + } + case HAL_PARAM_VENC_HIER_P_MAX_ENH_LAYERS: + { + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VENC_HIER_P_MAX_NUM_ENH_LAYER; + pkt->rg_property_data[1] = *(u32 *)pdata; + pkt->size += sizeof(u32); + break; + } + case HAL_CONFIG_VENC_HIER_P_NUM_FRAMES: + { + pkt->rg_property_data[0] = + HFI_PROPERTY_CONFIG_VENC_HIER_P_ENH_LAYER; + pkt->rg_property_data[1] = *(u32 *)pdata; + pkt->size += sizeof(u32); + break; + } + case HAL_PARAM_VENC_DISABLE_RC_TIMESTAMP: + { + create_pkt_enable(pkt->rg_property_data, + HFI_PROPERTY_PARAM_VENC_DISABLE_RC_TIMESTAMP, + ((struct hal_enable *)pdata)->enable); + pkt->size += sizeof(struct hfi_enable); + break; + } + case HAL_PARAM_VPE_COLOR_SPACE_CONVERSION: + { + struct hfi_vpe_color_space_conversion *hfi = NULL; + struct hal_vpe_color_space_conversion *hal = pdata; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VPE_COLOR_SPACE_CONVERSION; + hfi = (struct hfi_vpe_color_space_conversion *) + &pkt->rg_property_data[1]; + + hfi->input_color_primaries = hal->input_color_primaries; + if (hal->custom_matrix_enabled) + /* Bit Mask to enable all custom values */ + hfi->custom_matrix_enabled = 0x7; + else + hfi->custom_matrix_enabled = 0x0; + memcpy(hfi->csc_matrix, hal->csc_matrix, + sizeof(hfi->csc_matrix)); + memcpy(hfi->csc_bias, hal->csc_bias, sizeof(hfi->csc_bias)); + memcpy(hfi->csc_limit, hal->csc_limit, sizeof(hfi->csc_limit)); + pkt->size += sizeof(struct hfi_vpe_color_space_conversion); + break; + } + case HAL_PARAM_VENC_VPX_ERROR_RESILIENCE_MODE: + { + create_pkt_enable(pkt->rg_property_data, + HFI_PROPERTY_PARAM_VENC_VPX_ERROR_RESILIENCE_MODE, + ((struct hal_enable *)pdata)->enable); + pkt->size += sizeof(struct hfi_enable); + break; + } + case HAL_CONFIG_VENC_PERF_MODE: + { + u32 hfi_perf_mode = 0; + enum hal_perf_mode hal_perf_mode = *(enum hal_perf_mode *)pdata; + + switch (hal_perf_mode) { + case HAL_PERF_MODE_POWER_SAVE: + hfi_perf_mode = HFI_VENC_PERFMODE_POWER_SAVE; + break; + case HAL_PERF_MODE_POWER_MAX_QUALITY: + hfi_perf_mode = HFI_VENC_PERFMODE_MAX_QUALITY; + break; + default: + return -ENOTSUPP; + } + + pkt->rg_property_data[0] = HFI_PROPERTY_CONFIG_VENC_PERF_MODE; + pkt->rg_property_data[1] = hfi_perf_mode; + pkt->size += sizeof(u32); + break; + } + case HAL_PARAM_VENC_HIER_P_HYBRID_MODE: + { + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VENC_HIER_P_HYBRID_MODE; + pkt->rg_property_data[1] = + ((struct hfi_hybrid_hierp *)pdata)->layers ?: 0xFF; + pkt->size += sizeof(u32) + + sizeof(struct hfi_hybrid_hierp); + break; + } + case HAL_PARAM_VENC_MBI_STATISTICS_MODE: + { + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VENC_MBI_DUMPING; + pkt->rg_property_data[1] = hal_to_hfi_type( + HAL_PARAM_VENC_MBI_STATISTICS_MODE, + *(u32 *)pdata); + pkt->size += sizeof(u32); + break; + } + case HAL_CONFIG_VENC_BASELAYER_PRIORITYID: + { + pkt->rg_property_data[0] = + HFI_PROPERTY_CONFIG_VENC_BASELAYER_PRIORITYID; + pkt->rg_property_data[1] = *(u32 *)pdata; + pkt->size += sizeof(u32); + break; + } + case HAL_PROPERTY_PARAM_VENC_ASPECT_RATIO: + { + struct hfi_aspect_ratio *hfi = NULL; + struct hal_aspect_ratio *hal = pdata; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VENC_ASPECT_RATIO; + hfi = (struct hfi_aspect_ratio *) + &pkt->rg_property_data[1]; + memcpy(hfi, hal, + sizeof(struct hfi_aspect_ratio)); + pkt->size += sizeof(struct hfi_aspect_ratio); + break; + } + case HAL_PARAM_VENC_BITRATE_TYPE: + { + create_pkt_enable(pkt->rg_property_data, + HFI_PROPERTY_PARAM_VENC_BITRATE_TYPE, + ((struct hal_enable *)pdata)->enable); + pkt->size += sizeof(struct hfi_enable); + break; + } + case HAL_PARAM_VENC_H264_TRANSFORM_8x8: + { + create_pkt_enable(pkt->rg_property_data, + HFI_PROPERTY_PARAM_VENC_H264_8X8_TRANSFORM, + ((struct hal_enable *)pdata)->enable); + pkt->size += sizeof(struct hfi_enable); + break; + } + case HAL_PARAM_VENC_VIDEO_SIGNAL_INFO: + { + struct hal_video_signal_info *hal = pdata; + struct hfi_video_signal_metadata *signal_info = + (struct hfi_video_signal_metadata *) + &pkt->rg_property_data[1]; + + signal_info->enable = true; + signal_info->video_format = MSM_VIDC_NTSC; + signal_info->video_full_range = hal->full_range; + signal_info->color_description = MSM_VIDC_COLOR_DESC_PRESENT; + signal_info->color_primaries = hal->color_space; + signal_info->transfer_characteristics = hal->transfer_chars; + signal_info->matrix_coeffs = hal->matrix_coeffs; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VENC_VIDEO_SIGNAL_INFO; + pkt->size += sizeof(*signal_info); + break; + } + case HAL_PARAM_VENC_IFRAMESIZE_TYPE: + { + enum hal_iframesize_type hal = + *(enum hal_iframesize_type *)pdata; + struct hfi_iframe_size *hfi = (struct hfi_iframe_size *) + &pkt->rg_property_data[1]; + + switch (hal) { + case HAL_IFRAMESIZE_TYPE_DEFAULT: + hfi->type = HFI_IFRAME_SIZE_DEFAULT; + break; + case HAL_IFRAMESIZE_TYPE_MEDIUM: + hfi->type = HFI_IFRAME_SIZE_MEDIUM; + break; + case HAL_IFRAMESIZE_TYPE_HUGE: + hfi->type = HFI_IFRAME_SIZE_HIGH; + break; + case HAL_IFRAMESIZE_TYPE_UNLIMITED: + hfi->type = HFI_IFRAME_SIZE_UNLIMITED; + break; + default: + return -ENOTSUPP; + } + pkt->rg_property_data[0] = HFI_PROPERTY_PARAM_VENC_IFRAMESIZE; + pkt->size += sizeof(struct hfi_iframe_size); + break; + } + case HAL_PARAM_BUFFER_SIZE_MINIMUM: + { + struct hfi_buffer_size_minimum *hfi; + struct hal_buffer_size_minimum *prop = + (struct hal_buffer_size_minimum *) pdata; + u32 buffer_type; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_BUFFER_SIZE_MINIMUM; + + hfi = (struct hfi_buffer_size_minimum *) + &pkt->rg_property_data[1]; + hfi->buffer_size = prop->buffer_size; + + buffer_type = get_hfi_buffer(prop->buffer_type); + if (buffer_type) + hfi->buffer_type = buffer_type; + else + return -EINVAL; + + pkt->size += sizeof(struct hfi_buffer_size_minimum); + break; + } + case HAL_PARAM_SYNC_BASED_INTERRUPT: + { + create_pkt_enable(pkt->rg_property_data, + HFI_PROPERTY_PARAM_SYNC_BASED_INTERRUPT, + ((struct hal_enable *)pdata)->enable); + pkt->size += sizeof(struct hfi_enable); + break; + } + case HAL_PARAM_VENC_LOW_LATENCY: + { + struct hfi_enable *hfi; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VENC_LOW_LATENCY_MODE; + hfi = (struct hfi_enable *) &pkt->rg_property_data[1]; + hfi->enable = ((struct hal_enable *) pdata)->enable; + pkt->size += sizeof(u32); + break; + } + case HAL_CONFIG_VENC_BLUR_RESOLUTION: + { + struct hfi_frame_size *hfi; + struct hal_frame_size *prop = (struct hal_frame_size *) pdata; + u32 buffer_type; + + pkt->rg_property_data[0] = + HFI_PROPERTY_CONFIG_VENC_BLUR_FRAME_SIZE; + hfi = (struct hfi_frame_size *) &pkt->rg_property_data[1]; + buffer_type = get_hfi_buffer(prop->buffer_type); + if (buffer_type) + hfi->buffer_type = buffer_type; + else + return -EINVAL; + + hfi->height = prop->height; + hfi->width = prop->width; + pkt->size += sizeof(struct hfi_frame_size); + break; + } + case HAL_PARAM_VIDEO_CORES_USAGE: + { + struct hal_videocores_usage_info *hal = pdata; + struct hfi_videocores_usage_type *core_info = + (struct hfi_videocores_usage_type *) + &pkt->rg_property_data[1]; + + core_info->video_core_enable_mask = hal->video_core_enable_mask; + + pkt->rg_property_data[0] = + HFI_PROPERTY_CONFIG_VIDEOCORES_USAGE; + pkt->size += sizeof(*core_info); + break; + } + case HAL_PARAM_VIDEO_WORK_MODE: + { + struct hal_video_work_mode *hal = pdata; + struct hfi_video_work_mode *work_mode = + (struct hfi_video_work_mode *) + &pkt->rg_property_data[1]; + + work_mode->video_work_mode = get_hfi_work_mode( + hal->video_work_mode); + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_WORK_MODE; + pkt->size += sizeof(*work_mode); + break; + } + case HAL_PARAM_VIDEO_WORK_ROUTE: + { + struct hal_video_work_route *hal = pdata; + struct hfi_video_work_route *prop = + (struct hfi_video_work_route *) + &pkt->rg_property_data[1]; + prop->video_work_route = + hal->video_work_route; + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_WORK_ROUTE; + pkt->size += sizeof(*prop); + break; + } + case HAL_PARAM_VENC_HDR10_PQ_SEI: + { + struct hfi_hdr10_pq_sei *hfi; + struct hal_hdr10_pq_sei *prop = + (struct hal_hdr10_pq_sei *) pdata; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VENC_HDR10_PQ_SEI; + hfi = (struct hfi_hdr10_pq_sei *) + &pkt->rg_property_data[1]; + + memcpy(hfi, prop, sizeof(*hfi)); + pkt->size += sizeof(struct hfi_hdr10_pq_sei); + break; + } + case HAL_CONFIG_VENC_VBV_HRD_BUF_SIZE: + { + struct hfi_vbv_hdr_buf_size *hfi; + struct hal_vbv_hdr_buf_size *prop = + (struct hal_vbv_hdr_buf_size *) pdata; + + pkt->rg_property_data[0] = + HFI_PROPERTY_CONFIG_VENC_VBV_HRD_BUF_SIZE; + hfi = (struct hfi_vbv_hdr_buf_size *) + &pkt->rg_property_data[1]; + + hfi->vbv_hdr_buf_size = prop->vbv_hdr_buf_size; + pkt->size += sizeof(struct hfi_vbv_hdr_buf_size); + break; + } + /* FOLLOWING PROPERTIES ARE NOT IMPLEMENTED IN CORE YET */ + case HAL_CONFIG_BUFFER_REQUIREMENTS: + case HAL_CONFIG_PRIORITY: + case HAL_CONFIG_BATCH_INFO: + case HAL_PARAM_METADATA_PASS_THROUGH: + case HAL_SYS_IDLE_INDICATOR: + case HAL_PARAM_UNCOMPRESSED_FORMAT_SUPPORTED: + case HAL_PARAM_INTERLACE_FORMAT_SUPPORTED: + case HAL_PARAM_CHROMA_SITE: + case HAL_PARAM_PROPERTIES_SUPPORTED: + case HAL_PARAM_PROFILE_LEVEL_SUPPORTED: + case HAL_PARAM_CAPABILITY_SUPPORTED: + case HAL_PARAM_NAL_STREAM_FORMAT_SUPPORTED: + case HAL_PARAM_MULTI_VIEW_FORMAT: + case HAL_PARAM_MAX_SEQUENCE_HEADER_SIZE: + case HAL_PARAM_CODEC_SUPPORTED: + case HAL_PARAM_VDEC_MULTI_VIEW_SELECT: + case HAL_PARAM_VDEC_MB_QUANTIZATION: + case HAL_PARAM_VDEC_NUM_CONCEALED_MB: + case HAL_PARAM_VDEC_H264_ENTROPY_SWITCHING: + case HAL_CONFIG_BUFFER_COUNT_ACTUAL: + case HAL_CONFIG_VDEC_MULTI_STREAM: + case HAL_PARAM_VENC_MULTI_SLICE_INFO: + case HAL_CONFIG_VENC_TIMESTAMP_SCALE: + default: + dprintk(VIDC_ERR, "DEFAULT: Calling %#x\n", ptype); + rc = -ENOTSUPP; + break; + } + return rc; +} + +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: + dprintk(VIDC_WARN, + "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) { + dprintk(VIDC_ERR, "Invalid params, device: %pK\n", pkt); + 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) { + dprintk(VIDC_ERR, "%s invalid param :%pK\n", __func__, pkt); + 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_sys_ubwc_config(struct hfi_cmd_sys_set_property_packet *pkt, + struct msm_vidc_ubwc_config *config) +{ + if (!pkt) { + dprintk(VIDC_ERR, "%s invalid param :%pK\n", __func__, pkt); + return -EINVAL; + } + + pkt->size = sizeof(struct hfi_cmd_sys_set_property_packet) + + config->nSize + sizeof(u32); + pkt->packet_type = HFI_CMD_SYS_SET_PROPERTY; + pkt->num_properties = 1; + pkt->rg_property_data[0] = HFI_PROPERTY_SYS_UBWC_CONFIG; + + if (config->nSize == sizeof(struct msm_vidc_ubwc_config)) + memcpy(&pkt->rg_property_data[1], config, config->nSize); + else + memcpy(&pkt->rg_property_data[1], &(config->v1), config->nSize); + + dprintk(VIDC_DBG, + "UBWC config nSize: %u, MaxChannels: %u, MalLength: %u, %u, HBB: %u\n", + config->nSize, + config->v1.nMaxChannels, + config->v1.nMalLength, + config->v1.nHighestBankBit); + dprintk(VIDC_DBG, + "MaxChannelsOverride: %u, MalLengthOverride: %u, HBBOverride: %u\n", + config->v1.sOverrideBitInfo.bMaxChannelsOverride, + config->v1.sOverrideBitInfo.bMalLengthOverride, + config->v1.sOverrideBitInfo.bHBBOverride); + + return 0; +} + +int create_pkt_cmd_session_sync_process( + struct hfi_cmd_session_sync_process_packet *pkt, + struct hal_session *session) +{ + if (!pkt || !session) + return -EINVAL; + + *pkt = (struct hfi_cmd_session_sync_process_packet) {0}; + pkt->size = sizeof(*pkt); + pkt->packet_type = HFI_CMD_SESSION_SYNC; + pkt->session_id = hash32_ptr(session); + 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_ping = create_pkt_cmd_sys_ping, + .sys_image_version = create_pkt_cmd_sys_image_version, + .ssr_cmd = create_pkt_ssr_cmd, + .sys_ubwc_config = create_pkt_cmd_sys_ubwc_config, + .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_get_property = create_pkt_cmd_session_get_property, + .session_set_property = create_pkt_cmd_session_set_property, +}; + +struct hfi_packetization_ops *hfi_get_pkt_ops_handle( + enum hfi_packetization_type type) +{ + dprintk(VIDC_DBG, "%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/drivers/media/platform/msm/vidc/hfi_packetization.h b/drivers/media/platform/msm/vidc/hfi_packetization.h new file mode 100644 index 000000000000..5479a7f1da43 --- /dev/null +++ b/drivers/media/platform/msm/vidc/hfi_packetization.h @@ -0,0 +1,103 @@ +/* Copyright (c) 2012-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. + * + */ +#ifndef __HFI_PACKETIZATION__ +#define __HFI_PACKETIZATION__ + +#include +#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); + int (*sys_release_resource)( + struct hfi_cmd_sys_release_resource_packet *pkt, + struct vidc_resource_hdr *resource_hdr); + int (*sys_ping)(struct hfi_cmd_sys_ping_packet *pkt); + int (*sys_image_version)(struct hfi_cmd_sys_get_property_packet *pkt); + int (*ssr_cmd)(enum hal_ssr_trigger_type type, + struct hfi_cmd_sys_test_ssr_packet *pkt); + int (*sys_ubwc_config)(struct hfi_cmd_sys_set_property_packet *pkt, + struct msm_vidc_ubwc_config *config); + int (*session_init)( + struct hfi_cmd_sys_session_init_packet *pkt, + struct hal_session *session, + u32 session_domain, u32 session_codec); + int (*session_cmd)(struct vidc_hal_session_cmd_pkt *pkt, + int pkt_type, struct hal_session *session); + int (*session_set_buffers)( + struct hfi_cmd_session_set_buffers_packet *pkt, + struct hal_session *session, + struct vidc_buffer_addr_info *buffer_info); + int (*session_release_buffers)( + struct hfi_cmd_session_release_buffer_packet *pkt, + struct hal_session *session, + struct vidc_buffer_addr_info *buffer_info); + int (*session_register_buffer)( + struct hfi_cmd_session_register_buffers_packet *pkt, + struct hal_session *session, + struct vidc_register_buffer *buffer); + int (*session_unregister_buffer)( + struct hfi_cmd_session_unregister_buffers_packet *pkt, + struct hal_session *session, + struct vidc_unregister_buffer *buffer); + int (*session_etb_decoder)( + struct hfi_cmd_session_empty_buffer_compressed_packet *pkt, + struct hal_session *session, + struct vidc_frame_data *input_frame); + int (*session_etb_encoder)( + struct hfi_cmd_session_empty_buffer_uncompressed_plane0_packet + *pkt, struct hal_session *session, + struct vidc_frame_data *input_frame); + int (*session_ftb)(struct hfi_cmd_session_fill_buffer_packet *pkt, + struct hal_session *session, + struct vidc_frame_data *output_frame); + int (*session_get_buf_req)( + struct hfi_cmd_session_get_property_packet *pkt, + struct hal_session *session); + int (*session_flush)(struct hfi_cmd_session_flush_packet *pkt, + struct hal_session *session, enum hal_flush flush_mode); + int (*session_get_property)( + struct hfi_cmd_session_get_property_packet *pkt, + struct hal_session *session, enum hal_property ptype); + int (*session_set_property)( + struct hfi_cmd_session_set_property_packet *pkt, + struct hal_session *session, + enum hal_property ptype, void *pdata); + int (*session_sync_process)( + struct hfi_cmd_session_sync_process_packet *pkt, + struct hal_session *session); +}; + +struct hfi_packetization_ops *hfi_get_pkt_ops_handle( + enum hfi_packetization_type); +#endif diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c new file mode 100644 index 000000000000..cb804b175024 --- /dev/null +++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c @@ -0,0 +1,2150 @@ +/* Copyright (c) 2012-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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include "vidc_hfi_helper.h" +#include "vidc_hfi_io.h" +#include "msm_vidc_debug.h" +#include "vidc_hfi.h" + +static enum vidc_status hfi_parse_init_done_properties( + struct msm_vidc_capability *capability, + u32 num_sessions, u8 *data_ptr, u32 num_properties, + u32 rem_bytes); + +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) +{ + 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; + } + dprintk(VIDC_ERR, "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) { + dprintk(VIDC_ERR, "%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_buffer_requirements *buf_req; + struct hfi_index_extradata_input_crop_payload *crop_info; + 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; + + if (!validate_pkt_size(pkt->size, + sizeof(struct hfi_msg_event_notify_packet))) + return -E2BIG; + + event_notify.device_id = device_id; + event_notify.session_id = (void *)(uintptr_t)pkt->session_id; + 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; + dprintk(VIDC_DBG, "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; + dprintk(VIDC_DBG, "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)); + chroma_bit_depth = get_hal_pixel_depth( + (pixel_depth->bit_depth & + GENMASK(31, 16)) >> 16); + 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; + dprintk(VIDC_DBG, + "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; + dprintk(VIDC_DBG, + "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_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_count = + dpb_counts->max_ref_count; + event_notify.max_dec_buffering = + dpb_counts->max_dec_buffering; + dprintk(VIDC_DBG, + "DPB Counts: dpb %d ref %d buff %d\n", + dpb_counts->max_dpb_count, + dpb_counts->max_ref_count, + dpb_counts->max_dec_buffering); + data_ptr += + sizeof(struct hfi_dpb_counts); + rem_size -= sizeof(struct hfi_dpb_counts); + 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; + dprintk(VIDC_DBG, + "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; + dprintk(VIDC_DBG, + "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); + buf_req = + (struct hfi_buffer_requirements *) + data_ptr; + event_notify.capture_buf_count = + buf_req->buffer_count_min; + dprintk(VIDC_DBG, + "Capture Count : 0x%x\n", + event_notify.capture_buf_count); + 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); + crop_info = (struct + hfi_index_extradata_input_crop_payload *) + data_ptr; + event_notify.crop_data.left = crop_info->left; + event_notify.crop_data.top = crop_info->top; + event_notify.crop_data.width = crop_info->width; + event_notify.crop_data.height = + crop_info->height; + dprintk(VIDC_DBG, + "CROP info : Left = %d Top = %d\n", + crop_info->left, + crop_info->top); + dprintk(VIDC_DBG, + "CROP info : Width = %d Height = %d\n", + crop_info->width, + crop_info->height); + data_ptr += + sizeof(struct + hfi_index_extradata_input_crop_payload); + rem_size -= sizeof(struct + hfi_index_extradata_input_crop_payload); + break; + default: + dprintk(VIDC_ERR, + "%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; + + dprintk(VIDC_DBG, + "RECEIVED: EVENT_NOTIFY - release_buffer_reference\n"); + if (sizeof(struct hfi_msg_event_notify_packet) + > pkt->size) { + dprintk(VIDC_ERR, + "hal_process_session_init_done: bad_pkt_size\n"); + return -E2BIG; + } + if (pkt->size < sizeof(struct hfi_msg_event_notify_packet) - sizeof(u32) + + sizeof(struct hfi_msg_release_buffer_ref_event_packet)) { + dprintk(VIDC_ERR, "%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; + + event_notify.device_id = device_id; + event_notify.session_id = (void *)(uintptr_t)pkt->session_id; + 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; + event_notify.output_tag = data->output_tag; + + 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}; + + cmd_done.device_id = device_id; + cmd_done.session_id = (void *)(uintptr_t)pkt->session_id; + cmd_done.status = hfi_map_err_status(pkt->event_data1); + info->response.cmd = cmd_done; + dprintk(VIDC_INFO, "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: + dprintk(VIDC_INFO, "Non Fatal: HFI_EVENT_SESSION_ERROR\n"); + info->response_type = HAL_RESPONSE_UNUSED; + break; + default: + dprintk(VIDC_ERR, + "%s: session %x data1 %#x, data2 %#x\n", __func__, + pkt->session_id, 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; + dprintk(VIDC_DBG, "Received: EVENT_NOTIFY\n"); + + if (pkt->size < sizeof(struct hfi_msg_event_notify_packet)) { + dprintk(VIDC_ERR, "Invalid Params\n"); + return -E2BIG; + } + + switch (pkt->event_id) { + case HFI_EVENT_SYS_ERROR: + dprintk(VIDC_ERR, "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: + dprintk(VIDC_INFO, "HFI_EVENT_SESSION_ERROR[%#x]\n", + pkt->session_id); + return hfi_process_session_error(device_id, pkt, info); + + case HFI_EVENT_SESSION_SEQUENCE_CHANGED: + dprintk(VIDC_INFO, "HFI_EVENT_SESSION_SEQUENCE_CHANGED[%#x]\n", + pkt->session_id); + return hfi_process_sess_evt_seq_changed(device_id, pkt, info); + + case HFI_EVENT_RELEASE_BUFFER_REFERENCE: + dprintk(VIDC_INFO, "HFI_EVENT_RELEASE_BUFFER_REFERENCE[%#x]\n", + pkt->session_id); + 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; + + dprintk(VIDC_DBG, "RECEIVED: SYS_INIT_DONE\n"); + if (sizeof(struct hfi_msg_sys_init_done_packet) > pkt->size) { + dprintk(VIDC_ERR, "%s: bad_pkt_size: %d\n", __func__, + pkt->size); + return -E2BIG; + } + if (!pkt->num_properties) { + dprintk(VIDC_ERR, + "hal_process_sys_init_done: no_properties\n"); + status = VIDC_ERR_FAIL; + goto err_no_prop; + } + + status = hfi_map_err_status(pkt->error_type); + if (status) { + dprintk(VIDC_ERR, "%s: status %#x\n", + __func__, status); + goto err_no_prop; + } + +err_no_prop: + cmd_done.device_id = device_id; + cmd_done.session_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; + + dprintk(VIDC_DBG, "RECEIVED: SYS_RELEASE_RESOURCE_DONE\n"); + pkt_size = sizeof(struct hfi_msg_sys_release_resource_done_packet); + if (pkt_size > pkt->size) { + dprintk(VIDC_ERR, + "hal_process_sys_rel_resource_done: bad size: %d\n", + pkt->size); + return -E2BIG; + } + + status = hfi_map_err_status(pkt->error_type); + cmd_done.device_id = device_id; + cmd_done.session_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; +} + +enum hal_capability get_hal_cap_type(u32 capability_type) +{ + enum hal_capability hal_cap = 0; + + switch (capability_type) { + case HFI_CAPABILITY_FRAME_WIDTH: + hal_cap = HAL_CAPABILITY_FRAME_WIDTH; + break; + case HFI_CAPABILITY_FRAME_HEIGHT: + hal_cap = HAL_CAPABILITY_FRAME_HEIGHT; + break; + case HFI_CAPABILITY_MBS_PER_FRAME: + hal_cap = HAL_CAPABILITY_MBS_PER_FRAME; + break; + case HFI_CAPABILITY_MBS_PER_SECOND: + hal_cap = HAL_CAPABILITY_MBS_PER_SECOND; + break; + case HFI_CAPABILITY_FRAMERATE: + hal_cap = HAL_CAPABILITY_FRAMERATE; + break; + case HFI_CAPABILITY_SCALE_X: + hal_cap = HAL_CAPABILITY_SCALE_X; + break; + case HFI_CAPABILITY_SCALE_Y: + hal_cap = HAL_CAPABILITY_SCALE_Y; + break; + case HFI_CAPABILITY_BITRATE: + hal_cap = HAL_CAPABILITY_BITRATE; + break; + case HFI_CAPABILITY_BFRAME: + hal_cap = HAL_CAPABILITY_BFRAME; + break; + case HFI_CAPABILITY_PEAKBITRATE: + hal_cap = HAL_CAPABILITY_PEAKBITRATE; + break; + case HFI_CAPABILITY_HIER_P_NUM_ENH_LAYERS: + hal_cap = HAL_CAPABILITY_HIER_P_NUM_ENH_LAYERS; + break; + case HFI_CAPABILITY_ENC_LTR_COUNT: + hal_cap = HAL_CAPABILITY_ENC_LTR_COUNT; + break; + case HFI_CAPABILITY_CP_OUTPUT2_THRESH: + hal_cap = HAL_CAPABILITY_SECURE_OUTPUT2_THRESHOLD; + break; + case HFI_CAPABILITY_HIER_B_NUM_ENH_LAYERS: + hal_cap = HAL_CAPABILITY_HIER_B_NUM_ENH_LAYERS; + break; + case HFI_CAPABILITY_LCU_SIZE: + hal_cap = HAL_CAPABILITY_LCU_SIZE; + break; + case HFI_CAPABILITY_HIER_P_HYBRID_NUM_ENH_LAYERS: + hal_cap = HAL_CAPABILITY_HIER_P_HYBRID_NUM_ENH_LAYERS; + break; + case HFI_CAPABILITY_MBS_PER_SECOND_POWERSAVE: + hal_cap = HAL_CAPABILITY_MBS_PER_SECOND_POWER_SAVE; + break; + case HFI_CAPABILITY_EXTRADATA: + hal_cap = HAL_CAPABILITY_EXTRADATA; + break; + case HFI_CAPABILITY_PROFILE: + hal_cap = HAL_CAPABILITY_PROFILE; + break; + case HFI_CAPABILITY_LEVEL: + hal_cap = HAL_CAPABILITY_LEVEL; + break; + case HFI_CAPABILITY_I_FRAME_QP: + hal_cap = HAL_CAPABILITY_I_FRAME_QP; + break; + case HFI_CAPABILITY_P_FRAME_QP: + hal_cap = HAL_CAPABILITY_P_FRAME_QP; + break; + case HFI_CAPABILITY_B_FRAME_QP: + hal_cap = HAL_CAPABILITY_B_FRAME_QP; + break; + case HFI_CAPABILITY_RATE_CONTROL_MODES: + hal_cap = HAL_CAPABILITY_RATE_CONTROL_MODES; + break; + case HFI_CAPABILITY_BLUR_WIDTH: + hal_cap = HAL_CAPABILITY_BLUR_WIDTH; + break; + case HFI_CAPABILITY_BLUR_HEIGHT: + hal_cap = HAL_CAPABILITY_BLUR_HEIGHT; + break; + case HFI_CAPABILITY_ROTATION: + hal_cap = HAL_CAPABILITY_ROTATION; + break; + case HFI_CAPABILITY_COLOR_SPACE_CONVERSION: + hal_cap = HAL_CAPABILITY_COLOR_SPACE_CONVERSION; + break; + case HFI_CAPABILITY_SLICE_DELIVERY_MODES: + hal_cap = HAL_CAPABILITY_SLICE_DELIVERY_MODES; + break; + case HFI_CAPABILITY_SLICE_BYTE: + hal_cap = HAL_CAPABILITY_SLICE_BYTE; + break; + case HFI_CAPABILITY_SLICE_MB: + hal_cap = HAL_CAPABILITY_SLICE_MB; + break; + case HFI_CAPABILITY_SECURE: + hal_cap = HAL_CAPABILITY_SECURE; + break; + case HFI_CAPABILITY_MAX_NUM_B_FRAMES: + hal_cap = HAL_CAPABILITY_MAX_NUM_B_FRAMES; + break; + case HFI_CAPABILITY_MAX_VIDEOCORES: + hal_cap = HAL_CAPABILITY_MAX_VIDEOCORES; + break; + case HFI_CAPABILITY_MAX_WORKMODES: + hal_cap = HAL_CAPABILITY_MAX_WORKMODES; + break; + case HFI_CAPABILITY_UBWC_CR_STATS: + hal_cap = HAL_CAPABILITY_UBWC_CR_STATS; + break; + default: + dprintk(VIDC_DBG, "%s: unknown capablity %#x\n", + __func__, capability_type); + break; + } + + return hal_cap; +} + +static inline void copy_cap_prop( + struct hfi_capability_supported *in, + struct msm_vidc_capability *capability) +{ + struct hal_capability_supported *out = NULL; + + if (!in || !capability) { + dprintk(VIDC_ERR, "%s Invalid input parameters\n", + __func__); + return; + } + + switch (in->capability_type) { + case HFI_CAPABILITY_FRAME_WIDTH: + out = &capability->width; + break; + case HFI_CAPABILITY_FRAME_HEIGHT: + out = &capability->height; + break; + case HFI_CAPABILITY_MBS_PER_FRAME: + out = &capability->mbs_per_frame; + break; + case HFI_CAPABILITY_MBS_PER_SECOND: + out = &capability->mbs_per_sec; + break; + case HFI_CAPABILITY_FRAMERATE: + out = &capability->frame_rate; + break; + case HFI_CAPABILITY_SCALE_X: + out = &capability->scale_x; + break; + case HFI_CAPABILITY_SCALE_Y: + out = &capability->scale_y; + break; + case HFI_CAPABILITY_BITRATE: + out = &capability->bitrate; + break; + case HFI_CAPABILITY_BFRAME: + out = &capability->bframe; + break; + case HFI_CAPABILITY_PEAKBITRATE: + out = &capability->peakbitrate; + break; + case HFI_CAPABILITY_HIER_P_NUM_ENH_LAYERS: + out = &capability->hier_p; + break; + case HFI_CAPABILITY_ENC_LTR_COUNT: + out = &capability->ltr_count; + break; + case HFI_CAPABILITY_CP_OUTPUT2_THRESH: + out = &capability->secure_output2_threshold; + break; + case HFI_CAPABILITY_HIER_B_NUM_ENH_LAYERS: + out = &capability->hier_b; + break; + case HFI_CAPABILITY_LCU_SIZE: + out = &capability->lcu_size; + break; + case HFI_CAPABILITY_HIER_P_HYBRID_NUM_ENH_LAYERS: + out = &capability->hier_p_hybrid; + break; + case HFI_CAPABILITY_MBS_PER_SECOND_POWERSAVE: + out = &capability->mbs_per_sec_power_save; + break; + case HFI_CAPABILITY_EXTRADATA: + out = &capability->extradata; + break; + case HFI_CAPABILITY_PROFILE: + out = &capability->profile; + break; + case HFI_CAPABILITY_LEVEL: + out = &capability->level; + break; + case HFI_CAPABILITY_I_FRAME_QP: + out = &capability->i_qp; + break; + case HFI_CAPABILITY_P_FRAME_QP: + out = &capability->p_qp; + break; + case HFI_CAPABILITY_B_FRAME_QP: + out = &capability->b_qp; + break; + case HFI_CAPABILITY_RATE_CONTROL_MODES: + out = &capability->rc_modes; + break; + case HFI_CAPABILITY_BLUR_WIDTH: + out = &capability->blur_width; + break; + case HFI_CAPABILITY_BLUR_HEIGHT: + out = &capability->blur_height; + break; + case HFI_CAPABILITY_ROTATION: + out = &capability->rotation; + break; + case HFI_CAPABILITY_COLOR_SPACE_CONVERSION: + out = &capability->color_space_caps; + break; + case HFI_CAPABILITY_SLICE_DELIVERY_MODES: + out = &capability->slice_delivery_mode; + break; + case HFI_CAPABILITY_SLICE_BYTE: + out = &capability->slice_bytes; + break; + case HFI_CAPABILITY_SLICE_MB: + out = &capability->slice_mbs; + break; + case HFI_CAPABILITY_SECURE: + out = &capability->secure; + break; + case HFI_CAPABILITY_MAX_NUM_B_FRAMES: + out = &capability->max_num_b_frames; + break; + case HFI_CAPABILITY_MAX_VIDEOCORES: + out = &capability->max_video_cores; + break; + case HFI_CAPABILITY_MAX_WORKMODES: + out = &capability->max_work_modes; + break; + case HFI_CAPABILITY_UBWC_CR_STATS: + out = &capability->ubwc_cr_stats; + break; + default: + dprintk(VIDC_DBG, "%s: unknown capablity %#x\n", + __func__, in->capability_type); + break; + } + + if (out) { + out->capability_type = get_hal_cap_type(in->capability_type); + out->min = in->min; + out->max = in->max; + out->step_size = in->step_size; + } +} + +static int hfi_fill_codec_info(u8 *data_ptr, + struct vidc_hal_sys_init_done *sys_init_done, u32 rem_size) +{ + u32 i; + u32 codecs = 0, codec_count = 0, size = 0; + struct msm_vidc_capability *capability; + u32 prop_id = *((u32 *)data_ptr); + u8 *orig_data_ptr = data_ptr; + + if (prop_id == HFI_PROPERTY_PARAM_CODEC_SUPPORTED) { + struct hfi_codec_supported *prop; + + if (!validate_pkt_size(rem_size - sizeof(u32), + sizeof(struct hfi_codec_supported))) + return -E2BIG; + data_ptr = data_ptr + sizeof(u32); + prop = (struct hfi_codec_supported *) data_ptr; + sys_init_done->dec_codec_supported = + prop->decoder_codec_supported; + sys_init_done->enc_codec_supported = + prop->encoder_codec_supported; + size = sizeof(struct hfi_codec_supported) + sizeof(u32); + rem_size -= + sizeof(struct hfi_codec_supported) + sizeof(u32); + } else { + dprintk(VIDC_WARN, + "%s: prop_id %#x, expected codec_supported property\n", + __func__, prop_id); + } + + codecs = sys_init_done->dec_codec_supported; + for (i = 0; i < 8 * sizeof(codecs); i++) { + if ((1 << i) & codecs) { + capability = + &sys_init_done->capabilities[codec_count++]; + capability->codec = + vidc_get_hal_codec((1 << i) & codecs); + capability->domain = + vidc_get_hal_domain(HFI_VIDEO_DOMAIN_DECODER); + if (codec_count == VIDC_MAX_DECODE_SESSIONS) { + dprintk(VIDC_ERR, + "Max supported decoder sessions reached"); + break; + } + } + } + codecs = sys_init_done->enc_codec_supported; + for (i = 0; i < 8 * sizeof(codecs); i++) { + if ((1 << i) & codecs) { + capability = + &sys_init_done->capabilities[codec_count++]; + capability->codec = + vidc_get_hal_codec((1 << i) & codecs); + capability->domain = + vidc_get_hal_domain(HFI_VIDEO_DOMAIN_ENCODER); + if (codec_count == VIDC_MAX_SESSIONS) { + dprintk(VIDC_ERR, + "Max supported sessions reached"); + break; + } + } + } + sys_init_done->codec_count = codec_count; + + if (!validate_pkt_size(rem_size, sizeof(u32))) + return -E2BIG; + prop_id = *((u32 *)(orig_data_ptr + size)); + if (prop_id == HFI_PROPERTY_PARAM_MAX_SESSIONS_SUPPORTED) { + struct hfi_max_sessions_supported *prop; + + if (!validate_pkt_size(rem_size - sizeof(u32), sizeof(struct + hfi_max_sessions_supported))) + return -E2BIG; + prop = (struct hfi_max_sessions_supported *) + (orig_data_ptr + size + sizeof(u32)); + + sys_init_done->max_sessions_supported = prop->max_sessions; + size += sizeof(struct hfi_max_sessions_supported) + sizeof(u32); + rem_size -= + sizeof(struct hfi_max_sessions_supported) + sizeof(u32); + dprintk(VIDC_DBG, "max_sessions_supported %d\n", + prop->max_sessions); + } + return size; +} + +static int copy_profile_caps_to_sessions(struct hfi_profile_level *prof, + u32 profile_count, struct msm_vidc_capability *capabilities, + u32 num_sessions, u32 codecs, u32 domain) +{ + u32 i = 0, j = 0; + struct msm_vidc_capability *capability; + u32 sess_codec; + u32 sess_domain; + + /* + * iterate over num_sessions and copy all the profile capabilities + * to matching sessions. + */ + for (i = 0; i < num_sessions; i++) { + sess_codec = 0; + sess_domain = 0; + capability = &capabilities[i]; + + if (capability->codec) + sess_codec = + vidc_get_hfi_codec(capability->codec); + if (capability->domain) + sess_domain = + vidc_get_hfi_domain(capability->domain); + + if (!(sess_codec & codecs && sess_domain & domain)) + continue; + + capability->profile_level.profile_count = profile_count; + for (j = 0; j < profile_count; j++) { + /* HFI and HAL follow same enums, hence no conversion */ + capability->profile_level.profile_level[j].profile = + prof[j].profile; + capability->profile_level.profile_level[j].level = + prof[j].level; + } + } + + return 0; +} + +static int copy_caps_to_sessions(struct hfi_capability_supported *cap, + u32 num_caps, struct msm_vidc_capability *capabilities, + u32 num_sessions, u32 codecs, u32 domain) +{ + u32 i = 0, j = 0; + struct msm_vidc_capability *capability; + u32 sess_codec; + u32 sess_domain; + + /* + * iterate over num_sessions and copy all the capabilities + * to matching sessions. + */ + for (i = 0; i < num_sessions; i++) { + sess_codec = 0; + sess_domain = 0; + capability = &capabilities[i]; + + if (capability->codec) + sess_codec = + vidc_get_hfi_codec(capability->codec); + if (capability->domain) + sess_domain = + vidc_get_hfi_domain(capability->domain); + + if (!(sess_codec & codecs && sess_domain & domain)) + continue; + + for (j = 0; j < num_caps; j++) + copy_cap_prop(&cap[j], capability); + } + + return 0; +} + +static int copy_nal_stream_format_caps_to_sessions(u32 nal_stream_format_value, + struct msm_vidc_capability *capabilities, u32 num_sessions, + u32 codecs, u32 domain) +{ + u32 i = 0; + struct msm_vidc_capability *capability; + u32 sess_codec; + u32 sess_domain; + + for (i = 0; i < num_sessions; i++) { + sess_codec = 0; + sess_domain = 0; + capability = &capabilities[i]; + + if (capability->codec) + sess_codec = + vidc_get_hfi_codec(capability->codec); + if (capability->domain) + sess_domain = + vidc_get_hfi_domain(capability->domain); + + if (!(sess_codec & codecs && sess_domain & domain)) + continue; + + capability->nal_stream_format.nal_stream_format_supported = + nal_stream_format_value; + } + + return 0; +} + +static enum vidc_status hfi_parse_init_done_properties( + struct msm_vidc_capability *capabilities, + u32 num_sessions, u8 *data_ptr, u32 num_properties, + u32 rem_bytes) +{ + enum vidc_status status = VIDC_ERR_NONE; + u32 prop_id, next_offset; + u32 codecs = 0, domain = 0; + +#define VALIDATE_PROPERTY_STRUCTURE_SIZE(pkt_size, property_size) ({\ + if (pkt_size < property_size) { \ + status = VIDC_ERR_BAD_PARAM; \ + break; \ + } \ +}) + +#define VALIDATE_PROPERTY_PAYLOAD_SIZE(pkt_size, payload_size, \ + property_count) ({\ + if (pkt_size/payload_size < property_count) { \ + status = VIDC_ERR_BAD_PARAM; \ + break; \ + } \ +}) + + while (status == VIDC_ERR_NONE && num_properties && + rem_bytes >= sizeof(u32)) { + + prop_id = *((u32 *)data_ptr); + next_offset = sizeof(u32); + + switch (prop_id) { + case HFI_PROPERTY_PARAM_CODEC_MASK_SUPPORTED: + { + struct hfi_codec_mask_supported *prop = + (struct hfi_codec_mask_supported *) + (data_ptr + next_offset); + + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(*prop)); + + codecs = prop->codecs; + domain = prop->video_domains; + next_offset += sizeof(struct hfi_codec_mask_supported); + num_properties--; + break; + } + case HFI_PROPERTY_PARAM_CAPABILITY_SUPPORTED: + { + struct hfi_capability_supported_info *prop = + (struct hfi_capability_supported_info *) + (data_ptr + next_offset); + + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(*prop)); + VALIDATE_PROPERTY_PAYLOAD_SIZE(rem_bytes - + next_offset - sizeof(u32), + sizeof(struct hfi_capability_supported), + prop->num_capabilities); + + next_offset += sizeof(u32) + + prop->num_capabilities * + sizeof(struct hfi_capability_supported); + + copy_caps_to_sessions(&prop->rg_data[0], + prop->num_capabilities, + capabilities, num_sessions, + codecs, domain); + num_properties--; + break; + } + case HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SUPPORTED: + { + struct hfi_uncompressed_format_supported *prop = + (struct hfi_uncompressed_format_supported *) + (data_ptr + next_offset); + u32 num_format_entries; + char *fmt_ptr; + struct hfi_uncompressed_plane_info *plane_info; + + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(*prop)); + + num_format_entries = prop->format_entries; + next_offset = sizeof(*prop); + fmt_ptr = (char *)&prop->rg_format_info[0]; + + while (num_format_entries) { + u32 bytes_to_skip; + + plane_info = + (struct hfi_uncompressed_plane_info *) fmt_ptr; + + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(*plane_info)); + + bytes_to_skip = sizeof(*plane_info) - + sizeof(struct + hfi_uncompressed_plane_constraints) + + plane_info->num_planes * + sizeof(struct + hfi_uncompressed_plane_constraints); + + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + bytes_to_skip); + + fmt_ptr += bytes_to_skip; + next_offset += bytes_to_skip; + num_format_entries--; + } + num_properties--; + break; + } + case HFI_PROPERTY_PARAM_PROPERTIES_SUPPORTED: + { + struct hfi_properties_supported *prop = + (struct hfi_properties_supported *) + (data_ptr + next_offset); + + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(*prop)); + VALIDATE_PROPERTY_PAYLOAD_SIZE(rem_bytes - + next_offset - sizeof(*prop) + + sizeof(u32), sizeof(u32), + prop->num_properties); + + next_offset += sizeof(*prop) - sizeof(u32) + + prop->num_properties * sizeof(u32); + num_properties--; + break; + } + case HFI_PROPERTY_PARAM_PROFILE_LEVEL_SUPPORTED: + { + struct hfi_profile_level_supported *prop = + (struct hfi_profile_level_supported *) + (data_ptr + next_offset); + + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(*prop)); + VALIDATE_PROPERTY_PAYLOAD_SIZE(rem_bytes - + next_offset - + sizeof(u32), + sizeof(struct hfi_profile_level), + prop->profile_count); + + next_offset += sizeof(u32) + + prop->profile_count * + sizeof(struct hfi_profile_level); + + if (prop->profile_count > MAX_PROFILE_COUNT) { + prop->profile_count = MAX_PROFILE_COUNT; + dprintk(VIDC_WARN, + "prop count exceeds max profile count\n"); + break; + } + + copy_profile_caps_to_sessions( + &prop->rg_profile_level[0], + prop->profile_count, capabilities, + num_sessions, codecs, domain); + num_properties--; + break; + } + case HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SUPPORTED: + { + struct hfi_nal_stream_format_supported *prop = + (struct hfi_nal_stream_format_supported *) + (data_ptr + next_offset); + + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(*prop)); + + copy_nal_stream_format_caps_to_sessions( + prop->nal_stream_format_supported, + capabilities, num_sessions, + codecs, domain); + + next_offset += + sizeof(struct hfi_nal_stream_format_supported); + num_properties--; + break; + } + case HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SELECT: + { + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(u32)); + next_offset += sizeof(u32); + num_properties--; + break; + } + case HFI_PROPERTY_PARAM_VENC_INTRA_REFRESH: + { + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(struct hfi_intra_refresh)); + next_offset += + sizeof(struct hfi_intra_refresh); + num_properties--; + break; + } + case HFI_PROPERTY_TME_VERSION_SUPPORTED: + { + VALIDATE_PROPERTY_STRUCTURE_SIZE(rem_bytes - + next_offset, + sizeof(u32)); + capabilities->tme_version = + *((u32 *)(data_ptr + next_offset)); + next_offset += + sizeof(u32); + num_properties--; + break; + } + default: + dprintk(VIDC_DBG, + "%s: default case - data_ptr %pK, prop_id 0x%x\n", + __func__, data_ptr, prop_id); + break; + } + + if (rem_bytes > next_offset) { + rem_bytes -= next_offset; + data_ptr += next_offset; + } else { + rem_bytes = 0; + } + } + + return status; +} + +enum vidc_status hfi_process_sys_init_done_prop_read( + struct hfi_msg_sys_init_done_packet *pkt, + struct vidc_hal_sys_init_done *sys_init_done) +{ + enum vidc_status status = VIDC_ERR_NONE; + int bytes_read; + u32 rem_bytes, num_properties; + u8 *data_ptr; + + if (!pkt || !sys_init_done) { + dprintk(VIDC_ERR, + "hfi_msg_sys_init_done: Invalid input\n"); + return VIDC_ERR_FAIL; + } + if (pkt->size < sizeof(struct hfi_msg_sys_init_done_packet)) { + dprintk(VIDC_ERR, "%s: bad_packet_size: %d\n", + __func__, pkt->size); + return VIDC_ERR_FAIL; + } + + rem_bytes = pkt->size - sizeof(struct + hfi_msg_sys_init_done_packet) + sizeof(u32); + + if (!rem_bytes) { + dprintk(VIDC_ERR, + "hfi_msg_sys_init_done: missing_prop_info\n"); + return VIDC_ERR_FAIL; + } + + status = hfi_map_err_status(pkt->error_type); + if (status) { + dprintk(VIDC_ERR, "%s: status %#x\n", __func__, status); + return status; + } + + data_ptr = (u8 *) &pkt->rg_property_data[0]; + num_properties = pkt->num_properties; + dprintk(VIDC_DBG, + "%s: data_start %pK, num_properties %#x\n", + __func__, data_ptr, num_properties); + if (!num_properties) { + sys_init_done->capabilities = NULL; + dprintk(VIDC_DBG, + "Venus didn't set any properties in SYS_INIT_DONE"); + return status; + } + bytes_read = hfi_fill_codec_info(data_ptr, sys_init_done, rem_bytes); + if (bytes_read < 0) + return VIDC_ERR_FAIL; + data_ptr += bytes_read; + rem_bytes -= bytes_read; + num_properties--; + + status = hfi_parse_init_done_properties( + sys_init_done->capabilities, + VIDC_MAX_SESSIONS, data_ptr, num_properties, + rem_bytes); + if (status) { + dprintk(VIDC_ERR, "%s: parse status %#x\n", + __func__, status); + return status; + } + + return status; +} + +static void hfi_process_sess_get_prop_buf_req( + struct hfi_msg_session_property_info_packet *prop, + struct buffer_requirements *buffreq) +{ + struct hfi_buffer_requirements *hfi_buf_req; + u32 req_bytes; + + if (!prop) { + dprintk(VIDC_ERR, + "hal_process_sess_get_prop_buf_req: bad_prop: %pK\n", + 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]) { + dprintk(VIDC_ERR, + "hal_process_sess_get_prop_buf_req: bad_pkt: %d\n", + req_bytes); + return; + } + + hfi_buf_req = (struct hfi_buffer_requirements *) + &prop->rg_property_data[1]; + + if (!hfi_buf_req) { + dprintk(VIDC_ERR, "%s - invalid buffer req pointer\n", + __func__); + return; + } + + while (req_bytes) { + dprintk(VIDC_DBG, "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: + dprintk(VIDC_ERR, + "hal_process_sess_get_prop_buf_req: bad_buffer_type: %d\n", + 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} } }; + + dprintk(VIDC_DBG, "Received SESSION_PROPERTY_INFO[%#x]\n", + pkt->session_id); + + if (pkt->size < sizeof(struct hfi_msg_session_property_info_packet)) { + dprintk(VIDC_ERR, + "hal_process_session_prop_info: bad_pkt_size\n"); + return -E2BIG; + } else if (!pkt->num_properties) { + dprintk(VIDC_ERR, + "hal_process_session_prop_info: no_properties\n"); + return -EINVAL; + } + + switch (pkt->rg_property_data[0]) { + case HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS: + hfi_process_sess_get_prop_buf_req(pkt, &buff_req); + cmd_done.device_id = device_id; + cmd_done.session_id = (void *)(uintptr_t)pkt->session_id; + 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: + dprintk(VIDC_DBG, + "hal_process_session_prop_info: unknown_prop_id: %x\n", + 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}; + struct vidc_hal_session_init_done session_init_done = { {0} }; + + dprintk(VIDC_DBG, "RECEIVED: SESSION_INIT_DONE[%x]\n", pkt->session_id); + + if (sizeof(struct hfi_msg_sys_session_init_done_packet) > pkt->size) { + dprintk(VIDC_ERR, + "hal_process_session_init_done: bad_pkt_size\n"); + return -E2BIG; + } + + cmd_done.device_id = device_id; + cmd_done.session_id = (void *)(uintptr_t)pkt->session_id; + cmd_done.status = hfi_map_err_status(pkt->error_type); + cmd_done.data.session_init_done = session_init_done; + cmd_done.size = sizeof(struct vidc_hal_session_init_done); + + 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}; + + dprintk(VIDC_DBG, "RECEIVED: SESSION_LOAD_RESOURCES_DONE[%#x]\n", + pkt->session_id); + + if (sizeof(struct hfi_msg_session_load_resources_done_packet) != + pkt->size) { + dprintk(VIDC_ERR, + "hal_process_session_load_res_done: bad packet size: %d\n", + pkt->size); + return -E2BIG; + } + + cmd_done.device_id = device_id; + cmd_done.session_id = (void *)(uintptr_t)pkt->session_id; + 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}; + + dprintk(VIDC_DBG, "RECEIVED: SESSION_FLUSH_DONE[%#x]\n", + pkt->session_id); + + if (sizeof(struct hfi_msg_session_flush_done_packet) != pkt->size) { + dprintk(VIDC_ERR, + "hal_process_session_flush_done: bad packet size: %d\n", + pkt->size); + return -E2BIG; + } + + cmd_done.device_id = device_id; + cmd_done.session_id = (void *)(uintptr_t)pkt->session_id; + 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: + dprintk(VIDC_ERR, + "%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}; + struct hfi_picture_type *hfi_picture_type = NULL; + u32 is_sync_frame; + + dprintk(VIDC_DBG, "RECEIVED: SESSION_ETB_DONE[%#x]\n", pkt->session_id); + + if (!pkt || pkt->size < + sizeof(struct hfi_msg_session_empty_buffer_done_packet)) + goto bad_packet_size; + + data_done.device_id = device_id; + data_done.session_id = (void *)(uintptr_t)pkt->session_id; + 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.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); + is_sync_frame = pkt->rgData[0]; + if (is_sync_frame) { + if (pkt->size < + sizeof(struct hfi_msg_session_empty_buffer_done_packet) + + sizeof(struct hfi_picture_type)) + goto bad_packet_size; + hfi_picture_type = (struct hfi_picture_type *)&pkt->rgData[1]; + if (hfi_picture_type->picture_type) + data_done.input_done.flags = + hfi_picture_type->picture_type; + else + dprintk(VIDC_DBG, + "Non-Sync frame sent for H264/HEVC\n"); + } + + 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: + dprintk(VIDC_ERR, "%s: 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) { + dprintk(VIDC_ERR, "Invalid Params\n"); + 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)) { + dprintk(VIDC_ERR, "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; + dprintk(VIDC_DBG, "RECEIVED: SESSION_FTB_DONE[%#x]\n", + pkt->session_id); + if (sizeof(struct + hfi_msg_session_fill_buffer_done_compressed_packet) + > pkt->size) { + dprintk(VIDC_ERR, + "hal_process_session_ftb_done: bad_pkt_size\n"); + return -E2BIG; + } else if (pkt->error_type != HFI_ERR_NONE) { + dprintk(VIDC_ERR, + "got buffer back with error %x\n", + pkt->error_type); + /* Proceed with the FBD */ + } + + data_done.device_id = device_id; + data_done.session_id = (void *)(uintptr_t)pkt->session_id; + data_done.status = hfi_map_err_status(pkt->error_type); + data_done.size = sizeof(struct msm_vidc_cb_data_done); + data_done.clnt_data = 0; + + 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.input_tag = pkt->input_tag; + data_done.output_done.output_tag = pkt->output_tag; + data_done.output_done.mark_target = pkt->mark_target; + data_done.output_done.mark_data = pkt->mark_data; + 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; + + dprintk(VIDC_DBG, "RECEIVED: SESSION_FTB_DONE[%#x]\n", + pkt->session_id); + if (sizeof( + struct hfi_msg_session_fbd_uncompressed_plane0_packet) > + pkt->size) { + dprintk(VIDC_ERR, + "hal_process_session_ftb_done: bad_pkt_size\n"); + return -E2BIG; + } + + data_done.device_id = device_id; + data_done.session_id = (void *)(uintptr_t)pkt->session_id; + data_done.status = hfi_map_err_status(pkt->error_type); + data_done.size = sizeof(struct msm_vidc_cb_data_done); + data_done.clnt_data = 0; + + 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.mark_target = pkt->mark_target; + data_done.output_done.mark_data = pkt->mark_data; + 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_tag1 = pkt->input_tag2; + data_done.output_done.output_tag = pkt->output_tag; + 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}; + + dprintk(VIDC_DBG, "RECEIVED: SESSION_START_DONE[%#x]\n", + pkt->session_id); + + if (!pkt || pkt->size != + sizeof(struct hfi_msg_session_start_done_packet)) { + dprintk(VIDC_ERR, "%s: bad packet/packet size\n", + __func__); + return -E2BIG; + } + + cmd_done.device_id = device_id; + cmd_done.session_id = (void *)(uintptr_t)pkt->session_id; + 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}; + + dprintk(VIDC_DBG, "RECEIVED: SESSION_STOP_DONE[%#x]\n", + pkt->session_id); + + if (!pkt || pkt->size != + sizeof(struct hfi_msg_session_stop_done_packet)) { + dprintk(VIDC_ERR, "%s: bad packet/packet size\n", + __func__); + return -E2BIG; + } + + cmd_done.device_id = device_id; + cmd_done.session_id = (void *)(uintptr_t)pkt->session_id; + 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}; + + dprintk(VIDC_DBG, "RECEIVED: SESSION_RELEASE_RESOURCES_DONE[%#x]\n", + pkt->session_id); + + if (!pkt || pkt->size != + sizeof(struct hfi_msg_session_release_resources_done_packet)) { + dprintk(VIDC_ERR, "%s: bad packet/packet size\n", + __func__); + return -E2BIG; + } + + cmd_done.device_id = device_id; + cmd_done.session_id = (void *)(uintptr_t)pkt->session_id; + 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)) { + dprintk(VIDC_ERR, "bad packet/packet size %d\n", + pkt ? pkt->size : 0); + return -E2BIG; + } + dprintk(VIDC_DBG, "RECEIVED:SESSION_RELEASE_BUFFER_DONE[%#x]\n", + pkt->session_id); + + cmd_done.device_id = device_id; + cmd_done.size = sizeof(struct msm_vidc_cb_cmd_done); + cmd_done.session_id = (void *)(uintptr_t)pkt->session_id; + 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)) { + dprintk(VIDC_ERR, "%s: bad packet/packet size %d\n", + __func__, pkt ? pkt->size : 0); + return -E2BIG; + } + dprintk(VIDC_DBG, "RECEIVED: SESSION_REGISTER_BUFFERS_DONE[%#x]\n", + pkt->session_id); + + cmd_done.device_id = device_id; + cmd_done.size = sizeof(struct msm_vidc_cb_cmd_done); + cmd_done.session_id = (void *)(uintptr_t)pkt->session_id; + 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)) { + dprintk(VIDC_ERR, "%s: bad packet/packet size %d\n", + __func__, pkt ? pkt->size : 0); + return -E2BIG; + } + dprintk(VIDC_DBG, "RECEIVED: SESSION_UNREGISTER_BUFFERS_DONE[%#x]\n", + pkt->session_id); + + cmd_done.device_id = device_id; + cmd_done.size = sizeof(struct msm_vidc_cb_cmd_done); + cmd_done.session_id = (void *)(uintptr_t)pkt->session_id; + 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}; + + dprintk(VIDC_DBG, "RECEIVED: SESSION_END_DONE[%#x]\n", pkt->session_id); + + if (!pkt || pkt->size != + sizeof(struct hfi_msg_sys_session_end_done_packet)) { + dprintk(VIDC_ERR, "%s: bad packet/packet size\n", __func__); + return -E2BIG; + } + + cmd_done.device_id = device_id; + cmd_done.session_id = (void *)(uintptr_t)pkt->session_id; + 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}; + + dprintk(VIDC_DBG, "RECEIVED: SESSION_ABORT_DONE[%#x]\n", + pkt->session_id); + + if (!pkt || pkt->size != + sizeof(struct hfi_msg_sys_session_abort_done_packet)) { + dprintk(VIDC_ERR, "%s: bad packet/packet size: %d\n", + __func__, pkt ? pkt->size : 0); + return -E2BIG; + } + cmd_done.device_id = device_id; + cmd_done.session_id = (void *)(uintptr_t)pkt->session_id; + 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) +{ + int 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; + int req_bytes; + + req_bytes = pkt->size - sizeof(*pkt); + if (req_bytes < version_string_size || + !pkt->rg_property_data[1] || + pkt->num_properties > 1) { + dprintk(VIDC_ERR, "%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'; + dprintk(VIDC_DBG, "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) { + dprintk(VIDC_ERR, "%s: invalid param\n", __func__); + return -EINVAL; + } else if (pkt->size < sizeof(*pkt)) { + dprintk(VIDC_ERR, + "%s: bad_pkt_size\n", __func__); + return -E2BIG; + } else if (!pkt->num_properties) { + dprintk(VIDC_ERR, + "%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: + dprintk(VIDC_DBG, + "%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, + }; + + 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) { + dprintk(VIDC_ERR, "%s: bad packet/packet size\n", + __func__); + return -EINVAL; + } + + dprintk(VIDC_DBG, "Parse response %#x\n", msg_hdr->packet); + 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: + dprintk(VIDC_DBG, "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/drivers/media/platform/msm/vidc/msm_cvp.c b/drivers/media/platform/msm/vidc/msm_cvp.c new file mode 100644 index 000000000000..8616f2a9a231 --- /dev/null +++ b/drivers/media/platform/msm/vidc/msm_cvp.c @@ -0,0 +1,631 @@ +/* Copyright (c) 2018, 2020, 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 "msm_cvp.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, + "%s: %x : idx %2d fd %d off %d size %d type %d flags 0x%x\n", + str, hash32_ptr(inst->session), 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, + "%s: %x : idx %2d fd %d off %d daddr %x size %d type %d flags 0x%x\n", + str, hash32_ptr(inst->session), 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) +{ + 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 + dprintk(VIDC_ERR, "%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) { + dprintk(VIDC_ERR, "%s: invalid response\n", __func__); + return; + } + inst = get_inst(get_vidc_core(response->device_id), + response->session_id); + if (!inst) { + dprintk(VIDC_ERR, "%s: invalid session %pK\n", __func__, + response->session_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) { + dprintk(VIDC_ERR, "%s: client_data %x not found\n", + __func__, response->data.regbuf.client_data); + goto exit; + } + print_cvp_buffer(VIDC_DBG, "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: + 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) { + dprintk(VIDC_ERR, "%s: invalid response\n", __func__); + return; + } + inst = get_inst(get_vidc_core(response->device_id), + response->session_id); + if (!inst) { + dprintk(VIDC_ERR, "%s: invalid session %pK\n", __func__, + response->session_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; + } + } + if (!found) { + dprintk(VIDC_ERR, "%s: client_data %x not found\n", + __func__, response->data.unregbuf.client_data); + goto exit; + } + print_cvp_buffer(VIDC_DBG, "unregister_done", inst, cbuf); + + rc = msm_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); + + list_del(&cbuf->list); + kfree(cbuf); + cbuf = NULL; +exit: + mutex_unlock(&inst->cvpbufs.lock); + 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) { + dprintk(VIDC_ERR, "session %#x, vpss %d ise %d\n", + hash32_ptr(temp->session), + 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) { + dprintk(VIDC_ERR, "%s: invalid params\n", __func__); + 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) { + dprintk(VIDC_ERR, "%s: invalid params\n", __func__); + return -EINVAL; + } + + rc = msm_vidc_set_clocks(inst->core); + if (rc) { + dprintk(VIDC_ERR, + "%s: failed set_clocks for inst %pK (%#x)\n", + __func__, inst, hash32_ptr(inst->session)); + goto exit; + } + + rc = msm_comm_vote_bus(inst->core); + if (rc) { + dprintk(VIDC_ERR, + "%s: failed vote_bus for inst %pK (%#x)\n", + __func__, inst, hash32_ptr(inst->session)); + 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) { + dprintk(VIDC_ERR, "%s: invalid params\n", __func__); + return -EINVAL; + } + + session->session_id = hash32_ptr(inst->session); + dprintk(VIDC_DBG, "%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) { + dprintk(VIDC_ERR, "%s: invalid params\n", __func__); + return -EINVAL; + } + + dprintk(VIDC_DBG, + "%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) { + dprintk(VIDC_ERR, + "%s: session %#x rejected, cycles: vpss %d, ise %d\n", + __func__, hash32_ptr(inst->session), + 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) { + dprintk(VIDC_ERR, + "%s: failed to scale clocks and bus for inst %pK (%#x)\n", + __func__, inst, hash32_ptr(inst->session)); + 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) { + dprintk(VIDC_ERR, + "%s: failed to pause inst %pK (%#x)\n", + __func__, inst, hash32_ptr(inst->session)); + goto exit; + } + } else { + rc = msm_cvp_inst_resume(inst); + if (rc) { + dprintk(VIDC_ERR, + "%s: failed to resume inst %pK (%#x)\n", + __func__, inst, hash32_ptr(inst->session)); + 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) { + dprintk(VIDC_ERR, "%s: invalid params\n", __func__); + return -EINVAL; + } + hdev = inst->core->device; + print_client_buffer(VIDC_DBG, "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) { + dprintk(VIDC_ERR, "%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); + cbuf->smem.fd = buf->fd; + cbuf->smem.offset = buf->offset; + cbuf->smem.size = buf->size; + rc = msm_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); + 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) + msm_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) { + dprintk(VIDC_ERR, "%s: invalid params\n", __func__); + return -EINVAL; + } + hdev = inst->core->device; + print_client_buffer(VIDC_DBG, "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; + } + } + if (!found) { + print_client_buffer(VIDC_ERR, "invalid", inst, buf); + mutex_unlock(&inst->cvpbufs.lock); + return -EINVAL; + } + + memset(&vbuf, 0, sizeof(struct vidc_unregister_buffer)); + vbuf.index = cbuf->buf.index; + vbuf.type = get_hal_buftype(__func__, cbuf->buf.type); + 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); + + mutex_unlock(&inst->cvpbufs.lock); + return rc; +} + +int msm_vidc_cvp(struct msm_vidc_inst *inst, struct msm_vidc_arg *arg) +{ + int rc = 0; + + if (!inst || !arg) { + dprintk(VIDC_ERR, "%s: invalid args\n", __func__); + 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: + dprintk(VIDC_ERR, "%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_VIDC_VIDEO_SECURE, + .name = "Secure mode", + .type = V4L2_CTRL_TYPE_BUTTON, + .minimum = 0, + .maximum = 1, + .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) { + dprintk(VIDC_ERR, "%s: invalid params\n", __func__); + return -EINVAL; + } + hdev = inst->core->device; + + rc = call_hfi_op(hdev, session_pause, (void *)inst->session); + if (rc) + dprintk(VIDC_ERR, "%s: failed to pause inst %pK (%#x)\n", + __func__, inst, hash32_ptr(inst->session)); + + 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) { + dprintk(VIDC_ERR, "%s: invalid params\n", __func__); + return -EINVAL; + } + hdev = inst->core->device; + + rc = call_hfi_op(hdev, session_resume, (void *)inst->session); + if (rc) + dprintk(VIDC_ERR, "%s: failed to resume inst %pK (%#x)\n", + __func__, inst, hash32_ptr(inst->session)); + + 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) { + dprintk(VIDC_ERR, "%s: invalid params\n", __func__); + return -EINVAL; + } + dprintk(VIDC_DBG, "%s: inst %pK (%#x)\n", __func__, + inst, hash32_ptr(inst->session)); + + rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE); + if (rc) + dprintk(VIDC_ERR, "%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 = msm_smem_unmap_dma_buf(inst, &cbuf->smem); + if (rc) + dprintk(VIDC_ERR, "%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) + dprintk(VIDC_ERR, "%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) { + dprintk(VIDC_ERR, "%s: invalid params\n", __func__); + return -EINVAL; + } + + dprintk(VIDC_DBG, "%s: inst %pK (%#x)\n", __func__, + inst, hash32_ptr(inst->session)); + + /* 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/drivers/media/platform/msm/vidc/msm_cvp.h b/drivers/media/platform/msm/vidc/msm_cvp.h new file mode 100644 index 000000000000..f8dc75f443db --- /dev/null +++ b/drivers/media/platform/msm/vidc/msm_cvp.h @@ -0,0 +1,33 @@ +/* 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. + * + */ + +#ifndef _MSM_VIDC_CVP_H_ +#define _MSM_VIDC_CVP_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/drivers/media/platform/msm/vidc/msm_smem.c b/drivers/media/platform/msm/vidc/msm_smem.c new file mode 100644 index 000000000000..5395ca407c29 --- /dev/null +++ b/drivers/media/platform/msm/vidc/msm_smem.c @@ -0,0 +1,606 @@ +/* Copyright (c) 2012-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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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) +{ + 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) { + dprintk(VIDC_ERR, "Invalid params: %pK, %pK, %pK, %pK\n", + 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); + if (!cb) { + dprintk(VIDC_ERR, + "%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; + dprintk(VIDC_ERR, + "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) ?: -ENOMEM; + dprintk(VIDC_ERR, "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) ?: -ENOMEM; + dprintk(VIDC_ERR, "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 { + dprintk(VIDC_ERR, "sgl is NULL\n"); + rc = -ENOMEM; + goto mem_map_sg_failed; + } + + mapping_info->dev = cb->dev; + mapping_info->mapping = cb->mapping; + 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 { + dprintk(VIDC_DBG, "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) +{ + int rc = 0; + + if (!mapping_info) { + dprintk(VIDC_WARN, "Invalid mapping_info\n"); + return -EINVAL; + } + + if (!mapping_info->dev || !mapping_info->table || + !mapping_info->buf || !mapping_info->attach || + !mapping_info->cb_info) { + dprintk(VIDC_WARN, "Invalid params\n"); + return -EINVAL; + } + + trace_msm_smem_buffer_iommu_op_start("UNMAP", 0, 0, 0, 0, 0); + 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->mapping = 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) +{ + struct dma_buf *dma_buf; + + dma_buf = dma_buf_get(fd); + if (IS_ERR_OR_NULL(dma_buf)) { + dprintk(VIDC_ERR, "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) +{ + if (!dma_buf) { + dprintk(VIDC_ERR, "%s: NULL dma_buf\n", __func__); + return; + } + + dma_buf_put((struct dma_buf *)dma_buf); + + return; +} + +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; + + if (!inst || !smem) { + dprintk(VIDC_ERR, "%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); + if (!dbuf) { + rc = -EINVAL; + goto exit; + } + + smem->dma_buf = dbuf; + + rc = dma_buf_get_flags(dbuf, &ion_flags); + if (rc) { + dprintk(VIDC_ERR, "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; + + 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); + if (rc) { + dprintk(VIDC_ERR, "Failed to get device address: %d\n", rc); + goto exit; + } + temp = (u32)iova; + if ((dma_addr_t)temp != iova) { + dprintk(VIDC_ERR, "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) { + dprintk(VIDC_ERR, "%s: Invalid params: %pK %pK\n", + __func__, inst, smem); + rc = -EINVAL; + goto exit; + } + + if (smem->refcount) { + smem->refcount--; + } else { + dprintk(VIDC_WARN, + "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); + if (rc) { + dprintk(VIDC_ERR, "Failed to put device address: %d\n", rc); + goto exit; + } + + msm_smem_put_dma_buf(smem->dma_buf); + + 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) +{ + 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) { + dprintk(VIDC_ERR, "%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) { + dprintk(VIDC_DBG, "Allocating from ADSP heap\n"); + heap_mask = ION_HEAP(ION_ADSP_HEAP_ID); + } else { + heap_mask = ION_HEAP(ION_SYSTEM_HEAP_ID); + } + } else { + dprintk(VIDC_DBG, + "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)) { + dprintk(VIDC_ERR, + "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); + if (rc) { + dprintk(VIDC_ERR, "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) { + dprintk(VIDC_ERR, "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) { + dprintk(VIDC_ERR, + "Failed to map shared mem in kernel\n"); + rc = -EIO; + goto fail_map; + } + } + + dprintk(VIDC_DBG, + "%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) +{ + int rc = 0; + + dprintk(VIDC_DBG, + "%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); + 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 rc; +} + +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) +{ + int rc = 0; + + if (!smem || !size) { + dprintk(VIDC_ERR, "%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); + + return rc; +} + +int msm_smem_free(struct msm_smem *smem) +{ + int rc = 0; + + if (!smem) { + dprintk(VIDC_ERR, "NULL smem passed\n"); + return -EINVAL; + } + rc = free_dma_mem(smem); + + return rc; +}; + +int msm_smem_cache_operations(struct dma_buf *dbuf, + enum smem_cache_ops cache_op, unsigned long offset, unsigned long size) +{ + int rc = 0; + unsigned long flags = 0; + + if (!dbuf) { + dprintk(VIDC_ERR, "%s: Invalid params\n", __func__); + return -EINVAL; + } + + /* Return if buffer doesn't support caching */ + rc = dma_buf_get_flags(dbuf, &flags); + if (rc) { + dprintk(VIDC_ERR, "%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: + dprintk(VIDC_ERR, "%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) +{ + 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; + } + + list_for_each_entry(cb, &res->context_banks, list) { + if (cb->is_secure == is_secure && + cb->buffer_type & buffer_type) { + match = cb; + break; + } + } + if (!match) + dprintk(VIDC_ERR, + "%s: cb not found for buffer_type %x, is_secure %d\n", + __func__, buffer_type, is_secure); + + return match; +} + diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_private.c b/drivers/media/platform/msm/vidc/msm_v4l2_private.c new file mode 100644 index 000000000000..c9400a08a4e3 --- /dev/null +++ b/drivers/media/platform/msm/vidc/msm_v4l2_private.c @@ -0,0 +1,234 @@ +/* Copyright (c) 2018-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. + * + */ + +#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 __user *)arg; + + if (!kp || !up) { + dprintk(VIDC_ERR, "%s: invalid params\n", __func__); + 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: + dprintk(VIDC_ERR, "%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 __user *)arg; + + if (!kp || !up) { + dprintk(VIDC_ERR, "%s: invalid params\n", __func__); + 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: + dprintk(VIDC_ERR, "%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) { + dprintk(VIDC_ERR, "%s: invalid params\n", __func__); + 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) { + dprintk(VIDC_ERR, "%s: failed cmd type %x\n", + __func__, karg.type); + return -EINVAL; + } + + if (convert_to_user(&karg, arg)) + return -EFAULT; + + return rc; +} diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_private.h b/drivers/media/platform/msm/vidc/msm_v4l2_private.h new file mode 100644 index 000000000000..fa4472b527e4 --- /dev/null +++ b/drivers/media/platform/msm/vidc/msm_v4l2_private.h @@ -0,0 +1,22 @@ +/* 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. + * + */ + +#ifndef _MSM_V4L2_PRIVATE_H_ +#define _MSM_V4L2_PRIVATE_H_ + +#include +#include "msm_vidc_debug.h" + +long msm_v4l2_private(struct file *file, unsigned int cmd, unsigned long arg); + +#endif diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c new file mode 100644 index 000000000000..9a9b1b361a45 --- /dev/null +++ b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c @@ -0,0 +1,932 @@ +/* Copyright (c) 2012-2020, 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 +#include +#include +#include +#include +#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 "venus_boot.h" +#include "vidc_hfi_api.h" +#include "msm_v4l2_private.h" +#include "msm_vidc_clocks.h" +#include + +#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) { + dprintk(VIDC_ERR, + "Failed to create video 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_s_ext_ctrl(struct file *file, void *fh, + struct v4l2_ext_controls *a) +{ + struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh); + + return msm_vidc_s_ext_ctrl((void *)vidc_inst, a); +} + +int msm_v4l2_g_ext_ctrl(struct file *file, void *fh, + struct v4l2_ext_controls *a) +{ + struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh); + + return msm_vidc_g_ext_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_s_parm(struct file *file, void *fh, + struct v4l2_streamparm *a) +{ + struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh); + + return msm_vidc_comm_s_parm(vidc_inst, a); +} +static int msm_v4l2_g_parm(struct file *file, void *fh, + struct v4l2_streamparm *a) +{ + return 0; +} + +static int msm_v4l2_g_crop(struct file *file, void *fh, + struct v4l2_crop *a) +{ + struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh); + + return msm_vidc_g_crop(vidc_inst, a); +} + +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 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); +} + +static 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_s_ext_ctrls = msm_v4l2_s_ext_ctrl, + .vidioc_g_ext_ctrls = msm_v4l2_g_ext_ctrl, + .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_s_parm = msm_v4l2_s_parm, + .vidioc_g_parm = msm_v4l2_g_parm, + .vidioc_g_crop = msm_v4l2_g_crop, + .vidioc_enum_framesizes = msm_v4l2_enum_framesizes, + .vidioc_default = msm_v4l2_default, +}; + +static const struct v4l2_ioctl_ops msm_v4l2_enc_ioctl_ops = { +}; + +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) { + dprintk(VIDC_ERR, "%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 { + dprintk(VIDC_ERR, "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) { + dprintk(VIDC_ERR, "Failed to get platform resources\n"); + return rc; + } + + INIT_LIST_HEAD(&core->instances); + mutex_init(&core->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 msm_vidc_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(link_name, 0444, msm_vidc_link_name_show, NULL); + +static ssize_t store_pwr_collapse_delay(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 show_pwr_collapse_delay(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(pwr_collapse_delay, 0644, show_pwr_collapse_delay, + store_pwr_collapse_delay); + +static ssize_t show_thermal_level(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", vidc_driver->thermal_level); +} + +static ssize_t store_thermal_level(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) { + dprintk(VIDC_WARN, + "Invalid thermal level value: %s\n", buf); + return -EINVAL; + } + dprintk(VIDC_DBG, "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(thermal_level, 0644, show_thermal_level, + store_thermal_level); + +static ssize_t show_sku_version(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return scnprintf(buf, PAGE_SIZE, "%d", + vidc_driver->sku_version); +} + +static ssize_t store_sku_version(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + dprintk(VIDC_WARN, "store platform version is not allowed\n"); + return count; +} + +static DEVICE_ATTR(sku_version, 0444, show_sku_version, + store_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) { + dprintk(VIDC_ERR, "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) { + dprintk(VIDC_ERR, "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; + int nr = BASE_DEVICE_NUMBER; + + place_marker("M - DRIVER Video Start"); + + if (!vidc_driver) { + dprintk(VIDC_ERR, "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) { + dprintk(VIDC_ERR, "Failed to init core\n"); + goto err_core_init; + } + rc = sysfs_create_group(&pdev->dev.kobj, &msm_vidc_core_attr_group); + if (rc) { + dprintk(VIDC_ERR, + "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) { + dprintk(VIDC_ERR, "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) { + dprintk(VIDC_ERR, "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) { + dprintk(VIDC_ERR, "Failed to register video encoder\n"); + goto err_enc; + } + + /* setup the cvp device */ + if (core->resources.domain_cvp) { + rc = msm_vidc_register_video_device(MSM_VIDC_CVP, + nr + 2, core, dev); + if (rc) { + dprintk(VIDC_ERR, "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); + dprintk(VIDC_ERR, "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) ?: -EBADHANDLE; + if (rc != -EPROBE_DEFER) + dprintk(VIDC_ERR, "Failed to create HFI device\n"); + else + dprintk(VIDC_DBG, "msm_vidc: request probe defer\n"); + goto err_cores_exceeded; + } + + 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; + + dprintk(VIDC_DBG, "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) { + dprintk(VIDC_ERR, "Failed to trigger probe for sub-devices\n"); + goto err_fail_sub_device_probe; + } + + place_marker("M - DRIVER Video Ready"); + return rc; + +err_fail_sub_device_probe: + vidc_hfi_deinitialize(core->hfi_type, core->device); +err_cores_exceeded: + if (core->resources.domain_cvp) { + 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) { + dprintk(VIDC_ERR, "%s invalid input %pK", __func__, pdev); + return -EINVAL; + } + + core = dev_get_drvdata(&pdev->dev); + if (!core) { + dprintk(VIDC_ERR, "%s invalid core", __func__); + return -EINVAL; + } + + if (core->resources.use_non_secure_pil) + venus_boot_deinit(); + + vidc_hfi_deinitialize(core->hfi_type, core->device); + if (core->resources.domain_cvp) { + 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->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) { + dprintk(VIDC_ERR, "%s invalid core\n", __func__); + return -EINVAL; + } + + rc = msm_vidc_suspend(core->id); + if (rc == -ENOTSUPP) + rc = 0; + else if (rc) + dprintk(VIDC_WARN, "Failed to suspend: %d\n", rc); + + + return rc; +} + +static int msm_vidc_pm_resume(struct device *dev) +{ + update_marker("vidc resumed"); + dprintk(VIDC_INFO, "%s\n", __func__); + return 0; +} + +int msm_vidc_freeze_core(struct msm_vidc_core *core) +{ + int rc = 0; + int max_retry = 300; + struct hfi_device *hdev; + + hdev = core->device; + + mutex_lock(&core->lock); + + dprintk(VIDC_WARN, "%s: fatal SSR intended to dismantle vidc\n", + __func__); + + core->ssr_type = SSR_ERR_FATAL; + + if (core->state == VIDC_CORE_INIT_DONE) { + dprintk(VIDC_INFO, "%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) { + dprintk(VIDC_ERR, "%s: trigger_ssr failed\n", __func__); + core->trigger_ssr = false; + } + + } else { + dprintk(VIDC_WARN, "%s: video core %pK not initialized\n", + __func__, core); + } + mutex_unlock(&core->lock); + + while ((core->state != VIDC_CORE_UNINIT) && (max_retry > 0)) { + msleep(20); + max_retry--; + } + + mutex_lock(&core->lock); + core->trigger_ssr = false; + mutex_unlock(&core->lock); + + return rc; +} + +static int msm_vidc_pm_freeze(struct device *dev) +{ + int rc = 0; + struct msm_vidc_core *core; + + if (!dev || !dev->driver) + return 0; + + core = dev_get_drvdata(dev); + if (!core) + return 0; + + if (of_device_is_compatible(dev->of_node, "qcom,msm-vidc")) { + place_marker("vidc hibernation start"); + + rc = msm_vidc_freeze_core(core); + + place_marker("vidc hibernation end"); + } + + dprintk(VIDC_INFO, "%s: done\n", __func__); + + return rc; +} + +static const struct dev_pm_ops msm_vidc_pm_ops = { + .suspend = msm_vidc_pm_suspend, + .resume = msm_vidc_pm_resume, + .freeze = msm_vidc_pm_freeze, +}; + +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", + .owner = THIS_MODULE, + .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) { + dprintk(VIDC_ERR, + "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) + dprintk(VIDC_ERR, + "Failed to create debugfs for msm_vidc\n"); + + rc = platform_driver_register(&msm_vidc_driver); + if (rc) { + dprintk(VIDC_ERR, + "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/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c new file mode 100644 index 000000000000..ecbc73c54920 --- /dev/null +++ b/drivers/media/platform/msm/vidc/msm_vdec.c @@ -0,0 +1,1455 @@ +/* Copyright (c) 2012-2021, 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 "msm_vidc_internal.h" +#include "msm_vidc_common.h" +#include "vidc_hfi_api.h" +#include "msm_vidc_debug.h" +#include "msm_vidc_clocks.h" + +#define MSM_VDEC_DVC_NAME "msm_vdec_8974" +#define MIN_NUM_THUMBNAIL_MODE_OUTPUT_BUFFERS MIN_NUM_OUTPUT_BUFFERS +#define MIN_NUM_THUMBNAIL_MODE_CAPTURE_BUFFERS MIN_NUM_CAPTURE_BUFFERS +#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 MB_SIZE_IN_PIXEL (16 * 16) +#define OPERATING_FRAME_RATE_STEP (1 << 16) +#define MAX_VP9D_INST_COUNT 6 +#define MAX_4K_MBPF 38736 /* (4096 * 2304 / 256) */ +#define NUM_MBS_720P (((1280 + 15) >> 4) * ((720 + 15) >> 4)) +#define MAX_5k_MBPF 64800 /*(5760 * 2880 / 256) */ + +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 mpeg_video_output_order[] = { + "Display Order", + "Decode Order", + NULL +}; +static const char *const mpeg_vidc_video_alloc_mode_type[] = { + "Buffer Allocation Static", + "Buffer Allocation Dynamic Buffer" +}; + +static const char *const perf_level[] = { + "Nominal", + "Performance", + "Turbo" +}; + +static const char *const vp8_profile_level[] = { + "Unused", + "0.0", + "1.0", + "2.0", + "3.0", +}; + +static const char *const vp9_profile[] = { + "Unused", + "0", + "2_10", +}; + +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", +}; + +static const char *const mpeg2_profile[] = { + "Simple", + "Main", + "High", +}; + +static const char *const mpeg2_level[] = { + "0", + "1", + "2", + "3", +}; +static const char *const mpeg_vidc_video_entropy_mode[] = { + "CAVLC Entropy Mode", + "CABAC Entropy Mode", +}; + +static const char *const mpeg_vidc_video_dpb_color_format[] = { + "DPB Color Format None", + "DPB Color Format UBWC", + "DPB Color Format UBWC TP10", +}; + +static struct msm_vidc_ctrl msm_vdec_ctrls[] = { + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_OUTPUT_ORDER, + .name = "Output Order", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DISPLAY, + .maximum = V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DECODE, + .default_value = V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DISPLAY, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DISPLAY) | + (1 << V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DECODE) + ), + .qmenu = mpeg_video_output_order, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_PICTYPE_DEC_MODE, + .name = "Picture Type Decoding", + .type = V4L2_CTRL_TYPE_BITMASK, + .minimum = 0, + .maximum = (V4L2_MPEG_VIDC_VIDEO_PICTYPE_DECODE_I | + V4L2_MPEG_VIDC_VIDEO_PICTYPE_DECODE_P | + V4L2_MPEG_VIDC_VIDEO_PICTYPE_DECODE_B), + .default_value = (V4L2_MPEG_VIDC_VIDEO_PICTYPE_DECODE_I | + V4L2_MPEG_VIDC_VIDEO_PICTYPE_DECODE_P | + V4L2_MPEG_VIDC_VIDEO_PICTYPE_DECODE_B), + .step = 0, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .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_BUTTON, + .minimum = 0, + .maximum = 0, + .default_value = 0, + .step = 0, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA, + .name = "Extradata Type", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDC_EXTRADATA_NONE, + .maximum = V4L2_MPEG_VIDC_EXTRADATA_UBWC_CR_STATS_INFO, + .default_value = V4L2_MPEG_VIDC_EXTRADATA_NONE, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDC_EXTRADATA_NONE) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_INTERLACE_VIDEO) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_TIMESTAMP) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_S3D_FRAME_PACKING) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_FRAME_RATE) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_PANSCAN_WINDOW) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_RECOVERY_POINT_SEI) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_NUM_CONCEALED_MB) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_ASPECT_RATIO) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_MPEG2_SEQDISP) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_STREAM_USERDATA) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_FRAME_QP) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_OUTPUT_CROP) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_DISPLAY_COLOUR_SEI) | + (1 << + V4L2_MPEG_VIDC_EXTRADATA_CONTENT_LIGHT_LEVEL_SEI) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_VUI_DISPLAY) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_VPX_COLORSPACE) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_UBWC_CR_STATS_INFO) + ), + .qmenu = mpeg_video_vidc_extradata, + }, + { + .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, + .menu_skip_mask = 0, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_PROFILE, + .name = "H264 Profile", + .type = V4L2_CTRL_TYPE_MENU, + .maximum = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH, + .default_value = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, + .menu_skip_mask = 0, + .flags = V4L2_CTRL_FLAG_VOLATILE, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_LEVEL, + .name = "H264 Level", + .type = V4L2_CTRL_TYPE_MENU, + .maximum = V4L2_MPEG_VIDEO_H264_LEVEL_6_2, + .default_value = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + .menu_skip_mask = ( + (1 << V4L2_MPEG_VIDEO_H264_LEVEL_UNKNOWN) + ), + .flags = V4L2_CTRL_FLAG_VOLATILE, + .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_0, + .menu_skip_mask = 0, + .qmenu = vp8_profile_level, + .flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_VP9_PROFILE, + .name = "VP9 Profile", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDC_VIDEO_VP9_PROFILE_UNUSED, + .maximum = V4L2_MPEG_VIDC_VIDEO_VP9_PROFILE_P2_10, + .default_value = V4L2_MPEG_VIDC_VIDEO_VP9_PROFILE_P0, + .menu_skip_mask = 0, + .qmenu = vp9_profile, + .flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY, + }, + { + .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 = 0, + .qmenu = vp9_level, + .flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY, + }, + { + .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_HIGH, + .default_value = V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_SIMPLE, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_SIMPLE) | + (1 << V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_MAIN) | + (1 << V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_HIGH) + ), + .qmenu = mpeg2_profile, + .flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY, + }, + { + .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_3, + .default_value = V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_0, + .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) | + (1 << V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_3) + ), + .qmenu = mpeg2_level, + .flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY, + }, + { + .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, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, + .name = "CAPTURE Count", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = MIN_NUM_CAPTURE_BUFFERS, + .maximum = MAX_NUM_CAPTURE_BUFFERS, + .default_value = MIN_NUM_CAPTURE_BUFFERS, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + .flags = V4L2_CTRL_FLAG_VOLATILE, + }, + { + .id = V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, + .name = "OUTPUT Count", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = MIN_NUM_OUTPUT_BUFFERS, + .maximum = MAX_NUM_OUTPUT_BUFFERS, + .default_value = MIN_NUM_OUTPUT_BUFFERS, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + .flags = V4L2_CTRL_FLAG_VOLATILE, + }, + { + .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_CAVLC, + .step = 0, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) | + (1 << V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC) + ), + .qmenu = mpeg_vidc_video_entropy_mode, + .flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY, + }, + { + .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_DISABLE, + .step = 1, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_OPERATING_RATE, + .name = "Set Decoder Operating rate", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = INT_MAX, + .default_value = 0, + .step = 1, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_FRAME_RATE, + .name = "Set Decoder Frame rate", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = INT_MAX, + .default_value = 0, + .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, + }, +}; + +#define NUM_CTRLS ARRAY_SIZE(msm_vdec_ctrls) + +static u32 get_frame_size_compressed_full_yuv(int plane, + u32 max_mbs_per_frame, u32 size_per_mb) +{ + u32 frame_size; + + if (max_mbs_per_frame > MAX_4K_MBPF) + frame_size = (max_mbs_per_frame * size_per_mb * 3 / 2) / 4; + else + frame_size = (max_mbs_per_frame * size_per_mb * 3 / 2); + + /* multiply by 10/8 (1.25) to get size for 10 bit case */ + frame_size = frame_size + (frame_size >> 2); + + return frame_size; +} + +static u32 get_frame_size_compressed(int plane, + u32 max_mbs_per_frame, u32 size_per_mb) +{ + u32 frame_size; + + if (max_mbs_per_frame > MAX_4K_MBPF) + frame_size = (max_mbs_per_frame * size_per_mb * 3 / 2) / 4; + else + frame_size = (max_mbs_per_frame * size_per_mb * 3/2)/2; + + /* multiply by 10/8 (1.25) to get size for 10 bit case */ + frame_size = frame_size + (frame_size >> 2); + + return frame_size; +} + +static u32 get_frame_size(struct msm_vidc_inst *inst, + const struct msm_vidc_format *fmt, + int fmt_type, int plane) +{ + u32 frame_size = 0, num_mbs = 0; + u32 max_mbps = 0; + + if (fmt_type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + frame_size = fmt->get_frame_size(plane, + inst->capability.mbs_per_frame.max, + MB_SIZE_IN_PIXEL); + if (inst->flags & VIDC_SECURE) { + num_mbs = msm_vidc_get_mbs_per_frame(inst); + dprintk(VIDC_DBG, + "wxh= %dx%d num_mbs = %d max_mbpf = %d\n", + inst->prop.width[OUTPUT_PORT], + inst->prop.height[OUTPUT_PORT], + num_mbs, inst->capability.mbs_per_frame.max); + + max_mbps = inst->capability.mbs_per_frame.max; + if (num_mbs < NUM_MBS_720P && max_mbps <= MAX_5k_MBPF) + frame_size = ALIGN(frame_size, SZ_4K); + else + frame_size = ALIGN(frame_size/2, SZ_4K); + + dprintk(VIDC_DBG, + "Change secure input buffer size to %u\n", + frame_size); + } + + if (inst->buffer_size_limit && + (inst->buffer_size_limit < frame_size)) { + frame_size = inst->buffer_size_limit; + dprintk(VIDC_DBG, "input buffer size limited to %d\n", + frame_size); + } else { + dprintk(VIDC_DBG, "set input buffer size to %d\n", + frame_size); + } + } else if (fmt_type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + frame_size = fmt->get_frame_size(plane, + inst->capability.height.max, + inst->capability.width.max); + dprintk(VIDC_DBG, "set output buffer size to %d\n", + frame_size); + } else { + dprintk(VIDC_WARN, "Wrong format type\n"); + } + return frame_size; +} + +struct msm_vidc_format vdec_formats[] = { + { + .name = "YCbCr Semiplanar 4:2:0", + .description = "Y/CbCr 4:2:0", + .fourcc = V4L2_PIX_FMT_NV12, + .get_frame_size = get_frame_size_nv12, + .type = CAPTURE_PORT, + }, + { + .name = "YCbCr Semiplanar 4:2:0 10bit", + .description = "Y/CbCr 4:2:0 10bit", + .fourcc = V4L2_PIX_FMT_SDE_Y_CBCR_H2V2_P010_VENUS, + .get_frame_size = get_frame_size_p010, + .type = CAPTURE_PORT, + }, + { + .name = "UBWC YCbCr Semiplanar 4:2:0", + .description = "UBWC Y/CbCr 4:2:0", + .fourcc = V4L2_PIX_FMT_NV12_UBWC, + .get_frame_size = get_frame_size_nv12_ubwc, + .type = CAPTURE_PORT, + }, + { + .name = "UBWC YCbCr Semiplanar 4:2:0 10bit", + .description = "UBWC Y/CbCr 4:2:0 10bit", + .fourcc = V4L2_PIX_FMT_NV12_TP10_UBWC, + .get_frame_size = get_frame_size_tp10_ubwc, + .type = CAPTURE_PORT, + }, + { + .name = "Mpeg2", + .description = "Mpeg2 compressed format", + .fourcc = V4L2_PIX_FMT_MPEG2, + .get_frame_size = get_frame_size_compressed, + .type = OUTPUT_PORT, + .defer_outputs = false, + .input_min_count = 4, + .output_min_count = 6, + }, + { + .name = "H264", + .description = "H264 compressed format", + .fourcc = V4L2_PIX_FMT_H264, + .get_frame_size = get_frame_size_compressed, + .type = OUTPUT_PORT, + .defer_outputs = false, + .input_min_count = 4, + .output_min_count = 8, + }, + { + .name = "HEVC", + .description = "HEVC compressed format", + .fourcc = V4L2_PIX_FMT_HEVC, + .get_frame_size = get_frame_size_compressed, + .type = OUTPUT_PORT, + .defer_outputs = false, + .input_min_count = 4, + .output_min_count = 8, + }, + { + .name = "VP8", + .description = "VP8 compressed format", + .fourcc = V4L2_PIX_FMT_VP8, + .get_frame_size = get_frame_size_compressed_full_yuv, + .type = OUTPUT_PORT, + .defer_outputs = false, + .input_min_count = 4, + .output_min_count = 6, + }, + { + .name = "VP9", + .description = "VP9 compressed format", + .fourcc = V4L2_PIX_FMT_VP9, + .get_frame_size = get_frame_size_compressed_full_yuv, + .type = OUTPUT_PORT, + .defer_outputs = true, + .input_min_count = 4, + .output_min_count = 9, + }, +}; + +struct msm_vidc_format_constraint dec_pix_format_constraints[] = { + { + .fourcc = V4L2_PIX_FMT_SDE_Y_CBCR_H2V2_P010_VENUS, + .num_planes = 2, + .y_stride_multiples = 256, + .y_max_stride = 8192, + .y_min_plane_buffer_height_multiple = 32, + .y_buffer_alignment = 256, + .uv_stride_multiples = 256, + .uv_max_stride = 8192, + .uv_min_plane_buffer_height_multiple = 16, + .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 && + inst->fmts[OUTPUT_PORT].fourcc == 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_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f) +{ + struct msm_vidc_format *fmt = NULL; + struct msm_vidc_format_constraint *fmt_constraint = NULL; + struct hal_frame_size frame_sz; + unsigned int extra_idx = 0; + int rc = 0; + int ret = 0; + int i; + int max_input_size = 0; + + if (!inst || !f) { + dprintk(VIDC_ERR, "%s invalid parameters\n", __func__); + return -EINVAL; + } + + if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + fmt = msm_comm_get_pixel_fmt_fourcc(vdec_formats, + ARRAY_SIZE(vdec_formats), f->fmt.pix_mp.pixelformat, + CAPTURE_PORT); + if (!fmt || fmt->type != CAPTURE_PORT) { + dprintk(VIDC_ERR, + "Format: %d not supported on CAPTURE port\n", + f->fmt.pix_mp.pixelformat); + rc = -EINVAL; + goto err_invalid_fmt; + } + + if (inst->fmts[fmt->type].fourcc == f->fmt.pix_mp.pixelformat && + inst->prop.width[CAPTURE_PORT] == f->fmt.pix_mp.width && + inst->prop.height[CAPTURE_PORT] == + f->fmt.pix_mp.height) { + dprintk(VIDC_DBG, "No change in CAPTURE port params\n"); + return 0; + } + memcpy(&inst->fmts[fmt->type], fmt, + sizeof(struct msm_vidc_format)); + + inst->prop.width[CAPTURE_PORT] = f->fmt.pix_mp.width; + inst->prop.height[CAPTURE_PORT] = f->fmt.pix_mp.height; + rc = msm_vidc_check_session_supported(inst); + if (rc) { + dprintk(VIDC_ERR, + "%s: session not supported\n", __func__); + goto err_invalid_fmt; + } + + msm_comm_set_color_format(inst, + msm_comm_get_hal_output_buffer(inst), + f->fmt.pix_mp.pixelformat); + + fmt_constraint = + msm_comm_get_pixel_fmt_constraints(dec_pix_format_constraints, + ARRAY_SIZE(dec_pix_format_constraints), + f->fmt.pix_mp.pixelformat); + + if (!fmt_constraint) { + dprintk(VIDC_INFO, + "Format constraint not required for %d on CAPTURE port\n", + f->fmt.pix_mp.pixelformat); + } else { + rc = msm_comm_set_color_format_constraints(inst, + msm_comm_get_hal_output_buffer(inst), + fmt_constraint); + if (rc) { + dprintk(VIDC_ERR, + "Set constraint for %d failed on CAPTURE port\n", + f->fmt.pix_mp.pixelformat); + rc = -EINVAL; + goto err_invalid_fmt; + } + } + + inst->clk_data.opb_fourcc = f->fmt.pix_mp.pixelformat; + if (msm_comm_get_stream_output_mode(inst) == + HAL_VIDEO_DECODER_SECONDARY) { + frame_sz.buffer_type = HAL_BUFFER_OUTPUT2; + frame_sz.width = inst->prop.width[CAPTURE_PORT]; + frame_sz.height = inst->prop.height[CAPTURE_PORT]; + dprintk(VIDC_DBG, + "buffer type = %d width = %d, height = %d\n", + frame_sz.buffer_type, frame_sz.width, + frame_sz.height); + ret = msm_comm_try_set_prop(inst, + HAL_PARAM_FRAME_SIZE, &frame_sz); + } + + f->fmt.pix_mp.plane_fmt[0].sizeimage = + inst->fmts[fmt->type].get_frame_size(0, + f->fmt.pix_mp.height, f->fmt.pix_mp.width); + + extra_idx = EXTRADATA_IDX(inst->bufq[fmt->type].num_planes); + if (extra_idx && extra_idx < VIDEO_MAX_PLANES) { + f->fmt.pix_mp.plane_fmt[extra_idx].sizeimage = + VENUS_EXTRADATA_SIZE( + inst->prop.height[CAPTURE_PORT], + inst->prop.width[CAPTURE_PORT]); + } + + f->fmt.pix_mp.num_planes = inst->bufq[fmt->type].num_planes; + for (i = 0; i < inst->bufq[fmt->type].num_planes; i++) { + inst->bufq[CAPTURE_PORT].plane_sizes[i] = + f->fmt.pix_mp.plane_fmt[i].sizeimage; + } + + } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + + fmt = msm_comm_get_pixel_fmt_fourcc(vdec_formats, + ARRAY_SIZE(vdec_formats), + f->fmt.pix_mp.pixelformat, + OUTPUT_PORT); + if (!fmt || fmt->type != OUTPUT_PORT) { + dprintk(VIDC_ERR, + "Format: %d not supported on OUTPUT port\n", + f->fmt.pix_mp.pixelformat); + rc = -EINVAL; + goto err_invalid_fmt; + } + memcpy(&inst->fmts[fmt->type], fmt, + sizeof(struct msm_vidc_format)); + + if (inst->fmts[OUTPUT_PORT].fourcc == V4L2_PIX_FMT_VP9) { + if (msm_vidc_check_for_vp9d_overload(inst->core)) { + dprintk(VIDC_ERR, "VP9 Decode overload\n"); + rc = -ENOTSUPP; + goto err_invalid_fmt; + } + } + + rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE); + if (rc) { + dprintk(VIDC_ERR, "Failed to open instance\n"); + goto err_invalid_fmt; + } + + if (inst->fmts[fmt->type].fourcc == f->fmt.pix_mp.pixelformat && + inst->prop.width[OUTPUT_PORT] == f->fmt.pix_mp.width && + inst->prop.height[OUTPUT_PORT] == + f->fmt.pix_mp.height) { + dprintk(VIDC_DBG, "No change in OUTPUT port params\n"); + return 0; + } + inst->prop.width[OUTPUT_PORT] = f->fmt.pix_mp.width; + inst->prop.height[OUTPUT_PORT] = f->fmt.pix_mp.height; + rc = msm_vidc_check_session_supported(inst); + if (rc) { + dprintk(VIDC_ERR, + "%s: session not supported\n", __func__); + goto err_invalid_fmt; + } + + frame_sz.buffer_type = HAL_BUFFER_INPUT; + frame_sz.width = inst->prop.width[OUTPUT_PORT]; + frame_sz.height = inst->prop.height[OUTPUT_PORT]; + dprintk(VIDC_DBG, + "buffer type = %d width = %d, height = %d\n", + frame_sz.buffer_type, frame_sz.width, + frame_sz.height); + msm_comm_try_set_prop(inst, HAL_PARAM_FRAME_SIZE, &frame_sz); + + max_input_size = get_frame_size( + inst, &inst->fmts[fmt->type], f->type, 0); + if (f->fmt.pix_mp.plane_fmt[0].sizeimage > max_input_size || + !f->fmt.pix_mp.plane_fmt[0].sizeimage) { + f->fmt.pix_mp.plane_fmt[0].sizeimage = max_input_size; + } + + f->fmt.pix_mp.num_planes = inst->bufq[fmt->type].num_planes; + for (i = 0; i < inst->bufq[fmt->type].num_planes; ++i) { + inst->bufq[OUTPUT_PORT].plane_sizes[i] = + f->fmt.pix_mp.plane_fmt[i].sizeimage; + } + } +err_invalid_fmt: + return rc; +} + +int msm_vdec_enum_fmt(struct msm_vidc_inst *inst, struct v4l2_fmtdesc *f) +{ + const struct msm_vidc_format *fmt = NULL; + int rc = 0; + + if (!inst || !f) { + dprintk(VIDC_ERR, + "Invalid input, inst = %pK, f = %pK\n", inst, f); + return -EINVAL; + } + if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + fmt = msm_comm_get_pixel_fmt_index(vdec_formats, + ARRAY_SIZE(vdec_formats), f->index, CAPTURE_PORT); + } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + fmt = msm_comm_get_pixel_fmt_index(vdec_formats, + ARRAY_SIZE(vdec_formats), f->index, OUTPUT_PORT); + f->flags = V4L2_FMT_FLAG_COMPRESSED; + } + + memset(f->reserved, 0, sizeof(f->reserved)); + if (fmt) { + strlcpy(f->description, fmt->description, + sizeof(f->description)); + f->pixelformat = fmt->fourcc; + } else { + dprintk(VIDC_DBG, "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 *fmt = NULL; + + if (!inst || !inst->core) { + dprintk(VIDC_ERR, "Invalid input = %pK\n", inst); + return -EINVAL; + } + core = inst->core; + inst->prop.height[CAPTURE_PORT] = DEFAULT_HEIGHT; + inst->prop.width[CAPTURE_PORT] = DEFAULT_WIDTH; + inst->prop.height[OUTPUT_PORT] = DEFAULT_HEIGHT; + inst->prop.width[OUTPUT_PORT] = DEFAULT_WIDTH; + inst->capability.height.min = MIN_SUPPORTED_HEIGHT; + inst->capability.height.max = DEFAULT_HEIGHT; + inst->capability.width.min = MIN_SUPPORTED_WIDTH; + inst->capability.width.max = DEFAULT_WIDTH; + inst->capability.secure_output2_threshold.min = 0; + inst->capability.secure_output2_threshold.max = 0; + inst->buffer_mode_set[OUTPUT_PORT] = HAL_BUFFER_MODE_STATIC; + inst->buffer_mode_set[CAPTURE_PORT] = HAL_BUFFER_MODE_DYNAMIC; + inst->stream_output_mode = HAL_VIDEO_DECODER_PRIMARY; + /* To start with, both ports are 1 plane each */ + inst->bufq[OUTPUT_PORT].num_planes = 1; + inst->bufq[CAPTURE_PORT].num_planes = 1; + inst->prop.fps = DEFAULT_FPS; + inst->clk_data.operating_rate = 0; + if (core->resources.decode_batching) { + struct msm_vidc_inst *temp; + + inst->batch.size = MAX_DEC_BATCH_SIZE; + inst->decode_batching = true; + + mutex_lock(&core->lock); + list_for_each_entry(temp, &core->instances, list) { + if (temp != inst && + temp->state != MSM_VIDC_CORE_INVALID && + is_decode_session(temp) && + !is_thumbnail_session(temp)) { + inst->decode_batching = false; + dprintk(VIDC_DBG, + "decode-batching disabled in multiple sessions\n"); + break; + } + } + mutex_unlock(&core->lock); + } + + /* By default, initialize CAPTURE port to UBWC YUV format */ + fmt = msm_comm_get_pixel_fmt_fourcc(vdec_formats, + ARRAY_SIZE(vdec_formats), V4L2_PIX_FMT_NV12_UBWC, + CAPTURE_PORT); + if (!fmt || fmt->type != CAPTURE_PORT) { + dprintk(VIDC_ERR, + "vdec_formats corrupted\n"); + return -EINVAL; + } + memcpy(&inst->fmts[fmt->type], fmt, + sizeof(struct msm_vidc_format)); + + 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; + + /* By default, initialize OUTPUT port to H264 decoder */ + fmt = msm_comm_get_pixel_fmt_fourcc(vdec_formats, + ARRAY_SIZE(vdec_formats), V4L2_PIX_FMT_H264, + OUTPUT_PORT); + if (!fmt || fmt->type != OUTPUT_PORT) { + dprintk(VIDC_ERR, + "vdec_formats corrupted\n"); + return -EINVAL; + } + memcpy(&inst->fmts[fmt->type], fmt, + sizeof(struct msm_vidc_format)); + + return rc; +} + +static struct v4l2_ctrl *get_ctrl_from_cluster(int id, + struct v4l2_ctrl **cluster, int ncontrols) +{ + int c; + + for (c = 0; c < ncontrols; ++c) + if (cluster[c]->id == id) + return cluster[c]; + return NULL; +} + +int msm_vdec_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) +{ + int rc = 0, fourcc = 0; + struct hal_enable_picture enable_picture; + struct hal_enable hal_property; + enum hal_property property_id = 0; + u32 property_val = 0; + void *pdata = NULL; + struct hfi_device *hdev; + struct hal_extradata_enable extra; + struct hal_multi_stream multi_stream; + struct v4l2_ctrl *temp_ctrl = NULL; + struct hal_profile_level profile_level; + struct hal_frame_size frame_sz; + struct hal_buffer_requirements *bufreq; + struct hal_buffer_requirements *bufreq_out2; + + if (!inst || !inst->core || !inst->core->device) { + dprintk(VIDC_ERR, "%s invalid parameters\n", __func__); + return -EINVAL; + } + hdev = inst->core->device; + + /* Small helper macro for quickly getting a control and err checking */ +#define TRY_GET_CTRL(__ctrl_id) ({ \ + struct v4l2_ctrl *__temp; \ + __temp = get_ctrl_from_cluster( \ + __ctrl_id, \ + ctrl->cluster, ctrl->ncontrols); \ + if (!__temp) { \ + dprintk(VIDC_ERR, "Can't find %s (%x) in cluster\n", \ + #__ctrl_id, __ctrl_id); \ + /* Clusters are hardcoded, if we can't find */ \ + /* something then things are massively screwed up */ \ + MSM_VIDC_ERROR(1); \ + } \ + __temp; \ + }) + + v4l2_ctrl_unlock(ctrl); + + switch (ctrl->id) { + case V4L2_CID_MPEG_VIDC_VIDEO_OUTPUT_ORDER: + property_id = HAL_PARAM_VDEC_OUTPUT_ORDER; + property_val = ctrl->val; + pdata = &property_val; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_PICTYPE_DEC_MODE: + property_id = HAL_PARAM_VDEC_PICTURE_TYPE_DECODE; + enable_picture.picture_type = ctrl->val; + pdata = &enable_picture; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE: + switch (ctrl->val) { + case V4L2_MPEG_MSM_VIDC_DISABLE: + inst->flags &= ~VIDC_THUMBNAIL; + break; + case V4L2_MPEG_MSM_VIDC_ENABLE: + inst->flags |= VIDC_THUMBNAIL; + break; + } + + property_id = HAL_PARAM_VDEC_SYNC_FRAME_DECODE; + hal_property.enable = ctrl->val; + pdata = &hal_property; + msm_dcvs_try_enable(inst); + + bufreq = get_buff_req_buffer(inst, + HAL_BUFFER_INPUT); + if (!bufreq) { + dprintk(VIDC_ERR, + "Failed : No buffer requirements : %x\n", + HAL_BUFFER_OUTPUT); + return -EINVAL; + } + bufreq->buffer_count_min = + MIN_NUM_THUMBNAIL_MODE_OUTPUT_BUFFERS; + bufreq->buffer_count_min_host = + MIN_NUM_THUMBNAIL_MODE_OUTPUT_BUFFERS; + bufreq->buffer_count_actual = + MIN_NUM_THUMBNAIL_MODE_OUTPUT_BUFFERS; + + if (msm_comm_get_stream_output_mode(inst) == + HAL_VIDEO_DECODER_SECONDARY) { + + bufreq = get_buff_req_buffer(inst, + HAL_BUFFER_OUTPUT); + if (!bufreq) { + dprintk(VIDC_ERR, + "Failed : No buffer requirements: %x\n", + HAL_BUFFER_OUTPUT); + return -EINVAL; + } + + bufreq->buffer_count_min = + MIN_NUM_THUMBNAIL_MODE_CAPTURE_BUFFERS; + bufreq->buffer_count_min_host = + MIN_NUM_THUMBNAIL_MODE_OUTPUT_BUFFERS; + bufreq->buffer_count_actual = + MIN_NUM_THUMBNAIL_MODE_OUTPUT_BUFFERS; + + bufreq = get_buff_req_buffer(inst, + HAL_BUFFER_OUTPUT2); + if (!bufreq) { + dprintk(VIDC_ERR, + "Failed : No buffer requirements: %x\n", + HAL_BUFFER_OUTPUT2); + return -EINVAL; + } + + bufreq->buffer_count_min = + MIN_NUM_THUMBNAIL_MODE_CAPTURE_BUFFERS; + bufreq->buffer_count_min_host = + MIN_NUM_THUMBNAIL_MODE_OUTPUT_BUFFERS; + bufreq->buffer_count_actual = + MIN_NUM_THUMBNAIL_MODE_OUTPUT_BUFFERS; + + } else { + + bufreq = get_buff_req_buffer(inst, + HAL_BUFFER_OUTPUT); + if (!bufreq) { + dprintk(VIDC_ERR, + "Failed : No buffer requirements: %x\n", + HAL_BUFFER_OUTPUT); + return -EINVAL; + } + bufreq->buffer_count_min = + MIN_NUM_THUMBNAIL_MODE_CAPTURE_BUFFERS; + bufreq->buffer_count_min_host = + MIN_NUM_THUMBNAIL_MODE_OUTPUT_BUFFERS; + bufreq->buffer_count_actual = + MIN_NUM_THUMBNAIL_MODE_OUTPUT_BUFFERS; + + } + + break; + case V4L2_CID_MPEG_VIDC_VIDEO_SECURE: + property_id = HAL_PARAM_SECURE; + inst->flags |= VIDC_SECURE; + property_val = !!(inst->flags & VIDC_SECURE); + pdata = &property_val; + dprintk(VIDC_DBG, "Setting secure mode to: %d\n", + !!(inst->flags & VIDC_SECURE)); + if (msm_comm_check_for_inst_overload(inst->core)) { + dprintk(VIDC_ERR, + "Secure Instance reached Max limit, rejecting session\n"); + return -ENOTSUPP; + } + break; + case V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA: + property_id = HAL_PARAM_INDEX_EXTRADATA; + extra.index = msm_comm_get_hal_extradata_index(ctrl->val); + switch (ctrl->val) { + case V4L2_MPEG_VIDC_EXTRADATA_INTERLACE_VIDEO: + case V4L2_MPEG_VIDC_EXTRADATA_TIMESTAMP: + case V4L2_MPEG_VIDC_EXTRADATA_S3D_FRAME_PACKING: + case V4L2_MPEG_VIDC_EXTRADATA_FRAME_RATE: + case V4L2_MPEG_VIDC_EXTRADATA_PANSCAN_WINDOW: + case V4L2_MPEG_VIDC_EXTRADATA_RECOVERY_POINT_SEI: + case V4L2_MPEG_VIDC_EXTRADATA_NUM_CONCEALED_MB: + case V4L2_MPEG_VIDC_EXTRADATA_ASPECT_RATIO: + case V4L2_MPEG_VIDC_EXTRADATA_MPEG2_SEQDISP: + case V4L2_MPEG_VIDC_EXTRADATA_STREAM_USERDATA: + case V4L2_MPEG_VIDC_EXTRADATA_FRAME_QP: + case V4L2_MPEG_VIDC_EXTRADATA_OUTPUT_CROP: + case V4L2_MPEG_VIDC_EXTRADATA_DISPLAY_COLOUR_SEI: + case V4L2_MPEG_VIDC_EXTRADATA_CONTENT_LIGHT_LEVEL_SEI: + case V4L2_MPEG_VIDC_EXTRADATA_VUI_DISPLAY: + case V4L2_MPEG_VIDC_EXTRADATA_VPX_COLORSPACE: + case V4L2_MPEG_VIDC_EXTRADATA_UBWC_CR_STATS_INFO: + inst->bufq[CAPTURE_PORT].num_planes = 2; + inst->bufq[CAPTURE_PORT].plane_sizes[EXTRADATA_IDX(2)] = + VENUS_EXTRADATA_SIZE( + inst->prop.height[CAPTURE_PORT], + inst->prop.width[CAPTURE_PORT]); + break; + default: + rc = -ENOTSUPP; + break; + } + extra.enable = 1; + pdata = &extra; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE: + if (ctrl->val && !(inst->capability.pixelprocess_capabilities & + HAL_VIDEO_DECODER_MULTI_STREAM_CAPABILITY)) { + dprintk(VIDC_ERR, "Downscaling not supported: %#x\n", + ctrl->id); + rc = -ENOTSUPP; + break; + } + switch (ctrl->val) { + case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_PRIMARY: + /* Release DPBs if it was previously split mode */ + rc = msm_comm_release_output_buffers(inst, false); + if (rc) + dprintk(VIDC_ERR, + "%s Release output buffers failed\n", + __func__); + + multi_stream.buffer_type = HAL_BUFFER_OUTPUT; + multi_stream.enable = true; + pdata = &multi_stream; + rc = call_hfi_op(hdev, session_set_property, (void *) + inst->session, HAL_PARAM_VDEC_MULTI_STREAM, + pdata); + if (rc) { + dprintk(VIDC_ERR, + "Failed : Enabling OUTPUT port : %d\n", + rc); + break; + } + multi_stream.buffer_type = HAL_BUFFER_OUTPUT2; + multi_stream.enable = false; + pdata = &multi_stream; + rc = call_hfi_op(hdev, session_set_property, (void *) + inst->session, HAL_PARAM_VDEC_MULTI_STREAM, + pdata); + if (rc) { + dprintk(VIDC_ERR, + "Failed:Disabling OUTPUT2 port : %d\n", + rc); + break; + } + /* + * If stream output mode was secondary earlier then + * populate output bufreqs with output2 bufreqs + */ + if (is_secondary_output_mode(inst)) { + msm_comm_copy_bufreqs(inst, HAL_BUFFER_OUTPUT2, + HAL_BUFFER_OUTPUT); + msm_comm_copy_bufreqs(inst, + HAL_BUFFER_EXTRADATA_OUTPUT2, + HAL_BUFFER_EXTRADATA_OUTPUT); + } + + /* reset output2 buffer requirements */ + msm_comm_reset_bufreqs(inst, HAL_BUFFER_OUTPUT2); + msm_comm_reset_bufreqs(inst, + HAL_BUFFER_EXTRADATA_OUTPUT2); + + msm_comm_set_stream_output_mode(inst, + HAL_VIDEO_DECODER_PRIMARY); + break; + case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_SECONDARY: + switch (inst->bit_depth) { + case MSM_VIDC_BIT_DEPTH_8: + fourcc = V4L2_PIX_FMT_NV12_UBWC; + break; + case MSM_VIDC_BIT_DEPTH_10: + fourcc = V4L2_PIX_FMT_NV12_TP10_UBWC; + break; + default: + fourcc = V4L2_PIX_FMT_NV12_UBWC; + dprintk(VIDC_ERR, + "Invalid bit depth. Setting DPB as NV12UBWC"); + break; + } + + rc = msm_comm_set_color_format(inst, + HAL_BUFFER_OUTPUT, fourcc); + if (rc) { + dprintk(VIDC_ERR, + "%s Failed setting output color format : %d\n", + __func__, rc); + break; + } + inst->clk_data.dpb_fourcc = fourcc; + + multi_stream.buffer_type = HAL_BUFFER_OUTPUT2; + multi_stream.enable = true; + pdata = &multi_stream; + rc = call_hfi_op(hdev, session_set_property, (void *) + inst->session, HAL_PARAM_VDEC_MULTI_STREAM, + pdata); + if (rc) { + dprintk(VIDC_ERR, + "Failed :Enabling OUTPUT2 port : %d\n", + rc); + break; + } + + multi_stream.buffer_type = HAL_BUFFER_OUTPUT; + multi_stream.enable = false; + pdata = &multi_stream; + rc = call_hfi_op(hdev, session_set_property, (void *) + inst->session, HAL_PARAM_VDEC_MULTI_STREAM, + pdata); + if (rc) { + dprintk(VIDC_ERR, + "Failed disabling OUTPUT port : %d\n", + rc); + break; + } + + frame_sz.buffer_type = HAL_BUFFER_OUTPUT2; + frame_sz.width = inst->prop.width[CAPTURE_PORT]; + frame_sz.height = inst->prop.height[CAPTURE_PORT]; + pdata = &frame_sz; + dprintk(VIDC_DBG, + "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, (void *) + inst->session, HAL_PARAM_FRAME_SIZE, pdata); + if (rc) { + dprintk(VIDC_ERR, + "Failed setting OUTPUT2 size : %d\n", + rc); + break; + } + + /* Populate output2 bufreqs with output bufreqs */ + msm_comm_copy_bufreqs(inst, HAL_BUFFER_OUTPUT, + HAL_BUFFER_OUTPUT2); + msm_comm_copy_bufreqs(inst, + HAL_BUFFER_EXTRADATA_OUTPUT, + HAL_BUFFER_EXTRADATA_OUTPUT2); + + bufreq_out2 = get_buff_req_buffer(inst, + HAL_BUFFER_OUTPUT2); + if (!bufreq_out2) + break; + + rc = msm_comm_set_buffer_count(inst, + bufreq_out2->buffer_count_min, + bufreq_out2->buffer_count_actual, + HAL_BUFFER_OUTPUT2); + if (rc) { + dprintk(VIDC_ERR, + "%s: Failed to set opb buffer count to FW\n", + __func__); + break; + } + + msm_comm_set_stream_output_mode(inst, + HAL_VIDEO_DECODER_SECONDARY); + break; + default: + dprintk(VIDC_ERR, + "Failed : Unsupported multi stream setting\n"); + rc = -ENOTSUPP; + break; + } + break; + case V4L2_CID_MPEG_VIDEO_H264_PROFILE: + temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_LEVEL); + property_id = + HAL_PARAM_PROFILE_LEVEL_CURRENT; + profile_level.profile = msm_comm_v4l2_to_hal(ctrl->id, + ctrl->val); + profile_level.level = msm_comm_v4l2_to_hal( + V4L2_CID_MPEG_VIDEO_H264_LEVEL, + temp_ctrl->val); + pdata = &profile_level; + break; + case V4L2_CID_MPEG_VIDEO_H264_LEVEL: + temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_PROFILE); + property_id = + HAL_PARAM_PROFILE_LEVEL_CURRENT; + profile_level.level = msm_comm_v4l2_to_hal(ctrl->id, + ctrl->val); + profile_level.profile = msm_comm_v4l2_to_hal( + V4L2_CID_MPEG_VIDEO_H264_PROFILE, + temp_ctrl->val); + pdata = &profile_level; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_BUFFER_SIZE_LIMIT: + dprintk(VIDC_DBG, + "Limiting input buffer size from %u to %u\n", + inst->buffer_size_limit, ctrl->val); + inst->buffer_size_limit = ctrl->val; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_PRIORITY: + property_id = HAL_CONFIG_REALTIME; + hal_property.enable = ctrl->val; + pdata = &hal_property; + switch (ctrl->val) { + case V4L2_MPEG_MSM_VIDC_DISABLE: + inst->flags &= ~VIDC_REALTIME; + break; + case V4L2_MPEG_MSM_VIDC_ENABLE: + inst->flags |= VIDC_REALTIME; + break; + default: + dprintk(VIDC_WARN, + "inst(%pK) invalid priority ctrl value %#x\n", + inst, ctrl->val); + break; + } + break; + case V4L2_CID_MPEG_VIDC_VIDEO_OPERATING_RATE: + if (((ctrl->val >> 16) < inst->capability.frame_rate.min || + (ctrl->val >> 16) > inst->capability.frame_rate.max) && + ctrl->val != INT_MAX) { + if (!is_realtime_session(inst)) { + if ((ctrl->val >> 16) < + inst->capability.frame_rate.min) { + inst->clk_data.operating_rate = + inst->capability.frame_rate.min << 16; + } else { + inst->clk_data.operating_rate = + inst->capability.frame_rate.max << 16; + } + dprintk(VIDC_DBG, + "inst(%pK) operating rate capped from %d to %d\n", + inst, ctrl->val >> 16, + inst->clk_data.operating_rate >> 16); + inst->operating_rate_set = true; + } else { + dprintk(VIDC_ERR, "Invalid operating rate %u\n", + (ctrl->val >> 16)); + rc = -ENOTSUPP; + } + } else if (ctrl->val == INT_MAX) { + dprintk(VIDC_DBG, + "inst(%pK) Request for turbo mode\n", inst); + inst->clk_data.turbo_mode = true; + inst->operating_rate_set = true; + } else if (msm_vidc_validate_operating_rate(inst, ctrl->val)) { + dprintk(VIDC_ERR, "Failed to set operating rate\n"); + rc = -ENOTSUPP; + } else { + dprintk(VIDC_DBG, + "inst(%pK) operating rate changed from %d to %d\n", + inst, inst->clk_data.operating_rate >> 16, + ctrl->val >> 16); + inst->clk_data.operating_rate = ctrl->val; + inst->operating_rate_set = true; + inst->clk_data.turbo_mode = false; + } + break; + case V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_MODE: + if (ctrl->val == V4L2_MPEG_MSM_VIDC_ENABLE) + hal_property.enable = 1; + else + hal_property.enable = 0; + inst->clk_data.low_latency_mode = (bool) hal_property.enable; + break; + default: + break; + } + + v4l2_ctrl_lock(ctrl); +#undef TRY_GET_CTRL + + if (!rc && property_id) { + dprintk(VIDC_DBG, + "Control: %x : Name = %s, ID = 0x%x Value = %d\n", + hash32_ptr(inst->session), ctrl->name, + ctrl->id, ctrl->val); + rc = call_hfi_op(hdev, session_set_property, (void *) + inst->session, property_id, pdata); + } + + return rc; +} + +int msm_vdec_s_ext_ctrl(struct msm_vidc_inst *inst, + struct v4l2_ext_controls *ctrl) +{ + int rc = 0, i = 0; + struct v4l2_ext_control *ext_control; + struct v4l2_control control; + struct hal_conceal_color conceal_color = {0}; + struct hfi_device *hdev; + + if (!inst || !inst->core || !inst->core->device || !ctrl) { + dprintk(VIDC_ERR, + "%s invalid parameters\n", __func__); + return -EINVAL; + } + + hdev = inst->core->device; + + v4l2_try_ext_ctrls(&inst->ctrl_handler, ctrl); + + ext_control = ctrl->controls; + + for (i = 0; i < ctrl->count; i++) { + switch (ext_control[i].id) { + case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE: + control.value = ext_control[i].value; + control.id = + V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE; + rc = msm_comm_s_ctrl(inst, &control); + if (rc) + dprintk(VIDC_ERR, + "%s Failed setting stream output mode : %d\n", + __func__, rc); + break; + case V4L2_CID_MPEG_VIDC_VIDEO_CONCEAL_COLOR_8BIT: + conceal_color.conceal_color_8bit = ext_control[i].value; + i++; + switch (ext_control[i].id) { + case V4L2_CID_MPEG_VIDC_VIDEO_CONCEAL_COLOR_10BIT: + conceal_color.conceal_color_10bit = + ext_control[i].value; + dprintk(VIDC_DBG, + "conceal color: 8bit=0x%x 10bit=0x%x", + conceal_color.conceal_color_8bit, + conceal_color.conceal_color_10bit); + rc = call_hfi_op(hdev, session_set_property, + inst->session, + HAL_PARAM_VDEC_CONCEAL_COLOR, + &conceal_color); + if (rc) { + dprintk(VIDC_ERR, + "%s Failed setting conceal color", + __func__); + } + break; + default: + dprintk(VIDC_ERR, + "%s Could not find CONCEAL_COLOR_10BIT ext_control", + __func__); + rc = -ENOTSUPP; + break; + } + + break; + default: + dprintk(VIDC_ERR + , "%s Unsupported set control %d", + __func__, ext_control[i].id); + rc = -ENOTSUPP; + break; + } + } + + 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/drivers/media/platform/msm/vidc/msm_vdec.h b/drivers/media/platform/msm/vidc/msm_vdec.h new file mode 100644 index 000000000000..7617182c9b95 --- /dev/null +++ b/drivers/media/platform/msm/vidc/msm_vdec.h @@ -0,0 +1,29 @@ +/* Copyright (c) 2012, 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. + * + */ +#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(void *instance, struct v4l2_fmtdesc *f); +int msm_vdec_s_fmt(void *instance, struct v4l2_format *f); +int msm_vdec_s_ctrl(void *instance, struct v4l2_ctrl *ctrl); +int msm_vdec_g_ctrl(void *instance, struct v4l2_ctrl *ctrl); +int msm_vdec_s_ext_ctrl(void *instance, struct v4l2_ext_controls *a); + +#endif diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c new file mode 100644 index 000000000000..135a513989a7 --- /dev/null +++ b/drivers/media/platform/msm/vidc/msm_venc.c @@ -0,0 +1,2957 @@ +/* Copyright (c) 2012-2021, 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 "msm_vidc_internal.h" +#include "msm_vidc_common.h" +#include "vidc_hfi_api.h" +#include "msm_vidc_debug.h" +#include "msm_vidc_clocks.h" + +#define MSM_VENC_DVC_NAME "msm_venc_8974" +#define MIN_BIT_RATE 32000 +#define MAX_BIT_RATE 300000000 +#define DEFAULT_BIT_RATE 64000 +#define BIT_RATE_STEP 1 +#define DEFAULT_FRAME_RATE 15 +#define OPERATING_FRAME_RATE_STEP (1 << 16) +#define MAX_SLICE_BYTE_SIZE ((MAX_BIT_RATE)>>3) +#define MIN_SLICE_BYTE_SIZE 512 +#define MAX_SLICE_MB_SIZE ((4096 * 2304) >> 8) +#define I_FRAME_QP 127 +#define P_FRAME_QP 127 +#define B_FRAME_QP 127 +#define MAX_INTRA_REFRESH_MBS ((4096 * 2304) >> 8) +#define MAX_NUM_B_FRAMES 4 +#define MAX_LTR_FRAME_COUNT 10 +#define MAX_HYBRID_HIER_P_LAYERS 6 + +#define L_MODE V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY +#define MIN_TIME_RESOLUTION 1 +#define MAX_TIME_RESOLUTION 0xFFFFFF +#define DEFAULT_TIME_RESOLUTION 0x7530 +#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", + "RC OFF", + "CBR VFR", + "MBR VFR", + "CQ", + NULL +}; + +static const char *const mpeg_video_flip[] = { + "No Flip", + "Horizontal Flip", + "Vertical Flip", + "Both", + NULL +}; + +static const char *const h264_video_entropy_cabac_model[] = { + "Model 0", + "Model 1", + "Model 2", + NULL +}; + +static const char *const hevc_tier_level[] = { + "Main Tier Level 1", + "Main Tier Level 2", + "Main Tier Level 2.1", + "Main Tier Level 3", + "Main Tier Level 3.1", + "Main Tier Level 4", + "Main Tier Level 4.1", + "Main Tier Level 5", + "Main Tier Level 5.1", + "Main Tier Level 5.2", + "Main Tier Level 6", + "Main Tier Level 6.1", + "Main Tier Level 6.2", + "High Tier Level 1", + "High Tier Level 2", + "High Tier Level 2.1", + "High Tier Level 3", + "High Tier Level 3.1", + "High Tier Level 4", + "High Tier Level 4.1", + "High Tier Level 5", + "High Tier Level 5.1", + "High Tier Level 5.2", + "High Tier Level 6", + "High Tier Level 6.1", + "High Tier Level 6.2", + "Level unknown", +}; + +static const char *const tme_profile[] = { + "0", + "1", + "2", + "3", +}; + +static const char *const tme_level[] = { + "Integer", +}; + +static const char *const hevc_profile[] = { + "Main", + "Main10", + "Main Still Pic", +}; + +static const char *const vp8_profile_level[] = { + "Unused", + "0.0", + "1.0", + "2.0", + "3.0", +}; + +static const char *const perf_level[] = { + "Nominal", + "Performance", + "Turbo" +}; + +static const char *const mbi_statistics[] = { + "Camcorder Default", + "Mode 1", + "Mode 2", + "Mode 3" +}; + +static const char *const timestamp_mode[] = { + "Honor", + "Ignore", +}; + +static const char *const iframe_sizes[] = { + "Default", + "Medium", + "Huge", + "Unlimited" +}; + +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-byte" +}; + +static struct msm_vidc_ctrl msm_venc_ctrls[] = { + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_IDR_PERIOD, + .name = "IDR Period", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 1, + .maximum = INT_MAX, + .default_value = DEFAULT_FRAME_RATE, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES, + .name = "Intra Period for P frames", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = INT_MAX, + .default_value = 2*DEFAULT_FRAME_RATE-1, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_I_FRAME_QP, + .name = "I Frame Quantization", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 127, + .default_value = I_FRAME_QP, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_P_FRAME_QP, + .name = "P Frame Quantization", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 127, + .default_value = P_FRAME_QP, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_B_FRAME_QP, + .name = "B Frame Quantization", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 127, + .default_value = B_FRAME_QP, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_I_FRAME_QP_MIN, + .name = "I Frame Quantization Range Minimum", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 127, + .default_value = I_FRAME_QP, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_P_FRAME_QP_MIN, + .name = "P Frame Quantization Range Minimum", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 127, + .default_value = P_FRAME_QP, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_B_FRAME_QP_MIN, + .name = "B Frame Quantization Range Minimum", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 127, + .default_value = B_FRAME_QP, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_I_FRAME_QP_MAX, + .name = "I Frame Quantization Range Maximum", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 127, + .default_value = I_FRAME_QP, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_P_FRAME_QP_MAX, + .name = "P Frame Quantization Range Maximum", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 127, + .default_value = P_FRAME_QP, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_B_FRAME_QP_MAX, + .name = "B Frame Quantization Range Maximum", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 127, + .default_value = B_FRAME_QP, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_QP_MASK, + .name = "QP mask for diff frame types", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 1, + .maximum = 7, + .default_value = 7, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES, + .name = "Intra Period for B frames", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = INT_MAX, + .default_value = 0, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_ADAPTIVE_B, + .name = "Adaptive B frames", + .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_MIN_BUFFERS_FOR_CAPTURE, + .name = "CAPTURE Count", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = MIN_NUM_CAPTURE_BUFFERS, + .maximum = MAX_NUM_CAPTURE_BUFFERS, + .default_value = MIN_NUM_CAPTURE_BUFFERS, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + .flags = V4L2_CTRL_FLAG_VOLATILE, + }, + { + .id = V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, + .name = "OUTPUT Count", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = MIN_NUM_OUTPUT_BUFFERS, + .maximum = MAX_NUM_OUTPUT_BUFFERS, + .default_value = MIN_NUM_OUTPUT_BUFFERS, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + .flags = V4L2_CTRL_FLAG_VOLATILE, + }, + + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_REQUEST_IFRAME, + .name = "Request I Frame", + .type = V4L2_CTRL_TYPE_BUTTON, + .minimum = 0, + .maximum = 0, + .default_value = 0, + .step = 0, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_BITRATE_MODE, + .name = "Video Framerate and 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_RC_OFF, + .step = 0, + .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_RC_OFF) | + (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_VIDEO_FRAME_QUALITY, + .name = "Frame quality", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = MIN_FRAME_QUALITY, + .maximum = MAX_FRAME_QUALITY, + .default_value = DEFAULT_FRAME_QUALITY, + .step = FRAME_QUALITY_STEP, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_IMG_GRID_ENABLE, + .name = "Image grid enable", + .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, + .menu_skip_mask = 0, + .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, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_BITRATE_PEAK, + .name = "Peak Bit Rate", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = MIN_BIT_RATE, + .maximum = MAX_BIT_RATE, + .default_value = DEFAULT_BIT_RATE, + .step = BIT_RATE_STEP, + .menu_skip_mask = 0, + .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_CAVLC, + .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_BASELINE, + .menu_skip_mask = 0, + }, + { + .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_UNKNOWN, + .default_value = V4L2_MPEG_VIDEO_H264_LEVEL_UNKNOWN, + .menu_skip_mask = 0, + }, + { + .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_0, + .menu_skip_mask = 0, + .qmenu = vp8_profile_level, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE, + .name = "HEVC Profile", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN, + .maximum = V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN_STILL_PIC, + .default_value = V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN) | + (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN10) | + (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN_STILL_PIC) + ), + .qmenu = hevc_profile, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_HEVC_TIER_LEVEL, + .name = "HEVC Tier and Level", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_1, + .maximum = V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_UNKNOWN, + .default_value = + V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_UNKNOWN, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_1) | + (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_2) | + (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_2_1) | + (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_3) | + (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_3_1) | + (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_4) | + (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_4_1) | + (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5) | + (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5_1) | + (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5_2) | + (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_1) | + (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_2) | + (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_2_1) | + (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_3) | + (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_3_1) | + (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_4) | + (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_4_1) | + (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_5) | + (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_5_1) | + (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_UNKNOWN) + ), + .qmenu = hevc_tier_level, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_TME_PROFILE, + .name = "TME Profile", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_0, + .maximum = V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_3, + .default_value = + V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_0, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_0) | + (1 << V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_1) | + (1 << V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_2) | + (1 << V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_3) + ), + .qmenu = tme_profile, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_TME_LEVEL, + .name = "TME Level", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDC_VIDEO_TME_LEVEL_INTEGER, + .maximum = V4L2_MPEG_VIDC_VIDEO_TME_LEVEL_INTEGER, + .default_value = V4L2_MPEG_VIDC_VIDEO_TME_LEVEL_INTEGER, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDC_VIDEO_TME_LEVEL_INTEGER) + ), + .qmenu = tme_level, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_TME_PAYLOAD_VERSION, + .name = "TME Payload Version", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 0xFFFFFFF, + .default_value = 0, + .step = 1, + .menu_skip_mask = 0, + .flags = V4L2_CTRL_FLAG_READ_ONLY, + .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, + .menu_skip_mask = 0, + .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, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_DELIVERY_MODE, + .name = "Slice delivery mode", + .type = V4L2_CTRL_TYPE_BUTTON, + .minimum = 0, + .maximum = 1, + .default_value = 0, + .step = 1, + .menu_skip_mask = 0, + .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_VIDC_VIDEO_INTRA_REFRESH_MODE_CYCLIC, + .name = "Cyclic 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_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, + .menu_skip_mask = 0, + .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, + .menu_skip_mask = 0, + .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 = L_MODE, + .default_value = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED) | + (1 << V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED) | + (1 << L_MODE) + ), + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEADER_MODE, + .name = "Sequence Header Mode", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE, + .maximum = V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME, + .default_value = + V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) | + (1 << V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME) + ), + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_SECURE, + .name = "Secure mode", + .type = V4L2_CTRL_TYPE_BUTTON, + .minimum = 0, + .maximum = 0, + .default_value = 0, + .step = 0, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA, + .name = "Extradata Type", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDC_EXTRADATA_NONE, + .maximum = V4L2_MPEG_VIDC_EXTRADATA_ENC_FRAME_QP, + .default_value = V4L2_MPEG_VIDC_EXTRADATA_NONE, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDC_EXTRADATA_NONE) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_INTERLACE_VIDEO) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_ENC_DTS) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_TIMESTAMP) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_S3D_FRAME_PACKING) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_FRAME_RATE) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_PANSCAN_WINDOW) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_RECOVERY_POINT_SEI) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_NUM_CONCEALED_MB) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_ASPECT_RATIO) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_LTR) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_ROI_QP) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_HDR10PLUS_METADATA) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_INPUT_CROP) | + (1ULL << V4L2_MPEG_VIDC_EXTRADATA_ENC_FRAME_QP) + ), + .qmenu = mpeg_video_vidc_extradata, + }, + { + .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 = (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_VIDC_VIDEO_HIER_P_NUM_LAYERS, + .name = "Set Hier P num layers", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 6, + .default_value = 0, + .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_HIER_B_NUM_LAYERS, + .name = "Set Hier B num layers", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 3, + .default_value = 0, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_HYBRID_HIERP_MODE, + .name = "Set Hybrid Hier P mode", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 5, + .default_value = 0, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_MAX_HIERP_LAYERS, + .name = "Set Max Hier P num layers sessions", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 6, + .default_value = 0, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_BASELAYER_ID, + .name = "Set Base Layer ID for Hier-P", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 6, + .default_value = 0, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_LAYER_ID, + .name = "Layer ID for different settings", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = MSM_VIDC_ALL_LAYER_ID, + .default_value = 0, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VENC_PARAM_SAR_WIDTH, + .name = "SAR Width", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 1, + .maximum = 4096, + .default_value = 1, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VENC_PARAM_SAR_HEIGHT, + .name = "SAR Height", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 1, + .maximum = 2160, + .default_value = 1, + .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_DISABLE, + .step = 1, + }, + { + .id = V4L2_CID_MPEG_VIDC_VENC_PARAM_LAYER_BITRATE, + .name = "Layer wise bitrate for H264/H265 Hybrid HP", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = MIN_BIT_RATE, + .maximum = MAX_BIT_RATE, + .default_value = DEFAULT_BIT_RATE, + .step = BIT_RATE_STEP, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_OPERATING_RATE, + .name = "Set Encoder Operating rate", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = INT_MAX, + .default_value = 0, + .step = 1, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_FRAME_RATE, + .name = "Set Encoder Frame rate", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = INT_MAX, + .default_value = 0, + .step = 1, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_VENC_BITRATE_TYPE, + .name = "BITRATE TYPE", + .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_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_WIDTH, + .name = "Set Blur width", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 2048, + .default_value = 0, + .step = 1, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_BLUR_HEIGHT, + .name = "Set Blur height", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 2048, + .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_BT709_5, + .maximum = MSM_VIDC_BT2020, + .default_value = MSM_VIDC_BT601_6_625, + .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_VIDC_VIDEO_IFRAME_SIZE_TYPE, + .name = "Bounds of I-frame size", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_SIZE_DEFAULT, + .maximum = V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_SIZE_UNLIMITED, + .default_value = V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_SIZE_DEFAULT, + .menu_skip_mask = ~( + (1 << V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_SIZE_DEFAULT) | + (1 << V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_SIZE_MEDIUM) | + (1 << V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_SIZE_HUGE) | + (1 << V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_SIZE_UNLIMITED)), + .qmenu = iframe_sizes, + }, + { + .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 = 0, + .step = 1, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC_CUSTOM_MATRIX, + .name = "Enable/Disable CSC Custom Matrix", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .default_value = 0, + .step = 1, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_FLIP, + .name = "Flip", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_CID_MPEG_VIDC_VIDEO_FLIP_NONE, + .maximum = V4L2_CID_MPEG_VIDC_VIDEO_FLIP_BOTH, + .default_value = V4L2_CID_MPEG_VIDC_VIDEO_FLIP_NONE, + .menu_skip_mask = ~( + (1 << V4L2_CID_MPEG_VIDC_VIDEO_FLIP_NONE) | + (1 << V4L2_CID_MPEG_VIDC_VIDEO_FLIP_HORI) | + (1 << V4L2_CID_MPEG_VIDC_VIDEO_FLIP_VERT) | + (1 << V4L2_CID_MPEG_VIDC_VIDEO_FLIP_BOTH) + ), + .qmenu = mpeg_video_flip, + }, + { + .id = V4L2_CID_MPEG_VIDC_VENC_HDR_INFO, + .name = "Enable/Disable HDR 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_VENC_RGB_PRIMARY_00, + .name = "RGB PRIMARIES[0][0]", + .type = V4L2_CTRL_TYPE_U32, + .minimum = 0, + .maximum = UINT_MAX, + .default_value = 0, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VENC_RGB_PRIMARY_01, + .name = "RGB PRIMARIES[0][1]", + .type = V4L2_CTRL_TYPE_U32, + .minimum = 0, + .maximum = UINT_MAX, + .default_value = 0, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VENC_RGB_PRIMARY_10, + .name = "RGB PRIMARIES[1][0]", + .type = V4L2_CTRL_TYPE_U32, + .minimum = 0, + .maximum = UINT_MAX, + .default_value = 0, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VENC_RGB_PRIMARY_11, + .name = "RGB PRIMARIES[1][1]", + .type = V4L2_CTRL_TYPE_U32, + .minimum = 0, + .maximum = UINT_MAX, + .default_value = 0, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VENC_RGB_PRIMARY_20, + .name = "RGB PRIMARIES[2][0]", + .type = V4L2_CTRL_TYPE_U32, + .minimum = 0, + .maximum = UINT_MAX, + .default_value = 0, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VENC_RGB_PRIMARY_21, + .name = "RGB PRIMARIES[2][1]", + .type = V4L2_CTRL_TYPE_U32, + .minimum = 0, + .maximum = UINT_MAX, + .default_value = 0, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VENC_WHITEPOINT_X, + .name = "WHITE POINT X", + .type = V4L2_CTRL_TYPE_U32, + .minimum = 0, + .maximum = UINT_MAX, + .default_value = 0, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VENC_WHITEPOINT_Y, + .name = "WHITE POINT Y", + .type = V4L2_CTRL_TYPE_U32, + .minimum = 0, + .maximum = UINT_MAX, + .default_value = 0, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VENC_MAX_DISP_LUM, + .name = "MAX DISPLAY LUMINANCE", + .type = V4L2_CTRL_TYPE_U32, + .minimum = 0, + .maximum = UINT_MAX, + .default_value = 0, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VENC_MIN_DISP_LUM, + .name = "MIN DISPLAY LUMINANCE", + .type = V4L2_CTRL_TYPE_U32, + .minimum = 0, + .maximum = UINT_MAX, + .default_value = 0, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VENC_MAX_CLL, + .name = "MAX CLL", + .type = V4L2_CTRL_TYPE_U32, + .minimum = 0, + .maximum = UINT_MAX, + .default_value = 0, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VENC_MAX_FLL, + .name = "MAX FLL", + .type = V4L2_CTRL_TYPE_U32, + .minimum = 0, + .maximum = UINT_MAX, + .default_value = 0, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_STREAM_FORMAT, + .name = "NAL Format", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_STARTCODES, + .maximum = V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_FOUR_BYTE_LENGTH, + .default_value = V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_STARTCODES, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_STARTCODES) | + (1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_FOUR_BYTE_LENGTH) + ), + .qmenu = mpeg_video_stream_format, + }, + { + .id = V4L2_CID_MPEG_VIDC_VENC_BITRATE_SAVINGS, + .name = "Enable/Disable bitrate savings", + .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_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, + }, + { + .id = V4L2_CID_MPEG_VIDC_VENC_COMPLEXITY, + .name = "Encoder complexity", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 100, + .default_value = 100, + .step = 1, + .qmenu = NULL, + }, +}; + +#define NUM_CTRLS ARRAY_SIZE(msm_venc_ctrls) + +static u32 get_frame_size_compressed(int plane, u32 height, u32 width) +{ + int sz = ALIGN(height, 32) * ALIGN(width, 32) * 3 / 2; + + return ALIGN(sz, SZ_4K); +} + +static struct msm_vidc_format venc_formats[] = { + { + .name = "YCbCr Semiplanar 4:2:0", + .description = "Y/CbCr 4:2:0", + .fourcc = V4L2_PIX_FMT_NV12, + .get_frame_size = get_frame_size_nv12, + .type = OUTPUT_PORT, + }, + { + .name = "UBWC YCbCr Semiplanar 4:2:0", + .description = "UBWC Y/CbCr 4:2:0", + .fourcc = V4L2_PIX_FMT_NV12_UBWC, + .get_frame_size = get_frame_size_nv12_ubwc, + .type = OUTPUT_PORT, + }, + { + .name = "H264", + .description = "H264 compressed format", + .fourcc = V4L2_PIX_FMT_H264, + .get_frame_size = get_frame_size_compressed, + .type = CAPTURE_PORT, + .input_min_count = 4, + .output_min_count = 4, + }, + { + .name = "VP8", + .description = "VP8 compressed format", + .fourcc = V4L2_PIX_FMT_VP8, + .get_frame_size = get_frame_size_compressed, + .type = CAPTURE_PORT, + .input_min_count = 4, + .output_min_count = 4, + }, + { + .name = "HEVC", + .description = "HEVC compressed format", + .fourcc = V4L2_PIX_FMT_HEVC, + .get_frame_size = get_frame_size_compressed, + .type = CAPTURE_PORT, + .input_min_count = 4, + .output_min_count = 4, + }, + { + .name = "YCrCb Semiplanar 4:2:0", + .description = "Y/CrCb 4:2:0", + .fourcc = V4L2_PIX_FMT_NV21, + .get_frame_size = get_frame_size_nv21, + .type = OUTPUT_PORT, + }, + { + .name = "TP10 UBWC 4:2:0", + .description = "TP10 UBWC 4:2:0", + .fourcc = V4L2_PIX_FMT_NV12_TP10_UBWC, + .get_frame_size = get_frame_size_tp10_ubwc, + .type = OUTPUT_PORT, + }, + { + .name = "TME", + .description = "TME MBI format", + .fourcc = V4L2_PIX_FMT_TME, + .get_frame_size = get_frame_size_compressed, + .type = CAPTURE_PORT, + .input_min_count = 4, + .output_min_count = 4, + }, + { + .name = "YCbCr Semiplanar 4:2:0 10bit", + .description = "Y/CbCr 4:2:0 10bit", + .fourcc = V4L2_PIX_FMT_SDE_Y_CBCR_H2V2_P010_VENUS, + .get_frame_size = get_frame_size_p010, + .type = OUTPUT_PORT, + }, + { + .name = "YCbCr Semiplanar 4:2:0 512 aligned", + .description = "Y/CbCr 4:2:0 512 aligned", + .fourcc = V4L2_PIX_FMT_NV12_512, + .get_frame_size = get_frame_size_nv12_512, + .type = OUTPUT_PORT, + }, +}; + +struct msm_vidc_format_constraint enc_pix_format_constraints[] = { + { + .fourcc = V4L2_PIX_FMT_SDE_Y_CBCR_H2V2_P010_VENUS, + .num_planes = 2, + .y_stride_multiples = 256, + .y_max_stride = 8192, + .y_min_plane_buffer_height_multiple = 32, + .y_buffer_alignment = 256, + .uv_stride_multiples = 256, + .uv_max_stride = 8192, + .uv_min_plane_buffer_height_multiple = 16, + .uv_buffer_alignment = 256, + }, + { + .fourcc = V4L2_PIX_FMT_NV12_512, + .num_planes = 2, + .y_stride_multiples = 512, + .y_max_stride = 8192, + .y_min_plane_buffer_height_multiple = 512, + .y_buffer_alignment = 512, + .uv_stride_multiples = 512, + .uv_max_stride = 8192, + .uv_min_plane_buffer_height_multiple = 256, + .uv_buffer_alignment = 256, + }, +}; + + +static int msm_venc_set_csc(struct msm_vidc_inst *inst, + u32 color_primaries, u32 custom_matrix); + +static struct v4l2_ctrl *get_ctrl_from_cluster(int id, + struct v4l2_ctrl **cluster, int ncontrols) +{ + int c; + + for (c = 0; c < ncontrols; ++c) + if (cluster[c]->id == id) + return cluster[c]; + return NULL; +} + +int msm_venc_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) +{ + int rc = 0; + struct hal_request_iframe request_iframe; + struct hal_bitrate bitrate; + struct hal_operating_rate operating_rate; + struct hal_profile_level profile_level; + enum hal_h264_entropy h264_entropy; + struct hal_intra_period intra_period; + struct hal_idr_period idr_period; + struct hal_intra_refresh intra_refresh; + struct hal_multi_slice_control multi_slice_control; + struct hal_h264_db_control h264_db_control; + struct hal_enable enable; + struct hal_quantization quant; + u32 property_id = 0, property_val = 0; + void *pdata = NULL; + struct v4l2_ctrl *temp_ctrl = NULL; + struct hfi_device *hdev; + struct hal_extradata_enable extra; + struct hal_ltr_use use_ltr; + struct hal_ltr_mark mark_ltr; + struct hal_hybrid_hierp hyb_hierp; + u32 hier_p_layers = 0; + int max_hierp_layers; + int baselayerid = 0; + struct hal_video_signal_info signal_info = {0}; + struct hal_vui_timing_info vui_timing_info = {0}; + enum hal_iframesize_type iframesize_type = HAL_IFRAMESIZE_TYPE_DEFAULT; + u32 color_primaries, custom_matrix; + struct hal_nal_stream_format_select stream_format; + struct hal_heic_frame_quality frame_quality; + struct hal_heic_grid_enable grid_enable; + + if (!inst || !inst->core || !inst->core->device) { + dprintk(VIDC_ERR, "%s invalid parameters\n", __func__); + return -EINVAL; + } + hdev = inst->core->device; + + /* Small helper macro for quickly getting a control and err checking */ +#define TRY_GET_CTRL(__ctrl_id) ({ \ + struct v4l2_ctrl *__temp; \ + __temp = get_ctrl_from_cluster( \ + __ctrl_id, \ + ctrl->cluster, ctrl->ncontrols); \ + if (!__temp) { \ + dprintk(VIDC_ERR, "Can't find %s (%x) in cluster\n", \ + #__ctrl_id, __ctrl_id); \ + /* Clusters are hardcoded, if we can't find */ \ + /* something then things are massively screwed up */ \ + MSM_VIDC_ERROR(1); \ + } \ + __temp; \ + }) + + /* + * Unlock the control prior to setting to the hardware. Otherwise + * lower level code that attempts to do a get_ctrl() will end up + * deadlocking. + */ + v4l2_ctrl_unlock(ctrl); + + switch (ctrl->id) { + case V4L2_CID_MPEG_VIDC_VIDEO_IDR_PERIOD: + if (inst->fmts[CAPTURE_PORT].fourcc != V4L2_PIX_FMT_H264 && + inst->fmts[CAPTURE_PORT].fourcc != + V4L2_PIX_FMT_H264_NO_SC && + inst->fmts[CAPTURE_PORT].fourcc != + V4L2_PIX_FMT_HEVC) { + dprintk(VIDC_ERR, + "Control %#x only valid for H264 and HEVC\n", + ctrl->id); + rc = -ENOTSUPP; + break; + } + + property_id = HAL_CONFIG_VENC_IDR_PERIOD; + idr_period.idr_period = ctrl->val; + pdata = &idr_period; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES: + case V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES: + { + int num_p, num_b; + + temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES); + num_b = temp_ctrl->val; + + temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES); + num_p = temp_ctrl->val; + + if (ctrl->id == V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES) + num_p = ctrl->val; + else if (ctrl->id == V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES) + num_b = ctrl->val; + + if ((num_b < inst->capability.bframe.min) || + (num_b > inst->capability.bframe.max)) { + dprintk(VIDC_ERR, + "Error setting num b frames %d min, max supported is %d, %d\n", + num_b, inst->capability.bframe.min, + inst->capability.bframe.max); + rc = -ENOTSUPP; + break; + } + + property_id = HAL_CONFIG_VENC_INTRA_PERIOD; + intra_period.pframes = num_p; + intra_period.bframes = num_b; + + pdata = &intra_period; + break; + } + case V4L2_CID_MPEG_VIDC_VIDEO_ADAPTIVE_B: + property_id = HAL_PARAM_VENC_ADAPTIVE_B; + enable.enable = ctrl->val; + pdata = &enable; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_REQUEST_IFRAME: + property_id = HAL_CONFIG_VENC_REQUEST_IFRAME; + request_iframe.enable = true; + pdata = &request_iframe; + break; + case V4L2_CID_MPEG_VIDC_VENC_COMPLEXITY: + if (is_realtime_session(inst)) + dprintk(VIDC_DBG, + "Client is setting complexity for RT session\n"); + break; + case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: + { + struct hal_buffer_requirements *buff_req_buffer = NULL; + struct v4l2_ctrl *hybrid_hp = TRY_GET_CTRL( + V4L2_CID_MPEG_VIDC_VIDEO_HYBRID_HIERP_MODE); + if ((ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR_VFR) + && hybrid_hp->val) { + dprintk(VIDC_ERR, + "CBR_VFR not allowed with Hybrid HP\n"); + rc = -ENOTSUPP; + break; + } + if ((ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_CQ) && + inst->fmts[CAPTURE_PORT].fourcc != V4L2_PIX_FMT_HEVC) { + dprintk(VIDC_ERR, "CQ supported only for HEVC\n"); + rc = -ENOTSUPP; + break; + } + property_id = HAL_PARAM_VENC_RATE_CONTROL; + property_val = ctrl->val; + pdata = &property_val; + + if (ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_CQ || + ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_RC_OFF) { + rc = call_hfi_op(hdev, session_set_property, + (void *)inst->session, property_id, pdata); + + if (!rc) { + dprintk(VIDC_DBG, + "Control: %x : Name = %s, ID = 0x%x Value = %d\n", + hash32_ptr(inst->session), ctrl->name, + ctrl->id, ctrl->val); + } else { + dprintk(VIDC_ERR, + "Failed to set rate control mode\n"); + break; + } + + rc = msm_comm_try_get_bufreqs(inst); + if (rc) { + dprintk(VIDC_ERR, + "Failed to get buffer requirements: %d\n", rc); + break; + } + buff_req_buffer = + get_buff_req_buffer(inst, HAL_BUFFER_OUTPUT); + + inst->bufq[CAPTURE_PORT].plane_sizes[0] + = buff_req_buffer ? buff_req_buffer->buffer_size : 0; + dprintk(VIDC_INFO, + "Get updated output buffer size %d\n", + inst->bufq[CAPTURE_PORT].plane_sizes[0]); + property_id = 0; + } + + break; + } + case V4L2_CID_MPEG_VIDC_VIDEO_FRAME_QUALITY: + { + if (ctrl->val < MIN_FRAME_QUALITY || + ctrl->val > MAX_FRAME_QUALITY) { + dprintk(VIDC_ERR, + "Frame quality value %d is not supported\n", + ctrl->val); + rc = -ENOTSUPP; + break; + } + property_id = HAL_CONFIG_HEIC_FRAME_QUALITY; + frame_quality.frame_quality = ctrl->val; + inst->frame_quality = ctrl->val; + pdata = &frame_quality; + break; + } + case V4L2_CID_MPEG_VIDC_IMG_GRID_ENABLE: + { + property_id = HAL_CONFIG_HEIC_GRID_ENABLE; + grid_enable.grid_enable = ctrl->val; + inst->grid_enable = ctrl->val; + pdata = &grid_enable; + break; + } + case V4L2_CID_MPEG_VIDEO_BITRATE: + { + property_id = HAL_CONFIG_VENC_TARGET_BITRATE; + bitrate.bit_rate = ctrl->val; + bitrate.layer_id = MSM_VIDC_ALL_LAYER_ID; + pdata = &bitrate; + inst->clk_data.bitrate = ctrl->val; + break; + } + case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: + { + struct v4l2_ctrl *avg_bitrate = TRY_GET_CTRL( + V4L2_CID_MPEG_VIDEO_BITRATE); + + if (ctrl->val < avg_bitrate->val) { + dprintk(VIDC_ERR, + "Peak bitrate (%d) is lower than average bitrate (%d)\n", + ctrl->val, avg_bitrate->val); + rc = -EINVAL; + break; + } else if (ctrl->val < avg_bitrate->val * 2) { + dprintk(VIDC_WARN, + "Peak bitrate (%d) ideally should be twice the average bitrate (%d)\n", + ctrl->val, avg_bitrate->val); + } + + property_id = HAL_CONFIG_VENC_MAX_BITRATE; + bitrate.bit_rate = ctrl->val; + bitrate.layer_id = MSM_VIDC_ALL_LAYER_ID; + pdata = &bitrate; + break; + } + case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE: + property_id = HAL_PARAM_VENC_H264_ENTROPY_CONTROL; + h264_entropy = msm_comm_v4l2_to_hal( + V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE, ctrl->val); + pdata = &h264_entropy; + break; + case V4L2_CID_MPEG_VIDEO_H264_PROFILE: + temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_LEVEL); + + property_id = HAL_PARAM_PROFILE_LEVEL_CURRENT; + profile_level.profile = msm_comm_v4l2_to_hal(ctrl->id, + ctrl->val); + profile_level.level = msm_comm_v4l2_to_hal( + V4L2_CID_MPEG_VIDEO_H264_LEVEL, + temp_ctrl->val); + pdata = &profile_level; + dprintk(VIDC_DBG, "\nprofile: %d\n", + profile_level.profile); + break; + case V4L2_CID_MPEG_VIDEO_H264_LEVEL: + temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_PROFILE); + + property_id = HAL_PARAM_PROFILE_LEVEL_CURRENT; + profile_level.level = msm_comm_v4l2_to_hal(ctrl->id, + ctrl->val); + profile_level.profile = msm_comm_v4l2_to_hal( + V4L2_CID_MPEG_VIDEO_H264_PROFILE, + temp_ctrl->val); + pdata = &profile_level; + dprintk(VIDC_DBG, "\nLevel: %d\n", + profile_level.level); + break; + case V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL: + property_id = HAL_PARAM_PROFILE_LEVEL_CURRENT; + profile_level.profile = HAL_VP8_PROFILE_MAIN; + profile_level.level = msm_comm_v4l2_to_hal( + V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL, + ctrl->val); + pdata = &profile_level; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE: + temp_ctrl = + TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_HEVC_TIER_LEVEL); + + property_id = HAL_PARAM_PROFILE_LEVEL_CURRENT; + profile_level.profile = msm_comm_v4l2_to_hal(ctrl->id, + ctrl->val); + profile_level.level = msm_comm_v4l2_to_hal( + V4L2_CID_MPEG_VIDC_VIDEO_HEVC_TIER_LEVEL, + temp_ctrl->val); + pdata = &profile_level; + inst->profile = profile_level.profile; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_HEVC_TIER_LEVEL: + temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE); + + property_id = HAL_PARAM_PROFILE_LEVEL_CURRENT; + profile_level.level = msm_comm_v4l2_to_hal(ctrl->id, + ctrl->val); + profile_level.profile = msm_comm_v4l2_to_hal( + V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE, + temp_ctrl->val); + pdata = &profile_level; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_TME_PROFILE: + temp_ctrl = + TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_TME_LEVEL); + + property_id = HAL_PARAM_PROFILE_LEVEL_CURRENT; + profile_level.profile = msm_comm_v4l2_to_hal(ctrl->id, + ctrl->val); + profile_level.level = msm_comm_v4l2_to_hal( + V4L2_CID_MPEG_VIDC_VIDEO_TME_LEVEL, + temp_ctrl->val); + pdata = &profile_level; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_TME_LEVEL: + temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_TME_PROFILE); + + property_id = HAL_PARAM_PROFILE_LEVEL_CURRENT; + profile_level.level = msm_comm_v4l2_to_hal(ctrl->id, + ctrl->val); + profile_level.profile = msm_comm_v4l2_to_hal( + V4L2_CID_MPEG_VIDC_VIDEO_TME_PROFILE, + temp_ctrl->val); + pdata = &profile_level; + break; + case V4L2_CID_ROTATE: + { + if (ctrl->val != 0 && ctrl->val != 90 + && ctrl->val != 180 && ctrl->val != 270) { + dprintk(VIDC_ERR, "Invalid rotation angle"); + rc = -ENOTSUPP; + } + dprintk(VIDC_DBG, "Rotation %d\n", ctrl->val); + break; + } + case V4L2_CID_MPEG_VIDC_VIDEO_FLIP: + { + dprintk(VIDC_DBG, "Flip %d\n", ctrl->val); + break; + } + case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE: { + int temp = 0; + if (inst->fmts[CAPTURE_PORT].fourcc != V4L2_PIX_FMT_HEVC && + inst->fmts[CAPTURE_PORT].fourcc != V4L2_PIX_FMT_H264) { + return rc; + } + switch (ctrl->val) { + case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB: + temp = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB; + break; + case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES: + temp = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES; + break; + case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE: + default: + temp = 0; + break; + } + + if (temp) + temp_ctrl = TRY_GET_CTRL(temp); + + property_id = HAL_PARAM_VENC_MULTI_SLICE_CONTROL; + multi_slice_control.multi_slice = ctrl->val; + multi_slice_control.slice_size = temp ? temp_ctrl->val : 0; + + pdata = &multi_slice_control; + break; + } + case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES: + case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB: + if (inst->fmts[CAPTURE_PORT].fourcc != V4L2_PIX_FMT_HEVC && + inst->fmts[CAPTURE_PORT].fourcc != V4L2_PIX_FMT_H264) { + return rc; + } + temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE); + + property_id = HAL_PARAM_VENC_MULTI_SLICE_CONTROL; + multi_slice_control.multi_slice = temp_ctrl->val; + multi_slice_control.slice_size = ctrl->val; + pdata = &multi_slice_control; + break; + case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_DELIVERY_MODE: { + bool codecs_supported = + inst->fmts[CAPTURE_PORT].fourcc == V4L2_PIX_FMT_HEVC || + inst->fmts[CAPTURE_PORT].fourcc == V4L2_PIX_FMT_H264 || + inst->fmts[CAPTURE_PORT].fourcc == + V4L2_PIX_FMT_H264_NO_SC; + + temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE); + if (codecs_supported && temp_ctrl->val == + V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) { + property_id = HAL_PARAM_VENC_SLICE_DELIVERY_MODE; + enable.enable = true; + } else { + dprintk(VIDC_WARN, + "Failed : slice delivery mode is not valid\n"); + enable.enable = false; + } + pdata = &enable; + break; + } + case V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE_CYCLIC: + { + property_id = HAL_PARAM_VENC_INTRA_REFRESH; + + intra_refresh.mode = HAL_INTRA_REFRESH_CYCLIC; + intra_refresh.ir_mbs = ctrl->val; + + pdata = &intra_refresh; + break; + } + case V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_RANDOM: + { + property_id = HAL_PARAM_VENC_INTRA_REFRESH; + + intra_refresh.mode = HAL_INTRA_REFRESH_RANDOM; + intra_refresh.ir_mbs = ctrl->val; + + pdata = &intra_refresh; + break; + } + case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE: + { + struct v4l2_ctrl *alpha, *beta; + + alpha = TRY_GET_CTRL( + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA); + beta = TRY_GET_CTRL( + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA); + + property_id = HAL_PARAM_VENC_H264_DEBLOCK_CONTROL; + h264_db_control.slice_alpha_offset = alpha->val; + h264_db_control.slice_beta_offset = beta->val; + h264_db_control.mode = msm_comm_v4l2_to_hal( + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE, + ctrl->val); + pdata = &h264_db_control; + break; + } + case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA: + { + struct v4l2_ctrl *mode, *beta; + + mode = TRY_GET_CTRL( + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE); + beta = TRY_GET_CTRL( + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA); + + property_id = HAL_PARAM_VENC_H264_DEBLOCK_CONTROL; + h264_db_control.slice_alpha_offset = ctrl->val; + h264_db_control.slice_beta_offset = beta->val; + h264_db_control.mode = msm_comm_v4l2_to_hal( + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE, + mode->val); + pdata = &h264_db_control; + break; + } + case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA: + { + struct v4l2_ctrl *mode, *alpha; + + mode = TRY_GET_CTRL( + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE); + alpha = TRY_GET_CTRL( + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA); + property_id = HAL_PARAM_VENC_H264_DEBLOCK_CONTROL; + h264_db_control.slice_alpha_offset = alpha->val; + h264_db_control.slice_beta_offset = ctrl->val; + h264_db_control.mode = msm_comm_v4l2_to_hal( + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE, + mode->val); + pdata = &h264_db_control; + break; + } + case V4L2_CID_MPEG_VIDEO_HEADER_MODE: + property_id = HAL_PARAM_VENC_SYNC_FRAME_SEQUENCE_HEADER; + + switch (ctrl->val) { + case V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE: + enable.enable = 0; + break; + case V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME: + enable.enable = 1; + break; + default: + rc = -ENOTSUPP; + break; + } + pdata = &enable; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_SECURE: + inst->flags |= VIDC_SECURE; + property_id = HAL_PARAM_SECURE; + property_val = !!(inst->flags & VIDC_SECURE); + pdata = &property_val; + dprintk(VIDC_INFO, "Setting secure mode to: %d\n", + !!(inst->flags & VIDC_SECURE)); + break; + case V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA: { + struct hal_buffer_requirements *buff_req_buffer = NULL; + int extra_idx = 0; + + property_id = HAL_PARAM_INDEX_EXTRADATA; + extra.index = msm_comm_get_hal_extradata_index(ctrl->val); + extra.enable = 1; + + switch (ctrl->val) { + case V4L2_MPEG_VIDC_EXTRADATA_ASPECT_RATIO: + case V4L2_MPEG_VIDC_EXTRADATA_ROI_QP: + case V4L2_MPEG_VIDC_EXTRADATA_HDR10PLUS_METADATA: + case V4L2_MPEG_VIDC_EXTRADATA_INPUT_CROP: + inst->bufq[OUTPUT_PORT].num_planes = 2; + break; + case V4L2_MPEG_VIDC_EXTRADATA_LTR: + case V4L2_MPEG_VIDC_EXTRADATA_ENC_FRAME_QP: + case V4L2_MPEG_VIDC_EXTRADATA_ENC_DTS: + inst->bufq[CAPTURE_PORT].num_planes = 2; + break; + default: + rc = -ENOTSUPP; + break; + } + + pdata = &extra; + rc = call_hfi_op(hdev, session_set_property, + (void *)inst->session, property_id, pdata); + + rc = msm_comm_try_get_bufreqs(inst); + if (rc) { + dprintk(VIDC_ERR, + "Failed to get buffer requirements: %d\n", rc); + break; + } + + extra_idx = EXTRADATA_IDX(inst->bufq[OUTPUT_PORT].num_planes); + if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) { + buff_req_buffer = get_buff_req_buffer(inst, + HAL_BUFFER_EXTRADATA_INPUT); + + inst->bufq[OUTPUT_PORT].plane_sizes[extra_idx] = + buff_req_buffer ? + buff_req_buffer->buffer_size : 0; + } + + extra_idx = EXTRADATA_IDX(inst->bufq[CAPTURE_PORT].num_planes); + if (extra_idx && (extra_idx < VIDEO_MAX_PLANES)) { + buff_req_buffer = get_buff_req_buffer(inst, + HAL_BUFFER_EXTRADATA_OUTPUT); + + inst->bufq[CAPTURE_PORT].plane_sizes[extra_idx] = + buff_req_buffer ? + buff_req_buffer->buffer_size : 0; + } + property_id = 0; + } + break; + case V4L2_CID_MPEG_VIDC_VIDEO_AU_DELIMITER: + property_id = HAL_PARAM_VENC_GENERATE_AUDNAL; + + switch (ctrl->val) { + case V4L2_MPEG_MSM_VIDC_DISABLE: + enable.enable = 0; + break; + case V4L2_MPEG_MSM_VIDC_ENABLE: + enable.enable = 1; + break; + default: + rc = -ENOTSUPP; + break; + } + + pdata = &enable; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_USELTRFRAME: + property_id = HAL_CONFIG_VENC_USELTRFRAME; + use_ltr.ref_ltr = ctrl->val; + use_ltr.use_constraint = true; + use_ltr.frames = 0; + pdata = &use_ltr; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_MARKLTRFRAME: + property_id = HAL_CONFIG_VENC_MARKLTRFRAME; + mark_ltr.mark_frame = ctrl->val; + pdata = &mark_ltr; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_HIER_P_NUM_LAYERS: + property_id = HAL_CONFIG_VENC_HIER_P_NUM_FRAMES; + hier_p_layers = ctrl->val; + if (hier_p_layers > inst->capability.hier_p.max) { + dprintk(VIDC_ERR, + "Error setting hier p num layers %d max supported is %d\n", + hier_p_layers, inst->capability.hier_p.max); + rc = -ENOTSUPP; + break; + } + pdata = &hier_p_layers; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_VPX_ERROR_RESILIENCE: + property_id = HAL_PARAM_VENC_VPX_ERROR_RESILIENCE_MODE; + enable.enable = ctrl->val; + pdata = &enable; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_HYBRID_HIERP_MODE: + { + struct v4l2_ctrl *rate_control; + + rate_control = + TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_BITRATE_MODE); + if ((rate_control->val == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR_VFR) + && ctrl->val) { + dprintk(VIDC_ERR, + "Hybrid HP not allowed with CBR_VFR\n"); + rc = -ENOTSUPP; + break; + } + property_id = HAL_PARAM_VENC_HIER_P_HYBRID_MODE; + hyb_hierp.layers = ctrl->val; + pdata = &hyb_hierp; + break; + } + case V4L2_CID_MPEG_VIDC_VIDEO_MAX_HIERP_LAYERS: + property_id = HAL_PARAM_VENC_HIER_P_MAX_ENH_LAYERS; + max_hierp_layers = ctrl->val; + if (max_hierp_layers > inst->capability.hier_p.max) { + dprintk(VIDC_ERR, + "Error max HP layers(%d)>max supported(%d)\n", + max_hierp_layers, inst->capability.hier_p.max); + rc = -ENOTSUPP; + break; + } + pdata = &max_hierp_layers; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_BASELAYER_ID: + property_id = HAL_CONFIG_VENC_BASELAYER_PRIORITYID; + baselayerid = ctrl->val; + pdata = &baselayerid; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_I_FRAME_QP: { + struct v4l2_ctrl *qpp, *qpb, *mask; + + property_id = HAL_CONFIG_VENC_FRAME_QP; + qpp = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_P_FRAME_QP); + qpb = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_B_FRAME_QP); + mask = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_QP_MASK); + + quant.qpi = ctrl->val; + quant.qpp = qpp->val; + quant.qpb = qpb->val; + quant.enable = mask->val; + quant.layer_id = MSM_VIDC_ALL_LAYER_ID; + pdata = &quant; + break; + } + case V4L2_CID_MPEG_VIDC_VIDEO_P_FRAME_QP: { + struct v4l2_ctrl *qpi, *qpb, *mask; + + property_id = HAL_CONFIG_VENC_FRAME_QP; + qpi = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_I_FRAME_QP); + qpb = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_B_FRAME_QP); + mask = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_QP_MASK); + + quant.qpp = ctrl->val; + quant.qpi = qpi->val; + quant.qpb = qpb->val; + quant.enable = mask->val; + quant.layer_id = MSM_VIDC_ALL_LAYER_ID; + pdata = &quant; + break; + } + case V4L2_CID_MPEG_VIDC_VIDEO_B_FRAME_QP: { + struct v4l2_ctrl *qpp, *qpi, *mask; + + property_id = HAL_CONFIG_VENC_FRAME_QP; + qpp = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_P_FRAME_QP); + qpi = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_I_FRAME_QP); + mask = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_QP_MASK); + + quant.qpb = ctrl->val; + quant.qpp = qpp->val; + quant.qpi = qpi->val; + quant.enable = mask->val; + quant.layer_id = MSM_VIDC_ALL_LAYER_ID; + pdata = &quant; + break; + } + case V4L2_CID_MPEG_VIDC_VIDEO_QP_MASK: { + struct v4l2_ctrl *qpi, *qpp, *qpb; + + property_id = HAL_CONFIG_VENC_FRAME_QP; + qpi = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_I_FRAME_QP); + qpp = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_P_FRAME_QP); + qpb = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_B_FRAME_QP); + + quant.qpi = qpi->val; + quant.qpp = qpp->val; + quant.qpb = qpb->val; + quant.enable = ctrl->val; + quant.layer_id = MSM_VIDC_ALL_LAYER_ID; + pdata = &quant; + break; + } + case V4L2_CID_MPEG_VIDC_VIDEO_PRIORITY: + property_id = HAL_CONFIG_REALTIME; + enable.enable = ctrl->val; + pdata = &enable; + switch (ctrl->val) { + case V4L2_MPEG_MSM_VIDC_DISABLE: + inst->flags &= ~VIDC_REALTIME; + break; + case V4L2_MPEG_MSM_VIDC_ENABLE: + inst->flags |= VIDC_REALTIME; + break; + default: + dprintk(VIDC_WARN, + "inst(%pK) invalid priority ctrl value %#x\n", + inst, ctrl->val); + break; + } + break; + case V4L2_CID_MPEG_VIDC_VIDEO_OPERATING_RATE: + if (((ctrl->val >> 16) < inst->capability.frame_rate.min || + (ctrl->val >> 16) > inst->capability.frame_rate.max) && + ctrl->val != INT_MAX) { + if (!is_realtime_session(inst)) { + if ((ctrl->val >> 16) < + inst->capability.frame_rate.min) { + inst->clk_data.operating_rate = + inst->capability.frame_rate.min << 16; + } else { + inst->clk_data.operating_rate = + inst->capability.frame_rate.max << 16; + } + dprintk(VIDC_DBG, + "inst(%pK) operating rate capped from %d to %d\n", + inst, ctrl->val >> 16, + inst->clk_data.operating_rate >> 16); + } else { + dprintk(VIDC_ERR, "Invalid operating rate %u\n", + (ctrl->val >> 16)); + rc = -ENOTSUPP; + } + } else if (ctrl->val == INT_MAX) { + dprintk(VIDC_DBG, "inst(%pK) Request for turbo mode\n", + inst); + inst->clk_data.turbo_mode = true; + } else if (msm_vidc_validate_operating_rate(inst, ctrl->val)) { + dprintk(VIDC_ERR, "Failed to set operating rate\n"); + rc = -ENOTSUPP; + } else { + dprintk(VIDC_DBG, + "inst(%pK) operating rate changed from %d to %d\n", + inst, inst->clk_data.operating_rate >> 16, + ctrl->val >> 16); + inst->clk_data.operating_rate = ctrl->val; + inst->clk_data.turbo_mode = false; + property_id = HAL_CONFIG_OPERATING_RATE; + operating_rate.operating_rate = + inst->clk_data.operating_rate; + pdata = &operating_rate; + } + break; + case V4L2_CID_MPEG_VIDC_VIDEO_VENC_BITRATE_TYPE: + { + property_id = HAL_PARAM_VENC_BITRATE_TYPE; + enable.enable = ctrl->val; + pdata = &enable; + break; + } + case V4L2_CID_MPEG_VIDC_VIDEO_COLOR_SPACE: + { + signal_info.color_space = ctrl->val; + temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_FULL_RANGE); + signal_info.full_range = temp_ctrl ? temp_ctrl->val : 0; + temp_ctrl = + TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_TRANSFER_CHARS); + signal_info.transfer_chars = temp_ctrl ? temp_ctrl->val : 0; + temp_ctrl = + TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_MATRIX_COEFFS); + signal_info.matrix_coeffs = temp_ctrl ? temp_ctrl->val : 0; + property_id = HAL_PARAM_VENC_VIDEO_SIGNAL_INFO; + pdata = &signal_info; + break; + } + case V4L2_CID_MPEG_VIDC_VIDEO_FULL_RANGE: + { + signal_info.full_range = ctrl->val; + temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_COLOR_SPACE); + signal_info.color_space = temp_ctrl ? temp_ctrl->val : 0; + temp_ctrl = + TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_TRANSFER_CHARS); + signal_info.transfer_chars = temp_ctrl ? temp_ctrl->val : 0; + temp_ctrl = + TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_MATRIX_COEFFS); + signal_info.matrix_coeffs = temp_ctrl ? temp_ctrl->val : 0; + property_id = HAL_PARAM_VENC_VIDEO_SIGNAL_INFO; + pdata = &signal_info; + break; + } + case V4L2_CID_MPEG_VIDC_VIDEO_TRANSFER_CHARS: + { + signal_info.transfer_chars = ctrl->val; + temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_FULL_RANGE); + signal_info.full_range = temp_ctrl ? temp_ctrl->val : 0; + temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_COLOR_SPACE); + signal_info.color_space = temp_ctrl ? temp_ctrl->val : 0; + temp_ctrl = + TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_MATRIX_COEFFS); + signal_info.matrix_coeffs = temp_ctrl ? temp_ctrl->val : 0; + property_id = HAL_PARAM_VENC_VIDEO_SIGNAL_INFO; + pdata = &signal_info; + break; + } + case V4L2_CID_MPEG_VIDC_VIDEO_MATRIX_COEFFS: + { + signal_info.matrix_coeffs = ctrl->val; + temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_FULL_RANGE); + signal_info.full_range = temp_ctrl ? temp_ctrl->val : 0; + temp_ctrl = + TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_TRANSFER_CHARS); + signal_info.transfer_chars = temp_ctrl ? temp_ctrl->val : 0; + temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_COLOR_SPACE); + signal_info.color_space = temp_ctrl ? temp_ctrl->val : 0; + property_id = HAL_PARAM_VENC_VIDEO_SIGNAL_INFO; + pdata = &signal_info; + break; + } + case V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC: + if (ctrl->val != V4L2_MPEG_MSM_VIDC_ENABLE) + break; + temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_COLOR_SPACE); + color_primaries = temp_ctrl->val; + temp_ctrl = + TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC_CUSTOM_MATRIX); + custom_matrix = temp_ctrl->val; + rc = msm_venc_set_csc(inst, color_primaries, custom_matrix); + if (rc) + dprintk(VIDC_ERR, "fail to set csc: %d\n", rc); + break; + case V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC_CUSTOM_MATRIX: + temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_COLOR_SPACE); + color_primaries = temp_ctrl->val; + rc = msm_venc_set_csc(inst, color_primaries, ctrl->val); + if (rc) + dprintk(VIDC_ERR, "fail to set csc: %d\n", rc); + break; + case V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_MODE: + { + property_id = HAL_PARAM_VENC_LOW_LATENCY; + if (ctrl->val == V4L2_MPEG_MSM_VIDC_ENABLE) + enable.enable = 1; + else + enable.enable = 0; + pdata = &enable; + inst->clk_data.low_latency_mode = (bool) enable.enable; + msm_dcvs_try_enable(inst); + break; + } + case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM: + property_id = HAL_PARAM_VENC_H264_TRANSFORM_8x8; + switch (ctrl->val) { + case V4L2_MPEG_MSM_VIDC_ENABLE: + enable.enable = 1; + break; + case V4L2_MPEG_MSM_VIDC_DISABLE: + enable.enable = 0; + break; + default: + dprintk(VIDC_ERR, + "Invalid H264 8x8 transform control value %d\n", + ctrl->val); + rc = -ENOTSUPP; + break; + } + pdata = &enable; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_SIZE_TYPE: + property_id = HAL_PARAM_VENC_IFRAMESIZE_TYPE; + iframesize_type = msm_comm_v4l2_to_hal( + V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_SIZE_TYPE, + ctrl->val); + pdata = &iframesize_type; + break; + case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE: + { + property_id = HAL_PARAM_VENC_DISABLE_RC_TIMESTAMP; + enable.enable = ctrl->val; + pdata = &enable; + break; + } + case V4L2_CID_MPEG_VIDC_VIDEO_VUI_TIMING_INFO: + { + struct v4l2_ctrl *rc_mode; + bool cfr = false; + + property_id = HAL_PARAM_VENC_VUI_TIMING_INFO; + pdata = &vui_timing_info; + + if (ctrl->val != V4L2_MPEG_MSM_VIDC_ENABLE) { + vui_timing_info.enable = 0; + break; + } + + rc_mode = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_BITRATE_MODE); + + switch (rc_mode->val) { + 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; + } + + vui_timing_info.enable = 1; + vui_timing_info.fixed_frame_rate = cfr; + vui_timing_info.time_scale = NSEC_PER_SEC; + break; + } + case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_FORMAT: + { + property_id = HAL_PARAM_NAL_STREAM_FORMAT_SELECT; + stream_format.nal_stream_format_select = BIT(ctrl->val); + pdata = &stream_format; + break; + } + case V4L2_CID_MPEG_VIDC_VENC_BITRATE_SAVINGS: + { + property_id = HAL_PARAM_VENC_BITRATE_SAVINGS; + enable.enable = ctrl->val; + pdata = &enable; + break; + } + case V4L2_CID_MPEG_VIDC_VIDEO_LTRCOUNT: + case V4L2_CID_MPEG_VIDC_VENC_PARAM_SAR_WIDTH: + case V4L2_CID_MPEG_VIDC_VENC_PARAM_SAR_HEIGHT: + case V4L2_CID_MPEG_VIDC_VIDEO_BLUR_WIDTH: + case V4L2_CID_MPEG_VIDC_VIDEO_BLUR_HEIGHT: + case V4L2_CID_MPEG_VIDC_VIDEO_LAYER_ID: + case V4L2_CID_MPEG_VIDC_VENC_PARAM_LAYER_BITRATE: + case V4L2_CID_MPEG_VIDC_VIDEO_I_FRAME_QP_MIN: + case V4L2_CID_MPEG_VIDC_VIDEO_P_FRAME_QP_MIN: + case V4L2_CID_MPEG_VIDC_VIDEO_B_FRAME_QP_MIN: + case V4L2_CID_MPEG_VIDC_VIDEO_I_FRAME_QP_MAX: + case V4L2_CID_MPEG_VIDC_VIDEO_P_FRAME_QP_MAX: + case V4L2_CID_MPEG_VIDC_VIDEO_B_FRAME_QP_MAX: + case V4L2_CID_MPEG_VIDC_VENC_HDR_INFO: + case V4L2_CID_MPEG_VIDC_VENC_RGB_PRIMARY_00: + case V4L2_CID_MPEG_VIDC_VENC_RGB_PRIMARY_01: + case V4L2_CID_MPEG_VIDC_VENC_RGB_PRIMARY_10: + case V4L2_CID_MPEG_VIDC_VENC_RGB_PRIMARY_11: + case V4L2_CID_MPEG_VIDC_VENC_RGB_PRIMARY_20: + case V4L2_CID_MPEG_VIDC_VENC_RGB_PRIMARY_21: + case V4L2_CID_MPEG_VIDC_VENC_WHITEPOINT_X: + case V4L2_CID_MPEG_VIDC_VENC_WHITEPOINT_Y: + case V4L2_CID_MPEG_VIDC_VENC_MAX_DISP_LUM: + case V4L2_CID_MPEG_VIDC_VENC_MIN_DISP_LUM: + case V4L2_CID_MPEG_VIDC_VENC_MAX_CLL: + case V4L2_CID_MPEG_VIDC_VENC_MAX_FLL: + dprintk(VIDC_DBG, "Set the control : %#x using ext ctrl\n", + ctrl->id); + break; + default: + dprintk(VIDC_ERR, "Unsupported index: %x\n", ctrl->id); + rc = -ENOTSUPP; + break; + } + + v4l2_ctrl_lock(ctrl); +#undef TRY_GET_CTRL + + if (!rc && property_id) { + dprintk(VIDC_DBG, + "Control: %x : Name = %s, ID = 0x%x Value = %d\n", + hash32_ptr(inst->session), ctrl->name, + ctrl->id, ctrl->val); + rc = call_hfi_op(hdev, session_set_property, + (void *)inst->session, property_id, pdata); + } + + return rc; +} + +int msm_venc_ext_layer_id_update(struct v4l2_ext_control *control, + u32 *property_id, + void **pdata, + struct hal_quantization *qp, + struct hal_quantization_range *qp_range, + struct hal_bitrate *bitrate) +{ + switch (control->id) { + case V4L2_CID_MPEG_VIDC_VIDEO_I_FRAME_QP: + qp->qpi = control->value; + *property_id = + HAL_CONFIG_VENC_FRAME_QP; + *pdata = qp; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_P_FRAME_QP: + qp->qpp = control->value; + *property_id = + HAL_CONFIG_VENC_FRAME_QP; + *pdata = qp; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_B_FRAME_QP: + qp->qpb = control->value; + *property_id = + HAL_CONFIG_VENC_FRAME_QP; + *pdata = qp; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_QP_MASK: + qp->enable = control->value; + *property_id = + HAL_CONFIG_VENC_FRAME_QP; + *pdata = qp; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_I_FRAME_QP_MIN: + qp_range->qpi_min = control->value; + *property_id = + HAL_PARAM_VENC_SESSION_QP_RANGE; + *pdata = qp_range; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_P_FRAME_QP_MIN: + qp_range->qpp_min = control->value; + *property_id = + HAL_PARAM_VENC_SESSION_QP_RANGE; + *pdata = qp_range; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_B_FRAME_QP_MIN: + qp_range->qpb_min = control->value; + *property_id = + HAL_PARAM_VENC_SESSION_QP_RANGE; + *pdata = qp_range; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_I_FRAME_QP_MAX: + qp_range->qpi_max = control->value; + *property_id = + HAL_PARAM_VENC_SESSION_QP_RANGE; + *pdata = qp_range; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_P_FRAME_QP_MAX: + qp_range->qpp_max = control->value; + *property_id = + HAL_PARAM_VENC_SESSION_QP_RANGE; + *pdata = qp_range; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_B_FRAME_QP_MAX: + qp_range->qpb_max = control->value; + *property_id = + HAL_PARAM_VENC_SESSION_QP_RANGE; + *pdata = qp_range; + break; + case V4L2_CID_MPEG_VIDC_VENC_PARAM_LAYER_BITRATE: + bitrate->bit_rate = control->value; + *property_id = + HAL_CONFIG_VENC_TARGET_BITRATE; + *pdata = bitrate; + break; + } + return 0; +} + +int msm_venc_s_ext_ctrl(struct msm_vidc_inst *inst, + struct v4l2_ext_controls *ctrl) +{ + int rc = 0, i; + struct v4l2_ext_control *control; + struct hfi_device *hdev; + struct hal_ltr_mode ltr_mode; + u32 property_id = 0; + void *pdata = NULL; + struct msm_vidc_capability *cap = NULL; + struct hal_aspect_ratio sar; + struct hal_bitrate bitrate; + struct hal_frame_size blur_res; + struct hal_quantization_range qp_range; + struct hal_quantization qp; + struct msm_vidc_mastering_display_colour_sei_payload *mdisp_sei = NULL; + struct msm_vidc_content_light_level_sei_payload *cll_sei = NULL; + + if (!inst || !inst->core || !inst->core->device || !ctrl) { + dprintk(VIDC_ERR, "%s invalid parameters\n", __func__); + return -EINVAL; + } + + /* This will check the range for contols and clip if necessary */ + v4l2_try_ext_ctrls(&inst->ctrl_handler, ctrl); + + hdev = inst->core->device; + cap = &inst->capability; + + control = ctrl->controls; + + mdisp_sei = &(inst->hdr10_sei_params.disp_color_sei); + cll_sei = &(inst->hdr10_sei_params.cll_sei); + + for (i = 0; i < ctrl->count; i++) { + switch (control[i].id) { + case V4L2_CID_MPEG_VIDC_VIDEO_LTRCOUNT: + ltr_mode.count = control[i].value; + if (ltr_mode.count > cap->ltr_count.max) { + dprintk(VIDC_ERR, + "Invalid LTR count %d. Supported max: %d\n", + ltr_mode.count, + cap->ltr_count.max); + rc = -EINVAL; + } + ltr_mode.mode = HAL_LTR_MODE_MANUAL; + ltr_mode.trust_mode = 1; + property_id = HAL_PARAM_VENC_LTRMODE; + pdata = <r_mode; + break; + case V4L2_CID_MPEG_VIDC_VENC_PARAM_SAR_WIDTH: + sar.aspect_width = control[i].value; + property_id = HAL_PROPERTY_PARAM_VENC_ASPECT_RATIO; + pdata = &sar; + break; + case V4L2_CID_MPEG_VIDC_VENC_PARAM_SAR_HEIGHT: + sar.aspect_height = control[i].value; + property_id = HAL_PROPERTY_PARAM_VENC_ASPECT_RATIO; + pdata = &sar; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_BLUR_WIDTH: + property_id = HAL_CONFIG_VENC_BLUR_RESOLUTION; + blur_res.width = control[i].value; + blur_res.buffer_type = HAL_BUFFER_INPUT; + property_id = HAL_CONFIG_VENC_BLUR_RESOLUTION; + pdata = &blur_res; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_BLUR_HEIGHT: + blur_res.height = control[i].value; + blur_res.buffer_type = HAL_BUFFER_INPUT; + property_id = HAL_CONFIG_VENC_BLUR_RESOLUTION; + pdata = &blur_res; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_LAYER_ID: + qp.layer_id = control[i].value; + /* Enable QP for all frame types by default */ + qp.enable = 7; + qp_range.layer_id = control[i].value; + bitrate.layer_id = control[i].value; + i++; + while (i < ctrl->count) { + msm_venc_ext_layer_id_update( + &control[i], + &property_id, + &pdata, + &qp, + &qp_range, + &bitrate); + i++; + } + break; + case V4L2_CID_MPEG_VIDC_VENC_HDR_INFO: + if (control[i].value == + V4L2_MPEG_MSM_VIDC_DISABLE || + !mdisp_sei || !cll_sei) + break; + i++; + while (i < ctrl->count) { + switch (control[i].id) { + case V4L2_CID_MPEG_VIDC_VENC_RGB_PRIMARY_00: + mdisp_sei->nDisplayPrimariesX[0] = + control[i].value; + break; + case V4L2_CID_MPEG_VIDC_VENC_RGB_PRIMARY_01: + mdisp_sei->nDisplayPrimariesY[0] = + control[i].value; + break; + case V4L2_CID_MPEG_VIDC_VENC_RGB_PRIMARY_10: + mdisp_sei->nDisplayPrimariesX[1] = + control[i].value; + break; + case V4L2_CID_MPEG_VIDC_VENC_RGB_PRIMARY_11: + mdisp_sei->nDisplayPrimariesY[1] = + control[i].value; + break; + case V4L2_CID_MPEG_VIDC_VENC_RGB_PRIMARY_20: + mdisp_sei->nDisplayPrimariesX[2] = + control[i].value; + break; + case V4L2_CID_MPEG_VIDC_VENC_RGB_PRIMARY_21: + mdisp_sei->nDisplayPrimariesY[2] = + control[i].value; + break; + case V4L2_CID_MPEG_VIDC_VENC_WHITEPOINT_X: + mdisp_sei->nWhitePointX = + control[i].value; + break; + case V4L2_CID_MPEG_VIDC_VENC_WHITEPOINT_Y: + mdisp_sei->nWhitePointY = + control[i].value; + break; + case V4L2_CID_MPEG_VIDC_VENC_MAX_DISP_LUM: + mdisp_sei->nMaxDisplayMasteringLuminance + = control[i].value; + break; + case V4L2_CID_MPEG_VIDC_VENC_MIN_DISP_LUM: + mdisp_sei->nMinDisplayMasteringLuminance + = control[i].value; + break; + case V4L2_CID_MPEG_VIDC_VENC_MAX_CLL: + cll_sei->nMaxContentLight = + control[i].value; + break; + case V4L2_CID_MPEG_VIDC_VENC_MAX_FLL: + cll_sei->nMaxPicAverageLight = + control[i].value; + break; + default: + dprintk(VIDC_ERR, + "Unknown Ctrl:%d, not part of HDR Info", + control[i].id); + } + i++; + } + property_id = + HAL_PARAM_VENC_HDR10_PQ_SEI; + pdata = &inst->hdr10_sei_params; + break; + default: + dprintk(VIDC_ERR, "Invalid id set: %d\n", + control[i].id); + rc = -ENOTSUPP; + break; + } + if (rc) + break; + } + + if (!rc && property_id) { + dprintk(VIDC_DBG, "Control: HAL property=%x\n", property_id); + rc = call_hfi_op(hdev, session_set_property, + (void *)inst->session, property_id, pdata); + } + return rc; +} + +int msm_venc_inst_init(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct msm_vidc_format *fmt = NULL; + + if (!inst) { + dprintk(VIDC_ERR, "Invalid input = %pK\n", inst); + return -EINVAL; + } + inst->prop.height[CAPTURE_PORT] = DEFAULT_HEIGHT; + inst->prop.width[CAPTURE_PORT] = DEFAULT_WIDTH; + inst->prop.height[OUTPUT_PORT] = DEFAULT_HEIGHT; + inst->prop.width[OUTPUT_PORT] = DEFAULT_WIDTH; + inst->capability.height.min = MIN_SUPPORTED_HEIGHT; + inst->capability.height.max = DEFAULT_HEIGHT; + inst->capability.width.min = MIN_SUPPORTED_WIDTH; + inst->capability.width.max = DEFAULT_WIDTH; + inst->capability.secure_output2_threshold.min = 0; + inst->capability.secure_output2_threshold.max = 0; + inst->buffer_mode_set[OUTPUT_PORT] = HAL_BUFFER_MODE_DYNAMIC; + inst->buffer_mode_set[CAPTURE_PORT] = HAL_BUFFER_MODE_STATIC; + inst->prop.fps = DEFAULT_FPS; + inst->capability.pixelprocess_capabilities = 0; + /* To start with, both ports are 1 plane each */ + inst->bufq[OUTPUT_PORT].num_planes = 1; + inst->bufq[CAPTURE_PORT].num_planes = 1; + inst->clk_data.operating_rate = 0; + + 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; + + /* By default, initialize OUTPUT port to UBWC YUV format */ + fmt = msm_comm_get_pixel_fmt_fourcc(venc_formats, + ARRAY_SIZE(venc_formats), V4L2_PIX_FMT_NV12_UBWC, + OUTPUT_PORT); + if (!fmt || fmt->type != OUTPUT_PORT) { + dprintk(VIDC_ERR, + "venc_formats corrupted\n"); + return -EINVAL; + } + memcpy(&inst->fmts[fmt->type], fmt, + sizeof(struct msm_vidc_format)); + + /* By default, initialize CAPTURE port to H264 encoder */ + fmt = msm_comm_get_pixel_fmt_fourcc(venc_formats, + ARRAY_SIZE(venc_formats), V4L2_PIX_FMT_H264, + CAPTURE_PORT); + if (!fmt || fmt->type != CAPTURE_PORT) { + dprintk(VIDC_ERR, + "venc_formats corrupted\n"); + return -EINVAL; + } + memcpy(&inst->fmts[fmt->type], fmt, + sizeof(struct msm_vidc_format)); + + return rc; +} + +int msm_venc_enum_fmt(struct msm_vidc_inst *inst, struct v4l2_fmtdesc *f) +{ + const struct msm_vidc_format *fmt = NULL; + int rc = 0; + + if (!inst || !f) { + dprintk(VIDC_ERR, + "Invalid input, inst = %pK, f = %pK\n", inst, f); + return -EINVAL; + } + if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + fmt = msm_comm_get_pixel_fmt_index(venc_formats, + ARRAY_SIZE(venc_formats), f->index, CAPTURE_PORT); + } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + fmt = msm_comm_get_pixel_fmt_index(venc_formats, + ARRAY_SIZE(venc_formats), f->index, OUTPUT_PORT); + f->flags = V4L2_FMT_FLAG_COMPRESSED; + } + + memset(f->reserved, 0, sizeof(f->reserved)); + if (fmt) { + strlcpy(f->description, fmt->description, + sizeof(f->description)); + f->pixelformat = fmt->fourcc; + } else { + dprintk(VIDC_DBG, "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 hal_vpe_color_space_conversion vpe_csc; + struct msm_vidc_platform_resources *resources; + u32 *bias_coeff = NULL; + u32 *csc_limit = NULL; + u32 *csc_matrix = NULL; + + 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; + + 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 = msm_comm_try_set_prop(inst, + HAL_PARAM_VPE_COLOR_SPACE_CONVERSION, &vpe_csc); + if (rc) + dprintk(VIDC_ERR, "Setting VPE coefficients failed\n"); + + return rc; +} + +int msm_venc_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f) +{ + struct msm_vidc_format *fmt = NULL; + struct msm_vidc_format_constraint *fmt_constraint = NULL; + int rc = 0; + struct hfi_device *hdev; + int extra_idx = 0, i = 0; + struct hal_buffer_requirements *buff_req_buffer; + struct hal_frame_size frame_sz; + + if (!inst || !f) { + dprintk(VIDC_ERR, + "Invalid input, inst = %pK, format = %pK\n", inst, f); + return -EINVAL; + } + + if (!inst->core || !inst->core->device) { + dprintk(VIDC_ERR, "%s invalid parameters\n", __func__); + return -EINVAL; + } + hdev = inst->core->device; + + if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + + fmt = msm_comm_get_pixel_fmt_fourcc(venc_formats, + ARRAY_SIZE(venc_formats), f->fmt.pix_mp.pixelformat, + CAPTURE_PORT); + if (!fmt || fmt->type != CAPTURE_PORT) { + dprintk(VIDC_ERR, + "Format: %d not supported on CAPTURE port\n", + f->fmt.pix_mp.pixelformat); + rc = -EINVAL; + goto exit; + } + + memcpy(&inst->fmts[fmt->type], fmt, + sizeof(struct msm_vidc_format)); + + rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE); + if (rc) { + dprintk(VIDC_ERR, "Failed to open instance\n"); + goto exit; + } + + inst->prop.width[CAPTURE_PORT] = f->fmt.pix_mp.width; + inst->prop.height[CAPTURE_PORT] = f->fmt.pix_mp.height; + rc = msm_vidc_check_session_supported(inst); + if (rc) { + dprintk(VIDC_ERR, + "%s: session not supported\n", __func__); + goto exit; + } + + frame_sz.buffer_type = HAL_BUFFER_OUTPUT; + frame_sz.width = inst->prop.width[CAPTURE_PORT]; + frame_sz.height = inst->prop.height[CAPTURE_PORT]; + dprintk(VIDC_DBG, "CAPTURE port width = %d, height = %d\n", + frame_sz.width, frame_sz.height); + rc = call_hfi_op(hdev, session_set_property, (void *) + inst->session, HAL_PARAM_FRAME_SIZE, &frame_sz); + if (rc) { + dprintk(VIDC_ERR, + "Failed to set framesize for CAPTURE port\n"); + goto exit; + } + + rc = msm_comm_try_get_bufreqs(inst); + if (rc) { + dprintk(VIDC_ERR, + "Failed to get buffer requirements: %d\n", rc); + return rc; + } + + /* + * Get CAPTURE plane size from HW. This may change based on + * settings like Slice delivery mode. HW should decide howmuch + * it needs. + */ + + buff_req_buffer = get_buff_req_buffer(inst, + HAL_BUFFER_OUTPUT); + + f->fmt.pix_mp.plane_fmt[0].sizeimage = buff_req_buffer ? + buff_req_buffer->buffer_size : 0; + + /* + * Get CAPTURE plane Extradata size from HW. This may change + * with no of Extradata's enabled. HW should decide howmuch + * it needs. + */ + + extra_idx = EXTRADATA_IDX(inst->bufq[fmt->type].num_planes); + if (extra_idx && extra_idx < VIDEO_MAX_PLANES) { + buff_req_buffer = get_buff_req_buffer(inst, + HAL_BUFFER_EXTRADATA_OUTPUT); + f->fmt.pix_mp.plane_fmt[extra_idx].sizeimage = + buff_req_buffer ? + buff_req_buffer->buffer_size : 0; + } + + f->fmt.pix_mp.num_planes = inst->bufq[fmt->type].num_planes; + for (i = 0; i < inst->bufq[fmt->type].num_planes; i++) { + inst->bufq[fmt->type].plane_sizes[i] = + f->fmt.pix_mp.plane_fmt[i].sizeimage; + } + /* + * Input extradata buffer size may change upon updating + * CAPTURE plane buffer size. + */ + + extra_idx = EXTRADATA_IDX(inst->bufq[OUTPUT_PORT].num_planes); + if (extra_idx && extra_idx < VIDEO_MAX_PLANES) { + buff_req_buffer = get_buff_req_buffer(inst, + HAL_BUFFER_EXTRADATA_INPUT); + inst->bufq[OUTPUT_PORT].plane_sizes[extra_idx] = + buff_req_buffer ? + buff_req_buffer->buffer_size : 0; + } + } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + struct hal_frame_size frame_sz; + + inst->prop.width[OUTPUT_PORT] = f->fmt.pix_mp.width; + inst->prop.height[OUTPUT_PORT] = f->fmt.pix_mp.height; + rc = msm_vidc_check_session_supported(inst); + if (rc) { + dprintk(VIDC_ERR, + "%s: session not supported\n", __func__); + goto exit; + } + + frame_sz.buffer_type = HAL_BUFFER_INPUT; + frame_sz.width = inst->prop.width[OUTPUT_PORT]; + frame_sz.height = inst->prop.height[OUTPUT_PORT]; + dprintk(VIDC_DBG, "OUTPUT port width = %d, height = %d\n", + frame_sz.width, frame_sz.height); + rc = call_hfi_op(hdev, session_set_property, (void *) + inst->session, HAL_PARAM_FRAME_SIZE, &frame_sz); + if (rc) { + dprintk(VIDC_ERR, + "Failed to set framesize for Output port\n"); + goto exit; + } + + fmt = msm_comm_get_pixel_fmt_fourcc(venc_formats, + ARRAY_SIZE(venc_formats), f->fmt.pix_mp.pixelformat, + OUTPUT_PORT); + if (!fmt || fmt->type != OUTPUT_PORT) { + dprintk(VIDC_ERR, + "Format: %d not supported on OUTPUT port\n", + f->fmt.pix_mp.pixelformat); + rc = -EINVAL; + goto exit; + } + inst->clk_data.opb_fourcc = f->fmt.pix_mp.pixelformat; + memcpy(&inst->fmts[fmt->type], fmt, + sizeof(struct msm_vidc_format)); + + f->fmt.pix_mp.plane_fmt[0].sizeimage = + inst->fmts[fmt->type].get_frame_size(0, + f->fmt.pix_mp.height, f->fmt.pix_mp.width); + + rc = msm_comm_try_get_bufreqs(inst); + if (rc) { + dprintk(VIDC_ERR, + "Failed to get buffer requirements: %d\n", rc); + return rc; + } + + /* + * Get OUTPUT plane Extradata size from HW. This may change + * with no of Extradata's enabled. HW should decide howmuch + * it needs. + */ + + extra_idx = EXTRADATA_IDX(inst->bufq[fmt->type].num_planes); + if (extra_idx && extra_idx < VIDEO_MAX_PLANES) { + buff_req_buffer = get_buff_req_buffer(inst, + HAL_BUFFER_EXTRADATA_INPUT); + f->fmt.pix_mp.plane_fmt[extra_idx].sizeimage = + buff_req_buffer ? + buff_req_buffer->buffer_size : 0; + } + + f->fmt.pix_mp.num_planes = inst->bufq[fmt->type].num_planes; + + for (i = 0; i < inst->bufq[fmt->type].num_planes; i++) { + inst->bufq[fmt->type].plane_sizes[i] = + f->fmt.pix_mp.plane_fmt[i].sizeimage; + } + + msm_comm_set_color_format(inst, HAL_BUFFER_INPUT, fmt->fourcc); + + fmt_constraint = + msm_comm_get_pixel_fmt_constraints(enc_pix_format_constraints, + ARRAY_SIZE(enc_pix_format_constraints), + f->fmt.pix_mp.pixelformat); + + if (!fmt_constraint) { + dprintk(VIDC_INFO, + "Format constraint not required for %d on OUTPUT port\n", + f->fmt.pix_mp.pixelformat); + } else { + rc = msm_comm_set_color_format_constraints(inst, + HAL_BUFFER_INPUT, + fmt_constraint); + if (rc) { + dprintk(VIDC_ERR, + "Set constraint for %d failed on CAPTURE port\n", + f->fmt.pix_mp.pixelformat); + rc = -EINVAL; + goto exit; + } + } + + } else { + dprintk(VIDC_ERR, "%s - Unsupported buf type: %d\n", + __func__, f->type); + rc = -EINVAL; + goto exit; + } +exit: + return rc; +} + +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); +} diff --git a/drivers/media/platform/msm/vidc/msm_venc.h b/drivers/media/platform/msm/vidc/msm_venc.h new file mode 100644 index 000000000000..df6f9baf19a6 --- /dev/null +++ b/drivers/media/platform/msm/vidc/msm_venc.h @@ -0,0 +1,28 @@ +/* Copyright (c) 2012-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. + * + */ +#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(void *instance, struct v4l2_fmtdesc *f); +int msm_venc_s_fmt(void *instance, struct v4l2_format *f); +int msm_venc_s_ctrl(void *instance, struct v4l2_ctrl *ctrl); +int msm_venc_s_ext_ctrl(void *instance, struct v4l2_ext_controls *a); + +#endif diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c new file mode 100644 index 000000000000..0dbcd352e75f --- /dev/null +++ b/drivers/media/platform/msm/vidc/msm_vidc.c @@ -0,0 +1,2254 @@ +/* Copyright (c) 2012-2021, 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 "msm_vidc.h" +#include "msm_vidc_internal.h" +#include "msm_vidc_debug.h" +#include "msm_vdec.h" +#include "msm_venc.h" +#include "msm_cvp.h" +#include "msm_vidc_common.h" +#include +#include "vidc_hfi_api.h" +#include "msm_vidc_clocks.h" +#include + +#define MAX_EVENTS 30 + +static int try_get_ctrl(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[OUTPUT_PORT].vb2_bufq; + struct vb2_queue *capq = &inst->bufq[CAPTURE_PORT].vb2_bufq; + struct vb2_buffer *out_vb = NULL; + struct vb2_buffer *cap_vb = NULL; + unsigned long flags; + 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[OUTPUT_PORT].vb2_bufq; + capq = &inst->bufq[CAPTURE_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); + +static void msm_vidc_ctrl_get_range(struct v4l2_queryctrl *ctrl, + struct hal_capability_supported *capability) + +{ + ctrl->maximum = capability->max; + ctrl->minimum = capability->min; +} + +int msm_vidc_query_ctrl(void *instance, struct v4l2_queryctrl *ctrl) +{ + struct msm_vidc_inst *inst = instance; + struct hal_profile_level_supported *prof_lev_supp; + struct hal_profile_level *prof_lev; + int rc = 0, i = 0, profile_mask = 0, v4l2_prof_value = 0, max_level = 0; + + if (!inst || !ctrl) + return -EINVAL; + + switch (ctrl->id) { + case V4L2_CID_MPEG_VIDC_VIDEO_HYBRID_HIERP_MODE: + msm_vidc_ctrl_get_range(ctrl, + &inst->capability.hier_p_hybrid); + break; + case V4L2_CID_MPEG_VIDC_VIDEO_HIER_B_NUM_LAYERS: + msm_vidc_ctrl_get_range(ctrl, &inst->capability.hier_b); + break; + case V4L2_CID_MPEG_VIDC_VIDEO_HIER_P_NUM_LAYERS: + msm_vidc_ctrl_get_range(ctrl, &inst->capability.hier_p); + break; + case V4L2_CID_MPEG_VIDC_VENC_PARAM_LAYER_BITRATE: + case V4L2_CID_MPEG_VIDEO_BITRATE: + msm_vidc_ctrl_get_range(ctrl, &inst->capability.bitrate); + break; + case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: + msm_vidc_ctrl_get_range(ctrl, &inst->capability.peakbitrate); + break; + case V4L2_CID_MPEG_VIDC_VIDEO_BLUR_WIDTH: + msm_vidc_ctrl_get_range(ctrl, &inst->capability.blur_width); + break; + case V4L2_CID_MPEG_VIDC_VIDEO_BLUR_HEIGHT: + msm_vidc_ctrl_get_range(ctrl, &inst->capability.blur_height); + break; + case V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES: + msm_vidc_ctrl_get_range(ctrl, &inst->capability.bframe); + break; + case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB: + msm_vidc_ctrl_get_range(ctrl, &inst->capability.slice_mbs); + break; + case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES: + msm_vidc_ctrl_get_range(ctrl, &inst->capability.slice_bytes); + break; + case V4L2_CID_MPEG_VIDC_VIDEO_COLOR_SPACE_CAPS: + msm_vidc_ctrl_get_range(ctrl, + &inst->capability.color_space_caps); + break; + case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_CAPS: + msm_vidc_ctrl_get_range(ctrl, &inst->capability.rotation); + break; + case V4L2_CID_MPEG_VIDC_VIDEO_FRAME_RATE: + case V4L2_CID_MPEG_VIDC_VIDEO_OPERATING_RATE: + msm_vidc_ctrl_get_range(ctrl, &inst->capability.frame_rate); + break; + case V4L2_CID_MPEG_VIDEO_H264_PROFILE: + case V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE: + case V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_PROFILE: + case V4L2_CID_MPEG_VIDC_VIDEO_VP9_PROFILE: + { + prof_lev_supp = &inst->capability.profile_level; + for (i = 0; i < prof_lev_supp->profile_count; i++) { + v4l2_prof_value = msm_comm_hal_to_v4l2(ctrl->id, + prof_lev_supp->profile_level[i].profile); + if (v4l2_prof_value == -EINVAL) { + dprintk(VIDC_WARN, "Invalid profile"); + rc = -EINVAL; + } + profile_mask |= (1 << v4l2_prof_value); + } + ctrl->flags = profile_mask; + break; + } + case V4L2_CID_MPEG_VIDEO_H264_LEVEL: + case V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL: + case V4L2_CID_MPEG_VIDC_VIDEO_HEVC_TIER_LEVEL: + case V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_LEVEL: + case V4L2_CID_MPEG_VIDC_VIDEO_VP9_LEVEL: + { + prof_lev_supp = &inst->capability.profile_level; + for (i = 0; i < prof_lev_supp->profile_count; i++) { + prof_lev = &prof_lev_supp->profile_level[i]; + if (max_level < prof_lev->level) + max_level = prof_lev->level; + } + ctrl->maximum = msm_comm_hal_to_v4l2(ctrl->id, max_level); + if (ctrl->maximum == -EINVAL) { + dprintk(VIDC_WARN, "Invalid max level"); + rc = -EINVAL; + } + break; + } + default: + rc = -EINVAL; + } + return rc; +} +EXPORT_SYMBOL(msm_vidc_query_ctrl); + +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); + + dprintk(VIDC_DBG, + "s_fmt: %x : type %d wxh %dx%d pixelfmt %#x num_planes %d size[0] %d size[1] %d in_reconfig %d\n", + hash32_ptr(inst->session), 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) +{ + struct msm_vidc_inst *inst = instance; + int i, rc = 0, color_format = 0; + enum vidc_ports port; + u32 num_planes; + + if (!inst || !f) { + dprintk(VIDC_ERR, + "Invalid input, inst = %pK, format = %pK\n", inst, f); + return -EINVAL; + } + if (inst->in_reconfig) { + inst->prop.height[OUTPUT_PORT] = inst->reconfig_height; + inst->prop.width[OUTPUT_PORT] = inst->reconfig_width; + } + + port = f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ? + OUTPUT_PORT : CAPTURE_PORT; + + f->fmt.pix_mp.pixelformat = inst->fmts[port].fourcc; + f->fmt.pix_mp.height = inst->prop.height[port]; + f->fmt.pix_mp.width = inst->prop.width[port]; + num_planes = f->fmt.pix_mp.num_planes = inst->bufq[port].num_planes; + for (i = 0; i < num_planes; ++i) + f->fmt.pix_mp.plane_fmt[i].sizeimage = + inst->bufq[port].plane_sizes[i]; + switch (inst->fmts[port].fourcc) { + case V4L2_PIX_FMT_NV12: + color_format = COLOR_FMT_NV12; + break; + case V4L2_PIX_FMT_NV12_512: + color_format = COLOR_FMT_NV12_512; + break; + case V4L2_PIX_FMT_NV12_UBWC: + color_format = COLOR_FMT_NV12_UBWC; + break; + case V4L2_PIX_FMT_NV12_TP10_UBWC: + color_format = COLOR_FMT_NV12_BPP10_UBWC; + break; + case V4L2_PIX_FMT_SDE_Y_CBCR_H2V2_P010_VENUS: + color_format = COLOR_FMT_P010; + break; + default: + dprintk(VIDC_DBG, + "Invalid : g_fmt called on %s port with Invalid fourcc 0x%x\n", + port == OUTPUT_PORT ? "OUTPUT" : "CAPTURE", + inst->fmts[port].fourcc); + goto exit; + } + + f->fmt.pix_mp.plane_fmt[0].bytesperline = VENUS_Y_STRIDE(color_format, + inst->prop.width[port]); + f->fmt.pix_mp.plane_fmt[0].reserved[0] = VENUS_Y_SCANLINES(color_format, + inst->prop.height[port]); + f->fmt.pix_mp.plane_fmt[0].sizeimage = VENUS_BUFFER_SIZE(color_format, + inst->prop.width[port], inst->prop.height[port]); + + dprintk(VIDC_DBG, + "g_fmt: %x : type %d wxh %dx%d pixelfmt %#x num_planes %d size[0] %d size[1] %d in_reconfig %d\n", + hash32_ptr(inst->session), 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); +exit: + 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_crop(void *instance, struct v4l2_crop *crop) +{ + struct msm_vidc_inst *inst = instance; + + if (!inst || !crop) + return -EINVAL; + + if (inst->session_type == MSM_VIDC_ENCODER) { + dprintk(VIDC_ERR, + "Session = %pK : Encoder Crop is not implemented yet\n", + inst); + return -EPERM; + } + + crop->c.left = inst->prop.crop_info.left; + crop->c.top = inst->prop.crop_info.top; + crop->c.width = inst->prop.crop_info.width; + crop->c.height = inst->prop.crop_info.height; + + return 0; +} +EXPORT_SYMBOL(msm_vidc_g_crop); + +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(inst, ctrl); + if (!rc) + control->value = ctrl->val; + } + + return rc; +} +EXPORT_SYMBOL(msm_vidc_g_ctrl); + +int msm_vidc_g_ext_ctrl(void *instance, struct v4l2_ext_controls *control) +{ + struct msm_vidc_inst *inst = instance; + struct v4l2_ext_control *ext_control; + int i = 0, rc = 0; + + if (!inst || !control) + return -EINVAL; + + ext_control = control->controls; + + for (i = 0; i < control->count; i++) { + switch (ext_control[i].id) { + default: + dprintk(VIDC_ERR, + "This control %x is not supported yet\n", + ext_control[i].id); + break; + } + } + return rc; +} +EXPORT_SYMBOL(msm_vidc_g_ext_ctrl); + +int msm_vidc_s_ext_ctrl(void *instance, struct v4l2_ext_controls *control) +{ + struct msm_vidc_inst *inst = instance; + + if (!inst || !control) + return -EINVAL; + + if (inst->session_type == MSM_VIDC_DECODER) + return msm_vdec_s_ext_ctrl(instance, control); + if (inst->session_type == MSM_VIDC_ENCODER) + return msm_venc_s_ext_ctrl(instance, control); + return -EINVAL; +} +EXPORT_SYMBOL(msm_vidc_s_ext_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) { + dprintk(VIDC_ERR, + "Failed to find buffer queue for type = %d\n", + b->type); + return -EINVAL; + } + + mutex_lock(&q->lock); + rc = vb2_reqbufs(&q->vb2_bufq, b); + mutex_unlock(&q->lock); + + if (rc) + dprintk(VIDC_ERR, "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) +{ + enum vidc_ports port = + !V4L2_TYPE_IS_MULTIPLANAR(b->type) ? MAX_PORT_NUM : + b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE ? CAPTURE_PORT : + b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ? OUTPUT_PORT : + MAX_PORT_NUM; + + return port != MAX_PORT_NUM && + inst->bufq[port].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) { + dprintk(VIDC_ERR, "%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) { + dprintk(VIDC_ERR, + "%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_DBG, + "skip rel buf (rbr pending)", inst, mbuf); + continue; + } + + print_vidc_buffer(VIDC_DBG, "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, i = 0; + struct buf_queue *q = NULL; + struct vidc_tag_data tag_data; + u32 cr = 0; + + if (!inst || !inst->core || !b || !valid_v4l2_buffer(b, inst)) { + dprintk(VIDC_ERR, "%s: invalid params, inst %pK\n", + __func__, inst); + return -EINVAL; + } + + q = msm_comm_get_vb2q(inst, b->type); + if (!q) { + dprintk(VIDC_ERR, + "Failed to find buffer queue for type = %d\n", b->type); + return -EINVAL; + } + mutex_lock(&q->lock); + + + for (i = 0; i < b->length; i++) { + b->m.planes[i].m.fd = b->m.planes[i].reserved[0]; + b->m.planes[i].data_offset = b->m.planes[i].reserved[1]; + } + + /* Compression ratio is valid only for Encoder YUV buffers. */ + if (inst->session_type == MSM_VIDC_ENCODER && + b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + cr = b->m.planes[0].reserved[2]; + msm_comm_update_input_cr(inst, b->index, cr); + } + + if (inst->session_type == MSM_VIDC_DECODER && + b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + msm_comm_store_mark_data(&inst->etb_data, b->index, + b->m.planes[0].reserved[3], b->m.planes[0].reserved[4]); + } + + tag_data.index = b->index; + tag_data.type = b->type; + tag_data.input_tag = b->m.planes[0].reserved[5]; + tag_data.output_tag = b->m.planes[0].reserved[6]; + msm_comm_store_tags(inst, &tag_data); + + rc = vb2_qbuf(&q->vb2_bufq, b); + if (rc) + dprintk(VIDC_ERR, "Failed to qbuf, %d\n", rc); + + 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, i = 0; + struct buf_queue *q = NULL; + struct vidc_tag_data tag_data; + + if (!inst || !b || !valid_v4l2_buffer(b, inst)) { + dprintk(VIDC_ERR, "%s: invalid params, inst %pK\n", + __func__, inst); + return -EINVAL; + } + + q = msm_comm_get_vb2q(inst, b->type); + if (!q) { + dprintk(VIDC_ERR, + "Failed to find buffer queue for 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) { + dprintk(VIDC_ERR, "Failed to dqbuf, %d\n", rc); + return rc; + } + + for (i = 0; i < b->length; i++) { + b->m.planes[i].reserved[0] = b->m.planes[i].m.fd; + b->m.planes[i].reserved[1] = b->m.planes[i].data_offset; + } + + if (inst->session_type == MSM_VIDC_DECODER && + b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + msm_comm_fetch_mark_data(&inst->fbd_data, b->index, + &b->m.planes[0].reserved[3], + &b->m.planes[0].reserved[4]); + } + + tag_data.index = b->index; + tag_data.type = b->type; + + msm_comm_fetch_tags(inst, &tag_data); + b->m.planes[0].reserved[5] = tag_data.input_tag; + b->m.planes[0].reserved[6] = tag_data.output_tag; + + 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) { + dprintk(VIDC_ERR, + "Failed to find buffer queue for type = %d\n", i); + return -EINVAL; + } + dprintk(VIDC_DBG, "Calling streamon\n"); + mutex_lock(&q->lock); + rc = vb2_streamon(&q->vb2_bufq, i); + mutex_unlock(&q->lock); + if (rc) { + dprintk(VIDC_ERR, "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) { + dprintk(VIDC_ERR, + "Failed to find buffer queue for type = %d\n", i); + return -EINVAL; + } + + if (!inst->in_reconfig) { + dprintk(VIDC_DBG, "%s: inst %pK release resources\n", + __func__, inst); + rc = msm_comm_try_state(inst, MSM_VIDC_RELEASE_RESOURCES_DONE); + if (rc) + dprintk(VIDC_ERR, + "%s: inst %pK move to rel res done failed\n", + __func__, inst); + } + + dprintk(VIDC_DBG, "Calling streamoff\n"); + mutex_lock(&q->lock); + rc = vb2_streamoff(&q->vb2_bufq, i); + mutex_unlock(&q->lock); + if (rc) + dprintk(VIDC_ERR, "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) { + dprintk(VIDC_ERR, "%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->width.min; + fsize->stepwise.max_width = capability->width.max; + fsize->stepwise.step_width = capability->width.step_size; + fsize->stepwise.min_height = capability->height.min; + fsize->stepwise.max_height = capability->height.max; + fsize->stepwise.step_height = capability->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) { + dprintk(VIDC_ERR, "%s : Invalid vb pointer %pK", + __func__, vb); + return; + } + + inst = vb2_get_drv_priv(vb->vb2_queue); + if (!inst) { + dprintk(VIDC_ERR, "%s : Invalid inst pointer", + __func__); + return; + } + + q = msm_comm_get_vb2q(inst, vb->type); + if (!q) { + dprintk(VIDC_ERR, + "%s : Failed to find buffer queue for type = %d\n", + __func__, vb->type); + return; + } + + if (q->vb2_bufq.streaming) { + dprintk(VIDC_DBG, "%d PORT is streaming\n", + vb->type); + return; + } + + rc = msm_vidc_release_buffer(inst, vb->type, vb->index); + if (rc) + dprintk(VIDC_ERR, "%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 i, rc = 0; + struct hal_buffer_requirements *bufreq; + enum hal_buffer buffer_type; + + if (!q || !num_buffers || !num_planes + || !sizes || !q->drv_priv) { + dprintk(VIDC_ERR, "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) { + dprintk(VIDC_ERR, "%s invalid parameters\n", __func__); + return -EINVAL; + } + + switch (q->type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: { + bufreq = get_buff_req_buffer(inst, + HAL_BUFFER_INPUT); + if (!bufreq) { + dprintk(VIDC_ERR, + "Failed : No buffer requirements : %x\n", + HAL_BUFFER_INPUT); + return -EINVAL; + } + if (*num_buffers < bufreq->buffer_count_min_host) { + dprintk(VIDC_DBG, + "Client passed num buffers %d less than the min_host count %d\n", + *num_buffers, bufreq->buffer_count_min_host); + } + *num_planes = inst->bufq[OUTPUT_PORT].num_planes; + if (*num_buffers < MIN_NUM_OUTPUT_BUFFERS || + *num_buffers > MAX_NUM_OUTPUT_BUFFERS) + bufreq->buffer_count_actual = *num_buffers = + MIN_NUM_OUTPUT_BUFFERS; + for (i = 0; i < *num_planes; i++) + sizes[i] = inst->bufq[OUTPUT_PORT].plane_sizes[i]; + + bufreq->buffer_count_actual = *num_buffers; + rc = msm_comm_set_buffer_count(inst, + bufreq->buffer_count_min, + bufreq->buffer_count_actual, HAL_BUFFER_INPUT); + } + break; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: { + buffer_type = msm_comm_get_hal_output_buffer(inst); + bufreq = get_buff_req_buffer(inst, + buffer_type); + if (!bufreq) { + dprintk(VIDC_ERR, + "Failed : No buffer requirements : %x\n", + buffer_type); + return -EINVAL; + } + if (inst->session_type != MSM_VIDC_DECODER && + inst->state > MSM_VIDC_LOAD_RESOURCES_DONE) { + if (*num_buffers < bufreq->buffer_count_min_host) { + dprintk(VIDC_DBG, + "Client passed num buffers %d less than the min_host count %d\n", + *num_buffers, + bufreq->buffer_count_min_host); + } + } + *num_planes = inst->bufq[CAPTURE_PORT].num_planes; + if (*num_buffers < MIN_NUM_CAPTURE_BUFFERS || + *num_buffers > MAX_NUM_CAPTURE_BUFFERS) + bufreq->buffer_count_actual = *num_buffers = + MIN_NUM_CAPTURE_BUFFERS; + + for (i = 0; i < *num_planes; i++) + sizes[i] = inst->bufq[CAPTURE_PORT].plane_sizes[i]; + + bufreq->buffer_count_actual = *num_buffers; + rc = msm_comm_set_buffer_count(inst, + bufreq->buffer_count_min, + bufreq->buffer_count_actual, buffer_type); + } + break; + default: + dprintk(VIDC_ERR, "Invalid q type = %d\n", q->type); + rc = -EINVAL; + break; + } + + dprintk(VIDC_DBG, + "queue_setup: %x : type %d num_buffers %d num_planes %d sizes[0] %d sizes[1] %d\n", + hash32_ptr(inst->session), 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)) { + dprintk(VIDC_DBG, + "No need to verify buffer counts : %pK\n", inst); + return 0; + } + + for (i = 0; i < HAL_BUFFER_MAX; i++) { + struct hal_buffer_requirements *req = &inst->buff_req.buffer[i]; + + if (req && (msm_comm_get_hal_output_buffer(inst) == + req->buffer_type)) { + dprintk(VIDC_DBG, "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) { + + dprintk(VIDC_ERR, + "Invalid data : Counts mismatch\n"); + dprintk(VIDC_ERR, + "Min Count = %d ", + req->buffer_count_min); + dprintk(VIDC_ERR, + "Min Host Count = %d ", + req->buffer_count_min_host); + dprintk(VIDC_ERR, + "Min Actual Count = %d\n", + req->buffer_count_actual); + rc = -EINVAL; + break; + } + } + } + return rc; +} + +int msm_vidc_set_internal_config(struct msm_vidc_inst *inst) +{ + int rc = 0; + u32 rc_mode; + bool set_rc = false; + struct hal_vbv_hdr_buf_size hrd_buf_size; + struct hal_enable latency; + struct hfi_device *hdev; + struct hal_multi_slice_control multi_slice_control; + u32 codec; + u32 mbps, mb_per_frame, fps, bitrate; + u32 slice_val, slice_mode, max_avg_slicesize; + u32 output_width, output_height; + + if (!inst || !inst->core || !inst->core->device) { + dprintk(VIDC_WARN, "%s: Invalid parameter\n", __func__); + return -EINVAL; + } + + if (inst->session_type != MSM_VIDC_ENCODER) + return rc; + + hdev = inst->core->device; + + codec = inst->fmts[CAPTURE_PORT].fourcc; + rc_mode = msm_comm_g_ctrl_for_id(inst, + V4L2_CID_MPEG_VIDEO_BITRATE_MODE); + latency.enable = msm_comm_g_ctrl_for_id(inst, + V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_MODE); + + if (rc_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_MBR_VFR) { + rc_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_MBR; + set_rc = true; + } else if (rc_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR && + latency.enable == V4L2_MPEG_MSM_VIDC_ENABLE && + codec != V4L2_PIX_FMT_VP8) { + rc_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR; + set_rc = true; + } + + if (set_rc) { + rc = call_hfi_op(hdev, session_set_property, + (void *)inst->session, HAL_PARAM_VENC_RATE_CONTROL, + (void *)&rc_mode); + } + + output_height = inst->prop.height[CAPTURE_PORT]; + output_width = inst->prop.width[CAPTURE_PORT]; + fps = inst->prop.fps; + mbps = NUM_MBS_PER_SEC(output_height, output_width, fps); + if ((rc_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR || + rc_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR_VFR) && + (codec != V4L2_PIX_FMT_VP8)) { + if ((rc_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR && + mbps <= CBR_MB_LIMIT) || + (rc_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR_VFR && + mbps <= CBR_VFR_MB_LIMIT)) + hrd_buf_size.vbv_hdr_buf_size = 500; + else + hrd_buf_size.vbv_hdr_buf_size = 1000; + dprintk(VIDC_DBG, "Enable hdr_buf_size %d :\n", + hrd_buf_size.vbv_hdr_buf_size); + rc = call_hfi_op(hdev, session_set_property, + (void *)inst->session, HAL_CONFIG_VENC_VBV_HRD_BUF_SIZE, + (void *)&hrd_buf_size); + + latency.enable = V4L2_MPEG_MSM_VIDC_ENABLE; + rc = call_hfi_op(hdev, session_set_property, + (void *)inst->session, HAL_PARAM_VENC_LOW_LATENCY, + (void *)&latency); + + inst->clk_data.low_latency_mode = latency.enable; + } + + /* Update Slice Config */ + slice_mode = msm_comm_g_ctrl_for_id(inst, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE); + + if ((codec == V4L2_PIX_FMT_H264 || codec == V4L2_PIX_FMT_HEVC) && + slice_mode != V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE) { + bitrate = inst->clk_data.bitrate; + mb_per_frame = NUM_MBS_PER_FRAME(output_height, output_width); + + if (rc_mode != V4L2_MPEG_VIDEO_BITRATE_MODE_RC_OFF && + rc_mode != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR_VFR && + rc_mode != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) { + slice_mode = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE; + slice_val = 0; + } else if (slice_mode == + V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) { + if (output_width > 3840 || output_height > 3840 || + mb_per_frame > NUM_MBS_PER_FRAME(3840, 2160) || + fps > 60) { + slice_mode = + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE; + slice_val = 0; + } else { + slice_val = msm_comm_g_ctrl_for_id(inst, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB); + slice_val = max(slice_val, mb_per_frame / 10); + } + } else { + if (output_width > 1920 || output_height > 1920 || + mb_per_frame > NUM_MBS_PER_FRAME(1920, 1088) || + fps > 30) { + slice_mode = + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE; + slice_val = 0; + } else { + slice_val = msm_comm_g_ctrl_for_id(inst, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES); + max_avg_slicesize = ((bitrate / fps) / 8) / 10; + slice_val = + max(slice_val, max_avg_slicesize); + } + } + + multi_slice_control.multi_slice = slice_mode; + multi_slice_control.slice_size = slice_val; + + rc = call_hfi_op(hdev, session_set_property, + (void *)inst->session, HAL_PARAM_VENC_MULTI_SLICE_CONTROL, + (void *)&multi_slice_control); + } + return rc; +} + +static int msm_vidc_set_rotation(struct msm_vidc_inst *inst) +{ + int rc = 0; + int value = 0; + struct hfi_device *hdev; + struct hal_vpe_rotation vpe_rotation; + struct hal_frame_size frame_sz; + + hdev = inst->core->device; + + /* Set rotation and flip first */ + value = msm_comm_g_ctrl_for_id(inst, V4L2_CID_ROTATE); + if (value < 0) { + dprintk(VIDC_ERR, "Get control for rotation failed\n"); + return value; + } + vpe_rotation.rotate = value; + value = msm_comm_g_ctrl_for_id(inst, V4L2_CID_MPEG_VIDC_VIDEO_FLIP); + if (value < 0) { + dprintk(VIDC_ERR, "Get control for flip failed\n"); + return value; + } + vpe_rotation.flip = value; + dprintk(VIDC_DBG, "Set rotation = %d, flip = %d for capture port.\n", + vpe_rotation.rotate, vpe_rotation.flip); + rc = call_hfi_op(hdev, session_set_property, + (void *)inst->session, + HAL_PARAM_VPE_ROTATION, &vpe_rotation); + if (rc) { + dprintk(VIDC_ERR, "Set rotation/flip at start stream failed\n"); + return rc; + } + + /* flip the output resolution if required */ + if (vpe_rotation.rotate == 90 || vpe_rotation.rotate == 270) { + frame_sz.buffer_type = HAL_BUFFER_OUTPUT; + frame_sz.width = inst->prop.height[CAPTURE_PORT]; + frame_sz.height = inst->prop.width[CAPTURE_PORT]; + dprintk(VIDC_DBG, "CAPTURE port width = %d, height = %d\n", + frame_sz.width, frame_sz.height); + rc = call_hfi_op(hdev, session_set_property, (void *) + inst->session, HAL_PARAM_FRAME_SIZE, &frame_sz); + if (rc) { + dprintk(VIDC_ERR, + "Failed to set framesize for CAPTURE port\n"); + return rc; + } + } + return rc; +} + +static inline int start_streaming(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct hal_buffer_size_minimum b; + struct hal_buffer_requirements *bufreq; + u32 rc_mode; + int value = 0; + + dprintk(VIDC_DBG, "%s: %x : inst %pK\n", __func__, + hash32_ptr(inst->session), inst); + hdev = inst->core->device; + + if (inst->session_type == MSM_VIDC_ENCODER) { + rc = msm_vidc_set_rotation(inst); + if (rc) { + dprintk(VIDC_ERR, + "Set rotation for encoder failed\n"); + goto fail_start; + } + } + + rc_mode = msm_comm_g_ctrl_for_id(inst, + V4L2_CID_MPEG_VIDEO_BITRATE_MODE); + /* HEIC HW/FWK tiling encode is supported only for CQ RC mode */ + if (rc_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CQ) { + if (!heic_encode_session_supported(inst)) { + dprintk(VIDC_ERR, + "HEIC Encode session not supported\n"); + return -ENOTSUPP; + } + } + + value = msm_comm_g_ctrl_for_id(inst, + V4L2_CID_MPEG_VIDC_VENC_BITRATE_SAVINGS); + if (!value && rc_mode != V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) { + struct hal_enable enable; + + dprintk(VIDC_INFO, + "Force enable bitrate savings for non-VBR_CFR\n"); + enable.enable = 1; + rc = call_hfi_op(hdev, session_set_property, + inst->session, HAL_PARAM_VENC_BITRATE_SAVINGS, + &enable); + } + + /* Check if current session is under HW capability */ + rc = msm_vidc_check_session_supported(inst); + if (rc) { + dprintk(VIDC_ERR, + "This session is not supported %pK\n", inst); + goto fail_start; + } + + rc = msm_vidc_check_scaling_supported(inst); + if (rc) { + dprintk(VIDC_ERR, + "This session scaling is not supported %pK\n", inst); + goto fail_start; + } + + rc = msm_vidc_set_internal_config(inst); + if (rc) { + dprintk(VIDC_ERR, + "Set internal config failed %pK\n", inst); + goto fail_start; + } + + /* Decide work route for current session */ + rc = call_core_op(inst->core, decide_work_route, inst); + if (rc) { + dprintk(VIDC_ERR, + "Failed to decide work route for session %pK\n", inst); + goto fail_start; + } + + /* Decide work mode for current session */ + rc = call_core_op(inst->core, decide_work_mode, inst); + if (rc) { + dprintk(VIDC_ERR, + "Failed to decide work mode for session %pK\n", inst); + goto fail_start; + } + + if (inst->session_type == MSM_VIDC_DECODER && + !inst->operating_rate_set && !is_realtime_session(inst)) { + inst->clk_data.turbo_mode = true; + dprintk(VIDC_INFO, + "inst(%pK) setting turbo mode "); + } + + /* Assign Core and LP mode for current session */ + rc = msm_vidc_decide_core_and_power_mode(inst); + if (rc) { + dprintk(VIDC_ERR, + "This session can't be submitted to HW %pK\n", inst); + goto fail_start; + } + + if (msm_comm_get_stream_output_mode(inst) == + HAL_VIDEO_DECODER_SECONDARY) { + b.buffer_type = HAL_BUFFER_OUTPUT2; + } else { + b.buffer_type = HAL_BUFFER_OUTPUT; + } + + rc = msm_comm_try_get_bufreqs(inst); + + b.buffer_size = inst->bufq[CAPTURE_PORT].plane_sizes[0]; + rc = call_hfi_op(hdev, session_set_property, + inst->session, HAL_PARAM_BUFFER_SIZE_MINIMUM, + &b); + + /* Verify if buffer counts are correct */ + rc = msm_vidc_verify_buffer_counts(inst); + if (rc) { + dprintk(VIDC_ERR, + "This session has mis-match buffer counts%pK\n", inst); + goto fail_start; + } + + if (inst->session_type == MSM_VIDC_DECODER && + msm_comm_get_stream_output_mode(inst) == + HAL_VIDEO_DECODER_SECONDARY) { + bufreq = get_buff_req_buffer(inst, + HAL_BUFFER_OUTPUT); + if (!bufreq) { + dprintk(VIDC_ERR, "Buffer requirements failed\n"); + goto fail_start; + } + /* For DPB buffers, Always use min count */ + rc = msm_comm_set_buffer_count(inst, + bufreq->buffer_count_min, + bufreq->buffer_count_min, + HAL_BUFFER_OUTPUT); + if (rc) { + dprintk(VIDC_ERR, + "failed to set buffer count\n"); + goto fail_start; + } + } + + rc = msm_comm_set_scratch_buffers(inst); + if (rc) { + dprintk(VIDC_ERR, + "Failed to set scratch buffers: %d\n", rc); + goto fail_start; + } + rc = msm_comm_set_persist_buffers(inst); + if (rc) { + dprintk(VIDC_ERR, + "Failed to set persist buffers: %d\n", rc); + goto fail_start; + } + + rc = msm_comm_set_recon_buffers(inst); + if (rc) { + dprintk(VIDC_ERR, + "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_output_buffers(inst); + if (rc) { + dprintk(VIDC_ERR, + "Failed to set output buffers: %d\n", rc); + goto fail_start; + } + } + + if (is_batching_allowed(inst)) + inst->batch.enable = true; + else + inst->batch.enable = false; + dprintk(VIDC_DBG, "%s: batching %s for inst %pK (%#x)\n", + __func__, inst->batch.enable ? "enabled" : "disabled", + inst, hash32_ptr(inst->session)); + + 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); + + rc = msm_comm_try_state(inst, MSM_VIDC_START_DONE); + if (rc) { + dprintk(VIDC_ERR, + "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_output_buffers(inst); + if (rc) { + dprintk(VIDC_ERR, + "Failed to queue output buffers: %d\n", rc); + goto fail_start; + } + } + +fail_start: + if (rc) + dprintk(VIDC_ERR, "%s: inst %pK session %x failed to start\n", + __func__, inst, hash32_ptr(inst->session)); + 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) { + dprintk(VIDC_ERR, "Invalid input, q = %pK\n", q); + return -EINVAL; + } + inst = q->drv_priv; + if (!inst || !inst->core || !inst->core->device) { + dprintk(VIDC_ERR, "%s invalid parameters\n", __func__); + return -EINVAL; + } + hdev = inst->core->device; + dprintk(VIDC_DBG, "Streamon called on: %d capability for inst: %pK\n", + q->type, inst); + switch (q->type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + if (inst->bufq[CAPTURE_PORT].vb2_bufq.streaming) + rc = start_streaming(inst); + break; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + if (inst->bufq[OUTPUT_PORT].vb2_bufq.streaming) + rc = start_streaming(inst); + break; + default: + dprintk(VIDC_ERR, "Queue type is not supported: %d\n", q->type); + rc = -EINVAL; + goto stream_start_failed; + } + if (rc) { + dprintk(VIDC_ERR, + "Streamon failed on: %d capability for inst: %pK\n", + q->type, inst); + goto stream_start_failed; + } + + rc = msm_comm_qbufs(inst); + if (rc) { + dprintk(VIDC_ERR, + "Failed to commit buffers queued before STREAM_ON to hardware: %d\n", + rc); + goto stream_start_failed; + } + + rc = msm_vidc_send_pending_eos_buffers(inst); + if (rc) { + dprintk(VIDC_ERR, + "Failed : Send pending EOS buffs for Inst = %pK, %d\n", + inst, 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(VIDC_ERR, "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; + + dprintk(VIDC_DBG, "%s: %x : inst %pK\n", __func__, + hash32_ptr(inst->session), inst); + + rc = msm_comm_try_state(inst, MSM_VIDC_RELEASE_RESOURCES_DONE); + if (rc) + dprintk(VIDC_ERR, + "Failed to move inst: %pK to state %d\n", + inst, MSM_VIDC_RELEASE_RESOURCES_DONE); + + 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) { + dprintk(VIDC_ERR, "Invalid input, q = %pK\n", q); + return; + } + + inst = q->drv_priv; + dprintk(VIDC_DBG, "Streamoff called on: %d capability\n", q->type); + switch (q->type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + if (!inst->bufq[CAPTURE_PORT].vb2_bufq.streaming) + rc = stop_streaming(inst); + break; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + if (!inst->bufq[OUTPUT_PORT].vb2_bufq.streaming) + rc = stop_streaming(inst); + break; + default: + dprintk(VIDC_ERR, + "Q-type is not supported: %d\n", q->type); + rc = -EINVAL; + break; + } + + msm_comm_scale_clocks_and_bus(inst); + + if (rc) + dprintk(VIDC_ERR, + "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) { + dprintk(VIDC_ERR, "%s: invalid params\n", __func__); + 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; + dprintk(VIDC_ERR, "%s: failed to get vidc-buf\n", __func__); + return -EINVAL; + } + if (!kref_get_mbuf(inst, mbuf)) { + dprintk(VIDC_ERR, "%s: mbuf not found\n", __func__); + return -EINVAL; + } + rc = msm_comm_qbuf(inst, mbuf); + if (rc) + dprintk(VIDC_ERR, "%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) { + dprintk(VIDC_ERR, "%s: invalid params\n", __func__); + return -EINVAL; + } + + mbuf = msm_comm_get_vidc_buffer(inst, vb2); + if (IS_ERR_OR_NULL(mbuf)) { + dprintk(VIDC_ERR, "%s: failed to get vidc-buf\n", __func__); + return -EINVAL; + } + if (!kref_get_mbuf(inst, mbuf)) { + dprintk(VIDC_ERR, "%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) + dprintk(VIDC_ERR, "%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) { + dprintk(VIDC_ERR, "%s: invalid params\n", __func__); + return -EINVAL; + } + + if (inst->session_type == MSM_VIDC_DECODER && + vb2->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_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) { + dprintk(VIDC_ERR, "%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(VIDC_ERR, "failed vb2-qbuf", inst, vb2); + msm_comm_generate_session_error(inst); + } +} + +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 == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + q = &inst->bufq[CAPTURE_PORT].vb2_bufq; + } else if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + q = &inst->bufq[OUTPUT_PORT].vb2_bufq; + } else { + dprintk(VIDC_ERR, "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) +{ + int rc = 0; + 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 rc; +} + +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 (cmd != VIDIOC_VIDEO_CMD) { + dprintk(VIDC_ERR, + "%s: invalid private cmd %#x\n", __func__, cmd); + return -ENOIOCTLCMD; + } + + if (!inst || !arg) { + dprintk(VIDC_ERR, "%s: invalid args\n", __func__); + return -EINVAL; + } + + if (inst->session_type == MSM_VIDC_CVP) { + rc = msm_vidc_cvp(inst, arg); + } else { + dprintk(VIDC_ERR, + "%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, c = 0; + struct msm_vidc_inst *inst; + const char *ctrl_name = NULL; + + if (!ctrl) { + dprintk(VIDC_ERR, "%s invalid parameters for ctrl\n", __func__); + return -EINVAL; + } + + inst = container_of(ctrl->handler, + struct msm_vidc_inst, ctrl_handler); + if (!inst) { + dprintk(VIDC_ERR, "%s invalid parameters for inst\n", __func__); + return -EINVAL; + } + + for (c = 0; c < ctrl->ncontrols; ++c) { + if (ctrl->cluster[c]->is_new) { + rc = msm_vidc_try_set_ctrl(inst, ctrl->cluster[c]); + if (rc) { + dprintk(VIDC_ERR, "Failed setting %x\n", + ctrl->cluster[c]->id); + break; + } + } + } + if (rc) { + ctrl_name = v4l2_ctrl_get_name(ctrl->id); + dprintk(VIDC_ERR, "Failed setting control: Inst = %pK (%s)\n", + inst, ctrl_name ? ctrl_name : "Invalid ctrl"); + } + + return rc; +} +static int try_get_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) +{ + int rc = 0; + struct hal_buffer_requirements *bufreq = NULL; + enum hal_buffer buffer_type; + + switch (ctrl->id) { + + case V4L2_CID_MPEG_VIDEO_H264_PROFILE: + ctrl->val = msm_comm_hal_to_v4l2( + V4L2_CID_MPEG_VIDEO_H264_PROFILE, + inst->profile); + break; + case V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE: + ctrl->val = msm_comm_hal_to_v4l2( + V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE, + inst->profile); + break; + case V4L2_CID_MPEG_VIDC_IMG_GRID_ENABLE: + ctrl->val = inst->grid_enable; + break; + case V4L2_CID_MPEG_VIDEO_H264_LEVEL: + ctrl->val = msm_comm_hal_to_v4l2( + V4L2_CID_MPEG_VIDEO_H264_LEVEL, + inst->level); + break; + case V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL: + ctrl->val = msm_comm_hal_to_v4l2( + V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL, + inst->level); + break; + case V4L2_CID_MPEG_VIDC_VIDEO_HEVC_TIER_LEVEL: + ctrl->val = msm_comm_hal_to_v4l2( + V4L2_CID_MPEG_VIDC_VIDEO_HEVC_TIER_LEVEL, + inst->level); + break; + + case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE: + ctrl->val = inst->entropy_mode; + break; + + case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: + buffer_type = msm_comm_get_hal_output_buffer(inst); + bufreq = get_buff_req_buffer(inst, + buffer_type); + if (!bufreq) { + dprintk(VIDC_ERR, + "Failed to find bufreqs for buffer type = %d\n", + buffer_type); + return -EINVAL; + } + ctrl->val = bufreq->buffer_count_min_host; + dprintk(VIDC_DBG, "g_min: %x : hal_buffer %d min buffers %d\n", + hash32_ptr(inst->session), buffer_type, ctrl->val); + break; + case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT: + bufreq = get_buff_req_buffer(inst, HAL_BUFFER_INPUT); + if (!bufreq) { + dprintk(VIDC_ERR, + "Failed to find bufreqs for buffer type = %d\n", + HAL_BUFFER_INPUT); + return -EINVAL; + } + + if (inst->session_type == MSM_VIDC_DECODER && + !(inst->flags & VIDC_THUMBNAIL) && + inst->fmts[OUTPUT_PORT].fourcc == + V4L2_PIX_FMT_VP9 && + bufreq->buffer_count_min_host < + MIN_NUM_OUTPUT_BUFFERS_VP9) + bufreq->buffer_count_min_host = + MIN_NUM_OUTPUT_BUFFERS_VP9; + + ctrl->val = bufreq->buffer_count_min_host; + dprintk(VIDC_DBG, "g_min: %x : hal_buffer %d min buffers %d\n", + hash32_ptr(inst->session), HAL_BUFFER_INPUT, ctrl->val); + break; + case V4L2_CID_MPEG_VIDC_VIDEO_TME_PAYLOAD_VERSION: + ctrl->val = inst->capability.tme_version; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_FORMAT: + ctrl->val = + inst->capability.nal_stream_format.nal_stream_format_supported; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_ROI_TYPE: + if (!inst->core || !inst->core->platform_data) + return -EINVAL; + + ctrl->val = (inst->core->platform_data->vpu_ver == + VPU_VERSION_4) ? + V4L2_CID_MPEG_VIDC_VIDEO_ROI_TYPE_2BIT : + V4L2_CID_MPEG_VIDC_VIDEO_ROI_TYPE_2BYTE; + break; + default: + /* + * Other controls aren't really volatile, shouldn't need to + * modify ctrl->value + */ + break; + } + + return rc; +} + +static int msm_vidc_op_g_volatile_ctrl(struct v4l2_ctrl *ctrl) +{ + int rc = 0, c = 0; + struct msm_vidc_inst *inst; + struct v4l2_ctrl *master; + + if (!ctrl) { + dprintk(VIDC_ERR, "%s invalid parameters for ctrl\n", __func__); + return -EINVAL; + } + + inst = container_of(ctrl->handler, + struct msm_vidc_inst, ctrl_handler); + if (!inst) { + dprintk(VIDC_ERR, "%s invalid parameters for inst\n", __func__); + return -EINVAL; + } + master = ctrl->cluster[0]; + if (!master) { + dprintk(VIDC_ERR, "%s invalid parameters for master\n", + __func__); + return -EINVAL; + } + + for (c = 0; c < master->ncontrols; ++c) { + if (master->cluster[c]->flags & V4L2_CTRL_FLAG_VOLATILE) { + rc = try_get_ctrl(inst, master->cluster[c]); + if (rc) { + dprintk(VIDC_ERR, "Failed getting %x\n", + master->cluster[c]->id); + return rc; + } + } + } + if (rc) + dprintk(VIDC_ERR, "Failed getting control: Inst = %pK (%s)\n", + inst, v4l2_ctrl_get_name(ctrl->id)); + return rc; +} + +static const struct v4l2_ctrl_ops msm_vidc_ctrl_ops = { + + .s_ctrl = msm_vidc_op_s_ctrl, + .g_volatile_ctrl = msm_vidc_op_g_volatile_ctrl, +}; + +static void batch_timer_callback(unsigned long data) +{ + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)data; + + if (!inst->batch.enable) + return; + + schedule_work(&inst->batch_work); +} + +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) { + dprintk(VIDC_ERR, "Invalid input, core_id = %d, session = %d\n", + core_id, session_type); + goto err_invalid_core; + } + core = get_vidc_core(core_id); + if (!core) { + dprintk(VIDC_ERR, + "Failed to find core for core_id = %d\n", core_id); + goto err_invalid_core; + } + + inst = kzalloc(sizeof(*inst), GFP_KERNEL); + if (!inst) { + dprintk(VIDC_ERR, "Failed to allocate memory\n"); + rc = -ENOMEM; + goto err_invalid_core; + } + + pr_info(VIDC_DBG_TAG "Opening video instance: %pK, %d\n", + "info", inst, session_type); + mutex_init(&inst->sync_lock); + mutex_init(&inst->bufq[CAPTURE_PORT].lock); + mutex_init(&inst->bufq[OUTPUT_PORT].lock); + mutex_init(&inst->lock); + + INIT_MSM_VIDC_LIST(&inst->scratchbufs); + INIT_MSM_VIDC_LIST(&inst->freqs); + INIT_MSM_VIDC_LIST(&inst->input_crs); + INIT_MSM_VIDC_LIST(&inst->buffer_tags); + 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->reconbufs); + INIT_MSM_VIDC_LIST(&inst->eosbufs); + INIT_MSM_VIDC_LIST(&inst->etb_data); + INIT_MSM_VIDC_LIST(&inst->fbd_data); + + kref_init(&inst->kref); + + inst->session_type = session_type; + inst->state = MSM_VIDC_CORE_UNINIT_DONE; + inst->core = core; + inst->clk_data.min_freq = 0; + inst->clk_data.curr_freq = 0; + inst->clk_data.ddr_bw = 0; + inst->clk_data.sys_cache_bw = 0; + inst->clk_data.bitrate = 0; + inst->operating_rate_set = false; + inst->clk_data.work_route = 1; + inst->clk_data.core_id = VIDC_CORE_ID_DEFAULT; + 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->profile = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE; + inst->level = V4L2_MPEG_VIDEO_H264_LEVEL_1_0; + inst->entropy_mode = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC; + inst->max_filled_length = 0; + 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) { + dprintk(VIDC_ERR, "Failed control initialization\n"); + goto fail_bufq_capture; + } + + rc = vb2_bufq_init(inst, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, + session_type); + if (rc) { + dprintk(VIDC_ERR, + "Failed to initialize vb2 queue on capture port\n"); + goto fail_bufq_capture; + } + rc = vb2_bufq_init(inst, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, + session_type); + if (rc) { + dprintk(VIDC_ERR, + "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) { + dprintk(VIDC_ERR, + "Failed to move video instance to init state\n"); + goto fail_init; + } + + if (msm_comm_check_for_inst_overload(core)) { + dprintk(VIDC_ERR, + "Instance count reached Max limit, rejecting session"); + goto fail_init; + } + + msm_comm_scale_clocks_and_bus(inst); + + 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) { + dprintk(VIDC_ERR, + "Failed to move video instance to open done state\n"); + goto fail_init; + } + } + + INIT_WORK(&inst->batch_work, msm_vidc_batch_handler); + setup_timer(&inst->batch_timer, + batch_timer_callback, (unsigned long)inst); + + 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[OUTPUT_PORT].vb2_bufq); +fail_bufq_output: + vb2_queue_release(&inst->bufq[CAPTURE_PORT].vb2_bufq); +fail_bufq_capture: + msm_comm_ctrl_deinit(inst); + mutex_destroy(&inst->sync_lock); + mutex_destroy(&inst->bufq[CAPTURE_PORT].lock); + mutex_destroy(&inst->bufq[OUTPUT_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->freqs); + DEINIT_MSM_VIDC_LIST(&inst->input_crs); + DEINIT_MSM_VIDC_LIST(&inst->buffer_tags); + DEINIT_MSM_VIDC_LIST(&inst->etb_data); + DEINIT_MSM_VIDC_LIST(&inst->fbd_data); + + 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[] = {OUTPUT_PORT, CAPTURE_PORT}; + int c = 0; + + if (!inst) { + dprintk(VIDC_ERR, "%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(VIDC_ERR, "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); + + del_timer(&inst->batch_timer); + + cancel_work_sync(&inst->batch_work); + + msm_comm_free_freq_table(inst); + + msm_comm_free_input_cr_table(inst); + + if (msm_comm_release_scratch_buffers(inst, false)) + dprintk(VIDC_ERR, + "Failed to release scratch buffers\n"); + + if (msm_comm_release_recon_buffers(inst)) + dprintk(VIDC_ERR, + "Failed to release recon buffers\n"); + + if (msm_comm_release_persist_buffers(inst)) + dprintk(VIDC_ERR, + "Failed to release persist buffers\n"); + + if (msm_comm_release_mark_data(inst)) + dprintk(VIDC_ERR, + "Failed to release mark_data buffers\n"); + + msm_comm_free_buffer_tags(inst); + + msm_comm_release_eos_buffers(inst); + + if (msm_comm_release_output_buffers(inst, true)) + dprintk(VIDC_ERR, + "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)) { + dprintk(VIDC_ERR, + "pending_getpropq not empty for instance %pK\n", + inst); + 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) { + dprintk(VIDC_ERR, "%s: invalid params\n", __func__); + return -EINVAL; + } + + core = inst->core; + + 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); + + for (i = 0; i < MAX_PORT_NUM; i++) + vb2_queue_release(&inst->bufq[i].vb2_bufq); + + 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->freqs); + DEINIT_MSM_VIDC_LIST(&inst->input_crs); + DEINIT_MSM_VIDC_LIST(&inst->etb_data); + DEINIT_MSM_VIDC_LIST(&inst->fbd_data); + + mutex_destroy(&inst->sync_lock); + mutex_destroy(&inst->bufq[CAPTURE_PORT].lock); + mutex_destroy(&inst->bufq[OUTPUT_PORT].lock); + mutex_destroy(&inst->lock); + + msm_vidc_debugfs_deinit_inst(inst); + + pr_info(VIDC_DBG_TAG "Closed video instance: %pK\n", + "info", inst); + 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) { + dprintk(VIDC_ERR, "%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) + dprintk(VIDC_ERR, + "Failed to move inst %pK to rel resource done state\n", + inst); + + /* + * 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) { + dprintk(VIDC_ERR, + "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/drivers/media/platform/msm/vidc/msm_vidc.h b/drivers/media/platform/msm/vidc/msm_vidc.h new file mode 100644 index 000000000000..c22970833f83 --- /dev/null +++ b/drivers/media/platform/msm/vidc/msm_vidc.h @@ -0,0 +1,136 @@ +/* Copyright (c) 2012-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 _MSM_VIDC_H_ +#define _MSM_VIDC_H_ + +#include +#include +#include +#include +#include +#include + +#define HAL_BUFFER_MAX 0xe + +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/.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 dma_iommu_mapping *mapping; + 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, +}; + +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_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/drivers/media/platform/msm/vidc/msm_vidc_clocks.c b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c new file mode 100644 index 000000000000..ed7c97bbf782 --- /dev/null +++ b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c @@ -0,0 +1,1774 @@ +/* Copyright (c) 2017-2021, 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 "msm_vidc_common.h" +#include "vidc_hfi_api.h" +#include "msm_vidc_debug.h" +#include "msm_vidc_clocks.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) + +static unsigned long msm_vidc_calc_freq_ar50(struct msm_vidc_inst *inst, + u32 filled_len); +static int msm_vidc_decide_work_mode_ar50(struct msm_vidc_inst *inst); +static unsigned long msm_vidc_calc_freq(struct msm_vidc_inst *inst, + u32 filled_len); + +struct msm_vidc_core_ops core_ops_vpu4 = { + .calc_freq = msm_vidc_calc_freq_ar50, + .decide_work_route = NULL, + .decide_work_mode = msm_vidc_decide_work_mode_ar50, +}; + +struct msm_vidc_core_ops core_ops_vpu5 = { + .calc_freq = msm_vidc_calc_freq, + .decide_work_route = msm_vidc_decide_work_route, + .decide_work_mode = msm_vidc_decide_work_mode, +}; + +static inline void msm_dcvs_print_dcvs_stats(struct clock_data *dcvs) +{ + dprintk(VIDC_PROF, + "DCVS: Load_Low %d, Load Norm %d, Load High %d\n", + dcvs->load_low, + dcvs->load_norm, + dcvs->load_high); + + dprintk(VIDC_PROF, + "DCVS: min_threshold %d, max_threshold %d\n", + dcvs->min_threshold, dcvs->max_threshold); +} + +static inline unsigned long int get_ubwc_compression_ratio( + struct ubwc_cr_stats_info_type ubwc_stats_info) +{ + unsigned long int sum = 0, weighted_sum = 0; + unsigned long int 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; +} + +int msm_vidc_get_mbs_per_frame(struct msm_vidc_inst *inst) +{ + int height, width; + + if (!inst->in_reconfig) { + height = max(inst->prop.height[CAPTURE_PORT], + inst->prop.height[OUTPUT_PORT]); + width = max(inst->prop.width[CAPTURE_PORT], + inst->prop.width[OUTPUT_PORT]); + } else { + height = inst->reconfig_height; + width = inst->reconfig_width; + } + + return NUM_MBS_PER_FRAME(height, width); +} + +static int msm_vidc_get_fps(struct msm_vidc_inst *inst) +{ + int fps; + + if ((inst->clk_data.operating_rate >> 16) > inst->prop.fps) + fps = (inst->clk_data.operating_rate >> 16) ? + (inst->clk_data.operating_rate >> 16) : 1; + else + fps = inst->prop.fps; + + return fps; +} + +void update_recon_stats(struct msm_vidc_inst *inst, + struct recon_stats_type *recon_stats) +{ + struct recon_buf *binfo; + u32 CR = 0, CF = 0; + u32 frame_size; + + 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->reconbufs.lock); + list_for_each_entry(binfo, &inst->reconbufs.list, list) { + if (binfo->buffer_index == + recon_stats->buffer_index) { + binfo->CR = CR; + binfo->CF = CF; + } + } + mutex_unlock(&inst->reconbufs.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 min_cf = MSM_VIDC_MAX_UBWC_COMPLEXITY_FACTOR, max_cf = 0; + u32 min_input_cr = MSM_VIDC_MAX_UBWC_COMPRESSION_RATIO, + max_input_cr = 0; + u32 min_cr = MSM_VIDC_MAX_UBWC_COMPRESSION_RATIO, max_cr = 0; + + mutex_lock(&inst->reconbufs.lock); + list_for_each_entry_safe(binfo, nextb, &inst->reconbufs.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->reconbufs.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; + vote_data->use_dpb_read = false; + + dprintk(VIDC_PROF, + "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_vote_bus(struct msm_vidc_core *core) +{ + int rc = 0, vote_data_count = 0, i = 0; + struct hfi_device *hdev; + struct msm_vidc_inst *inst = NULL; + struct vidc_bus_vote_data *vote_data = NULL; + bool is_turbo = false; + + if (!core || !core->device) { + dprintk(VIDC_ERR, "%s Invalid args: %pK\n", __func__, core); + return -EINVAL; + } + hdev = core->device; + + vote_data = kzalloc(sizeof(struct vidc_bus_vote_data) * + MAX_SUPPORTED_INSTANCES, GFP_ATOMIC); + if (!vote_data) { + dprintk(VIDC_DBG, + "vote_data allocation with GFP_ATOMIC failed\n"); + vote_data = kzalloc(sizeof(struct vidc_bus_vote_data) * + MAX_SUPPORTED_INSTANCES, GFP_KERNEL); + if (!vote_data) { + dprintk(VIDC_DBG, + "vote_data allocation failed\n"); + return -EINVAL; + } + } + + mutex_lock(&core->lock); + list_for_each_entry(inst, &core->instances, list) { + int codec = 0; + struct msm_vidc_buffer *temp, *next; + u32 filled_len = 0; + u32 device_addr = 0; + + if (!inst) { + dprintk(VIDC_ERR, "%s Invalid args\n", + __func__); + mutex_unlock(&core->lock); + return -EINVAL; + } + + mutex_lock(&inst->registeredbufs.lock); + list_for_each_entry_safe(temp, next, + &inst->registeredbufs.list, list) { + if (temp->vvb.vb2_buf.type == + V4L2_BUF_TYPE_VIDEO_OUTPUT_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_QCOM_BUF_FLAG_PERF_MODE)) { + is_turbo = true; + } + } + mutex_unlock(&inst->registeredbufs.lock); + + if ((!filled_len || !device_addr) && + (inst->session_type != MSM_VIDC_CVP)) { + dprintk(VIDC_DBG, "%s: no input for session %x\n", + __func__, hash32_ptr(inst->session)); + continue; + } + + ++vote_data_count; + + switch (inst->session_type) { + case MSM_VIDC_DECODER: + codec = inst->fmts[OUTPUT_PORT].fourcc; + break; + case MSM_VIDC_ENCODER: + codec = inst->fmts[CAPTURE_PORT].fourcc; + break; + case MSM_VIDC_CVP: + codec = V4L2_PIX_FMT_CVP; + break; + default: + dprintk(VIDC_ERR, "%s: invalid session_type %#x\n", + __func__, inst->session_type); + break; + } + + memset(&(vote_data[i]), 0x0, sizeof(struct vidc_bus_vote_data)); + + vote_data[i].domain = get_hal_domain(inst->session_type); + vote_data[i].codec = get_hal_codec(codec); + vote_data[i].input_width = inst->prop.width[OUTPUT_PORT]; + vote_data[i].input_height = inst->prop.height[OUTPUT_PORT]; + vote_data[i].output_width = inst->prop.width[CAPTURE_PORT]; + vote_data[i].output_height = inst->prop.height[CAPTURE_PORT]; + vote_data[i].rotation = + msm_comm_g_ctrl_for_id(inst, V4L2_CID_ROTATE); + vote_data[i].lcu_size = (codec == V4L2_PIX_FMT_HEVC || + codec == V4L2_PIX_FMT_VP9) ? 32 : 16; + vote_data[i].b_frames_enabled = + msm_comm_g_ctrl_for_id(inst, + V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES) != 0; + + vote_data[i].fps = msm_vidc_get_fps(inst); + if (inst->session_type == MSM_VIDC_ENCODER) { + vote_data[i].bitrate = inst->clk_data.bitrate; + /* scale bitrate if operating rate is larger than fps */ + if (vote_data[i].fps > inst->prop.fps + && inst->prop.fps) { + vote_data[i].bitrate = vote_data[i].bitrate / + inst->prop.fps * vote_data[i].fps; + } + } else if (inst->session_type == MSM_VIDC_DECODER) { + vote_data[i].bitrate = + filled_len * vote_data[i].fps * 8; + } + + vote_data[i].power_mode = 0; + if (inst->clk_data.buffer_counter < DCVS_FTB_WINDOW && + inst->session_type != MSM_VIDC_CVP) + vote_data[i].power_mode = VIDC_POWER_TURBO; + if (msm_vidc_clock_voting || is_turbo) + vote_data[i].power_mode = VIDC_POWER_TURBO; + + if (msm_comm_get_stream_output_mode(inst) == + HAL_VIDEO_DECODER_PRIMARY) { + vote_data[i].color_formats[0] = + msm_comm_get_hal_uncompressed( + inst->clk_data.opb_fourcc); + vote_data[i].num_formats = 1; + } else { + vote_data[i].color_formats[0] = + msm_comm_get_hal_uncompressed( + inst->clk_data.dpb_fourcc); + vote_data[i].color_formats[1] = + msm_comm_get_hal_uncompressed( + inst->clk_data.opb_fourcc); + vote_data[i].num_formats = 2; + } + vote_data[i].work_mode = inst->clk_data.work_mode; + fill_dynamic_stats(inst, &vote_data[i]); + + if (core->resources.sys_cache_res_set) + vote_data[i].use_sys_cache = true; + + if (inst->session_type == MSM_VIDC_CVP) { + vote_data[i].domain = + get_hal_domain(inst->session_type); + vote_data[i].ddr_bw = inst->clk_data.ddr_bw; + vote_data[i].sys_cache_bw = + inst->clk_data.sys_cache_bw; + } + + i++; + } + mutex_unlock(&core->lock); + if (vote_data_count) + rc = call_hfi_op(hdev, vote_bus, hdev->hfi_device_data, + vote_data, vote_data_count); + + kfree(vote_data); + return rc; +} + +static int msm_dcvs_scale_clocks(struct msm_vidc_inst *inst, + unsigned long freq) +{ + int rc = 0; + int bufs_with_fw = 0; + int bufs_with_client = 0; + struct hal_buffer_requirements *buf_reqs; + struct clock_data *dcvs; + + if (!inst || !inst->core || !inst->core->device) { + dprintk(VIDC_ERR, "%s Invalid params\n", __func__); + return -EINVAL; + } + + /* assume no increment or decrement is required initially */ + inst->clk_data.dcvs_flags = 0; + + if (!inst->clk_data.dcvs_mode || inst->batch.enable) { + dprintk(VIDC_DBG, "Skip DCVS (dcvs %d, batching %d)\n", + inst->clk_data.dcvs_mode, inst->batch.enable); + /* update load (freq) with normal value */ + inst->clk_data.load = inst->clk_data.load_norm; + return 0; + } + + dcvs = &inst->clk_data; + + if (is_decode_session(inst)) + bufs_with_fw = msm_comm_num_queued_bufs(inst, + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + else + bufs_with_fw = msm_comm_num_queued_bufs(inst, + V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + /* +1 as one buffer is going to be queued after the function */ + bufs_with_fw += 1; + + buf_reqs = get_buff_req_buffer(inst, dcvs->buffer_type); + if (!buf_reqs) { + dprintk(VIDC_ERR, "%s: invalid buf type %d\n", + __func__, dcvs->buffer_type); + return -EINVAL; + } + bufs_with_client = buf_reqs->buffer_count_actual - bufs_with_fw; + + /* + * PMS decides clock level based on below algo + + * Limits : + * max_threshold : Client extra allocated buffers. Client + * reserves these buffers for it's smooth flow. + * min_output_buf : HW requested buffers for it's smooth + * flow of buffers. + * min_threshold : Driver requested extra buffers for PMS. + + * 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 same as FW requested, + * pipeline has cushion to absorb FW slowness, Decrease clocks. + * 3) When none of 1) or 2) FW is just fast enough to maintain + * pipeline, request Right Clocks. + */ + + if (bufs_with_client <= dcvs->max_threshold) { + dcvs->load = dcvs->load_high; + dcvs->dcvs_flags |= MSM_VIDC_DCVS_INCR; + } else if (bufs_with_fw < buf_reqs->buffer_count_min) { + dcvs->load = dcvs->load_low; + dcvs->dcvs_flags |= MSM_VIDC_DCVS_DECR; + } else { + dcvs->load = dcvs->load_norm; + dcvs->dcvs_flags = 0; + } + + dprintk(VIDC_PROF, + "DCVS: %x : total bufs %d outside fw %d max threshold %d with fw %d min bufs %d flags %#x\n", + hash32_ptr(inst->session), buf_reqs->buffer_count_actual, + bufs_with_client, dcvs->max_threshold, bufs_with_fw, + buf_reqs->buffer_count_min, dcvs->dcvs_flags); + return rc; +} + +static void msm_vidc_update_freq_entry(struct msm_vidc_inst *inst, + unsigned long freq, u32 device_addr, bool is_turbo) +{ + struct vidc_freq_data *temp, *next; + bool found = false; + + mutex_lock(&inst->freqs.lock); + list_for_each_entry_safe(temp, next, &inst->freqs.list, list) { + if (temp->device_addr == device_addr) { + temp->freq = freq; + found = true; + break; + } + } + + if (!found) { + temp = kzalloc(sizeof(*temp), GFP_KERNEL); + if (!temp) { + dprintk(VIDC_WARN, "%s: malloc failure.\n", __func__); + goto exit; + } + temp->freq = freq; + temp->device_addr = device_addr; + list_add_tail(&temp->list, &inst->freqs.list); + } + temp->turbo = !!is_turbo; +exit: + mutex_unlock(&inst->freqs.lock); +} + +void msm_vidc_clear_freq_entry(struct msm_vidc_inst *inst, + u32 device_addr) +{ + struct vidc_freq_data *temp, *next; + + mutex_lock(&inst->freqs.lock); + list_for_each_entry_safe(temp, next, &inst->freqs.list, list) { + if (temp->device_addr == device_addr) + temp->freq = 0; + } + mutex_unlock(&inst->freqs.lock); + + inst->clk_data.buffer_counter++; +} + +static unsigned long msm_vidc_max_freq(struct msm_vidc_core *core) +{ + 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; + dprintk(VIDC_PROF, "Max rate = %lu\n", freq); + return freq; +} + +void msm_comm_free_freq_table(struct msm_vidc_inst *inst) +{ + struct vidc_freq_data *temp, *next; + + mutex_lock(&inst->freqs.lock); + list_for_each_entry_safe(temp, next, &inst->freqs.list, list) { + list_del(&temp->list); + kfree(temp); + } + INIT_LIST_HEAD(&inst->freqs.list); + mutex_unlock(&inst->freqs.lock); +} + +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) { + dprintk(VIDC_WARN, "%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) +{ + unsigned long freq = 0; + unsigned long vpp_cycles = 0, vsp_cycles = 0; + unsigned long 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_CALC_NO_QUIRKS); + + 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 { + dprintk(VIDC_ERR, "Unknown session type = %s\n", __func__); + return msm_vidc_max_freq(inst->core); + } + + freq = max(vpp_cycles, vsp_cycles); + freq = max(freq, fw_cycles); + + dprintk(VIDC_DBG, "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; + } + + dcvs->load_norm = rate; + dcvs->load_low = i < (core->resources.allowed_clks_tbl_size - 1) ? + allowed_clks_tbl[i+1].clock_rate : dcvs->load_norm; + dcvs->load_high = i > 0 ? allowed_clks_tbl[i-1].clock_rate : + dcvs->load_norm; + + msm_dcvs_print_dcvs_stats(dcvs); + + dprintk(VIDC_PROF, "%s Inst %pK : Filled Len = %d Freq = %lu\n", + __func__, inst, filled_len, freq); + + return freq; +} + +static unsigned long msm_vidc_calc_freq(struct msm_vidc_inst *inst, + u32 filled_len) +{ + unsigned long freq = 0; + unsigned long sw_overhead = 0; + unsigned long vpp_cycles = 0, vsp_cycles = 0; + unsigned long 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; + 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_CALC_NO_QUIRKS); + + 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; + 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->prop.fps && inst->prop.fps) { + vsp_factor_num *= operating_rate; + vsp_factor_den *= inst->prop.fps; + } + vsp_cycles += div_u64(((u64)inst->clk_data.bitrate * + vsp_factor_num), vsp_factor_den); + + /* sw overhead factor */ + sw_overhead = div_u64((u64)vsp_cycles * fw_vpp_cycles, + vpp_cycles); + vsp_cycles += max(vsp_cycles/20, sw_overhead); + + /* 21 / 20 is minimum overhead factor */ + vpp_cycles += max(vpp_cycles / 20, fw_vpp_cycles); + + if (inst->clk_data.work_route > 1) + vpp_cycles += (vpp_cycles * 14 / 1000); + + } else if (inst->session_type == MSM_VIDC_DECODER) { + vpp_cycles = mbs_per_second * inst->clk_data.entry->vpp_cycles / + inst->clk_data.work_route; + + 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); + + /* sw overhead factor */ + sw_overhead = div_u64(((u64)vsp_cycles * fw_vpp_cycles), + vpp_cycles); + vsp_cycles += max(vsp_cycles/20, sw_overhead); + + /* 21 / 20 is minimum overhead factor */ + vpp_cycles += max(vpp_cycles / 20, fw_vpp_cycles); + + /* 1.059 pipeline overhead factor */ + if (inst->clk_data.work_route > 1) + vpp_cycles += vpp_cycles/17; + + } else { + dprintk(VIDC_ERR, "Unknown session type = %s\n", __func__); + return msm_vidc_max_freq(inst->core); + } + + 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; + } + + dcvs->load_norm = rate; + dcvs->load_low = i < (core->resources.allowed_clks_tbl_size - 1) ? + allowed_clks_tbl[i+1].clock_rate : dcvs->load_norm; + dcvs->load_high = i > 0 ? allowed_clks_tbl[i-1].clock_rate : + dcvs->load_norm; + + dprintk(VIDC_PROF, + "%s: inst %pK: %x : filled len %d required freq %lu load_norm %d\n", + __func__, inst, hash32_ptr(inst->session), + filled_len, freq, dcvs->load_norm); + + return freq; +} + +int msm_vidc_set_clocks(struct msm_vidc_core *core) +{ + 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; + + hdev = core->device; + allowed_clks_tbl = core->resources.allowed_clks_tbl; + if (!allowed_clks_tbl) { + dprintk(VIDC_ERR, + "%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 == + V4L2_BUF_TYPE_VIDEO_OUTPUT_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) { + dprintk(VIDC_DBG, "%s no input for session %x\n", + __func__, hash32_ptr(inst->session)); + 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) { + dprintk(VIDC_PROF, + "msm_vidc_clock_voting %d\n", + msm_vidc_clock_voting); + freq_core_max = msm_vidc_clock_voting; + decrement = false; + break; + } + + if (inst->clk_data.turbo_mode) { + dprintk(VIDC_PROF, + "Found an instance with Turbo request\n"); + freq_core_max = msm_vidc_max_freq(core); + 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 (increment) { + if (i > 0) + rate = allowed_clks_tbl[i-1].clock_rate; + } else if (decrement) { + if (i < (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); + + dprintk(VIDC_PROF, + "%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); + + return rc; +} + +int msm_vidc_validate_operating_rate(struct msm_vidc_inst *inst, + u32 operating_rate) +{ + struct msm_vidc_inst *temp; + struct msm_vidc_core *core; + unsigned long max_freq, freq_left, op_rate_possible, load, cycles; + unsigned long mbs_per_second, freq_core0 = 0, freq_core1 = 0, freq; + int rc = 0; + u32 curr_operating_rate = 0; + + if (!inst || !inst->core) { + dprintk(VIDC_ERR, "%s Invalid args\n", __func__); + return -EINVAL; + } + core = inst->core; + curr_operating_rate = + max(inst->clk_data.operating_rate >> 16, inst->prop.fps); + operating_rate = operating_rate >> 16; + + /* always allow decreasing operating rate*/ + if (curr_operating_rate >= operating_rate) + return 0; + + mutex_lock(&core->lock); + max_freq = msm_vidc_max_freq(core); + list_for_each_entry(temp, &core->instances, list) { + if (temp == inst || + temp->state < MSM_VIDC_START_DONE || + temp->state >= MSM_VIDC_RELEASE_RESOURCES_DONE) + continue; + + if (temp->clk_data.core_id == VIDC_CORE_ID_1) + freq_core0 += temp->clk_data.min_freq; + else if (temp->clk_data.core_id == VIDC_CORE_ID_2) + freq_core1 += temp->clk_data.min_freq; + else if (temp->clk_data.core_id == VIDC_CORE_ID_3) { + freq_core0 += temp->clk_data.min_freq; + freq_core1 += temp->clk_data.min_freq; + } + } + + if (inst->clk_data.core_id == VIDC_CORE_ID_1) + freq = freq_core0; + else if (inst->clk_data.core_id == VIDC_CORE_ID_2) + freq = freq_core1; + else + freq = max(freq_core0, freq_core1); + + freq_left = max_freq > freq ? max_freq - freq : 0; + + mbs_per_second = msm_comm_get_inst_load_per_core(inst, + LOAD_CALC_NO_QUIRKS); + + cycles = inst->clk_data.entry->vpp_cycles; + if (inst->session_type == MSM_VIDC_ENCODER) + cycles = inst->flags & VIDC_LOW_POWER ? + inst->clk_data.entry->low_power_cycles : + cycles; + + if (inst->clk_data.work_route) + cycles /= inst->clk_data.work_route; + + load = cycles * mbs_per_second; + + op_rate_possible = load ? (freq_left * curr_operating_rate / load) : 0; + + + if (op_rate_possible >= operating_rate || + msm_vidc_clock_voting || + inst->clk_data.buffer_counter < DCVS_FTB_WINDOW) { + dprintk(VIDC_DBG, + "Requestd operating rate is valid %u\n", + operating_rate); + rc = 0; + } else { + dprintk(VIDC_DBG, + "Current load is high for requested settings. Cannot set operating rate to %u\n", + operating_rate); + rc = -EINVAL; + } + mutex_unlock(&core->lock); + + 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) { + dprintk(VIDC_ERR, "%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 == + V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + filled_len = max(filled_len, + temp->vvb.vb2_buf.planes[0].bytesused); + if (inst->session_type == MSM_VIDC_ENCODER && + (temp->vvb.flags & + V4L2_QCOM_BUF_FLAG_PERF_MODE)) { + is_turbo = true; + } + device_addr = temp->smem[0].device_addr; + } + } + mutex_unlock(&inst->registeredbufs.lock); + + if (!filled_len || !device_addr) { + dprintk(VIDC_DBG, "%s no input for session %x\n", + __func__, hash32_ptr(inst->session)); + return 0; + } + + freq = call_core_op(inst->core, calc_freq, inst, filled_len); + inst->clk_data.min_freq = freq; + /* update dcvs flags */ + msm_dcvs_scale_clocks(inst, freq); + + if (inst->clk_data.buffer_counter < DCVS_FTB_WINDOW || is_turbo || + msm_vidc_clock_voting) { + inst->clk_data.min_freq = msm_vidc_max_freq(inst->core); + inst->clk_data.dcvs_flags = 0; + } + + msm_vidc_update_freq_entry(inst, freq, device_addr, is_turbo); + + msm_vidc_set_clocks(inst->core); + + return 0; +} + +int msm_comm_scale_clocks_and_bus(struct msm_vidc_inst *inst) +{ + struct msm_vidc_core *core; + struct hfi_device *hdev; + + if (!inst || !inst->core || !inst->core->device) { + dprintk(VIDC_ERR, "%s Invalid params\n", __func__); + return -EINVAL; + } + core = inst->core; + hdev = core->device; + + if (msm_comm_scale_clocks(inst)) { + dprintk(VIDC_WARN, + "Failed to scale clocks. Performance might be impacted\n"); + } + if (msm_comm_vote_bus(core)) { + dprintk(VIDC_WARN, + "Failed to scale DDR bus. Performance might be impacted\n"); + } + return 0; +} + +int msm_dcvs_try_enable(struct msm_vidc_inst *inst) +{ + if (!inst || !inst->core) { + dprintk(VIDC_ERR, "%s: Invalid args: %p\n", __func__, inst); + return -EINVAL; + } + + if (msm_vidc_clock_voting || + !inst->core->resources.dcvs || + inst->flags & VIDC_THUMBNAIL || + inst->clk_data.low_latency_mode || + inst->batch.enable || + inst->grid_enable) { + dprintk(VIDC_PROF, "DCVS disabled: %pK\n", inst); + inst->clk_data.dcvs_mode = false; + return false; + } + inst->clk_data.dcvs_mode = true; + dprintk(VIDC_PROF, "DCVS enabled: %pK\n", inst); + + return true; +} + +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) { + dprintk(VIDC_ERR, "%s Invalid args: Inst = %pK\n", + __func__, inst); + return -EINVAL; + } + + if (inst->session_type == MSM_VIDC_CVP) { + dprintk(VIDC_DBG, "%s: cvp session\n", __func__); + return 0; + } + + count = inst->core->resources.codec_data_count; + fourcc = inst->session_type == MSM_VIDC_DECODER ? + inst->fmts[OUTPUT_PORT].fourcc : + inst->fmts[CAPTURE_PORT].fourcc; + + 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) { + dprintk(VIDC_ERR, "%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; + struct clock_data *dcvs; + struct hal_buffer_requirements *buf_req; + + dprintk(VIDC_DBG, "Init DCVS Load\n"); + + if (!inst || !inst->core || !inst->clk_data.entry) { + dprintk(VIDC_ERR, "%s Invalid args: Inst = %pK\n", + __func__, inst); + return; + } + + core = inst->core; + dcvs = &inst->clk_data; + load = msm_comm_get_inst_load_per_core(inst, LOAD_CALC_NO_QUIRKS); + cycles = inst->clk_data.entry->vpp_cycles; + allowed_clks_tbl = core->resources.allowed_clks_tbl; + if (inst->session_type == MSM_VIDC_ENCODER) { + cycles = inst->flags & VIDC_LOW_POWER ? + inst->clk_data.entry->low_power_cycles : + cycles; + + dcvs->buffer_type = HAL_BUFFER_INPUT; + dcvs->min_threshold = + msm_vidc_get_extra_buff_count(inst, HAL_BUFFER_INPUT); + buf_req = get_buff_req_buffer(inst, HAL_BUFFER_INPUT); + if (buf_req) + dcvs->max_threshold = + buf_req->buffer_count_actual - + buf_req->buffer_count_min_host + 2; + else + dprintk(VIDC_ERR, + "%s: No bufer req for buffer type %x\n", + __func__, HAL_BUFFER_INPUT); + + } else if (inst->session_type == MSM_VIDC_DECODER) { + dcvs->buffer_type = msm_comm_get_hal_output_buffer(inst); + buf_req = get_buff_req_buffer(inst, dcvs->buffer_type); + if (buf_req) + dcvs->max_threshold = + buf_req->buffer_count_actual - + buf_req->buffer_count_min_host + 2; + else + dprintk(VIDC_ERR, + "%s: No bufer req for buffer type %x\n", + __func__, dcvs->buffer_type); + + dcvs->min_threshold = + msm_vidc_get_extra_buff_count(inst, dcvs->buffer_type); + } else { + dprintk(VIDC_ERR, "%s: invalid session type %#x\n", + __func__, inst->session_type); + return; + } + + 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; + } + + dcvs->load = dcvs->load_norm = rate; + + dcvs->load_low = i < (core->resources.allowed_clks_tbl_size - 1) ? + allowed_clks_tbl[i+1].clock_rate : dcvs->load_norm; + dcvs->load_high = i > 0 ? allowed_clks_tbl[i-1].clock_rate : + dcvs->load_norm; + + inst->clk_data.buffer_counter = 0; + + msm_dcvs_print_dcvs_stats(dcvs); + + rc = msm_comm_scale_clocks_and_bus(inst); + + if (rc) + dprintk(VIDC_ERR, "%s Failed to scale Clocks and Bus\n", + __func__); +} + +static bool is_output_buffer(struct msm_vidc_inst *inst, + enum hal_buffer buffer_type) +{ + if (msm_comm_get_stream_output_mode(inst) == + HAL_VIDEO_DECODER_SECONDARY) { + return buffer_type == HAL_BUFFER_OUTPUT2; + } else { + return buffer_type == HAL_BUFFER_OUTPUT; + } +} + +int msm_vidc_get_extra_buff_count(struct msm_vidc_inst *inst, + enum hal_buffer buffer_type) +{ + int count = 0; + + if (!inst || !inst->core) { + dprintk(VIDC_ERR, "%s Invalid args\n", __func__); + return 0; + } + /* + * no extra buffers for thumbnail session because + * neither dcvs nor batching will be enabled + */ + if (is_thumbnail_session(inst)) + return 0; + + /* Add DCVS extra buffer count */ + if (inst->core->resources.dcvs) { + if (is_decode_session(inst) && + is_output_buffer(inst, buffer_type)) { + count += DCVS_DEC_EXTRA_OUTPUT_BUFFERS; + } else if ((is_encode_session(inst) && + buffer_type == HAL_BUFFER_INPUT)) { + count += DCVS_ENC_EXTRA_INPUT_BUFFERS; + } + } + + /* + * if platform supports decode batching ensure minimum + * batch size count of extra buffers added on output port + */ + if (is_output_buffer(inst, buffer_type)) { + if (is_batching_allowed(inst) && + count < inst->batch.size) + count = inst->batch.size; + } + + return count; +} + +int msm_vidc_decide_work_route(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct hal_video_work_route pdata; + + if (!inst || !inst->core || !inst->core->device) { + dprintk(VIDC_ERR, + "%s Invalid args: Inst = %pK\n", + __func__, inst); + return -EINVAL; + } + + hdev = inst->core->device; + + pdata.video_work_route = 2; + if (inst->session_type == MSM_VIDC_DECODER) { + switch (inst->fmts[OUTPUT_PORT].fourcc) { + 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 rc_mode = 0; + u32 output_width, output_height, fps, mbps; + + switch (inst->fmts[CAPTURE_PORT].fourcc) { + case V4L2_PIX_FMT_VP8: + case V4L2_PIX_FMT_TME: + pdata.video_work_route = 1; + goto decision_done; + } + + rc_mode = msm_comm_g_ctrl_for_id(inst, + V4L2_CID_MPEG_VIDEO_BITRATE_MODE); + if (rc_mode == + 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); + output_height = inst->prop.height[CAPTURE_PORT]; + output_width = inst->prop.width[CAPTURE_PORT]; + fps = inst->prop.fps; + mbps = NUM_MBS_PER_SEC(output_height, output_width, fps); + if (slice_mode == + V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES || + (rc_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR && + mbps <= CBR_MB_LIMIT) || + (rc_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR_VFR && + mbps <= CBR_VFR_MB_LIMIT)) { + pdata.video_work_route = 1; + dprintk(VIDC_DBG, "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, HAL_PARAM_VIDEO_WORK_ROUTE, + (void *)&pdata); + if (rc) + dprintk(VIDC_WARN, + " Failed to configure work route %pK\n", inst); + + return rc; +} + +static int msm_vidc_decide_work_mode_ar50(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct hal_video_work_mode pdata; + struct hal_enable latency; + + if (!inst || !inst->core || !inst->core->device) { + dprintk(VIDC_ERR, + "%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 = VIDC_WORK_MODE_1; + goto decision_done; + } + + if (inst->session_type == MSM_VIDC_DECODER) { + pdata.video_work_mode = VIDC_WORK_MODE_2; + switch (inst->fmts[OUTPUT_PORT].fourcc) { + case V4L2_PIX_FMT_MPEG2: + pdata.video_work_mode = VIDC_WORK_MODE_1; + break; + case V4L2_PIX_FMT_H264: + case V4L2_PIX_FMT_HEVC: + if (inst->prop.height[OUTPUT_PORT] * + inst->prop.width[OUTPUT_PORT] <= + 1280 * 720) + pdata.video_work_mode = VIDC_WORK_MODE_1; + break; + } + } else if (inst->session_type == MSM_VIDC_ENCODER) { + u32 rc_mode = 0; + + pdata.video_work_mode = VIDC_WORK_MODE_1; + rc_mode = msm_comm_g_ctrl_for_id(inst, + V4L2_CID_MPEG_VIDEO_BITRATE_MODE); + if (rc_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR || + rc_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_MBR || + rc_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_MBR_VFR) + pdata.video_work_mode = VIDC_WORK_MODE_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, HAL_PARAM_VIDEO_WORK_MODE, + (void *)&pdata); + if (rc) + dprintk(VIDC_WARN, + " Failed to configure Work Mode %pK\n", inst); + + /* For WORK_MODE_1, set Low Latency mode by default to HW. */ + + if (inst->session_type == MSM_VIDC_ENCODER && + inst->clk_data.work_mode == VIDC_WORK_MODE_1) { + latency.enable = 1; + rc = call_hfi_op(hdev, session_set_property, + (void *)inst->session, HAL_PARAM_VENC_LOW_LATENCY, + (void *)&latency); + } + + rc = msm_comm_scale_clocks_and_bus(inst); + + return rc; +} + +int msm_vidc_decide_work_mode(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_device *hdev; + struct hal_video_work_mode pdata; + struct hal_enable latency; + u32 yuv_size = 0; + + if (!inst || !inst->core || !inst->core->device) { + dprintk(VIDC_ERR, + "%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 = VIDC_WORK_MODE_1; + dprintk(VIDC_DBG, "Configured work mode = 1"); + goto decision_done; + } + + if (inst->session_type == MSM_VIDC_DECODER) { + pdata.video_work_mode = VIDC_WORK_MODE_2; + switch (inst->fmts[OUTPUT_PORT].fourcc) { + case V4L2_PIX_FMT_MPEG2: + pdata.video_work_mode = VIDC_WORK_MODE_1; + break; + case V4L2_PIX_FMT_H264: + case V4L2_PIX_FMT_HEVC: + case V4L2_PIX_FMT_VP8: + case V4L2_PIX_FMT_VP9: + yuv_size = inst->prop.height[OUTPUT_PORT] * + inst->prop.width[OUTPUT_PORT]; + if ((inst->pic_struct != + MSM_VIDC_PIC_STRUCT_PROGRESSIVE) || + (yuv_size <= 1280 * 720)) + pdata.video_work_mode = VIDC_WORK_MODE_1; + break; + } + } else if (inst->session_type == MSM_VIDC_ENCODER) { + u32 codec = inst->fmts[CAPTURE_PORT].fourcc; + + pdata.video_work_mode = VIDC_WORK_MODE_2; + + switch (codec) { + case V4L2_PIX_FMT_VP8: + case V4L2_PIX_FMT_TME: + pdata.video_work_mode = VIDC_WORK_MODE_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, HAL_PARAM_VIDEO_WORK_MODE, + (void *)&pdata); + if (rc) + dprintk(VIDC_WARN, + " Failed to configure Work Mode %pK\n", inst); + + /* For WORK_MODE_1, set Low Latency mode by default to HW. */ + + if (inst->session_type == MSM_VIDC_ENCODER && + inst->clk_data.work_mode == VIDC_WORK_MODE_1) { + latency.enable = 1; + rc = call_hfi_op(hdev, session_set_property, + (void *)inst->session, HAL_PARAM_VENC_LOW_LATENCY, + (void *)&latency); + } + + return rc; +} + +static inline int msm_vidc_power_save_mode_enable(struct msm_vidc_inst *inst, + bool enable) +{ + u32 rc = 0, mbs_per_frame, mbs_per_sec; + u32 prop_id = 0; + void *pdata = NULL; + struct hfi_device *hdev = NULL; + enum hal_perf_mode venc_mode; + u32 rc_mode = 0; + u32 hq_mbs_per_sec = 0; + struct msm_vidc_core *core; + struct msm_vidc_inst *instance = NULL; + int complexity; + + core = inst->core; + hdev = inst->core->device; + if (inst->session_type != MSM_VIDC_ENCODER) { + dprintk(VIDC_DBG, + "%s : Not an encoder session. Nothing to do\n", + __func__); + return 0; + } + mbs_per_frame = msm_vidc_get_mbs_per_frame(inst); + mbs_per_sec = mbs_per_frame * msm_vidc_get_fps(inst); + + if (mbs_per_frame > inst->core->resources.max_hq_mbs_per_frame || + mbs_per_sec > inst->core->resources.max_hq_mbs_per_sec) { + enable = true; + } + if (!enable) { + mutex_lock(&core->lock); + list_for_each_entry(instance, &core->instances, list) { + if (instance->clk_data.core_id && + !(instance->flags & VIDC_LOW_POWER)) + hq_mbs_per_sec += + msm_comm_get_inst_load_per_core( + instance, LOAD_CALC_NO_QUIRKS); + } + mutex_unlock(&core->lock); + if (hq_mbs_per_sec > inst->core->resources.max_hq_mbs_per_sec) + enable = true; + } + /* Power saving always disabled for CQ RC mode. */ + rc_mode = msm_comm_g_ctrl_for_id(inst, + V4L2_CID_MPEG_VIDEO_BITRATE_MODE); + if (rc_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CQ) + enable = false; + + complexity = msm_comm_g_ctrl_for_id(inst, + V4L2_CID_MPEG_VIDC_VENC_COMPLEXITY); + if (!is_realtime_session(inst) && !complexity) + enable = true; + prop_id = HAL_CONFIG_VENC_PERF_MODE; + venc_mode = enable ? HAL_PERF_MODE_POWER_SAVE : + HAL_PERF_MODE_POWER_MAX_QUALITY; + pdata = &venc_mode; + rc = call_hfi_op(hdev, session_set_property, + (void *)inst->session, prop_id, pdata); + if (rc) { + dprintk(VIDC_ERR, + "%s: Failed to set power save mode for inst: %pK\n", + __func__, inst); + goto fail_power_mode_set; + } + inst->flags = enable ? + inst->flags | VIDC_LOW_POWER : + inst->flags & ~VIDC_LOW_POWER; + + dprintk(VIDC_PROF, + "Power Save Mode for inst: %pK Enable = %d\n", inst, enable); +fail_power_mode_set: + return rc; +} + +static int msm_vidc_move_core_to_power_save_mode(struct msm_vidc_core *core, + u32 core_id) +{ + struct msm_vidc_inst *inst = NULL; + + dprintk(VIDC_PROF, "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 = inst->flags & VIDC_REALTIME ? true : false; + 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; + 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_CALC_NO_QUIRKS); + 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(struct msm_vidc_inst *inst) +{ + int rc = 0, hier_mode = 0; + struct hfi_device *hdev; + struct msm_vidc_core *core; + unsigned long max_freq, lp_cycles = 0; + struct hal_videocores_usage_info core_info; + u32 core0_load = 0, core1_load = 0, core0_lp_load = 0, + core1_lp_load = 0; + u32 current_inst_load = 0, current_inst_lp_load = 0, + min_load = 0, min_lp_load = 0; + u32 min_core_id, min_lp_core_id; + u32 complexity; + + if (!inst || !inst->core || !inst->core->device) { + dprintk(VIDC_ERR, + "%s Invalid args: Inst = %pK\n", + __func__, inst); + return -EINVAL; + } + + core = inst->core; + hdev = core->device; + max_freq = msm_vidc_max_freq(inst->core); + inst->clk_data.core_id = 0; + + core0_load = get_core_load(core, VIDC_CORE_ID_1, false, true); + core1_load = get_core_load(core, VIDC_CORE_ID_2, false, true); + core0_lp_load = get_core_load(core, VIDC_CORE_ID_1, true, true); + core1_lp_load = get_core_load(core, VIDC_CORE_ID_2, true, true); + + min_load = min(core0_load, core1_load); + min_core_id = core0_load < core1_load ? + VIDC_CORE_ID_1 : VIDC_CORE_ID_2; + min_lp_load = min(core0_lp_load, core1_lp_load); + min_lp_core_id = core0_lp_load < core1_lp_load ? + VIDC_CORE_ID_1 : VIDC_CORE_ID_2; + + lp_cycles = inst->session_type == MSM_VIDC_ENCODER ? + inst->clk_data.entry->low_power_cycles : + inst->clk_data.entry->vpp_cycles; + /* + * Incase there is only 1 core enabled, mark it as the core + * with min load. This ensures that this core is selected and + * video session is set to run on the enabled core. + */ + if (inst->capability.max_video_cores.max <= VIDC_CORE_ID_1) { + min_core_id = min_lp_core_id = VIDC_CORE_ID_1; + min_load = core0_load; + min_lp_load = core0_lp_load; + } + + current_inst_load = (msm_comm_get_inst_load(inst, LOAD_CALC_NO_QUIRKS) * + inst->clk_data.entry->vpp_cycles)/inst->clk_data.work_route; + + current_inst_lp_load = (msm_comm_get_inst_load(inst, + LOAD_CALC_NO_QUIRKS) * lp_cycles)/inst->clk_data.work_route; + + dprintk(VIDC_DBG, "Core 0 RT Load = %d Core 1 RT Load = %d\n", + core0_load, core1_load); + dprintk(VIDC_DBG, "Core 0 RT LP Load = %d Core 1 RT LP Load = %d\n", + core0_lp_load, core1_lp_load); + dprintk(VIDC_DBG, "Max Load = %lu\n", max_freq); + dprintk(VIDC_DBG, "Current Load = %d Current LP Load = %d\n", + current_inst_load, current_inst_lp_load); + + /* Hier mode can be normal HP or Hybrid HP. */ + + hier_mode = msm_comm_g_ctrl_for_id(inst, + V4L2_CID_MPEG_VIDC_VIDEO_HIER_P_NUM_LAYERS); + hier_mode |= msm_comm_g_ctrl_for_id(inst, + V4L2_CID_MPEG_VIDC_VIDEO_HYBRID_HIERP_MODE); + + /* Try for preferred core based on settings. */ + if (inst->session_type == MSM_VIDC_ENCODER && hier_mode && + inst->capability.max_video_cores.max >= VIDC_CORE_ID_3) { + if (current_inst_load / 2 + core0_load <= max_freq && + current_inst_load / 2 + core1_load <= max_freq) { + if (inst->clk_data.work_mode == VIDC_WORK_MODE_2) { + inst->clk_data.core_id = VIDC_CORE_ID_3; + msm_vidc_power_save_mode_enable(inst, false); + goto decision_done; + } + } + } + + if (inst->session_type == MSM_VIDC_ENCODER && hier_mode && + inst->capability.max_video_cores.max >= VIDC_CORE_ID_3) { + if (current_inst_lp_load / 2 + + core0_lp_load <= max_freq && + current_inst_lp_load / 2 + + core1_lp_load <= max_freq) { + if (inst->clk_data.work_mode == VIDC_WORK_MODE_2) { + inst->clk_data.core_id = VIDC_CORE_ID_3; + msm_vidc_power_save_mode_enable(inst, true); + goto decision_done; + } + } + } + + if (current_inst_load + min_load < max_freq) { + inst->clk_data.core_id = min_core_id; + dprintk(VIDC_DBG, + "Selected normally : Core ID = %d\n", + inst->clk_data.core_id); + msm_vidc_power_save_mode_enable(inst, false); + } else if (current_inst_lp_load + min_load < max_freq) { + /* Move current instance to LP and return */ + inst->clk_data.core_id = min_core_id; + dprintk(VIDC_DBG, + "Selected by moving current to LP : Core ID = %d\n", + inst->clk_data.core_id); + msm_vidc_power_save_mode_enable(inst, true); + + } else if (current_inst_lp_load + min_lp_load < max_freq) { + /* Move all instances to LP mode and return */ + inst->clk_data.core_id = min_lp_core_id; + dprintk(VIDC_DBG, + "Moved all inst's to LP: Core ID = %d\n", + inst->clk_data.core_id); + msm_vidc_move_core_to_power_save_mode(core, min_lp_core_id); + } else { + complexity = msm_comm_g_ctrl_for_id(inst, + V4L2_CID_MPEG_VIDC_VENC_COMPLEXITY); + if (!is_realtime_session(inst)) { + if (inst->session_type == MSM_VIDC_ENCODER) + msm_vidc_power_save_mode_enable(inst, + (complexity == 0)); + inst->clk_data.core_id = min_core_id; + dprintk(VIDC_DBG, "Supporting NRT session"); + goto decision_done; + + } else { + rc = -EINVAL; + dprintk(VIDC_ERR, + "Sorry ... Core Can't support this load\n"); + } + return rc; + } + +decision_done: + core_info.video_core_enable_mask = inst->clk_data.core_id; + dprintk(VIDC_DBG, + "Core Enable Mask %d\n", core_info.video_core_enable_mask); + + rc = call_hfi_op(hdev, session_set_property, + (void *)inst->session, + HAL_PARAM_VIDEO_CORES_USAGE, &core_info); + if (rc) + dprintk(VIDC_WARN, + " Failed to configure CORE ID %pK\n", inst); + + rc = msm_comm_scale_clocks_and_bus(inst); + + msm_print_core_status(core, VIDC_CORE_ID_1); + msm_print_core_status(core, VIDC_CORE_ID_2); + + return rc; +} + +void msm_vidc_init_core_clk_ops(struct msm_vidc_core *core) +{ + if (!core) + return; + + if (core->platform_data->vpu_ver == VPU_VERSION_4) + core->core_ops = &core_ops_vpu4; + else + core->core_ops = &core_ops_vpu5; +} + +void msm_print_core_status(struct msm_vidc_core *core, u32 core_id) +{ + struct msm_vidc_inst *inst = NULL; + + dprintk(VIDC_PROF, "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; + + dprintk(VIDC_PROF, + "inst %pK (%4ux%4u) to (%4ux%4u) %3u %s %s %s %s %lu\n", + inst, + inst->prop.width[OUTPUT_PORT], + inst->prop.height[OUTPUT_PORT], + inst->prop.width[CAPTURE_PORT], + inst->prop.height[CAPTURE_PORT], + inst->prop.fps, + inst->session_type == MSM_VIDC_ENCODER ? "ENC" : "DEC", + inst->clk_data.work_mode == VIDC_WORK_MODE_1 ? + "WORK_MODE_1" : "WORK_MODE_2", + inst->flags & VIDC_LOW_POWER ? "LP" : "HQ", + inst->flags & VIDC_REALTIME ? "RealTime" : "NonRTime", + inst->clk_data.min_freq); + } + mutex_unlock(&core->lock); +} diff --git a/drivers/media/platform/msm/vidc/msm_vidc_clocks.h b/drivers/media/platform/msm/vidc/msm_vidc_clocks.h new file mode 100644 index 000000000000..c25bf8103765 --- /dev/null +++ b/drivers/media/platform/msm/vidc/msm_vidc_clocks.h @@ -0,0 +1,48 @@ +/* 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. + * + */ + +#ifndef _MSM_VIDC_CLOCKS_H_ +#define _MSM_VIDC_CLOCKS_H_ +#include "msm_vidc_internal.h" + +/* extra o/p buffers in case of encoder dcvs */ +#define DCVS_ENC_EXTRA_INPUT_BUFFERS 4 + +/* extra o/p buffers in case of decoder dcvs */ +#define DCVS_DEC_EXTRA_OUTPUT_BUFFERS 4 + +void msm_clock_data_reset(struct msm_vidc_inst *inst); +int msm_vidc_validate_operating_rate(struct msm_vidc_inst *inst, + u32 operating_rate); +int msm_vidc_get_extra_buff_count(struct msm_vidc_inst *inst, + enum hal_buffer buffer_type); +int msm_vidc_set_clocks(struct msm_vidc_core *core); +int msm_comm_vote_bus(struct msm_vidc_core *core); +int msm_dcvs_try_enable(struct msm_vidc_inst *inst); +int msm_vidc_get_mbs_per_frame(struct msm_vidc_inst *inst); +int msm_comm_scale_clocks_and_bus(struct msm_vidc_inst *inst); +int msm_comm_init_clocks_and_bus_data(struct msm_vidc_inst *inst); +void msm_comm_free_freq_table(struct msm_vidc_inst *inst); +int msm_vidc_decide_work_route(struct msm_vidc_inst *inst); +int msm_vidc_decide_work_mode(struct msm_vidc_inst *inst); +int msm_vidc_decide_core_and_power_mode(struct msm_vidc_inst *inst); +void msm_print_core_status(struct msm_vidc_core *core, u32 core_id); +void msm_vidc_clear_freq_entry(struct msm_vidc_inst *inst, + u32 device_addr); +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); +#endif diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c new file mode 100644 index 000000000000..bde2bdd84147 --- /dev/null +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c @@ -0,0 +1,7261 @@ +/* Copyright (c) 2012-2020, 2021 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 "msm_vidc_common.h" +#include "vidc_hfi_api.h" +#include "msm_vidc_debug.h" +#include "msm_vidc_clocks.h" +#include "msm_cvp.h" + +#define MSM_VIDC_QBUF_BATCH_TIMEOUT 300 +#define IS_ALREADY_IN_STATE(__p, __d) (\ + (__p >= __d)\ +) + +#define V4L2_EVENT_SEQ_CHANGED_SUFFICIENT \ + V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_SUFFICIENT +#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 +#define L_MODE V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY + +const char *const mpeg_video_vidc_extradata[] = { + "Extradata none", + "Extradata MB Quantization", + "Extradata Interlace Video", + "Extradata enc DTS", + "Reserved", + "Extradata timestamp", + "Extradata S3D Frame Packing", + "Extradata Frame Rate", + "Extradata Panscan Window", + "Extradata Recovery point SEI", + "Extradata Multislice info", + "Extradata number of concealed MB", + "Extradata metadata filler", + "Extradata input crop", + "Extradata digital zoom", + "Extradata aspect ratio", + "Extradata mpeg2 seqdisp", + "Extradata stream userdata", + "Extradata frame QP", + "Extradata frame bits info", + "Extradata LTR", + "Extradata macroblock metadata", + "Extradata VQZip SEI", + "Extradata HDR10+ Metadata", + "Extradata ROI QP", + "Extradata output crop", + "Extradata display colour SEI", + "Extradata light level SEI", + "Extradata PQ Info", + "Extradata display VUI", + "Extradata vpx color space", + "Extradata UBWC CR stats info", + "Extradata enc frame QP", +}; + +static void handle_session_error(enum hal_command_response cmd, void *data); +static void msm_vidc_print_running_insts(struct msm_vidc_core *core); + +int msm_comm_g_ctrl_for_id(struct msm_vidc_inst *inst, int id) +{ + int rc = 0; + struct v4l2_control ctrl = { + .id = id, + }; + + rc = msm_comm_g_ctrl(inst, &ctrl); + return rc ? rc : ctrl.value; +} + +static struct v4l2_ctrl **get_super_cluster(struct msm_vidc_inst *inst, + int num_ctrls) +{ + int c = 0; + struct v4l2_ctrl **cluster = kmalloc(sizeof(struct v4l2_ctrl *) * + num_ctrls, GFP_KERNEL); + + if (!cluster || !inst) { + kfree(cluster); + return NULL; + } + + for (c = 0; c < num_ctrls; c++) + cluster[c] = inst->ctrls[c]; + + return cluster; +} + +int msm_comm_hal_to_v4l2(int id, int value) +{ + switch (id) { + /* H264 */ + case V4L2_CID_MPEG_VIDEO_H264_PROFILE: + switch (value) { + case HAL_H264_PROFILE_BASELINE: + return V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE; + case HAL_H264_PROFILE_CONSTRAINED_BASE: + return + V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE; + case HAL_H264_PROFILE_MAIN: + return V4L2_MPEG_VIDEO_H264_PROFILE_MAIN; + case HAL_H264_PROFILE_HIGH: + return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH; + case HAL_H264_PROFILE_STEREO_HIGH: + return V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH; + case HAL_H264_PROFILE_MULTIVIEW_HIGH: + return V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH; + case HAL_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 HAL_H264_LEVEL_1: + return V4L2_MPEG_VIDEO_H264_LEVEL_1_0; + case HAL_H264_LEVEL_1b: + return V4L2_MPEG_VIDEO_H264_LEVEL_1B; + case HAL_H264_LEVEL_11: + return V4L2_MPEG_VIDEO_H264_LEVEL_1_1; + case HAL_H264_LEVEL_12: + return V4L2_MPEG_VIDEO_H264_LEVEL_1_2; + case HAL_H264_LEVEL_13: + return V4L2_MPEG_VIDEO_H264_LEVEL_1_3; + case HAL_H264_LEVEL_2: + return V4L2_MPEG_VIDEO_H264_LEVEL_2_0; + case HAL_H264_LEVEL_21: + return V4L2_MPEG_VIDEO_H264_LEVEL_2_1; + case HAL_H264_LEVEL_22: + return V4L2_MPEG_VIDEO_H264_LEVEL_2_2; + case HAL_H264_LEVEL_3: + return V4L2_MPEG_VIDEO_H264_LEVEL_3_0; + case HAL_H264_LEVEL_31: + return V4L2_MPEG_VIDEO_H264_LEVEL_3_1; + case HAL_H264_LEVEL_32: + return V4L2_MPEG_VIDEO_H264_LEVEL_3_2; + case HAL_H264_LEVEL_4: + return V4L2_MPEG_VIDEO_H264_LEVEL_4_0; + case HAL_H264_LEVEL_41: + return V4L2_MPEG_VIDEO_H264_LEVEL_4_1; + case HAL_H264_LEVEL_42: + return V4L2_MPEG_VIDEO_H264_LEVEL_4_2; + case HAL_H264_LEVEL_5: + return V4L2_MPEG_VIDEO_H264_LEVEL_5_0; + case HAL_H264_LEVEL_51: + return V4L2_MPEG_VIDEO_H264_LEVEL_5_1; + case HAL_H264_LEVEL_52: + return V4L2_MPEG_VIDEO_H264_LEVEL_5_2; + case HAL_H264_LEVEL_6: + return V4L2_MPEG_VIDEO_H264_LEVEL_6_0; + case HAL_H264_LEVEL_61: + return V4L2_MPEG_VIDEO_H264_LEVEL_6_1; + case HAL_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 HAL_H264_ENTROPY_CAVLC: + return V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC; + case HAL_H264_ENTROPY_CABAC: + return V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC; + default: + goto unknown_value; + } + case V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE: + switch (value) { + case HAL_HEVC_PROFILE_MAIN: + return V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN; + case HAL_HEVC_PROFILE_MAIN10: + return V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN10; + case HAL_HEVC_PROFILE_MAIN_STILL_PIC: + return V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN_STILL_PIC; + default: + goto unknown_value; + } + case V4L2_CID_MPEG_VIDC_VIDEO_HEVC_TIER_LEVEL: + switch (value) { + case HAL_HEVC_MAIN_TIER_LEVEL_1: + return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_1; + case HAL_HEVC_MAIN_TIER_LEVEL_2: + return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_2; + case HAL_HEVC_MAIN_TIER_LEVEL_2_1: + return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_2_1; + case HAL_HEVC_MAIN_TIER_LEVEL_3: + return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_3; + case HAL_HEVC_MAIN_TIER_LEVEL_3_1: + return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_3_1; + case HAL_HEVC_MAIN_TIER_LEVEL_4: + return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_4; + case HAL_HEVC_MAIN_TIER_LEVEL_4_1: + return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_4_1; + case HAL_HEVC_MAIN_TIER_LEVEL_5: + return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_5; + case HAL_HEVC_MAIN_TIER_LEVEL_5_1: + return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_5_1; + case HAL_HEVC_MAIN_TIER_LEVEL_5_2: + return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_5_2; + case HAL_HEVC_MAIN_TIER_LEVEL_6: + return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_6; + case HAL_HEVC_MAIN_TIER_LEVEL_6_1: + return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_6_1; + case HAL_HEVC_MAIN_TIER_LEVEL_6_2: + return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_6_2; + case HAL_HEVC_HIGH_TIER_LEVEL_1: + return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_1; + case HAL_HEVC_HIGH_TIER_LEVEL_2: + return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_2; + case HAL_HEVC_HIGH_TIER_LEVEL_2_1: + return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_2_1; + case HAL_HEVC_HIGH_TIER_LEVEL_3: + return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_3; + case HAL_HEVC_HIGH_TIER_LEVEL_3_1: + return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_3_1; + case HAL_HEVC_HIGH_TIER_LEVEL_4: + return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_4; + case HAL_HEVC_HIGH_TIER_LEVEL_4_1: + return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_4_1; + case HAL_HEVC_HIGH_TIER_LEVEL_5: + return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5; + case HAL_HEVC_HIGH_TIER_LEVEL_5_1: + return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5_1; + case HAL_HEVC_HIGH_TIER_LEVEL_5_2: + return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5_2; + case HAL_HEVC_HIGH_TIER_LEVEL_6: + return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_6; + case HAL_HEVC_HIGH_TIER_LEVEL_6_1: + return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_6_1; + case HAL_HEVC_HIGH_TIER_LEVEL_6_2: + return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_6_2; + case HAL_HEVC_TIER_LEVEL_UNKNOWN: + return V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_UNKNOWN; + default: + goto unknown_value; + } + case V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL: + switch (value) { + case HAL_VP8_LEVEL_VERSION_0: + return V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_0; + case HAL_VP8_LEVEL_VERSION_1: + return V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_1; + case HAL_VP8_LEVEL_VERSION_2: + return V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_2; + case HAL_VP8_LEVEL_VERSION_3: + return V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_3; + case HAL_VP8_LEVEL_UNUSED: + return V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED; + default: + goto unknown_value; + } + case V4L2_CID_MPEG_VIDC_VIDEO_VP9_PROFILE: + switch (value) { + case HAL_VP9_PROFILE_P0: + return V4L2_MPEG_VIDC_VIDEO_VP9_PROFILE_P0; + case HAL_VP9_PROFILE_P2_10: + return V4L2_MPEG_VIDC_VIDEO_VP9_PROFILE_P2_10; + case HAL_VP9_PROFILE_UNUSED: + return V4L2_MPEG_VIDC_VIDEO_VP9_PROFILE_UNUSED; + default: + goto unknown_value; + } + case V4L2_CID_MPEG_VIDC_VIDEO_VP9_LEVEL: + switch (value) { + case HAL_VP9_LEVEL_1: + return V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_1; + case HAL_VP9_LEVEL_11: + return V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_11; + case HAL_VP9_LEVEL_2: + return V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_2; + case HAL_VP9_LEVEL_21: + return V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_21; + case HAL_VP9_LEVEL_3: + return V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_3; + case HAL_VP9_LEVEL_31: + return V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_31; + case HAL_VP9_LEVEL_4: + return V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_4; + case HAL_VP9_LEVEL_41: + return V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_41; + case HAL_VP9_LEVEL_5: + return V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_5; + case HAL_VP9_LEVEL_51: + return V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_51; + case HAL_VP9_LEVEL_6: + return V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_6; + case HAL_VP9_LEVEL_61: + return V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_61; + case HAL_VP9_LEVEL_UNUSED: + return V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_UNUSED; + default: + goto unknown_value; + } + case V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_PROFILE: + switch (value) { + case HAL_MPEG2_PROFILE_SIMPLE: + return V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_SIMPLE; + case HAL_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 HAL_MPEG2_LEVEL_LL: + return V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_0; + case HAL_MPEG2_LEVEL_ML: + return V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_1; + case HAL_MPEG2_LEVEL_HL: + return V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_2; + default: + goto unknown_value; + } + } + +unknown_value: + dprintk(VIDC_WARN, "Unknown control (%x, %d)\n", id, value); + return -EINVAL; +} + +int msm_comm_v4l2_to_hal(int id, int value) +{ + switch (id) { + /* H264 */ + case V4L2_CID_MPEG_VIDEO_H264_PROFILE: + switch (value) { + case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE: + return HAL_H264_PROFILE_BASELINE; + case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE: + return HAL_H264_PROFILE_CONSTRAINED_BASE; + case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN: + return HAL_H264_PROFILE_MAIN; + case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH: + return HAL_H264_PROFILE_HIGH; + case V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH: + return HAL_H264_PROFILE_STEREO_HIGH; + case V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH: + return HAL_H264_PROFILE_MULTIVIEW_HIGH; + case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH: + return HAL_H264_PROFILE_CONSTRAINED_HIGH; + default: + goto unknown_value; + } + case V4L2_CID_MPEG_VIDEO_H264_LEVEL: + switch (value) { + case V4L2_MPEG_VIDEO_H264_LEVEL_1_0: + return HAL_H264_LEVEL_1; + case V4L2_MPEG_VIDEO_H264_LEVEL_1B: + return HAL_H264_LEVEL_1b; + case V4L2_MPEG_VIDEO_H264_LEVEL_1_1: + return HAL_H264_LEVEL_11; + case V4L2_MPEG_VIDEO_H264_LEVEL_1_2: + return HAL_H264_LEVEL_12; + case V4L2_MPEG_VIDEO_H264_LEVEL_1_3: + return HAL_H264_LEVEL_13; + case V4L2_MPEG_VIDEO_H264_LEVEL_2_0: + return HAL_H264_LEVEL_2; + case V4L2_MPEG_VIDEO_H264_LEVEL_2_1: + return HAL_H264_LEVEL_21; + case V4L2_MPEG_VIDEO_H264_LEVEL_2_2: + return HAL_H264_LEVEL_22; + case V4L2_MPEG_VIDEO_H264_LEVEL_3_0: + return HAL_H264_LEVEL_3; + case V4L2_MPEG_VIDEO_H264_LEVEL_3_1: + return HAL_H264_LEVEL_31; + case V4L2_MPEG_VIDEO_H264_LEVEL_3_2: + return HAL_H264_LEVEL_32; + case V4L2_MPEG_VIDEO_H264_LEVEL_4_0: + return HAL_H264_LEVEL_4; + case V4L2_MPEG_VIDEO_H264_LEVEL_4_1: + return HAL_H264_LEVEL_41; + case V4L2_MPEG_VIDEO_H264_LEVEL_4_2: + return HAL_H264_LEVEL_42; + case V4L2_MPEG_VIDEO_H264_LEVEL_5_0: + return HAL_H264_LEVEL_5; + case V4L2_MPEG_VIDEO_H264_LEVEL_5_1: + return HAL_H264_LEVEL_51; + case V4L2_MPEG_VIDEO_H264_LEVEL_5_2: + return HAL_H264_LEVEL_52; + case V4L2_MPEG_VIDEO_H264_LEVEL_6_0: + return HAL_H264_LEVEL_6; + case V4L2_MPEG_VIDEO_H264_LEVEL_6_1: + return HAL_H264_LEVEL_61; + case V4L2_MPEG_VIDEO_H264_LEVEL_6_2: + return HAL_H264_LEVEL_62; + case V4L2_MPEG_VIDEO_H264_LEVEL_UNKNOWN: + return HAL_H264_LEVEL_UNKNOWN; + default: + goto unknown_value; + } + case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE: + switch (value) { + case V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC: + return HAL_H264_ENTROPY_CAVLC; + case V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC: + return HAL_H264_ENTROPY_CABAC; + default: + goto unknown_value; + } + case V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL: + switch (value) { + case V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_0: + return HAL_VP8_LEVEL_VERSION_0; + case V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_1: + return HAL_VP8_LEVEL_VERSION_1; + case V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_2: + return HAL_VP8_LEVEL_VERSION_2; + case V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_3: + return HAL_VP8_LEVEL_VERSION_3; + case V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED: + return HAL_VP8_LEVEL_UNUSED; + default: + goto unknown_value; + } + case V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE: + switch (value) { + case V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN: + return HAL_HEVC_PROFILE_MAIN; + case V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN10: + return HAL_HEVC_PROFILE_MAIN10; + case V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN_STILL_PIC: + return HAL_HEVC_PROFILE_MAIN_STILL_PIC; + default: + goto unknown_value; + } + case V4L2_CID_MPEG_VIDC_VIDEO_HEVC_TIER_LEVEL: + switch (value) { + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_1: + return HAL_HEVC_MAIN_TIER_LEVEL_1; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_2: + return HAL_HEVC_MAIN_TIER_LEVEL_2; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_2_1: + return HAL_HEVC_MAIN_TIER_LEVEL_2_1; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_3: + return HAL_HEVC_MAIN_TIER_LEVEL_3; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_3_1: + return HAL_HEVC_MAIN_TIER_LEVEL_3_1; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_4: + return HAL_HEVC_MAIN_TIER_LEVEL_4; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_4_1: + return HAL_HEVC_MAIN_TIER_LEVEL_4_1; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_5: + return HAL_HEVC_MAIN_TIER_LEVEL_5; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_5_1: + return HAL_HEVC_MAIN_TIER_LEVEL_5_1; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_5_2: + return HAL_HEVC_MAIN_TIER_LEVEL_5_2; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_6: + return HAL_HEVC_MAIN_TIER_LEVEL_6; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_6_1: + return HAL_HEVC_MAIN_TIER_LEVEL_6_1; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_6_2: + return HAL_HEVC_MAIN_TIER_LEVEL_6_2; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_1: + return HAL_HEVC_HIGH_TIER_LEVEL_1; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_2: + return HAL_HEVC_HIGH_TIER_LEVEL_2; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_2_1: + return HAL_HEVC_HIGH_TIER_LEVEL_2_1; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_3: + return HAL_HEVC_HIGH_TIER_LEVEL_3; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_3_1: + return HAL_HEVC_HIGH_TIER_LEVEL_3_1; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_4: + return HAL_HEVC_HIGH_TIER_LEVEL_4; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_4_1: + return HAL_HEVC_HIGH_TIER_LEVEL_4_1; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5: + return HAL_HEVC_HIGH_TIER_LEVEL_5; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5_1: + return HAL_HEVC_HIGH_TIER_LEVEL_5_1; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5_2: + return HAL_HEVC_HIGH_TIER_LEVEL_5_2; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_6: + return HAL_HEVC_HIGH_TIER_LEVEL_6; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_6_1: + return HAL_HEVC_HIGH_TIER_LEVEL_6_1; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_6_2: + return HAL_HEVC_HIGH_TIER_LEVEL_6_2; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_UNKNOWN: + return HAL_HEVC_TIER_LEVEL_UNKNOWN; + default: + goto unknown_value; + } + case V4L2_CID_MPEG_VIDC_VIDEO_TME_PROFILE: + switch (value) { + case V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_0: + return HAL_TME_PROFILE_0; + case V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_1: + return HAL_TME_PROFILE_1; + case V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_2: + return HAL_TME_PROFILE_2; + case V4L2_MPEG_VIDC_VIDEO_TME_PROFILE_3: + return HAL_TME_PROFILE_3; + default: + goto unknown_value; + } + case V4L2_CID_MPEG_VIDC_VIDEO_TME_LEVEL: + switch (value) { + case V4L2_MPEG_VIDC_VIDEO_TME_LEVEL_INTEGER: + return HAL_TME_LEVEL_INTEGER; + default: + goto unknown_value; + } + case V4L2_CID_MPEG_VIDC_VIDEO_FLIP: + switch (value) { + case V4L2_CID_MPEG_VIDC_VIDEO_FLIP_NONE: + return HAL_FLIP_NONE; + case V4L2_CID_MPEG_VIDC_VIDEO_FLIP_HORI: + return HAL_FLIP_HORIZONTAL; + case V4L2_CID_MPEG_VIDC_VIDEO_FLIP_VERT: + return HAL_FLIP_VERTICAL; + case V4L2_CID_MPEG_VIDC_VIDEO_FLIP_BOTH: + return HAL_FLIP_BOTH; + default: + goto unknown_value; + } + case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE: + switch (value) { + case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED: + return HAL_H264_DB_MODE_DISABLE; + case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED: + return HAL_H264_DB_MODE_ALL_BOUNDARY; + case L_MODE: + return HAL_H264_DB_MODE_SKIP_SLICE_BOUNDARY; + default: + goto unknown_value; + } + case V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_SIZE_TYPE: + switch (value) { + case V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_SIZE_DEFAULT: + return HAL_IFRAMESIZE_TYPE_DEFAULT; + case V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_SIZE_MEDIUM: + return HAL_IFRAMESIZE_TYPE_MEDIUM; + case V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_SIZE_HUGE: + return HAL_IFRAMESIZE_TYPE_HUGE; + case V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_SIZE_UNLIMITED: + return HAL_IFRAMESIZE_TYPE_UNLIMITED; + default: + goto unknown_value; + } + } + +unknown_value: + dprintk(VIDC_WARN, "Unknown control (%x, %d)\n", id, value); + return -EINVAL; +} + +int msm_comm_get_v4l2_profile(int fourcc, int profile) +{ + switch (fourcc) { + case V4L2_PIX_FMT_H264: + return msm_comm_hal_to_v4l2( + V4L2_CID_MPEG_VIDEO_H264_PROFILE, + profile); + case V4L2_PIX_FMT_HEVC: + return msm_comm_hal_to_v4l2( + V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE, + profile); + case V4L2_PIX_FMT_VP8: + case V4L2_PIX_FMT_VP9: + case V4L2_PIX_FMT_MPEG2: + return 0; + default: + dprintk(VIDC_WARN, "Unknown codec id %x\n", fourcc); + return 0; + } +} + +int msm_comm_get_v4l2_level(int fourcc, int level) +{ + switch (fourcc) { + case V4L2_PIX_FMT_H264: + return msm_comm_hal_to_v4l2( + V4L2_CID_MPEG_VIDEO_H264_LEVEL, + level); + case V4L2_PIX_FMT_HEVC: + return msm_comm_hal_to_v4l2( + V4L2_CID_MPEG_VIDC_VIDEO_HEVC_TIER_LEVEL, + level); + case V4L2_PIX_FMT_VP8: + return msm_comm_hal_to_v4l2( + V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL, + level); + case V4L2_PIX_FMT_VP9: + case V4L2_PIX_FMT_MPEG2: + return 0; + default: + dprintk(VIDC_WARN, "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) { + dprintk(VIDC_ERR, "%s - invalid input\n", __func__); + return -EINVAL; + } + + inst->ctrls = kcalloc(num_ctrls, sizeof(struct v4l2_ctrl *), + GFP_KERNEL); + if (!inst->ctrls) { + dprintk(VIDC_ERR, "%s - failed to allocate ctrl\n", __func__); + return -ENOMEM; + } + + ret_val = v4l2_ctrl_handler_init(&inst->ctrl_handler, num_ctrls); + + if (ret_val) { + dprintk(VIDC_ERR, "CTRL ERR: Control handler init failed, %d\n", + inst->ctrl_handler.error); + return ret_val; + } + + for (; idx < 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, + drv_ctrls[idx].maximum, + drv_ctrls[idx].menu_skip_mask, + 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) { + dprintk(VIDC_ERR, "%s - invalid ctrl %s\n", __func__, + drv_ctrls[idx].name); + return -EINVAL; + } + + ret_val = inst->ctrl_handler.error; + if (ret_val) { + dprintk(VIDC_ERR, + "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; + inst->ctrls[idx] = ctrl; + } + + /* Construct a super cluster of all controls */ + inst->cluster = get_super_cluster(inst, num_ctrls); + if (!inst->cluster) { + dprintk(VIDC_WARN, + "Failed to setup super cluster\n"); + return -EINVAL; + } + + v4l2_ctrl_cluster(num_ctrls, inst->cluster); + + return ret_val; +} + +int msm_comm_ctrl_deinit(struct msm_vidc_inst *inst) +{ + if (!inst) { + dprintk(VIDC_ERR, "%s invalid parameters\n", __func__); + return -EINVAL; + } + + kfree(inst->ctrls); + kfree(inst->cluster); + 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) { + dprintk(VIDC_ERR, "%s: invalid params\n", __func__); + return -EINVAL; + } + + if (!is_decode_session(inst)) { + dprintk(VIDC_DBG, "%s: not a decode session %x\n", + __func__, hash32_ptr(inst->session)); + 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) { + dprintk(VIDC_ERR, "%s: invalid params, return default mode\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; +} + +static int msm_comm_get_mbs_per_sec(struct msm_vidc_inst *inst) +{ + int output_port_mbs, capture_port_mbs; + int fps; + + output_port_mbs = inst->in_reconfig ? + NUM_MBS_PER_FRAME(inst->reconfig_width, + inst->reconfig_height) : + NUM_MBS_PER_FRAME(inst->prop.width[OUTPUT_PORT], + inst->prop.height[OUTPUT_PORT]); + + capture_port_mbs = NUM_MBS_PER_FRAME(inst->prop.width[CAPTURE_PORT], + inst->prop.height[CAPTURE_PORT]); + + if ((inst->clk_data.operating_rate >> 16) > inst->prop.fps) + fps = (inst->clk_data.operating_rate >> 16) ? + inst->clk_data.operating_rate >> 16 : 1; + else + fps = inst->prop.fps; + + return max(output_port_mbs, capture_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; + + load = msm_comm_get_mbs_per_sec(inst); + + if (is_thumbnail_session(inst)) { + if (quirks & LOAD_CALC_IGNORE_THUMBNAIL_LOAD) + load = 0; + } + + if (is_turbo_session(inst)) { + if (!(quirks & LOAD_CALC_IGNORE_TURBO_LOAD)) + load = inst->core->resources.max_load; + } + + /* Clock and Load calculations for REALTIME/NON-REALTIME + * OPERATING RATE SET/NO OPERATING RATE SET + * + * | OPERATING RATE SET | OPERATING RATE NOT SET | + * ----------------|--------------------- |------------------------| + * REALTIME | load = res * op_rate | load = res * fps | + * | clk = res * op_rate | clk = res * fps | + * ----------------|----------------------|------------------------| + * NON-REALTIME | load = res * 1 fps | load = res * 1 fps | + * | clk = res * op_rate | clk = res * fps | + * ----------------|----------------------|------------------------| + */ + + if (!is_realtime_session(inst) && + (quirks & LOAD_CALC_IGNORE_NON_REALTIME_LOAD)) { + if (!inst->prop.fps) { + dprintk(VIDC_INFO, "instance:%pK fps = 0\n", inst); + load = 0; + } else { + load = msm_comm_get_mbs_per_sec(inst) / inst->prop.fps; + } + } + +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_load(struct msm_vidc_core *core, + enum session_type type, enum load_calc_quirks quirks) +{ + struct msm_vidc_inst *inst = NULL; + int num_mbs_per_sec = 0; + + if (!core) { + dprintk(VIDC_ERR, "Invalid args: %pK\n", core); + return -EINVAL; + } + + mutex_lock(&core->lock); + list_for_each_entry(inst, &core->instances, list) { + if (inst->session_type != type) + 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) +{ + 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: + dprintk(VIDC_ERR, "Wrong domain %d\n", session_type); + domain = HAL_UNUSED_DOMAIN; + break; + } + + return domain; +} + +enum hal_video_codec get_hal_codec(int fourcc) +{ + 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: + dprintk(VIDC_ERR, "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; +} + +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) { + dprintk(VIDC_ERR, "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 *msm_comm_get_pixel_fmt_index( + const struct msm_vidc_format fmt[], int size, int index, int fmt_type) +{ + int i, k = 0; + + if (!fmt || index < 0) { + dprintk(VIDC_ERR, "Invalid inputs, fmt = %pK, index = %d\n", + fmt, index); + return NULL; + } + for (i = 0; i < size; i++) { + if (fmt[i].type != fmt_type) + continue; + if (k == index) + break; + k++; + } + if (i == size) { + dprintk(VIDC_INFO, "Format not found\n"); + return NULL; + } + return &fmt[i]; +} +struct msm_vidc_format *msm_comm_get_pixel_fmt_fourcc( + struct msm_vidc_format fmt[], int size, int fourcc, int fmt_type) +{ + int i; + + if (!fmt) { + dprintk(VIDC_ERR, "Invalid inputs, fmt = %pK\n", fmt); + return NULL; + } + for (i = 0; i < size; i++) { + if (fmt[i].fourcc == fourcc) + break; + } + if (i == size) { + dprintk(VIDC_INFO, "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) +{ + int i; + + if (!fmt) { + dprintk(VIDC_ERR, "Invalid inputs, fmt = %pK\n", fmt); + return NULL; + } + for (i = 0; i < size; i++) { + if (fmt[i].fourcc == fourcc) + break; + } + if (i == size) { + dprintk(VIDC_INFO, "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 == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + return &inst->bufq[CAPTURE_PORT]; + if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + return &inst->bufq[OUTPUT_PORT]; + return NULL; +} + +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; + struct vidc_hal_sys_init_done *sys_init_msg; + u32 index; + + if (!IS_HAL_SYS_CMD(cmd)) { + dprintk(VIDC_ERR, "%s - invalid cmd\n", __func__); + return; + } + + index = SYS_MSG_INDEX(cmd); + + if (!response) { + dprintk(VIDC_ERR, + "Failed to get valid response for sys init\n"); + return; + } + core = get_vidc_core(response->device_id); + if (!core) { + dprintk(VIDC_ERR, "Wrong device_id received\n"); + return; + } + sys_init_msg = &response->data.sys_init_done; + if (!sys_init_msg) { + dprintk(VIDC_ERR, "sys_init_done message not proper\n"); + return; + } + + core->enc_codec_supported = sys_init_msg->enc_codec_supported; + core->dec_codec_supported = sys_init_msg->dec_codec_supported; + + /* This should come from sys_init_done */ + core->resources.max_inst_count = + sys_init_msg->max_sessions_supported ? + min_t(u32, sys_init_msg->max_sessions_supported, + MAX_SUPPORTED_INSTANCES) : 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; + + if (core->id == MSM_VIDC_CORE_VENUS && + (core->dec_codec_supported & HAL_VIDEO_CODEC_H264)) + core->dec_codec_supported |= + HAL_VIDEO_CODEC_MVC; + + core->codec_count = sys_init_msg->codec_count; + memcpy(core->capabilities, sys_init_msg->capabilities, + sys_init_msg->codec_count * sizeof(struct msm_vidc_capability)); + + dprintk(VIDC_DBG, + "%s: supported_codecs[%d]: enc = %#x, dec = %#x\n", + __func__, core->codec_count, core->enc_codec_supported, + core->dec_codec_supported); + + complete(&(core->completions[index])); +} + +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 *session_id) +{ + struct msm_vidc_inst *inst = NULL; + bool matches = false; + + if (!core || !session_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 == session_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) { + dprintk(VIDC_ERR, "Invalid release_buf_done response\n"); + return; + } + + inst = get_inst(get_vidc_core(response->device_id), + response->session_id); + if (!inst) { + dprintk(VIDC_WARN, "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) { + dprintk(VIDC_DBG, "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) { + dprintk(VIDC_DBG, "releasing persist: %x\n", + buf->smem.device_addr); + buf_found = true; + } + } + mutex_unlock(&inst->persistbufs.lock); + + if (!buf_found) + dprintk(VIDC_ERR, "invalid buffer received from firmware"); + if (IS_HAL_SESSION_CMD(cmd)) + complete(&inst->completions[SESSION_MSG_INDEX(cmd)]); + else + dprintk(VIDC_ERR, "Invalid inst cmd response: %d\n", cmd); + + 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) { + dprintk(VIDC_ERR, + "Failed to get valid response for sys init\n"); + return; + } + core = get_vidc_core(response->device_id); + if (!core) { + dprintk(VIDC_ERR, "Wrong device_id received\n"); + return; + } + 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) { + dprintk(VIDC_ERR, "Invalid parameter %s\n", __func__); + return; + } + mutex_lock(&inst->lock); + if (inst->state == MSM_VIDC_CORE_INVALID) { + dprintk(VIDC_DBG, + "Inst: %pK is in bad state can't change state to %d\n", + inst, state); + goto exit; + } + dprintk(VIDC_DBG, "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) { + dprintk(VIDC_ERR, "Invalid(%pK) instance id\n", inst); + return -EINVAL; + } + if (IS_HAL_SESSION_CMD(cmd)) { + complete(&inst->completions[SESSION_MSG_INDEX(cmd)]); + } else { + dprintk(VIDC_ERR, "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 (!IS_HAL_SESSION_CMD(cmd)) { + dprintk(VIDC_ERR, "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) { + dprintk(VIDC_ERR, "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 (IS_ALREADY_IN_STATE(flipped_state, desired_state)) { + dprintk(VIDC_INFO, "inst: %pK is already in state: %d\n", + inst, inst->state); + goto err_same_state; + } + dprintk(VIDC_DBG, "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) { + dprintk(VIDC_ERR, "%s: invalid input parameters\n", __func__); + return; + } + dprintk(VIDC_ERR, "%s: Too many clients\n", __func__); + response.session_id = inst; + response.status = VIDC_ERR_MAX_CLIENTS; + handle_session_error(cmd, (void *)&response); +} + +static void print_cap(const char *type, + struct hal_capability_supported *cap) +{ + dprintk(VIDC_DBG, + "%-24s: %-8d %-8d %-8d\n", + type, cap->min, cap->max, cap->step_size); +} + +static int msm_vidc_comm_update_ctrl(struct msm_vidc_inst *inst, + u32 id, struct hal_capability_supported *capability) +{ + struct v4l2_ctrl *ctrl = NULL; + int rc = 0; + + ctrl = v4l2_ctrl_find(&inst->ctrl_handler, id); + if (ctrl) { + v4l2_ctrl_modify_range(ctrl, capability->min, + capability->max, ctrl->step, + ctrl->default_value); + dprintk(VIDC_DBG, + "%s: Updated Range = %lld --> %lld Def value = %lld\n", + ctrl->name, ctrl->minimum, ctrl->maximum, + ctrl->default_value); + } else { + dprintk(VIDC_ERR, + "Failed to find Conrol %d\n", id); + rc = -EINVAL; + } + + return rc; + } + +static void msm_vidc_comm_update_ctrl_limits(struct msm_vidc_inst *inst) +{ + if (inst->session_type == MSM_VIDC_ENCODER) { + if (get_hal_codec(inst->fmts[CAPTURE_PORT].fourcc) == + HAL_VIDEO_CODEC_TME) + return; + msm_vidc_comm_update_ctrl(inst, + V4L2_CID_MPEG_VIDC_VIDEO_HYBRID_HIERP_MODE, + &inst->capability.hier_p_hybrid); + msm_vidc_comm_update_ctrl(inst, + V4L2_CID_MPEG_VIDC_VIDEO_HIER_B_NUM_LAYERS, + &inst->capability.hier_b); + msm_vidc_comm_update_ctrl(inst, + V4L2_CID_MPEG_VIDC_VIDEO_HIER_P_NUM_LAYERS, + &inst->capability.hier_p); + msm_vidc_comm_update_ctrl(inst, V4L2_CID_MPEG_VIDEO_BITRATE, + &inst->capability.bitrate); + msm_vidc_comm_update_ctrl(inst, + V4L2_CID_MPEG_VIDC_VENC_PARAM_LAYER_BITRATE, + &inst->capability.bitrate); + msm_vidc_comm_update_ctrl(inst, + V4L2_CID_MPEG_VIDEO_BITRATE_PEAK, + &inst->capability.peakbitrate); + msm_vidc_comm_update_ctrl(inst, + V4L2_CID_MPEG_VIDC_VIDEO_I_FRAME_QP, + &inst->capability.i_qp); + msm_vidc_comm_update_ctrl(inst, + V4L2_CID_MPEG_VIDC_VIDEO_P_FRAME_QP, + &inst->capability.p_qp); + msm_vidc_comm_update_ctrl(inst, + V4L2_CID_MPEG_VIDC_VIDEO_B_FRAME_QP, + &inst->capability.b_qp); + msm_vidc_comm_update_ctrl(inst, + V4L2_CID_MPEG_VIDC_VIDEO_I_FRAME_QP_MIN, + &inst->capability.i_qp); + msm_vidc_comm_update_ctrl(inst, + V4L2_CID_MPEG_VIDC_VIDEO_P_FRAME_QP_MIN, + &inst->capability.p_qp); + msm_vidc_comm_update_ctrl(inst, + V4L2_CID_MPEG_VIDC_VIDEO_B_FRAME_QP_MIN, + &inst->capability.b_qp); + msm_vidc_comm_update_ctrl(inst, + V4L2_CID_MPEG_VIDC_VIDEO_I_FRAME_QP_MAX, + &inst->capability.i_qp); + msm_vidc_comm_update_ctrl(inst, + V4L2_CID_MPEG_VIDC_VIDEO_P_FRAME_QP_MAX, + &inst->capability.p_qp); + msm_vidc_comm_update_ctrl(inst, + V4L2_CID_MPEG_VIDC_VIDEO_B_FRAME_QP_MAX, + &inst->capability.b_qp); + msm_vidc_comm_update_ctrl(inst, + V4L2_CID_MPEG_VIDC_VIDEO_BLUR_WIDTH, + &inst->capability.blur_width); + msm_vidc_comm_update_ctrl(inst, + V4L2_CID_MPEG_VIDC_VIDEO_BLUR_HEIGHT, + &inst->capability.blur_height); + msm_vidc_comm_update_ctrl(inst, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES, + &inst->capability.slice_bytes); + msm_vidc_comm_update_ctrl(inst, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB, + &inst->capability.slice_mbs); + msm_vidc_comm_update_ctrl(inst, + V4L2_CID_MPEG_VIDC_VIDEO_LTRCOUNT, + &inst->capability.ltr_count); + msm_vidc_comm_update_ctrl(inst, + V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES, + &inst->capability.bframe); + } + msm_vidc_comm_update_ctrl(inst, + V4L2_CID_MPEG_VIDC_VIDEO_FRAME_RATE, + &inst->capability.frame_rate); +} + +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; + struct msm_vidc_capability *capability = NULL; + struct hfi_device *hdev; + struct msm_vidc_core *core; + struct hal_profile_level *profile_level; + u32 i, codec; + + if (!response) { + dprintk(VIDC_ERR, + "Failed to get valid response for session init\n"); + return; + } + + inst = get_inst(get_vidc_core(response->device_id), + response->session_id); + + if (!inst) { + dprintk(VIDC_WARN, "Got a response for an inactive session\n"); + return; + } + + if (response->status) { + dprintk(VIDC_ERR, + "Session init response from FW : %#x\n", + response->status); + 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); + return; + } + + if (inst->session_type == MSM_VIDC_CVP) { + dprintk(VIDC_DBG, "%s: cvp session %#x\n", + __func__, hash32_ptr(inst->session)); + signal_session_msg_receipt(cmd, inst); + put_inst(inst); + return; + } + + core = inst->core; + hdev = inst->core->device; + codec = inst->session_type == MSM_VIDC_DECODER ? + inst->fmts[OUTPUT_PORT].fourcc : + inst->fmts[CAPTURE_PORT].fourcc; + + /* check if capabilities are available for this session */ + for (i = 0; i < VIDC_MAX_SESSIONS; i++) { + if (core->capabilities[i].codec == + get_hal_codec(codec) && + core->capabilities[i].domain == + get_hal_domain(inst->session_type)) { + capability = &core->capabilities[i]; + break; + } + } + + if (capability) { + dprintk(VIDC_DBG, + "%s: capabilities for codec 0x%x, domain %#x\n", + __func__, capability->codec, capability->domain); + memcpy(&inst->capability, capability, + sizeof(struct msm_vidc_capability)); + } else { + dprintk(VIDC_ERR, + "Watch out : Some property may fail inst %pK\n", inst); + dprintk(VIDC_ERR, + "Caps N/A for codec 0x%x, domain %#x\n", + inst->capability.codec, inst->capability.domain); + } + inst->capability.pixelprocess_capabilities = + call_hfi_op(hdev, get_core_capabilities, hdev->hfi_device_data); + + dprintk(VIDC_DBG, + "Capability type : min max step size\n"); + print_cap("width", &inst->capability.width); + print_cap("height", &inst->capability.height); + print_cap("mbs_per_frame", &inst->capability.mbs_per_frame); + print_cap("mbs_per_sec", &inst->capability.mbs_per_sec); + print_cap("frame_rate", &inst->capability.frame_rate); + print_cap("bitrate", &inst->capability.bitrate); + print_cap("peak_bitrate", &inst->capability.peakbitrate); + print_cap("scale_x", &inst->capability.scale_x); + print_cap("scale_y", &inst->capability.scale_y); + print_cap("hier_p", &inst->capability.hier_p); + print_cap("ltr_count", &inst->capability.ltr_count); + print_cap("bframe", &inst->capability.bframe); + print_cap("secure_output2_threshold", + &inst->capability.secure_output2_threshold); + print_cap("hier_b", &inst->capability.hier_b); + print_cap("lcu_size", &inst->capability.lcu_size); + print_cap("hier_p_hybrid", &inst->capability.hier_p_hybrid); + print_cap("mbs_per_sec_low_power", + &inst->capability.mbs_per_sec_power_save); + print_cap("extradata", &inst->capability.extradata); + print_cap("profile", &inst->capability.profile); + print_cap("level", &inst->capability.level); + print_cap("i_qp", &inst->capability.i_qp); + print_cap("p_qp", &inst->capability.p_qp); + print_cap("b_qp", &inst->capability.b_qp); + print_cap("rc_modes", &inst->capability.rc_modes); + print_cap("blur_width", &inst->capability.blur_width); + print_cap("blur_height", &inst->capability.blur_height); + print_cap("rotation", &inst->capability.rotation); + print_cap("color_space_caps", &inst->capability.color_space_caps); + print_cap("slice_delivery_mode", &inst->capability.slice_delivery_mode); + print_cap("slice_bytes", &inst->capability.slice_bytes); + print_cap("slice_mbs", &inst->capability.slice_mbs); + print_cap("secure", &inst->capability.secure); + print_cap("max_num_b_frames", &inst->capability.max_num_b_frames); + print_cap("max_video_cores", &inst->capability.max_video_cores); + print_cap("max_work_modes", &inst->capability.max_work_modes); + print_cap("ubwc_cr_stats", &inst->capability.ubwc_cr_stats); + + dprintk(VIDC_DBG, "profile count : %u\n", + inst->capability.profile_level.profile_count); + for (i = 0; i < inst->capability.profile_level.profile_count; i++) { + profile_level = + &inst->capability.profile_level.profile_level[i]; + dprintk(VIDC_DBG, "profile : %u\n", profile_level->profile); + dprintk(VIDC_DBG, "level : %u\n", profile_level->level); + } + + signal_session_msg_receipt(cmd, inst); + + /* + * Update controls after informing session_init_done to avoid + * timeouts. + */ + + msm_vidc_comm_update_ctrl_limits(inst); + put_inst(inst); +} + +static void msm_vidc_queue_rbr_event(struct msm_vidc_inst *inst, + int fd, u32 offset, u32 output_tag) +{ + 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; + ptr[2] = output_tag; + + 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 hal_buffer_requirements *bufreq; + int extra_buff_count = 0; + + if (!event_notify) { + dprintk(VIDC_WARN, "Got an empty event from hfi\n"); + return; + } + + inst = get_inst(get_vidc_core(event_notify->device_id), + event_notify->session_id); + if (!inst || !inst->core || !inst->core->device) { + dprintk(VIDC_WARN, "Got a response for an inactive session\n"); + goto err_bad_event; + } + hdev = inst->core->device; + + switch (event_notify->hal_event_type) { + case HAL_EVENT_SEQ_CHANGED_SUFFICIENT_RESOURCES: + event = V4L2_EVENT_SEQ_CHANGED_SUFFICIENT; + 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}; + + dprintk(VIDC_DBG, + "%s: inst: %pK data_buffer: %x extradata_buffer: %x\n", + __func__, inst, 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, + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, planes); + if (!mbuf || !kref_get_mbuf(inst, mbuf)) { + dprintk(VIDC_ERR, + "%s: data_addr %x, extradata_addr %x not found\n", + __func__, planes[0], planes[1]); + } else { + mbuf->output_tag = event_notify->output_tag; + 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[0] = height + * ptr[1] = width + * ptr[2] = bit depth + * ptr[3] = pic struct (progressive or interlaced) + * ptr[4] = colour space + * ptr[5] = crop_data(top) + * ptr[6] = crop_data(left) + * ptr[7] = crop_data(height) + * ptr[8] = crop_data(width) + * ptr[9] = profile + * ptr[10] = level + */ + + inst->entropy_mode = event_notify->entropy_mode; + inst->profile = event_notify->profile; + inst->level = event_notify->level; + inst->prop.crop_info.left = + event_notify->crop_data.left; + inst->prop.crop_info.top = + event_notify->crop_data.top; + inst->prop.crop_info.height = + event_notify->crop_data.height; + inst->prop.crop_info.width = + event_notify->crop_data.width; + /* 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; + + ptr = (u32 *)seq_changed_event.u.data; + ptr[0] = event_notify->height; + ptr[1] = event_notify->width; + ptr[2] = event_notify->bit_depth; + ptr[3] = event_notify->pic_struct; + ptr[4] = event_notify->colour_space; + ptr[5] = event_notify->crop_data.top; + ptr[6] = event_notify->crop_data.left; + ptr[7] = event_notify->crop_data.height; + ptr[8] = event_notify->crop_data.width; + ptr[9] = msm_comm_get_v4l2_profile( + inst->fmts[OUTPUT_PORT].fourcc, + event_notify->profile); + ptr[10] = msm_comm_get_v4l2_level( + inst->fmts[OUTPUT_PORT].fourcc, + event_notify->level); + ptr[11] = event_notify->max_dpb_count; + ptr[12] = event_notify->max_ref_count; + ptr[13] = event_notify->max_dec_buffering; + + dprintk(VIDC_DBG, + "Event payload: height = %u width = %u profile = %u level = %u\n", + event_notify->height, event_notify->width, + ptr[9], ptr[10]); + + dprintk(VIDC_DBG, + "Event payload: bit_depth = %u pic_struct = %u colour_space = %u\n", + event_notify->bit_depth, event_notify->pic_struct, + event_notify->colour_space); + + dprintk(VIDC_DBG, + "Event payload: CROP top = %u left = %u Height = %u Width = %u\n", + event_notify->crop_data.top, + event_notify->crop_data.left, + event_notify->crop_data.height, + event_notify->crop_data.width); + + mutex_lock(&inst->lock); + inst->in_reconfig = true; + inst->reconfig_height = event_notify->height; + inst->reconfig_width = event_notify->width; + inst->bit_depth = event_notify->bit_depth; + + if (msm_comm_get_stream_output_mode(inst) == + HAL_VIDEO_DECODER_SECONDARY) { + bufreq = get_buff_req_buffer(inst, + HAL_BUFFER_OUTPUT); + if (!bufreq) + return; + + /* No need to add extra buffers to DPBs */ + bufreq->buffer_count_min = event_notify->capture_buf_count; + bufreq->buffer_count_min_host = bufreq->buffer_count_min; + + bufreq = get_buff_req_buffer(inst, + HAL_BUFFER_OUTPUT2); + if (!bufreq) + return; + + extra_buff_count = msm_vidc_get_extra_buff_count(inst, + HAL_BUFFER_OUTPUT2); + bufreq->buffer_count_min = event_notify->capture_buf_count; + bufreq->buffer_count_min_host = bufreq->buffer_count_min + + extra_buff_count; + } else { + + bufreq = get_buff_req_buffer(inst, + HAL_BUFFER_OUTPUT); + if (!bufreq) + return; + + extra_buff_count = msm_vidc_get_extra_buff_count(inst, + HAL_BUFFER_OUTPUT); + bufreq->buffer_count_min = event_notify->capture_buf_count; + bufreq->buffer_count_min_host = bufreq->buffer_count_min + + extra_buff_count; + } + dprintk(VIDC_DBG, "%s: buffer[%d] count: min %d min_host %d\n", + __func__, bufreq->buffer_type, bufreq->buffer_count_min, + bufreq->buffer_count_min_host); + + mutex_unlock(&inst->lock); + + if (event == V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT) { + dprintk(VIDC_DBG, "V4L2_EVENT_SEQ_CHANGED_INSUFFICIENT\n"); + } else { + dprintk(VIDC_DBG, "V4L2_EVENT_SEQ_CHANGED_SUFFICIENT\n"); + dprintk(VIDC_DBG, + "event_notify->height = %d event_notify->width = %d\n", + event_notify->height, + event_notify->width); + } + + 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); + } + +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) { + dprintk(VIDC_ERR, + "Failed to get valid response for prop info\n"); + return; + } + + inst = get_inst(get_vidc_core(response->device_id), + response->session_id); + if (!inst) { + dprintk(VIDC_WARN, "Got a response for an inactive session\n"); + return; + } + + getprop = kzalloc(sizeof(*getprop), GFP_KERNEL); + if (!getprop) { + dprintk(VIDC_ERR, "%s: getprop kzalloc failed\n", __func__); + goto err_prop_info; + } + + getprop->data = kmemdup(&response->data.property, + sizeof(union hal_get_property), GFP_KERNEL); + if (!getprop->data) { + dprintk(VIDC_ERR, "%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); + + 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) { + dprintk(VIDC_ERR, + "Failed to get valid response for load resource\n"); + return; + } + + inst = get_inst(get_vidc_core(response->device_id), + response->session_id); + if (!inst) { + dprintk(VIDC_WARN, "Got a response for an inactive session\n"); + return; + } + + if (response->status) { + dprintk(VIDC_ERR, + "Load resource response from FW : %#x\n", + response->status); + msm_comm_generate_session_error(inst); + } + + 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) { + dprintk(VIDC_ERR, "Failed to get valid response for start\n"); + return; + } + + inst = get_inst(get_vidc_core(response->device_id), + response->session_id); + if (!inst) { + dprintk(VIDC_WARN, "Got a response for an inactive session\n"); + return; + } + + 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) { + dprintk(VIDC_ERR, "Failed to get valid response for stop\n"); + return; + } + + inst = get_inst(get_vidc_core(response->device_id), + response->session_id); + if (!inst) { + dprintk(VIDC_WARN, "Got a response for an inactive session\n"); + return; + } + + 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) { + dprintk(VIDC_ERR, + "Failed to get valid response for release resource\n"); + return; + } + + inst = get_inst(get_vidc_core(response->device_id), + response->session_id); + if (!inst) { + dprintk(VIDC_WARN, "Got a response for an inactive session\n"); + return; + } + + 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 *output_buf; + + output_buf = get_buff_req_buffer(inst, HAL_BUFFER_OUTPUT); + + if (!output_buf) { + dprintk(VIDC_DBG, + "This output buffer not required, buffer_type: %x\n", + HAL_BUFFER_OUTPUT); + return; + } + mutex_lock(&inst->outputbufs.lock); + if (list_empty(&inst->outputbufs.list)) { + dprintk(VIDC_DBG, "%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) { + dprintk(VIDC_DBG, + "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 != output_buf->buffer_count_actual) { + dprintk(VIDC_WARN, + "OUTPUT Buffer count mismatch %d of %d\n", + buffers_owned_by_driver, + output_buf->buffer_count_actual); + msm_vidc_handle_hw_error(inst->core); + } +} + +int msm_comm_queue_output_buffers(struct msm_vidc_inst *inst) +{ + struct internal_buf *binfo; + struct hfi_device *hdev; + struct vidc_frame_data frame_data = {0}; + struct hal_buffer_requirements *output_buf, *extra_buf; + int rc = 0; + + if (!inst || !inst->core || !inst->core->device) { + dprintk(VIDC_ERR, "%s invalid parameters\n", __func__); + return -EINVAL; + } + + hdev = inst->core->device; + + output_buf = get_buff_req_buffer(inst, HAL_BUFFER_OUTPUT); + if (!output_buf) { + dprintk(VIDC_DBG, + "This output buffer not required, buffer_type: %x\n", + HAL_BUFFER_OUTPUT); + return 0; + } + dprintk(VIDC_DBG, + "output: num = %d, size = %d\n", + output_buf->buffer_count_actual, + output_buf->buffer_size); + + extra_buf = get_buff_req_buffer(inst, HAL_BUFFER_EXTRADATA_OUTPUT); + + 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 = output_buf->buffer_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 = binfo->smem.device_addr + + output_buf->buffer_size; + frame_data.buffer_type = HAL_BUFFER_OUTPUT; + frame_data.extradata_size = extra_buf ? + extra_buf->buffer_size : 0; + rc = call_hfi_op(hdev, session_ftb, + (void *) inst->session, &frame_data); + binfo->buffer_ownership = FIRMWARE; + } + mutex_unlock(&inst->outputbufs.lock); + + return 0; +} + +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) { + dprintk(VIDC_ERR, "Failed to get valid response for flush\n"); + return; + } + + inst = get_inst(get_vidc_core(response->device_id), + response->session_id); + if (!inst) { + dprintk(VIDC_WARN, "Got a response for an inactive session\n"); + return; + } + + if (response->data.flush_type & HAL_FLUSH_INPUT) + mutex_lock(&inst->bufq[OUTPUT_PORT].lock); + if (response->data.flush_type & HAL_FLUSH_OUTPUT) + mutex_lock(&inst->bufq[CAPTURE_PORT].lock); + + if (msm_comm_get_stream_output_mode(inst) == + HAL_VIDEO_DECODER_SECONDARY) { + + if (!(inst->fmts[OUTPUT_PORT].defer_outputs && + inst->in_reconfig)) + msm_comm_validate_output_buffers(inst); + + if (!inst->in_reconfig) { + rc = msm_comm_queue_output_buffers(inst); + if (rc) { + dprintk(VIDC_ERR, + "Failed to queue output buffers: %d\n", + rc); + } + } + } + inst->in_flush = false; + 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: + ptr[0] = V4L2_QCOM_CMD_FLUSH_OUTPUT; + break; + case HAL_FLUSH_OUTPUT: + ptr[0] = V4L2_QCOM_CMD_FLUSH_CAPTURE; + break; + case HAL_FLUSH_ALL: + ptr[0] |= V4L2_QCOM_CMD_FLUSH_CAPTURE; + ptr[0] |= V4L2_QCOM_CMD_FLUSH_OUTPUT; + break; + default: + dprintk(VIDC_ERR, "Invalid flush type received!"); + goto exit; + } + + dprintk(VIDC_DBG, + "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[CAPTURE_PORT].lock); + if (response->data.flush_type & HAL_FLUSH_INPUT) + mutex_unlock(&inst->bufq[OUTPUT_PORT].lock); + + 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) { + dprintk(VIDC_ERR, + "Failed to get valid response for session error\n"); + return; + } + + inst = get_inst(get_vidc_core(response->device_id), + response->session_id); + if (!inst) { + dprintk(VIDC_WARN, "Got a response for an inactive session\n"); + return; + } + + hdev = inst->core->device; + dprintk(VIDC_ERR, "Session error received for inst %pK session %x\n", + inst, hash32_ptr(inst->session)); + + if (response->status == VIDC_ERR_MAX_CLIENTS) { + dprintk(VIDC_WARN, "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) { + dprintk(VIDC_WARN, "Unsupported bitstream in %pK", inst); + event = V4L2_EVENT_MSM_VIDC_HW_UNSUPPORTED; + } else { + dprintk(VIDC_WARN, "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); + put_inst(inst); +} + +static void msm_comm_clean_notify_client(struct msm_vidc_core *core) +{ + struct msm_vidc_inst *inst = NULL; + + if (!core) { + dprintk(VIDC_ERR, "%s: Invalid params\n", __func__); + return; + } + + dprintk(VIDC_WARN, "%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); + dprintk(VIDC_WARN, + "%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) { + dprintk(VIDC_ERR, + "Failed to get valid response for sys error\n"); + return; + } + + core = get_vidc_core(response->device_id); + if (!core) { + dprintk(VIDC_ERR, + "Got SYS_ERR but unable to identify core\n"); + return; + } + hdev = core->device; + + mutex_lock(&core->lock); + if (core->state == VIDC_CORE_UNINIT) { + dprintk(VIDC_ERR, + "%s: Core %pK already moved to state %d\n", + __func__, core, core->state); + mutex_unlock(&core->lock); + return; + } + + dprintk(VIDC_WARN, "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) { + dprintk(VIDC_WARN, + "%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); + + dprintk(VIDC_DBG, "Calling core_release\n"); + rc = call_hfi_op(hdev, core_release, hdev->hfi_device_data); + if (rc) { + dprintk(VIDC_ERR, "core_release failed\n"); + mutex_unlock(&core->lock); + return; + } + core->state = VIDC_CORE_UNINIT; + mutex_unlock(&core->lock); + + dprintk(VIDC_WARN, "SYS_ERROR handled.\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) { + dprintk(VIDC_ERR, "%s invalid params\n", __func__); + return; + } + if (!inst->session) { + dprintk(VIDC_DBG, "%s: inst %pK session already cleaned\n", + __func__, inst); + return; + } + + hdev = inst->core->device; + mutex_lock(&inst->lock); + dprintk(VIDC_DBG, "%s: inst %pK\n", __func__, inst); + rc = call_hfi_op(hdev, session_clean, + (void *)inst->session); + if (rc) { + dprintk(VIDC_ERR, + "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) { + dprintk(VIDC_ERR, + "Failed to get valid response for session close\n"); + return; + } + + inst = get_inst(get_vidc_core(response->device_id), + response->session_id); + if (!inst) { + dprintk(VIDC_WARN, "Got a response for an inactive session\n"); + return; + } + + 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 == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + port = CAPTURE_PORT; + } else if (mbuf->vvb.vb2_buf.type == + V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + port = OUTPUT_PORT; + } else { + dprintk(VIDC_ERR, "%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) { + dprintk(VIDC_ERR, "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) { + dprintk(VIDC_ERR, "%s: invalid params %pK %pK\n", + __func__, inst, mbuf); + return -EINVAL; + } + + if (mbuf->vvb.vb2_buf.type == + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + port = CAPTURE_PORT; + else if (mbuf->vvb.vb2_buf.type == + V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + port = OUTPUT_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) { + rc = -EINVAL; + dprintk(VIDC_ERR, "%s:port %d buffer not found\n", + __func__, port); + 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 { + dprintk(VIDC_ERR, "%s: port %d is not streaming\n", + __func__, port); + } +unlock: + mutex_unlock(&inst->bufq[port].lock); + return rc; +} + +bool heic_encode_session_supported(struct msm_vidc_inst *inst) +{ + u32 slice_mode; + u32 idr_period; + u32 n_bframes; + u32 n_pframes; + + slice_mode = msm_comm_g_ctrl_for_id(inst, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE); + idr_period = msm_comm_g_ctrl_for_id(inst, + V4L2_CID_MPEG_VIDC_VIDEO_IDR_PERIOD); + n_bframes = msm_comm_g_ctrl_for_id(inst, + V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES); + n_pframes = msm_comm_g_ctrl_for_id(inst, + V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES); + + /* + * HEIC Encode is supported for Constant Quality RC mode only. + * All configurations below except grid_enable are required for any + * HEIC session including FWK tiled HEIC encode. + * grid_enable flag along with dimension check enables HW tiling. + */ + if (inst->session_type == MSM_VIDC_ENCODER && + get_hal_codec(inst->fmts[CAPTURE_PORT].fourcc) == + HAL_VIDEO_CODEC_HEVC && + inst->frame_quality >= MIN_FRAME_QUALITY && + inst->frame_quality <= MAX_FRAME_QUALITY && + slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE && + idr_period == 1 && + n_bframes == 0 && + n_pframes == 0) { + if (inst->grid_enable > 0) { + if (inst->prop.width[CAPTURE_PORT] < + HEIC_GRID_DIMENSION || + inst->prop.height[CAPTURE_PORT] < + HEIC_GRID_DIMENSION) + return false; + } + return true; + } else { + return false; + } +} + +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; + struct vidc_tag_data tag_data; + u32 planes[VIDEO_MAX_PLANES] = {0}; + u32 extra_idx = 0; + + if (!response) { + dprintk(VIDC_ERR, "Invalid response from vidc_hal\n"); + return; + } + + inst = get_inst(get_vidc_core(response->device_id), + response->session_id); + if (!inst) { + dprintk(VIDC_WARN, "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)) { + dprintk(VIDC_DBG, "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, + V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, planes); + if (!mbuf || !kref_get_mbuf(inst, mbuf)) { + dprintk(VIDC_ERR, + "%s: data_addr %x, extradata_addr %x not found\n", + __func__, planes[0], planes[1]); + goto exit; + } + mbuf->flags &= ~MSM_VIDC_FLAG_QUEUED; + vb = &mbuf->vvb.vb2_buf; + + vb->planes[0].bytesused = response->input_done.filled_len; + if (vb->planes[0].bytesused > vb->planes[0].length) + dprintk(VIDC_INFO, "bytesused overflow length\n"); + + vb->planes[0].data_offset = response->input_done.offset; + if (vb->planes[0].data_offset > vb->planes[0].length) + dprintk(VIDC_INFO, "data_offset overflow length\n"); + + if (empty_buf_done->status == VIDC_ERR_NOT_SUPPORTED) { + dprintk(VIDC_INFO, "Failed : Unsupported input stream\n"); + mbuf->vvb.flags |= V4L2_QCOM_BUF_INPUT_UNSUPPORTED; + } + if (empty_buf_done->status == VIDC_ERR_BITSTREAM_ERR) { + dprintk(VIDC_INFO, "Failed : Corrupted input stream\n"); + mbuf->vvb.flags |= V4L2_BUF_FLAG_DATA_CORRUPT; + } + if (empty_buf_done->flags & HAL_BUFFERFLAG_SYNCFRAME) + mbuf->vvb.flags |= V4L2_BUF_FLAG_KEYFRAME; + + extra_idx = EXTRADATA_IDX(inst->bufq[OUTPUT_PORT].num_planes); + if (extra_idx && extra_idx < VIDEO_MAX_PLANES) + vb->planes[extra_idx].bytesused = vb->planes[extra_idx].length; + + tag_data.index = vb->index; + tag_data.input_tag = empty_buf_done->input_tag; + tag_data.output_tag = empty_buf_done->output_tag; + tag_data.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + + msm_comm_store_tags(inst, &tag_data); + + update_recon_stats(inst, &empty_buf_done->recon_stats); + msm_vidc_clear_freq_entry(inst, mbuf->smem[0].device_addr); + /* + * 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: + 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) { + dprintk(VIDC_ERR, + "FW returned same buffer: %x\n", + dev_addr); + break; + } + binfo->buffer_ownership = DRIVER; + found = true; + break; + } + } + mutex_unlock(&inst->outputbufs.lock); + + if (!found) { + dprintk(VIDC_ERR, + "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; + struct vidc_tag_data tag_data; + enum hal_buffer buffer_type; + u64 time_usec = 0; + u32 planes[VIDEO_MAX_PLANES] = {0}; + u32 extra_idx; + + if (!response) { + dprintk(VIDC_ERR, "Invalid response from vidc_hal\n"); + return; + } + + inst = get_inst(get_vidc_core(response->device_id), + response->session_id); + if (!inst) { + dprintk(VIDC_WARN, "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, + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, planes); + if (!mbuf || !kref_get_mbuf(inst, mbuf)) { + dprintk(VIDC_ERR, + "%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)) + dprintk(VIDC_ERR, + "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->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) + dprintk(VIDC_INFO, + "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) + dprintk(VIDC_INFO, + "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); + + if (inst->session_type == MSM_VIDC_DECODER) { + msm_comm_store_mark_data(&inst->fbd_data, vb->index, + fill_buf_done->mark_data, fill_buf_done->mark_target); + } + if (inst->session_type == MSM_VIDC_ENCODER) { + if (inst->max_filled_length < fill_buf_done->filled_len1) + inst->max_filled_length = fill_buf_done->filled_len1; + } + + tag_data.index = vb->index; + tag_data.input_tag = fill_buf_done->input_tag; + tag_data.output_tag = fill_buf_done->output_tag; + tag_data.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + + msm_comm_store_tags(inst, &tag_data); + + extra_idx = EXTRADATA_IDX(inst->bufq[CAPTURE_PORT].num_planes); + if (extra_idx && extra_idx < VIDEO_MAX_PLANES) + vb->planes[extra_idx].bytesused = vb->planes[extra_idx].length; + + mbuf->vvb.flags = 0; + if (fill_buf_done->flags1 & HAL_BUFFERFLAG_READONLY) + mbuf->vvb.flags |= V4L2_QCOM_BUF_FLAG_READONLY; + if (fill_buf_done->flags1 & HAL_BUFFERFLAG_EOS) + mbuf->vvb.flags |= V4L2_QCOM_BUF_FLAG_EOS; + if (fill_buf_done->flags1 & HAL_BUFFERFLAG_CODECCONFIG) + mbuf->vvb.flags |= V4L2_QCOM_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_QCOM_BUF_END_OF_SUBFRAME; + switch (fill_buf_done->picture_type) { + case HAL_PICTURE_P: + mbuf->vvb.flags |= V4L2_BUF_FLAG_PFRAME; + break; + case HAL_PICTURE_B: + mbuf->vvb.flags |= V4L2_BUF_FLAG_BFRAME; + break; + case HAL_FRAME_NOTCODED: + case HAL_UNUSED_PICT: + /* Do we need to care about these? */ + case HAL_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: + put_inst(inst); +} + +void handle_cmd_response(enum hal_command_response cmd, void *data) +{ + dprintk(VIDC_DBG, "Command response = %d\n", cmd); + 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: + dprintk(VIDC_DBG, "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) +{ + 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) { + dprintk(VIDC_DBG, + "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); + dprintk(VIDC_DBG, + "Core freq %ld Thermal level %d Turbo mode %d\n", + freq, tl, is_turbo); + + if (is_turbo && tl >= VIDC_THERMAL_LOW) { + dprintk(VIDC_ERR, + "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) +{ + bool allowed = false; + + if (!inst || !inst->core) + return false; + + /* + * Enable decode batching based on below conditions + * - platform supports batching + * - decode session and H264/HEVC/VP9 format + * - session resolution <= 1080p + * - low latency not enabled + * - not a thumbnail session + * - UBWC color format + */ + if (inst->decode_batching && is_decode_session(inst) && + (inst->fmts[OUTPUT_PORT].fourcc == V4L2_PIX_FMT_H264 || + inst->fmts[OUTPUT_PORT].fourcc == V4L2_PIX_FMT_HEVC || + inst->fmts[OUTPUT_PORT].fourcc == V4L2_PIX_FMT_VP9) && + (msm_vidc_get_mbs_per_frame(inst) <= + NUM_MBS_PER_FRAME(MAX_DEC_BATCH_HEIGHT, MAX_DEC_BATCH_WIDTH)) && + !inst->clk_data.low_latency_mode && + !is_thumbnail_session(inst) && + (inst->fmts[CAPTURE_PORT].fourcc == V4L2_PIX_FMT_NV12_UBWC || + inst->fmts[CAPTURE_PORT].fourcc == V4L2_PIX_FMT_NV12_TP10_UBWC)) + allowed = true; + + return allowed; +} + +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) { + dprintk(VIDC_ERR, "%s invalid params\n", __func__); + return -EINVAL; + } + hdev = inst->core->device; + abort_completion = SESSION_MSG_INDEX(HAL_SESSION_ABORT_DONE); + + dprintk(VIDC_WARN, "%s: inst %pK session %x\n", __func__, + inst, hash32_ptr(inst->session)); + rc = call_hfi_op(hdev, session_abort, (void *)inst->session); + if (rc) { + dprintk(VIDC_ERR, + "%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) { + dprintk(VIDC_ERR, "%s: inst %pK session %x abort timed out\n", + __func__, inst, hash32_ptr(inst->session)); + 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) { + dprintk(VIDC_ERR, "%s Invalid params\n", __func__); + 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) { + dprintk(VIDC_WARN, "%s: abort inst %pK\n", + __func__, inst); + rc = msm_comm_session_abort(inst); + if (rc) { + dprintk(VIDC_ERR, + "%s session_abort failed rc: %d\n", + __func__, rc); + goto err_sess_abort; + } + change_inst_state(inst, MSM_VIDC_CORE_INVALID); + dprintk(VIDC_WARN, + "%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)) { + dprintk(VIDC_WARN, + "Thermal level critical, stop all active sessions!\n"); + handle_thermal_event(core); + } + } +} + +int msm_comm_check_core_init(struct msm_vidc_core *core) +{ + int rc = 0; + + mutex_lock(&core->lock); + if (core->state >= VIDC_CORE_INIT_DONE) { + dprintk(VIDC_INFO, "Video core: %d is already in state: %d\n", + core->id, core->state); + goto exit; + } + dprintk(VIDC_DBG, "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) { + dprintk(VIDC_ERR, "%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; + } + dprintk(VIDC_DBG, "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); + if (rc) { + dprintk(VIDC_ERR, "%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 = 0; + 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) { + dprintk(VIDC_INFO, "Video core: %d is already in state: %d\n", + core->id, core->state); + goto core_already_inited; + } + if (!core->capabilities) { + core->capabilities = kcalloc(VIDC_MAX_SESSIONS, + sizeof(struct msm_vidc_capability), GFP_KERNEL); + if (!core->capabilities) { + dprintk(VIDC_ERR, + "%s: failed to allocate capabilities\n", + __func__); + rc = -ENOMEM; + goto fail_cap_alloc; + } + } else { + dprintk(VIDC_WARN, + "%s: capabilities memory is expected to be freed\n", + __func__); + } + dprintk(VIDC_DBG, "%s: core %pK\n", __func__, core); + rc = call_hfi_op(hdev, core_init, hdev->hfi_device_data); + if (rc) { + dprintk(VIDC_ERR, "Failed to init core, id = %d\n", + core->id); + goto fail_core_init; + } + core->state = VIDC_CORE_INIT; + core->smmu_fault_handled = false; + core->trigger_ssr = false; + +core_already_inited: + change_inst_state(inst, MSM_VIDC_CORE_INIT); + mutex_unlock(&core->lock); + + rc = msm_comm_scale_clocks_and_bus(inst); + return rc; + +fail_core_init: + kfree(core->capabilities); +fail_cap_alloc: + core->capabilities = NULL; + 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) { + dprintk(VIDC_ERR, "%s invalid parameters\n", __func__); + return -EINVAL; + } + + core = inst->core; + hdev = core->device; + + mutex_lock(&core->lock); + if (core->state == VIDC_CORE_UNINIT) { + dprintk(VIDC_INFO, "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); + + 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)); + + dprintk(VIDC_DBG, "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; + + dprintk(VIDC_DBG, "inst %pK: waiting for session init done\n", inst); + rc = wait_for_state(inst, flipped_state, MSM_VIDC_OPEN_DONE, + HAL_SESSION_INIT_DONE); + if (rc) { + dprintk(VIDC_ERR, "Session init failed for inst %pK\n", inst); + msm_comm_generate_sys_error(inst); + return rc; + } + + return rc; +} + +static int msm_comm_init_buffer_count(struct msm_vidc_inst *inst) +{ + int extra_buff_count = 0; + struct hal_buffer_requirements *bufreq; + int rc = 0; + int port; + + if (!is_decode_session(inst) && !is_encode_session(inst)) + return 0; + + if (is_decode_session(inst)) + port = OUTPUT_PORT; + else + port = CAPTURE_PORT; + + /* Update input buff counts */ + bufreq = get_buff_req_buffer(inst, HAL_BUFFER_INPUT); + if (!bufreq) + return -EINVAL; + + extra_buff_count = msm_vidc_get_extra_buff_count(inst, + HAL_BUFFER_INPUT); + bufreq->buffer_count_min = inst->fmts[port].input_min_count; + /* batching needs minimum batch size count of input buffers */ + if (is_batching_allowed(inst) && + bufreq->buffer_count_min < inst->batch.size) + bufreq->buffer_count_min = inst->batch.size; + bufreq->buffer_count_min_host = bufreq->buffer_count_actual = + bufreq->buffer_count_min + extra_buff_count; + + dprintk(VIDC_DBG, "%s: %x : input min %d min_host %d actual %d\n", + __func__, hash32_ptr(inst->session), + bufreq->buffer_count_min, bufreq->buffer_count_min_host, + bufreq->buffer_count_actual); + + rc = msm_comm_set_buffer_count(inst, + bufreq->buffer_count_min, + bufreq->buffer_count_actual, HAL_BUFFER_INPUT); + if (rc) { + dprintk(VIDC_ERR, + "%s: Failed to set in buffer count to FW\n", + __func__); + return -EINVAL; + } + + bufreq = get_buff_req_buffer(inst, HAL_BUFFER_EXTRADATA_INPUT); + if (!bufreq) + return -EINVAL; + + bufreq->buffer_count_min = inst->fmts[port].input_min_count; + bufreq->buffer_count_min_host = bufreq->buffer_count_actual = + bufreq->buffer_count_min + extra_buff_count; + + /* Update output buff count */ + bufreq = get_buff_req_buffer(inst, HAL_BUFFER_OUTPUT); + if (!bufreq) + return -EINVAL; + + extra_buff_count = msm_vidc_get_extra_buff_count(inst, + HAL_BUFFER_OUTPUT); + bufreq->buffer_count_min = inst->fmts[port].output_min_count; + bufreq->buffer_count_min_host = bufreq->buffer_count_actual = + bufreq->buffer_count_min + extra_buff_count; + + dprintk(VIDC_DBG, "%s: %x : output min %d min_host %d actual %d\n", + __func__, hash32_ptr(inst->session), + bufreq->buffer_count_min, bufreq->buffer_count_min_host, + bufreq->buffer_count_actual); + + rc = msm_comm_set_buffer_count(inst, + bufreq->buffer_count_min, + bufreq->buffer_count_actual, HAL_BUFFER_OUTPUT); + if (rc) { + dprintk(VIDC_ERR, + "%s: Failed to set out buffer count to FW\n", + __func__); + return -EINVAL; + } + + bufreq = get_buff_req_buffer(inst, HAL_BUFFER_EXTRADATA_OUTPUT); + if (!bufreq) + return -EINVAL; + + bufreq->buffer_count_min = inst->fmts[port].output_min_count; + bufreq->buffer_count_min_host = bufreq->buffer_count_actual = + bufreq->buffer_count_min + extra_buff_count; + + return 0; +} + +static int msm_comm_session_init(int flipped_state, + struct msm_vidc_inst *inst) +{ + int rc = 0; + int fourcc = 0; + struct hfi_device *hdev; + + if (!inst || !inst->core || !inst->core->device) { + dprintk(VIDC_ERR, "%s invalid parameters\n", __func__); + return -EINVAL; + } + hdev = inst->core->device; + + if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_OPEN)) { + dprintk(VIDC_INFO, "inst: %pK is already in state: %d\n", + inst, inst->state); + goto exit; + } + if (inst->session_type == MSM_VIDC_DECODER) { + fourcc = inst->fmts[OUTPUT_PORT].fourcc; + } else if (inst->session_type == MSM_VIDC_ENCODER) { + fourcc = inst->fmts[CAPTURE_PORT].fourcc; + } else if (inst->session_type == MSM_VIDC_CVP) { + fourcc = V4L2_PIX_FMT_CVP; + } else { + dprintk(VIDC_ERR, "Invalid session\n"); + return -EINVAL; + } + + rc = msm_comm_init_clocks_and_bus_data(inst); + if (rc) { + dprintk(VIDC_ERR, "Failed to initialize clocks and bus data\n"); + goto exit; + } + + dprintk(VIDC_DBG, "%s: inst %pK\n", __func__, inst); + rc = call_hfi_op(hdev, session_init, hdev->hfi_device_data, + inst, get_hal_domain(inst->session_type), + get_hal_codec(fourcc), + &inst->session); + + if (rc || !inst->session) { + dprintk(VIDC_ERR, + "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_init_buffer_count(inst); + if (rc) { + dprintk(VIDC_ERR, "Failed to initialize buff counts\n"); + goto exit; + } + change_inst_state(inst, MSM_VIDC_OPEN); + +exit: + return rc; +} + +static void msm_vidc_print_running_insts(struct msm_vidc_core *core) +{ + struct msm_vidc_inst *temp; + int op_rate = 0; + + dprintk(VIDC_ERR, "Running instances:\n"); + dprintk(VIDC_ERR, "%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) { + if (temp->state >= MSM_VIDC_OPEN_DONE && + temp->state < MSM_VIDC_STOP_DONE) { + char properties[4] = ""; + + 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 (temp->clk_data.operating_rate) + op_rate = temp->clk_data.operating_rate >> 16; + else + op_rate = temp->prop.fps; + + dprintk(VIDC_ERR, "%4d|%4d|%4d|%4d|%4d|%4s\n", + temp->session_type, + max(temp->prop.width[CAPTURE_PORT], + temp->prop.width[OUTPUT_PORT]), + max(temp->prop.height[CAPTURE_PORT], + temp->prop.height[OUTPUT_PORT]), + temp->prop.fps, 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; + int num_mbs_per_sec = 0, max_load_adj = 0; + struct msm_vidc_core *core; + enum load_calc_quirks quirks = LOAD_CALC_IGNORE_TURBO_LOAD | + LOAD_CALC_IGNORE_THUMBNAIL_LOAD | + LOAD_CALC_IGNORE_NON_REALTIME_LOAD; + + if (!inst || !inst->core || !inst->core->device) { + dprintk(VIDC_ERR, "%s invalid parameters\n", __func__); + return -EINVAL; + } + if (inst->state == MSM_VIDC_CORE_INVALID) { + dprintk(VIDC_ERR, + "%s: inst %pK is in invalid state\n", __func__, inst); + return -EINVAL; + } + if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_LOAD_RESOURCES)) { + dprintk(VIDC_INFO, "inst: %pK is already in state: %d\n", + inst, inst->state); + goto exit; + } + core = inst->core; + + num_mbs_per_sec = + msm_comm_get_load(core, MSM_VIDC_DECODER, quirks) + + msm_comm_get_load(core, MSM_VIDC_ENCODER, quirks); + + max_load_adj = core->resources.max_load + + inst->capability.mbs_per_frame.max; + + if (num_mbs_per_sec > max_load_adj) { + dprintk(VIDC_ERR, "HW is overloaded, needed: %d max: %d\n", + num_mbs_per_sec, max_load_adj); + msm_vidc_print_running_insts(core); + msm_comm_kill_session(inst); + return -EBUSY; + } + + hdev = core->device; + dprintk(VIDC_DBG, "%s: inst %pK\n", __func__, inst); + rc = call_hfi_op(hdev, session_load_res, (void *) inst->session); + if (rc) { + dprintk(VIDC_ERR, + "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) { + dprintk(VIDC_ERR, "%s invalid parameters\n", __func__); + return -EINVAL; + } + if (inst->state == MSM_VIDC_CORE_INVALID) { + dprintk(VIDC_ERR, + "%s: inst %pK is in invalid\n", __func__, inst); + return -EINVAL; + } + if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_START)) { + dprintk(VIDC_INFO, + "inst: %pK is already in state: %d\n", + inst, inst->state); + goto exit; + } + hdev = inst->core->device; + dprintk(VIDC_DBG, "%s: inst %pK\n", __func__, inst); + rc = call_hfi_op(hdev, session_start, (void *) inst->session); + if (rc) { + dprintk(VIDC_ERR, + "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) { + dprintk(VIDC_ERR, "%s invalid parameters\n", __func__); + return -EINVAL; + } + if (inst->state == MSM_VIDC_CORE_INVALID) { + dprintk(VIDC_ERR, + "%s: inst %pK is in invalid state\n", __func__, inst); + return -EINVAL; + } + if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_STOP)) { + dprintk(VIDC_INFO, + "inst: %pK is already in state: %d\n", + inst, inst->state); + goto exit; + } + hdev = inst->core->device; + dprintk(VIDC_DBG, "%s: inst %pK\n", __func__, inst); + rc = call_hfi_op(hdev, session_stop, (void *) inst->session); + if (rc) { + dprintk(VIDC_ERR, "%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) { + dprintk(VIDC_ERR, "%s invalid parameters\n", __func__); + return -EINVAL; + } + if (inst->state == MSM_VIDC_CORE_INVALID) { + dprintk(VIDC_ERR, + "%s: inst %pK is in invalid state\n", __func__, inst); + return -EINVAL; + } + if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_RELEASE_RESOURCES)) { + dprintk(VIDC_INFO, + "inst: %pK is already in state: %d\n", + inst, inst->state); + goto exit; + } + hdev = inst->core->device; + dprintk(VIDC_DBG, "%s: inst %pK\n", __func__, inst); + rc = call_hfi_op(hdev, session_release_res, (void *) inst->session); + if (rc) { + dprintk(VIDC_ERR, + "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) { + dprintk(VIDC_ERR, "%s invalid params\n", __func__); + return -EINVAL; + } + if (IS_ALREADY_IN_STATE(flipped_state, MSM_VIDC_CLOSE)) { + dprintk(VIDC_INFO, + "inst: %pK is already in state: %d\n", + inst, inst->state); + goto exit; + } + hdev = inst->core->device; + dprintk(VIDC_DBG, "%s: inst %pK\n", __func__, inst); + rc = call_hfi_op(hdev, session_end, (void *) inst->session); + if (rc) { + dprintk(VIDC_ERR, + "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) { + dprintk(VIDC_ERR, + "%s: Failed to find core for core_id = %d\n", + __func__, core_id); + return -EINVAL; + } + + hdev = (struct hfi_device *)core->device; + if (!hdev) { + dprintk(VIDC_ERR, "%s Invalid device handle\n", __func__); + return -EINVAL; + } + + rc = call_hfi_op(hdev, suspend, hdev->hfi_device_data); + if (rc) + dprintk(VIDC_WARN, "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) { + dprintk(VIDC_ERR, "%s: invalid params\n", __func__); + return -EINVAL; + } + + bufreqs = get_buff_req_buffer(inst, buf_type); + if (!bufreqs) { + dprintk(VIDC_ERR, "%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; +} + +int msm_comm_copy_bufreqs(struct msm_vidc_inst *inst, enum hal_buffer src_type, + enum hal_buffer dst_type) +{ + struct hal_buffer_requirements *src_bufreqs; + struct hal_buffer_requirements *dst_bufreqs; + + if (!inst) { + dprintk(VIDC_ERR, "%s: invalid params\n", __func__); + return -EINVAL; + } + + src_bufreqs = get_buff_req_buffer(inst, src_type); + dst_bufreqs = get_buff_req_buffer(inst, dst_type); + if (!src_bufreqs || !dst_bufreqs) { + dprintk(VIDC_ERR, "%s: invalid buf type: src %d dst %d\n", + __func__, src_type, dst_type); + return -EINVAL; + } + dst_bufreqs->buffer_size = src_bufreqs->buffer_size; + dst_bufreqs->buffer_region_size = src_bufreqs->buffer_region_size; + dst_bufreqs->buffer_count_min = src_bufreqs->buffer_count_min; + dst_bufreqs->buffer_count_min_host = src_bufreqs->buffer_count_min_host; + dst_bufreqs->buffer_count_actual = src_bufreqs->buffer_count_actual; + dst_bufreqs->contiguous = src_bufreqs->contiguous; + dst_bufreqs->buffer_alignment = src_bufreqs->buffer_alignment; + + 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]; + } + dprintk(VIDC_ERR, "Failed to get buff req for : %x", buffer_type); + return NULL; +} + +static int set_output_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; + struct hal_buffer_requirements *output_buf, *extradata_buf; + int i; + struct hfi_device *hdev; + struct hal_buffer_size_minimum b; + + hdev = inst->core->device; + + output_buf = get_buff_req_buffer(inst, buffer_type); + if (!output_buf) { + dprintk(VIDC_DBG, + "This output buffer not required, buffer_type: %x\n", + buffer_type); + return 0; + } + + /* For DPB buffers, Always use FW count */ + output_buf->buffer_count_actual = output_buf->buffer_count_min_host = + output_buf->buffer_count_min; + + dprintk(VIDC_DBG, + "output: num = %d, size = %d\n", + output_buf->buffer_count_actual, + output_buf->buffer_size); + + buffer_size = output_buf->buffer_size; + b.buffer_type = buffer_type; + b.buffer_size = buffer_size; + rc = call_hfi_op(hdev, session_set_property, + inst->session, HAL_PARAM_BUFFER_SIZE_MINIMUM, + &b); + + extradata_buf = get_buff_req_buffer(inst, HAL_BUFFER_EXTRADATA_OUTPUT); + if (extradata_buf) { + dprintk(VIDC_DBG, + "extradata: num = %d, size = %d\n", + extradata_buf->buffer_count_actual, + extradata_buf->buffer_size); + buffer_size += extradata_buf->buffer_size; + } else { + dprintk(VIDC_DBG, + "This extradata buffer not required, buffer_type: %x\n", + buffer_type); + } + + if (inst->flags & VIDC_SECURE) + smem_flags |= SMEM_SECURE; + + if (output_buf->buffer_size) { + for (i = 0; i < output_buf->buffer_count_actual; + i++) { + binfo = kzalloc(sizeof(*binfo), GFP_KERNEL); + if (!binfo) { + dprintk(VIDC_ERR, "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) { + dprintk(VIDC_ERR, + "Failed to allocate output memory\n"); + goto err_no_mem; + } + binfo->buffer_type = buffer_type; + binfo->buffer_ownership = DRIVER; + dprintk(VIDC_DBG, "Output buffer address: %#x\n", + binfo->smem.device_addr); + + if (inst->buffer_mode_set[CAPTURE_PORT] == + HAL_BUFFER_MODE_STATIC) { + struct vidc_buffer_addr_info buffer_info = {0}; + + buffer_info.buffer_size = + output_buf->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 = + binfo->smem.device_addr + + output_buf->buffer_size; + if (extradata_buf) + buffer_info.extradata_size = + extradata_buf->buffer_size; + rc = call_hfi_op(hdev, session_set_buffers, + (void *) inst->session, &buffer_info); + if (rc) { + dprintk(VIDC_ERR, + "%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) { + dprintk(VIDC_ERR, "%s - invalid params\n", __func__); + 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; + dprintk(VIDC_DBG, "%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) { + dprintk(VIDC_ERR, + "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) { + dprintk(VIDC_ERR, "%s: invalid params\n", __func__); + 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) { + dprintk(VIDC_ERR, + "%s: session_set_buffers failed\n", + __func__); + reused = false; + break; + } + } + reused = true; + dprintk(VIDC_DBG, + "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; + 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) { + dprintk(VIDC_ERR, "Out of memory\n"); + 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) { + dprintk(VIDC_ERR, + "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) { + dprintk(VIDC_DBG, + "This internal buffer not required, buffer_type: %x\n", + buffer_type); + return 0; + } + + dprintk(VIDC_DBG, "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) { + dprintk(VIDC_ERR, "%s: invalid params %pK", __func__, inst); + return -EINVAL; + } + dprintk(VIDC_DBG, + "Trying to move inst: %pK (%#x) from: %#x to %#x\n", + inst, hash32_ptr(inst->session), inst->state, state); + + mutex_lock(&inst->sync_lock); + if (inst->state == MSM_VIDC_CORE_INVALID) { + dprintk(VIDC_ERR, "%s: inst %pK is in invalid\n", + __func__, inst); + rc = -EINVAL; + goto exit; + } + + flipped_state = get_flipped_state(inst->state, state); + dprintk(VIDC_DBG, + "inst: %pK (%#x) flipped_state = %#x\n", + inst, hash32_ptr(inst->session), 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; + dprintk(VIDC_DBG, "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; + dprintk(VIDC_DBG, + "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: + dprintk(VIDC_DBG, "Sending core uninit\n"); + rc = msm_vidc_deinit_core(inst); + if (rc || state == get_flipped_state(inst->state, state)) + break; + default: + dprintk(VIDC_ERR, "State not recognized\n"); + rc = -EINVAL; + break; + } + +exit: + mutex_unlock(&inst->sync_lock); + + if (rc) { + dprintk(VIDC_ERR, + "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) { + dprintk(VIDC_ERR, "%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.buffer_type = HAL_BUFFER_INPUT; + data.filled_len = 0; + data.offset = 0; + data.flags = HAL_BUFFERFLAG_EOS; + data.timestamp = 0; + data.extradata_addr = data.device_addr; + data.extradata_size = 0; + dprintk(VIDC_DBG, "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) { + dprintk(VIDC_ERR, "%s invalid params\n", __func__); + 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_QCOM_CMD_FLUSH: + rc = msm_comm_flush(inst, flags); + if (rc) { + dprintk(VIDC_ERR, + "Failed to flush buffers: %d\n", rc); + } + break; + case V4L2_QCOM_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) { + dprintk(VIDC_DBG, + "Inst = %pK is not ready for EOS\n", inst); + break; + } + + binfo = kzalloc(sizeof(*binfo), GFP_KERNEL); + if (!binfo) { + dprintk(VIDC_ERR, "%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); + dprintk(VIDC_ERR, + "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) { + dprintk(VIDC_ERR, + "Failed pending_eos_buffers sending\n"); + list_del(&binfo->list); + kfree(binfo); + break; + } + break; + } + default: + dprintk(VIDC_ERR, "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; + int extra_idx; + struct vb2_buffer *vb; + struct vb2_v4l2_buffer *vbuf; + struct vidc_tag_data tag_data; + + if (!inst || !mbuf || !data) { + dprintk(VIDC_ERR, "%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; + + if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_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_QCOM_BUF_FLAG_EOS) + data->flags |= HAL_BUFFERFLAG_EOS; + + if (vbuf->flags & V4L2_QCOM_BUF_FLAG_CODECCONFIG) + data->flags |= HAL_BUFFERFLAG_CODECCONFIG; + + if (inst->session_type == MSM_VIDC_DECODER) { + msm_comm_fetch_mark_data(&inst->etb_data, vb->index, + &data->mark_data, &data->mark_target); + } + + } else if (vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + data->buffer_type = msm_comm_get_hal_output_buffer(inst); + } + + tag_data.index = vb->index; + tag_data.type = vb->type; + + msm_comm_fetch_tags(inst, &tag_data); + data->input_tag = tag_data.input_tag; + data->output_tag = tag_data.output_tag; + + + extra_idx = EXTRADATA_IDX(vb->num_planes); + if (extra_idx && extra_idx < VIDEO_MAX_PLANES) { + data->extradata_addr = mbuf->smem[extra_idx].device_addr; + data->extradata_size = vb->planes[extra_idx].length; + data->flags |= HAL_BUFFERFLAG_EXTRADATA; + } +} + +enum hal_buffer get_hal_buffer_type(unsigned int type, + unsigned int plane_num) +{ + if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + if (plane_num == 0) + return HAL_BUFFER_INPUT; + else + return HAL_BUFFER_EXTRADATA_INPUT; + } else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_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) { + dprintk(VIDC_ERR, "%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) { + dprintk(VIDC_ERR, "%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) { + dprintk(VIDC_ERR, "%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 == V4L2_BUF_TYPE_VIDEO_OUTPUT_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 == + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + e = MSM_VIDC_DEBUGFS_EVENT_FTB; + rc = call_hfi_op(hdev, session_ftb, inst->session, &frame_data); + } else { + dprintk(VIDC_ERR, "%s: invalid qbuf type %d:\n", __func__, + mbuf->vvb.vb2_buf.type); + rc = -EINVAL; + } + if (rc) { + dprintk(VIDC_ERR, "%s: Failed to qbuf: %d\n", __func__, rc); + goto err_bad_input; + } + mbuf->flags |= MSM_VIDC_FLAG_QUEUED; + msm_vidc_debugfs_update(inst, e); + +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); + + inst = get_inst(get_vidc_core(MSM_VIDC_CORE_VENUS), inst); + if (!inst) { + dprintk(VIDC_ERR, "%s: invalid params\n", __func__); + return; + } + + if (inst->state == MSM_VIDC_CORE_INVALID) { + dprintk(VIDC_ERR, "%s: invalid state\n", __func__); + goto exit; + } + + rc = msm_comm_scale_clocks_and_bus(inst); + if (rc) + dprintk(VIDC_ERR, "%s: scale clocks failed\n", __func__); + + dprintk(VIDC_INFO, + "%s: queing batch pending buffers to firmware\n", __func__); + + rc = msm_comm_qbufs_batch(inst, NULL); + if (rc) { + dprintk(VIDC_ERR, "%s: Failed batch-qbuf to hfi: %d\n", + __func__, rc); + } + +exit: + put_inst(inst); +} + +static int msm_comm_qbuf_in_rbr(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *mbuf) +{ + int rc = 0; + + if (!inst || !mbuf) { + dprintk(VIDC_ERR, "%s: Invalid arguments\n", __func__); + return -EINVAL; + } + + if (inst->state == MSM_VIDC_CORE_INVALID) { + dprintk(VIDC_ERR, "%s: inst is in bad state\n", __func__); + return -EINVAL; + } + + rc = msm_comm_scale_clocks_and_bus(inst); + if (rc) + dprintk(VIDC_ERR, "%s: scale clocks failed\n", __func__); + + print_vidc_buffer(VIDC_DBG, "qbuf in rbr", inst, mbuf); + rc = msm_comm_qbuf_to_hfi(inst, mbuf); + if (rc) + dprintk(VIDC_ERR, "%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; + + if (!inst || !mbuf) { + dprintk(VIDC_ERR, "%s: Invalid arguments\n", __func__); + return -EINVAL; + } + + if (inst->state == MSM_VIDC_CORE_INVALID) { + dprintk(VIDC_ERR, "%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_DBG, "qbuf deferred", inst, mbuf); + return 0; + } + + rc = msm_comm_scale_clocks_and_bus(inst); + if (rc) + dprintk(VIDC_ERR, "%s: scale clocks failed\n", __func__); + + print_vidc_buffer(VIDC_DBG, "qbuf", inst, mbuf); + rc = msm_comm_qbuf_to_hfi(inst, mbuf); + if (rc) + dprintk(VIDC_ERR, "%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; + + if (!inst) { + dprintk(VIDC_ERR, "%s: Invalid arguments\n", __func__); + return -EINVAL; + } + + if (inst->state != MSM_VIDC_START_DONE) { + dprintk(VIDC_DBG, "%s: inst not in start state: %d\n", + __func__, inst->state); + return 0; + } + + rc = msm_comm_scale_clocks_and_bus(inst); + if (rc) + dprintk(VIDC_ERR, "%s: scale clocks failed\n", __func__); + + mutex_lock(&inst->registeredbufs.lock); + list_for_each_entry(mbuf, &inst->registeredbufs.list, list) { + /* Queue only deferred buffers */ + if (!(mbuf->flags & MSM_VIDC_FLAG_DEFERRED)) + continue; + print_vidc_buffer(VIDC_DBG, "qbufs", inst, mbuf); + rc = msm_comm_qbuf_to_hfi(inst, mbuf); + if (rc) { + dprintk(VIDC_ERR, "%s: Failed qbuf to hfi: %d\n", + __func__, rc); + break; + } + } + mutex_unlock(&inst->registeredbufs.lock); + + 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; + + mutex_lock(&inst->registeredbufs.lock); + list_for_each_entry(buf, &inst->registeredbufs.list, list) { + /* Don't queue if buffer is not CAPTURE_MPLANE */ + if (buf->vvb.vb2_buf.type != + V4L2_BUF_TYPE_VIDEO_CAPTURE_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_DBG, "batch-qbuf", inst, buf); + rc = msm_comm_qbuf_to_hfi(inst, buf); + if (rc) { + dprintk(VIDC_ERR, "%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 || !mbuf) { + dprintk(VIDC_ERR, "%s: Invalid arguments\n", __func__); + return -EINVAL; + } + + if (inst->state == MSM_VIDC_CORE_INVALID) { + dprintk(VIDC_ERR, "%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_DBG, "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) { + mod_timer(&inst->batch_timer, jiffies + + msecs_to_jiffies(MSM_VIDC_QBUF_BATCH_TIMEOUT)); + count = num_pending_qbufs(inst, + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + if (count < inst->batch.size) { + print_vidc_buffer(VIDC_DBG, + "batch-qbuf deferred", inst, mbuf); + return 0; + } + } + + rc = msm_comm_scale_clocks_and_bus(inst); + if (rc) + dprintk(VIDC_ERR, "%s: scale clocks failed\n", __func__); + + rc = msm_comm_qbufs_batch(inst, mbuf); + if (rc) { + dprintk(VIDC_ERR, "%s: Failed qbuf to hfi: %d\n", + __func__, rc); + } + + return rc; +} + +int msm_comm_try_get_bufreqs(struct msm_vidc_inst *inst) +{ + int rc = 0, i = 0; + union hal_get_property hprop; + enum hal_buffer int_buf[] = { + 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, + }; + + memset(&hprop, 0x0, sizeof(hprop)); + + rc = msm_comm_try_get_prop(inst, HAL_PARAM_GET_BUFFER_REQUIREMENTS, + &hprop); + if (rc) { + dprintk(VIDC_ERR, "Failed getting buffer requirements: %d", rc); + return rc; + } + + /* reset internal buffers */ + for (i = 0; i < ARRAY_SIZE(int_buf); i++) + msm_comm_reset_bufreqs(inst, int_buf[i]); + + dprintk(VIDC_DBG, "Buffer requirements from HW:\n"); + dprintk(VIDC_DBG, "%15s %8s %8s %8s %8s\n", + "buffer type", "count", "mincount_host", "mincount_fw", "size"); + for (i = 0; i < HAL_BUFFER_MAX; i++) { + struct hal_buffer_requirements req = hprop.buf_req.buffer[i]; + struct hal_buffer_requirements *curr_req; + + /* + * For decoder we can ignore the buffer counts that firmware + * sends for inp/out buffers. + * FW buffer counts for these are used only in reconfig + */ + curr_req = get_buff_req_buffer(inst, req.buffer_type); + if (!curr_req) + return -EINVAL; + + if (req.buffer_type == HAL_BUFFER_INPUT || + req.buffer_type == HAL_BUFFER_OUTPUT || + req.buffer_type == HAL_BUFFER_OUTPUT2 || + req.buffer_type == HAL_BUFFER_EXTRADATA_INPUT || + req.buffer_type == HAL_BUFFER_EXTRADATA_OUTPUT || + req.buffer_type == HAL_BUFFER_EXTRADATA_OUTPUT2) { + curr_req->buffer_size = req.buffer_size; + curr_req->buffer_region_size = req.buffer_region_size; + curr_req->contiguous = req.contiguous; + curr_req->buffer_alignment = req.buffer_alignment; + } else { + memcpy(curr_req, &req, + sizeof(struct hal_buffer_requirements)); + } + + if (req.buffer_type != HAL_BUFFER_NONE) { + dprintk(VIDC_DBG, "%15s %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); + } + } + + dprintk(VIDC_DBG, "Buffer requirements driver adjusted:\n"); + dprintk(VIDC_DBG, "%15s %8s %8s %8s %8s\n", + "buffer type", "count", "mincount_host", "mincount_fw", "size"); + 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) { + dprintk(VIDC_DBG, "%15s %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); + } + } + return rc; +} + +int msm_comm_try_get_prop(struct msm_vidc_inst *inst, enum hal_property ptype, + union hal_get_property *hprop) +{ + int rc = 0; + struct hfi_device *hdev; + struct getprop_buf *buf; + + if (!inst || !inst->core || !inst->core->device) { + dprintk(VIDC_ERR, "%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. + */ + + dprintk(VIDC_ERR, + "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); + + switch (ptype) { + case HAL_PARAM_GET_BUFFER_REQUIREMENTS: + rc = call_hfi_op(hdev, session_get_buf_req, inst->session); + break; + default: + rc = -EAGAIN; + break; + } + + if (rc) { + dprintk(VIDC_ERR, "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) { + dprintk(VIDC_ERR, + "%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 { + dprintk(VIDC_ERR, "%s getprop list empty\n", __func__); + rc = -EINVAL; + } + mutex_unlock(&inst->pending_getpropq.lock); +exit: + return rc; +} + +int msm_comm_release_output_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) { + dprintk(VIDC_ERR, + "Invalid instance pointer = %pK\n", inst); + return -EINVAL; + } + mutex_lock(&inst->outputbufs.lock); + if (list_empty(&inst->outputbufs.list)) { + dprintk(VIDC_DBG, "%s - No OUTPUT buffers allocated\n", + __func__); + mutex_unlock(&inst->outputbufs.lock); + return 0; + } + mutex_unlock(&inst->outputbufs.lock); + + core = inst->core; + if (!core) { + dprintk(VIDC_ERR, + "Invalid core pointer = %pK\n", core); + return -EINVAL; + } + hdev = core->device; + if (!hdev) { + dprintk(VIDC_ERR, "Invalid device pointer = %pK\n", hdev); + 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) { + dprintk(VIDC_INFO, "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[CAPTURE_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) { + dprintk(VIDC_WARN, + "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); + } + + 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) { + dprintk(VIDC_ERR, "%s - invalid param\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; + + dprintk(VIDC_DBG, + "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) { + dprintk(VIDC_ERR, + "Invalid instance pointer = %pK\n", inst); + return -EINVAL; + } + core = inst->core; + if (!core) { + dprintk(VIDC_ERR, + "Invalid core pointer = %pK\n", core); + return -EINVAL; + } + hdev = core->device; + if (!hdev) { + dprintk(VIDC_ERR, "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) + dprintk(VIDC_WARN, + "%s: wait for signal failed, rc %d\n", + __func__, rc); + mutex_lock(&inst->scratchbufs.lock); + } else { + dprintk(VIDC_WARN, + "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) { + dprintk(VIDC_ERR, + "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) { + dprintk(VIDC_ERR, + "Invalid instance pointer = %pK\n", inst); + return -EINVAL; + } + + mutex_lock(&inst->reconbufs.lock); + list_for_each_entry_safe(buf, next, &inst->reconbufs.list, list) { + list_del(&buf->list); + kfree(buf); + } + INIT_LIST_HEAD(&inst->reconbufs.list); + mutex_unlock(&inst->reconbufs.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) { + dprintk(VIDC_ERR, + "Invalid instance pointer = %pK\n", inst); + return -EINVAL; + } + core = inst->core; + if (!core) { + dprintk(VIDC_ERR, + "Invalid core pointer = %pK\n", core); + return -EINVAL; + } + hdev = core->device; + if (!hdev) { + dprintk(VIDC_ERR, "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) + dprintk(VIDC_WARN, + "%s: wait for signal failed, rc %d\n", + __func__, rc); + mutex_lock(&inst->persistbufs.lock); + } else { + dprintk(VIDC_WARN, + "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_try_set_prop(struct msm_vidc_inst *inst, + enum hal_property ptype, void *pdata) +{ + int rc = 0; + struct hfi_device *hdev; + + if (!inst) { + dprintk(VIDC_ERR, "Invalid input: %pK\n", inst); + return -EINVAL; + } + + if (!inst->core || !inst->core->device) { + dprintk(VIDC_ERR, "%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) { + dprintk(VIDC_ERR, "Not in proper state to set property\n"); + rc = -EAGAIN; + goto exit; + } + rc = call_hfi_op(hdev, session_set_property, (void *)inst->session, + ptype, pdata); + if (rc) + dprintk(VIDC_ERR, "Failed to set hal property for framesize\n"); +exit: + mutex_unlock(&inst->sync_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 hfi_device *hdev; + struct hal_buffer_count_actual buf_count; + + hdev = inst->core->device; + + buf_count.buffer_type = type; + buf_count.buffer_count_actual = act_count; + buf_count.buffer_count_min_host = host_count; + dprintk(VIDC_DBG, "%s: %x : hal_buffer %d min_host %d actual %d\n", + __func__, hash32_ptr(inst->session), type, + host_count, act_count); + rc = call_hfi_op(hdev, session_set_property, + inst->session, HAL_PARAM_BUFFER_COUNT_ACTUAL, &buf_count); + if (rc) + dprintk(VIDC_ERR, + "Failed to set actual buffer count %d for buffer type %d\n", + act_count, type); + return rc; +} + +int msm_comm_set_output_buffers(struct msm_vidc_inst *inst) +{ + int rc = 0; + bool force_release = true; + + if (!inst || !inst->core || !inst->core->device) { + dprintk(VIDC_ERR, "%s invalid parameters\n", __func__); + return -EINVAL; + } + + if (inst->fmts[OUTPUT_PORT].defer_outputs) + force_release = false; + + if (msm_comm_release_output_buffers(inst, force_release)) + dprintk(VIDC_WARN, "Failed to release output buffers\n"); + + rc = set_output_buffers(inst, HAL_BUFFER_OUTPUT); + if (rc) + goto error; + return rc; +error: + msm_comm_release_output_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) { + dprintk(VIDC_ERR, "%s invalid parameters\n", __func__); + return -EINVAL; + } + + if (msm_comm_release_scratch_buffers(inst, true)) + dprintk(VIDC_WARN, "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, i = 0; + struct hal_buffer_requirements *internal_buf; + struct recon_buf *binfo; + struct msm_vidc_list *buf_list = &inst->reconbufs; + + if (!inst) { + dprintk(VIDC_ERR, "%s invalid parameters\n", __func__); + return -EINVAL; + } + + if (inst->session_type == MSM_VIDC_ENCODER) + internal_buf = get_buff_req_buffer(inst, + HAL_BUFFER_INTERNAL_RECON); + else if (inst->session_type == MSM_VIDC_DECODER) + internal_buf = get_buff_req_buffer(inst, + msm_comm_get_hal_output_buffer(inst)); + else + return -EINVAL; + + if (!internal_buf || !internal_buf->buffer_count_actual) { + dprintk(VIDC_DBG, "Inst : %pK Recon buffers not required\n", + inst); + return 0; + } + + msm_comm_release_recon_buffers(inst); + + for (i = 0; i < internal_buf->buffer_count_actual; i++) { + binfo = kzalloc(sizeof(*binfo), GFP_KERNEL); + if (!binfo) { + dprintk(VIDC_ERR, "Out of memory\n"); + 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) { + dprintk(VIDC_ERR, "%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[] = {OUTPUT_PORT, CAPTURE_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(VIDC_ERR, "flush in invalid", + inst, vb); + vb2_buffer_done(vb, VB2_BUF_STATE_DONE); + } else { + dprintk(VIDC_WARN, + "%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) +{ + int i, 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) { + dprintk(VIDC_ERR, + "Invalid params, inst %pK\n", inst); + return -EINVAL; + } + + if (inst->state < MSM_VIDC_OPEN_DONE) { + dprintk(VIDC_ERR, + "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_QCOM_CMD_FLUSH_OUTPUT; + op_flush = flags & V4L2_QCOM_CMD_FLUSH_CAPTURE; + + if (ip_flush && !op_flush) { + dprintk(VIDC_WARN, + "Input only flush not supported, making it flush all\n"); + op_flush = true; + return 0; + } + + msm_clock_data_reset(inst); + + if (inst->state == MSM_VIDC_CORE_INVALID) { + dprintk(VIDC_ERR, + "Core %pK and inst %pK are in bad state\n", + core, inst); + msm_comm_flush_in_invalid_state(inst); + return 0; + } + + if (ip_flush) + mutex_lock(&inst->bufq[OUTPUT_PORT].lock); + if (op_flush) + mutex_lock(&inst->bufq[CAPTURE_PORT].lock); + + /* enable in flush */ + inst->in_flush = true; + + 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 == + V4L2_BUF_TYPE_VIDEO_OUTPUT_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_DBG, "flush buf", inst, mbuf); + msm_comm_flush_vidc_buffer(inst, mbuf); + + for (i = 0; i < mbuf->vvb.vb2_buf.num_planes; i++) { + if (msm_smem_unmap_dma_buf(inst, &mbuf->smem[i])) + print_vidc_buffer(VIDC_ERR, + "dqbuf: unmap failed.", inst, mbuf); + if (msm_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) { + dprintk(VIDC_DBG, "Send flush on all ports to firmware\n"); + rc = call_hfi_op(hdev, session_flush, inst->session, + HAL_FLUSH_ALL); + } else { + dprintk(VIDC_DBG, "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[CAPTURE_PORT].lock); + if (ip_flush) + mutex_unlock(&inst->bufq[OUTPUT_PORT].lock); + + if (rc) { + dprintk(VIDC_ERR, + "Sending flush to firmware failed, flush out all buffers\n"); + msm_comm_flush_in_invalid_state(inst); + /* disable in_flush */ + inst->in_flush = false; + } + + return rc; +} + +enum hal_extradata_id msm_comm_get_hal_extradata_index( + enum v4l2_mpeg_vidc_extradata index) +{ + int ret = 0; + + switch (index) { + case V4L2_MPEG_VIDC_EXTRADATA_NONE: + ret = HAL_EXTRADATA_NONE; + break; + case V4L2_MPEG_VIDC_EXTRADATA_INTERLACE_VIDEO: + ret = HAL_EXTRADATA_INTERLACE_VIDEO; + break; + case V4L2_MPEG_VIDC_EXTRADATA_TIMESTAMP: + ret = HAL_EXTRADATA_TIMESTAMP; + break; + case V4L2_MPEG_VIDC_EXTRADATA_S3D_FRAME_PACKING: + ret = HAL_EXTRADATA_S3D_FRAME_PACKING; + break; + case V4L2_MPEG_VIDC_EXTRADATA_FRAME_RATE: + ret = HAL_EXTRADATA_FRAME_RATE; + break; + case V4L2_MPEG_VIDC_EXTRADATA_PANSCAN_WINDOW: + ret = HAL_EXTRADATA_PANSCAN_WINDOW; + break; + case V4L2_MPEG_VIDC_EXTRADATA_RECOVERY_POINT_SEI: + ret = HAL_EXTRADATA_RECOVERY_POINT_SEI; + break; + case V4L2_MPEG_VIDC_EXTRADATA_NUM_CONCEALED_MB: + ret = HAL_EXTRADATA_NUM_CONCEALED_MB; + break; + case V4L2_MPEG_VIDC_EXTRADATA_ASPECT_RATIO: + ret = HAL_EXTRADATA_ASPECT_RATIO; + break; + case V4L2_MPEG_VIDC_EXTRADATA_MPEG2_SEQDISP: + ret = HAL_EXTRADATA_MPEG2_SEQDISP; + break; + case V4L2_MPEG_VIDC_EXTRADATA_STREAM_USERDATA: + ret = HAL_EXTRADATA_STREAM_USERDATA; + break; + case V4L2_MPEG_VIDC_EXTRADATA_FRAME_QP: + ret = HAL_EXTRADATA_DEC_FRAME_QP; + break; + case V4L2_MPEG_VIDC_EXTRADATA_ENC_FRAME_QP: + ret = HAL_EXTRADATA_ENC_FRAME_QP; + break; + case V4L2_MPEG_VIDC_EXTRADATA_LTR: + ret = HAL_EXTRADATA_LTR_INFO; + break; + case V4L2_MPEG_VIDC_EXTRADATA_ROI_QP: + ret = HAL_EXTRADATA_ROI_QP; + break; + case V4L2_MPEG_VIDC_EXTRADATA_OUTPUT_CROP: + ret = HAL_EXTRADATA_OUTPUT_CROP; + break; + case V4L2_MPEG_VIDC_EXTRADATA_DISPLAY_COLOUR_SEI: + ret = HAL_EXTRADATA_MASTERING_DISPLAY_COLOUR_SEI; + break; + case V4L2_MPEG_VIDC_EXTRADATA_CONTENT_LIGHT_LEVEL_SEI: + ret = HAL_EXTRADATA_CONTENT_LIGHT_LEVEL_SEI; + break; + case V4L2_MPEG_VIDC_EXTRADATA_VUI_DISPLAY: + ret = HAL_EXTRADATA_VUI_DISPLAY_INFO; + break; + case V4L2_MPEG_VIDC_EXTRADATA_VPX_COLORSPACE: + ret = HAL_EXTRADATA_VPX_COLORSPACE; + break; + case V4L2_MPEG_VIDC_EXTRADATA_UBWC_CR_STATS_INFO: + ret = HAL_EXTRADATA_UBWC_CR_STATS_INFO; + break; + case V4L2_MPEG_VIDC_EXTRADATA_HDR10PLUS_METADATA: + ret = HAL_EXTRADATA_HDR10PLUS_METADATA; + break; + case V4L2_MPEG_VIDC_EXTRADATA_ENC_DTS: + ret = HAL_EXTRADATA_ENC_DTS_METADATA; + break; + case V4L2_MPEG_VIDC_EXTRADATA_INPUT_CROP: + ret = HAL_EXTRADATA_INPUT_CROP; + break; + default: + dprintk(VIDC_WARN, "Extradata not found: %d\n", index); + break; + } + return ret; +}; + +int msm_vidc_noc_error_info(struct msm_vidc_core *core) +{ + struct hfi_device *hdev; + + if (!core || !core->device) { + dprintk(VIDC_WARN, "%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) { + dprintk(VIDC_WARN, "%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) { + dprintk(VIDC_ERR, "%s: Invalid params\n", __func__); + return; + } + hdev = core->device; + + mutex_lock(&core->lock); + if (core->state == VIDC_CORE_INIT_DONE) { + dprintk(VIDC_WARN, "%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) { + dprintk(VIDC_ERR, "%s: trigger_ssr failed\n", + __func__); + core->trigger_ssr = false; + } + } else { + dprintk(VIDC_WARN, "%s: video core %pK not initialized\n", + __func__, core); + } + mutex_unlock(&core->lock); +} + +static int msm_vidc_load_supported(struct msm_vidc_inst *inst) +{ + int num_mbs_per_sec = 0, max_load_adj = 0; + enum load_calc_quirks quirks = LOAD_CALC_IGNORE_TURBO_LOAD | + LOAD_CALC_IGNORE_THUMBNAIL_LOAD | + LOAD_CALC_IGNORE_NON_REALTIME_LOAD; + + if (inst->state == MSM_VIDC_OPEN_DONE) { + max_load_adj = inst->core->resources.max_load; + num_mbs_per_sec = msm_comm_get_load(inst->core, + MSM_VIDC_DECODER, quirks); + num_mbs_per_sec += msm_comm_get_load(inst->core, + MSM_VIDC_ENCODER, quirks); + if (num_mbs_per_sec > max_load_adj) { + dprintk(VIDC_ERR, + "H/W is overloaded. needed: %d max: %d\n", + num_mbs_per_sec, + max_load_adj); + 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; + + if (inst->grid_enable > 0) { + dprintk(VIDC_DBG, "Skip scaling check for HEIC\n"); + return 0; + } + + input_height = inst->prop.height[OUTPUT_PORT]; + input_width = inst->prop.width[OUTPUT_PORT]; + output_height = inst->prop.height[CAPTURE_PORT]; + output_width = inst->prop.width[CAPTURE_PORT]; + + if (!input_height || !input_width || !output_height || !output_width) { + dprintk(VIDC_ERR, + "Invalid : Input height = %d width = %d", + input_height, input_width); + dprintk(VIDC_ERR, + " output height = %d width = %d\n", + output_height, output_width); + return -ENOTSUPP; + } + + if (!inst->capability.scale_x.min || + !inst->capability.scale_x.max || + !inst->capability.scale_y.min || + !inst->capability.scale_y.max) { + + if (input_width * input_height != + output_width * output_height) { + dprintk(VIDC_ERR, + "%s: scaling is not supported (%dx%d != %dx%d)\n", + __func__, input_width, input_height, + output_width, output_height); + return -ENOTSUPP; + } + + dprintk(VIDC_DBG, "%s: supported WxH = %dx%d\n", + __func__, input_width, input_height); + return 0; + } + + x_min = (1<<16)/inst->capability.scale_x.min; + y_min = (1<<16)/inst->capability.scale_y.min; + x_max = inst->capability.scale_x.max >> 16; + y_max = inst->capability.scale_y.max >> 16; + + if (input_height > output_height) { + if (input_height > x_min * output_height) { + dprintk(VIDC_ERR, + "Unsupported height min height %d vs %d\n", + input_height / x_min, output_height); + return -ENOTSUPP; + } + } else { + if (output_height > x_max * input_height) { + dprintk(VIDC_ERR, + "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) { + dprintk(VIDC_ERR, + "Unsupported width min width %d vs %d\n", + input_width / y_min, output_width); + return -ENOTSUPP; + } + } else { + if (output_width > y_max * input_width) { + dprintk(VIDC_ERR, + "Unsupported width max width %d vs %d\n", + y_max * input_width, output_width); + return -ENOTSUPP; + } + } + return 0; +} + +static bool is_image_session(struct msm_vidc_inst *inst) +{ + if (inst->session_type == MSM_VIDC_ENCODER && + get_hal_codec(inst->fmts[CAPTURE_PORT].fourcc) == + HAL_VIDEO_CODEC_HEVC) + return (inst->profile == HAL_HEVC_PROFILE_MAIN_STILL_PIC || + inst->grid_enable); + else + return false; +} + +static int msm_vidc_check_image_session_capabilities(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct msm_vidc_image_capability *capability = NULL; + + u32 output_height = ALIGN(inst->prop.height[CAPTURE_PORT], 512); + u32 output_width = ALIGN(inst->prop.width[CAPTURE_PORT], 512); + + if (inst->grid_enable) + capability = inst->core->platform_data->heic_image_capability; + else + capability = inst->core->platform_data->hevc_image_capability; + + if (!capability) + return -EINVAL; + + if (output_width < capability->width.min || + output_height < capability->height.min) { + dprintk(VIDC_ERR, + "HEIC Unsupported WxH = (%u)x(%u), min supported is - (%u)x(%u)\n", + output_width, + output_height, + capability->width.min, + capability->height.min); + rc = -ENOTSUPP; + } + if (!rc && (output_width > capability->width.max || + output_height > capability->height.max)) { + dprintk(VIDC_ERR, + "HEIC Unsupported WxH = (%u)x(%u), max supported is - (%u)x(%u)\n", + output_width, + output_height, + capability->width.max, + capability->height.max); + rc = -ENOTSUPP; + } + if (!rc && output_height * output_width > + capability->width.max * capability->height.max) { + dprintk(VIDC_ERR, + "HEIC Unsupported WxH = (%u)x(%u), max supported is - (%u)x(%u)\n", + output_width, output_height, + capability->width.max, capability->height.max); + rc = -ENOTSUPP; + } + + return rc; +} + +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; + + if (!inst || !inst->core || !inst->core->device) { + dprintk(VIDC_WARN, "%s: Invalid parameter\n", __func__); + return -EINVAL; + } + capability = &inst->capability; + hdev = inst->core->device; + core = inst->core; + rc = msm_vidc_load_supported(inst); + if (rc) { + dprintk(VIDC_WARN, + "%s: Hardware is overloaded\n", __func__); + return rc; + } + + if (!is_thermal_permissible(core)) { + dprintk(VIDC_WARN, + "Thermal level critical, stop all active sessions!\n"); + return -ENOTSUPP; + } + + output_height = inst->prop.height[CAPTURE_PORT]; + output_width = inst->prop.width[CAPTURE_PORT]; + input_height = inst->prop.height[OUTPUT_PORT]; + input_width = inst->prop.width[OUTPUT_PORT]; + + if (inst->session_type == MSM_VIDC_ENCODER && (input_width % 2 != 0 || + input_height % 2 != 0 || output_width % 2 != 0 || + output_height % 2 != 0)) { + dprintk(VIDC_ERR, + "Height and Width should be even numbers for NV12\n"); + dprintk(VIDC_ERR, + "Input WxH = (%u)x(%u), Output WxH = (%u)x(%u)\n", + input_width, input_height, + output_width, output_height); + rc = -ENOTSUPP; + } + + if (is_image_session(inst)) { + rc = msm_vidc_check_image_session_capabilities(inst); + return rc; + } + + output_height = ALIGN(inst->prop.height[CAPTURE_PORT], 16); + output_width = ALIGN(inst->prop.width[CAPTURE_PORT], 16); + + if (!rc) { + if (output_width < capability->width.min || + output_height < capability->height.min) { + dprintk(VIDC_ERR, + "Unsupported WxH = (%u)x(%u), min supported is - (%u)x(%u)\n", + output_width, + output_height, + capability->width.min, + capability->height.min); + rc = -ENOTSUPP; + } + if (!rc && output_width > capability->width.max) { + dprintk(VIDC_ERR, + "Unsupported width = %u supported max width = %u\n", + output_width, + capability->width.max); + rc = -ENOTSUPP; + } + + if (!rc && output_height * output_width > + capability->width.max * capability->height.max) { + dprintk(VIDC_ERR, + "Unsupported WxH = (%u)x(%u), max supported is - (%u)x(%u)\n", + output_width, output_height, + capability->width.max, capability->height.max); + rc = -ENOTSUPP; + } + } + if (rc) { + dprintk(VIDC_ERR, + "%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) { + dprintk(VIDC_ERR, "%s: invalid input parameters\n", __func__); + return; + } + dprintk(VIDC_WARN, "%s: inst %pK\n", __func__, inst); + response.session_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) { + dprintk(VIDC_ERR, "%s: invalid input parameters\n", __func__); + return; + } + dprintk(VIDC_WARN, "%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) { + dprintk(VIDC_ERR, "%s: invalid input parameters\n", __func__); + return -EINVAL; + } else if (!inst->session) { + dprintk(VIDC_ERR, "%s: no session to kill for inst %pK\n", + __func__, inst); + return 0; + } + + dprintk(VIDC_ERR, "%s: inst %pK, session %x state %d\n", __func__, + inst, hash32_ptr(inst->session), 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) { + dprintk(VIDC_ERR, + "%s: inst %pK session %x abort failed\n", + __func__, inst, hash32_ptr(inst->session)); + change_inst_state(inst, MSM_VIDC_CORE_INVALID); + } + } + + change_inst_state(inst, MSM_VIDC_CLOSE_DONE); + msm_comm_session_clean(inst); + + dprintk(VIDC_WARN, "%s: inst %pK session %x handled\n", __func__, + inst, hash32_ptr(inst->session)); + 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) { + dprintk(VIDC_ERR, "%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); + return rc; +} + +void msm_comm_smem_free(struct msm_vidc_inst *inst, struct msm_smem *mem) +{ + if (!inst || !inst->core || !mem) { + dprintk(VIDC_ERR, + "%s: invalid params: %pK %pK\n", __func__, inst, mem); + return; + } + msm_smem_free(mem); +} + +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) { + dprintk(VIDC_ERR, "%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) { + dprintk(VIDC_DBG, "Calling vidc_hal_core_release\n"); + rc = call_hfi_op(hdev, core_release, + hdev->hfi_device_data); + if (rc) { + dprintk(VIDC_ERR, + "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 hal_uncompressed_format_select hal_fmt = {0}; + enum hal_uncompressed_format format = HAL_UNUSED_COLOR; + int rc = 0; + struct hfi_device *hdev; + + if (!inst || !inst->core || !inst->core->device) { + dprintk(VIDC_ERR, "%s - invalid param\n", __func__); + return -EINVAL; + } + + hdev = inst->core->device; + + format = msm_comm_get_hal_uncompressed(fourcc); + if (format == HAL_UNUSED_COLOR) { + dprintk(VIDC_ERR, "Using unsupported colorformat %#x\n", + fourcc); + rc = -ENOTSUPP; + goto exit; + } + + hal_fmt.buffer_type = buffer_type; + hal_fmt.format = format; + + rc = call_hfi_op(hdev, session_set_property, inst->session, + HAL_PARAM_UNCOMPRESSED_FORMAT_SELECT, &hal_fmt); + if (rc) + dprintk(VIDC_ERR, + "Failed to set input color format\n"); + else + dprintk(VIDC_DBG, "Setting uncompressed colorformat to %#x\n", + format); + +exit: + return rc; +} + +int msm_vidc_comm_s_parm(struct msm_vidc_inst *inst, struct v4l2_streamparm *a) +{ + u32 property_id = 0; + u64 us_per_frame = 0; + void *pdata; + int rc = 0, fps = 0; + struct hal_frame_rate frame_rate; + struct hfi_device *hdev; + + if (!inst || !inst->core || !inst->core->device || !a) { + dprintk(VIDC_ERR, "%s invalid parameters\n", __func__); + return -EINVAL; + } + + hdev = inst->core->device; + property_id = HAL_CONFIG_FRAME_RATE; + + if (a->parm.output.timeperframe.denominator) { + switch (a->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + us_per_frame = a->parm.output.timeperframe.numerator * + (u64)USEC_PER_SEC; + do_div(us_per_frame, + a->parm.output.timeperframe.denominator); + break; + default: + dprintk(VIDC_ERR, + "Scale clocks : Unknown buffer type %d\n", + a->type); + break; + } + } + + if (!us_per_frame) { + dprintk(VIDC_ERR, + "Failed to scale clocks : time between frames is 0\n"); + rc = -EINVAL; + goto exit; + } + + fps = us_per_frame > USEC_PER_SEC ? + 0 : USEC_PER_SEC / (u32)us_per_frame; + + if (fps % 15 == 14 || fps % 24 == 23) + fps = fps + 1; + else if ((fps > 1) && (fps % 24 == 1 || fps % 15 == 1)) + fps = fps - 1; + + if (fps < inst->capability.frame_rate.min || + fps > inst->capability.frame_rate.max) { + dprintk(VIDC_ERR, + "FPS is out of limits : fps = %d Min = %d, Max = %d\n", + fps, inst->capability.frame_rate.min, + inst->capability.frame_rate.max); + rc = -EINVAL; + goto exit; + } + + dprintk(VIDC_PROF, "reported fps changed for %pK: %d->%d\n", + inst, inst->prop.fps, fps); + inst->prop.fps = fps; + if (inst->session_type == MSM_VIDC_ENCODER && + get_hal_codec(inst->fmts[CAPTURE_PORT].fourcc) != + HAL_VIDEO_CODEC_TME) { + frame_rate.frame_rate = inst->prop.fps * BIT(16); + frame_rate.buffer_type = HAL_BUFFER_OUTPUT; + pdata = &frame_rate; + rc = call_hfi_op(hdev, session_set_property, + inst->session, property_id, pdata); + if (rc) + dprintk(VIDC_WARN, + "Failed to set frame rate %d\n", rc); + } +exit: + return rc; +} + +void msm_comm_print_inst_info(struct msm_vidc_inst *inst) +{ + struct msm_vidc_buffer *mbuf; + struct internal_buf *buf; + bool is_decode = false; + enum vidc_ports port; + bool is_secure = false; + + if (!inst) { + dprintk(VIDC_ERR, "%s - invalid param %pK\n", + __func__, inst); + return; + } + + is_decode = inst->session_type == MSM_VIDC_DECODER; + port = is_decode ? OUTPUT_PORT : CAPTURE_PORT; + is_secure = inst->flags & VIDC_SECURE; + dprintk(VIDC_ERR, + "%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, + inst->prop.height[port], inst->prop.width[port], + inst->prop.fps, inst->prop.bitrate, + !inst->bit_depth ? "8" : "10"); + + dprintk(VIDC_ERR, + "---Buffer details for inst: %pK of type: %d---\n", + inst, inst->session_type); + mutex_lock(&inst->registeredbufs.lock); + dprintk(VIDC_ERR, "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); + dprintk(VIDC_ERR, "scratch buffer list:\n"); + list_for_each_entry(buf, &inst->scratchbufs.list, list) + dprintk(VIDC_ERR, "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); + dprintk(VIDC_ERR, "persist buffer list:\n"); + list_for_each_entry(buf, &inst->persistbufs.list, list) + dprintk(VIDC_ERR, "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); + dprintk(VIDC_ERR, "dpb buffer list:\n"); + list_for_each_entry(buf, &inst->outputbufs.list, list) + dprintk(VIDC_ERR, "type: %d addr: %x size: %u\n", + buf->buffer_type, buf->smem.device_addr, + buf->smem.size); + mutex_unlock(&inst->outputbufs.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) { + dprintk(VIDC_DBG, + "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) { + dprintk(VIDC_DBG, "send session_continue\n"); + rc = call_hfi_op(hdev, session_continue, + (void *)inst->session); + if (rc) { + dprintk(VIDC_ERR, + "failed to send session_continue\n"); + rc = -EINVAL; + goto sess_continue_fail; + } + inst->in_reconfig = false; + inst->prop.height[CAPTURE_PORT] = inst->reconfig_height; + inst->prop.width[CAPTURE_PORT] = inst->reconfig_width; + inst->prop.height[OUTPUT_PORT] = inst->reconfig_height; + inst->prop.width[OUTPUT_PORT] = inst->reconfig_width; + if (msm_comm_get_stream_output_mode(inst) == + HAL_VIDEO_DECODER_SECONDARY) { + rc = msm_comm_queue_output_buffers(inst); + if (rc) { + dprintk(VIDC_ERR, + "Failed to queue output buffers: %d\n", + rc); + goto sess_continue_fail; + } + } + } else if (inst->session_type == MSM_VIDC_ENCODER) { + dprintk(VIDC_DBG, + "session_continue not supported for encoder"); + } else { + dprintk(VIDC_ERR, + "session_continue called in wrong state for decoder"); + } + +sess_continue_fail: + mutex_unlock(&inst->lock); + return rc; +} + +u32 get_frame_size_nv12(int plane, u32 height, u32 width) +{ + return VENUS_BUFFER_SIZE(COLOR_FMT_NV12, width, height); +} + +u32 get_frame_size_nv12_ubwc(int plane, u32 height, u32 width) +{ + return VENUS_BUFFER_SIZE(COLOR_FMT_NV12_UBWC, width, height); +} + +u32 get_frame_size_rgba(int plane, u32 height, u32 width) +{ + return VENUS_BUFFER_SIZE(COLOR_FMT_RGBA8888, width, height); +} + +u32 get_frame_size_nv21(int plane, u32 height, u32 width) +{ + return VENUS_BUFFER_SIZE(COLOR_FMT_NV21, width, height); +} + +u32 get_frame_size_tp10_ubwc(int plane, u32 height, u32 width) +{ + return VENUS_BUFFER_SIZE(COLOR_FMT_NV12_BPP10_UBWC, width, height); +} + +u32 get_frame_size_p010(int plane, u32 height, u32 width) +{ + return VENUS_BUFFER_SIZE(COLOR_FMT_P010, width, height); +} + +u32 get_frame_size_nv12_512(int plane, u32 height, u32 width) +{ + return VENUS_BUFFER_SIZE(COLOR_FMT_NV12_512, width, height); +} + +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, + "%s: %s: %x : 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 == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ? + "OUTPUT" : "CAPTURE", hash32_ptr(inst->session), + 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, + "%s: %s: %x : 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 == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ? + "OUTPUT" : "CAPTURE", hash32_ptr(inst->session), + 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(u32 tag, const char *str, struct msm_vidc_inst *inst, + struct vb2_buffer *vb2) +{ + if (!(tag & msm_vidc_debug) || !inst || !vb2) + return; + + if (vb2->num_planes == 1) + dprintk(tag, + "%s: %s: %x : idx %2d fd %d off %d size %d filled %d\n", + str, vb2->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ? + "OUTPUT" : "CAPTURE", hash32_ptr(inst->session), + vb2->index, vb2->planes[0].m.fd, + vb2->planes[0].data_offset, vb2->planes[0].length, + vb2->planes[0].bytesused); + else + dprintk(tag, + "%s: %s: %x : idx %2d fd %d off %d size %d filled %d, extradata: fd %d off %d size %d filled %d\n", + str, vb2->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ? + "OUTPUT" : "CAPTURE", hash32_ptr(inst->session), + 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); +} + +void print_v4l2_buffer(u32 tag, const char *str, struct msm_vidc_inst *inst, + struct v4l2_buffer *v4l2) +{ + if (!(tag & msm_vidc_debug) || !inst || !v4l2) + return; + + if (v4l2->length == 1) + dprintk(tag, + "%s: %s: %x : idx %2d fd %d off %d size %d filled %d\n", + str, v4l2->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ? + "OUTPUT" : "CAPTURE", hash32_ptr(inst->session), + v4l2->index, v4l2->m.planes[0].m.fd, + v4l2->m.planes[0].data_offset, + v4l2->m.planes[0].length, + v4l2->m.planes[0].bytesused); + else + dprintk(tag, + "%s: %s: %x : idx %2d fd %d off %d size %d filled %d, extradata: fd %d off %d size %d filled %d\n", + str, v4l2->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ? + "OUTPUT" : "CAPTURE", hash32_ptr(inst->session), + v4l2->index, v4l2->m.planes[0].m.fd, + v4l2->m.planes[0].data_offset, + v4l2->m.planes[0].length, + v4l2->m.planes[0].bytesused, + v4l2->m.planes[1].m.fd, + v4l2->m.planes[1].data_offset, + v4l2->m.planes[1].length, + v4l2->m.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) { + dprintk(VIDC_ERR, "%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) +{ + int i = 0; + struct vb2_buffer *vb; + + if (!inst || !mbuf || !vb2) { + dprintk(VIDC_ERR, "%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) { + dprintk(VIDC_ERR, "%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) +{ + int i = 0; + struct vb2_buffer *vb; + + if (!inst || !mbuf || !dma_planes) { + dprintk(VIDC_ERR, "%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(struct msm_vidc_buffer *mbuf, + u32 type, u32 *planes, u32 i) +{ + if (!mbuf || !planes) { + dprintk(VIDC_ERR, "%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(struct msm_vidc_buffer *mbuf, + u32 type, u32 *planes) +{ + 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(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(mbuf, type, planes)) { + found = true; + break; + } + } + mutex_unlock(&inst->registeredbufs.lock); + if (!found) { + dprintk(VIDC_ERR, + "%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) { + dprintk(VIDC_ERR, "%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 == + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + port = CAPTURE_PORT; + else if (mbuf->vvb.vb2_buf.type == + V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + port = OUTPUT_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 { + dprintk(VIDC_ERR, "%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, i; + struct vb2_buffer *vb; + bool skip; + + if (!inst || !mbuf) { + dprintk(VIDC_ERR, "%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; + + skip = true; + if (inst->session_type == MSM_VIDC_DECODER) { + if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + if (!i) { /* bitstream */ + skip = false; + offset = vb->planes[i].data_offset; + size = vb->planes[i].bytesused; + cache_op = SMEM_CACHE_CLEAN_INVALIDATE; + } + } else if (vb->type == + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + if (!i) { /* yuv */ + skip = false; + offset = 0; + size = vb->planes[i].length; + cache_op = SMEM_CACHE_INVALIDATE; + } + } + } else if (inst->session_type == MSM_VIDC_ENCODER) { + if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + if (!i) { /* yuv */ + skip = false; + offset = vb->planes[i].data_offset; + size = vb->planes[i].bytesused; + cache_op = SMEM_CACHE_CLEAN_INVALIDATE; + } + } else if (vb->type == + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + if (!i) { /* bitstream */ + skip = false; + offset = 0; + size = vb->planes[i].length; + if (inst->max_filled_length) + size = inst->max_filled_length; + cache_op = SMEM_CACHE_INVALIDATE; + } + } + } + + if (!skip) { + rc = msm_smem_cache_operations(mbuf->smem[i].dma_buf, + cache_op, offset, size); + 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, i; + struct vb2_buffer *vb; + bool skip; + + if (!inst || !mbuf) { + dprintk(VIDC_ERR, "%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; + + skip = true; + if (inst->session_type == MSM_VIDC_DECODER) { + if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + /* bitstream and extradata */ + /* we do not need cache operations */ + } else if (vb->type == + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + if (!i) { /* yuv */ + skip = false; + offset = vb->planes[i].data_offset; + size = vb->planes[i].bytesused; + cache_op = SMEM_CACHE_INVALIDATE; + } + } + } else if (inst->session_type == MSM_VIDC_ENCODER) { + if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + /* yuv and extradata */ + /* we do not need cache operations */ + } else if (vb->type == + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + if (!i) { /* bitstream */ + skip = false; + /* + * Include vp8e header bytes as well + * by making offset equal to zero + */ + offset = 0; + size = vb->planes[i].bytesused + + vb->planes[i].data_offset; + cache_op = SMEM_CACHE_INVALIDATE; + } + } + } + + if (!skip) { + rc = msm_smem_cache_operations(mbuf->smem[i].dma_buf, + cache_op, offset, size); + 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 = NULL; + bool found = false; + int i = 0, planes = 0; + + if (!inst || !vb2) { + dprintk(VIDC_ERR, "%s: invalid params\n", __func__); + return NULL; + } + + for (planes = 0; planes < vb2->num_planes; planes++) { + /* + * always compare dma_buf addresses which is guaranteed + * to be same across the processes (duplicate fds). + */ + dma_planes[planes] = (unsigned long)msm_smem_get_dma_buf( + vb2->planes[planes].m.fd); + if (!dma_planes[planes]) + goto put_ref; + } + + 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 == + V4L2_BUF_TYPE_VIDEO_OUTPUT_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) { + dprintk(VIDC_ERR, "%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 = msm_smem_map_dma_buf(inst, &mbuf->smem[i]); + if (rc) { + dprintk(VIDC_ERR, "%s: map failed.\n", __func__); + goto exit; + } + /* increase refcount as we get both fbd and rbr */ + rc = msm_smem_map_dma_buf(inst, &mbuf->smem[i]); + if (rc) { + dprintk(VIDC_ERR, "%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_DBG, + "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); + +exit: + if (rc == -EEXIST) { + print_vidc_buffer(VIDC_DBG, "qbuf upon rbr", inst, mbuf); + } else if (rc) { + dprintk(VIDC_ERR, "%s: rc %d\n", __func__, rc); + msm_comm_unmap_vidc_buffer(inst, mbuf); + if (!found) + kref_put_mbuf(mbuf); + } + mutex_unlock(&inst->registeredbufs.lock); +put_ref: + while (planes) + msm_smem_put_dma_buf((struct dma_buf *)dma_planes[--planes]); + + return rc ? ((rc == -EEXIST && !inst->batch.enable) ? + ERR_PTR(rc) : mbuf) : mbuf; +} + +void msm_comm_put_vidc_buffer(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *mbuf) +{ + struct msm_vidc_buffer *temp; + bool found = false; + int i = 0; + + if (!inst || !mbuf) { + dprintk(VIDC_ERR, "%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_DBG, "dqbuf", inst, mbuf); + for (i = 0; i < mbuf->vvb.vb2_buf.num_planes; i++) { + if (msm_smem_unmap_dma_buf(inst, &mbuf->smem[i])) + print_vidc_buffer(VIDC_ERR, + "dqbuf: unmap failed.", inst, mbuf); + + if (!(mbuf->vvb.flags & V4L2_QCOM_BUF_FLAG_READONLY)) { + /* rbr won't come for this buffer */ + if (msm_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; + int i = 0; + u32 planes[VIDEO_MAX_PLANES] = {0}; + + mutex_lock(&inst->bufq[CAPTURE_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, + mbuf->output_tag); + + /* clear RBR_PENDING flag */ + mbuf->flags &= ~MSM_VIDC_FLAG_RBR_PENDING; + + for (i = 0; i < mbuf->vvb.vb2_buf.num_planes; i++) { + if (msm_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(temp, + V4L2_BUF_TYPE_VIDEO_CAPTURE_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->in_flush) { + print_vidc_buffer(VIDC_DBG, "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[CAPTURE_PORT].lock); +} + +int msm_comm_unmap_vidc_buffer(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *mbuf) +{ + int rc = 0, i; + + if (!inst || !mbuf) { + dprintk(VIDC_ERR, "%s: invalid params %pK %pK\n", + __func__, inst, mbuf); + return -EINVAL; + } + if (mbuf->vvb.vb2_buf.num_planes > VIDEO_MAX_PLANES) { + dprintk(VIDC_ERR, "%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 (msm_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; +} + +void msm_comm_free_buffer_tags(struct msm_vidc_inst *inst) +{ + struct vidc_tag_data *temp, *next; + + if (!inst) { + dprintk(VIDC_ERR, "%s: invalid params %pK\n", + __func__, inst); + return; + } + + mutex_lock(&inst->buffer_tags.lock); + list_for_each_entry_safe(temp, next, &inst->buffer_tags.list, list) { + list_del(&temp->list); + kfree(temp); + } + INIT_LIST_HEAD(&inst->buffer_tags.list); + mutex_unlock(&inst->buffer_tags.lock); +} + +void msm_comm_store_tags(struct msm_vidc_inst *inst, + struct vidc_tag_data *tag_data) +{ + + struct vidc_tag_data *temp, *next; + struct vidc_tag_data *pdata = NULL; + bool found = false; + + if (!inst || !tag_data) { + dprintk(VIDC_ERR, "%s: invalid params %pK %pK\n", + __func__, inst, tag_data); + return; + } + + + mutex_lock(&inst->buffer_tags.lock); + list_for_each_entry_safe(temp, next, &inst->buffer_tags.list, list) { + if (temp->index == tag_data->index && + temp->type == tag_data->type) { + temp->input_tag = tag_data->input_tag; + temp->output_tag = tag_data->output_tag; + found = true; + break; + } + } + + if (!found) { + pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + dprintk(VIDC_WARN, "%s: malloc failure.\n", __func__); + goto exit; + } + pdata->input_tag = tag_data->input_tag; + pdata->output_tag = tag_data->output_tag; + pdata->index = tag_data->index; + pdata->type = tag_data->type; + list_add_tail(&pdata->list, &inst->buffer_tags.list); + } + +exit: + mutex_unlock(&inst->buffer_tags.lock); +} + +void msm_comm_fetch_tags(struct msm_vidc_inst *inst, + struct vidc_tag_data *tag_data) +{ + struct vidc_tag_data *temp, *next; + + if (!inst || !tag_data) { + dprintk(VIDC_ERR, "%s: invalid params %pK %pK\n", + __func__, inst, tag_data); + return; + } + mutex_lock(&inst->buffer_tags.lock); + list_for_each_entry_safe(temp, next, &inst->buffer_tags.list, list) { + if (temp->index == tag_data->index && + temp->type == tag_data->type) { + tag_data->input_tag = temp->input_tag; + tag_data->output_tag = temp->output_tag; + break; + } + } + mutex_unlock(&inst->buffer_tags.lock); +} + +void msm_comm_store_mark_data(struct msm_vidc_list *data_list, + u32 index, u32 mark_data, u32 mark_target) +{ + struct msm_vidc_buf_data *pdata = NULL; + bool found = false; + + if (!data_list) { + dprintk(VIDC_ERR, "%s: invalid params %pK\n", + __func__, data_list); + return; + } + + mutex_lock(&data_list->lock); + list_for_each_entry(pdata, &data_list->list, list) { + if (pdata->index == index) { + pdata->mark_data = mark_data; + pdata->mark_target = mark_target; + found = true; + break; + } + } + + if (!found) { + pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + dprintk(VIDC_WARN, "%s: malloc failure.\n", __func__); + goto exit; + } + pdata->index = index; + pdata->mark_data = mark_data; + pdata->mark_target = mark_target; + list_add_tail(&pdata->list, &data_list->list); + } + +exit: + mutex_unlock(&data_list->lock); +} + +void msm_comm_fetch_mark_data(struct msm_vidc_list *data_list, + u32 index, u32 *mark_data, u32 *mark_target) +{ + struct msm_vidc_buf_data *pdata = NULL; + + if (!data_list || !mark_data || !mark_target) { + dprintk(VIDC_ERR, "%s: invalid params %pK %pK %pK\n", + __func__, data_list, mark_data, mark_target); + return; + } + + *mark_data = *mark_target = 0; + mutex_lock(&data_list->lock); + list_for_each_entry(pdata, &data_list->list, list) { + if (pdata->index == index) { + *mark_data = pdata->mark_data; + *mark_target = pdata->mark_target; + /* clear after fetch */ + pdata->mark_data = pdata->mark_target = 0; + break; + } + } + mutex_unlock(&data_list->lock); +} + +int msm_comm_release_mark_data(struct msm_vidc_inst *inst) +{ + struct msm_vidc_buf_data *pdata, *next; + + if (!inst) { + dprintk(VIDC_ERR, "%s: invalid params %pK\n", + __func__, inst); + 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 hal_uncompressed_plane_actual_constraints_info + *pconstraint = NULL; + u32 num_planes = 2; + u32 size = 0; + int rc = 0; + struct hfi_device *hdev; + + if (!inst || !inst->core || !inst->core->device) { + dprintk(VIDC_ERR, "%s - invalid param\n", __func__); + return -EINVAL; + } + + hdev = inst->core->device; + + size = sizeof(buffer_type) + + sizeof(u32) + + num_planes + * sizeof(struct hal_uncompressed_plane_constraints); + + pconstraint = kzalloc(size, GFP_KERNEL); + if (!pconstraint) { + dprintk(VIDC_ERR, "No memory cannot alloc constrain\n"); + rc = -ENOMEM; + goto exit; + } + + pconstraint->buffer_type = buffer_type; + pconstraint->num_planes = pix_constraint->num_planes; + //set Y plan constraints + dprintk(VIDC_INFO, "Set Y plan constraints.\n"); + pconstraint->rg_plane_format[0].stride_multiples = + pix_constraint->y_stride_multiples; + pconstraint->rg_plane_format[0].max_stride = + pix_constraint->y_max_stride; + pconstraint->rg_plane_format[0].min_plane_buffer_height_multiple = + pix_constraint->y_min_plane_buffer_height_multiple; + pconstraint->rg_plane_format[0].buffer_alignment = + pix_constraint->y_buffer_alignment; + + //set UV plan constraints + dprintk(VIDC_INFO, "Set UV plan constraints.\n"); + pconstraint->rg_plane_format[1].stride_multiples = + pix_constraint->uv_stride_multiples; + pconstraint->rg_plane_format[1].max_stride = + pix_constraint->uv_max_stride; + pconstraint->rg_plane_format[1].min_plane_buffer_height_multiple = + pix_constraint->uv_min_plane_buffer_height_multiple; + pconstraint->rg_plane_format[1].buffer_alignment = + pix_constraint->uv_buffer_alignment; + + rc = call_hfi_op(hdev, + session_set_property, + inst->session, + HAL_PARAM_UNCOMPRESSED_PLANE_ACTUAL_CONSTRAINTS_INFO, + pconstraint); + if (rc) + dprintk(VIDC_ERR, + "Failed to set input color format constraint\n"); + else + dprintk(VIDC_DBG, "Set color format constraint success\n"); + +exit: + if (pconstraint) + kfree(pconstraint); + 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); + + /* Instance count includes current instance as well. */ + + if ((instance_count > core->resources.max_inst_count) || + (secure_instance_count > core->resources.max_secure_inst_count)) + overload = true; + return overload; +} diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.h b/drivers/media/platform/msm/vidc/msm_vidc_common.h new file mode 100644 index 000000000000..a4e4b7821b3f --- /dev/null +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.h @@ -0,0 +1,264 @@ +/* Copyright (c) 2012-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. + * + */ + +#ifndef _MSM_VIDC_COMMON_H_ +#define _MSM_VIDC_COMMON_H_ +#include "msm_vidc_internal.h" + +#define MAX_DEC_BATCH_SIZE 6 +#define MAX_DEC_BATCH_WIDTH 1920 +#define MAX_DEC_BATCH_HEIGHT 1088 +#define SKIP_BATCH_WINDOW 100 +#define MIN_FRAME_QUALITY 0 +#define MAX_FRAME_QUALITY 100 +#define DEFAULT_FRAME_QUALITY 80 +#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 (((1280+15)/16)*((720+15)/16)*30) + +struct vb2_buf_entry { + struct list_head list; + struct vb2_buffer *vb; +}; + +struct getprop_buf { + struct list_head list; + void *data; +}; + +extern const char *const mpeg_video_vidc_extradata[]; + +enum load_calc_quirks { + LOAD_CALC_NO_QUIRKS = 0, + LOAD_CALC_IGNORE_TURBO_LOAD = 1 << 0, + LOAD_CALC_IGNORE_THUMBNAIL_LOAD = 1 << 1, + LOAD_CALC_IGNORE_NON_REALTIME_LOAD = 1 << 2, +}; + +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 bool is_realtime_session(struct msm_vidc_inst *inst) +{ + return !!(inst->flags & VIDC_REALTIME); +} + +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 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); +} +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 *session_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 *msm_comm_get_pixel_fmt_index( + const struct msm_vidc_format fmt[], int size, int index, int fmt_type); +struct msm_vidc_format *msm_comm_get_pixel_fmt_fourcc( + struct msm_vidc_format fmt[], int size, int fourcc, int fmt_type); +struct msm_vidc_format_constraint *msm_comm_get_pixel_fmt_constraints( + struct msm_vidc_format_constraint fmt[], int size, int fourcc); +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_set_prop(struct msm_vidc_inst *inst, + enum hal_property ptype, void *pdata); +int msm_comm_try_get_prop(struct msm_vidc_inst *inst, + enum hal_property ptype, 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_output_buffers(struct msm_vidc_inst *inst); +int msm_comm_queue_output_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_output_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); +enum hal_extradata_id msm_comm_get_hal_extradata_index( + enum v4l2_mpeg_vidc_extradata index); +int msm_comm_reset_bufreqs(struct msm_vidc_inst *inst, + enum hal_buffer buf_type); +int msm_comm_copy_bufreqs(struct msm_vidc_inst *inst, + enum hal_buffer src_type, enum hal_buffer dst_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); +enum hal_domain get_hal_domain(int session_type); +int msm_comm_check_core_init(struct msm_vidc_core *core); +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_load(struct msm_vidc_core *core, + enum session_type 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); +int msm_vidc_comm_s_parm(struct msm_vidc_inst *inst, struct v4l2_streamparm *a); +bool msm_comm_turbo_session(struct msm_vidc_inst *inst); +void msm_comm_print_inst_info(struct msm_vidc_inst *inst); +int msm_comm_v4l2_to_hal(int id, int value); +int msm_comm_hal_to_v4l2(int id, int value); +int msm_comm_get_v4l2_profile(int fourcc, int profile); +int msm_comm_get_v4l2_level(int fourcc, int level); +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 get_frame_size_nv12(int plane, u32 height, u32 width); +u32 get_frame_size_nv12_512(int plane, u32 height, u32 width); +u32 get_frame_size_nv12_ubwc(int plane, u32 height, u32 width); +u32 get_frame_size_rgba(int plane, u32 height, u32 width); +u32 get_frame_size_nv21(int plane, u32 height, u32 width); +u32 get_frame_size_tp10_ubwc(int plane, u32 height, u32 width); +u32 get_frame_size_p010(int plane, u32 height, u32 width); +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(struct msm_vidc_buffer *mbuf, + u32 type, u32 *planes, u32 i); +bool msm_comm_compare_device_planes(struct msm_vidc_buffer *mbuf, + u32 type, u32 *planes); +void msm_comm_store_tags(struct msm_vidc_inst *inst, + struct vidc_tag_data *tag_data); +void msm_comm_fetch_tags(struct msm_vidc_inst *inst, + struct vidc_tag_data *tag_data); +void msm_comm_free_buffer_tags(struct msm_vidc_inst *inst); +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(u32 tag, const char *str, struct msm_vidc_inst *inst, + struct vb2_buffer *vb2); +void print_v4l2_buffer(u32 tag, const char *str, struct msm_vidc_inst *inst, + struct v4l2_buffer *v4l2); +void kref_put_mbuf(struct msm_vidc_buffer *mbuf); +bool kref_get_mbuf(struct msm_vidc_inst *inst, struct msm_vidc_buffer *mbuf); +void msm_comm_store_mark_data(struct msm_vidc_list *data_list, + u32 index, u32 mark_data, u32 mark_target); +void msm_comm_fetch_mark_data(struct msm_vidc_list *data_list, + u32 index, u32 *mark_data, u32 *mark_target); +int msm_comm_release_mark_data(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 msm_comm_num_queued_bufs(struct msm_vidc_inst *inst, u32 type); +bool msm_comm_check_for_inst_overload(struct msm_vidc_core *core); +void msm_vidc_batch_handler(struct work_struct *work); +#endif diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c new file mode 100644 index 000000000000..8d81a1e70288 --- /dev/null +++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c @@ -0,0 +1,605 @@ +/* Copyright (c) 2012-2020, 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 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" + +int msm_vidc_debug = VIDC_ERR | VIDC_WARN | VIDC_FW; +EXPORT_SYMBOL(msm_vidc_debug); + +int msm_vidc_debug_out = VIDC_OUT_PRINTK; +EXPORT_SYMBOL(msm_vidc_debug_out); + +/* 0x18 = HFI_DEBUG_MSG_FATAL | HFI_DEBUG_MSG_ERROR */ +int msm_vidc_fw_debug = 0x18; +int msm_vidc_fw_debug_mode = 1; +int msm_vidc_fw_low_power_mode = 1; +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; + +#define MAX_DBG_BUF_SIZE 4096 + +#define DYNAMIC_BUF_OWNER(__binfo) ({ \ + atomic_read(&__binfo->ref_count) >= 2 ? "video driver" : "firmware";\ +}) + +struct core_inst_pair { + struct msm_vidc_core *core; + struct msm_vidc_inst *inst; +}; + +static int core_info_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +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) { + dprintk(VIDC_ERR, "Invalid params, core: %pK\n", core); + return 0; + } + + dbuf = kzalloc(MAX_DBG_BUF_SIZE, GFP_KERNEL); + if (!dbuf) { + dprintk(VIDC_ERR, "%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) { + dprintk(VIDC_WARN, "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); + +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 = core_info_open, + .read = core_info_read, +}; + +static int trigger_ssr_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +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)) { + dprintk(VIDC_WARN, "%s User memory fault\n", __func__); + rc = -EFAULT; + goto exit; + } + + rc = kstrtoul(kbuf, 0, &ssr_trigger_val); + if (rc) { + dprintk(VIDC_WARN, "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 = trigger_ssr_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) { + dprintk(VIDC_ERR, "returning error - pos %lld, count %ld\n", + *ppos, count); + rc = -EINVAL; + } + + rc = simple_write_to_buffer(kbuf, sizeof(kbuf) - 1, ppos, buf, count); + if (rc < 0) { + dprintk(VIDC_ERR, "%s User memory fault\n", __func__); + rc = -EFAULT; + goto exit; + } + + rc = kstrtoint(kbuf, 0, &msm_vidc_debug); + if (rc) { + dprintk(VIDC_ERR, "returning error err %d\n", rc); + rc = -EINVAL; + } else { + core->resources.msm_vidc_hw_rsp_timeout = + (msm_vidc_debug > (VIDC_ERR | VIDC_WARN)) ? 1500 : 1000; + rc = count; + dprintk(VIDC_DBG, "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)) { \ + dprintk(VIDC_ERR, "Failed creating debugfs file '%pd/%s'\n", \ + dir, __name); \ + f = NULL; \ + } \ + f; \ +}) + + ok = + __debugfs_create(x32, "fw_level", &msm_vidc_fw_debug) && + __debugfs_create(u32, "fw_debug_mode", &msm_vidc_fw_debug_mode) && + __debugfs_create(bool, "fw_coverage", &msm_vidc_fw_coverage) && + __debugfs_create(u32, "fw_low_power_mode", + &msm_vidc_fw_low_power_mode) && + __debugfs_create(u32, "debug_output", &msm_vidc_debug_out) && + __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); + +#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) { + dprintk(VIDC_ERR, "Invalid params, core: %pK\n", core); + 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; + dprintk(VIDC_ERR, "Failed to create debugfs for msm_vidc\n"); + goto failed_create_dir; + } + if (!debugfs_create_file("info", 0444, dir, core, &core_info_fops)) { + dprintk(VIDC_ERR, "debugfs_create_file: fail\n"); + goto failed_create_dir; + } + if (!debugfs_create_file("trigger_ssr", 0200, + dir, core, &ssr_fops)) { + dprintk(VIDC_ERR, "debugfs_create_file: fail\n"); + goto failed_create_dir; + } + if (!debugfs_create_file("debug_level", 0644, + parent, core, &debug_level_fops)) { + dprintk(VIDC_ERR, "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) +{ + dprintk(VIDC_INFO, "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) { + dprintk(VIDC_ERR, "%s: invalid param\n", __func__); + return -EINVAL; + } + + if (inst->buffer_mode_set[CAPTURE_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 == V4L2_BUF_TYPE_VIDEO_CAPTURE_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; + + if (!idata || !idata->core || !idata->inst) { + dprintk(VIDC_ERR, "%s: Invalid params\n", __func__); + 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) { + dprintk(VIDC_ERR, "%s: Instance has become obsolete", __func__); + return 0; + } + + dbuf = kzalloc(MAX_DBG_BUF_SIZE, GFP_KERNEL); + if (!dbuf) { + dprintk(VIDC_ERR, "%s: Allocation failed!\n", __func__); + len = -ENOMEM; + goto failed_alloc; + } + cur = dbuf; + end = cur + MAX_DBG_BUF_SIZE; + + 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", + inst->prop.height[CAPTURE_PORT]); + cur += write_str(cur, end - cur, "width: %d\n", + inst->prop.width[CAPTURE_PORT]); + cur += write_str(cur, end - cur, "fps: %d\n", inst->prop.fps); + 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++) { + cur += write_str(cur, end - cur, "capability: %s\n", + i == OUTPUT_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", + inst->bufq[i].num_planes); + cur += write_str(cur, end - cur, + "type: %s\n", inst->fmts[i].type == OUTPUT_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 < inst->bufq[i].num_planes; j++) + cur += write_str(cur, end - cur, + "size for plane %d: %u\n", + j, inst->bufq[i].plane_sizes[j]); + + 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) +{ + dprintk(VIDC_INFO, "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) { + dprintk(VIDC_ERR, "Invalid params, inst: %pK\n", inst); + goto exit; + } + snprintf(debugfs_name, MAX_DEBUGFS_NAME, "inst_%p", inst); + + idata = kzalloc(sizeof(struct core_inst_pair), GFP_KERNEL); + if (!idata) { + dprintk(VIDC_ERR, "%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; + dprintk(VIDC_ERR, "Failed to create debugfs for msm_vidc\n"); + goto failed_create_dir; + } + + info = debugfs_create_file("info", 0444, dir, + idata, &inst_info_fops); + if (!info) { + dprintk(VIDC_ERR, "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) { + dprintk(VIDC_INFO, "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++; + 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++; + if (inst->count.ebd && inst->count.ebd == inst->count.etb) { + toc(inst, FRAME_PROCESSING); + dprintk(VIDC_PROF, "EBD: FW needs input buffers\n"); + } + if (inst->count.ftb == inst->count.fbd) + dprintk(VIDC_PROF, "EBD: FW needs output buffers\n"); + break; + case MSM_VIDC_DEBUGFS_EVENT_FTB: { + inst->count.ftb++; + 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++; + if (inst->count.fbd && + inst->count.fbd == inst->count.ftb) { + toc(inst, FRAME_PROCESSING); + dprintk(VIDC_PROF, "FBD: FW needs output buffers\n"); + } + if (inst->count.etb == inst->count.ebd) + dprintk(VIDC_PROF, "FBD: FW needs input buffers\n"); + break; + default: + dprintk(VIDC_ERR, "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); +} + diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.h b/drivers/media/platform/msm/vidc/msm_vidc_debug.h new file mode 100644 index 000000000000..17e6ed52429b --- /dev/null +++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.h @@ -0,0 +1,216 @@ +/* Copyright (c) 2012-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 __MSM_VIDC_DEBUG__ +#define __MSM_VIDC_DEBUG__ +#include +#include +#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 ": %4s: " + +/* 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 = 0x0001, + VIDC_WARN = 0x0002, + VIDC_INFO = 0x0004, + VIDC_DBG = 0x0008, + VIDC_PROF = 0x0010, + VIDC_PKT = 0x0020, + VIDC_FW = 0x1000, +}; + +enum vidc_msg_out { + VIDC_OUT_PRINTK = 0, +}; + +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, +}; + +extern int msm_vidc_debug; +extern int msm_vidc_debug_out; +extern int msm_vidc_fw_debug; +extern int msm_vidc_fw_debug_mode; +extern int msm_vidc_fw_low_power_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; + +#define dprintk(__level, __fmt, arg...) \ + do { \ + if (msm_vidc_debug & __level) { \ + if (msm_vidc_debug_out == VIDC_OUT_PRINTK) { \ + pr_info(VIDC_DBG_TAG __fmt, \ + get_debug_level_str(__level), \ + ## arg); \ + } \ + } \ + } while (0) + +#define dprintk_ratelimit(__level, __fmt, arg...) \ + do { \ + if (msm_vidc_debug & __level) { \ + if (msm_vidc_debug_out == VIDC_OUT_PRINTK && \ + msm_vidc_check_ratelimit()) { \ + pr_info(VIDC_DBG_TAG __fmt, \ + get_debug_level_str(__level), \ + ## arg); \ + } \ + } \ + } while (0) + +#define MSM_VIDC_ERROR(value) \ + do { if (value) \ + dprintk(VIDC_DBG, "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); + +static inline char *get_debug_level_str(int level) +{ + switch (level) { + case VIDC_ERR: + return "err"; + case VIDC_WARN: + return "warn"; + case VIDC_INFO: + return "info"; + case VIDC_DBG: + return "dbg"; + case VIDC_PROF: + return "prof"; + case VIDC_PKT: + return "pkt"; + case VIDC_FW: + return "fw"; + default: + return "???"; + } +} + +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_PROF) && + 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_PROF) && + !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_PROF)) { + if (i->debug.samples) { + dprintk(VIDC_PROF, "%s averaged %d ms/sample\n", + i->debug.pdata[x].name, + i->debug.pdata[x].cumulative / + i->debug.samples); + } + + dprintk(VIDC_PROF, "%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/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h new file mode 100644 index 000000000000..b2cad6dab3e2 --- /dev/null +++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h @@ -0,0 +1,581 @@ +/* Copyright (c) 2012-2021, 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 _MSM_VIDC_INTERNAL_H_ +#define _MSM_VIDC_INTERNAL_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "msm_vidc.h" +#include +#include "vidc_hfi_api.h" +#include + +#define MSM_VIDC_DRV_NAME "msm_vidc_driver" +#define MSM_VIDC_VERSION KERNEL_VERSION(0, 0, 1) +#define MAX_DEBUGFS_NAME 50 +#define DEFAULT_TIMEOUT 3 +#define DEFAULT_HEIGHT 1088 +#define DEFAULT_WIDTH 1920 +#define MIN_SUPPORTED_WIDTH 32 +#define MIN_SUPPORTED_HEIGHT 32 +#define DEFAULT_FPS 15 +#define MIN_NUM_OUTPUT_BUFFERS 1 +#define MIN_NUM_OUTPUT_BUFFERS_VP9 6 +#define MIN_NUM_CAPTURE_BUFFERS 1 +#define MAX_NUM_OUTPUT_BUFFERS VIDEO_MAX_FRAME // same as VB2_MAX_FRAME +#define MAX_NUM_CAPTURE_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 + +#define V4L2_EVENT_VIDC_BASE 10 + +#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 EXTRADATA_IDX(__num_planes) ((__num_planes) ? (__num_planes) - 1 : 0) + +#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, args...) \ + (((c) && (c)->core_ops && (c)->core_ops->op) ? \ + ((c)->core_ops->op(args)) : 0) + +struct msm_vidc_inst; + +enum vidc_ports { + OUTPUT_PORT, + CAPTURE_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 vidc_tag_data { + struct list_head list; + u32 index; + u32 type; + u32 input_tag; + u32 output_tag; +}; + +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 mark_data; + u32 mark_target; +}; + +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; +}; + +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; +}; + +struct msm_vidc_capability_range { + u32 min; + u32 max; +}; + +struct msm_vidc_image_capability { + struct msm_vidc_capability_range width; + struct msm_vidc_capability_range height; +}; + +enum vpu_version { + VPU_VERSION_4 = 1, + VPU_VERSION_5, +}; + +#define IS_VPU_4(ver) \ + (ver == VPU_VERSION_4) + +#define IS_VPU_5(ver) \ + (ver == VPU_VERSION_5) + +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_csc_coeff csc_data; + struct msm_vidc_efuse_data *efuse_data; + unsigned int efuse_data_length; + struct msm_vidc_ubwc_config *ubwc_config; + unsigned int ubwc_config_length; + struct msm_vidc_image_capability *heic_image_capability; + struct msm_vidc_image_capability *hevc_image_capability; + unsigned int sku_version; + uint32_t vpu_ver; +}; + +struct msm_vidc_format { + char name[MAX_NAME_LENGTH]; + u8 description[32]; + u32 fourcc; + int type; + u32 (*get_frame_size)(int plane, u32 height, u32 width); + bool defer_outputs; + u32 input_min_count; + u32 output_min_count; +}; + +struct msm_vidc_format_constraint { + u32 fourcc; + u32 num_planes; + u32 y_stride_multiples; + u32 y_max_stride; + u32 y_min_plane_buffer_height_multiple; + u32 y_buffer_alignment; + u32 uv_stride_multiples; + u32 uv_max_stride; + u32 uv_min_plane_buffer_height_multiple; + 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_crop { + u32 left; + u32 top; + u32 width; + u32 height; +}; + +struct session_prop { + u32 width[MAX_PORT_NUM]; + u32 height[MAX_PORT_NUM]; + struct session_crop crop_info; + u32 fps; + u32 bitrate; +}; + +struct buf_queue { + struct vb2_queue vb2_bufq; + struct mutex lock; + unsigned int plane_sizes[VB2_MAX_PLANES]; + int num_planes; +}; + +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 load; + int load_low; + int load_norm; + int load_high; + int min_threshold; + int max_threshold; + enum hal_buffer buffer_type; + bool dcvs_mode; + 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; + enum hal_work_mode work_mode; + bool low_latency_mode; + bool turbo_mode; + u32 work_route; + u32 dcvs_flags; +}; + +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), + VIDC_REALTIME = BIT(4), +}; + +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); +}; + +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; + u32 enc_codec_supported; + u32 dec_codec_supported; + u32 codec_count; + struct msm_vidc_capability *capabilities; + struct delayed_work fw_unload_work; + struct work_struct ssr_work; + 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 list_head list; + struct mutex sync_lock, lock; + struct msm_vidc_core *core; + enum session_type session_type; + void *session; + 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 freqs; + struct msm_vidc_list input_crs; + struct msm_vidc_list buffer_tags; + 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 reconbufs; + 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 buffer_requirements buff_req; + struct v4l2_ctrl_handler ctrl_handler; + struct completion completions[SESSION_MSG_END - SESSION_MSG_START + 1]; + struct v4l2_ctrl **cluster; + struct v4l2_fh event_handler; + struct msm_smem *extradata_handle; + bool in_reconfig; + u32 reconfig_width; + u32 reconfig_height; + struct dentry *debugfs_root; + void *priv; + struct msm_vidc_debug debug; + struct buf_count count; + struct clock_data clk_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; + int bit_depth; + struct kref kref; + bool in_flush; + u32 pic_struct; + u32 colour_space; + u32 profile; + u32 level; + u32 entropy_mode; + u32 grid_enable; + u32 frame_quality; + struct msm_vidc_codec_data *codec_data; + struct hal_hdr10_pq_sei hdr10_sei_params; + struct batch_mode batch; + struct timer_list batch_timer; + struct work_struct batch_work; + bool decode_batching; + u32 max_filled_length; + bool operating_rate_set; +}; + +extern struct msm_vidc_drv *vidc_driver; + +struct msm_vidc_ctrl_cluster { + struct v4l2_ctrl **cluster; + struct list_head list; +}; + +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; + u64 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_freeze_core(struct msm_vidc_core *core); +int msm_vidc_noc_error_info(struct msm_vidc_core *core); +bool heic_encode_session_supported(struct msm_vidc_inst *inst); +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; + u32 output_tag; +}; + +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); +int msm_smem_free(struct msm_smem *smem); + +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); +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); +void msm_smem_put_dma_buf(void *dma_buf); +int msm_smem_cache_operations(struct dma_buf *dbuf, + enum smem_cache_ops cache_op, unsigned long offset, unsigned long size); +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/drivers/media/platform/msm/vidc/msm_vidc_platform.c b/drivers/media/platform/msm/vidc/msm_vidc_platform.c new file mode 100644 index 000000000000..0470055e24b3 --- /dev/null +++ b/drivers/media/platform/msm/vidc/msm_vidc_platform.c @@ -0,0 +1,1128 @@ +/* Copyright (c) 2017-2021, 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 +#include +#include +#include +#include +#include "msm_vidc_internal.h" +#include "msm_vidc_debug.h" +#include "vidc_hfi_helper.h" + +#define CODEC_ENTRY(n, p, vsp, vpp, lp) \ +{ \ + .fourcc = n, \ + .session_type = p, \ + .vsp_cycles = vsp, \ + .vpp_cycles = vpp, \ + .low_power_cycles = lp \ +} + +#define UBWC_CONFIG(sz, type, mco, mlo, hbbo, rs1, mc, ml, hbb, rs2) \ +{ \ + .nSize = sz, \ + .ePacketType = type, \ + .v1.sOverrideBitInfo.bMaxChannelsOverride = mco, \ + .v1.sOverrideBitInfo.bMalLengthOverride = mlo, \ + .v1.sOverrideBitInfo.bHBBOverride = hbbo, \ + .v1.sOverrideBitInfo.reserved1 = rs1, \ + .v1.nMaxChannels = mc, \ + .v1.nMalLength = ml, \ + .v1.nHighestBankBit = hbb, \ + .v1.reserved2 = {rs2} \ +} + +#define EFUSE_ENTRY(sa, s, m, sh, p) \ +{ \ + .start_address = sa, \ + .size = s, \ + .mask = m, \ + .shift = sh, \ + .purpose = p \ +} + +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 atoll data */ +static struct msm_vidc_codec_data atoll_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), +}; + +/* 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), +}; + +/* Update with trinket data */ +static struct msm_vidc_codec_data trinket_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), +}; + +/* Update with 855 data */ +static struct msm_vidc_codec_data sm8150_codec_data[] = { + CODEC_ENTRY(V4L2_PIX_FMT_H264, MSM_VIDC_ENCODER, 10, 675, 320), + CODEC_ENTRY(V4L2_PIX_FMT_HEVC, MSM_VIDC_ENCODER, 10, 675, 320), + CODEC_ENTRY(V4L2_PIX_FMT_VP8, MSM_VIDC_ENCODER, 10, 675, 320), + CODEC_ENTRY(V4L2_PIX_FMT_TME, MSM_VIDC_ENCODER, 0, 540, 540), + CODEC_ENTRY(V4L2_PIX_FMT_MPEG2, MSM_VIDC_DECODER, 10, 200, 200), + CODEC_ENTRY(V4L2_PIX_FMT_H264, MSM_VIDC_DECODER, 10, 200, 200), + CODEC_ENTRY(V4L2_PIX_FMT_HEVC, MSM_VIDC_DECODER, 10, 200, 200), + CODEC_ENTRY(V4L2_PIX_FMT_VP8, MSM_VIDC_DECODER, 10, 200, 200), + CODEC_ENTRY(V4L2_PIX_FMT_VP9, MSM_VIDC_DECODER, 10, 200, 200), +}; + +static struct msm_vidc_codec_data sdmmagpie_codec_data[] = { + CODEC_ENTRY(V4L2_PIX_FMT_H264, MSM_VIDC_ENCODER, 10, 675, 320), + CODEC_ENTRY(V4L2_PIX_FMT_HEVC, MSM_VIDC_ENCODER, 10, 675, 320), + CODEC_ENTRY(V4L2_PIX_FMT_VP8, MSM_VIDC_ENCODER, 10, 675, 320), + CODEC_ENTRY(V4L2_PIX_FMT_TME, MSM_VIDC_ENCODER, 0, 540, 540), + CODEC_ENTRY(V4L2_PIX_FMT_MPEG2, MSM_VIDC_DECODER, 10, 200, 200), + CODEC_ENTRY(V4L2_PIX_FMT_H264, MSM_VIDC_DECODER, 10, 200, 200), + CODEC_ENTRY(V4L2_PIX_FMT_HEVC, MSM_VIDC_DECODER, 10, 200, 200), + CODEC_ENTRY(V4L2_PIX_FMT_VP8, MSM_VIDC_DECODER, 10, 200, 200), + CODEC_ENTRY(V4L2_PIX_FMT_VP9, MSM_VIDC_DECODER, 10, 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), +}; + +/* + * 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] = { + 470, 8170, 8148, 0, 490, 50, 0, 34, 483 +}; + +/* offset coefficients in s9 fixed point format */ +static u32 vpe_csc_custom_bias_coeff[HAL_MAX_BIAS_COEFFS] = { + 34, 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, + }, +}; + +static struct msm_vidc_common_data atoll_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 = 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-size", + .value = 8160, + }, + { + .key = "qcom,max-b-frames-per-sec", + .value = 60, + }, + { + .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 atoll_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 = 1216800, /* UHD@30 +1080@30 */ + }, + { + .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-size", + .value = 8160, + }, + { + .key = "qcom,max-b-frames-per-sec", + .value = 60, + }, + { + .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 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 = 3, + }, + { + .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-size", + .value = 8160, + }, + { + .key = "qcom,max-b-frames-per-sec", + .value = 60, + }, + { + .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 trinket_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 = 6, + }, + { + .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-size", + .value = 8160, + }, + { + .key = "qcom,max-b-frames-per-sec", + .value = 60, + }, + { + .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 = 3, + }, + { + .key = "qcom,max-hw-load", + .value = 3916800, /* + * 1920x1088/256 MBs@480fps. It is less + * any other usecases (ex: + * 3840x2160@120fps, 4096x2160@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-size", + .value = 8160, + }, + { + .key = "qcom,max-b-frames-per-sec", + .value = 60, + }, + { + .key = "qcom,power-collapse-delay", + .value = 1500, + }, + { + .key = "qcom,hw-resp-timeout", + .value = 1000, + }, + { + .key = "qcom,debug-timeout", + .value = 0, + }, + { + .key = "qcom,domain-cvp", + .value = 1, + }, + { + .key = "qcom,decode-batching", + .value = 1, + }, + { + .key = "qcom,dcvs", + .value = 1, + }, + { + .key = "qcom,fw-cycles", + .value = 760000, + }, + { + .key = "qcom,fw-vpp-cycles", + .value = 166667, + }, +}; + +static struct msm_vidc_common_data sdmmagpie_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 = 3110400, /* 4096x2160@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-size", + .value = 8160, + }, + { + .key = "qcom,max-b-frames-per-sec", + .value = 60, + }, + { + .key = "qcom,power-collapse-delay", + .value = 1500, + }, + { + .key = "qcom,hw-resp-timeout", + .value = 1000, + }, + { + .key = "qcom,debug-timeout", + .value = 0, + }, + { + .key = "qcom,domain-cvp", + .value = 1, + }, + { + .key = "qcom,decode-batching", + .value = 1, + }, + { + .key = "qcom,dcvs", + .value = 1, + }, + { + .key = "qcom,fw-cycles", + .value = 760000, + }, + { + .key = "qcom,fw-vpp-cycles", + .value = 166667, + }, +}; + +static struct msm_vidc_common_data sdmmagpie_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 = 1281600, /* 4k@30 Decode + 1080p@30 Encode */ + }, + { + .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-size", + .value = 8160, + }, + { + .key = "qcom,max-b-frames-per-sec", + .value = 60, + }, + { + .key = "qcom,power-collapse-delay", + .value = 1500, + }, + { + .key = "qcom,hw-resp-timeout", + .value = 1000, + }, + { + .key = "qcom,debug-timeout", + .value = 0, + }, + { + .key = "qcom,domain-cvp", + .value = 1, + }, + { + .key = "qcom,decode-batching", + .value = 1, + }, + { + .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 = 3, + }, + { + .key = "qcom,max-hw-load", + .value = 3110400, /* 4096x2160@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-size", + .value = 8160, + }, + { + .key = "qcom,max-b-frames-per-sec", + .value = 60, + }, + { + .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 = 6, + }, + { + .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-size", + .value = 8160, + }, + { + .key = "qcom,max-b-frames-per-sec", + .value = 60, + }, + { + .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 = 6, + }, + { + .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-size", + .value = 8160, + }, + { + .key = "qcom,max-b-frames-per-sec", + .value = 60, + }, + { + .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 sdm670_efuse_data[] = { + EFUSE_ENTRY(0x007801A0, 4, 0x00008000, 0x0f, SKU_VERSION), +}; + +static struct msm_vidc_efuse_data sdmmagpie_efuse_data[] = { + EFUSE_ENTRY(0x00786018, 4, 0x00000400, 0x0a, SKU_VERSION), +}; + +static struct msm_vidc_efuse_data atoll_efuse_data[] = { + EFUSE_ENTRY(0x007801D4, 4, 0x08000000, 0x1b, SKU_VERSION), +}; + +static struct msm_vidc_ubwc_config trinket_ubwc_data[] = { + UBWC_CONFIG(sizeof(struct msm_vidc_ubwc_config_v1), + HFI_PROPERTY_SYS_UBWC_CONFIG, 0, 1, 0, 0, 0, 64, 0, 0), +}; + +static struct msm_vidc_ubwc_config sdmshrike_ubwc_data[] = { + UBWC_CONFIG(sizeof(struct msm_vidc_ubwc_config), + HFI_PROPERTY_SYS_UBWC_CONFIG, 1, 0, 1, 0, 8, 0, 16, 0), +}; + +static struct msm_vidc_image_capability default_heic_image_capability = { + {512, 8192}, {512, 8192} +}; + +static struct msm_vidc_image_capability default_hevc_image_capability = { + {512, 512}, {512, 512} +}; + +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), + .ubwc_config = 0, + .ubwc_config_length = 0, + .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, + .heic_image_capability = &default_heic_image_capability, + .hevc_image_capability = &default_hevc_image_capability, + .sku_version = 0, + .vpu_ver = VPU_VERSION_5, +}; + +static struct msm_vidc_platform_data atoll_data = { + .codec_data = atoll_codec_data, + .codec_data_length = ARRAY_SIZE(atoll_codec_data), + .common_data = atoll_common_data, + .common_data_length = ARRAY_SIZE(atoll_common_data), + .ubwc_config = NULL, + .ubwc_config_length = 0, + .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 = atoll_efuse_data, + .efuse_data_length = ARRAY_SIZE(atoll_efuse_data), + .heic_image_capability = &default_heic_image_capability, + .hevc_image_capability = &default_hevc_image_capability, + .sku_version = 0, + .vpu_ver = VPU_VERSION_4, +}; + +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), + .ubwc_config = 0, + .ubwc_config_length = 0, + .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, + .heic_image_capability = NULL, + .hevc_image_capability = NULL, + .sku_version = 0, + .vpu_ver = VPU_VERSION_4, +}; + +static struct msm_vidc_platform_data trinket_data = { + .codec_data = trinket_codec_data, + .codec_data_length = ARRAY_SIZE(trinket_codec_data), + .common_data = trinket_common_data, + .common_data_length = ARRAY_SIZE(trinket_common_data), + .ubwc_config = trinket_ubwc_data, + .ubwc_config_length = ARRAY_SIZE(trinket_ubwc_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, + .heic_image_capability = &default_heic_image_capability, + .hevc_image_capability = &default_hevc_image_capability, + .sku_version = 0, + .vpu_ver = VPU_VERSION_4, +}; + +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), + .ubwc_config = 0, + .ubwc_config_length = 0, + .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, + .heic_image_capability = &default_heic_image_capability, + .hevc_image_capability = &default_hevc_image_capability, + .sku_version = 0, + .vpu_ver = VPU_VERSION_5, +}; + +static struct msm_vidc_platform_data sdmshrike_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), + .ubwc_config = sdmshrike_ubwc_data, + .ubwc_config_length = ARRAY_SIZE(sdmshrike_ubwc_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, + .heic_image_capability = &default_heic_image_capability, + .hevc_image_capability = &default_hevc_image_capability, + .sku_version = 0, + .vpu_ver = VPU_VERSION_5, +}; + +static struct msm_vidc_platform_data sdmmagpie_data = { + .codec_data = sdmmagpie_codec_data, + .codec_data_length = ARRAY_SIZE(sdmmagpie_codec_data), + .common_data = sdmmagpie_common_data_v0, + .common_data_length = ARRAY_SIZE(sdmmagpie_common_data_v0), + .ubwc_config = 0, + .ubwc_config_length = 0, + .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 = sdmmagpie_efuse_data, + .efuse_data_length = ARRAY_SIZE(sdmmagpie_efuse_data), + .heic_image_capability = &default_heic_image_capability, + .hevc_image_capability = &default_hevc_image_capability, + .sku_version = 0, + .vpu_ver = VPU_VERSION_5, +}; + +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), + .ubwc_config = 0, + .ubwc_config_length = 0, + .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, + .heic_image_capability = NULL, + .hevc_image_capability = NULL, + .sku_version = 0, + .vpu_ver = VPU_VERSION_4, +}; + +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), + .ubwc_config = 0, + .ubwc_config_length = 0, + .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), + .heic_image_capability = NULL, + .hevc_image_capability = NULL, + .sku_version = 0, + .vpu_ver = VPU_VERSION_4, +}; + +static const struct of_device_id msm_vidc_dt_match[] = { + { + .compatible = "qcom,atoll-vidc", + .data = &atoll_data, + }, + { + .compatible = "qcom,sm6150-vidc", + .data = &sm6150_data, + }, + { + .compatible = "qcom,trinket-vidc", + .data = &trinket_data, + }, + { + .compatible = "qcom,sm8150-vidc", + .data = &sm8150_data, + }, + { + .compatible = "qcom,sdmshrike-vidc", + .data = &sdmshrike_data, + }, + { + .compatible = "qcom,sdmmagpie-vidc", + .data = &sdmmagpie_data, + }, + { + .compatible = "qcom,sdm845-vidc", + .data = &sdm845_data, + }, + { + .compatible = "qcom,sdm670-vidc", + .data = &sdm670_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; + + 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) { + dprintk(VIDC_ERR, + "failed efuse ioremap: res->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; + dprintk(VIDC_DBG, + "efuse 0x%x, platform version 0x%x\n", + efuse, data->sku_version); + + devm_iounmap(dev, base); + } + break; + + default: + break; + } + } + return 0; +} + +void *vidc_get_drv_data(struct device *dev) +{ + struct msm_vidc_platform_data *driver_data = NULL; + const struct of_device_id *match; + int rc = 0; + + if (!IS_ENABLED(CONFIG_OF) || !dev->of_node) { + 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 (!of_find_property(dev->of_node, "sku-index", NULL) || + !driver_data) { + goto exit; + } else if (!strcmp(match->compatible, "qcom,sdm670-vidc")) { + rc = msm_vidc_read_efuse(driver_data, dev); + if (rc) + goto exit; + + 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,sdmmagpie-vidc")) { + rc = msm_vidc_read_efuse(driver_data, dev); + if (rc) + goto exit; + + if (driver_data->sku_version == SKU_VERSION_1) { + driver_data->common_data = sdmmagpie_common_data_v1; + driver_data->common_data_length = + ARRAY_SIZE(sdmmagpie_common_data_v1); + } + } else if (!strcmp(match->compatible, "qcom,atoll-vidc")) { + rc = msm_vidc_read_efuse(driver_data, dev); + if (rc) + goto exit; + + if (driver_data->sku_version == SKU_VERSION_1) { + /* atoll SKU does not differentiate for any param in + * devicetree.Keeping the same index for different SKU + * so as to parse same DT node. + */ + driver_data->sku_version = 0; + driver_data->common_data = atoll_common_data_v1; + driver_data->common_data_length = + ARRAY_SIZE(atoll_common_data_v1); + } + } + +exit: + return driver_data; +} diff --git a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c new file mode 100644 index 000000000000..bff189c8760a --- /dev/null +++ b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c @@ -0,0 +1,1433 @@ +/* Copyright (c) 2012-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. + * + */ + +#include +#include +#include +#include +#include +#include "msm_vidc_debug.h" +#include "msm_vidc_resources.h" +#include "msm_vidc_res_parse.h" +#include "venus_boot.h" +#include "soc/qcom/secure_buffer.h" + +enum clock_properties { + CLOCK_PROP_HAS_SCALING = 1 << 0, + CLOCK_PROP_HAS_MEM_RETENTION = 1 << 1, +}; + +#define PERF_GOV "performance" + +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)) { + dprintk(VIDC_ERR, "Failed to read %s from device tree\n", + name); + goto fail_read; + } + + num_elements = len / sizeof(u32); + if (num_elements <= 0) { + dprintk(VIDC_ERR, "%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 + */ + dprintk(VIDC_DBG, "qcom,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) { + dprintk(VIDC_DBG, "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) { + dprintk(VIDC_ERR, "%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)) { + dprintk(VIDC_ERR, "Failed to read register table\n"); + msm_vidc_free_reg_table(res); + return -EINVAL; + } + for (i = 0; i < reg_set->count; i++) { + dprintk(VIDC_DBG, + "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 + */ + dprintk(VIDC_DBG, "qcom,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) { + dprintk(VIDC_DBG, "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) { + dprintk(VIDC_ERR, "%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) { + dprintk(VIDC_ERR, "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++) { + dprintk(VIDC_DBG, "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) { + dprintk(VIDC_DBG, "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) { + dprintk(VIDC_ERR, + "Failed to allocate memory for subcache tbl\n"); + rc = -ENOMEM; + goto err_load_subcache_table_fail; + } + + subcaches->count = num_subcaches; + dprintk(VIDC_DBG, "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)) { + dprintk(VIDC_DBG, "%s not found\n", table_name); + return 0; + } + + num_elemts = get_u32_array_num_elements(of_node, table_name); + if (!num_elemts) { + dprintk(VIDC_ERR, "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) { + dprintk(VIDC_ERR, "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))) { + dprintk(VIDC_ERR, "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)) { + dprintk(VIDC_DBG, "qcom,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) { + dprintk(VIDC_ERR, + "%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) { + dprintk(VIDC_ERR, "%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) { + dprintk(VIDC_ERR, "'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) { + dprintk(VIDC_ERR, "'qcom,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) { + dprintk(VIDC_ERR, "'qcom,bus-slave' not found in node\n"); + goto err_bus; + } + + rc = of_property_read_string(dev->of_node, "qcom,bus-governor", + &bus->governor); + if (rc) { + rc = 0; + dprintk(VIDC_DBG, + "'qcom,bus-governor' not found, default to performance governor\n"); + bus->governor = PERF_GOV; + } + + if (!strcmp(bus->governor, PERF_GOV)) + bus->is_prfm_gov_used = true; + + rc = of_property_read_u32_array(dev->of_node, "qcom,bus-range-kbps", + range, ARRAY_SIZE(range)); + if (rc) { + rc = 0; + dprintk(VIDC_DBG, + "'qcom,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; + dprintk(VIDC_DBG, "Found bus %s [%d->%d] with governor %s\n", + bus->name, bus->master, bus->slave, bus->governor); +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 + */ + dprintk(VIDC_DBG, "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) { + dprintk(VIDC_DBG, "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) { + dprintk(VIDC_ERR, "%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) { + dprintk(VIDC_ERR, "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; + dprintk(VIDC_ERR, + "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)) { + dprintk(VIDC_WARN, "%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; + dprintk(VIDC_ERR, + "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"); + + dprintk(VIDC_DBG, "Found regulator %s: h/w collapse = %s\n", + rinfo->name, + rinfo->has_hw_power_collapse ? "yes" : "no"); + } + + if (!regulators->count) + dprintk(VIDC_DBG, "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) { + dprintk(VIDC_DBG, "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) { + dprintk(VIDC_ERR, "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) { + dprintk(VIDC_ERR, "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) { + dprintk(VIDC_ERR, "Failed to allocate memory for clock tbl\n"); + rc = -ENOMEM; + goto err_load_clk_prop_fail; + } + + clocks->count = num_clocks; + dprintk(VIDC_DBG, "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->count = 0; + vc->has_scaling = false; + } + + if (clock_props[c] & CLOCK_PROP_HAS_MEM_RETENTION) + vc->has_mem_retention = true; + else + vc->has_mem_retention = false; + + dprintk(VIDC_DBG, "Found clock %s: scale-able = %s\n", vc->name, + vc->count ? "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) { + dprintk(VIDC_DBG, "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; + dprintk(VIDC_DBG, "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) { + dprintk(VIDC_DBG, "'sku_index' not found in node\n"); + return 0; + } + + if (sku_index != res->sku_version) { + dprintk(VIDC_DBG, + "Failed to parser dt: sku_index %d res->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) { + dprintk(VIDC_ERR, "%s Invalid data\n", __func__); + return -ENOENT; + } + platform_data = core->platform_data; + res = &core->resources; + + res->codec_data_count = platform_data->codec_data_length; + res->codec_data = platform_data->codec_data; + + res->sku_version = platform_data->sku_version; + + res->fw_name = "venus"; + + dprintk(VIDC_DBG, "Firmware filename: %s\n", res->fw_name); + + res->max_load = find_key_value(platform_data, + "qcom,max-hw-load"); + + 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->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->domain_cvp = find_key_value(platform_data, + "qcom,domain-cvp"); + 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->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->csc_coeff_data = &platform_data->csc_data; + + res->vpu_ver = platform_data->vpu_ver; + + res->ubwc_config = platform_data->ubwc_config; + res->ubwc_config_length = platform_data->ubwc_config_length; + + 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"); + } + + if (IS_ERR(res->cx_ipeak_context)) { + rc = PTR_ERR(res->cx_ipeak_context); + if (rc == -EPROBE_DEFER) + dprintk(VIDC_INFO, + "cx-ipeak register failed. Deferring probe!"); + else + dprintk(VIDC_ERR, + "cx-ipeak register failed. rc: %d", rc); + + res->cx_ipeak_context = NULL; + goto err_cx_ipeak; + } + + if (res->cx_ipeak_context) + dprintk(VIDC_INFO, "cx-ipeak register successful"); + else + dprintk(VIDC_INFO, "cx-ipeak register not implemented"); + + of_property_read_u32(pdev->dev.of_node, + "qcom,clock-freq-threshold", + &res->clk_freq_threshold); + dprintk(VIDC_DBG, "cx ipeak threshold frequency = %u\n", + res->clk_freq_threshold); + + return rc; + +err_cx_ipeak: + 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) { + dprintk(VIDC_ERR, "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) + dprintk(VIDC_WARN, "Failed to load subcache info: %d\n", rc); + + rc = msm_vidc_load_qdss_table(res); + if (rc) + dprintk(VIDC_WARN, "Failed to load qdss reg table: %d\n", rc); + + rc = msm_vidc_load_reg_table(res); + if (rc) { + dprintk(VIDC_ERR, "Failed to load reg table: %d\n", rc); + goto err_load_reg_table; + } + + rc = msm_vidc_load_buffer_usage_table(res); + if (rc) { + dprintk(VIDC_ERR, + "Failed to load buffer usage table: %d\n", rc); + goto err_load_buffer_usage_table; + } + + rc = msm_vidc_load_regulator_table(res); + if (rc) { + dprintk(VIDC_ERR, "Failed to load list of regulators %d\n", rc); + goto err_load_regulator_table; + } + + rc = msm_vidc_load_clock_table(res); + if (rc) { + dprintk(VIDC_ERR, + "Failed to load clock table: %d\n", rc); + goto err_load_clock_table; + } + + rc = msm_vidc_load_allowed_clocks_table(res); + if (rc) { + dprintk(VIDC_ERR, + "Failed to load allowed clocks table: %d\n", rc); + goto err_load_allowed_clocks_table; + } + + if (of_device_is_compatible(pdev->dev.of_node, + "qcom,sa6155p-vidc")) { + res->max_load = 2073600; + dprintk(VIDC_INFO, "msm_vidc: Use higher max_load on Auto\n"); + } + + rc = msm_vidc_load_reset_table(res); + if (rc) { + dprintk(VIDC_ERR, + "Failed to load reset table: %d\n", rc); + goto err_load_reset_table; + } + + rc = msm_vidc_populate_legacy_context_bank(res); + if (rc) { + dprintk(VIDC_ERR, + "Failed to setup context banks %d\n", rc); + goto err_setup_legacy_cb; + } + + res->use_non_secure_pil = of_property_read_bool(pdev->dev.of_node, + "qcom,use-non-secure-pil"); + + if (res->use_non_secure_pil || !is_iommu_present(res)) { + of_property_read_u32(pdev->dev.of_node, "qcom,fw-bias", + &firmware_base); + res->firmware_base = (phys_addr_t)firmware_base; + dprintk(VIDC_DBG, + "Using fw-bias : %pa", &res->firmware_base); + } + + rc = msm_vidc_populate_cx_ipeak_context(res); + if (rc) { + dprintk(VIDC_ERR, + "Failed to setup cx-ipeak %d\n", rc); + goto err_register_cx_ipeak; + } + +return rc; + +err_load_reset_table: +err_register_cx_ipeak: +err_setup_legacy_cb: + 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 get_secure_vmid(struct context_bank_info *cb) +{ + if (!strcasecmp(cb->name, "venus_sec_bitstream")) + return VMID_CP_BITSTREAM; + else if (!strcasecmp(cb->name, "venus_sec_pixel")) + return VMID_CP_PIXEL; + else if (!strcasecmp(cb->name, "venus_sec_non_pixel")) + return VMID_CP_NON_PIXEL; + + WARN(1, "No matching secure vmid for cb name: %s\n", + cb->name); + return VMID_INVAL; +} + +static int msm_vidc_setup_context_bank(struct msm_vidc_platform_resources *res, + struct context_bank_info *cb, struct device *dev) +{ + int rc = 0; + int secure_vmid = VMID_INVAL; + struct bus_type *bus; + + if (!dev || !cb || !res) { + dprintk(VIDC_ERR, + "%s: Invalid Input params\n", __func__); + return -EINVAL; + } + cb->dev = dev; + + bus = cb->dev->bus; + if (IS_ERR_OR_NULL(bus)) { + dprintk(VIDC_ERR, "%s - failed to get bus type\n", __func__); + rc = PTR_ERR(bus) ?: -ENODEV; + goto remove_cb; + } + + cb->mapping = arm_iommu_create_mapping(bus, cb->addr_range.start, + cb->addr_range.size); + if (IS_ERR_OR_NULL(cb->mapping)) { + dprintk(VIDC_ERR, "%s - failed to create mapping\n", __func__); + rc = PTR_ERR(cb->mapping) ?: -ENODEV; + goto remove_cb; + } + + if (cb->is_secure) { + secure_vmid = get_secure_vmid(cb); + rc = iommu_domain_set_attr(cb->mapping->domain, + DOMAIN_ATTR_SECURE_VMID, &secure_vmid); + if (rc) { + dprintk(VIDC_ERR, + "%s - programming secure vmid failed: %s %d\n", + __func__, dev_name(dev), rc); + goto release_mapping; + } + } + + if (res->cache_pagetables) { + int cache_pagetables = 1; + + rc = iommu_domain_set_attr(cb->mapping->domain, + DOMAIN_ATTR_USE_UPSTREAM_HINT, &cache_pagetables); + if (rc) { + WARN_ONCE(rc, + "%s: failed to set cache pagetables attribute, %d\n", + __func__, rc); + rc = 0; + } + } + + rc = arm_iommu_attach_device(cb->dev, cb->mapping); + if (rc) { + dprintk(VIDC_ERR, "%s - Couldn't arm_iommu_attach_device\n", + __func__); + goto release_mapping; + } + + /* + * 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)); + + dprintk(VIDC_DBG, "Attached %s and created mapping\n", dev_name(dev)); + dprintk(VIDC_DBG, + "Context bank name:%s, buffer_type: %#x, is_secure: %d, address range start: %#x, size: %#x, dev: %pK, mapping: %pK", + cb->name, cb->buffer_type, cb->is_secure, cb->addr_range.start, + cb->addr_range.size, cb->dev, cb->mapping); + + return rc; + +release_mapping: + arm_iommu_release_mapping(cb->mapping); +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; + struct msm_vidc_inst *inst; + + if (!domain || !core) { + dprintk(VIDC_ERR, "%s - invalid param %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; + } + } + + dprintk(VIDC_ERR, "%s - faulting address: %lx\n", __func__, iova); + + mutex_lock(&core->lock); + list_for_each_entry(inst, &core->instances, list) { + msm_comm_print_inst_info(inst); + } + core->smmu_fault_handled = true; + mutex_unlock(&core->lock); + /* + * Return -ENOSYS to elicit the default behaviour of smmu driver. + * If we return -ENOSYS, 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 -ENOSYS; +} + +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) { + dprintk(VIDC_ERR, "%s - invalid inputs\n", __func__); + return -EINVAL; + } + + np = dev->of_node; + cb = devm_kzalloc(dev, sizeof(*cb), GFP_KERNEL); + if (!cb) { + dprintk(VIDC_ERR, "%s - Failed to allocate cb\n", __func__); + return -ENOMEM; + } + + INIT_LIST_HEAD(&cb->list); + list_add_tail(&cb->list, &core->resources.context_banks); + + rc = of_property_read_string(np, "label", &cb->name); + if (rc) { + dprintk(VIDC_DBG, + "Failed to read cb label from device tree\n"); + rc = 0; + } + + dprintk(VIDC_DBG, "%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) { + dprintk(VIDC_ERR, + "Could not read addr pool for context bank : %s %d\n", + cb->name, rc); + goto err_setup_cb; + } + + cb->is_secure = of_property_read_bool(np, "qcom,secure-context-bank"); + dprintk(VIDC_DBG, "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) { + dprintk(VIDC_ERR, "failed to load buffer_type info %d\n", rc); + rc = -ENOENT; + goto err_setup_cb; + } + dprintk(VIDC_DBG, + "context bank %s address start = %x address 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) { + dprintk(VIDC_ERR, "Cannot setup context bank %d\n", rc); + goto err_setup_cb; + } + + if (core->resources.non_fatal_pagefaults) { + int data = 1; + + dprintk(VIDC_DBG, "set non-fatal-faults attribute on %s\n", + dev_name(dev)); + rc = iommu_domain_set_attr(cb->mapping->domain, + DOMAIN_ATTR_NON_FATAL_FAULTS, &data); + if (rc) { + dprintk(VIDC_WARN, + "%s: set non fatal attribute failed: %s %d\n", + __func__, dev_name(dev), rc); + /* ignore the error */ + } + } + + iommu_set_fault_handler(cb->mapping->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) { + dprintk(VIDC_ERR, "%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) { + dprintk(VIDC_DBG, + "%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) { + dprintk(VIDC_ERR, + "%s - Failed to allocate cb\n", __func__); + return -ENOMEM; + } + INIT_LIST_HEAD(&cb->list); + list_add_tail(&cb->list, &res->context_banks); + + ctx_node = of_parse_phandle(domains_child_node, + "qcom,vidc-domain-phandle", 0); + if (!ctx_node) { + dprintk(VIDC_ERR, + "%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) { + dprintk(VIDC_ERR, + "%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) { + dprintk(VIDC_ERR, + "%s Could not read addr pool for group : %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) { + dprintk(VIDC_ERR, + "%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)) { + dprintk(VIDC_ERR, "%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) { + dprintk(VIDC_ERR, "Cannot setup context bank %d\n", rc); + goto err_setup_cb; + } + dprintk(VIDC_DBG, + "%s: context bank %s secure %d addr start = %#x addr size = %#x buffer_type = %#x\n", + __func__, 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) { + dprintk(VIDC_ERR, "Invalid platform device\n"); + return -EINVAL; + } else if (!pdev->dev.parent) { + dprintk(VIDC_ERR, "Failed to find a parent for %s\n", + dev_name(&pdev->dev)); + return -ENODEV; + } + + core = dev_get_drvdata(pdev->dev.parent); + if (!core) { + dprintk(VIDC_ERR, "Failed to find cookie in parent device %s", + dev_name(pdev->dev.parent)); + return -EINVAL; + } + + if (of_property_read_bool(pdev->dev.of_node, "qcom,fw-context-bank")) { + if (core->resources.use_non_secure_pil) { + struct context_bank_info *cb; + + cb = devm_kzalloc(&pdev->dev, sizeof(*cb), GFP_KERNEL); + if (!cb) { + dprintk(VIDC_ERR, "alloc venus cb failed\n"); + return -ENOMEM; + } + + cb->dev = &pdev->dev; + rc = venus_boot_init(&core->resources, cb); + if (rc) { + dprintk(VIDC_ERR, + "Failed to init non-secure PIL %d\n", rc); + } + } + } else { + rc = msm_vidc_populate_context_bank(&pdev->dev, core); + if (rc) + dprintk(VIDC_ERR, "Failed to probe context bank\n"); + else + dprintk(VIDC_DBG, "Successfully probed context bank\n"); + } + return rc; +} + +int read_bus_resources_from_dt(struct platform_device *pdev) +{ + struct msm_vidc_core *core; + + if (!pdev) { + dprintk(VIDC_ERR, "Invalid platform device\n"); + return -EINVAL; + } else if (!pdev->dev.parent) { + dprintk(VIDC_ERR, "Failed to find a parent for %s\n", + dev_name(&pdev->dev)); + return -ENODEV; + } + + core = dev_get_drvdata(pdev->dev.parent); + if (!core) { + dprintk(VIDC_ERR, "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) { + dprintk(VIDC_ERR, "%s: invalid platform device\n", __func__); + return -EINVAL; + } else if (!pdev->dev.parent) { + dprintk(VIDC_ERR, "Failed to find a parent for %s\n", + dev_name(&pdev->dev)); + return -ENODEV; + } + + core = dev_get_drvdata(pdev->dev.parent); + if (!core) { + dprintk(VIDC_ERR, "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/drivers/media/platform/msm/vidc/msm_vidc_res_parse.h b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.h new file mode 100644 index 000000000000..2d7a1b126068 --- /dev/null +++ b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.h @@ -0,0 +1,39 @@ + +/* Copyright (c) 2012-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 DT_PARSE +#define DT_PARSE +#include +#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/drivers/media/platform/msm/vidc/msm_vidc_resources.h b/drivers/media/platform/msm/vidc/msm_vidc_resources.h new file mode 100644 index 000000000000..53d62fb91c45 --- /dev/null +++ b/drivers/media/platform/msm/vidc/msm_vidc_resources.h @@ -0,0 +1,265 @@ +/* Copyright (c) 2013-2020, 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 __MSM_VIDC_RESOURCES_H__ +#define __MSM_VIDC_RESOURCES_H__ + +#include +#include +#include "msm_vidc.h" +#include +#include "soc/qcom/cx_ipeak.h" + +#define MAX_BUFFER_TYPES 32 + +struct dcvs_table { + u32 load; + u32 load_low; + u32 load_high; + u32 supported_codecs; +}; + +struct dcvs_limit { + u32 min_mbpf; + u32 fps; +}; + +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 dma_iommu_mapping *mapping; +}; + +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]; + const char *governor; + struct device *dev; + struct devfreq_dev_profile devfreq_prof; + struct devfreq *devfreq; + struct msm_bus_client_handle *client; + bool is_prfm_gov_used; +}; + +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 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 dcvs_table *dcvs_tbl; + uint32_t dcvs_tbl_size; + struct dcvs_limit *dcvs_limit; + 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_hq_mbs_per_frame; + uint32_t max_hq_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 use_non_secure_pil; + bool sw_power_collapsible; + bool slave_side_cp; + struct list_head context_banks; + 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 domain_cvp; + bool non_fatal_pagefaults; + bool cache_pagetables; + bool decode_batching; + bool dcvs; + struct msm_vidc_codec_data *codec_data; + int codec_data_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 clk_freq_threshold; + struct cx_ipeak_client *cx_ipeak_context; + struct msm_vidc_ubwc_config *ubwc_config; + uint32_t ubwc_config_length; +}; + + +/** + * The version 1 HFI strcuture for the UBWC configuration + * @bMaxChannelsOverride : enable - 1 /disable - 0 max channel override + * @bMalLengthOverride : enable - 1 /disable - 0 HBB override + * @bHBBOverride : enable - 1 /disable - 0 mal length override + * @nMaxChannels: Num DDR channels 4/8 channel, + * This is to control mircotilling mode. + * @nMalLength : UBWC compression ratio granularity 32B/64B MAL + * @nHighestBankBit : Valid range 13-19 + */ + +struct msm_vidc_ubwc_config_v1 { + struct { + u32 bMaxChannelsOverride : 1; + u32 bMalLengthOverride : 1; + u32 bHBBOverride : 1; + u32 reserved1 : 29; + } sOverrideBitInfo; + + u32 nMaxChannels; + u32 nMalLength; + u32 nHighestBankBit; + u32 reserved2[2]; +}; + +/** + * The version 2 HFI strcuture for the UBWC configuration + * @nSize : the size of the packet in bytes + * @ePacketType: HFI_PROPERTY_SYS_UBWC_CONFIG + * @v1 : The same UBWC config parameters as the version 1 + */ + +struct msm_vidc_ubwc_config { + u32 nSize; + u32 ePacketType; + struct msm_vidc_ubwc_config_v1 v1; +}; + +static inline bool is_iommu_present(struct msm_vidc_platform_resources *res) +{ + return !list_empty(&res->context_banks); +} + +#endif + diff --git a/drivers/media/platform/msm/vidc/venus_boot.c b/drivers/media/platform/msm/vidc/venus_boot.c new file mode 100644 index 000000000000..7fe7d0e17881 --- /dev/null +++ b/drivers/media/platform/msm/vidc/venus_boot.c @@ -0,0 +1,470 @@ +/* Copyright (c) 2014-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. + */ + +#define VIDC_DBG_LABEL "venus_boot" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "msm_vidc_debug.h" +#include "vidc_hfi_io.h" +#include "venus_boot.h" + +/* VENUS WRAPPER registers */ +#define VENUS_WRAPPER_SEC_CPA_START_ADDR \ + (VIDC_WRAPPER_BASE_OFFS + 0x1020) +#define VENUS_WRAPPER_SEC_CPA_END_ADDR \ + (VIDC_WRAPPER_BASE_OFFS + 0x1024) +#define VENUS_WRAPPER_SEC_FW_START_ADDR \ + (VIDC_WRAPPER_BASE_OFFS + 0x1028) +#define VENUS_WRAPPER_SEC_FW_END_ADDR \ + (VIDC_WRAPPER_BASE_OFFS + 0x102C) + +#define VENUS_WRAPPER_A9SS_SW_RESET (VIDC_WRAPPER_BASE_OFFS + 0x3000) + +/* VENUS VBIF registers */ +#define VENUS_VBIF_CLKON_FORCE_ON BIT(0) + +#define VENUS_VBIF_ADDR_TRANS_EN (VIDC_VBIF_BASE_OFFS + 0x1000) +#define VENUS_VBIF_AT_OLD_BASE (VIDC_VBIF_BASE_OFFS + 0x1004) +#define VENUS_VBIF_AT_OLD_HIGH (VIDC_VBIF_BASE_OFFS + 0x1008) +#define VENUS_VBIF_AT_NEW_BASE (VIDC_VBIF_BASE_OFFS + 0x1010) +#define VENUS_VBIF_AT_NEW_HIGH (VIDC_VBIF_BASE_OFFS + 0x1018) + + +/* Poll interval in uS */ +#define POLL_INTERVAL_US 50 + +#define VENUS_REGION_SIZE 0x00500000 + +static struct { + struct msm_vidc_platform_resources *resources; + struct regulator *gdsc; + const char *reg_name; + void __iomem *reg_base; + struct device *iommu_ctx_bank_dev; + struct dma_iommu_mapping *mapping; + dma_addr_t fw_iova; + bool is_booted; + bool hw_ver_checked; + u32 fw_sz; + u32 hw_ver_major; + u32 hw_ver_minor; + void *venus_notif_hdle; +} *venus_data = NULL; + +/* Get venus clocks and set rates for rate-settable clocks */ +static int venus_clock_setup(void) +{ + int i, rc = 0; + unsigned long rate; + struct msm_vidc_platform_resources *res = venus_data->resources; + struct clock_info *cl; + + for (i = 0; i < res->clock_set.count; i++) { + cl = &res->clock_set.clock_tbl[i]; + /* Make sure rate-settable clocks' rates are set */ + if (!clk_get_rate(cl->clk) && cl->count) { + rate = clk_round_rate(cl->clk, 0); + rc = clk_set_rate(cl->clk, rate); + if (rc) { + dprintk(VIDC_ERR, + "Failed to set clock rate %lu %s: %d\n", + rate, cl->name, rc); + break; + } + } + } + + return rc; +} + +static int venus_clock_prepare_enable(void) +{ + int i, rc = 0; + struct msm_vidc_platform_resources *res = venus_data->resources; + struct clock_info *cl; + + for (i = 0; i < res->clock_set.count; i++) { + cl = &res->clock_set.clock_tbl[i]; + rc = clk_prepare_enable(cl->clk); + if (rc) { + dprintk(VIDC_ERR, "failed to enable %s\n", cl->name); + for (i--; i >= 0; i--) { + cl = &res->clock_set.clock_tbl[i]; + clk_disable_unprepare(cl->clk); + } + return rc; + } + } + + return rc; +} + +static void venus_clock_disable_unprepare(void) +{ + struct msm_vidc_platform_resources *res = venus_data->resources; + struct clock_info *cl; + int i = res->clock_set.count; + + for (i--; i >= 0; i--) { + cl = &res->clock_set.clock_tbl[i]; + clk_disable_unprepare(cl->clk); + } +} + +static int venus_setup_cb(struct device *dev, + u32 size) +{ + dma_addr_t va_start = 0x0; + size_t va_size = size; + + venus_data->mapping = arm_iommu_create_mapping( + dev->bus, va_start, va_size); + if (IS_ERR_OR_NULL(venus_data->mapping)) { + dprintk(VIDC_ERR, "%s: failed to create mapping for %s\n", + __func__, dev_name(dev)); + return -ENODEV; + } + dprintk(VIDC_DBG, + "%s Attached device %pK and created mapping %pK for %s\n", + __func__, dev, venus_data->mapping, dev_name(dev)); + return 0; +} + +static int pil_venus_mem_setup(size_t size) +{ + int rc = 0; + + if (!venus_data->mapping) { + size = round_up(size, SZ_4K); + rc = venus_setup_cb(venus_data->iommu_ctx_bank_dev, size); + if (rc) { + dprintk(VIDC_ERR, + "%s: Failed to setup context bank for venus : %s\n", + __func__, + dev_name(venus_data->iommu_ctx_bank_dev)); + return rc; + } + venus_data->fw_sz = size; + } + + return rc; +} + +static int pil_venus_auth_and_reset(void) +{ + int rc; + + phys_addr_t fw_bias = venus_data->resources->firmware_base; + void __iomem *reg_base = venus_data->reg_base; + u32 ver; + bool iommu_present = is_iommu_present(venus_data->resources); + struct device *dev = venus_data->iommu_ctx_bank_dev; + + if (!fw_bias) { + dprintk(VIDC_ERR, "FW bias is not valid\n"); + return -EINVAL; + } + venus_data->fw_iova = (dma_addr_t)NULL; + /* Get Venus version number */ + if (!venus_data->hw_ver_checked) { + ver = readl_relaxed(reg_base + VIDC_WRAPPER_HW_VERSION); + venus_data->hw_ver_minor = (ver & 0x0FFF0000) >> 16; + venus_data->hw_ver_major = (ver & 0xF0000000) >> 28; + venus_data->hw_ver_checked = 1; + } + + if (iommu_present) { + u32 cpa_start_addr, cpa_end_addr, fw_start_addr, fw_end_addr; + /* Get the cpa and fw start/end addr */ + cpa_start_addr = + VENUS_WRAPPER_SEC_CPA_START_ADDR; + cpa_end_addr = + VENUS_WRAPPER_SEC_CPA_END_ADDR; + fw_start_addr = + VENUS_WRAPPER_SEC_FW_START_ADDR; + fw_end_addr = + VENUS_WRAPPER_SEC_FW_END_ADDR; + + /* Program CPA start and end address */ + writel_relaxed(0, reg_base + cpa_start_addr); + writel_relaxed(venus_data->fw_sz, reg_base + cpa_end_addr); + + /* Program FW start and end address */ + writel_relaxed(0, reg_base + fw_start_addr); + writel_relaxed(venus_data->fw_sz, reg_base + fw_end_addr); + } else { + rc = regulator_enable(venus_data->gdsc); + if (rc) { + dprintk(VIDC_ERR, "GDSC enable failed\n"); + goto err; + } + + rc = venus_clock_prepare_enable(); + if (rc) { + dprintk(VIDC_ERR, "Clock prepare and enable failed\n"); + regulator_disable(venus_data->gdsc); + goto err; + } + + writel_relaxed(0, reg_base + VENUS_VBIF_AT_OLD_BASE); + writel_relaxed(VENUS_REGION_SIZE, + reg_base + VENUS_VBIF_AT_OLD_HIGH); + writel_relaxed(fw_bias, reg_base + VENUS_VBIF_AT_NEW_BASE); + writel_relaxed(fw_bias + VENUS_REGION_SIZE, + reg_base + VENUS_VBIF_AT_NEW_HIGH); + writel_relaxed(0x7F007F, reg_base + VENUS_VBIF_ADDR_TRANS_EN); + venus_clock_disable_unprepare(); + regulator_disable(venus_data->gdsc); + } + /* Make sure all register writes are committed. */ + mb(); + + /* + * Need to wait 10 cycles of internal clocks before bringing ARM9 + * out of reset. + */ + udelay(1); + + if (iommu_present) { + phys_addr_t pa = fw_bias; + + rc = arm_iommu_attach_device(dev, venus_data->mapping); + if (rc) { + dprintk(VIDC_ERR, + "Failed to attach iommu for %s : %d\n", + dev_name(dev), rc); + goto release_mapping; + } + + dprintk(VIDC_DBG, "Attached and created mapping for %s\n", + dev_name(dev)); + + /* Map virtual addr space 0 - fw_sz to fw phys addr space */ + rc = iommu_map(venus_data->mapping->domain, + venus_data->fw_iova, pa, venus_data->fw_sz, + IOMMU_READ|IOMMU_WRITE|IOMMU_PRIV); + if (!rc) { + dprintk(VIDC_DBG, + "%s - Successfully mapped and performed test translation!\n", + dev_name(dev)); + } + + if (rc || (venus_data->fw_iova != 0)) { + dprintk(VIDC_ERR, "%s - Failed to setup IOMMU\n", + dev_name(dev)); + goto err_iommu_map; + } + } + /* Bring Arm9 out of reset */ + writel_relaxed(0, reg_base + VENUS_WRAPPER_A9SS_SW_RESET); + + venus_data->is_booted = 1; + return 0; + +err_iommu_map: + if (iommu_present) + arm_iommu_detach_device(dev); +release_mapping: + if (iommu_present) + arm_iommu_release_mapping(venus_data->mapping); +err: + return rc; +} + +static int pil_venus_shutdown(void) +{ + void __iomem *reg_base = venus_data->reg_base; + u32 reg; + int rc; + + if (!venus_data->is_booted) + return 0; + + /* Assert the reset to ARM9 */ + reg = readl_relaxed(reg_base + VENUS_WRAPPER_A9SS_SW_RESET); + reg |= BIT(4); + writel_relaxed(reg, reg_base + VENUS_WRAPPER_A9SS_SW_RESET); + + /* Make sure reset is asserted before the mapping is removed */ + mb(); + + if (is_iommu_present(venus_data->resources)) { + iommu_unmap(venus_data->mapping->domain, venus_data->fw_iova, + venus_data->fw_sz); + arm_iommu_detach_device(venus_data->iommu_ctx_bank_dev); + } + /* + * Force the VBIF clk to be on to avoid AXI bridge halt ack failure + * for certain Venus version. + */ + if (venus_data->hw_ver_major == 0x1 && + (venus_data->hw_ver_minor == 0x2 || + venus_data->hw_ver_minor == 0x3)) { + reg = readl_relaxed(reg_base + VIDC_VENUS_VBIF_CLK_ON); + reg |= VENUS_VBIF_CLKON_FORCE_ON; + writel_relaxed(reg, reg_base + VIDC_VENUS_VBIF_CLK_ON); + } + + /* Halt AXI and AXI OCMEM VBIF Access */ + reg = readl_relaxed(reg_base + VENUS_VBIF_AXI_HALT_CTRL0); + reg |= VENUS_VBIF_AXI_HALT_CTRL0_HALT_REQ; + writel_relaxed(reg, reg_base + VENUS_VBIF_AXI_HALT_CTRL0); + + /* Request for AXI bus port halt */ + rc = readl_poll_timeout(reg_base + VENUS_VBIF_AXI_HALT_CTRL1, + reg, reg & VENUS_VBIF_AXI_HALT_CTRL1_HALT_ACK, + POLL_INTERVAL_US, + VENUS_VBIF_AXI_HALT_ACK_TIMEOUT_US); + if (rc) + dprintk(VIDC_ERR, "Port halt timeout\n"); + + venus_data->is_booted = 0; + + return 0; +} + +static int venus_notifier_cb(struct notifier_block *this, unsigned long code, + void *ss_handle) +{ + struct notif_data *data = (struct notif_data *)ss_handle; + static bool venus_data_set; + int ret; + + if (!data->no_auth) + return NOTIFY_DONE; + + if (!venus_data_set) { + ret = venus_clock_setup(); + if (ret) + return ret; + + ret = of_property_read_string(data->pdev->dev.of_node, + "qcom,proxy-reg-names", &venus_data->reg_name); + if (ret) + return ret; + + venus_data->gdsc = devm_regulator_get( + &data->pdev->dev, venus_data->reg_name); + if (IS_ERR(venus_data->gdsc)) { + dprintk(VIDC_ERR, "Failed to get Venus GDSC\n"); + return -ENODEV; + } + + venus_data_set = true; + } + + if (code != SUBSYS_AFTER_POWERUP && code != SUBSYS_AFTER_SHUTDOWN) + return NOTIFY_DONE; + + ret = regulator_enable(venus_data->gdsc); + if (ret) { + dprintk(VIDC_ERR, "GDSC enable failed\n"); + return ret; + } + + ret = venus_clock_prepare_enable(); + if (ret) { + dprintk(VIDC_ERR, "Clock prepare and enable failed\n"); + goto err_clks; + } + + if (code == SUBSYS_AFTER_POWERUP) { + if (is_iommu_present(venus_data->resources)) + pil_venus_mem_setup(VENUS_REGION_SIZE); + pil_venus_auth_and_reset(); + } else if (code == SUBSYS_AFTER_SHUTDOWN) + pil_venus_shutdown(); + + venus_clock_disable_unprepare(); + regulator_disable(venus_data->gdsc); + + return NOTIFY_DONE; +err_clks: + regulator_disable(venus_data->gdsc); + return ret; +} + +static struct notifier_block venus_notifier = { + .notifier_call = venus_notifier_cb, +}; + +int venus_boot_init(struct msm_vidc_platform_resources *res, + struct context_bank_info *cb) +{ + int rc = 0; + + if (!res || !cb) { + dprintk(VIDC_ERR, "Invalid platform resource handle\n"); + return -EINVAL; + } + venus_data = kzalloc(sizeof(*venus_data), GFP_KERNEL); + if (!venus_data) + return -ENOMEM; + + venus_data->resources = res; + venus_data->iommu_ctx_bank_dev = cb->dev; + if (!venus_data->iommu_ctx_bank_dev) { + dprintk(VIDC_ERR, "Invalid venus context bank device\n"); + return -ENODEV; + } + venus_data->reg_base = ioremap_nocache(res->register_base, + (unsigned long)res->register_size); + dprintk(VIDC_DBG, "venus reg: base %llx size %x\n", + res->register_base, res->register_size); + if (!venus_data->reg_base) { + dprintk(VIDC_ERR, + "could not map reg addr %pa of size %d\n", + &res->register_base, res->register_size); + rc = -ENOMEM; + goto err_ioremap_fail; + } + + venus_data->venus_notif_hdle = subsys_notif_register_notifier("venus", + &venus_notifier); + if (IS_ERR(venus_data->venus_notif_hdle)) { + dprintk(VIDC_ERR, "register event notification failed\n"); + rc = PTR_ERR(venus_data->venus_notif_hdle); + goto err_subsys_notif; + } + + return rc; + +err_subsys_notif: +err_ioremap_fail: + kfree(venus_data); + return rc; +} + +void venus_boot_deinit(void) +{ + venus_data->resources = NULL; + subsys_notif_unregister_notifier(venus_data->venus_notif_hdle, + &venus_notifier); + kfree(venus_data); +} diff --git a/drivers/media/platform/msm/vidc/venus_boot.h b/drivers/media/platform/msm/vidc/venus_boot.h new file mode 100644 index 000000000000..da4e77291f51 --- /dev/null +++ b/drivers/media/platform/msm/vidc/venus_boot.h @@ -0,0 +1,22 @@ +/* Copyright (c) 2014, 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. + * + */ + +#ifndef __VENUS_BOOT_H__ +#define __VENUS_BOOT_H__ +#include "msm_vidc_resources.h" + +int venus_boot_init(struct msm_vidc_platform_resources *res, + struct context_bank_info *cb); +void venus_boot_deinit(void); + +#endif /* __VENUS_BOOT_H__ */ diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c new file mode 100644 index 000000000000..6e34d0e69db9 --- /dev/null +++ b/drivers/media/platform/msm/vidc/venus_hfi.c @@ -0,0 +1,5347 @@ +/* Copyright (c) 2012-2020, 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "hfi_packetization.h" +#include "msm_vidc_debug.h" +#include "venus_hfi.h" +#include "vidc_hfi_io.h" + +#define FIRMWARE_SIZE 0X00A00000 +#define REG_ADDR_OFFSET_BITMASK 0x000FFFFF +#define QDSS_IOVA_START 0x80001000 +#define MIN_PAYLOAD_SIZE 3 + +#define VERSION_HANA (0x5 << 28 | 0x10 << 16) + +static struct hal_device_data hal_ctxt; + +#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_gov_data DEFAULT_BUS_VOTE = { + .data = NULL, + .data_count = 0, +}; + +const int max_packets = 1000; + +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); +static inline int __suspend(struct venus_hfi_device *device); +static int __disable_regulators(struct venus_hfi_device *device); +static int __enable_regulators(struct venus_hfi_device *device); +static inline int __prepare_enable_clks(struct venus_hfi_device *device); +static inline void __disable_unprepare_clks(struct venus_hfi_device *device); +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 session_id); +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); +static int __iface_cmdq_write(struct venus_hfi_device *device, + void *pkt); +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); +static int __enable_subcaches(struct venus_hfi_device *device); +static int __set_subcaches(struct venus_hfi_device *device); +static int __release_subcaches(struct venus_hfi_device *device); +static int __disable_subcaches(struct venus_hfi_device *device); +static int __power_collapse(struct venus_hfi_device *device, bool force); +static int venus_hfi_noc_error_info(void *dev); + +static void interrupt_init_vpu4(struct venus_hfi_device *device); +static void interrupt_init_vpu5(struct venus_hfi_device *device); +static void setup_dsp_uc_memmap_vpu5(struct venus_hfi_device *device); +static void clock_config_on_enable_vpu5(struct venus_hfi_device *device); + +struct venus_hfi_vpu_ops vpu4_ops = { + .interrupt_init = interrupt_init_vpu4, + .setup_dsp_uc_memmap = NULL, + .clock_config_on_enable = NULL, +}; + +struct venus_hfi_vpu_ops vpu5_ops = { + .interrupt_init = interrupt_init_vpu5, + .setup_dsp_uc_memmap = setup_dsp_uc_memmap_vpu5, + .clock_config_on_enable = clock_config_on_enable_vpu5, +}; + +/** + * 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, enum vidc_msg_prio log_level) +{ + 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 * row_size]; + + 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); + dprintk(log_level, "%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; + + if (!device || !packet) { + dprintk(VIDC_ERR, "Invalid Param\n"); + return; + } else if (!device->hal_data->firmware_base + || is_iommu_present(device->res)) { + return; + } + + fw_bias = device->hal_data->firmware_base; + sys_init = (struct hfi_cmd_sys_session_init_packet *)packet; + + session = __get_session(device, sys_init->session_id); + if (!session) { + dprintk(VIDC_DBG, "%s :Invalid session id: %x\n", + __func__, sys_init->session_id); + 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->domain_cvp) + return 0; + + if (!device->dsp_iface_q_table.mem_data.dma_handle) { + dprintk(VIDC_ERR, "%s: invalid dsm_handle\n", __func__); + return -EINVAL; + } + + if (device->dsp_flags & DSP_INIT) { + dprintk(VIDC_DBG, "%s: dsp already inited\n", __func__); + return 0; + } + + dprintk(VIDC_DBG, "%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) { + dprintk(VIDC_ERR, "%s: dsp init failed\n", __func__); + return rc; + } + + device->dsp_flags |= DSP_INIT; + dprintk(VIDC_DBG, "%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->domain_cvp) + 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)) { + dprintk(VIDC_DBG, + "%s: cvp session %x not paused\n", + __func__, hash32_ptr(temp)); + return -EBUSY; + } + } + } + + dprintk(VIDC_DBG, "%s: suspend dsp\n", __func__); + rc = fastcvpd_video_suspend(flags); + if (rc) { + dprintk(VIDC_ERR, "%s: dsp suspend failed with error %d\n", + __func__, rc); + return -EINVAL; + } + + device->dsp_flags |= DSP_SUSPEND; + dprintk(VIDC_DBG, "%s: dsp suspended\n", __func__); + return 0; +} + +static int __dsp_resume(struct venus_hfi_device *device, u32 flags) +{ + int rc; + + if (!device->res->domain_cvp) + return 0; + + if (!(device->dsp_flags & DSP_SUSPEND)) { + dprintk(VIDC_DBG, "%s: dsp not suspended\n", __func__); + return 0; + } + + dprintk(VIDC_DBG, "%s: resume dsp\n", __func__); + rc = fastcvpd_video_resume(flags); + if (rc) { + dprintk(VIDC_ERR, + "%s: dsp resume failed with error %d\n", + __func__, rc); + return rc; + } + + device->dsp_flags &= ~DSP_SUSPEND; + dprintk(VIDC_DBG, "%s: dsp resumed\n", __func__); + return rc; +} + +static int __dsp_shutdown(struct venus_hfi_device *device, u32 flags) +{ + int rc; + + if (!device->res->domain_cvp) + return 0; + + if (!(device->dsp_flags & DSP_INIT)) { + dprintk(VIDC_DBG, "%s: dsp not inited\n", __func__); + return 0; + } + + dprintk(VIDC_DBG, "%s: shutdown dsp\n", __func__); + rc = fastcvpd_video_shutdown(flags); + if (rc) { + dprintk(VIDC_ERR, + "%s: dsp shutdown failed with error %d\n", + __func__, rc); + WARN_ON(1); + } + + device->dsp_flags &= ~DSP_INIT; + dprintk(VIDC_DBG, "%s: dsp shutdown successful\n", __func__); + return rc; +} + +static int __session_pause(struct venus_hfi_device *device, + struct hal_session *session) +{ + int rc = 0; + + /* ignore if session paused already */ + if (session->flags & SESSION_PAUSE) + return 0; + + session->flags |= SESSION_PAUSE; + dprintk(VIDC_DBG, "%s: cvp session %x paused\n", __func__, + hash32_ptr(session)); + + return rc; +} + +static int __session_resume(struct venus_hfi_device *device, + struct hal_session *session) +{ + int rc = 0; + + /* ignore if session already resumed */ + if (!(session->flags & SESSION_PAUSE)) + return 0; + + session->flags &= ~SESSION_PAUSE; + dprintk(VIDC_DBG, "%s: cvp session %x resumed\n", __func__, + hash32_ptr(session)); + + rc = __resume(device); + if (rc) { + dprintk(VIDC_ERR, "%s: resume failed\n", __func__); + goto exit; + } + + if (device->dsp_flags & DSP_SUSPEND) { + dprintk(VIDC_ERR, "%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; + + if (!session || !session->device) { + dprintk(VIDC_ERR, "%s: invalid params\n", __func__); + return -EINVAL; + } + device = session->device; + + 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; + + if (!session || !session->device) { + dprintk(VIDC_ERR, "%s: invalid params\n", __func__); + return -EINVAL; + } + device = session->device; + + 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) +{ + 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 + */ + dprintk(VIDC_WARN, + "Failed to acquire regulator control: %s\n", + rinfo->name); + } else { + + dprintk(VIDC_DBG, + "Acquire regulator control from HW: %s\n", + rinfo->name); + + } + } + + if (!regulator_is_enabled(rinfo->regulator)) { + dprintk(VIDC_WARN, "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) +{ + int rc = 0; + + if (rinfo->has_hw_power_collapse) { + rc = regulator_set_mode(rinfo->regulator, + REGULATOR_MODE_FAST); + if (rc) { + dprintk(VIDC_WARN, + "Failed to hand off regulator control: %s\n", + rinfo->name); + } else { + dprintk(VIDC_DBG, + "Hand off regulator control to HW: %s\n", + rinfo->name); + } + } + + return rc; +} + +static int __hand_off_regulators(struct venus_hfi_device *device) +{ + struct regulator_info *rinfo; + int rc = 0, c = 0; + + venus_hfi_for_each_regulator(device, rinfo) { + rc = __hand_off_regulator(rinfo); + /* + * 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); + + return rc; +} + +static int __write_queue(struct vidc_iface_q_info *qinfo, u8 *packet, + bool *rx_req_is_set) +{ + 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) { + dprintk(VIDC_ERR, "Invalid Params\n"); + return -EINVAL; + } else if (!qinfo->q_array.align_virtual_addr) { + dprintk(VIDC_WARN, "Queues have already been freed\n"); + return -EINVAL; + } + + queue = (struct hfi_queue_header *) qinfo->q_hdr; + if (!queue) { + dprintk(VIDC_ERR, "queue not present\n"); + return -ENOENT; + } + + if (msm_vidc_debug & VIDC_PKT) { + dprintk(VIDC_PKT, "%s: %pK\n", __func__, qinfo); + __dump_packet(packet, VIDC_PKT); + } + + packet_size_in_words = (*(u32 *)packet) >> 2; + if (!packet_size_in_words || packet_size_in_words > + qinfo->q_array.mem_size>>2) { + dprintk(VIDC_ERR, "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; + dprintk(VIDC_ERR, "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)) { + dprintk(VIDC_ERR, "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) { + dprintk(VIDC_ERR, "Invalid Param\n"); + 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->session_id); + + if (!session) { + dprintk(VIDC_DBG, "%s: Invalid session id: %x\n", + __func__, init_done->session_id); + 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; + } + case HFI_MSG_SESSION_GET_SEQUENCE_HEADER_DONE: + { + struct + hfi_msg_session_get_sequence_header_done_packet + *pkt = + (struct hfi_msg_session_get_sequence_header_done_packet *) + packet; + pkt->sequence_header += 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; + + if (!qinfo || !packet || !pb_tx_req_is_set) { + dprintk(VIDC_ERR, "Invalid Params\n"); + return -EINVAL; + } else if (!qinfo->q_array.align_virtual_addr) { + dprintk(VIDC_WARN, "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) { + dprintk(VIDC_ERR, "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; + dprintk(VIDC_DBG, + "%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))) { + dprintk(VIDC_ERR, "Invalid read index\n"); + return -ENODATA; + } + + packet_size_in_words = (*read_ptr) >> 2; + if (!packet_size_in_words) { + dprintk(VIDC_ERR, "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 { + dprintk(VIDC_WARN, + "BAD packet received, read_idx: %#x, pkt_size: %d\n", + read_idx, packet_size_in_words << 2); + dprintk(VIDC_WARN, "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)) { + dprintk(VIDC_PKT, "%s: %pK\n", __func__, qinfo); + __dump_packet(packet, VIDC_PKT); + } + + 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) { + dprintk(VIDC_ERR, "Invalid Params\n"); + return -EINVAL; + } + + dprintk(VIDC_INFO, "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); + if (rc) { + dprintk(VIDC_ERR, "Alloc failed\n"); + rc = -ENOMEM; + goto fail_smem_alloc; + } + + dprintk(VIDC_DBG, "%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) { + dprintk(VIDC_ERR, "invalid param %pK %pK\n", dev, mem); + return; + } + + msm_smem_free(mem); +} + +static void __write_register(struct venus_hfi_device *device, + u32 reg, u32 value) +{ + u32 hwiosymaddr = reg; + u8 *base_addr; + + if (!device) { + dprintk(VIDC_ERR, "Invalid params: %pK\n", device); + return; + } + + __strict_check(device); + + if (!device->power_enabled) { + dprintk(VIDC_WARN, + "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; + dprintk(VIDC_DBG, "Base addr: %pK, written 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(); +} + +static int __read_register(struct venus_hfi_device *device, u32 reg) +{ + int rc = 0; + u8 *base_addr; + + if (!device) { + dprintk(VIDC_ERR, "Invalid params: %pK\n", device); + return -EINVAL; + } + + __strict_check(device); + + if (!device->power_enabled) { + dprintk(VIDC_WARN, + "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(); + dprintk(VIDC_DBG, "Base addr: %pK, read from: %#x, value: %#x...\n", + base_addr, reg, rc); + + return rc; +} + +static void __set_registers(struct venus_hfi_device *device) +{ + struct reg_set *reg_set; + int i; + + if (!device->res) { + dprintk(VIDC_ERR, + "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); + } +} + +/* + * The existence of this function is a hack for 8996 (or certain Venus versions) + * to overcome a hardware bug. Whenever the GDSCs momentarily power collapse + * (after calling __hand_off_regulators()), the values of the threshold + * registers (typically programmed by TZ) are incorrectly reset. As a result + * reprogram these registers at certain agreed upon points. + */ +static void __set_threshold_registers(struct venus_hfi_device *device) +{ + u32 version = __read_register(device, VIDC_WRAPPER_HW_VERSION); + + version &= ~GENMASK(15, 0); + if (version != (0x3 << 28 | 0x43 << 16)) + return; + + if (__tzbsp_set_video_state(TZBSP_VIDEO_STATE_RESTORE_THRESHOLD)) + dprintk(VIDC_ERR, "Failed to restore threshold values\n"); +} + +static void __iommu_detach(struct venus_hfi_device *device) +{ + struct context_bank_info *cb; + + if (!device || !device->res) { + dprintk(VIDC_ERR, "Invalid parameter: %pK\n", device); + return; + } + + list_for_each_entry(cb, &device->res->context_banks, list) { + if (cb->dev) + arm_iommu_detach_device(cb->dev); + if (cb->mapping) + arm_iommu_release_mapping(cb->mapping); + } +} + +static int __devfreq_target(struct device *devfreq_dev, + unsigned long *freq, u32 flags) +{ + int rc = 0; + uint64_t ab = 0; + struct bus_info *bus = NULL, *temp = NULL; + struct venus_hfi_device *device = dev_get_drvdata(devfreq_dev); + + venus_hfi_for_each_bus(device, temp) { + if (temp->dev == devfreq_dev) { + bus = temp; + break; + } + } + + if (!bus) { + rc = -EBADHANDLE; + goto err_unknown_device; + } + + /* + * Clamp for all non zero frequencies. This clamp is necessary to stop + * devfreq driver from spamming - Couldn't update frequency - logs, if + * the scaled ab value is not part of the frequency table. + */ + if (*freq) + *freq = clamp_t(typeof(*freq), *freq, bus->range[0], + bus->range[1]); + + /* we expect governors to provide values in kBps form, convert to Bps */ + ab = *freq * 1000; + rc = msm_bus_scale_update_bw(bus->client, ab, 0); + if (rc) { + dprintk(VIDC_ERR, "Failed voting bus %s to ab %llu\n: %d", + bus->name, ab, rc); + goto err_unknown_device; + } + + dprintk(VIDC_PROF, "Voting bus %s to ab %llu\n", bus->name, ab); + + return 0; +err_unknown_device: + return rc; +} + +static int __devfreq_get_status(struct device *devfreq_dev, + struct devfreq_dev_status *stat) +{ + int rc = 0; + struct bus_info *bus = NULL, *temp = NULL; + struct venus_hfi_device *device = dev_get_drvdata(devfreq_dev); + + venus_hfi_for_each_bus(device, temp) { + if (temp->dev == devfreq_dev) { + bus = temp; + break; + } + } + + if (!bus) { + rc = -EBADHANDLE; + goto err_unknown_device; + } + + *stat = (struct devfreq_dev_status) { + .private_data = &device->bus_vote, + /* + * Put in dummy place holder values for upstream govs, our + * custom gov only needs .private_data. We should fill this in + * properly if we can actually measure busy_time accurately + * (which we can't at the moment) + */ + .total_time = 1, + .busy_time = 1, + .current_frequency = 0, + }; + +err_unknown_device: + return rc; +} + +static int __unvote_buses(struct venus_hfi_device *device) +{ + int rc = 0; + struct bus_info *bus = NULL; + + kfree(device->bus_vote.data); + device->bus_vote.data = NULL; + device->bus_vote.data_count = 0; + + venus_hfi_for_each_bus(device, bus) { + unsigned long zero = 0; + + if (!bus->is_prfm_gov_used) { + mutex_lock(&bus->devfreq->lock); + rc = update_devfreq(bus->devfreq); + mutex_unlock(&bus->devfreq->lock); + } + else + rc = __devfreq_target(bus->dev, &zero, 0); + + if (rc) + goto err_unknown_device; + } + +err_unknown_device: + return rc; +} + +static int __vote_buses(struct venus_hfi_device *device, + struct vidc_bus_vote_data *data, int num_data) +{ + int rc = 0; + struct bus_info *bus = NULL; + struct vidc_bus_vote_data *new_data = NULL; + + if (!num_data) { + dprintk(VIDC_DBG, "No vote data available\n"); + goto no_data_count; + } else if (!data) { + dprintk(VIDC_ERR, "Invalid voting data\n"); + return -EINVAL; + } + + new_data = kmemdup(data, num_data * sizeof(*new_data), GFP_KERNEL); + if (!new_data) { + dprintk(VIDC_ERR, "Can't alloc memory to cache bus votes\n"); + rc = -ENOMEM; + goto err_no_mem; + } + +no_data_count: + kfree(device->bus_vote.data); + device->bus_vote.data = new_data; + device->bus_vote.data_count = num_data; + + venus_hfi_for_each_bus(device, bus) { + if (bus && bus->devfreq) { + if (!bus->is_prfm_gov_used) { + mutex_lock(&bus->devfreq->lock); + rc = update_devfreq(bus->devfreq); + mutex_unlock(&bus->devfreq->lock); + if (rc) + goto err_no_mem; + } else { + bus->devfreq->nb.notifier_call( + &bus->devfreq->nb, 0, NULL); + } + } + } + +err_no_mem: + return rc; +} + +static int venus_hfi_vote_buses(void *dev, struct vidc_bus_vote_data *d, int n) +{ + int rc = 0; + struct venus_hfi_device *device = dev; + + if (!device) + return -EINVAL; + + mutex_lock(&device->lock); + rc = __vote_buses(device, d, n); + 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) { + dprintk(VIDC_ERR, "set_res: Invalid Params\n"); + 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) { + dprintk(VIDC_ERR, "set_res: failed to create packet\n"); + goto err_create_pkt; + } + + rc = __iface_cmdq_write(device, pkt); + 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) { + dprintk(VIDC_ERR, "release_res: Invalid Params\n"); + 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) { + dprintk(VIDC_ERR, "release_res: failed to create packet\n"); + goto err_create_pkt; + } + + rc = __iface_cmdq_write(device, pkt); + if (rc) + rc = -ENOTEMPTY; + +err_create_pkt: + return rc; +} + +static int __tzbsp_set_video_state(enum tzbsp_video_state state) +{ + 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) { + dprintk(VIDC_ERR, "Failed scm_call %d\n", rc); + return rc; + } + + dprintk(VIDC_DBG, "Set state %d, resp %d\n", state, tzbsp_rsp); + if (tzbsp_rsp) { + dprintk(VIDC_ERR, + "Failed to set video core state to suspend: %d\n", + tzbsp_rsp); + return -EINVAL; + } + + return 0; +} + +static inline int __boot_firmware(struct venus_hfi_device *device) +{ + int rc = 0; + u32 ctrl_init_val = 0, ctrl_status = 0, count = 0, max_tries = 1000; + + ctrl_init_val = BIT(0); + if (device->res->domain_cvp) + ctrl_init_val |= BIT(1); + + __write_register(device, VIDC_CTRL_INIT, ctrl_init_val); + while (!ctrl_status && count < max_tries) { + ctrl_status = __read_register(device, VIDC_CTRL_STATUS); + if ((ctrl_status & VIDC_CTRL_ERROR_STATUS__M) == 0x4) { + dprintk(VIDC_ERR, "invalid setting for UC_REGION\n"); + break; + } + + usleep_range(50, 100); + count++; + } + + if (count >= max_tries) { + dprintk(VIDC_ERR, "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) { + dprintk(VIDC_ERR, "%s invalid device\n", __func__); + return -EINVAL; + } else if (!device->res->sw_power_collapsible) { + return -ENOTSUPP; + } + + dprintk(VIDC_DBG, "Suspending Venus\n"); + mutex_lock(&device->lock); + rc = __power_collapse(device, true); + if (rc) { + dprintk(VIDC_WARN, "%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) { + dprintk(VIDC_ERR, "%s invalid device\n", __func__); + return -EINVAL; + } + + mutex_lock(&device->lock); + + if (!device->power_enabled) { + dprintk(VIDC_WARN, "%s: venus power off\n", __func__); + rc = -EINVAL; + goto exit; + } + __flush_debug_queue(device, NULL); +exit: + mutex_unlock(&device->lock); + return rc; +} + +static enum hal_default_properties venus_hfi_get_default_properties(void *dev) +{ + enum hal_default_properties prop = 0; + struct venus_hfi_device *device = (struct venus_hfi_device *) dev; + + if (!device) { + dprintk(VIDC_ERR, "%s invalid device\n", __func__); + return -EINVAL; + } + + mutex_lock(&device->lock); + + prop = HAL_VIDEO_DYNAMIC_BUF_MODE; + + mutex_unlock(&device->lock); + return prop; +} + +static int __set_clk_rate(struct venus_hfi_device *device, + struct clock_info *cl, u64 rate) +{ + 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 (device->clk_freq < threshold_freq && rate >= threshold_freq) { + rc = cx_ipeak_update(ipeak, true); + if (rc) { + dprintk(VIDC_ERR, + "cx_ipeak_update failed! ipeak %pK\n", ipeak); + return rc; + } + dprintk(VIDC_PROF, "cx_ipeak_update: up, clk freq = %u\n", + device->clk_freq); + } + + rc = clk_set_rate(clk, rate); + if (rc) { + dprintk(VIDC_ERR, + "%s: Failed to set clock rate %llu %s: %d\n", + __func__, rate, cl->name, rc); + return rc; + } + + if (device->clk_freq >= threshold_freq && rate < threshold_freq) { + rc = cx_ipeak_update(ipeak, false); + if (rc) { + dprintk(VIDC_ERR, + "cx_ipeak_update failed! ipeak %pK\n", ipeak); + device->clk_freq = rate; + return rc; + } + dprintk(VIDC_PROF, "cx_ipeak_update: down, clk freq = %u\n", + device->clk_freq); + } + + device->clk_freq = rate; + + return rc; +} + +static int __set_clocks(struct venus_hfi_device *device, u32 freq) +{ + struct clock_info *cl; + int rc = 0; + + venus_hfi_for_each_clock(device, cl) { + if (cl->has_scaling) {/* has_scaling */ + rc = __set_clk_rate(device, cl, freq); + if (rc) + return rc; + + trace_msm_vidc_perf_clock_scale(cl->name, freq); + dprintk(VIDC_PROF, "Scaling clock %s to %u\n", + cl->name, freq); + } + } + + return 0; +} + +static int venus_hfi_scale_clocks(void *dev, u32 freq) +{ + int rc = 0; + struct venus_hfi_device *device = dev; + + if (!device) { + dprintk(VIDC_ERR, "Invalid args: %pK\n", device); + return -EINVAL; + } + + mutex_lock(&device->lock); + + if (__resume(device)) { + dprintk(VIDC_ERR, "Resume from power collapse failed\n"); + rc = -ENODEV; + goto exit; + } + + rc = __set_clocks(device, freq); +exit: + mutex_unlock(&device->lock); + + return rc; +} + +static int __scale_clocks(struct venus_hfi_device *device) +{ + int rc = 0; + struct allowed_clock_rates_table *allowed_clks_tbl = NULL; + u32 rate = 0; + + allowed_clks_tbl = device->res->allowed_clks_tbl; + + dprintk(VIDC_DBG, "%s: NULL scale data\n", __func__); + rate = device->clk_freq ? device->clk_freq : + allowed_clks_tbl[0].clock_rate; + + rc = __set_clocks(device, rate); + 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) +{ + struct vidc_iface_q_info *q_info; + struct vidc_hal_cmd_pkt_hdr *cmd_packet; + int result = -E2BIG; + + if (!device || !pkt) { + dprintk(VIDC_ERR, "Invalid Params\n"); + return -EINVAL; + } + + __strict_check(device); + + if (!__core_in_valid_state(device)) { + dprintk(VIDC_ERR, "%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) { + dprintk(VIDC_ERR, "cannot write to shared Q's\n"); + goto err_q_null; + } + + if (!q_info->q_array.align_virtual_addr) { + dprintk(VIDC_ERR, "cannot write to shared CMD Q's\n"); + result = -ENODATA; + goto err_q_null; + } + + __sim_modify_cmd_packet((u8 *)pkt, device); + if (__resume(device)) { + dprintk(VIDC_ERR, "%s: Power on failed\n", __func__); + goto err_q_write; + } + + if (!__write_queue(q_info, (u8 *)pkt, requires_interrupt)) { + 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))) { + dprintk(VIDC_DBG, + "PM work already scheduled\n"); + } + } + + result = 0; + } else { + dprintk(VIDC_ERR, "__iface_cmdq_write: queue full\n"); + } + +err_q_write: +err_q_null: + return result; +} + +static int __iface_cmdq_write(struct venus_hfi_device *device, void *pkt) +{ + bool needs_interrupt = false; + int rc = __iface_cmdq_write_relaxed(device, pkt, &needs_interrupt); + + if (!rc && needs_interrupt) { + /* Consumer of cmdq prefers that we raise an interrupt */ + rc = 0; + __write_register(device, VIDC_CPU_IC_SOFTINT, + 1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT); + } + + 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) { + dprintk(VIDC_ERR, "Invalid Params\n"); + return -EINVAL; + } + + __strict_check(device); + + if (!__core_in_valid_state(device)) { + dprintk(VIDC_DBG, "%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 == 0) { + dprintk(VIDC_ERR, "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) + __write_register(device, VIDC_CPU_IC_SOFTINT, + 1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT); + 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) { + dprintk(VIDC_ERR, "Invalid Params\n"); + return -EINVAL; + } + + __strict_check(device); + + q_info = &device->iface_queues[VIDC_IFACEQ_DBGQ_IDX]; + if (q_info->q_array.align_virtual_addr == 0) { + dprintk(VIDC_ERR, "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) + __write_register(device, VIDC_CPU_IC_SOFTINT, + 1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT); + 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) { + dprintk(VIDC_ERR, "%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)) { + dprintk(VIDC_ERR, "%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); + if (!cb) { + dprintk(VIDC_ERR, + "%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)) { + dprintk(VIDC_ERR, "%s: failed dma mapping\n", __func__); + goto fail_dma_map; + } + dprintk(VIDC_DBG, + "%s: kvaddr %pK dma_handle %#llx iova %#llx size %ld\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 = 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) { + dprintk(VIDC_ERR, + "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); + + for (i = 0; cb && i < num_entries; i++) { + iommu_unmap(cb->mapping->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->domain_cvp) + __interface_dsp_queues_release(device); +} + +static int __get_qdss_iommu_virtual_addr(struct venus_hfi_device *dev, + struct hfi_mem_map *mem_map, struct dma_iommu_mapping *mapping) +{ + 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 (mapping) { + rc = iommu_map(mapping->domain, iova, + qdss_addr_tbl[i].start, + qdss_addr_tbl[i].size, + IOMMU_READ | IOMMU_WRITE); + + if (rc) { + dprintk(VIDC_ERR, + "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) { + dprintk(VIDC_ERR, + "QDSS mapping failed, Freeing other entries %d\n", i); + + for (--i; mapping && i >= 0; i--) { + iommu_unmap(mapping->domain, + mem_map[i].virtual_addr, + mem_map[i].size); + } + } + + return rc; +} + +static void __setup_ucregion_memory_map(struct venus_hfi_device *device) +{ + __write_register(device, VIDC_UC_REGION_ADDR, + (u32)device->iface_q_table.align_device_addr); + __write_register(device, VIDC_UC_REGION_SIZE, SHARED_QSIZE); + __write_register(device, VIDC_QTBL_ADDR, + (u32)device->iface_q_table.align_device_addr); + __write_register(device, VIDC_QTBL_INFO, 0x01); + if (device->sfr.align_device_addr) + __write_register(device, VIDC_SFR_ADDR, + (u32)device->sfr.align_device_addr); + if (device->qdss.align_device_addr) + __write_register(device, VIDC_MMAP_ADDR, + (u32)device->qdss.align_device_addr); + call_venus_op(device, setup_dsp_uc_memmap, device); +} + +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) { + dprintk(VIDC_ERR, "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) { + dprintk(VIDC_WARN, + "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) { + dprintk(VIDC_WARN, "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); + if (!cb) { + dprintk(VIDC_ERR, + "%s: failed to get context bank\n", __func__); + return -EINVAL; + } + + rc = __get_qdss_iommu_virtual_addr(dev, mem_map, cb->mapping); + if (rc) { + dprintk(VIDC_ERR, + "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->domain_cvp) { + rc = __interface_dsp_queues_init(dev); + if (rc) { + dprintk(VIDC_ERR, "dsp_queues_init failed\n"); + goto fail_alloc_queue; + } + } + + __setup_ucregion_memory_map(dev); + return 0; +fail_alloc_queue: + return -ENOMEM; +} + +static int __sys_set_debug(struct venus_hfi_device *device, u32 debug) +{ + 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) { + dprintk(VIDC_WARN, + "Debug mode setting to FW failed\n"); + return -ENOTEMPTY; + } + + if (__iface_cmdq_write(device, pkt)) + return -ENOTEMPTY; + return 0; +} + +static int __sys_set_ubwc_config(void *device) +{ + int rc = 0; + struct venus_hfi_device *dev = device; + u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE] = {0}; + struct hfi_cmd_sys_set_property_packet *pkt = + (struct hfi_cmd_sys_set_property_packet *) &packet; + + if (!dev->res->ubwc_config) + return rc; + + rc = call_hfi_pkt_op(dev, sys_ubwc_config, pkt, dev->res->ubwc_config); + if (rc) { + dprintk(VIDC_WARN, + "UBWC Config setting to FW failed\n"); + return -ENOTEMPTY; + } + + if (__iface_cmdq_write(dev, pkt)) + return -ENOTEMPTY; + + return 0; +} + +static int __sys_set_coverage(struct venus_hfi_device *device, u32 mode) +{ + 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); + if (rc) { + dprintk(VIDC_WARN, + "Coverage mode setting to FW failed\n"); + return -ENOTEMPTY; + } + + if (__iface_cmdq_write(device, pkt)) { + dprintk(VIDC_WARN, "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) +{ + 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)) + 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) { + dprintk(VIDC_ERR, "Invalid device\n"); + return -ENODEV; + } + + dev = device; + + dprintk(VIDC_DBG, "Core initializing\n"); + + mutex_lock(&dev->lock); + + dev->bus_vote.data = + kzalloc(sizeof(struct vidc_bus_vote_data), GFP_KERNEL); + if (!dev->bus_vote.data) { + dprintk(VIDC_ERR, "Bus vote data memory is not allocated\n"); + rc = -ENOMEM; + goto err_no_mem; + } + + dev->bus_vote.data_count = 1; + dev->bus_vote.data->power_mode = VIDC_POWER_TURBO; + + rc = __load_fw(dev); + if (rc) { + dprintk(VIDC_ERR, "Failed to load Venus FW\n"); + goto err_load_fw; + } + + __set_state(dev, VENUS_STATE_INIT); + + dprintk(VIDC_DBG, "Dev_Virt: %pa, Reg_Virt: %pK\n", + &dev->hal_data->firmware_base, + dev->hal_data->register_base); + + + rc = __interface_queues_init(dev); + if (rc) { + dprintk(VIDC_ERR, "failed to init queues\n"); + rc = -ENOMEM; + goto err_core_init; + } + + rc = __boot_firmware(dev); + if (rc) { + dprintk(VIDC_ERR, "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) { + dprintk(VIDC_ERR, "Failed to create sys init pkt\n"); + goto err_core_init; + } + + if (__iface_cmdq_write(dev, &pkt)) { + 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)) + dprintk(VIDC_WARN, "Failed to send image version pkt to f/w\n"); + + __sys_set_debug(device, msm_vidc_fw_debug); + + rc = __sys_set_ubwc_config(device); + if (rc) { + dprintk(VIDC_ERR, "Failed to set ubwc config\n"); + goto err_core_init; + } + + __enable_subcaches(device); + __set_subcaches(device); + __dsp_send_hfi_queue(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); + } + dprintk(VIDC_DBG, "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: +err_no_mem: + dprintk(VIDC_ERR, "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) { + dprintk(VIDC_ERR, "invalid device\n"); + return -ENODEV; + } + + mutex_lock(&device->lock); + dprintk(VIDC_DBG, "Core releasing\n"); + if (device->res->pm_qos_latency_us && + pm_qos_request_active(&device->qos)) + pm_qos_remove_request(&device->qos); + + __resume(device); + __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); + + dprintk(VIDC_DBG, "Core released successfully\n"); + mutex_unlock(&device->lock); + + return rc; +} + +static void __core_clear_interrupt(struct venus_hfi_device *device) +{ + u32 intr_status = 0, mask = 0; + + if (!device) { + dprintk(VIDC_ERR, "%s: NULL device\n", __func__); + return; + } + + intr_status = __read_register(device, VIDC_WRAPPER_INTR_STATUS); + mask = (VIDC_WRAPPER_INTR_STATUS_A2H_BMSK | + VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK | + VIDC_CTRL_INIT_IDLE_MSG_BMSK); + + if (intr_status & mask) { + device->intr_status |= intr_status; + device->reg_count++; + dprintk(VIDC_DBG, + "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, 1); + __write_register(device, VIDC_WRAPPER_INTR_CLEAR, intr_status); +} + +static int venus_hfi_core_ping(void *device) +{ + struct hfi_cmd_sys_ping_packet pkt; + int rc = 0; + struct venus_hfi_device *dev; + + if (!device) { + dprintk(VIDC_ERR, "invalid device\n"); + return -ENODEV; + } + + dev = device; + mutex_lock(&dev->lock); + + rc = call_hfi_pkt_op(dev, sys_ping, &pkt); + if (rc) { + dprintk(VIDC_ERR, "core_ping: failed to create packet\n"); + goto err_create_pkt; + } + + if (__iface_cmdq_write(dev, &pkt)) + rc = -ENOTEMPTY; + +err_create_pkt: + mutex_unlock(&dev->lock); + return rc; +} + +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) { + dprintk(VIDC_ERR, "invalid device\n"); + return -ENODEV; + } + + dev = device; + mutex_lock(&dev->lock); + + rc = call_hfi_pkt_op(dev, ssr_cmd, type, &pkt); + if (rc) { + dprintk(VIDC_ERR, "core_ping: failed to create packet\n"); + goto err_create_pkt; + } + + if (__iface_cmdq_write(dev, &pkt)) + rc = -ENOTEMPTY; + +err_create_pkt: + mutex_unlock(&dev->lock); + return rc; +} + +static int venus_hfi_session_set_property(void *sess, + enum hal_property ptype, void *pdata) +{ + 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; + int rc = 0; + + if (!session || !session->device || !pdata) { + dprintk(VIDC_ERR, "Invalid Params\n"); + return -EINVAL; + } + + device = session->device; + mutex_lock(&device->lock); + + dprintk(VIDC_INFO, "in set_prop,with prop id: %#x\n", ptype); + if (!__is_session_valid(device, session, __func__)) { + rc = -EINVAL; + goto err_set_prop; + } + + rc = call_hfi_pkt_op(device, session_set_property, + pkt, session, ptype, pdata); + + if (rc == -ENOTSUPP) { + dprintk(VIDC_DBG, + "set property: unsupported prop id: %#x\n", ptype); + rc = 0; + goto err_set_prop; + } else if (rc) { + dprintk(VIDC_ERR, "set property: failed to create packet\n"); + rc = -EINVAL; + goto err_set_prop; + } + + if (__iface_cmdq_write(session->device, pkt)) { + rc = -ENOTEMPTY; + goto err_set_prop; + } + +err_set_prop: + mutex_unlock(&device->lock); + return rc; +} + +static int venus_hfi_session_get_property(void *sess, + enum hal_property ptype) +{ + struct hfi_cmd_session_get_property_packet pkt = {0}; + struct hal_session *session = sess; + int rc = 0; + struct venus_hfi_device *device; + + if (!session || !session->device) { + dprintk(VIDC_ERR, "Invalid Params\n"); + return -EINVAL; + } + + device = session->device; + mutex_lock(&device->lock); + + dprintk(VIDC_INFO, "%s: property id: %d\n", __func__, ptype); + if (!__is_session_valid(device, session, __func__)) { + rc = -EINVAL; + goto err_create_pkt; + } + + rc = call_hfi_pkt_op(device, session_get_property, + &pkt, session, ptype); + if (rc) { + dprintk(VIDC_ERR, "get property profile: pkt failed\n"); + goto err_create_pkt; + } + + if (__iface_cmdq_write(session->device, &pkt)) { + rc = -ENOTEMPTY; + dprintk(VIDC_ERR, "%s cmdq_write error\n", __func__); + } + +err_create_pkt: + mutex_unlock(&device->lock); + return rc; +} + +static void __set_default_sys_properties(struct venus_hfi_device *device) +{ + if (__sys_set_debug(device, msm_vidc_fw_debug)) + dprintk(VIDC_WARN, "Setting fw_debug msg ON failed\n"); + if (__sys_set_power_control(device, msm_vidc_fw_low_power_mode)) + dprintk(VIDC_WARN, "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; + + if (!session || !session->device) { + dprintk(VIDC_WARN, "%s: invalid params\n", __func__); + return; + } + device = session->device; + dprintk(VIDC_DBG, "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 *session) +{ + struct hal_session *sess_close; + struct venus_hfi_device *device; + + if (!session) { + dprintk(VIDC_ERR, "Invalid Params %s\n", __func__); + return -EINVAL; + } + + sess_close = session; + device = sess_close->device; + + if (!device) { + dprintk(VIDC_ERR, "Invalid device handle %s\n", __func__); + return -EINVAL; + } + + mutex_lock(&device->lock); + + __session_clean(sess_close); + + mutex_unlock(&device->lock); + return 0; +} + +static int venus_hfi_session_init(void *device, void *session_id, + enum hal_domain session_type, enum hal_video_codec codec_type, + void **new_session) +{ + struct hfi_cmd_sys_session_init_packet pkt; + struct venus_hfi_device *dev; + struct hal_session *s; + + if (!device || !new_session) { + dprintk(VIDC_ERR, "%s - invalid input\n", __func__); + return -EINVAL; + } + + dev = device; + mutex_lock(&dev->lock); + + s = kzalloc(sizeof(struct hal_session), GFP_KERNEL); + if (!s) { + dprintk(VIDC_ERR, "new session fail: Out of memory\n"); + goto err_session_init_fail; + } + + s->session_id = session_id; + s->is_decoder = (session_type == HAL_VIDEO_DOMAIN_DECODER); + s->device = dev; + s->codec = codec_type; + s->domain = session_type; + dprintk(VIDC_DBG, + "%s: inst %pK, session %pK, codec 0x%x, domain 0x%x\n", + __func__, session_id, s, s->codec, s->domain); + + list_add_tail(&s->list, &dev->sess_head); + + __set_default_sys_properties(device); + + if (call_hfi_pkt_op(dev, session_init, &pkt, + s, session_type, codec_type)) { + dprintk(VIDC_ERR, "session_init: failed to create packet\n"); + goto err_session_init_fail; + } + + *new_session = s; + if (__iface_cmdq_write(dev, &pkt)) + 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 = session->device; + + if (!__is_session_valid(device, session, __func__)) + return -EINVAL; + + rc = call_hfi_pkt_op(device, session_cmd, + &pkt, pkt_type, session); + if (rc == -EPERM) + return 0; + + if (rc) { + dprintk(VIDC_ERR, "send session cmd: create pkt failed\n"); + goto err_create_pkt; + } + + if (__iface_cmdq_write(session->device, &pkt)) + rc = -ENOTEMPTY; + +err_create_pkt: + return rc; +} + +static int venus_hfi_session_end(void *session) +{ + struct hal_session *sess; + struct venus_hfi_device *device; + int rc = 0; + + if (!session) { + dprintk(VIDC_ERR, "Invalid Params %s\n", __func__); + return -EINVAL; + } + + sess = session; + device = sess->device; + + mutex_lock(&device->lock); + + if (msm_vidc_fw_coverage) { + if (__sys_set_coverage(sess->device, msm_vidc_fw_coverage)) + dprintk(VIDC_WARN, "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; + int rc = 0; + + if (!session || !session->device) { + dprintk(VIDC_ERR, "Invalid Params %s\n", __func__); + return -EINVAL; + } + + device = session->device; + + 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; + + if (!session || !session->device || !buffer_info) { + dprintk(VIDC_ERR, "Invalid Params\n"); + return -EINVAL; + } + + device = session->device; + 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, buffer_info); + if (rc) { + dprintk(VIDC_ERR, "set buffers: failed to create packet\n"); + goto err_create_pkt; + } + + dprintk(VIDC_INFO, "set buffers: %#x\n", buffer_info->buffer_type); + if (__iface_cmdq_write(session->device, pkt)) + 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; + + if (!session || !session->device || !buffer_info) { + dprintk(VIDC_ERR, "Invalid Params\n"); + return -EINVAL; + } + + device = session->device; + 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, buffer_info); + if (rc) { + dprintk(VIDC_ERR, "release buffers: failed to create packet\n"); + goto err_create_pkt; + } + + dprintk(VIDC_INFO, "Release buffers: %#x\n", buffer_info->buffer_type); + if (__iface_cmdq_write(session->device, pkt)) + 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; + + if (!session || !session->device || !buffer) { + dprintk(VIDC_ERR, "%s: invalid params\n", __func__); + return -EINVAL; + } + device = session->device; + + 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, buffer); + if (rc) { + dprintk(VIDC_ERR, "%s: failed to create packet\n", __func__); + goto exit; + } + if (__iface_cmdq_write(session->device, pkt)) + 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; + + if (!session || !session->device || !buffer) { + dprintk(VIDC_ERR, "%s: invalid params\n", __func__); + return -EINVAL; + } + device = session->device; + + 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, buffer); + if (rc) { + dprintk(VIDC_ERR, "%s: failed to create packet\n", __func__); + goto exit; + } + if (__iface_cmdq_write(session->device, pkt)) + rc = -ENOTEMPTY; +exit: + mutex_unlock(&device->lock); + + return rc; +} + +static int venus_hfi_session_load_res(void *session) +{ + struct hal_session *sess; + struct venus_hfi_device *device; + int rc = 0; + + if (!session) { + dprintk(VIDC_ERR, "Invalid Params %s\n", __func__); + return -EINVAL; + } + + sess = session; + device = sess->device; + + mutex_lock(&device->lock); + rc = __send_session_cmd(sess, HFI_CMD_SESSION_LOAD_RESOURCES); + mutex_unlock(&device->lock); + + return rc; +} + +static int venus_hfi_session_release_res(void *session) +{ + struct hal_session *sess; + struct venus_hfi_device *device; + int rc = 0; + + if (!session) { + dprintk(VIDC_ERR, "Invalid Params %s\n", __func__); + return -EINVAL; + } + + sess = session; + device = sess->device; + + mutex_lock(&device->lock); + rc = __send_session_cmd(sess, HFI_CMD_SESSION_RELEASE_RESOURCES); + mutex_unlock(&device->lock); + + return rc; +} + +static int venus_hfi_session_start(void *session) +{ + struct hal_session *sess; + struct venus_hfi_device *device; + int rc = 0; + + if (!session) { + dprintk(VIDC_ERR, "Invalid Params %s\n", __func__); + return -EINVAL; + } + + sess = session; + device = sess->device; + + mutex_lock(&device->lock); + rc = __send_session_cmd(sess, HFI_CMD_SESSION_START); + mutex_unlock(&device->lock); + + return rc; +} + +static int venus_hfi_session_continue(void *session) +{ + struct hal_session *sess; + struct venus_hfi_device *device; + int rc = 0; + + if (!session) { + dprintk(VIDC_ERR, "Invalid Params %s\n", __func__); + return -EINVAL; + } + + sess = session; + device = sess->device; + + mutex_lock(&device->lock); + rc = __send_session_cmd(sess, HFI_CMD_SESSION_CONTINUE); + mutex_unlock(&device->lock); + + return rc; +} + +static int venus_hfi_session_stop(void *session) +{ + struct hal_session *sess; + struct venus_hfi_device *device; + int rc = 0; + + if (!session) { + dprintk(VIDC_ERR, "Invalid Params %s\n", __func__); + return -EINVAL; + } + + sess = session; + device = sess->device; + + mutex_lock(&device->lock); + rc = __send_session_cmd(sess, 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 = session->device; + + 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, input_frame); + if (rc) { + dprintk(VIDC_ERR, + "Session etb decoder: failed to create pkt\n"); + goto err_create_pkt; + } + + if (!relaxed) + rc = __iface_cmdq_write(session->device, &pkt); + else + rc = __iface_cmdq_write_relaxed(session->device, + &pkt, NULL); + 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, input_frame); + if (rc) { + dprintk(VIDC_ERR, + "Session etb encoder: failed to create pkt\n"); + goto err_create_pkt; + } + + if (!relaxed) + rc = __iface_cmdq_write(session->device, &pkt); + else + rc = __iface_cmdq_write_relaxed(session->device, + &pkt, NULL); + 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; + + if (!session || !session->device || !input_frame) { + dprintk(VIDC_ERR, "Invalid Params\n"); + return -EINVAL; + } + + device = session->device; + 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 = session->device; + 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, output_frame); + if (rc) { + dprintk(VIDC_ERR, "Session ftb: failed to create pkt\n"); + goto err_create_pkt; + } + + if (!relaxed) + rc = __iface_cmdq_write(session->device, &pkt); + else + rc = __iface_cmdq_write_relaxed(session->device, + &pkt, NULL); + +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; + + if (!session || !session->device || !output_frame) { + dprintk(VIDC_ERR, "Invalid Params\n"); + return -EINVAL; + } + + device = session->device; + 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; + struct hfi_cmd_session_sync_process_packet pkt; + + if (!session || !session->device) { + dprintk(VIDC_ERR, "%s: Invalid Params\n", __func__); + return -EINVAL; + } + + device = session->device; + + 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) { + dprintk(VIDC_ERR, "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) { + dprintk(VIDC_ERR, "Failed to queue batched etb: %d\n", + rc); + goto err_etbs_and_ftbs; + } + } + + rc = call_hfi_pkt_op(device, session_sync_process, &pkt, session); + if (rc) { + dprintk(VIDC_ERR, "Failed to create sync packet\n"); + goto err_etbs_and_ftbs; + } + + if (__iface_cmdq_write(session->device, &pkt)) + 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; + + if (!session || !session->device) { + dprintk(VIDC_ERR, "invalid session"); + return -ENODEV; + } + + device = session->device; + mutex_lock(&device->lock); + + if (!__is_session_valid(device, session, __func__)) { + rc = -EINVAL; + goto err_create_pkt; + } + rc = call_hfi_pkt_op(device, session_get_buf_req, + &pkt, session); + if (rc) { + dprintk(VIDC_ERR, + "Session get buf req: failed to create pkt\n"); + goto err_create_pkt; + } + + if (__iface_cmdq_write(session->device, &pkt)) + 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; + + if (!session || !session->device) { + dprintk(VIDC_ERR, "invalid session"); + return -ENODEV; + } + + device = session->device; + mutex_lock(&device->lock); + + if (!__is_session_valid(device, session, __func__)) { + rc = -EINVAL; + goto err_create_pkt; + } + rc = call_hfi_pkt_op(device, session_flush, + &pkt, session, flush_mode); + if (rc) { + dprintk(VIDC_ERR, "Session flush: failed to create pkt\n"); + goto err_create_pkt; + } + + if (__iface_cmdq_write(session->device, &pkt)) + 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) { + dprintk(VIDC_INFO, "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 (device && 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; + } + + dprintk(VIDC_INFO, "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); +} + +static 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) { + dprintk(VIDC_ERR, "Failed to create sys pc prep pkt\n"); + goto err_pc_prep; + } + + if (__iface_cmdq_write(device, &pkt)) + rc = -ENOTEMPTY; + if (rc) + dprintk(VIDC_ERR, "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) { + dprintk(VIDC_ERR, "%s: NULL device\n", __func__); + return; + } + + dprintk(VIDC_PROF, + "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) { + dprintk(VIDC_WARN, "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); + dprintk(VIDC_PROF, "%s: power collapse successful!\n", + __func__); + break; + case -EBUSY: + device->skip_pc_count = 0; + dprintk(VIDC_DBG, "%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++; + dprintk(VIDC_WARN, "%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: + dprintk(VIDC_ERR, "%s: power collapse failed\n", __func__); + break; + } +} + +static int __power_collapse(struct venus_hfi_device *device, bool force) +{ + int rc = 0; + u32 wfi_status = 0, idle_status = 0, pc_ready = 0; + u32 flags = 0; + int count = 0; + const int max_tries = 10; + + if (!device) { + dprintk(VIDC_ERR, "%s: invalid params\n", __func__); + return -EINVAL; + } + if (!device->power_enabled) { + dprintk(VIDC_DBG, "%s: Power already disabled\n", + __func__); + goto exit; + } + + rc = __core_in_valid_state(device); + if (!rc) { + dprintk(VIDC_WARN, + "Core is in bad state, Skipping power collapse\n"); + return -EINVAL; + } + + rc = __dsp_suspend(device, force, flags); + if (rc == -EBUSY) + goto exit; + else if (rc) + goto skip_power_off; + + pc_ready = __read_register(device, VIDC_CTRL_STATUS) & + VIDC_CTRL_STATUS_PC_READY; + if (!pc_ready) { + wfi_status = __read_register(device, + VIDC_WRAPPER_CPU_STATUS); + idle_status = __read_register(device, + VIDC_CTRL_STATUS); + if (!(wfi_status & BIT(0))) { + dprintk(VIDC_WARN, + "Skipping PC as wfi_status (%#x) bit not set\n", + wfi_status); + goto skip_power_off; + } + if (!(idle_status & BIT(30))) { + dprintk(VIDC_WARN, + "Skipping PC as idle_status (%#x) bit not set\n", + idle_status); + goto skip_power_off; + } + + rc = __prepare_pc(device); + if (rc) { + dprintk(VIDC_WARN, "Failed PC %d\n", rc); + goto skip_power_off; + } + + while (count < max_tries) { + wfi_status = __read_register(device, + VIDC_WRAPPER_CPU_STATUS); + pc_ready = __read_register(device, + VIDC_CTRL_STATUS); + if ((wfi_status & BIT(0)) && (pc_ready & + VIDC_CTRL_STATUS_PC_READY)) + break; + usleep_range(150, 250); + count++; + } + + if (count == max_tries) { + dprintk(VIDC_ERR, + "Skip PC. Core is not in right state (%#x, %#x)\n", + wfi_status, pc_ready); + goto skip_power_off; + } + } + + __flush_debug_queue(device, device->raw_packet); + + rc = __suspend(device); + if (rc) + dprintk(VIDC_ERR, "Failed __suspend\n"); + +exit: + return rc; + +skip_power_off: + dprintk(VIDC_WARN, "Skip PC(%#x, %#x, %#x)\n", + wfi_status, idle_status, pc_ready); + + 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) { + dprintk(VIDC_ERR, "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'; + + dprintk(VIDC_ERR, "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 = VIDC_FW; + + if (!device) { + dprintk(VIDC_ERR, "%s: Invalid params\n", __func__); + return; + } + + if (!packet) { + packet = kzalloc(VIDC_IFACEQ_VAR_HUGE_PKT_SIZE, GFP_KERNEL); + if (!packet) { + dprintk(VIDC_ERR, "In %s() Fail to allocate mem\n", + __func__); + return; + } + + local_packet = true; + + /* + * Local packek is used when something FATAL occurred. + * It is good to print these logs by default. + */ + + log_level = VIDC_ERR; + } + +#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))) { \ + dprintk(VIDC_ERR, \ + "%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)) { + dprintk(VIDC_ERR, "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) + dprintk(VIDC_ERR, + "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(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: + dprintk(VIDC_WARN, "%s: device %pK, invalid session %pK\n", + func, device, session); + return false; +} + +static struct hal_session *__get_session(struct venus_hfi_device *device, + u32 session_id) +{ + struct hal_session *temp = NULL; + + list_for_each_entry(temp, &device->sess_head, list) { + if (session_id == hash32_ptr(temp)) + return temp; + } + + return NULL; +} + +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) { + dprintk(VIDC_ERR, + "%s: Invalid args : Res packet = %p, Raw packet = %p\n", + __func__, packets, raw_packet); + return 0; + } + + if (device->intr_status & VIDC_WRAPPER_INTR_CLEAR_A2HWD_BMSK) { + struct msm_vidc_cb_info info = { + .response_type = HAL_SYS_WATCHDOG_TIMEOUT, + .response.cmd = { + .device_id = device->device_id, + } + }; + + print_sfr_message(device); + + dprintk(VIDC_ERR, "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 **session_id = NULL; + struct msm_vidc_cb_info *info = &packets[packet_count++]; + struct vidc_hal_sys_init_done sys_init_done = {0}; + int rc = 0; + + rc = hfi_process_msg_packet(device->device_id, + (struct vidc_hal_msg_pkt_hdr *)raw_packet, info); + if (rc) { + dprintk(VIDC_WARN, + "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: + dprintk(VIDC_DBG, "Received SYS_RELEASE_RESOURCE\n"); + break; + case HAL_SYS_INIT_DONE: + dprintk(VIDC_DBG, "Received SYS_INIT_DONE\n"); + + sys_init_done.capabilities = + device->sys_init_capabilities; + hfi_process_sys_init_done_prop_read( + (struct hfi_msg_sys_init_done_packet *) + raw_packet, &sys_init_done); + info->response.cmd.data.sys_init_done = sys_init_done; + break; + case HAL_SESSION_LOAD_RESOURCE_DONE: + /* + * Work around for H/W bug, need to re-program these + * registers as part of a handshake agreement with the + * firmware. This strictly only needs to be done for + * decoder secure sessions, but there's no harm in doing + * so for all sessions as it's at worst a NO-OP. + */ + __set_threshold_registers(device); + 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: + session_id = &info->response.cmd.session_id; + break; + case HAL_SESSION_ERROR: + case HAL_SESSION_ETB_DONE: + case HAL_SESSION_FTB_DONE: + session_id = &info->response.data.session_id; + break; + case HAL_SESSION_EVENT_CHANGE: + session_id = &info->response.event.session_id; + break; + case HAL_RESPONSE_UNUSED: + default: + session_id = NULL; + break; + } + + /* + * hfi_process_msg_packet provides a session_id that's a hashed + * value of struct hal_session, we need to coerce the hashed + * value back to pointer that we can use. Ideally, hfi_process\ + * _msg_packet should take care of this, but it doesn't have + * required information for it + */ + if (session_id) { + struct hal_session *session = NULL; + + if (upper_32_bits((uintptr_t)*session_id) != 0) { + dprintk(VIDC_ERR, + "Upper 32-bits != 0 for sess_id=%pK\n", + *session_id); + } + session = __get_session(device, + (u32)(uintptr_t)*session_id); + if (!session) { + dprintk(VIDC_ERR, + "Received a packet (%#x) for an unrecognized session (%pK), discarding\n", + info->response_type, + *session_id); + --packet_count; + continue; + } + + *session_id = session->session_id; + } + + if (packet_count >= max_packets) { + dprintk(VIDC_WARN, + "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))) { + dprintk(VIDC_ERR, "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)) { + dprintk(VIDC_DBG, "%s - Core not in init state\n", __func__); + goto err_no_work; + } + + if (!device->callback) { + dprintk(VIDC_ERR, "No interrupt callback function: %pK\n", + device); + goto err_no_work; + } + + if (__resume(device)) { + dprintk(VIDC_ERR, "%s: Power enable failed\n", __func__); + goto err_no_work; + } + + __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)) { + dprintk(VIDC_ERR, + "Ignore responses from %d to %d as device is in invalid state", + (i + 1), num_responses); + break; + } + dprintk(VIDC_DBG, "Processing response %d of %d, type %d\n", + (i + 1), num_responses, r->response_type); + device->callback(r->response_type, &r->response); + } + + /* We need re-enable the irq which was disabled in ISR handler */ + if (!(intr_status & VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK)) + 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) { + dprintk(VIDC_ERR, "Core present/Already added\n"); + rc = -EEXIST; + goto err_core_init; + } + + dprintk(VIDC_DBG, "HAL_DATA will be assigned now\n"); + hal = (struct hal_data *) + kzalloc(sizeof(struct hal_data), GFP_KERNEL); + if (!hal) { + dprintk(VIDC_ERR, "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) { + dprintk(VIDC_ERR, + "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)) { + dprintk(VIDC_ERR, "() :request_irq failed\n"); + goto error_irq_fail; + } + + disable_irq_nosync(res->irq); + dprintk(VIDC_INFO, + "firmware_base = %pa, register_base = %pa, register_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) { + dprintk(VIDC_ERR, "Invalid params: %pK\n", device); + return -EINVAL; + } + + venus_hfi_for_each_clock(device, cl) { + + dprintk(VIDC_DBG, "%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)) { + dprintk(VIDC_ERR, + "Failed to get clock: %s\n", cl->name); + rc = 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, + enum reset_state state) +{ + int i, rc = 0; + struct reset_control *rst; + struct reset_set *rst_set = &res->reset_set; + + if (!rst_set->reset_tbl) + return 0; + + for (i = 0; i < rst_set->count; i++) { + rst = rst_set->reset_tbl[i].rst; + dprintk(VIDC_DBG, "%s reset_state name = %s state %d\n", + __func__, rst_set->reset_tbl[i].name, state); + switch (state) { + case INIT: + if (rst) + continue; + + rst = devm_reset_control_get(&res->pdev->dev, + rst_set->reset_tbl[i].name); + if (IS_ERR(rst)) + rc = PTR_ERR(rst); + + rst_set->reset_tbl[i].rst = rst; + break; + case ASSERT: + if (!rst) + goto no_init; + + rc = reset_control_assert(rst); + break; + case DEASSERT: + if (!rst) + goto no_init; + + rc = reset_control_deassert(rst); + break; + default: + dprintk(VIDC_ERR, "Invalid reset request\n"); + } + + if (rc) + return rc; + } + return 0; +no_init: + dprintk(VIDC_ERR, "%s reset_state name = %s failed state %d\n", + __func__, rst_set->reset_tbl[i].name, state); + return PTR_ERR(rst); +} + +static inline void __disable_unprepare_clks(struct venus_hfi_device *device) +{ + struct clock_info *cl; + int rc = 0; + + if (!device) { + dprintk(VIDC_ERR, "Invalid params: %pK\n", device); + return; + } + + venus_hfi_for_each_clock_reverse(device, cl) { + dprintk(VIDC_DBG, "Clock: %s disable and unprepare\n", + cl->name); + rc = clk_set_flags(cl->clk, CLKFLAG_NORETAIN_PERIPH); + if (rc) { + dprintk(VIDC_WARN, + "Failed set flag NORETAIN_PERIPH %s\n", + cl->name); + } + rc = clk_set_flags(cl->clk, CLKFLAG_NORETAIN_MEM); + if (rc) { + dprintk(VIDC_WARN, + "Failed set flag NORETAIN_MEM %s\n", + cl->name); + } + clk_disable_unprepare(cl->clk); + } +} + +static inline int __prepare_ahb2axi_bridge(struct venus_hfi_device *device) +{ + int rc; + + if (!device) { + dprintk(VIDC_ERR, "NULL device\n"); + return -EINVAL; + } + + if (device->res->vpu_ver != VPU_VERSION_5) + return 0; + + rc = __handle_reset_clk(device->res, ASSERT); + if (rc) { + dprintk(VIDC_ERR, "failed to assert reset clocks\n"); + return rc; + } + + /* wait for deassert */ + usleep_range(150, 250); + + rc = __handle_reset_clk(device->res, DEASSERT); + if (rc) { + dprintk(VIDC_ERR, "failed to deassert reset clocks\n"); + return rc; + } + + return 0; +} + +static inline int __unprepare_ahb2axi_bridge(struct venus_hfi_device *device, + u32 version) +{ + int rc; + + if (!device) { + dprintk(VIDC_ERR, "NULL device\n"); + return -EINVAL; + } + + /* reset axi0 and axi1 as needed only for specific video hardware */ + version &= ~GENMASK(15, 0); + if (version != VERSION_HANA) + return -EINVAL; + + dprintk(VIDC_ERR, + "reset axi cbcr to recover\n"); + + rc = __handle_reset_clk(device->res, ASSERT); + if (rc) { + dprintk(VIDC_ERR, "failed to assert reset clocks\n"); + return rc; + } + + /* wait for deassert */ + usleep_range(150, 250); + + rc = __handle_reset_clk(device->res, DEASSERT); + if (rc) { + dprintk(VIDC_ERR, "failed to deassert reset clocks\n"); + return rc; + } + + return 0; +} + +static inline int __prepare_enable_clks(struct venus_hfi_device *device) +{ + struct clock_info *cl = NULL, *cl_fail = NULL; + int rc = 0, c = 0; + + if (!device) { + dprintk(VIDC_ERR, "Invalid params: %pK\n", device); + 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)); + + rc = clk_set_flags(cl->clk, CLKFLAG_RETAIN_PERIPH); + if (rc) { + dprintk(VIDC_WARN, + "Failed set flag RETAIN_PERIPH %s\n", + cl->name); + } + rc = clk_set_flags(cl->clk, CLKFLAG_RETAIN_MEM); + if (rc) { + dprintk(VIDC_WARN, + "Failed set flag RETAIN_MEM %s\n", + cl->name); + } + rc = clk_prepare_enable(cl->clk); + if (rc) { + dprintk(VIDC_ERR, "Failed to enable clocks\n"); + cl_fail = cl; + goto fail_clk_enable; + } + + c++; + dprintk(VIDC_DBG, "Clock: %s prepared and enabled\n", cl->name); + } + + call_venus_op(device, clock_config_on_enable, device); + return rc; + +fail_clk_enable: + venus_hfi_for_each_clock_reverse_continue(device, cl, c) { + dprintk(VIDC_ERR, "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; + + kfree(device->bus_vote.data); + device->bus_vote = DEFAULT_BUS_VOTE; + + venus_hfi_for_each_bus_reverse(device, bus) { + devfreq_remove_device(bus->devfreq); + bus->devfreq = NULL; + dev_set_drvdata(bus->dev, NULL); + + 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) { + struct devfreq_dev_profile profile = { + .initial_freq = 0, + .polling_ms = INT_MAX, + .freq_table = NULL, + .max_state = 0, + .target = __devfreq_target, + .get_dev_status = __devfreq_get_status, + .exit = NULL, + }; + + if (!strcmp(bus->governor, "msm-vidc-llcc")) { + if (msm_vidc_syscache_disable) { + dprintk(VIDC_DBG, + "Skipping LLC bus init %s: %s\n", + bus->name, bus->governor); + continue; + } + } + + /* + * This is stupid, but there's no other easy way to ahold + * of struct bus_info in venus_hfi_devfreq_*() + */ + WARN(dev_get_drvdata(bus->dev), "%s's drvdata already set\n", + dev_name(bus->dev)); + dev_set_drvdata(bus->dev, device); + + 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) ?: -EBADHANDLE; + dprintk(VIDC_ERR, "Failed to register bus %s: %d\n", + bus->name, rc); + bus->client = NULL; + goto err_add_dev; + } + + bus->devfreq_prof = profile; + bus->devfreq = devfreq_add_device(bus->dev, + &bus->devfreq_prof, bus->governor, NULL); + if (IS_ERR_OR_NULL(bus->devfreq)) { + rc = PTR_ERR(bus->devfreq) ?: -EBADHANDLE; + dprintk(VIDC_ERR, + "Failed to add devfreq device for bus %s and governor %s: %d\n", + bus->name, bus->governor, rc); + bus->devfreq = NULL; + goto err_add_dev; + } + + /* + * Devfreq starts monitoring immediately, since we are just + * initializing stuff at this point, force it to suspend + */ + devfreq_suspend_device(bus->devfreq); + } + + 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) ?: -EBADHANDLE; + dprintk(VIDC_ERR, "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) { + dprintk(VIDC_ERR, "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) { + dprintk(VIDC_DBG, "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) { + dprintk(VIDC_ERR, "init_subcaches: invalid device %pK\n", + device); + return -EINVAL; + } + + if (!is_sys_cache_present(device)) + return 0; + + venus_hfi_for_each_subcache(device, sinfo) { + sinfo->subcache = llcc_slice_getd(&device->res->pdev->dev, + sinfo->name); + if (IS_ERR_OR_NULL(sinfo->subcache)) { + rc = PTR_ERR(sinfo->subcache) ? : -EBADHANDLE; + dprintk(VIDC_ERR, + "init_subcaches: invalid subcache: %s rc %d\n", + sinfo->name, rc); + sinfo->subcache = NULL; + goto err_subcache_get; + } + dprintk(VIDC_DBG, "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 rc = 0; + + rc = __init_regulators(device); + if (rc) { + dprintk(VIDC_ERR, "Failed to get all regulators\n"); + return -ENODEV; + } + + rc = __init_clocks(device); + if (rc) { + dprintk(VIDC_ERR, "Failed to init clocks\n"); + rc = -ENODEV; + goto err_init_clocks; + } + + rc = __handle_reset_clk(res, INIT); + if (rc) { + dprintk(VIDC_ERR, "Failed to init reset clocks\n"); + rc = -ENODEV; + goto err_init_reset_clk; + } + + rc = __init_bus(device); + if (rc) { + dprintk(VIDC_ERR, "Failed to init bus: %d\n", rc); + goto err_init_bus; + } + + rc = __init_subcaches(device); + if (rc) + dprintk(VIDC_WARN, "Failed to init subcaches: %d\n", rc); + + device->sys_init_capabilities = + kzalloc(sizeof(struct msm_vidc_capability) + * VIDC_MAX_SESSIONS, GFP_KERNEL); + + 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); + kfree(device->sys_init_capabilities); + device->sys_init_capabilities = NULL; +} + +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; + + 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; + dprintk(VIDC_DBG, "%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; + dprintk(VIDC_DBG, + "%s memprot.cp_nonpixel_start: %#x size: %#x\n", + __func__, memprot.cp_nonpixel_start, + memprot.cp_nonpixel_size); + } + } + + 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) { + dprintk(VIDC_ERR, "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; + + dprintk(VIDC_DBG, "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); + 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 + */ + dprintk(VIDC_WARN, + "Failed to acquire control on %s\n", + rinfo->name); + + goto disable_regulator_failed; + } + + rc = regulator_disable(rinfo->regulator); + if (rc) { + dprintk(VIDC_WARN, + "Failed to disable %s: %d\n", + rinfo->name, rc); + goto disable_regulator_failed; + } + + 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) +{ + int rc = 0; + + if (!msm_vidc_fw_low_power_mode) { + dprintk(VIDC_DBG, "Not enabling hardware power collapse\n"); + return 0; + } + + rc = __hand_off_regulators(device); + if (rc) + dprintk(VIDC_WARN, + "%s : Failed to enable HW power collapse %d\n", + __func__, rc); + return rc; +} + +static int __enable_regulators(struct venus_hfi_device *device) +{ + int rc = 0, c = 0; + struct regulator_info *rinfo; + + dprintk(VIDC_DBG, "Enabling regulators\n"); + + venus_hfi_for_each_regulator(device, rinfo) { + rc = regulator_enable(rinfo->regulator); + if (rc) { + dprintk(VIDC_ERR, + "Failed to enable %s: %d\n", + rinfo->name, rc); + goto err_reg_enable_failed; + } + + dprintk(VIDC_DBG, "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; +} + +static int __disable_regulators(struct venus_hfi_device *device) +{ + struct regulator_info *rinfo; + int rc = 0; + + dprintk(VIDC_DBG, "Disabling regulators\n"); + + venus_hfi_for_each_regulator_reverse(device, rinfo) + __disable_regulator(rinfo, device); + + return rc; +} + +static int __enable_subcaches(struct venus_hfi_device *device) +{ + 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) { + dprintk(VIDC_WARN, "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; + dprintk(VIDC_DBG, "Activated subcache %s\n", sinfo->name); + c++; + } + + dprintk(VIDC_DBG, "Activated %d Subcaches to Venus\n", c); + + return 0; + +err_activate_fail: + __release_subcaches(device); + __disable_subcaches(device); + return 0; +} + +static int __set_subcaches(struct venus_hfi_device *device) +{ + 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) { + dprintk(VIDC_DBG, "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 == true) { + sc_res[c].size = sinfo->subcache->llcc_slice_size; + sc_res[c].sc_id = sinfo->subcache->llcc_slice_id; + c++; + } + } + + /* Set resource to Venus for activated subcaches */ + if (c) { + dprintk(VIDC_DBG, "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) { + dprintk(VIDC_WARN, "Failed to set subcaches %d\n", rc); + goto err_fail_set_subacaches; + } + + venus_hfi_for_each_subcache(device, sinfo) { + if (sinfo->isactive == true) + sinfo->isset = true; + } + + dprintk(VIDC_DBG, "Set Subcaches done to Venus\n"); + device->res->sys_cache_res_set = true; + } + + return 0; + +err_fail_set_subacaches: + __disable_subcaches(device); + + return 0; +} + +static int __release_subcaches(struct venus_hfi_device *device) +{ + 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 == true) { + /* Update the entry */ + sc_res[c].size = sinfo->subcache->llcc_slice_size; + sc_res[c].sc_id = sinfo->subcache->llcc_slice_id; + c++; + sinfo->isset = false; + } + } + + if (c > 0) { + dprintk(VIDC_DBG, "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) + dprintk(VIDC_WARN, + "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) +{ + 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 == true) { + dprintk(VIDC_DBG, "De-activate subcache %s\n", + sinfo->name); + rc = llcc_slice_deactivate(sinfo->subcache); + if (rc) { + dprintk(VIDC_WARN, + "Failed to de-activate %s: %d\n", + sinfo->name, rc); + } + sinfo->isactive = false; + } + } + + return 0; +} + +static void interrupt_init_vpu5(struct venus_hfi_device *device) +{ + u32 mask_val = 0; + + /* All interrupts should be disabled initially 0x1F6 : Reset value */ + mask_val = __read_register(device, VIDC_WRAPPER_INTR_MASK); + + /* Write 0 to unmask CPU and WD interrupts */ + mask_val &= ~(VIDC_WRAPPER_INTR_MASK_A2HWD_BMSK | + VIDC_WRAPPER_INTR_MASK_A2HCPU_BMSK); + __write_register(device, VIDC_WRAPPER_INTR_MASK, mask_val); +} + +static void interrupt_init_vpu4(struct venus_hfi_device *device) +{ + __write_register(device, VIDC_WRAPPER_INTR_MASK, + VIDC_WRAPPER_INTR_MASK_A2HVCODEC_BMSK); +} + +static void setup_dsp_uc_memmap_vpu5(struct venus_hfi_device *device) +{ + /* initialize DSP QTBL & UCREGION with CPU queues */ + __write_register(device, HFI_DSP_QTBL_ADDR, + (u32)device->iface_q_table.align_device_addr); + __write_register(device, HFI_DSP_UC_REGION_ADDR, + (u32)device->iface_q_table.align_device_addr); + __write_register(device, HFI_DSP_UC_REGION_SIZE, SHARED_QSIZE); + if (device->res->domain_cvp) { + __write_register(device, HFI_DSP_QTBL_ADDR, + (u32)device->dsp_iface_q_table.align_device_addr); + __write_register(device, HFI_DSP_UC_REGION_ADDR, + (u32)device->dsp_iface_q_table.align_device_addr); + __write_register(device, HFI_DSP_UC_REGION_SIZE, + device->dsp_iface_q_table.mem_data.size); + } +} + +static void clock_config_on_enable_vpu5(struct venus_hfi_device *device) +{ + __write_register(device, VIDC_WRAPPER_CPU_CGC_DIS, 0); + __write_register(device, VIDC_WRAPPER_CPU_CLOCK_CONFIG, 0); +} + +static int __venus_power_on(struct venus_hfi_device *device) +{ + int rc = 0; + + + if (device->power_enabled) + return 0; + + device->power_enabled = true; + /* Vote for all hardware resources */ + rc = __vote_buses(device, device->bus_vote.data, + device->bus_vote.data_count); + if (rc) { + dprintk(VIDC_ERR, "Failed to vote buses, err: %d\n", rc); + goto fail_vote_buses; + } + + rc = __enable_regulators(device); + if (rc) { + dprintk(VIDC_ERR, "Failed to enable GDSC, err = %d\n", rc); + goto fail_enable_gdsc; + } + + rc = __prepare_ahb2axi_bridge(device); + if (rc) { + dprintk(VIDC_ERR, "Failed to enable ahb2axi: %d\n", rc); + goto fail_enable_clks; + } + + rc = __prepare_enable_clks(device); + if (rc) { + dprintk(VIDC_ERR, "Failed to enable clocks: %d\n", rc); + goto fail_enable_clks; + } + + rc = __scale_clocks(device); + if (rc) { + dprintk(VIDC_WARN, + "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); + + call_venus_op(device, interrupt_init, device); + device->intr_status = 0; + enable_irq(device->hal_data->irq); + + /* + * Hand off control of regulators to h/w _after_ enabling clocks. + * 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. Since Venus isn't up yet, the GDSC will be off briefly. + */ + if (__enable_hw_power_collapse(device)) + dprintk(VIDC_ERR, "Failed to enabled inter-frame PC\n"); + + return rc; + +fail_enable_clks: + __disable_regulators(device); +fail_enable_gdsc: + __unvote_buses(device); +fail_vote_buses: + device->power_enabled = false; + return rc; +} + +static void __venus_power_off(struct venus_hfi_device *device, bool axi_reset) +{ + u32 version; + + if (!device->power_enabled) + return; + + if (!(device->intr_status & VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK)) + disable_irq_nosync(device->hal_data->irq); + device->intr_status = 0; + + if (axi_reset) + version = __read_register(device, VIDC_WRAPPER_HW_VERSION); + + __disable_unprepare_clks(device); + + if (axi_reset) + __unprepare_ahb2axi_bridge(device, version); + + if (__disable_regulators(device)) + dprintk(VIDC_WARN, "Failed to disable regulators\n"); + + if (__unvote_buses(device)) + dprintk(VIDC_WARN, "Failed to unvote for buses\n"); + device->power_enabled = false; +} + +static inline int __suspend(struct venus_hfi_device *device) +{ + int rc = 0; + + if (!device) { + dprintk(VIDC_ERR, "Invalid params: %pK\n", device); + return -EINVAL; + } else if (!device->power_enabled) { + dprintk(VIDC_DBG, "Power already disabled\n"); + return 0; + } + + dprintk(VIDC_PROF, "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); + if (rc) { + dprintk(VIDC_WARN, "Failed to suspend video core %d\n", rc); + goto err_tzbsp_suspend; + } + + __disable_subcaches(device); + + __venus_power_off(device, false); + dprintk(VIDC_PROF, "Venus power off\n"); + return rc; + +err_tzbsp_suspend: + return rc; +} + +static inline int __resume(struct venus_hfi_device *device) +{ + int rc = 0; + u32 flags = 0; + + if (!device) { + dprintk(VIDC_ERR, "Invalid params: %pK\n", device); + return -EINVAL; + } else if (device->power_enabled) { + goto exit; + } else if (!__core_in_valid_state(device)) { + dprintk(VIDC_DBG, "venus_hfi_device in deinit state."); + return -EINVAL; + } + + dprintk(VIDC_PROF, "Resuming from power collapse\n"); + rc = __venus_power_on(device); + if (rc) { + dprintk(VIDC_ERR, "Failed to power on venus\n"); + goto err_venus_power_on; + } + + /* Reboot the firmware */ + rc = __tzbsp_set_video_state(TZBSP_VIDEO_STATE_RESUME); + if (rc) { + dprintk(VIDC_ERR, "Failed to resume video core %d\n", rc); + goto err_set_video_state; + } + + __setup_ucregion_memory_map(device); + /* Wait for boot completion */ + rc = __boot_firmware(device); + if (rc) { + dprintk(VIDC_ERR, "Failed to reset venus core\n"); + goto err_reset_core; + } + + /* + * Work around for H/W bug, need to reprogram these registers once + * firmware is out reset + */ + __set_threshold_registers(device); + + 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_fw_debug); + + __enable_subcaches(device); + __set_subcaches(device); + __dsp_resume(device, flags); + + dprintk(VIDC_PROF, "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); +err_set_video_state: + __venus_power_off(device, false); +err_venus_power_on: + dprintk(VIDC_ERR, "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) { + dprintk(VIDC_ERR, "Failed to init resources: %d\n", rc); + goto fail_init_res; + } + + rc = __initialize_packetization(device); + if (rc) { + dprintk(VIDC_ERR, "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); + if (rc) { + dprintk(VIDC_ERR, "Failed to power on venus in in load_fw\n"); + goto fail_venus_power_on; + } + + if ((!device->res->use_non_secure_pil && !device->res->firmware_base) + || device->res->use_non_secure_pil) { + 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)) { + dprintk(VIDC_ERR, "Failed to download firmware\n"); + device->resources.fw.cookie = NULL; + rc = -ENOMEM; + goto fail_load_fw; + } + } + + if (!device->res->use_non_secure_pil && !device->res->firmware_base) { + rc = __protect_cp_mem(device); + if (rc) { + dprintk(VIDC_ERR, "Failed to protect memory\n"); + goto fail_protect_mem; + } + } + 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: + __venus_power_off(device, true); +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); + + __vote_buses(device, NULL, 0); + subsystem_put(device->resources.fw.cookie); + __interface_queues_release(device); + __venus_power_off(device, true); + device->resources.fw.cookie = NULL; + __deinit_resources(device); + + dprintk(VIDC_PROF, "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) { + dprintk(VIDC_ERR, + "%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) { + dprintk(VIDC_WARN, "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: + dprintk(VIDC_DBG, "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; + + if (!device) { + dprintk(VIDC_ERR, "%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 { + dprintk(VIDC_ERR, "%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); + dprintk(VIDC_ERR, "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); + dprintk(VIDC_ERR, "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); + dprintk(VIDC_ERR, "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); + dprintk(VIDC_ERR, "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); + dprintk(VIDC_ERR, "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); + dprintk(VIDC_ERR, "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); + dprintk(VIDC_ERR, "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); + dprintk(VIDC_ERR, "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); + dprintk(VIDC_ERR, "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); + dprintk(VIDC_ERR, "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); + dprintk(VIDC_ERR, "CORE%d_NOC_ERR_ERRLOG3_HIGH: %#x\n", core_type, val); +} + +static int venus_hfi_noc_error_info(void *dev) +{ + struct venus_hfi_device *device; + const u32 vcodec = 0, cvp = 1; + + if (!dev) { + dprintk(VIDC_ERR, "%s: null device\n", __func__); + return -EINVAL; + } + device = dev; + + mutex_lock(&device->lock); + dprintk(VIDC_ERR, "%s: non error information\n", __func__); + + if (__read_register(device, VCODEC_CORE0_VIDEO_NOC_BASE_OFFS + + VCODEC_COREX_VIDEO_NOC_ERR_ERRVLD_LOW_OFFS)) + __noc_error_info(device, vcodec); + + if (device->res->vpu_ver == VPU_VERSION_5) { + if (__read_register(device, CVP_NOC_BASE_OFFS + + VCODEC_COREX_VIDEO_NOC_ERR_ERRVLD_LOW_OFFS)) + __noc_error_info(device, cvp); + } + + mutex_unlock(&device->lock); + + return 0; +} + +static int __initialize_packetization(struct venus_hfi_device *device) +{ + int rc = 0; + + if (!device || !device->res) { + dprintk(VIDC_ERR, "%s - invalid param\n", __func__); + 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; + dprintk(VIDC_ERR, "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_4) + device->vpu_ops = &vpu4_ops; + else + device->vpu_ops = &vpu5_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 = NULL; + int rc = 0; + + if (!res || !callback) { + dprintk(VIDC_ERR, "Invalid Parameters\n"); + return NULL; + } + + dprintk(VIDC_INFO, "entered , device_id: %d\n", device_id); + + hdevice = (struct venus_hfi_device *) + kzalloc(sizeof(struct venus_hfi_device), GFP_KERNEL); + if (!hdevice) { + dprintk(VIDC_ERR, "failed to allocate new device\n"); + goto exit; + } + + hdevice->response_pkt = kmalloc_array(max_packets, + sizeof(*hdevice->response_pkt), GFP_KERNEL); + if (!hdevice->response_pkt) { + dprintk(VIDC_ERR, "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) { + dprintk(VIDC_ERR, "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 = callback; + + __init_venus_ops(hdevice); + + hdevice->vidc_workq = create_singlethread_workqueue( + "msm_vidc_workerq_venus"); + if (!hdevice->vidc_workq) { + dprintk(VIDC_ERR, ": create vidc workq failed\n"); + goto err_cleanup; + } + + hdevice->venus_pm_workq = create_singlethread_workqueue( + "pm_workerq_venus"); + if (!hdevice->venus_pm_workq) { + dprintk(VIDC_ERR, ": create pm workq failed\n"); + 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); + kfree(hdevice); +exit: + 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) { + dprintk(VIDC_ERR, "Invalid params: %pK %pK\n", 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; + + mutex_lock(&dev->lock); + __iommu_detach(dev); + mutex_unlock(&dev->lock); + + 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); + kfree(close); + 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_ping = venus_hfi_core_ping; + 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_get_property = venus_hfi_session_get_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; + hdev->get_default_properties = venus_hfi_get_default_properties; +} + +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) { + dprintk(VIDC_ERR, "Invalid params: %pK %pK %pK\n", + 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) ?: -EINVAL; + goto err_venus_hfi_init; + } + + venus_init_hfi_callbacks(hdev); + +err_venus_hfi_init: + return rc; +} + diff --git a/drivers/media/platform/msm/vidc/venus_hfi.h b/drivers/media/platform/msm/vidc/venus_hfi.h new file mode 100644 index 000000000000..1ba14db390b7 --- /dev/null +++ b/drivers/media/platform/msm/vidc/venus_hfi.h @@ -0,0 +1,296 @@ +/* Copyright (c) 2012-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. + * + */ + +#ifndef __H_VENUS_HFI_H__ +#define __H_VENUS_HFI_H__ + +#include +#include +#include +#include +#include +#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" + +#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 unneccessary 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, args...) \ + (((d) && (d)->vpu_ops && (d)->vpu_ops->op) ? \ + ((d)->vpu_ops->op(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 *ptr); + void (*setup_dsp_uc_memmap)(struct venus_hfi_device *device); + void (*clock_config_on_enable)(struct venus_hfi_device *device); +}; + +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; + unsigned long clk_bitrate; + unsigned long scaled_rate; + struct msm_vidc_gov_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 msm_vidc_capability *sys_init_capabilities; + 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); +bool venus_hfi_is_session_supported(unsigned long sessions_supported, + enum vidc_vote_data_session session_type); + +#endif diff --git a/drivers/media/platform/msm/vidc/vidc_hfi.c b/drivers/media/platform/msm/vidc/vidc_hfi.c new file mode 100644 index 000000000000..273471a944ef --- /dev/null +++ b/drivers/media/platform/msm/vidc/vidc_hfi.c @@ -0,0 +1,73 @@ +/* Copyright (c) 2012-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. + * + */ +#include +#include "msm_vidc_debug.h" +#include "vidc_hfi_api.h" +#include "venus_hfi.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 = (struct hfi_device *) + kzalloc(sizeof(struct hfi_device), GFP_KERNEL); + if (!hdev) { + dprintk(VIDC_ERR, "%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: + dprintk(VIDC_ERR, "Unsupported host-firmware interface\n"); + goto err_hfi_init; + } + + if (rc) { + if (rc != -EPROBE_DEFER) + dprintk(VIDC_ERR, "%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) { + dprintk(VIDC_ERR, "%s invalid device %pK", __func__, hdev); + return; + } + + switch (hfi_type) { + case VIDC_HFI_VENUS: + venus_hfi_delete_device(hdev->hfi_device_data); + break; + default: + dprintk(VIDC_ERR, "Unsupported host-firmware interface\n"); + } + + kfree(hdev); +} + diff --git a/drivers/media/platform/msm/vidc/vidc_hfi.h b/drivers/media/platform/msm/vidc/vidc_hfi.h new file mode 100644 index 000000000000..8a1a7cec757b --- /dev/null +++ b/drivers/media/platform/msm/vidc/vidc_hfi.h @@ -0,0 +1,869 @@ +/* Copyright (c) 2012-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. + * + */ +#ifndef __H_VIDC_HFI_H__ +#define __H_VIDC_HFI_H__ + +#include +#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_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_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_MASTERING_DISPLAY_COLOUR_SEI_EXTRADATA \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x001E) +#define HFI_PROPERTY_PARAM_VDEC_CONTENT_LIGHT_LEVEL_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_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_DTS_INFO \ + (HFI_PROPERTY_PARAM_VENC_OX_START + 0x00C) + +#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_enable_picture { + u32 picture_type; +}; + +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_SYS_PING (HFI_CMD_SYS_OX_START + 0x002) + +#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_PING_ACK (HFI_MSG_SYS_OX_START + 0x2) +#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 session_id; +}; + +struct hfi_cmd_sys_ping_packet { + u32 size; + u32 packet_type; + u32 client_data; +}; + +struct hfi_cmd_session_load_resources_packet { + u32 size; + u32 packet_type; + u32 session_id; +}; + +struct hfi_cmd_session_start_packet { + u32 size; + u32 packet_type; + u32 session_id; +}; + +struct hfi_cmd_session_stop_packet { + u32 size; + u32 packet_type; + u32 session_id; +}; + +struct hfi_cmd_session_empty_buffer_compressed_packet { + u32 size; + u32 packet_type; + u32 session_id; + u32 time_stamp_hi; + u32 time_stamp_lo; + u32 flags; + u32 mark_target; + u32 mark_data; + 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 session_id; + u32 view_id; + u32 time_stamp_hi; + u32 time_stamp_lo; + u32 flags; + u32 mark_target; + u32 mark_data; + 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 session_id; + 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 session_id; + u32 flush_type; +}; + +struct hfi_cmd_session_suspend_packet { + u32 size; + u32 packet_type; + u32 session_id; +}; + +struct hfi_cmd_session_resume_packet { + u32 size; + u32 packet_type; + u32 session_id; +}; + +struct hfi_cmd_session_get_property_packet { + u32 size; + u32 packet_type; + u32 session_id; + u32 num_properties; + u32 rg_property_data[1]; +}; + +struct hfi_cmd_session_release_buffer_packet { + u32 size; + u32 packet_type; + u32 session_id; + 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 session_id; +}; + +struct hfi_msg_sys_session_abort_done_packet { + u32 size; + u32 packet_type; + u32 session_id; + u32 error_type; +}; + +struct hfi_msg_sys_ping_ack_packet { + u32 size; + u32 packet_type; + u32 client_data; +}; + +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 session_id; + u32 error_type; +}; + +struct hfi_msg_session_start_done_packet { + u32 size; + u32 packet_type; + u32 session_id; + u32 error_type; +}; + +struct hfi_msg_session_stop_done_packet { + u32 size; + u32 packet_type; + u32 session_id; + u32 error_type; +}; + +struct hfi_msg_session_suspend_done_packet { + u32 size; + u32 packet_type; + u32 session_id; + u32 error_type; +}; + +struct hfi_msg_session_resume_done_packet { + u32 size; + u32 packet_type; + u32 session_id; + u32 error_type; +}; + +struct hfi_msg_session_flush_done_packet { + u32 size; + u32 packet_type; + u32 session_id; + 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 session_id; + 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; + u32 rgData[1]; +}; + +struct hfi_msg_session_fill_buffer_done_compressed_packet { + u32 size; + u32 packet_type; + u32 session_id; + u32 time_stamp_hi; + u32 time_stamp_lo; + u32 error_type; + u32 flags; + u32 mark_target; + u32 mark_data; + 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 session_id; + u32 stream_id; + u32 view_id; + u32 error_type; + u32 time_stamp_hi; + u32 time_stamp_lo; + u32 flags; + u32 mark_target; + u32 mark_data; + 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 session_id; + u32 num_properties; + u32 rg_property_data[1]; +}; + +struct hfi_msg_session_release_resources_done_packet { + u32 size; + u32 packet_type; + u32 session_id; + u32 error_type; +}; + +struct hfi_msg_session_release_buffers_done_packet { + u32 size; + u32 packet_type; + u32 session_id; + 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 session_id; + u32 client_data; + u32 error_type; +}; + +struct hfi_msg_session_unregister_buffers_done_packet { + u32 size; + u32 packet_type; + u32 session_id; + 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 session_id; +}; + +enum session_flags { + SESSION_PAUSE = BIT(1), +}; + +struct hal_session { + struct list_head list; + void *session_id; + bool is_decoder; + enum hal_video_codec codec; + enum hal_domain domain; + u32 flags; + void *device; +}; + +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); + +enum vidc_status hfi_process_sys_init_done_prop_read( + struct hfi_msg_sys_init_done_packet *pkt, + struct vidc_hal_sys_init_done *sys_init_done); + +enum vidc_status hfi_process_session_init_done_prop_read( + struct hfi_msg_sys_session_init_done_packet *pkt, + struct vidc_hal_session_init_done *session_init_done); + +#endif + diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h new file mode 100644 index 000000000000..798f57ba8bc2 --- /dev/null +++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h @@ -0,0 +1,1523 @@ +/* Copyright (c) 2012-2020, 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 __VIDC_HFI_API_H__ +#define __VIDC_HFI_API_H__ + +#include +#include +#include +#include +#include +#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_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 + +/* 16 encoder and 16 decoder sessions */ +#define VIDC_MAX_SESSIONS 32 +#define VIDC_MAX_DECODE_SESSIONS 16 +#define VIDC_MAX_ENCODE_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_extradata_id { + HAL_EXTRADATA_NONE, + HAL_EXTRADATA_INTERLACE_VIDEO, + HAL_EXTRADATA_TIMESTAMP, + HAL_EXTRADATA_S3D_FRAME_PACKING, + HAL_EXTRADATA_FRAME_RATE, + HAL_EXTRADATA_PANSCAN_WINDOW, + HAL_EXTRADATA_RECOVERY_POINT_SEI, + HAL_EXTRADATA_INDEX, + HAL_EXTRADATA_NUM_CONCEALED_MB, + HAL_EXTRADATA_ASPECT_RATIO, + HAL_EXTRADATA_MPEG2_SEQDISP, + HAL_EXTRADATA_STREAM_USERDATA, + HAL_EXTRADATA_DEC_FRAME_QP, + HAL_EXTRADATA_ENC_FRAME_QP, + HAL_EXTRADATA_LTR_INFO, + HAL_EXTRADATA_ROI_QP, + HAL_EXTRADATA_OUTPUT_CROP, + HAL_EXTRADATA_MASTERING_DISPLAY_COLOUR_SEI, + HAL_EXTRADATA_CONTENT_LIGHT_LEVEL_SEI, + HAL_EXTRADATA_VUI_DISPLAY_INFO, + HAL_EXTRADATA_VPX_COLORSPACE, + HAL_EXTRADATA_UBWC_CR_STATS_INFO, + HAL_EXTRADATA_HDR10PLUS_METADATA, + HAL_EXTRADATA_ENC_DTS_METADATA, + HAL_EXTRADATA_INPUT_CROP, +}; + +enum hal_property { + HAL_CONFIG_FRAME_RATE = 0x04000001, + HAL_CONFIG_OPERATING_RATE, + HAL_PARAM_UNCOMPRESSED_FORMAT_SELECT, + HAL_PARAM_UNCOMPRESSED_PLANE_ACTUAL_CONSTRAINTS_INFO, + HAL_PARAM_UNCOMPRESSED_PLANE_ACTUAL_INFO, + HAL_PARAM_INDEX_EXTRADATA, + HAL_PARAM_FRAME_SIZE, + HAL_CONFIG_REALTIME, + HAL_PARAM_BUFFER_COUNT_ACTUAL, + HAL_PARAM_BUFFER_SIZE_MINIMUM, + HAL_PARAM_NAL_STREAM_FORMAT_SELECT, + HAL_PARAM_VDEC_OUTPUT_ORDER, + HAL_PARAM_VDEC_PICTURE_TYPE_DECODE, + HAL_PARAM_VDEC_OUTPUT2_KEEP_ASPECT_RATIO, + HAL_PARAM_VDEC_MULTI_STREAM, + HAL_PARAM_VDEC_DISPLAY_PICTURE_BUFFER_COUNT, + HAL_CONFIG_VDEC_MB_ERROR_MAP_REPORTING, + HAL_PARAM_VDEC_CONTINUE_DATA_TRANSFER, + HAL_CONFIG_VDEC_MB_ERROR_MAP, + HAL_CONFIG_VENC_REQUEST_IFRAME, + HAL_CONFIG_VENC_TARGET_BITRATE, + HAL_PARAM_PROFILE_LEVEL_CURRENT, + HAL_PARAM_VENC_H264_ENTROPY_CONTROL, + HAL_PARAM_VENC_RATE_CONTROL, + HAL_PARAM_VENC_H264_DEBLOCK_CONTROL, + HAL_PARAM_VENC_TEMPORAL_SPATIAL_TRADEOFF, + HAL_PARAM_VENC_SESSION_QP_RANGE, + HAL_CONFIG_VENC_INTRA_PERIOD, + HAL_CONFIG_VENC_IDR_PERIOD, + HAL_PARAM_VENC_ADAPTIVE_B, + HAL_PARAM_VPE_ROTATION, + HAL_PARAM_VENC_INTRA_REFRESH, + HAL_PARAM_VENC_MULTI_SLICE_CONTROL, + HAL_SYS_DEBUG_CONFIG, + HAL_CONFIG_BUFFER_REQUIREMENTS, + HAL_CONFIG_PRIORITY, + HAL_CONFIG_BATCH_INFO, + HAL_PARAM_METADATA_PASS_THROUGH, + HAL_SYS_IDLE_INDICATOR, + HAL_PARAM_UNCOMPRESSED_FORMAT_SUPPORTED, + HAL_PARAM_INTERLACE_FORMAT_SUPPORTED, + HAL_PARAM_CHROMA_SITE, + HAL_PARAM_PROPERTIES_SUPPORTED, + HAL_PARAM_PROFILE_LEVEL_SUPPORTED, + HAL_PARAM_CAPABILITY_SUPPORTED, + HAL_PARAM_NAL_STREAM_FORMAT_SUPPORTED, + HAL_PARAM_MULTI_VIEW_FORMAT, + HAL_PARAM_MAX_SEQUENCE_HEADER_SIZE, + HAL_PARAM_CODEC_SUPPORTED, + HAL_PARAM_VDEC_MULTI_VIEW_SELECT, + HAL_PARAM_VDEC_MB_QUANTIZATION, + HAL_PARAM_VDEC_NUM_CONCEALED_MB, + HAL_PARAM_VDEC_H264_ENTROPY_SWITCHING, + HAL_PARAM_VENC_SLICE_DELIVERY_MODE, + HAL_CONFIG_BUFFER_COUNT_ACTUAL, + HAL_CONFIG_VDEC_MULTI_STREAM, + HAL_PARAM_VENC_MULTI_SLICE_INFO, + HAL_CONFIG_VENC_TIMESTAMP_SCALE, + HAL_PARAM_VENC_SYNC_FRAME_SEQUENCE_HEADER, + HAL_PARAM_VDEC_SYNC_FRAME_DECODE, + HAL_CONFIG_VENC_MAX_BITRATE, + HAL_PARAM_VENC_VUI_TIMING_INFO, + HAL_PARAM_VENC_GENERATE_AUDNAL, + HAL_PARAM_BUFFER_ALLOC_MODE, + HAL_PARAM_VDEC_FRAME_ASSEMBLY, + HAL_PARAM_VENC_PRESERVE_TEXT_QUALITY, + HAL_PARAM_VDEC_CONCEAL_COLOR, + HAL_PARAM_VDEC_SCS_THRESHOLD, + HAL_PARAM_GET_BUFFER_REQUIREMENTS, + HAL_PARAM_VENC_LTRMODE, + HAL_CONFIG_VENC_MARKLTRFRAME, + HAL_CONFIG_VENC_USELTRFRAME, + HAL_CONFIG_VENC_LTRPERIOD, + HAL_CONFIG_VENC_HIER_P_NUM_FRAMES, + HAL_PARAM_VENC_HIER_P_MAX_ENH_LAYERS, + HAL_PARAM_VENC_DISABLE_RC_TIMESTAMP, + HAL_PARAM_VENC_SEARCH_RANGE, + HAL_PARAM_VPE_COLOR_SPACE_CONVERSION, + HAL_PARAM_VENC_VPX_ERROR_RESILIENCE_MODE, + HAL_CONFIG_VENC_PERF_MODE, + HAL_PARAM_VDEC_NON_SECURE_OUTPUT2, + HAL_PARAM_VENC_HIER_P_HYBRID_MODE, + HAL_PARAM_VENC_MBI_STATISTICS_MODE, + HAL_PARAM_SYNC_BASED_INTERRUPT, + HAL_CONFIG_VENC_FRAME_QP, + HAL_CONFIG_VENC_BASELAYER_PRIORITYID, + HAL_PROPERTY_PARAM_VENC_ASPECT_RATIO, + HAL_CONFIG_VDEC_ENTROPY, + HAL_PARAM_VENC_BITRATE_TYPE, + HAL_PARAM_VENC_LOW_LATENCY, + HAL_CONFIG_VENC_BLUR_RESOLUTION, + HAL_PARAM_VENC_H264_TRANSFORM_8x8, + HAL_PARAM_VENC_VIDEO_SIGNAL_INFO, + HAL_PARAM_VENC_IFRAMESIZE_TYPE, + HAL_PARAM_VIDEO_CORES_USAGE, + HAL_PARAM_VIDEO_WORK_MODE, + HAL_PARAM_SECURE, + HAL_PARAM_VENC_HDR10_PQ_SEI, + HAL_PARAM_VIDEO_WORK_ROUTE, + HAL_CONFIG_VENC_VBV_HRD_BUF_SIZE, + HAL_CONFIG_HEIC_FRAME_QUALITY, + HAL_CONFIG_HEIC_GRID_ENABLE, + HAL_PARAM_VENC_BITRATE_SAVINGS, +}; + +enum hal_domain { + HAL_VIDEO_DOMAIN_VPE, + HAL_VIDEO_DOMAIN_ENCODER, + HAL_VIDEO_DOMAIN_DECODER, + HAL_VIDEO_DOMAIN_CVP, + 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_mpeg2_profile { + HAL_UNUSED_MPEG2_PROFILE = 0x00000000, + HAL_MPEG2_PROFILE_SIMPLE = 0x00000001, + HAL_MPEG2_PROFILE_MAIN = 0x00000002, +}; + +enum hal_mpeg2_level { + HAL_UNUSED_MEPG2_LEVEL = 0x00000000, + HAL_MPEG2_LEVEL_LL = 0x00000001, + HAL_MPEG2_LEVEL_ML = 0x00000002, + HAL_MPEG2_LEVEL_HL = 0x00000004, +}; + +enum hal_h264_profile { + HAL_UNUSED_H264_PROFILE = 0x00000000, + HAL_H264_PROFILE_BASELINE = 0x00000001, + HAL_H264_PROFILE_MAIN = 0x00000002, + HAL_H264_PROFILE_HIGH = 0x00000004, + HAL_H264_PROFILE_STEREO_HIGH = 0x00000008, + HAL_H264_PROFILE_MULTIVIEW_HIGH = 0x00000010, + HAL_H264_PROFILE_CONSTRAINED_BASE = 0x00000020, + HAL_H264_PROFILE_CONSTRAINED_HIGH = 0x00000040, +}; + +enum hal_h264_level { + HAL_H264_LEVEL_UNKNOWN = 0x00000000, + HAL_H264_LEVEL_1 = 0x00000001, + HAL_H264_LEVEL_1b = 0x00000002, + HAL_H264_LEVEL_11 = 0x00000004, + HAL_H264_LEVEL_12 = 0x00000008, + HAL_H264_LEVEL_13 = 0x00000010, + HAL_H264_LEVEL_2 = 0x00000020, + HAL_H264_LEVEL_21 = 0x00000040, + HAL_H264_LEVEL_22 = 0x00000080, + HAL_H264_LEVEL_3 = 0x00000100, + HAL_H264_LEVEL_31 = 0x00000200, + HAL_H264_LEVEL_32 = 0x00000400, + HAL_H264_LEVEL_4 = 0x00000800, + HAL_H264_LEVEL_41 = 0x00001000, + HAL_H264_LEVEL_42 = 0x00002000, + HAL_H264_LEVEL_5 = 0x00004000, + HAL_H264_LEVEL_51 = 0x00008000, + HAL_H264_LEVEL_52 = 0x00010000, + HAL_H264_LEVEL_6 = 0x00020000, + HAL_H264_LEVEL_61 = 0x00040000, + HAL_H264_LEVEL_62 = 0x00080000, +}; + +enum hal_hevc_profile { + HAL_UNUSED_HEVC_PROFILE = 0x00000000, + HAL_HEVC_PROFILE_MAIN = 0x00000001, + HAL_HEVC_PROFILE_MAIN10 = 0x00000002, + HAL_HEVC_PROFILE_MAIN_STILL_PIC = 0x00000004, +}; + +enum hal_hevc_level { + HAL_HEVC_TIER_LEVEL_UNKNOWN = 0x00000000, + HAL_HEVC_MAIN_TIER_LEVEL_1 = 0x10000001, + HAL_HEVC_MAIN_TIER_LEVEL_2 = 0x10000002, + HAL_HEVC_MAIN_TIER_LEVEL_2_1 = 0x10000004, + HAL_HEVC_MAIN_TIER_LEVEL_3 = 0x10000008, + HAL_HEVC_MAIN_TIER_LEVEL_3_1 = 0x10000010, + HAL_HEVC_MAIN_TIER_LEVEL_4 = 0x10000020, + HAL_HEVC_MAIN_TIER_LEVEL_4_1 = 0x10000040, + HAL_HEVC_MAIN_TIER_LEVEL_5 = 0x10000080, + HAL_HEVC_MAIN_TIER_LEVEL_5_1 = 0x10000100, + HAL_HEVC_MAIN_TIER_LEVEL_5_2 = 0x10000200, + HAL_HEVC_MAIN_TIER_LEVEL_6 = 0x10000400, + HAL_HEVC_MAIN_TIER_LEVEL_6_1 = 0x10000800, + HAL_HEVC_MAIN_TIER_LEVEL_6_2 = 0x10001000, + HAL_HEVC_HIGH_TIER_LEVEL_1 = 0x20000001, + HAL_HEVC_HIGH_TIER_LEVEL_2 = 0x20000002, + HAL_HEVC_HIGH_TIER_LEVEL_2_1 = 0x20000004, + HAL_HEVC_HIGH_TIER_LEVEL_3 = 0x20000008, + HAL_HEVC_HIGH_TIER_LEVEL_3_1 = 0x20000010, + HAL_HEVC_HIGH_TIER_LEVEL_4 = 0x20000020, + HAL_HEVC_HIGH_TIER_LEVEL_4_1 = 0x20000040, + HAL_HEVC_HIGH_TIER_LEVEL_5 = 0x20000080, + HAL_HEVC_HIGH_TIER_LEVEL_5_1 = 0x20000100, + HAL_HEVC_HIGH_TIER_LEVEL_5_2 = 0x20000200, + HAL_HEVC_HIGH_TIER_LEVEL_6 = 0x20000400, + HAL_HEVC_HIGH_TIER_LEVEL_6_1 = 0x20000800, + HAL_HEVC_HIGH_TIER_LEVEL_6_2 = 0x20001000, +}; + +enum hal_hevc_tier { + HAL_HEVC_TIER_MAIN = 0x00000001, + HAL_HEVC_TIER_HIGH = 0x00000002, + HAL_UNUSED_HEVC_TIER = 0x10000000, +}; + +enum hal_vp8_profile { + HAL_VP8_PROFILE_UNUSED = 0x00000000, + HAL_VP8_PROFILE_MAIN = 0x00000001, +}; + +enum hal_vp8_level { + HAL_VP8_LEVEL_UNUSED = 0x00000000, + HAL_VP8_LEVEL_VERSION_0 = 0x00000001, + HAL_VP8_LEVEL_VERSION_1 = 0x00000002, + HAL_VP8_LEVEL_VERSION_2 = 0x00000004, + HAL_VP8_LEVEL_VERSION_3 = 0x00000008, +}; + +enum hal_tme_profile { + HAL_TME_PROFILE_0 = 0x00000001, + HAL_TME_PROFILE_1 = 0x00000002, + HAL_TME_PROFILE_2 = 0x00000004, + HAL_TME_PROFILE_3 = 0x00000008, +}; + +enum hal_tme_level { + HAL_TME_LEVEL_INTEGER = 0x00000001, +}; + +enum hal_vp9_profile { + HAL_VP9_PROFILE_UNUSED = 0x00000000, + HAL_VP9_PROFILE_P0 = 0x00000001, + HAL_VP9_PROFILE_P2_10 = 0x00000004, +}; + +enum hal_vp9_level { + HAL_VP9_LEVEL_UNUSED = 0x00000000, + HAL_VP9_LEVEL_1 = 0x00000001, + HAL_VP9_LEVEL_11 = 0x00000002, + HAL_VP9_LEVEL_2 = 0x00000004, + HAL_VP9_LEVEL_21 = 0x00000008, + HAL_VP9_LEVEL_3 = 0x00000010, + HAL_VP9_LEVEL_31 = 0x00000020, + HAL_VP9_LEVEL_4 = 0x00000040, + HAL_VP9_LEVEL_41 = 0x00000080, + HAL_VP9_LEVEL_5 = 0x00000100, + HAL_VP9_LEVEL_51 = 0x00000200, + HAL_VP9_LEVEL_6 = 0x00000400, + HAL_VP9_LEVEL_61 = 0x00000800, +}; + +struct hal_frame_rate { + enum hal_buffer buffer_type; + u32 frame_rate; +}; + +struct hal_operating_rate { + u32 operating_rate; +}; + +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_statistics_mode_type { + HAL_STATISTICS_MODE_DEFAULT = 0x00000001, + HAL_STATISTICS_MODE_1 = 0x00000002, + HAL_STATISTICS_MODE_2 = 0x00000004, + HAL_STATISTICS_MODE_3 = 0x00000008, +}; + +enum hal_ssr_trigger_type { + SSR_ERR_FATAL = 1, + SSR_SW_DIV_BY_ZERO, + SSR_HW_WDOG_IRQ, +}; + +struct hal_uncompressed_format_select { + enum hal_buffer buffer_type; + enum hal_uncompressed_format format; +}; + +struct hal_uncompressed_plane_actual { + int actual_stride; + u32 actual_plane_buffer_height; +}; + +struct hal_uncompressed_plane_actual_info { + enum hal_buffer buffer_type; + u32 num_planes; + struct hal_uncompressed_plane_actual rg_plane_format[1]; +}; + +struct hal_uncompressed_plane_constraints { + u32 stride_multiples; + u32 max_stride; + u32 min_plane_buffer_height_multiple; + u32 buffer_alignment; +}; + +struct hal_uncompressed_plane_actual_constraints_info { + enum hal_buffer buffer_type; + u32 num_planes; + struct hal_uncompressed_plane_constraints rg_plane_format[1]; +}; + +struct hal_frame_size { + enum hal_buffer buffer_type; + u32 width; + u32 height; +}; + +struct hal_enable { + bool enable; +}; + +struct hal_buffer_count_actual { + enum hal_buffer buffer_type; + u32 buffer_count_actual; + u32 buffer_count_min_host; +}; + +struct hal_buffer_size_minimum { + enum hal_buffer buffer_type; + u32 buffer_size; +}; + +struct hal_buffer_display_hold_count_actual { + enum hal_buffer buffer_type; + u32 hold_count; +}; + +enum hal_nal_stream_format { + HAL_NAL_FORMAT_STARTCODES = 0x00000001, + HAL_NAL_FORMAT_ONE_NAL_PER_BUFFER = 0x00000002, + HAL_NAL_FORMAT_ONE_BYTE_LENGTH = 0x00000004, + HAL_NAL_FORMAT_TWO_BYTE_LENGTH = 0x00000008, + HAL_NAL_FORMAT_FOUR_BYTE_LENGTH = 0x00000010, +}; + +enum hal_output_order { + HAL_OUTPUT_ORDER_DISPLAY, + HAL_OUTPUT_ORDER_DECODE, + HAL_UNUSED_OUTPUT = 0x10000000, +}; + +enum hal_picture { + HAL_PICTURE_I = 0x01, + HAL_PICTURE_P = 0x02, + HAL_PICTURE_B = 0x04, + HAL_PICTURE_IDR = 0x08, + HAL_PICTURE_CRA = 0x10, + HAL_FRAME_NOTCODED = 0x7F002000, + HAL_FRAME_YUV = 0x7F004000, + HAL_UNUSED_PICT = 0x10000000, +}; + +struct hal_extradata_enable { + u32 enable; + enum hal_extradata_id index; +}; + +struct hal_enable_picture { + u32 picture_type; +}; + +struct hal_multi_stream { + enum hal_buffer buffer_type; + u32 enable; + u32 width; + u32 height; +}; + +struct hal_display_picture_buffer_count { + u32 enable; + u32 count; +}; + +struct hal_mb_error_map { + u32 error_map_size; + u8 rg_error_map[1]; +}; + +struct hal_request_iframe { + u32 enable; +}; + +struct hal_bitrate { + u32 bit_rate; + u32 layer_id; +}; + +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_h264_entropy { + HAL_H264_ENTROPY_CAVLC = 1, + HAL_H264_ENTROPY_CABAC = 2, + HAL_UNUSED_ENTROPY = 0x10000000, +}; + +struct hal_h264_entropy_control { + enum hal_h264_entropy entropy_mode; +}; + +enum hal_rate_control { + HAL_RATE_CONTROL_VBR, + HAL_RATE_CONTROL_CBR, + HAL_RATE_CONTROL_MBR, + HAL_RATE_CONTROL_OFF, + HAL_RATE_CONTROL_CBR_VFR, + HAL_RATE_CONTROL_MBR_VFR, + HAL_RATE_CONTROL_CQ, + HAL_UNUSED_RC = 0x10000000, +}; + +enum hal_h264_db_mode { + HAL_H264_DB_MODE_DISABLE, + HAL_H264_DB_MODE_SKIP_SLICE_BOUNDARY, + HAL_H264_DB_MODE_ALL_BOUNDARY, + HAL_UNUSED_H264_DB = 0x10000000, +}; + +struct hal_h264_db_control { + enum hal_h264_db_mode mode; + int slice_alpha_offset; + int slice_beta_offset; +}; + +struct hal_temporal_spatial_tradeoff { + u32 ts_factor; +}; + +struct hal_quantization { + u32 qpi; + u32 qpp; + u32 qpb; + u32 layer_id; + u32 enable; +}; + +struct hal_quantization_range { + u32 qpi_min; + u32 qpp_min; + u32 qpb_min; + u32 qpi_max; + u32 qpp_max; + u32 qpb_max; + u32 layer_id; +}; + +struct hal_intra_period { + u32 pframes; + u32 bframes; +}; + +struct hal_idr_period { + u32 idr_period; +}; + +struct hal_heic_frame_quality { + u32 frame_quality; +}; + +struct hal_heic_grid_enable { + u32 grid_enable; +}; + +enum hal_flip { + HAL_FLIP_NONE, + HAL_FLIP_VERTICAL, + HAL_FLIP_HORIZONTAL, + HAL_FLIP_BOTH, + HAL_UNUSED_FLIP = 0x10000000, +}; + +struct hal_vpe_rotation { + u32 rotate; + enum hal_flip flip; +}; + +enum hal_intra_refresh_mode { + HAL_INTRA_REFRESH_NONE, + HAL_INTRA_REFRESH_CYCLIC, + HAL_INTRA_REFRESH_RANDOM, + HAL_UNUSED_INTRA = 0x10000000, +}; + +struct hal_intra_refresh { + enum hal_intra_refresh_mode mode; + u32 ir_mbs; +}; + +enum hal_multi_slice { + HAL_MULTI_SLICE_OFF, + HAL_MULTI_SLICE_BY_MB_COUNT, + HAL_MULTI_SLICE_BY_BYTE_COUNT, + HAL_MULTI_SLICE_GOB, + HAL_UNUSED_SLICE = 0x10000000, +}; + +struct hal_multi_slice_control { + enum hal_multi_slice multi_slice; + u32 slice_size; +}; + +struct hal_debug_config { + u32 debug_config; +}; + +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_metadata_pass_through { + u32 enable; + u32 size; +}; + +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, +}; + +struct hal_properties_supported { + u32 num_properties; + u32 rg_properties[1]; +}; + +enum hal_capability { + HAL_CAPABILITY_FRAME_WIDTH = 0x1, + HAL_CAPABILITY_FRAME_HEIGHT, + HAL_CAPABILITY_MBS_PER_FRAME, + HAL_CAPABILITY_MBS_PER_SECOND, + HAL_CAPABILITY_FRAMERATE, + HAL_CAPABILITY_SCALE_X, + HAL_CAPABILITY_SCALE_Y, + HAL_CAPABILITY_BITRATE, + HAL_CAPABILITY_BFRAME, + HAL_CAPABILITY_PEAKBITRATE, + HAL_CAPABILITY_HIER_P_NUM_ENH_LAYERS, + HAL_CAPABILITY_ENC_LTR_COUNT, + HAL_CAPABILITY_SECURE_OUTPUT2_THRESHOLD, + HAL_CAPABILITY_HIER_B_NUM_ENH_LAYERS, + HAL_CAPABILITY_LCU_SIZE, + HAL_CAPABILITY_HIER_P_HYBRID_NUM_ENH_LAYERS, + HAL_CAPABILITY_MBS_PER_SECOND_POWER_SAVE, + HAL_CAPABILITY_EXTRADATA, + HAL_CAPABILITY_PROFILE, + HAL_CAPABILITY_LEVEL, + HAL_CAPABILITY_I_FRAME_QP, + HAL_CAPABILITY_P_FRAME_QP, + HAL_CAPABILITY_B_FRAME_QP, + HAL_CAPABILITY_RATE_CONTROL_MODES, + HAL_CAPABILITY_BLUR_WIDTH, + HAL_CAPABILITY_BLUR_HEIGHT, + HAL_CAPABILITY_SLICE_DELIVERY_MODES, + HAL_CAPABILITY_SLICE_BYTE, + HAL_CAPABILITY_SLICE_MB, + HAL_CAPABILITY_SECURE, + HAL_CAPABILITY_MAX_NUM_B_FRAMES, + HAL_CAPABILITY_MAX_VIDEOCORES, + HAL_CAPABILITY_MAX_WORKMODES, + HAL_CAPABILITY_UBWC_CR_STATS, + HAL_CAPABILITY_ROTATION, + HAL_CAPABILITY_COLOR_SPACE_CONVERSION, + HAL_UNUSED_CAPABILITY = 0x10000000, +}; + +struct hal_capability_supported { + enum hal_capability capability_type; + u32 min; + u32 max; + u32 step_size; +}; + +struct hal_capability_supported_info { + u32 num_capabilities; + struct hal_capability_supported rg_data[1]; +}; + +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_aspect_ratio { + u32 aspect_width; + u32 aspect_height; +}; + +struct hal_codec_supported { + u32 decoder_codec_supported; + u32 encoder_codec_supported; +}; + +struct hal_multi_view_select { + u32 view_index; +}; + +struct hal_timestamp_scale { + u32 time_stamp_scale; +}; + + +struct hal_vui_timing_info { + u32 enable; + u32 fixed_frame_rate; + u32 time_scale; +}; + +struct hal_preserve_text_quality { + u32 enable; +}; + +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, +}; + +struct hal_videocores_usage_info { + u32 video_core_enable_mask; +}; + +enum hal_work_mode { + VIDC_WORK_MODE_1 = 1, + VIDC_WORK_MODE_2 = 2, + VIDC_WORK_MODE_UNUSED = 0x10000000, +}; + +struct hal_video_work_mode { + u32 video_work_mode; +}; + +struct hal_video_work_route { + u32 video_work_route; +}; + +struct hal_vpe_color_space_conversion { + u32 input_color_primaries; + u32 custom_matrix_enabled; + u32 csc_matrix[HAL_MAX_MATRIX_COEFFS]; + u32 csc_bias[HAL_MAX_BIAS_COEFFS]; + u32 csc_limit[HAL_MAX_LIMIT_COEFFS]; +}; + +struct hal_video_signal_info { + u32 color_space; + u32 transfer_chars; + u32 matrix_coeffs; + bool full_range; +}; + +enum hal_iframesize_type { + HAL_IFRAMESIZE_TYPE_DEFAULT, + HAL_IFRAMESIZE_TYPE_MEDIUM, + HAL_IFRAMESIZE_TYPE_HUGE, + HAL_IFRAMESIZE_TYPE_UNLIMITED, +}; + +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 mark_target; + u32 mark_data; + u32 input_tag; + u32 output_tag; + u32 clnt_data; + 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 hal_ltr_mode { + enum ltr_mode mode; + u32 count; + u32 trust_mode; +}; + +struct hal_ltr_use { + u32 ref_ltr; + u32 use_constraint; + u32 frames; +}; + +struct hal_ltr_mark { + u32 mark_frame; +}; + +enum hal_perf_mode { + HAL_PERF_MODE_POWER_SAVE, + HAL_PERF_MODE_POWER_MAX_QUALITY, +}; + +struct hal_hybrid_hierp { + u32 layers; +}; + +struct hal_scs_threshold { + u32 threshold_value; +}; + +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_frame_rate frame_rate; + struct hal_uncompressed_format_select format_select; + struct hal_uncompressed_plane_actual plane_actual; + struct hal_uncompressed_plane_actual_info plane_actual_info; + struct hal_uncompressed_plane_constraints plane_constraints; + struct hal_uncompressed_plane_actual_constraints_info + plane_constraints_info; + struct hal_frame_size frame_size; + struct hal_enable enable; + struct hal_buffer_count_actual buffer_count_actual; + struct hal_extradata_enable extradata_enable; + struct hal_enable_picture enable_picture; + struct hal_multi_stream multi_stream; + struct hal_display_picture_buffer_count display_picture_buffer_count; + struct hal_mb_error_map mb_error_map; + struct hal_request_iframe request_iframe; + struct hal_bitrate bitrate; + struct hal_profile_level profile_level; + struct hal_profile_level_supported profile_level_supported; + struct hal_h264_db_control h264_db_control; + struct hal_temporal_spatial_tradeoff temporal_spatial_tradeoff; + struct hal_quantization quantization; + struct hal_quantization_range quantization_range; + struct hal_intra_period intra_period; + struct hal_idr_period idr_period; + struct hal_vpe_rotation vpe_rotation; + struct hal_intra_refresh intra_refresh; + struct hal_multi_slice_control multi_slice_control; + struct hal_debug_config debug_config; + struct hal_batch_info batch_info; + struct hal_metadata_pass_through metadata_pass_through; + struct hal_uncompressed_format_supported uncompressed_format_supported; + struct hal_interlace_format_supported interlace_format_supported; + struct hal_properties_supported properties_supported; + struct hal_capability_supported capability_supported; + struct hal_capability_supported_info capability_supported_info; + 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_codec_supported codec_supported; + struct hal_multi_view_select multi_view_select; + struct hal_timestamp_scale timestamp_scale; + struct hal_vui_timing_info vui_timing_info; + struct hal_preserve_text_quality preserve_text_quality; + struct hal_buffer_info buffer_info; + struct hal_buffer_alloc_mode buffer_alloc_mode; + struct buffer_requirements buf_req; + enum hal_h264_entropy h264_entropy; + 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_PING_ACK_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 mark_target; + u32 mark_data; + u32 stats; + u32 offset; + u32 input_tag; + u32 output_tag; + u32 alloc_len; + u32 filled_len; + enum hal_picture 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 mark_target; + u32 mark_data; + 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_tag1; + u32 output_tag; + enum hal_picture 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 width; + struct hal_capability_supported height; + struct hal_capability_supported mbs_per_frame; + struct hal_capability_supported mbs_per_sec; + struct hal_capability_supported frame_rate; + struct hal_capability_supported scale_x; + struct hal_capability_supported scale_y; + struct hal_capability_supported bitrate; + struct hal_capability_supported bframe; + struct hal_capability_supported peakbitrate; + struct hal_capability_supported hier_p; + struct hal_capability_supported ltr_count; + struct hal_capability_supported secure_output2_threshold; + struct hal_capability_supported hier_b; + struct hal_capability_supported lcu_size; + struct hal_capability_supported hier_p_hybrid; + struct hal_capability_supported mbs_per_sec_power_save; + struct hal_capability_supported extradata; + struct hal_capability_supported profile; + struct hal_capability_supported level; + struct hal_capability_supported i_qp; + struct hal_capability_supported p_qp; + struct hal_capability_supported b_qp; + struct hal_capability_supported rc_modes; + struct hal_capability_supported blur_width; + struct hal_capability_supported blur_height; + struct hal_capability_supported color_space_caps; + struct hal_capability_supported rotation; + struct hal_capability_supported slice_delivery_mode; + struct hal_capability_supported slice_bytes; + struct hal_capability_supported slice_mbs; + struct hal_capability_supported secure; + struct hal_capability_supported max_num_b_frames; + struct hal_capability_supported max_video_cores; + struct hal_capability_supported max_work_modes; + struct hal_capability_supported ubwc_cr_stats; + struct hal_profile_level_supported profile_level; + struct hal_uncompressed_format_supported uncomp_format; + struct hal_interlace_format_supported HAL_format; + struct hal_nal_stream_format_supported nal_stream_format; + struct hal_intra_refresh intra_refresh; + enum buffer_mode_type alloc_mode_out; + enum buffer_mode_type alloc_mode_in; + u32 pixelprocess_capabilities; + u32 tme_version; +}; + +struct vidc_hal_sys_init_done { + u32 dec_codec_supported; + u32 enc_codec_supported; + u32 codec_count; + struct msm_vidc_capability *capabilities; + u32 max_sessions_supported; +}; + +struct vidc_hal_session_init_done { + struct msm_vidc_capability capability; +}; + +struct msm_vidc_cb_cmd_done { + u32 device_id; + void *session_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 vidc_hal_session_init_done session_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 hal_index_extradata_input_crop_payload { + u32 size; + u32 version; + u32 port_index; + u32 left; + u32 top; + u32 width; + u32 height; +}; + +struct msm_vidc_cb_event { + u32 device_id; + void *session_id; + enum vidc_status status; + u32 height; + u32 width; + int bit_depth; + u32 hal_event_type; + u32 packet_buffer; + u32 extra_data_buffer; + u32 output_tag; + u32 pic_struct; + u32 colour_space; + u32 profile; + u32 level; + u32 entropy_mode; + u32 capture_buf_count; + u32 max_dpb_count; + u32 max_ref_count; + u32 max_dec_buffering; + struct hal_index_extradata_input_crop_payload crop_data; +}; + +struct msm_vidc_cb_data_done { + u32 device_id; + void *session_id; + enum vidc_status status; + u32 size; + u32 clnt_data; + 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 vidc_vote_data_session { + VIDC_BUS_VOTE_DATA_SESSION_INVALID = 0, + /* + * No declarations exist. Values generated by VIDC_VOTE_DATA_SESSION_VAL + * describe the enumerations e.g.: + * + * enum vidc_bus_vote_data_session_type h264_decoder_session = + * VIDC_VOTE_DATA_SESSION_VAL(HAL_VIDEO_CODEC_H264, + * HAL_VIDEO_DOMAIN_DECODER); + */ +}; + +/* + * Careful modifying VIDC_VOTE_DATA_SESSION_VAL(). + * + * This macro assigns two bits to each codec: the lower bit denoting the codec + * type, and the higher bit denoting session type. + */ +static inline enum vidc_vote_data_session VIDC_VOTE_DATA_SESSION_VAL( + enum hal_video_codec c, enum hal_domain d) { + if (d != HAL_VIDEO_DOMAIN_ENCODER && d != HAL_VIDEO_DOMAIN_DECODER) + return VIDC_BUS_VOTE_DATA_SESSION_INVALID; + + return (1 << ilog2(c) * 2) | ((d - 1) << (ilog2(c) * 2 + 1)); +} + +struct msm_vidc_gov_data { + struct vidc_bus_vote_data *data; + u32 data_count; +}; + +enum msm_vidc_power_mode { + VIDC_POWER_NORMAL = 0, + VIDC_POWER_LOW, + VIDC_POWER_TURBO +}; + +struct vidc_bus_vote_data { + 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, fps, bitrate; + int output_height, output_width; + int rotation; + int compression_ratio; + int complexity_factor; + int input_cr; + u32 ddr_bw; + u32 sys_cache_bw; + bool use_dpb_read; + unsigned int lcu_size; + enum msm_vidc_power_mode power_mode; + enum hal_work_mode work_mode; + bool use_sys_cache; + bool b_frames_enabled; +}; + +struct vidc_clk_scale_data { + enum vidc_vote_data_session session[VIDC_MAX_SESSIONS]; + enum msm_vidc_power_mode power_mode[VIDC_MAX_SESSIONS]; + u32 load[VIDC_MAX_SESSIONS]; + int num_sessions; +}; + +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, args...) \ + (((q) && (q)->op) ? ((q)->op(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_ping)(void *device); + int (*core_trigger_ssr)(void *device, enum hal_ssr_trigger_type); + int (*session_init)(void *device, void *session_id, + enum hal_domain session_type, enum hal_video_codec codec_type, + void **new_session); + 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, enum hal_property ptype, + void *pdata); + int (*session_get_property)(void *sess, enum hal_property ptype); + int (*session_pause)(void *sess); + int (*session_resume)(void *sess); + int (*scale_clocks)(void *dev, u32 freq); + int (*vote_bus)(void *dev, struct vidc_bus_vote_data *data, + int num_data); + 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 vidc_get_hfi_codec(enum hal_video_codec hal_codec); +enum hal_domain vidc_get_hal_domain(u32 hfi_domain); +enum hal_video_codec vidc_get_hal_codec(u32 hfi_codec); + +#endif /*__VIDC_HFI_API_H__ */ diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h new file mode 100644 index 000000000000..b9c2e90313d0 --- /dev/null +++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h @@ -0,0 +1,1169 @@ +/* Copyright (c) 2012-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. + * + */ + +#ifndef __H_VIDC_HFI_HELPER_H__ +#define __H_VIDC_HFI_HELPER_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_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_HIGH0 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_PARAM_VDEC_DPB_COUNTS \ + (HFI_PROPERTY_PARAM_VDEC_COMMON_START + 0x00B) + + +#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_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_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) + +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_ROTATION (HFI_COMMON_BASE + 0X2F) +#define HFI_CAPABILITY_COLOR_SPACE_CONVERSION (HFI_COMMON_BASE + 0X30) +#define HFI_CAPABILITY_MAX_WORKROUTES (HFI_COMMON_BASE + 0X31) +#define HFI_CAPABILITY_CQ_QUALITY_LEVEL (HFI_COMMON_BASE + 0X32) + +struct hfi_capability_supported { + u32 capability_type; + u32 min; + u32 max; + u32 step_size; +}; + +struct hfi_capability_supported_info { + u32 num_capabilities; + struct hfi_capability_supported rg_data[1]; +}; + +#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; +}; + +#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; +}; + +struct hfi_multi_view_format { + u32 views; + u32 rg_view_order[1]; +}; + +#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 + +struct hfi_profile_level { + u32 profile; + u32 level; +}; + +struct hfi_dpb_counts { + u32 max_dpb_count; + u32 max_ref_count; + u32 max_dec_buffering; +}; + +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; +}; + +struct hfi_picture_type { + u32 picture_type; +}; + +/* 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_MONOCHROME (HFI_COMMON_BASE + 0x1) +#define HFI_COLOR_FORMAT_NV12 (HFI_COMMON_BASE + 0x2) +#define HFI_COLOR_FORMAT_NV21 (HFI_COMMON_BASE + 0x3) +#define HFI_COLOR_FORMAT_NV12_4x4TILE (HFI_COMMON_BASE + 0x4) +#define HFI_COLOR_FORMAT_NV21_4x4TILE (HFI_COMMON_BASE + 0x5) +#define HFI_COLOR_FORMAT_YUYV (HFI_COMMON_BASE + 0x6) +#define HFI_COLOR_FORMAT_YVYU (HFI_COMMON_BASE + 0x7) +#define HFI_COLOR_FORMAT_UYVY (HFI_COMMON_BASE + 0x8) +#define HFI_COLOR_FORMAT_VYUY (HFI_COMMON_BASE + 0x9) +#define HFI_COLOR_FORMAT_RGB565 (HFI_COMMON_BASE + 0xA) +#define HFI_COLOR_FORMAT_BGR565 (HFI_COMMON_BASE + 0xB) +#define HFI_COLOR_FORMAT_RGB888 (HFI_COMMON_BASE + 0xC) +#define HFI_COLOR_FORMAT_BGR888 (HFI_COMMON_BASE + 0xD) +#define HFI_COLOR_FORMAT_YUV444 (HFI_COMMON_BASE + 0xE) +#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 + +#define HFI_STATISTICS_MODE_DEFAULT 0x10 +#define HFI_STATISTICS_MODE_1 0x11 +#define HFI_STATISTICS_MODE_2 0x12 +#define HFI_STATISTICS_MODE_3 0x13 + +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_codec_supported { + u32 decoder_codec_supported; + u32 encoder_codec_supported; +}; + +struct hfi_properties_supported { + u32 num_properties; + u32 rg_properties[1]; +}; + +struct hfi_max_sessions_supported { + u32 max_sessions; +}; + +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_venc_config_advanced { + u8 pipe2d; + u8 hw_mode; + u8 low_delay_enforce; + u8 worker_vppsg_delay; + u32 close_gop; + u32 h264_constrain_intra_pred; + u32 h264_transform_8x8_flag; + u32 multi_refp_en; + u32 qmatrix_en; + u8 vpp_info_packet_mode; + u8 ref_tile_mode; + u8 bitstream_flush_mode; + u32 vppsg_vspap_fb_sync_delay; + u32 rc_initial_delay; + u32 peak_bitrate_constraint; + u32 ds_display_frame_width; + u32 ds_display_frame_height; + u32 perf_tune_param_ptr; + u32 input_x_offset; + u32 input_y_offset; + u32 input_roi_width; + u32 input_roi_height; + u32 vsp_fifo_dma_sel; + u32 h264_num_ref_frames; +}; + +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_IFRAME_SIZE_DEFAULT (HFI_COMMON_BASE + 0x1) +#define HFI_IFRAME_SIZE_MEDIUM (HFI_COMMON_BASE + 0x2) +#define HFI_IFRAME_SIZE_HIGH (HFI_COMMON_BASE + 0x3) +#define HFI_IFRAME_SIZE_UNLIMITED (HFI_COMMON_BASE + 0x4) +struct hfi_iframe_size { + u32 type; +}; + + +#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 session_id; +}; + +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 session_id; + u32 session_domain; + u32 session_codec; +}; + +struct hfi_cmd_sys_session_end_packet { + u32 size; + u32 packet_type; + u32 session_id; +}; + +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_session_set_property_packet { + u32 size; + u32 packet_type; + u32 session_id; + u32 num_properties; + u32 rg_property_data[1]; +}; + +struct hfi_cmd_session_set_buffers_packet { + u32 size; + u32 packet_type; + u32 session_id; + 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 session_id; + 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 session_id; + 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 session_id; + u32 sync_id; + u32 rg_data[1]; +}; + +struct hfi_msg_event_notify_packet { + u32 size; + u32 packet_type; + u32 session_id; + 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 session_id; + 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 session_id; + u32 error_type; +}; + +struct hfi_msg_session_get_sequence_header_done_packet { + u32 size; + u32 packet_type; + u32 session_id; + u32 error_type; + u32 header_len; + u32 sequence_header; +}; + +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_mastering_display_colour_sei_payload { + u32 display_primariesX[3]; + u32 display_primariesY[3]; + u32 white_pointX; + u32 white_pointY; + u32 max_display_mastering_luminance; + u32 min_display_mastering_luminance; +}; + +struct hfi_content_light_level_sei_payload { + u32 max_content_light; + u32 max_pic_average_light; +}; + +struct hfi_hdr10_pq_sei { + struct hfi_mastering_display_colour_sei_payload mdisp_info; + struct hfi_content_light_level_sei_payload cll_info; +}; + +struct hfi_vbv_hdr_buf_size { + u32 vbv_hdr_buf_size; +}; + +#endif diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_io.h b/drivers/media/platform/msm/vidc/vidc_hfi_io.h new file mode 100644 index 000000000000..cbe30758103d --- /dev/null +++ b/drivers/media/platform/msm/vidc/vidc_hfi_io.h @@ -0,0 +1,196 @@ +/* Copyright (c) 2012-2020, 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 __VIDC_HFI_IO_H__ +#define __VIDC_HFI_IO_H__ + +#include + +#define VIDC_VBIF_BASE_OFFS 0x00080000 + +#define VIDC_CPU_BASE_OFFS 0x000C0000 +#define VIDEO_CC_BASE_OFFS 0x00100000 +#define VIDC_CPU_CS_BASE_OFFS (VIDC_CPU_BASE_OFFS + 0x00012000) +#define VIDC_CPU_IC_BASE_OFFS (VIDC_CPU_BASE_OFFS + 0x0001F000) + +#define VIDC_CPU_CS_REMAP_OFFS (VIDC_CPU_CS_BASE_OFFS + 0x00) +#define VIDC_CPU_CS_TIMER_CONTROL (VIDC_CPU_CS_BASE_OFFS + 0x04) +#define VIDC_CPU_CS_A2HSOFTINTEN (VIDC_CPU_CS_BASE_OFFS + 0x10) +#define VIDC_CPU_CS_A2HSOFTINTENCLR (VIDC_CPU_CS_BASE_OFFS + 0x14) +#define VIDC_CPU_CS_A2HSOFTINT (VIDC_CPU_CS_BASE_OFFS + 0x18) +#define VIDC_CPU_CS_A2HSOFTINTCLR (VIDC_CPU_CS_BASE_OFFS + 0x1C) +#define VIDC_CPU_CS_VMIMSG (VIDC_CPU_CS_BASE_OFFS + 0x34) +#define VIDC_CPU_CS_VMIMSGAG0 (VIDC_CPU_CS_BASE_OFFS + 0x38) +#define VIDC_CPU_CS_VMIMSGAG1 (VIDC_CPU_CS_BASE_OFFS + 0x3C) +#define VIDC_CPU_CS_VMIMSGAG2 (VIDC_CPU_CS_BASE_OFFS + 0x40) +#define VIDC_CPU_CS_VMIMSGAG3 (VIDC_CPU_CS_BASE_OFFS + 0x44) +#define VIDC_CPU_CS_SCIACMD (VIDC_CPU_CS_BASE_OFFS + 0x48) + +/* HFI_CTRL_STATUS */ +#define VIDC_CPU_CS_SCIACMDARG0 (VIDC_CPU_CS_BASE_OFFS + 0x4C) +#define VIDC_CPU_CS_SCIACMDARG0_BMSK 0xff +#define VIDC_CPU_CS_SCIACMDARG0_SHFT 0x0 +#define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_ERROR_STATUS_BMSK 0xfe +#define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_ERROR_STATUS_SHFT 0x1 +#define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_STATUS_BMSK 0x1 +#define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_STATUS_SHFT 0x0 +#define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_PC_READY 0x100 +#define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_IDLE_MSG_BMSK 0x40000000 + +/* HFI_QTBL_INFO */ +#define VIDC_CPU_CS_SCIACMDARG1 (VIDC_CPU_CS_BASE_OFFS + 0x50) + +/* HFI_QTBL_ADDR */ +#define VIDC_CPU_CS_SCIACMDARG2 (VIDC_CPU_CS_BASE_OFFS + 0x54) + +/* HFI_VERSION_INFO */ +#define VIDC_CPU_CS_SCIACMDARG3 (VIDC_CPU_CS_BASE_OFFS + 0x58) + +/* VIDC_SFR_ADDR */ +#define VIDC_CPU_CS_SCIBCMD (VIDC_CPU_CS_BASE_OFFS + 0x5C) + +/* VIDC_MMAP_ADDR */ +#define VIDC_CPU_CS_SCIBCMDARG0 (VIDC_CPU_CS_BASE_OFFS + 0x60) + +/* VIDC_UC_REGION_ADDR */ +#define VIDC_CPU_CS_SCIBARG1 (VIDC_CPU_CS_BASE_OFFS + 0x64) + +/* VIDC_UC_REGION_ADDR */ +#define VIDC_CPU_CS_SCIBARG2 (VIDC_CPU_CS_BASE_OFFS + 0x68) + +#define VIDC_CPU_CS_SCIBARG3 (VIDC_CPU_CS_BASE_OFFS + 0x6C) + +#define VIDC_CPU_IC_IRQSTATUS (VIDC_CPU_IC_BASE_OFFS + 0x00) +#define VIDC_CPU_IC_FIQSTATUS (VIDC_CPU_IC_BASE_OFFS + 0x04) +#define VIDC_CPU_IC_RAWINTR (VIDC_CPU_IC_BASE_OFFS + 0x08) +#define VIDC_CPU_IC_INTSELECT (VIDC_CPU_IC_BASE_OFFS + 0x0C) +#define VIDC_CPU_IC_INTENABLE (VIDC_CPU_IC_BASE_OFFS + 0x10) +#define VIDC_CPU_IC_INTENACLEAR (VIDC_CPU_IC_BASE_OFFS + 0x14) +#define VIDC_CPU_IC_SOFTINT (VIDC_CPU_IC_BASE_OFFS + 0x18) +#define VIDC_CPU_IC_SOFTINT_H2A_BMSK 0x8000 +#define VIDC_CPU_IC_SOFTINT_H2A_SHFT 0xF +#define VIDC_CPU_IC_SOFTINTCLEAR (VIDC_CPU_IC_BASE_OFFS + 0x1C) + +/* + * -------------------------------------------------------------------------- + * MODULE: vidc_wrapper + * -------------------------------------------------------------------------- + */ +#define VIDC_WRAPPER_BASE_OFFS 0x000E0000 + +#define VIDC_WRAPPER_HW_VERSION (VIDC_WRAPPER_BASE_OFFS + 0x00) +#define VIDC_WRAPPER_HW_VERSION_MAJOR_VERSION_MASK 0x78000000 +#define VIDC_WRAPPER_HW_VERSION_MAJOR_VERSION_SHIFT 28 +#define VIDC_WRAPPER_HW_VERSION_MINOR_VERSION_MASK 0xFFF0000 +#define VIDC_WRAPPER_HW_VERSION_MINOR_VERSION_SHIFT 16 +#define VIDC_WRAPPER_HW_VERSION_STEP_VERSION_MASK 0xFFFF +#define VIDC_WRAPPER_CLOCK_CONFIG (VIDC_WRAPPER_BASE_OFFS + 0x04) + +#define VIDC_WRAPPER_INTR_STATUS (VIDC_WRAPPER_BASE_OFFS + 0x0C) +#define VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK 0x10 +#define VIDC_WRAPPER_INTR_STATUS_A2HWD_SHFT 0x4 +#define VIDC_WRAPPER_INTR_STATUS_A2H_BMSK 0x4 +#define VIDC_WRAPPER_INTR_STATUS_A2H_SHFT 0x2 + +#define VIDC_WRAPPER_INTR_MASK (VIDC_WRAPPER_BASE_OFFS + 0x10) +#define VIDC_WRAPPER_INTR_MASK_A2HWD_BMSK 0x10 +#define VIDC_WRAPPER_INTR_MASK_A2HWD_SHFT 0x4 +#define VIDC_WRAPPER_INTR_MASK_A2HVCODEC_BMSK 0x8 +#define VIDC_WRAPPER_INTR_MASK_A2HCPU_BMSK 0x4 +#define VIDC_WRAPPER_INTR_MASK_A2HCPU_SHFT 0x2 + +#define VIDC_WRAPPER_INTR_CLEAR (VIDC_WRAPPER_BASE_OFFS + 0x14) +#define VIDC_WRAPPER_INTR_CLEAR_A2HWD_BMSK 0x10 +#define VIDC_WRAPPER_INTR_CLEAR_A2HWD_SHFT 0x4 +#define VIDC_WRAPPER_INTR_CLEAR_A2H_BMSK 0x4 +#define VIDC_WRAPPER_INTR_CLEAR_A2H_SHFT 0x2 + +#define VIDC_WRAPPER_CPU_CLOCK_CONFIG (VIDC_WRAPPER_BASE_OFFS + 0x2000) +#define VIDC_WRAPPER_CPU_CGC_DIS (VIDC_WRAPPER_BASE_OFFS + 0x2010) +#define VIDC_WRAPPER_CPU_STATUS (VIDC_WRAPPER_BASE_OFFS + 0x2014) +#define VIDC_VENUS_VBIF_CLK_ON (VIDC_VBIF_BASE_OFFS + 0x4) +#define VENUS_VBIF_AXI_HALT_CTRL0 (VIDC_VBIF_BASE_OFFS + 0x208) +#define VENUS_VBIF_AXI_HALT_CTRL1 (VIDC_VBIF_BASE_OFFS + 0x20C) + +#define VENUS_VBIF_AXI_HALT_CTRL0_HALT_REQ BIT(0) +#define VENUS_VBIF_AXI_HALT_CTRL1_HALT_ACK BIT(0) +#define VENUS_VBIF_AXI_HALT_ACK_TIMEOUT_US 500000 + + +#define VIDC_CTRL_INIT VIDC_CPU_CS_SCIACMD + +#define VIDC_CTRL_STATUS VIDC_CPU_CS_SCIACMDARG0 +#define VIDC_CTRL_ERROR_STATUS__M \ + VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_ERROR_STATUS_BMSK +#define VIDC_CTRL_INIT_IDLE_MSG_BMSK \ + VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_IDLE_MSG_BMSK +#define VIDC_CTRL_STATUS_PC_READY \ + VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_PC_READY + + +#define VIDC_QTBL_INFO VIDC_CPU_CS_SCIACMDARG1 + +#define VIDC_QTBL_ADDR VIDC_CPU_CS_SCIACMDARG2 + +#define VIDC_VERSION_INFO VIDC_CPU_CS_SCIACMDARG3 + +#define VIDC_SFR_ADDR VIDC_CPU_CS_SCIBCMD +#define VIDC_MMAP_ADDR VIDC_CPU_CS_SCIBCMDARG0 +#define VIDC_UC_REGION_ADDR VIDC_CPU_CS_SCIBARG1 +#define VIDC_UC_REGION_SIZE VIDC_CPU_CS_SCIBARG2 + +/* HFI_DSP_QTBL_ADDR + * 31:3 - HFI_DSP_QTBL_ADDR + * 4-byte aligned Address + */ +#define HFI_DSP_QTBL_ADDR VIDC_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 VIDC_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 VIDC_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/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index f39603798acb..b6e2fac1bb18 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -369,10 +369,16 @@ enum v4l2_mpeg_video_bitrate_mode { V4L2_MPEG_VIDEO_BITRATE_MODE_VBR = 0, V4L2_MPEG_VIDEO_BITRATE_MODE_CBR = 1, V4L2_MPEG_VIDEO_BITRATE_MODE_MBR = 2, + /* RC_OFF */ + V4L2_MPEG_VIDEO_BITRATE_MODE_RC_OFF = 3, /* VFR Modes */ - V4L2_MPEG_VIDEO_BITRATE_MODE_CBR_VFR = 3, - V4L2_MPEG_VIDEO_BITRATE_MODE_MBR_VFR = 4, - V4L2_MPEG_VIDEO_BITRATE_MODE_CQ = 5, +#define V4L2_MPEG_VIDEO_BITRATE_MODE_CBR_VFR \ + V4L2_MPEG_VIDEO_BITRATE_MODE_CBR_VFR + V4L2_MPEG_VIDEO_BITRATE_MODE_CBR_VFR = 4, +#define V4L2_MPEG_VIDEO_BITRATE_MODE_MBR_VFR \ + V4L2_MPEG_VIDEO_BITRATE_MODE_MBR_VFR + V4L2_MPEG_VIDEO_BITRATE_MODE_MBR_VFR = 5, + V4L2_MPEG_VIDEO_BITRATE_MODE_CQ = 6, }; #define V4L2_CID_MPEG_VIDEO_BITRATE (V4L2_CID_MPEG_BASE+207) #define V4L2_CID_MPEG_VIDEO_BITRATE_PEAK (V4L2_CID_MPEG_BASE+208) @@ -448,9 +454,13 @@ enum v4l2_mpeg_video_h264_level { V4L2_MPEG_VIDEO_H264_LEVEL_5_1 = 15, V4L2_MPEG_VIDEO_H264_LEVEL_5_2 = 16, V4L2_MPEG_VIDEO_H264_LEVEL_6_0 = 17, - V4L2_MPEG_VIDEO_H264_LEVEL_6_1 = 18, - V4L2_MPEG_VIDEO_H264_LEVEL_6_2 = 19, - V4L2_MPEG_VIDEO_H264_LEVEL_UNKNOWN = 20, + V4L2_MPEG_VIDEO_H264_LEVEL_UNKNOWN = 18, +#define V4L2_MPEG_VIDEO_H264_LEVEL_6_1 \ + V4L2_MPEG_VIDEO_H264_LEVEL_6_1 + V4L2_MPEG_VIDEO_H264_LEVEL_6_1 = 19, +#define V4L2_MPEG_VIDEO_H264_LEVEL_6_2 \ + V4L2_MPEG_VIDEO_H264_LEVEL_6_2 + V4L2_MPEG_VIDEO_H264_LEVEL_6_2 = 20, }; #define V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA (V4L2_CID_MPEG_BASE+360) #define V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA (V4L2_CID_MPEG_BASE+361) @@ -602,8 +612,9 @@ enum v4l2_vp8_golden_frame_sel { #define V4L2_CID_MPEG_VIDEO_VPX_MAX_QP (V4L2_CID_MPEG_BASE+508) #define V4L2_CID_MPEG_VIDEO_VPX_I_FRAME_QP (V4L2_CID_MPEG_BASE+509) #define V4L2_CID_MPEG_VIDEO_VPX_P_FRAME_QP (V4L2_CID_MPEG_BASE+510) +#define V4L2_CID_MPEG_VIDEO_VPX_PROFILE (V4L2_CID_MPEG_BASE+511) -#define V4L2_CID_MPEG_VIDEO_VP8_PROFILE (V4L2_CID_MPEG_BASE+511) +#define V4L2_CID_MPEG_VIDEO_VP8_PROFILE (V4L2_CID_MPEG_BASE+512) enum v4l2_mpeg_video_vp8_profile { V4L2_MPEG_VIDEO_VP8_PROFILE_0 = 0, V4L2_MPEG_VIDEO_VP8_PROFILE_1 = 1, @@ -611,8 +622,7 @@ enum v4l2_mpeg_video_vp8_profile { V4L2_MPEG_VIDEO_VP8_PROFILE_3 = 3, }; /* Deprecated alias for compatibility reasons. */ -#define V4L2_CID_MPEG_VIDEO_VPX_PROFILE V4L2_CID_MPEG_VIDEO_VP8_PROFILE -#define V4L2_CID_MPEG_VIDEO_VP9_PROFILE (V4L2_CID_MPEG_BASE+512) +#define V4L2_CID_MPEG_VIDEO_VP9_PROFILE (V4L2_CID_MPEG_BASE+513) enum v4l2_mpeg_video_vp9_profile { V4L2_MPEG_VIDEO_VP9_PROFILE_0 = 0, V4L2_MPEG_VIDEO_VP9_PROFILE_1 = 1, @@ -642,30 +652,8 @@ enum v4l2_mpeg_video_hevc_hier_coding_type { #define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_QP (V4L2_CID_MPEG_BASE + 613) #define V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_QP (V4L2_CID_MPEG_BASE + 614) #define V4L2_CID_MPEG_VIDEO_HEVC_PROFILE (V4L2_CID_MPEG_BASE + 615) -enum v4l2_mpeg_video_hevc_profile { - V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN = 0, - V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE = 1, - V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10 = 2, -}; #define V4L2_CID_MPEG_VIDEO_HEVC_LEVEL (V4L2_CID_MPEG_BASE + 616) -enum v4l2_mpeg_video_hevc_level { - V4L2_MPEG_VIDEO_HEVC_LEVEL_1 = 0, - V4L2_MPEG_VIDEO_HEVC_LEVEL_2 = 1, - V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1 = 2, - V4L2_MPEG_VIDEO_HEVC_LEVEL_3 = 3, - V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1 = 4, - V4L2_MPEG_VIDEO_HEVC_LEVEL_4 = 5, - V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1 = 6, - V4L2_MPEG_VIDEO_HEVC_LEVEL_5 = 7, - V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1 = 8, - V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2 = 9, - V4L2_MPEG_VIDEO_HEVC_LEVEL_6 = 10, - V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1 = 11, - V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2 = 12, - V4L2_MPEG_VIDEO_HEVC_LEVEL_UNKNOWN = 13, -}; - #define V4L2_CID_MPEG_VIDEO_HEVC_FRAME_RATE_RESOLUTION (V4L2_CID_MPEG_BASE + 617) #define V4L2_CID_MPEG_VIDEO_HEVC_TIER (V4L2_CID_MPEG_BASE + 618) enum v4l2_mpeg_video_hevc_tier { @@ -814,7 +802,14 @@ enum v4l2_mpeg_vidc_video_stream_format { V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_FOUR_BYTE_LENGTH = 4, }; -#define V4L2_CID_MPEG_VIDC_VIDEO_DECODE_ORDER (V4L2_CID_MPEG_MSM_VIDC_BASE+3) +#define V4L2_CID_MPEG_VIDC_VIDEO_OUTPUT_ORDER (V4L2_CID_MPEG_MSM_VIDC_BASE+3) +enum v4l2_mpeg_vidc_video_output_order { + V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DISPLAY = 0, + V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DECODE = 1, +}; + +#define V4L2_CID_MPEG_VIDC_VIDEO_FRAME_RATE (V4L2_CID_MPEG_MSM_VIDC_BASE+4) +#define V4L2_CID_MPEG_VIDC_VIDEO_IDR_PERIOD (V4L2_CID_MPEG_MSM_VIDC_BASE+5) #define V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES (V4L2_CID_MPEG_MSM_VIDC_BASE+6) #define V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES (V4L2_CID_MPEG_MSM_VIDC_BASE+7) #define V4L2_CID_MPEG_VIDC_VIDEO_REQUEST_IFRAME (V4L2_CID_MPEG_MSM_VIDC_BASE+8) @@ -875,20 +870,10 @@ enum v4l2_mpeg_vidc_video_sync_frame_decode { #define V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA \ (V4L2_CID_MPEG_MSM_VIDC_BASE + 17) enum v4l2_mpeg_vidc_extradata { -#define EXTRADATA_NONE \ - EXTRADATA_NONE - EXTRADATA_NONE = 0, - EXTRADATA_DEFAULT = 1, - EXTRADATA_ADVANCED = 2, - EXTRADATA_ENC_INPUT_ROI = 4, - EXTRADATA_ENC_INPUT_HDR10PLUS = 8, - EXTRADATA_ENC_INPUT_CVP = 16, -}; -enum v4l2_mpeg_vidc3x_extradata { - V4L2_MPEG_VIDC_EXTRADATA_NONE = 0, + V4L2_MPEG_VIDC_EXTRADATA_NONE = 0, V4L2_MPEG_VIDC_EXTRADATA_MB_QUANTIZATION = 1, V4L2_MPEG_VIDC_EXTRADATA_INTERLACE_VIDEO = 2, - #define V4L2_MPEG_VIDC_EXTRADATA_ENC_DTS \ +#define V4L2_MPEG_VIDC_EXTRADATA_ENC_DTS \ V4L2_MPEG_VIDC_EXTRADATA_ENC_DTS V4L2_MPEG_VIDC_EXTRADATA_ENC_DTS = 3, V4L2_MPEG_VIDC_EXTRADATA_VC1_FRAMEDISP = 4, @@ -998,6 +983,13 @@ enum v4l2_mpeg_vidc_video_preserve_text_quality { V4L2_MPEG_VIDC_VIDEO_PRESERVE_TEXT_QUALITY_ENABLED = 1 }; +#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, +}; + #define V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_LEVEL (V4L2_CID_MPEG_MSM_VIDC_BASE+23) enum v4l2_mpeg_vidc_video_mpeg2_level { V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_0 = 0, @@ -1083,7 +1075,7 @@ enum vl42_mpeg_vidc_video_vpx_error_resilience { #define V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE \ (V4L2_CID_MPEG_MSM_VIDC_BASE + 40) -enum v4l2_cid_mpeg_video_hevc_profile { +enum v4l2_mpeg_video_hevc_profile { V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN = 0, V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN10 = 1, V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN_STILL_PIC = 2, @@ -1091,7 +1083,7 @@ enum v4l2_cid_mpeg_video_hevc_profile { #define V4L2_CID_MPEG_VIDC_VIDEO_HEVC_TIER_LEVEL \ (V4L2_CID_MPEG_MSM_VIDC_BASE + 41) -enum v4l2_cid_mpeg_video_hevc_level { +enum v4l2_mpeg_video_hevc_level { V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_1 = 0, V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_1 = 1, V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_2 = 2, @@ -1203,14 +1195,18 @@ enum v4l2_mpeg_vidc_video_lowlatency_mode { V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_ENABLE = 1, }; -#define V4L2_CID_MPEG_VIDC_VIDEO_BLUR_DIMENSIONS \ +#define V4L2_CID_MPEG_VIDC_VIDEO_BLUR_WIDTH \ (V4L2_CID_MPEG_MSM_VIDC_BASE + 57) -#define V4L2_CID_MPEG_VIDC_VIDEO_BLUR_WIDTH \ +#define V4L2_CID_MPEG_VIDC_VIDEO_BLUR_HEIGHT \ (V4L2_CID_MPEG_MSM_VIDC_BASE + 58) -#define V4L2_CID_MPEG_VIDC_VIDEO_BLUR_HEIGHT \ - (V4L2_CID_MPEG_MSM_VIDC_BASE + 59) +#define V4L2_CID_MPEG_VIDC_VIDEO_H264_TRANSFORM_8x8 \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 59) +enum v4l2_mpeg_vidc_video_h264_transform_8x8 { + V4L2_MPEG_VIDC_VIDEO_H264_TRANSFORM_8x8_DISABLE = 0, + V4L2_MPEG_VIDC_VIDEO_H264_TRANSFORM_8x8_ENABLE = 1, +}; #define V4L2_CID_MPEG_VIDC_VIDEO_COLOR_SPACE \ (V4L2_CID_MPEG_MSM_VIDC_BASE + 60) @@ -1257,7 +1253,11 @@ enum v4l2_mpeg_vidc_video_vp9_level { V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_41 = 8, V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_5 = 9, V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_51 = 10, +#define V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_6 \ + V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_6 V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_6 = 11, +#define V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_61 \ + V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_61 V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_61 = 12, }; @@ -1295,23 +1295,6 @@ enum v4l2_mpeg_vidc_video_h263_profile { V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHLATENCY = 8, }; -#define V4L2_CID_MPEG_VIDC_VIDEO_OUTPUT_ORDER \ - (V4L2_CID_MPEG_MSM_VIDC_BASE+75) -enum v4l2_mpeg_vidc_video_output_order { - V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DISPLAY = 0, - V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DECODE = 1, -}; - -#define V4L2_CID_MPEG_VIDC_VIDEO_H264_TRANSFORM_8x8 \ - (V4L2_CID_MPEG_MSM_VIDC_BASE + 76) -enum v4l2_mpeg_vidc_video_h264_transform_8x8 { - V4L2_MPEG_VIDC_VIDEO_H264_TRANSFORM_8x8_DISABLE = 0, - V4L2_MPEG_VIDC_VIDEO_H264_TRANSFORM_8x8_ENABLE = 1, -}; - -#define V4L2_CID_MPEG_VIDC_VIDEO_QP_MASK \ - (V4L2_CID_MPEG_MSM_VIDC_BASE + 77) - #define V4L2_CID_MPEG_VIDEO_MIN_QP_PACKED \ (V4L2_CID_MPEG_MSM_VIDC_BASE + 96) #define V4L2_CID_MPEG_VIDEO_MAX_QP_PACKED \ @@ -1336,8 +1319,7 @@ enum v4l2_mpeg_vidc_video_h264_transform_8x8 { (V4L2_CID_MPEG_MSM_VIDC_BASE + 106) #define V4L2_CID_MPEG_VIDC_VIDEO_B_FRAME_QP_MAX \ (V4L2_CID_MPEG_MSM_VIDC_BASE + 107) - -#define V4L2_CID_MPEG_VIDC_VIDEO_DYN_QP \ +#define V4L2_CID_MPEG_VIDC_VIDEO_QP_MASK \ (V4L2_CID_MPEG_MSM_VIDC_BASE + 108) enum v4l2_mpeg_vidc_video_venc_iframesize_type { @@ -1389,50 +1371,38 @@ enum v4l2_mpeg_vidc_video_flip { #define V4L2_CID_MPEG_VIDC_VENC_HDR_INFO \ (V4L2_CID_MPEG_MSM_VIDC_BASE + 116) - -#define V4L2_CID_MPEG_VIDC_IMG_GRID_SIZE \ +#define V4L2_CID_MPEG_VIDC_VENC_RGB_PRIMARY_00 \ (V4L2_CID_MPEG_MSM_VIDC_BASE + 117) - -#define V4L2_CID_MPEG_VIDC_COMPRESSION_QUALITY \ +#define V4L2_CID_MPEG_VIDC_VENC_RGB_PRIMARY_01 \ (V4L2_CID_MPEG_MSM_VIDC_BASE + 118) - -#define V4L2_CID_MPEG_VIDC_VIDEO_FRAME_RATE \ +#define V4L2_CID_MPEG_VIDC_VENC_RGB_PRIMARY_10 \ (V4L2_CID_MPEG_MSM_VIDC_BASE + 119) - -#define V4L2_CID_MPEG_VIDC_VENC_BITRATE_SAVINGS \ - (V4L2_CID_MPEG_MSM_VIDC_BASE + 131) - -#define V4L2_CID_MPEG_VIDC_VIDEO_HEVC_MAX_HIER_CODING_LAYER \ +#define V4L2_CID_MPEG_VIDC_VENC_RGB_PRIMARY_11 \ (V4L2_CID_MPEG_MSM_VIDC_BASE + 120) -enum v4l2_mpeg_vidc_video_hevc_max_hier_coding_layer { - V4L2_MPEG_VIDC_VIDEO_HEVC_MAX_HIER_CODING_LAYER_0 = 0, - V4L2_MPEG_VIDC_VIDEO_HEVC_MAX_HIER_CODING_LAYER_1 = 1, - V4L2_MPEG_VIDC_VIDEO_HEVC_MAX_HIER_CODING_LAYER_2 = 2, - V4L2_MPEG_VIDC_VIDEO_HEVC_MAX_HIER_CODING_LAYER_3 = 3, - V4L2_MPEG_VIDC_VIDEO_HEVC_MAX_HIER_CODING_LAYER_4 = 4, - V4L2_MPEG_VIDC_VIDEO_HEVC_MAX_HIER_CODING_LAYER_5 = 5, - V4L2_MPEG_VIDC_VIDEO_HEVC_MAX_HIER_CODING_LAYER_6 = 6, -}; - -#define V4L2_CID_MPEG_VIDC_VENC_CVP_DISABLE \ +#define V4L2_CID_MPEG_VIDC_VENC_RGB_PRIMARY_20 \ (V4L2_CID_MPEG_MSM_VIDC_BASE + 121) -#define V4L2_CID_MPEG_VIDC_VENC_NATIVE_RECORDER \ +#define V4L2_CID_MPEG_VIDC_VENC_RGB_PRIMARY_21 \ (V4L2_CID_MPEG_MSM_VIDC_BASE + 122) - -#define V4L2_CID_MPEG_VIDC_VENC_RC_TIMESTAMP_DISABLE \ +#define V4L2_CID_MPEG_VIDC_VENC_WHITEPOINT_X \ (V4L2_CID_MPEG_MSM_VIDC_BASE + 123) - -#define V4L2_CID_MPEG_VIDC_SUPERFRAME \ +#define V4L2_CID_MPEG_VIDC_VENC_WHITEPOINT_Y \ (V4L2_CID_MPEG_MSM_VIDC_BASE + 124) - -#define V4L2_CID_MPEG_VIDC_CAPTURE_FRAME_RATE \ +#define V4L2_CID_MPEG_VIDC_VENC_MAX_DISP_LUM \ (V4L2_CID_MPEG_MSM_VIDC_BASE + 125) - -#define V4L2_CID_MPEG_VIDC_CVP_FRAME_RATE \ +#define V4L2_CID_MPEG_VIDC_VENC_MIN_DISP_LUM \ (V4L2_CID_MPEG_MSM_VIDC_BASE + 126) - -#define V4L2_CID_MPEG_VIDC_VIDEO_ROI_TYPE \ +#define V4L2_CID_MPEG_VIDC_VENC_MAX_CLL \ (V4L2_CID_MPEG_MSM_VIDC_BASE + 127) +#define V4L2_CID_MPEG_VIDC_VENC_MAX_FLL \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 128) +#define V4L2_CID_MPEG_VIDC_VIDEO_FRAME_QUALITY \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 129) +#define V4L2_CID_MPEG_VIDC_IMG_GRID_ENABLE \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 130) +#define V4L2_CID_MPEG_VIDC_VENC_BITRATE_SAVINGS \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 131) +#define V4L2_CID_MPEG_VIDC_VIDEO_ROI_TYPE \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 132) enum v4l2_mpeg_vidc_video_roi_type { V4L2_CID_MPEG_VIDC_VIDEO_ROI_TYPE_NONE = 0, V4L2_CID_MPEG_VIDC_VIDEO_ROI_TYPE_2BIT = 1, @@ -1440,16 +1410,13 @@ enum v4l2_mpeg_vidc_video_roi_type { }; #define V4L2_CID_MPEG_VIDC_SET_PERF_LEVEL \ - (V4L2_CID_MPEG_MSM_VIDC_BASE + 128) + (V4L2_CID_MPEG_MSM_VIDC_BASE + 133) enum v4l2_mpeg_vidc_perf_level { V4L2_CID_MPEG_VIDC_PERF_LEVEL_NOMINAL = 0, V4L2_CID_MPEG_VIDC_PERF_LEVEL_PERFORMANCE = 1, V4L2_CID_MPEG_VIDC_PERF_LEVEL_TURBO = 2, }; -#define V4L2_CID_MPEG_VIDC_VIDEO_LOWLATENCY_HINT \ - (V4L2_CID_MPEG_MSM_VIDC_BASE + 133) - #define V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS (V4L2_CID_MPEG_MSM_VIDC_BASE + 134) #define V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF (V4L2_CID_MPEG_MSM_VIDC_BASE + 135) #define V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS (V4L2_CID_MPEG_MSM_VIDC_BASE + 136) @@ -1471,7 +1438,7 @@ enum v4l2_mpeg_vidc_video_h264_vui_bitstream_restrict { (V4L2_CID_MPEG_MSM_VIDC_BASE + 140) enum v4l2_mpeg_vidc_video_deinterlace { V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE_DISABLED = 0, - V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE_ENABLED + V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE_ENABLED = 1 }; #define V4L2_CID_MPEG_VIDC_VIDEO_MPEG4_TIME_RESOLUTION \ @@ -1582,9 +1549,6 @@ enum v4l2_mpeg_vidc_video_intra_refresh_mode { #define V4L2_CID_MPEG_VIDC_VIDEO_IR_MBS (V4L2_CID_MPEG_MSM_VIDC_BASE+166) -#define V4L2_CID_MPEG_VIDC_ENABLE_ONLY_BASE_LAYER_IR \ - (V4L2_CID_MPEG_MSM_VIDC_BASE + 167) - enum v4l2_mpeg_vidc_video_mbi_statistics_mode { V4L2_CID_MPEG_VIDC_VIDEO_MBI_MODE_DEFAULT = 0, V4L2_CID_MPEG_VIDC_VIDEO_MBI_MODE_1 = 1, @@ -1601,7 +1565,8 @@ enum v4l2_mpeg_vidc_video_h264_vui_timing_info { V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_DISABLED = 0, V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_ENABLED = 1 }; - +#define V4L2_CID_MPEG_VIDC_VENC_COMPLEXITY \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 167) /* Camera class control IDs */ #define V4L2_CID_CAMERA_CLASS_BASE (V4L2_CTRL_CLASS_CAMERA | 0x900) diff --git a/include/uapi/media/msm_media_info.h b/include/uapi/media/msm_media_info.h index 734fee1b75f4..5c309676a9ef 100644 --- a/include/uapi/media/msm_media_info.h +++ b/include/uapi/media/msm_media_info.h @@ -816,6 +816,18 @@ enum color_fmts { COLOR_FMT_NV12_512, }; +static inline unsigned int VENUS_EXTRADATA_SIZE(int width, int height) +{ + (void)height; + (void)width; + + /* + * In the future, calculate the size based on the w/h but just + * hardcode it for now since 16K satisfies all current usecases. + */ + return 16 * 1024; +} + /* * Function arguments: * @color_fmt diff --git a/include/uapi/media/msm_vidc_utils.h b/include/uapi/media/msm_vidc_utils.h index c121c36c1692..67e1289a9cbb 100644 --- a/include/uapi/media/msm_vidc_utils.h +++ b/include/uapi/media/msm_vidc_utils.h @@ -4,211 +4,291 @@ #include -#define MSM_VIDC_EXTRADATA_NONE 0x00000000 +#define MSM_VIDC_HAL_INTERLACE_COLOR_FORMAT_NV12 0x2 +#define MSM_VIDC_HAL_INTERLACE_COLOR_FORMAT_NV12_UBWC 0x8002 +#define MSM_VIDC_EXTRADATA_FRAME_QP_ADV 0x1 + struct msm_vidc_extradata_header { - __u32 size; - __u32 version; /** Keeping binary compatibility */ - __u32 port_index; /* with firmware and OpenMAX IL **/ - __u32 type; /* msm_vidc_extradata_type */ - __u32 data_size; - __u32 data[1]; + unsigned int size; + unsigned int:32; /** Keeping binary compatibility */ + unsigned int:32; /* with firmware and OpenMAX IL **/ + unsigned int type; /* msm_vidc_extradata_type */ + unsigned int data_size; + unsigned char data[1]; }; -/* msm_vidc_interlace_type */ -#define MSM_VIDC_INTERLACE_FRAME_PROGRESSIVE 0x01 -#define MSM_VIDC_INTERLACE_INTERLEAVE_FRAME_TOPFIELDFIRST 0x02 -#define MSM_VIDC_INTERLACE_INTERLEAVE_FRAME_BOTTOMFIELDFIRST 0x04 -#define MSM_VIDC_INTERLACE_FRAME_TOPFIELDFIRST 0x08 -#define MSM_VIDC_INTERLACE_FRAME_BOTTOMFIELDFIRST 0x10 -#define MSM_VIDC_INTERLACE_FRAME_MBAFF 0x20 -/* Color formats */ -#define MSM_VIDC_HAL_INTERLACE_COLOR_FORMAT_NV12 0x2 -#define MSM_VIDC_HAL_INTERLACE_COLOR_FORMAT_NV12_UBWC 0x8002 -#define MSM_VIDC_EXTRADATA_INTERLACE_VIDEO 0x00000002 struct msm_vidc_interlace_payload { - __u32 format; /* Interlace format */ - __u32 color_format; + unsigned int format; + unsigned int color_format; }; -#define MSM_VIDC_EXTRADATA_FRAME_RATE 0x00000007 struct msm_vidc_framerate_payload { - __u32 frame_rate; /*In Q16 format */ + unsigned int frame_rate; }; -#define MSM_VIDC_EXTRADATA_TIMESTAMP 0x00000005 struct msm_vidc_ts_payload { - __u32 timestamp_lo; - __u32 timestamp_hi; + unsigned int timestamp_lo; + unsigned int timestamp_hi; }; -#define MSM_VIDC_EXTRADATA_NUM_CONCEALED_MB 0x7F100001 struct msm_vidc_concealmb_payload { - __u32 num_mbs; + unsigned int num_mbs; }; - -#define MSM_VIDC_FRAME_RECONSTRUCTION_INCORRECT 0x0 -#define MSM_VIDC_FRAME_RECONSTRUCTION_CORRECT 0x01 -#define MSM_VIDC_FRAME_RECONSTRUCTION_APPROXIMATELY_CORRECT 0x02 -#define MSM_VIDC_EXTRADATA_RECOVERY_POINT_SEI 0x00000009 struct msm_vidc_recoverysei_payload { - __u32 flags; + unsigned int flags; }; -#define MSM_VIDC_EXTRADATA_ASPECT_RATIO 0x7F100003 struct msm_vidc_aspect_ratio_payload { - __u32 size; - __u32 version; - __u32 port_index; - __u32 aspect_width; - __u32 aspect_height; + unsigned int size; + unsigned int version; + unsigned int port_index; + unsigned int aspect_width; + unsigned int aspect_height; +}; + +struct msm_vidc_mpeg2_seqdisp_payload { + unsigned int video_format; + unsigned int color_descp; + unsigned int color_primaries; + unsigned int transfer_char; + unsigned int matrix_coeffs; + unsigned int disp_width; + unsigned int disp_height; +}; + +struct msm_vidc_input_crop_payload { + unsigned int size; + unsigned int version; + unsigned int port_index; + unsigned int left; + unsigned int top; + unsigned int width; + unsigned int height; }; struct msm_vidc_misr_info { - __u32 misr_set; - __u32 misr_dpb_luma[8]; - __u32 misr_dpb_chroma[8]; - __u32 misr_opb_luma[8]; - __u32 misr_opb_chroma[8]; + unsigned int misr_set; + unsigned int misr_dpb_luma[8]; + unsigned int misr_dpb_chroma[8]; + unsigned int misr_opb_luma[8]; + unsigned int misr_opb_chroma[8]; }; -#define MSM_VIDC_EXTRADATA_OUTPUT_CROP 0x0700000F struct msm_vidc_output_crop_payload { - __u32 size; - __u32 version; - __u32 port_index; - __u32 left; - __u32 top; - __u32 display_width; - __u32 display_height; - __u32 width; - __u32 height; - __u32 frame_num; - __u32 bit_depth_y; - __u32 bit_depth_c; + unsigned int size; + unsigned int version; + unsigned int port_index; + unsigned int left; + unsigned int top; + unsigned int display_width; + unsigned int display_height; + unsigned int width; + unsigned int height; + unsigned int frame_num; + unsigned int bit_depth_y; + unsigned int bit_depth_c; struct msm_vidc_misr_info misr_info[2]; }; -#define MSM_VIDC_EXTRADATA_INDEX 0x7F100002 struct msm_vidc_extradata_index { - __u32 type; + unsigned int type; union { + struct msm_vidc_input_crop_payload input_crop; struct msm_vidc_aspect_ratio_payload aspect_ratio; }; }; -#define MSM_VIDC_EXTRADATA_PANSCAN_WINDOW 0x00000008 struct msm_vidc_panscan_window { - __u32 panscan_height_offset; - __u32 panscan_width_offset; - __u32 panscan_window_width; - __u32 panscan_window_height; + unsigned int panscan_height_offset; + unsigned int panscan_width_offset; + unsigned int panscan_window_width; + unsigned int panscan_window_height; }; + struct msm_vidc_panscan_window_payload { - __u32 num_panscan_windows; + unsigned int num_panscan_windows; struct msm_vidc_panscan_window wnd[1]; }; - -#define MSM_VIDC_USERDATA_TYPE_FRAME 0x1 -#define MSM_VIDC_USERDATA_TYPE_TOP_FIELD 0x2 -#define MSM_VIDC_USERDATA_TYPE_BOTTOM_FIELD 0x3 -#define MSM_VIDC_EXTRADATA_STREAM_USERDATA 0x0000000E struct msm_vidc_stream_userdata_payload { - __u32 type; - __u32 data[1]; + unsigned int type; + unsigned int data[1]; }; -#define MSM_VIDC_EXTRADATA_FRAME_QP 0x0000000F struct msm_vidc_frame_qp_payload { - __u32 frame_qp; - __u32 qp_sum; - __u32 skip_qp_sum; - __u32 skip_num_blocks; - __u32 total_num_blocks; + unsigned int frame_qp; + unsigned int qp_sum; + unsigned int skip_qp_sum; + unsigned int skip_num_blocks; + unsigned int total_num_blocks; +}; + +struct msm_vidc_dts_payload { + unsigned int timestamp_hi; + unsigned int timestamp_lo; }; -#define MSM_VIDC_EXTRADATA_FRAME_BITS_INFO 0x00000010 struct msm_vidc_frame_bits_info_payload { - __u32 frame_bits; - __u32 header_bits; + unsigned int frame_bits; + unsigned int header_bits; }; -#define MSM_VIDC_EXTRADATA_S3D_FRAME_PACKING 0x00000006 struct msm_vidc_s3d_frame_packing_payload { - __u32 fpa_id; - __u32 cancel_flag; - __u32 fpa_type; - __u32 quin_cunx_flag; - __u32 content_interprtation_type; - __u32 spatial_flipping_flag; - __u32 frame0_flipped_flag; - __u32 field_views_flag; - __u32 current_frame_is_frame0_flag; - __u32 frame0_self_contained_flag; - __u32 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; - __u32 fpa_extension_flag; + unsigned int fpa_id; + unsigned int cancel_flag; + unsigned int fpa_type; + unsigned int quin_cunx_flag; + unsigned int content_interprtation_type; + unsigned int spatial_flipping_flag; + unsigned int frame0_flipped_flag; + unsigned int field_views_flag; + unsigned int current_frame_is_frame0_flag; + unsigned int frame0_self_contained_flag; + unsigned int frame1_self_contained_flag; + unsigned int frame0_graid_pos_x; + unsigned int frame0_graid_pos_y; + unsigned int frame1_graid_pos_x; + unsigned int frame1_graid_pos_y; + unsigned int fpa_reserved_byte; + unsigned int fpa_repetition_period; + unsigned int fpa_extension_flag; +}; + +struct msm_vidc_ubwc_cr_stats_info { + unsigned int stats_tile_32; + unsigned int stats_tile_64; + unsigned int stats_tile_96; + unsigned int stats_tile_128; + unsigned int stats_tile_160; + unsigned int stats_tile_192; + unsigned int stats_tile_256; +}; + +struct msm_vidc_yuv_stats_payload { + unsigned int frame_qp; + unsigned int texture; + unsigned int luma_in_q16; + unsigned int frame_difference; +}; + +struct msm_vidc_vpx_colorspace_payload { + unsigned int color_space; + unsigned int yuv_range_flag; + unsigned int sumsampling_x; + unsigned int sumsampling_y; }; struct msm_vidc_roi_qp_payload { - __s32 upper_qp_offset; - __s32 lower_qp_offset; - __u32 b_roi_info; - __u32 mbi_info_size; - __u32 data[1]; + int upper_qp_offset; + int lower_qp_offset; + unsigned int b_roi_info; + int mbi_info_size; + unsigned int data[1]; }; -#define MSM_VIDC_EXTRADATA_ROI_QP 0x00000013 +#define MSM_VIDC_EXTRADATA_ROI_DELTAQP 0x1 struct msm_vidc_roi_deltaqp_payload { - __u32 b_roi_info; /*Enable/Disable*/ - __u32 mbi_info_size; /*Size of QP data*/ - __u32 data[1]; + unsigned int b_roi_info; /*Enable/Disable*/ + int mbi_info_size; /*Size of QP data*/ + unsigned int data[1]; +}; + +struct msm_vidc_hdr10plus_metadata_payload { + unsigned int size; + unsigned int data[1]; }; -#define MSM_VIDC_EXTRADATA_MASTERING_DISPLAY_COLOUR_SEI 0x00000015 struct msm_vidc_mastering_display_colour_sei_payload { - __u32 nDisplayPrimariesX[3]; - __u32 nDisplayPrimariesY[3]; - __u32 nWhitePointX; - __u32 nWhitePointY; - __u32 nMaxDisplayMasteringLuminance; - __u32 nMinDisplayMasteringLuminance; + unsigned int nDisplayPrimariesX[3]; + unsigned int nDisplayPrimariesY[3]; + unsigned int nWhitePointX; + unsigned int nWhitePointY; + unsigned int nMaxDisplayMasteringLuminance; + unsigned int nMinDisplayMasteringLuminance; }; -#define MSM_VIDC_EXTRADATA_CONTENT_LIGHT_LEVEL_SEI 0x00000016 struct msm_vidc_content_light_level_sei_payload { - __u32 nMaxContentLight; - __u32 nMaxPicAverageLight; + unsigned int nMaxContentLight; + unsigned int nMaxPicAverageLight; }; -#define MSM_VIDC_EXTRADATA_HDR10PLUS_METADATA 0x0000001A -struct msm_vidc_hdr10plus_metadata_payload { - __u32 size; - __u32 data[1]; +struct msm_vidc_vui_display_info_payload { + unsigned int video_signal_present_flag; + unsigned int video_format; + unsigned int bit_depth_y; + unsigned int bit_depth_c; + unsigned int video_full_range_flag; + unsigned int color_description_present_flag; + unsigned int color_primaries; + unsigned int transfer_characteristics; + unsigned int matrix_coefficients; + unsigned int chroma_location_info_present_flag; + unsigned int chroma_format_idc; + unsigned int separate_color_plane_flag; + unsigned int chroma_sample_loc_type_top_field; + unsigned int chroma_sample_loc_type_bottom_field; }; -#define MSM_VIDC_EXTRADATA_CVP_METADATA 0x0000001B -struct msm_vidc_enc_cvp_metadata_payload { - __u32 data[256]; -}; +/* msm_vidc_extradata_type */ +#define MSM_VIDC_EXTRADATA_NONE 0x00000000 +#define MSM_VIDC_EXTRADATA_MB_QUANTIZATION 0x00000001 +#define MSM_VIDC_EXTRADATA_INTERLACE_VIDEO 0x00000002 +#define MSM_VIDC_EXTRADATA_TIMESTAMP 0x00000005 +#define MSM_VIDC_EXTRADATA_S3D_FRAME_PACKING 0x00000006 +#define MSM_VIDC_EXTRADATA_FRAME_RATE 0x00000007 +#define MSM_VIDC_EXTRADATA_PANSCAN_WINDOW 0x00000008 +#define MSM_VIDC_EXTRADATA_RECOVERY_POINT_SEI 0x00000009 +#define MSM_VIDC_EXTRADATA_MPEG2_SEQDISP 0x0000000D +#define MSM_VIDC_EXTRADATA_STREAM_USERDATA 0x0000000E +#define MSM_VIDC_EXTRADATA_FRAME_QP 0x0000000F +#define MSM_VIDC_EXTRADATA_FRAME_BITS_INFO 0x00000010 +#define MSM_VIDC_EXTRADATA_ROI_QP 0x00000013 +#define MSM_VIDC_EXTRADATA_VPX_COLORSPACE_INFO 0x00000014 +#define MSM_VIDC_EXTRADATA_MASTERING_DISPLAY_COLOUR_SEI 0x00000015 +#define MSM_VIDC_EXTRADATA_CONTENT_LIGHT_LEVEL_SEI 0x00000016 +#define MSM_VIDC_EXTRADATA_PQ_INFO 0x00000017 +#define MSM_VIDC_EXTRADATA_COLOUR_REMAPPING_INFO_SEI 0x00000018 +#define MSM_VIDC_EXTRADATA_UBWC_CR_STAT_INFO 0x00000019 +#define MSM_VIDC_EXTRADATA_HDR10PLUS_METADATA 0x0000001A +#define MSM_VIDC_EXTRADATA_INPUT_CROP 0x0700000E +#define MSM_VIDC_EXTRADATA_OUTPUT_CROP 0x0700000F +#define MSM_VIDC_EXTRADATA_MULTISLICE_INFO 0x7F100000 +#define MSM_VIDC_EXTRADATA_NUM_CONCEALED_MB 0x7F100001 +#define MSM_VIDC_EXTRADATA_INDEX 0x7F100002 +#define MSM_VIDC_EXTRADATA_ASPECT_RATIO 0x7F100003 +#define MSM_VIDC_EXTRADATA_METADATA_LTR 0x7F100004 +#define MSM_VIDC_EXTRADATA_METADATA_MBI 0x7F100005 +#define MSM_VIDC_EXTRADATA_VUI_DISPLAY_INFO 0x7F100006 +#define MSM_VIDC_EXTRADATA_ENC_DTS_INFO 0x7F100008 -/* video_format */ -#define MSM_VIDC_COMPONENT 0 -#define MSM_VIDC_PAL 1 -#define MSM_VIDC_NTSC 2 -#define MSM_VIDC_SECAM 3 -#define MSM_VIDC_MAC 4 -#define MSM_VIDC_UNSPECIFIED_FORMAT 5 -#define MSM_VIDC_RESERVED_1_FORMAT 6 -#define MSM_VIDC_RESERVED_2_FORMAT 7 +/* msm_vidc_interlace_type */ +#define MSM_VIDC_INTERLACE_FRAME_PROGRESSIVE 0x01 +#define MSM_VIDC_INTERLACE_INTERLEAVE_FRAME_TOPFIELDFIRST 0x02 +#define MSM_VIDC_INTERLACE_INTERLEAVE_FRAME_BOTTOMFIELDFIRST 0x04 +#define MSM_VIDC_INTERLACE_FRAME_TOPFIELDFIRST 0x08 +#define MSM_VIDC_INTERLACE_FRAME_BOTTOMFIELDFIRST 0x10 +#define MSM_VIDC_INTERLACE_FRAME_MBAFF 0x20 + +/* msm_vidc_framepack_type */ +#define MSM_VIDC_FRAMEPACK_CHECKERBOARD 0x00 +#define MSM_VIDC_FRAMEPACK_COLUMN_INTERLEAVE 0x01 +#define MSM_VIDC_FRAMEPACK_ROW_INTERLEAVE 0x02 +#define MSM_VIDC_FRAMEPACK_SIDE_BY_SIDE 0x03 +#define MSM_VIDC_FRAMEPACK_TOP_BOTTOM 0x04 +#define MSM_VIDC_FRAMEPACK_TEMPORAL_INTERLEAVE 0x05 + +/* msm_vidc_recovery_sei */ +#define MSM_VIDC_FRAME_RECONSTRUCTION_INCORRECT 0x0 +#define MSM_VIDC_FRAME_RECONSTRUCTION_CORRECT 0x01 +#define MSM_VIDC_FRAME_RECONSTRUCTION_APPROXIMATELY_CORRECT 0x02 + +/* msm_vidc_userdata_type */ +#define MSM_VIDC_USERDATA_TYPE_FRAME 0x1 +#define MSM_VIDC_USERDATA_TYPE_TOP_FIELD 0x2 +#define MSM_VIDC_USERDATA_TYPE_BOTTOM_FIELD 0x3 /* See colour_primaries of ISO/IEC 14496 for significance */ -/* color_primaries values */ +/* msm_vidc_h264_color_primaries_values */ #define MSM_VIDC_RESERVED_1 0 #define MSM_VIDC_BT709_5 1 #define MSM_VIDC_UNSPECIFIED 2 @@ -221,7 +301,17 @@ struct msm_vidc_enc_cvp_metadata_payload { #define MSM_VIDC_GENERIC_FILM 8 #define MSM_VIDC_BT2020 9 -/* matrix_coeffs values */ +/* msm_vidc_vp9_color_primaries_values */ +#define MSM_VIDC_CS_UNKNOWN 0 +#define MSM_VIDC_CS_BT_601 1 +#define MSM_VIDC_CS_BT_709 2 +#define MSM_VIDC_CS_SMPTE_170 3 +#define MSM_VIDC_CS_SMPTE_240 4 +#define MSM_VIDC_CS_BT_2020 5 +#define MSM_VIDC_CS_RESERVED 6 +#define MSM_VIDC_CS_RGB 7 + +/* msm_vidc_h264_matrix_coeff_values */ #define MSM_VIDC_MATRIX_RGB 0 #define MSM_VIDC_MATRIX_BT_709_5 1 #define MSM_VIDC_MATRIX_UNSPECIFIED 2 @@ -236,7 +326,7 @@ struct msm_vidc_enc_cvp_metadata_payload { #define MSM_VIDC_MATRIX_BT_2020 9 #define MSM_VIDC_MATRIX_BT_2020_CONST 10 -/* transfer_char values */ +/* msm_vidc_h264_transfer_chars_values */ #define MSM_VIDC_TRANSFER_RESERVED_1 0 #define MSM_VIDC_TRANSFER_BT709_5 1 #define MSM_VIDC_TRANSFER_UNSPECIFIED 2 @@ -258,118 +348,30 @@ struct msm_vidc_enc_cvp_metadata_payload { #define MSM_VIDC_TRANSFER_SMPTE_ST428_1 17 #define MSM_VIDC_TRANSFER_HLG 18 -#define MSM_VIDC_EXTRADATA_VUI_DISPLAY_INFO 0x7F100006 -struct msm_vidc_vui_display_info_payload { - __u32 video_signal_present_flag; - __u32 video_format; - __u32 bit_depth_y; - __u32 bit_depth_c; - __u32 video_full_range_flag; - __u32 color_description_present_flag; - __u32 color_primaries; - __u32 transfer_char; - __u32 matrix_coeffs; - __u32 chroma_location_info_present_flag; - __u32 chroma_format_idc; - __u32 separate_color_plane_flag; - __u32 chroma_sample_loc_type_top_field; - __u32 chroma_sample_loc_type_bottom_field; -}; - -#define MSM_VIDC_EXTRADATA_HDR_HIST 0x7F100008 -struct msm_vidc_extradata_hdr_hist_payload { - __u32 value_count[1024]; -}; - -#define MSM_VIDC_EXTRADATA_MPEG2_SEQDISP 0x0000000D -struct msm_vidc_mpeg2_seqdisp_payload { - __u32 video_format; - __u32 color_descp; - __u32 color_primaries; - __u32 transfer_char; - __u32 matrix_coeffs; - __u32 disp_width; - __u32 disp_height; -}; - -/* VPx color_space values */ -#define MSM_VIDC_CS_UNKNOWN 0 -#define MSM_VIDC_CS_BT_601 1 -#define MSM_VIDC_CS_BT_709 2 -#define MSM_VIDC_CS_SMPTE_170 3 -#define MSM_VIDC_CS_SMPTE_240 4 -#define MSM_VIDC_CS_BT_2020 5 -#define MSM_VIDC_CS_RESERVED 6 -#define MSM_VIDC_CS_RGB 7 -#define MSM_VIDC_EXTRADATA_VPX_COLORSPACE_INFO 0x00000014 -struct msm_vidc_vpx_colorspace_payload { - __u32 color_space; - __u32 yuv_range_flag; - __u32 sumsampling_x; - __u32 sumsampling_y; -}; - -#define MSM_VIDC_EXTRADATA_METADATA_LTRINFO 0x7F100004 -/* Don't use the #define below. It is to bypass checkpatch */ -#define LTRINFO MSM_VIDC_EXTRADATA_METADATA_LTRINFO -struct msm_vidc_metadata_ltr_payload { - __u32 ltr_use_mark; -}; - -/* ptr[2]: event_notify: pixel_depth */ +/* msm_vidc_pixel_depth */ #define MSM_VIDC_BIT_DEPTH_8 0 #define MSM_VIDC_BIT_DEPTH_10 1 #define MSM_VIDC_BIT_DEPTH_UNSUPPORTED 0XFFFFFFFF -/* ptr[3]: event_notify: pic_struct */ +/* msm_vidc_video_format */ +#define MSM_VIDC_COMPONENT 0 +#define MSM_VIDC_PAL 1 +#define MSM_VIDC_NTSC 2 +#define MSM_VIDC_SECAM 3 +#define MSM_VIDC_MAC 4 +#define MSM_VIDC_UNSPECIFIED_FORMAT 5 +#define MSM_VIDC_RESERVED_1_FORMAT 6 +#define MSM_VIDC_RESERVED_2_FORMAT 7 + +/* msm_vidc_color_desc_flag */ +#define MSM_VIDC_COLOR_DESC_NOT_PRESENT 0 +#define MSM_VIDC_COLOR_DESC_PRESENT 1 + +/* msm_vidc_pic_struct */ #define MSM_VIDC_PIC_STRUCT_MAYBE_INTERLACED 0x0 #define MSM_VIDC_PIC_STRUCT_PROGRESSIVE 0x1 /*default when layer ID isn't specified*/ #define MSM_VIDC_ALL_LAYER_ID 0xFF -static inline unsigned int VENUS_EXTRADATA_SIZE(int width, int height) -{ - (void)height; - (void)width; - - /* - * In the future, calculate the size based on the w/h but just - * hardcode it for now since 16K satisfies all current usecases. - */ - return 16 * 1024; -} - -/* V4L2_CID_MPEG_VIDC_VENC_HDR_INFO payload index */ -enum msm_vidc_hdr_info_types { - MSM_VIDC_RGB_PRIMARY_00, - MSM_VIDC_RGB_PRIMARY_01, - MSM_VIDC_RGB_PRIMARY_10, - MSM_VIDC_RGB_PRIMARY_11, - MSM_VIDC_RGB_PRIMARY_20, - MSM_VIDC_RGB_PRIMARY_21, - MSM_VIDC_WHITEPOINT_X, - MSM_VIDC_WHITEPOINT_Y, - MSM_VIDC_MAX_DISP_LUM, - MSM_VIDC_MIN_DISP_LUM, - MSM_VIDC_RGB_MAX_CLL, - MSM_VIDC_RGB_MAX_FLL, -}; - -enum msm_vidc_plane_reserved_field_types { - MSM_VIDC_BUFFER_FD, - MSM_VIDC_DATA_OFFSET, - MSM_VIDC_COMP_RATIO, - MSM_VIDC_INPUT_TAG_1, - MSM_VIDC_INPUT_TAG_2, -}; - -enum msm_vidc_cb_event_types { - MSM_VIDC_HEIGHT, - MSM_VIDC_WIDTH, - MSM_VIDC_BIT_DEPTH, - MSM_VIDC_PIC_STRUCT, - MSM_VIDC_COLOR_SPACE, - MSM_VIDC_FW_MIN_COUNT, -}; #endif From f2b58b01287a3d2bd39fb9969722e58a43cf9c39 Mon Sep 17 00:00:00 2001 From: Sultan Alsawaf Date: Sat, 10 Jul 2021 15:31:19 -0700 Subject: [PATCH 123/356] msm: vidc: Fix uninitialized tag_data usage Signed-off-by: Sultan Alsawaf Change-Id: I3839d059c7666250519423c5417bcc4b3785d0e2 --- drivers/media/platform/msm/vidc/msm_vidc.c | 10 +++++++--- .../media/platform/msm/vidc/msm_vidc_common.c | 19 +++++++++++++------ .../media/platform/msm/vidc/msm_vidc_common.h | 2 +- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c index 0dbcd352e75f..680bc052c271 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc.c +++ b/drivers/media/platform/msm/vidc/msm_vidc.c @@ -608,9 +608,13 @@ int msm_vidc_dqbuf(void *instance, struct v4l2_buffer *b) tag_data.index = b->index; tag_data.type = b->type; - msm_comm_fetch_tags(inst, &tag_data); - b->m.planes[0].reserved[5] = tag_data.input_tag; - b->m.planes[0].reserved[6] = tag_data.output_tag; + if (msm_comm_fetch_tags(inst, &tag_data)) { + b->m.planes[0].reserved[5] = tag_data.input_tag; + b->m.planes[0].reserved[6] = tag_data.output_tag; + } else { + b->m.planes[0].reserved[5] = 0; + b->m.planes[0].reserved[6] = 0; + } return rc; } diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c index bde2bdd84147..631b3f890139 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c @@ -4264,9 +4264,13 @@ static void populate_frame_data(struct vidc_frame_data *data, tag_data.index = vb->index; tag_data.type = vb->type; - msm_comm_fetch_tags(inst, &tag_data); - data->input_tag = tag_data.input_tag; - data->output_tag = tag_data.output_tag; + if (msm_comm_fetch_tags(inst, &tag_data)) { + data->input_tag = tag_data.input_tag; + data->output_tag = tag_data.output_tag; + } else { + data->input_tag = 0; + data->output_tag = 0; + } extra_idx = EXTRADATA_IDX(vb->num_planes); @@ -7054,7 +7058,7 @@ void msm_comm_store_tags(struct msm_vidc_inst *inst, mutex_unlock(&inst->buffer_tags.lock); } -void msm_comm_fetch_tags(struct msm_vidc_inst *inst, +bool msm_comm_fetch_tags(struct msm_vidc_inst *inst, struct vidc_tag_data *tag_data) { struct vidc_tag_data *temp, *next; @@ -7062,7 +7066,7 @@ void msm_comm_fetch_tags(struct msm_vidc_inst *inst, if (!inst || !tag_data) { dprintk(VIDC_ERR, "%s: invalid params %pK %pK\n", __func__, inst, tag_data); - return; + return false; } mutex_lock(&inst->buffer_tags.lock); list_for_each_entry_safe(temp, next, &inst->buffer_tags.list, list) { @@ -7070,10 +7074,13 @@ void msm_comm_fetch_tags(struct msm_vidc_inst *inst, temp->type == tag_data->type) { tag_data->input_tag = temp->input_tag; tag_data->output_tag = temp->output_tag; - break; + mutex_unlock(&inst->buffer_tags.lock); + return true; } } mutex_unlock(&inst->buffer_tags.lock); + + return false; } void msm_comm_store_mark_data(struct msm_vidc_list *data_list, diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.h b/drivers/media/platform/msm/vidc/msm_vidc_common.h index a4e4b7821b3f..2119e06d7309 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.h +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.h @@ -234,7 +234,7 @@ bool msm_comm_compare_device_planes(struct msm_vidc_buffer *mbuf, u32 type, u32 *planes); void msm_comm_store_tags(struct msm_vidc_inst *inst, struct vidc_tag_data *tag_data); -void msm_comm_fetch_tags(struct msm_vidc_inst *inst, +bool msm_comm_fetch_tags(struct msm_vidc_inst *inst, struct vidc_tag_data *tag_data); void msm_comm_free_buffer_tags(struct msm_vidc_inst *inst); int msm_comm_qbuf_cache_operations(struct msm_vidc_inst *inst, From 571ef5ca55d29980b51368ae2ba9e6adaac07f98 Mon Sep 17 00:00:00 2001 From: Vaibhav Deshu Venkatesh Date: Wed, 28 Nov 2018 12:10:46 -0800 Subject: [PATCH 124/356] msm: vidc: Return EINVAL for SMMU fault handler Currently we are returning 0 in SMMU fault handler. However, if we return -EINVAL, then smmu driver assumes page fault handler is not installed and prints a list of useful debug information. CRs-Fixed: 2344373 Change-Id: I3ca6731eb9a30b7d4ef03f4d580e622d9a8c6c0f Signed-off-by: Vaibhav Deshu Venkatesh --- drivers/media/platform/msm/vidc/msm_vidc_res_parse.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c index bff189c8760a..d0fec086730d 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c @@ -1146,12 +1146,12 @@ int msm_vidc_smmu_fault_handler(struct iommu_domain *domain, core->smmu_fault_handled = true; mutex_unlock(&core->lock); /* - * Return -ENOSYS to elicit the default behaviour of smmu driver. - * If we return -ENOSYS, then smmu driver assumes page fault handler + * 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 -ENOSYS; + return -EINVAL; } static int msm_vidc_populate_context_bank(struct device *dev, From 49554e23d2d9a9c5faea364030e0b1c8a59ee6f4 Mon Sep 17 00:00:00 2001 From: Chinmay Sawarkar Date: Wed, 28 Nov 2018 13:12:24 -0800 Subject: [PATCH 125/356] msm: vidc: Remove non secure firmware loading Non secure loading of firmware is not supported, hence removing the support. CRs-Fixed: 2358497 Change-Id: I1da79824deefd48f42570051be352de7649f1855 Signed-off-by: Chinmay Sawarkar --- drivers/media/platform/msm/vidc/Makefile | 1 - .../media/platform/msm/vidc/msm_v4l2_vidc.c | 4 - .../platform/msm/vidc/msm_vidc_res_parse.c | 40 +- .../platform/msm/vidc/msm_vidc_resources.h | 1 - drivers/media/platform/msm/vidc/venus_boot.c | 470 ------------------ drivers/media/platform/msm/vidc/venus_boot.h | 22 - drivers/media/platform/msm/vidc/venus_hfi.c | 7 +- 7 files changed, 9 insertions(+), 536 deletions(-) delete mode 100644 drivers/media/platform/msm/vidc/venus_boot.c delete mode 100644 drivers/media/platform/msm/vidc/venus_boot.h diff --git a/drivers/media/platform/msm/vidc/Makefile b/drivers/media/platform/msm/vidc/Makefile index 5cb9d0c8920c..0464ce7d4abc 100644 --- a/drivers/media/platform/msm/vidc/Makefile +++ b/drivers/media/platform/msm/vidc/Makefile @@ -15,7 +15,6 @@ msm-vidc-objs := msm_v4l2_vidc.o \ hfi_response_handler.o \ hfi_packetization.o \ vidc_hfi.o \ - venus_boot.o \ msm_vidc_clocks.o obj-$(CONFIG_MSM_VIDC_LEGACY_V4L2) := msm-vidc.o diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c index 9a9b1b361a45..d05ce6bdf246 100644 --- a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c +++ b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c @@ -29,7 +29,6 @@ #include "msm_vidc_internal.h" #include "msm_vidc_res_parse.h" #include "msm_vidc_resources.h" -#include "venus_boot.h" #include "vidc_hfi_api.h" #include "msm_v4l2_private.h" #include "msm_vidc_clocks.h" @@ -727,9 +726,6 @@ static int msm_vidc_remove(struct platform_device *pdev) return -EINVAL; } - if (core->resources.use_non_secure_pil) - venus_boot_deinit(); - vidc_hfi_deinitialize(core->hfi_type, core->device); if (core->resources.domain_cvp) { device_remove_file(&core->vdev[MSM_VIDC_CVP].vdev.dev, diff --git a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c index d0fec086730d..46e05840c27c 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c @@ -19,7 +19,6 @@ #include "msm_vidc_debug.h" #include "msm_vidc_resources.h" #include "msm_vidc_res_parse.h" -#include "venus_boot.h" #include "soc/qcom/secure_buffer.h" enum clock_properties { @@ -980,17 +979,6 @@ int read_platform_resources_from_dt( goto err_setup_legacy_cb; } - res->use_non_secure_pil = of_property_read_bool(pdev->dev.of_node, - "qcom,use-non-secure-pil"); - - if (res->use_non_secure_pil || !is_iommu_present(res)) { - of_property_read_u32(pdev->dev.of_node, "qcom,fw-bias", - &firmware_base); - res->firmware_base = (phys_addr_t)firmware_base; - dprintk(VIDC_DBG, - "Using fw-bias : %pa", &res->firmware_base); - } - rc = msm_vidc_populate_cx_ipeak_context(res); if (rc) { dprintk(VIDC_ERR, @@ -1359,30 +1347,12 @@ int read_context_bank_resources_from_dt(struct platform_device *pdev) return -EINVAL; } - if (of_property_read_bool(pdev->dev.of_node, "qcom,fw-context-bank")) { - if (core->resources.use_non_secure_pil) { - struct context_bank_info *cb; - - cb = devm_kzalloc(&pdev->dev, sizeof(*cb), GFP_KERNEL); - if (!cb) { - dprintk(VIDC_ERR, "alloc venus cb failed\n"); - return -ENOMEM; - } + rc = msm_vidc_populate_context_bank(&pdev->dev, core); + if (rc) + dprintk(VIDC_ERR, "Failed to probe context bank\n"); + else + dprintk(VIDC_DBG, "Successfully probed context bank\n"); - cb->dev = &pdev->dev; - rc = venus_boot_init(&core->resources, cb); - if (rc) { - dprintk(VIDC_ERR, - "Failed to init non-secure PIL %d\n", rc); - } - } - } else { - rc = msm_vidc_populate_context_bank(&pdev->dev, core); - if (rc) - dprintk(VIDC_ERR, "Failed to probe context bank\n"); - else - dprintk(VIDC_DBG, "Successfully probed context bank\n"); - } return rc; } diff --git a/drivers/media/platform/msm/vidc/msm_vidc_resources.h b/drivers/media/platform/msm/vidc/msm_vidc_resources.h index 53d62fb91c45..c24dab8b9561 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_resources.h +++ b/drivers/media/platform/msm/vidc/msm_vidc_resources.h @@ -184,7 +184,6 @@ struct msm_vidc_platform_resources { struct clock_set clock_set; struct bus_set bus_set; struct reset_set reset_set; - bool use_non_secure_pil; bool sw_power_collapsible; bool slave_side_cp; struct list_head context_banks; diff --git a/drivers/media/platform/msm/vidc/venus_boot.c b/drivers/media/platform/msm/vidc/venus_boot.c deleted file mode 100644 index 7fe7d0e17881..000000000000 --- a/drivers/media/platform/msm/vidc/venus_boot.c +++ /dev/null @@ -1,470 +0,0 @@ -/* Copyright (c) 2014-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. - */ - -#define VIDC_DBG_LABEL "venus_boot" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "msm_vidc_debug.h" -#include "vidc_hfi_io.h" -#include "venus_boot.h" - -/* VENUS WRAPPER registers */ -#define VENUS_WRAPPER_SEC_CPA_START_ADDR \ - (VIDC_WRAPPER_BASE_OFFS + 0x1020) -#define VENUS_WRAPPER_SEC_CPA_END_ADDR \ - (VIDC_WRAPPER_BASE_OFFS + 0x1024) -#define VENUS_WRAPPER_SEC_FW_START_ADDR \ - (VIDC_WRAPPER_BASE_OFFS + 0x1028) -#define VENUS_WRAPPER_SEC_FW_END_ADDR \ - (VIDC_WRAPPER_BASE_OFFS + 0x102C) - -#define VENUS_WRAPPER_A9SS_SW_RESET (VIDC_WRAPPER_BASE_OFFS + 0x3000) - -/* VENUS VBIF registers */ -#define VENUS_VBIF_CLKON_FORCE_ON BIT(0) - -#define VENUS_VBIF_ADDR_TRANS_EN (VIDC_VBIF_BASE_OFFS + 0x1000) -#define VENUS_VBIF_AT_OLD_BASE (VIDC_VBIF_BASE_OFFS + 0x1004) -#define VENUS_VBIF_AT_OLD_HIGH (VIDC_VBIF_BASE_OFFS + 0x1008) -#define VENUS_VBIF_AT_NEW_BASE (VIDC_VBIF_BASE_OFFS + 0x1010) -#define VENUS_VBIF_AT_NEW_HIGH (VIDC_VBIF_BASE_OFFS + 0x1018) - - -/* Poll interval in uS */ -#define POLL_INTERVAL_US 50 - -#define VENUS_REGION_SIZE 0x00500000 - -static struct { - struct msm_vidc_platform_resources *resources; - struct regulator *gdsc; - const char *reg_name; - void __iomem *reg_base; - struct device *iommu_ctx_bank_dev; - struct dma_iommu_mapping *mapping; - dma_addr_t fw_iova; - bool is_booted; - bool hw_ver_checked; - u32 fw_sz; - u32 hw_ver_major; - u32 hw_ver_minor; - void *venus_notif_hdle; -} *venus_data = NULL; - -/* Get venus clocks and set rates for rate-settable clocks */ -static int venus_clock_setup(void) -{ - int i, rc = 0; - unsigned long rate; - struct msm_vidc_platform_resources *res = venus_data->resources; - struct clock_info *cl; - - for (i = 0; i < res->clock_set.count; i++) { - cl = &res->clock_set.clock_tbl[i]; - /* Make sure rate-settable clocks' rates are set */ - if (!clk_get_rate(cl->clk) && cl->count) { - rate = clk_round_rate(cl->clk, 0); - rc = clk_set_rate(cl->clk, rate); - if (rc) { - dprintk(VIDC_ERR, - "Failed to set clock rate %lu %s: %d\n", - rate, cl->name, rc); - break; - } - } - } - - return rc; -} - -static int venus_clock_prepare_enable(void) -{ - int i, rc = 0; - struct msm_vidc_platform_resources *res = venus_data->resources; - struct clock_info *cl; - - for (i = 0; i < res->clock_set.count; i++) { - cl = &res->clock_set.clock_tbl[i]; - rc = clk_prepare_enable(cl->clk); - if (rc) { - dprintk(VIDC_ERR, "failed to enable %s\n", cl->name); - for (i--; i >= 0; i--) { - cl = &res->clock_set.clock_tbl[i]; - clk_disable_unprepare(cl->clk); - } - return rc; - } - } - - return rc; -} - -static void venus_clock_disable_unprepare(void) -{ - struct msm_vidc_platform_resources *res = venus_data->resources; - struct clock_info *cl; - int i = res->clock_set.count; - - for (i--; i >= 0; i--) { - cl = &res->clock_set.clock_tbl[i]; - clk_disable_unprepare(cl->clk); - } -} - -static int venus_setup_cb(struct device *dev, - u32 size) -{ - dma_addr_t va_start = 0x0; - size_t va_size = size; - - venus_data->mapping = arm_iommu_create_mapping( - dev->bus, va_start, va_size); - if (IS_ERR_OR_NULL(venus_data->mapping)) { - dprintk(VIDC_ERR, "%s: failed to create mapping for %s\n", - __func__, dev_name(dev)); - return -ENODEV; - } - dprintk(VIDC_DBG, - "%s Attached device %pK and created mapping %pK for %s\n", - __func__, dev, venus_data->mapping, dev_name(dev)); - return 0; -} - -static int pil_venus_mem_setup(size_t size) -{ - int rc = 0; - - if (!venus_data->mapping) { - size = round_up(size, SZ_4K); - rc = venus_setup_cb(venus_data->iommu_ctx_bank_dev, size); - if (rc) { - dprintk(VIDC_ERR, - "%s: Failed to setup context bank for venus : %s\n", - __func__, - dev_name(venus_data->iommu_ctx_bank_dev)); - return rc; - } - venus_data->fw_sz = size; - } - - return rc; -} - -static int pil_venus_auth_and_reset(void) -{ - int rc; - - phys_addr_t fw_bias = venus_data->resources->firmware_base; - void __iomem *reg_base = venus_data->reg_base; - u32 ver; - bool iommu_present = is_iommu_present(venus_data->resources); - struct device *dev = venus_data->iommu_ctx_bank_dev; - - if (!fw_bias) { - dprintk(VIDC_ERR, "FW bias is not valid\n"); - return -EINVAL; - } - venus_data->fw_iova = (dma_addr_t)NULL; - /* Get Venus version number */ - if (!venus_data->hw_ver_checked) { - ver = readl_relaxed(reg_base + VIDC_WRAPPER_HW_VERSION); - venus_data->hw_ver_minor = (ver & 0x0FFF0000) >> 16; - venus_data->hw_ver_major = (ver & 0xF0000000) >> 28; - venus_data->hw_ver_checked = 1; - } - - if (iommu_present) { - u32 cpa_start_addr, cpa_end_addr, fw_start_addr, fw_end_addr; - /* Get the cpa and fw start/end addr */ - cpa_start_addr = - VENUS_WRAPPER_SEC_CPA_START_ADDR; - cpa_end_addr = - VENUS_WRAPPER_SEC_CPA_END_ADDR; - fw_start_addr = - VENUS_WRAPPER_SEC_FW_START_ADDR; - fw_end_addr = - VENUS_WRAPPER_SEC_FW_END_ADDR; - - /* Program CPA start and end address */ - writel_relaxed(0, reg_base + cpa_start_addr); - writel_relaxed(venus_data->fw_sz, reg_base + cpa_end_addr); - - /* Program FW start and end address */ - writel_relaxed(0, reg_base + fw_start_addr); - writel_relaxed(venus_data->fw_sz, reg_base + fw_end_addr); - } else { - rc = regulator_enable(venus_data->gdsc); - if (rc) { - dprintk(VIDC_ERR, "GDSC enable failed\n"); - goto err; - } - - rc = venus_clock_prepare_enable(); - if (rc) { - dprintk(VIDC_ERR, "Clock prepare and enable failed\n"); - regulator_disable(venus_data->gdsc); - goto err; - } - - writel_relaxed(0, reg_base + VENUS_VBIF_AT_OLD_BASE); - writel_relaxed(VENUS_REGION_SIZE, - reg_base + VENUS_VBIF_AT_OLD_HIGH); - writel_relaxed(fw_bias, reg_base + VENUS_VBIF_AT_NEW_BASE); - writel_relaxed(fw_bias + VENUS_REGION_SIZE, - reg_base + VENUS_VBIF_AT_NEW_HIGH); - writel_relaxed(0x7F007F, reg_base + VENUS_VBIF_ADDR_TRANS_EN); - venus_clock_disable_unprepare(); - regulator_disable(venus_data->gdsc); - } - /* Make sure all register writes are committed. */ - mb(); - - /* - * Need to wait 10 cycles of internal clocks before bringing ARM9 - * out of reset. - */ - udelay(1); - - if (iommu_present) { - phys_addr_t pa = fw_bias; - - rc = arm_iommu_attach_device(dev, venus_data->mapping); - if (rc) { - dprintk(VIDC_ERR, - "Failed to attach iommu for %s : %d\n", - dev_name(dev), rc); - goto release_mapping; - } - - dprintk(VIDC_DBG, "Attached and created mapping for %s\n", - dev_name(dev)); - - /* Map virtual addr space 0 - fw_sz to fw phys addr space */ - rc = iommu_map(venus_data->mapping->domain, - venus_data->fw_iova, pa, venus_data->fw_sz, - IOMMU_READ|IOMMU_WRITE|IOMMU_PRIV); - if (!rc) { - dprintk(VIDC_DBG, - "%s - Successfully mapped and performed test translation!\n", - dev_name(dev)); - } - - if (rc || (venus_data->fw_iova != 0)) { - dprintk(VIDC_ERR, "%s - Failed to setup IOMMU\n", - dev_name(dev)); - goto err_iommu_map; - } - } - /* Bring Arm9 out of reset */ - writel_relaxed(0, reg_base + VENUS_WRAPPER_A9SS_SW_RESET); - - venus_data->is_booted = 1; - return 0; - -err_iommu_map: - if (iommu_present) - arm_iommu_detach_device(dev); -release_mapping: - if (iommu_present) - arm_iommu_release_mapping(venus_data->mapping); -err: - return rc; -} - -static int pil_venus_shutdown(void) -{ - void __iomem *reg_base = venus_data->reg_base; - u32 reg; - int rc; - - if (!venus_data->is_booted) - return 0; - - /* Assert the reset to ARM9 */ - reg = readl_relaxed(reg_base + VENUS_WRAPPER_A9SS_SW_RESET); - reg |= BIT(4); - writel_relaxed(reg, reg_base + VENUS_WRAPPER_A9SS_SW_RESET); - - /* Make sure reset is asserted before the mapping is removed */ - mb(); - - if (is_iommu_present(venus_data->resources)) { - iommu_unmap(venus_data->mapping->domain, venus_data->fw_iova, - venus_data->fw_sz); - arm_iommu_detach_device(venus_data->iommu_ctx_bank_dev); - } - /* - * Force the VBIF clk to be on to avoid AXI bridge halt ack failure - * for certain Venus version. - */ - if (venus_data->hw_ver_major == 0x1 && - (venus_data->hw_ver_minor == 0x2 || - venus_data->hw_ver_minor == 0x3)) { - reg = readl_relaxed(reg_base + VIDC_VENUS_VBIF_CLK_ON); - reg |= VENUS_VBIF_CLKON_FORCE_ON; - writel_relaxed(reg, reg_base + VIDC_VENUS_VBIF_CLK_ON); - } - - /* Halt AXI and AXI OCMEM VBIF Access */ - reg = readl_relaxed(reg_base + VENUS_VBIF_AXI_HALT_CTRL0); - reg |= VENUS_VBIF_AXI_HALT_CTRL0_HALT_REQ; - writel_relaxed(reg, reg_base + VENUS_VBIF_AXI_HALT_CTRL0); - - /* Request for AXI bus port halt */ - rc = readl_poll_timeout(reg_base + VENUS_VBIF_AXI_HALT_CTRL1, - reg, reg & VENUS_VBIF_AXI_HALT_CTRL1_HALT_ACK, - POLL_INTERVAL_US, - VENUS_VBIF_AXI_HALT_ACK_TIMEOUT_US); - if (rc) - dprintk(VIDC_ERR, "Port halt timeout\n"); - - venus_data->is_booted = 0; - - return 0; -} - -static int venus_notifier_cb(struct notifier_block *this, unsigned long code, - void *ss_handle) -{ - struct notif_data *data = (struct notif_data *)ss_handle; - static bool venus_data_set; - int ret; - - if (!data->no_auth) - return NOTIFY_DONE; - - if (!venus_data_set) { - ret = venus_clock_setup(); - if (ret) - return ret; - - ret = of_property_read_string(data->pdev->dev.of_node, - "qcom,proxy-reg-names", &venus_data->reg_name); - if (ret) - return ret; - - venus_data->gdsc = devm_regulator_get( - &data->pdev->dev, venus_data->reg_name); - if (IS_ERR(venus_data->gdsc)) { - dprintk(VIDC_ERR, "Failed to get Venus GDSC\n"); - return -ENODEV; - } - - venus_data_set = true; - } - - if (code != SUBSYS_AFTER_POWERUP && code != SUBSYS_AFTER_SHUTDOWN) - return NOTIFY_DONE; - - ret = regulator_enable(venus_data->gdsc); - if (ret) { - dprintk(VIDC_ERR, "GDSC enable failed\n"); - return ret; - } - - ret = venus_clock_prepare_enable(); - if (ret) { - dprintk(VIDC_ERR, "Clock prepare and enable failed\n"); - goto err_clks; - } - - if (code == SUBSYS_AFTER_POWERUP) { - if (is_iommu_present(venus_data->resources)) - pil_venus_mem_setup(VENUS_REGION_SIZE); - pil_venus_auth_and_reset(); - } else if (code == SUBSYS_AFTER_SHUTDOWN) - pil_venus_shutdown(); - - venus_clock_disable_unprepare(); - regulator_disable(venus_data->gdsc); - - return NOTIFY_DONE; -err_clks: - regulator_disable(venus_data->gdsc); - return ret; -} - -static struct notifier_block venus_notifier = { - .notifier_call = venus_notifier_cb, -}; - -int venus_boot_init(struct msm_vidc_platform_resources *res, - struct context_bank_info *cb) -{ - int rc = 0; - - if (!res || !cb) { - dprintk(VIDC_ERR, "Invalid platform resource handle\n"); - return -EINVAL; - } - venus_data = kzalloc(sizeof(*venus_data), GFP_KERNEL); - if (!venus_data) - return -ENOMEM; - - venus_data->resources = res; - venus_data->iommu_ctx_bank_dev = cb->dev; - if (!venus_data->iommu_ctx_bank_dev) { - dprintk(VIDC_ERR, "Invalid venus context bank device\n"); - return -ENODEV; - } - venus_data->reg_base = ioremap_nocache(res->register_base, - (unsigned long)res->register_size); - dprintk(VIDC_DBG, "venus reg: base %llx size %x\n", - res->register_base, res->register_size); - if (!venus_data->reg_base) { - dprintk(VIDC_ERR, - "could not map reg addr %pa of size %d\n", - &res->register_base, res->register_size); - rc = -ENOMEM; - goto err_ioremap_fail; - } - - venus_data->venus_notif_hdle = subsys_notif_register_notifier("venus", - &venus_notifier); - if (IS_ERR(venus_data->venus_notif_hdle)) { - dprintk(VIDC_ERR, "register event notification failed\n"); - rc = PTR_ERR(venus_data->venus_notif_hdle); - goto err_subsys_notif; - } - - return rc; - -err_subsys_notif: -err_ioremap_fail: - kfree(venus_data); - return rc; -} - -void venus_boot_deinit(void) -{ - venus_data->resources = NULL; - subsys_notif_unregister_notifier(venus_data->venus_notif_hdle, - &venus_notifier); - kfree(venus_data); -} diff --git a/drivers/media/platform/msm/vidc/venus_boot.h b/drivers/media/platform/msm/vidc/venus_boot.h deleted file mode 100644 index da4e77291f51..000000000000 --- a/drivers/media/platform/msm/vidc/venus_boot.h +++ /dev/null @@ -1,22 +0,0 @@ -/* Copyright (c) 2014, 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. - * - */ - -#ifndef __VENUS_BOOT_H__ -#define __VENUS_BOOT_H__ -#include "msm_vidc_resources.h" - -int venus_boot_init(struct msm_vidc_platform_resources *res, - struct context_bank_info *cb); -void venus_boot_deinit(void); - -#endif /* __VENUS_BOOT_H__ */ diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c index 6e34d0e69db9..763c5e25f3a7 100644 --- a/drivers/media/platform/msm/vidc/venus_hfi.c +++ b/drivers/media/platform/msm/vidc/venus_hfi.c @@ -4918,8 +4918,7 @@ static int __load_fw(struct venus_hfi_device *device) goto fail_venus_power_on; } - if ((!device->res->use_non_secure_pil && !device->res->firmware_base) - || device->res->use_non_secure_pil) { + if (!device->res->firmware_base) { if (!device->resources.fw.cookie) device->resources.fw.cookie = subsystem_get_with_fwname("venus", @@ -4931,9 +4930,11 @@ static int __load_fw(struct venus_hfi_device *device) rc = -ENOMEM; goto fail_load_fw; } + } else { + dprintk(VIDC_ERR, "Firmware base must be 0\n"); } - if (!device->res->use_non_secure_pil && !device->res->firmware_base) { + if (!device->res->firmware_base) { rc = __protect_cp_mem(device); if (rc) { dprintk(VIDC_ERR, "Failed to protect memory\n"); From 60822610ebccfc52af6e912a60ebfacad4046f68 Mon Sep 17 00:00:00 2001 From: Chinmay Sawarkar Date: Wed, 28 Nov 2018 13:21:14 -0800 Subject: [PATCH 126/356] msm: vidc: Remove deprecated iommu initialization apis IOMMU initialization APIs have been deprecated and replaced by device tree properties. IOMMU driver will map/unmap and attach/detach device at bootup, based on the dtsi entries. CRs-Fixed: 2358497 Change-Id: I2be820ed406c46209e927e5f7f861e75d67e966a Signed-off-by: Chinmay Sawarkar --- drivers/media/platform/msm/vidc/msm_smem.c | 4 +- drivers/media/platform/msm/vidc/msm_vidc.h | 2 +- .../platform/msm/vidc/msm_vidc_res_parse.c | 80 +------------------ .../platform/msm/vidc/msm_vidc_resources.h | 2 +- drivers/media/platform/msm/vidc/venus_hfi.c | 35 ++------ 5 files changed, 15 insertions(+), 108 deletions(-) diff --git a/drivers/media/platform/msm/vidc/msm_smem.c b/drivers/media/platform/msm/vidc/msm_smem.c index 5395ca407c29..efee3b3091e1 100644 --- a/drivers/media/platform/msm/vidc/msm_smem.c +++ b/drivers/media/platform/msm/vidc/msm_smem.c @@ -110,7 +110,7 @@ static int msm_dma_get_device_address(struct dma_buf *dbuf, unsigned long align, } mapping_info->dev = cb->dev; - mapping_info->mapping = cb->mapping; + mapping_info->domain = cb->domain; mapping_info->table = table; mapping_info->attach = attach; mapping_info->buf = dbuf; @@ -158,7 +158,7 @@ static int msm_dma_put_device_address(u32 flags, trace_msm_smem_buffer_iommu_op_end("UNMAP", 0, 0, 0, 0, 0); mapping_info->dev = NULL; - mapping_info->mapping = NULL; + mapping_info->domain = NULL; mapping_info->table = NULL; mapping_info->attach = NULL; mapping_info->buf = NULL; diff --git a/drivers/media/platform/msm/vidc/msm_vidc.h b/drivers/media/platform/msm/vidc/msm_vidc.h index c22970833f83..bc0c03bd2c3e 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc.h +++ b/drivers/media/platform/msm/vidc/msm_vidc.h @@ -57,7 +57,7 @@ enum hal_buffer { struct dma_mapping_info { struct device *dev; - struct dma_iommu_mapping *mapping; + struct iommu_domain *domain; struct sg_table *table; struct dma_buf_attachment *attach; struct dma_buf *buf; diff --git a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c index 46e05840c27c..31cc5c4ebf4b 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c @@ -1004,25 +1004,10 @@ return rc; return rc; } -static int get_secure_vmid(struct context_bank_info *cb) -{ - if (!strcasecmp(cb->name, "venus_sec_bitstream")) - return VMID_CP_BITSTREAM; - else if (!strcasecmp(cb->name, "venus_sec_pixel")) - return VMID_CP_PIXEL; - else if (!strcasecmp(cb->name, "venus_sec_non_pixel")) - return VMID_CP_NON_PIXEL; - - WARN(1, "No matching secure vmid for cb name: %s\n", - cb->name); - return VMID_INVAL; -} - static int msm_vidc_setup_context_bank(struct msm_vidc_platform_resources *res, struct context_bank_info *cb, struct device *dev) { int rc = 0; - int secure_vmid = VMID_INVAL; struct bus_type *bus; if (!dev || !cb || !res) { @@ -1039,45 +1024,7 @@ static int msm_vidc_setup_context_bank(struct msm_vidc_platform_resources *res, goto remove_cb; } - cb->mapping = arm_iommu_create_mapping(bus, cb->addr_range.start, - cb->addr_range.size); - if (IS_ERR_OR_NULL(cb->mapping)) { - dprintk(VIDC_ERR, "%s - failed to create mapping\n", __func__); - rc = PTR_ERR(cb->mapping) ?: -ENODEV; - goto remove_cb; - } - - if (cb->is_secure) { - secure_vmid = get_secure_vmid(cb); - rc = iommu_domain_set_attr(cb->mapping->domain, - DOMAIN_ATTR_SECURE_VMID, &secure_vmid); - if (rc) { - dprintk(VIDC_ERR, - "%s - programming secure vmid failed: %s %d\n", - __func__, dev_name(dev), rc); - goto release_mapping; - } - } - - if (res->cache_pagetables) { - int cache_pagetables = 1; - - rc = iommu_domain_set_attr(cb->mapping->domain, - DOMAIN_ATTR_USE_UPSTREAM_HINT, &cache_pagetables); - if (rc) { - WARN_ONCE(rc, - "%s: failed to set cache pagetables attribute, %d\n", - __func__, rc); - rc = 0; - } - } - - rc = arm_iommu_attach_device(cb->dev, cb->mapping); - if (rc) { - dprintk(VIDC_ERR, "%s - Couldn't arm_iommu_attach_device\n", - __func__); - goto release_mapping; - } + cb->domain = iommu_get_domain_for_dev(cb->dev); /* * configure device segment size and segment boundary to ensure @@ -1092,14 +1039,10 @@ static int msm_vidc_setup_context_bank(struct msm_vidc_platform_resources *res, dprintk(VIDC_DBG, "Attached %s and created mapping\n", dev_name(dev)); dprintk(VIDC_DBG, - "Context bank name:%s, buffer_type: %#x, is_secure: %d, address range start: %#x, size: %#x, dev: %pK, mapping: %pK", + "Context bank name:%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->mapping); + cb->addr_range.size, cb->dev, cb->domain); - return rc; - -release_mapping: - arm_iommu_release_mapping(cb->mapping); remove_cb: return rc; } @@ -1203,22 +1146,7 @@ static int msm_vidc_populate_context_bank(struct device *dev, goto err_setup_cb; } - if (core->resources.non_fatal_pagefaults) { - int data = 1; - - dprintk(VIDC_DBG, "set non-fatal-faults attribute on %s\n", - dev_name(dev)); - rc = iommu_domain_set_attr(cb->mapping->domain, - DOMAIN_ATTR_NON_FATAL_FAULTS, &data); - if (rc) { - dprintk(VIDC_WARN, - "%s: set non fatal attribute failed: %s %d\n", - __func__, dev_name(dev), rc); - /* ignore the error */ - } - } - - iommu_set_fault_handler(cb->mapping->domain, + iommu_set_fault_handler(cb->domain, msm_vidc_smmu_fault_handler, (void *)core); return 0; diff --git a/drivers/media/platform/msm/vidc/msm_vidc_resources.h b/drivers/media/platform/msm/vidc/msm_vidc_resources.h index c24dab8b9561..6475d87d5c4c 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_resources.h +++ b/drivers/media/platform/msm/vidc/msm_vidc_resources.h @@ -61,7 +61,7 @@ struct context_bank_info { bool is_secure; struct addr_range addr_range; struct device *dev; - struct dma_iommu_mapping *mapping; + struct iommu_domain *domain; }; struct buffer_usage_table { diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c index 763c5e25f3a7..0c6de9141891 100644 --- a/drivers/media/platform/msm/vidc/venus_hfi.c +++ b/drivers/media/platform/msm/vidc/venus_hfi.c @@ -985,23 +985,6 @@ static void __set_threshold_registers(struct venus_hfi_device *device) dprintk(VIDC_ERR, "Failed to restore threshold values\n"); } -static void __iommu_detach(struct venus_hfi_device *device) -{ - struct context_bank_info *cb; - - if (!device || !device->res) { - dprintk(VIDC_ERR, "Invalid parameter: %pK\n", device); - return; - } - - list_for_each_entry(cb, &device->res->context_banks, list) { - if (cb->dev) - arm_iommu_detach_device(cb->dev); - if (cb->mapping) - arm_iommu_release_mapping(cb->mapping); - } -} - static int __devfreq_target(struct device *devfreq_dev, unsigned long *freq, u32 flags) { @@ -1793,7 +1776,7 @@ static void __interface_queues_release(struct venus_hfi_device *device) false, device->res, HAL_BUFFER_INTERNAL_CMD_QUEUE); for (i = 0; cb && i < num_entries; i++) { - iommu_unmap(cb->mapping->domain, + iommu_unmap(cb->domain, mem_map[i].virtual_addr, mem_map[i].size); } @@ -1827,7 +1810,7 @@ static void __interface_queues_release(struct venus_hfi_device *device) } static int __get_qdss_iommu_virtual_addr(struct venus_hfi_device *dev, - struct hfi_mem_map *mem_map, struct dma_iommu_mapping *mapping) + struct hfi_mem_map *mem_map, struct iommu_domain *domain) { int i; int rc = 0; @@ -1839,8 +1822,8 @@ static int __get_qdss_iommu_virtual_addr(struct venus_hfi_device *dev, return -ENODATA; for (i = 0; i < num_entries; i++) { - if (mapping) { - rc = iommu_map(mapping->domain, iova, + if (domain) { + rc = iommu_map(domain, iova, qdss_addr_tbl[i].start, qdss_addr_tbl[i].size, IOMMU_READ | IOMMU_WRITE); @@ -1868,8 +1851,8 @@ static int __get_qdss_iommu_virtual_addr(struct venus_hfi_device *dev, dprintk(VIDC_ERR, "QDSS mapping failed, Freeing other entries %d\n", i); - for (--i; mapping && i >= 0; i--) { - iommu_unmap(mapping->domain, + for (--i; domain && i >= 0; i--) { + iommu_unmap(domain, mem_map[i].virtual_addr, mem_map[i].size); } @@ -2025,7 +2008,7 @@ static int __interface_queues_init(struct venus_hfi_device *dev) return -EINVAL; } - rc = __get_qdss_iommu_virtual_addr(dev, mem_map, cb->mapping); + rc = __get_qdss_iommu_virtual_addr(dev, mem_map, cb->domain); if (rc) { dprintk(VIDC_ERR, "IOMMU mapping failed, Freeing qdss memdata\n"); @@ -5260,10 +5243,6 @@ void venus_hfi_delete_device(void *device) dev = (struct venus_hfi_device *) device; - mutex_lock(&dev->lock); - __iommu_detach(dev); - mutex_unlock(&dev->lock); - 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--; From 78f200c1d8bdb38aa94ef839e634721d6f6f1ec3 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Fri, 9 Jun 2023 02:26:10 +0000 Subject: [PATCH 127/356] msm: vidc: Update llcc setup for 4.19 Stolen from techpack/video --- drivers/media/platform/msm/vidc/venus_hfi.c | 23 ++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c index 0c6de9141891..83d54ceb26f3 100644 --- a/drivers/media/platform/msm/vidc/venus_hfi.c +++ b/drivers/media/platform/msm/vidc/venus_hfi.c @@ -4229,10 +4229,19 @@ static int __init_subcaches(struct venus_hfi_device *device) return 0; venus_hfi_for_each_subcache(device, sinfo) { - sinfo->subcache = llcc_slice_getd(&device->res->pdev->dev, - sinfo->name); + 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 { + dprintk(VIDC_ERR, "Invalid subcache name %s\n", + sinfo->name); + } if (IS_ERR_OR_NULL(sinfo->subcache)) { - rc = PTR_ERR(sinfo->subcache) ? : -EBADHANDLE; + rc = PTR_ERR(sinfo->subcache) ? + PTR_ERR(sinfo->subcache) : -EBADHANDLE; dprintk(VIDC_ERR, "init_subcaches: invalid subcache: %s rc %d\n", sinfo->name, rc); @@ -4519,8 +4528,8 @@ static int __set_subcaches(struct venus_hfi_device *device) venus_hfi_for_each_subcache(device, sinfo) { if (sinfo->isactive == true) { - sc_res[c].size = sinfo->subcache->llcc_slice_size; - sc_res[c].sc_id = sinfo->subcache->llcc_slice_id; + sc_res[c].size = sinfo->subcache->slice_size; + sc_res[c].sc_id = sinfo->subcache->slice_id; c++; } } @@ -4579,8 +4588,8 @@ static int __release_subcaches(struct venus_hfi_device *device) venus_hfi_for_each_subcache_reverse(device, sinfo) { if (sinfo->isset == true) { /* Update the entry */ - sc_res[c].size = sinfo->subcache->llcc_slice_size; - sc_res[c].sc_id = sinfo->subcache->llcc_slice_id; + sc_res[c].size = sinfo->subcache->slice_size; + sc_res[c].sc_id = sinfo->subcache->slice_id; c++; sinfo->isset = false; } From 7f6182bbe170e5d45cafa0929ded8efe9516717e Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Wed, 7 Jun 2023 02:59:10 +0000 Subject: [PATCH 128/356] msm: vidc: Switch to timer_setup() --- drivers/media/platform/msm/vidc/msm_vidc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c index 680bc052c271..cd5823ab0598 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc.c +++ b/drivers/media/platform/msm/vidc/msm_vidc.c @@ -1870,9 +1870,9 @@ static const struct v4l2_ctrl_ops msm_vidc_ctrl_ops = { .g_volatile_ctrl = msm_vidc_op_g_volatile_ctrl, }; -static void batch_timer_callback(unsigned long data) +static void batch_timer_callback(struct timer_list *t) { - struct msm_vidc_inst *inst = (struct msm_vidc_inst *)data; + struct msm_vidc_inst *inst = from_timer(inst, t, batch_timer); if (!inst->batch.enable) return; @@ -2017,8 +2017,8 @@ void *msm_vidc_open(int core_id, int session_type) } INIT_WORK(&inst->batch_work, msm_vidc_batch_handler); - setup_timer(&inst->batch_timer, - batch_timer_callback, (unsigned long)inst); + timer_setup(&inst->batch_timer, + batch_timer_callback, 0); return inst; fail_init: From 65e84887c6dad3261443b17f9c0b767395d2f577 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Wed, 7 Jun 2023 01:40:28 +0000 Subject: [PATCH 129/356] msm: vidc: Remove boot markers --- drivers/media/platform/msm/vidc/msm_v4l2_vidc.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c index d05ce6bdf246..99e790891836 100644 --- a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c +++ b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c @@ -533,8 +533,6 @@ static int msm_vidc_probe_vidc_device(struct platform_device *pdev) struct device *dev; int nr = BASE_DEVICE_NUMBER; - place_marker("M - DRIVER Video Start"); - if (!vidc_driver) { dprintk(VIDC_ERR, "Invalid vidc driver\n"); return -EINVAL; @@ -641,7 +639,6 @@ static int msm_vidc_probe_vidc_device(struct platform_device *pdev) goto err_fail_sub_device_probe; } - place_marker("M - DRIVER Video Ready"); return rc; err_fail_sub_device_probe: @@ -781,7 +778,6 @@ static int msm_vidc_pm_suspend(struct device *dev) static int msm_vidc_pm_resume(struct device *dev) { - update_marker("vidc resumed"); dprintk(VIDC_INFO, "%s\n", __func__); return 0; } @@ -850,14 +846,9 @@ static int msm_vidc_pm_freeze(struct device *dev) if (!core) return 0; - if (of_device_is_compatible(dev->of_node, "qcom,msm-vidc")) { - place_marker("vidc hibernation start"); - + if (of_device_is_compatible(dev->of_node, "qcom,msm-vidc")) rc = msm_vidc_freeze_core(core); - place_marker("vidc hibernation end"); - } - dprintk(VIDC_INFO, "%s: done\n", __func__); return rc; From a282b16ddff271b508bdd8e2bb41e1f5ef653933 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Wed, 7 Jun 2023 02:22:05 +0000 Subject: [PATCH 130/356] msm: vidc: Remove usage of KERNEL_VERSION macro --- drivers/media/platform/msm/vidc/msm_vidc_internal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h index b2cad6dab3e2..3ef56ab63951 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h +++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h @@ -37,7 +37,7 @@ #include #define MSM_VIDC_DRV_NAME "msm_vidc_driver" -#define MSM_VIDC_VERSION KERNEL_VERSION(0, 0, 1) +#define MSM_VIDC_VERSION ((0 << 16) + (4 << 8) + 19) #define MAX_DEBUGFS_NAME 50 #define DEFAULT_TIMEOUT 3 #define DEFAULT_HEIGHT 1088 From ecdeb9757cf635cf2c80b3a09d767e54dee4d360 Mon Sep 17 00:00:00 2001 From: Vikash Garodia Date: Fri, 22 Mar 2019 19:43:29 +0530 Subject: [PATCH 131/356] msm: vidc: Remove devfreq module from video Bus bandwidth voting can be achieved by directly call the bus apis. DevFreq functionality is not utilized nor necessary. Also, video bus bandwidth votes are dynamic and cannot conform to the OPP table entries. CRs-Fixed: 2384822 Change-Id: Ib83f51d7d07efe24a256e0287433e7a28e2ae057 Signed-off-by: Chinmay Sawarkar Signed-off-by: Vikash Garodia --- drivers/media/platform/msm/vidc/Kconfig | 2 - drivers/media/platform/msm/vidc/Makefile | 4 +- .../msm/vidc/{governors => }/fixedpoint.h | 0 .../media/platform/msm/vidc/governors/Kconfig | 6 - .../platform/msm/vidc/governors/Makefile | 9 - .../{governors => }/msm_vidc_ar50_dyn_gov.c | 192 +++++------------ .../vidc/{governors => }/msm_vidc_dyn_gov.c | 196 ++++++------------ .../platform/msm/vidc/msm_vidc_res_parse.c | 16 +- .../platform/msm/vidc/msm_vidc_resources.h | 5 +- drivers/media/platform/msm/vidc/venus_hfi.c | 146 ++----------- drivers/media/platform/msm/vidc/venus_hfi.h | 3 + 11 files changed, 148 insertions(+), 431 deletions(-) rename drivers/media/platform/msm/vidc/{governors => }/fixedpoint.h (100%) delete mode 100644 drivers/media/platform/msm/vidc/governors/Kconfig delete mode 100644 drivers/media/platform/msm/vidc/governors/Makefile rename drivers/media/platform/msm/vidc/{governors => }/msm_vidc_ar50_dyn_gov.c (87%) rename drivers/media/platform/msm/vidc/{governors => }/msm_vidc_dyn_gov.c (88%) diff --git a/drivers/media/platform/msm/vidc/Kconfig b/drivers/media/platform/msm/vidc/Kconfig index 7d31ba880b62..af46985494fb 100644 --- a/drivers/media/platform/msm/vidc/Kconfig +++ b/drivers/media/platform/msm/vidc/Kconfig @@ -6,5 +6,3 @@ menuconfig MSM_VIDC_LEGACY_V4L2 tristate "Qualcomm Technologies, Inc. MSM V4L2 based video driver" depends on ARCH_QCOM && VIDEO_V4L2 select VIDEOBUF2_CORE - -source "drivers/media/platform/msm/vidc/governors/Kconfig" diff --git a/drivers/media/platform/msm/vidc/Makefile b/drivers/media/platform/msm/vidc/Makefile index 0464ce7d4abc..57bf05ce5b22 100644 --- a/drivers/media/platform/msm/vidc/Makefile +++ b/drivers/media/platform/msm/vidc/Makefile @@ -10,6 +10,8 @@ msm-vidc-objs := msm_v4l2_vidc.o \ msm_cvp.o \ msm_smem.o \ msm_vidc_debug.o \ + msm_vidc_ar50_dyn_gov.o \ + msm_vidc_dyn_gov.o \ msm_vidc_res_parse.o \ venus_hfi.o \ hfi_response_handler.o \ @@ -18,5 +20,3 @@ msm-vidc-objs := msm_v4l2_vidc.o \ msm_vidc_clocks.o obj-$(CONFIG_MSM_VIDC_LEGACY_V4L2) := msm-vidc.o - -obj-$(CONFIG_MSM_VIDC_LEGACY_V4L2) += governors/ diff --git a/drivers/media/platform/msm/vidc/governors/fixedpoint.h b/drivers/media/platform/msm/vidc/fixedpoint.h similarity index 100% rename from drivers/media/platform/msm/vidc/governors/fixedpoint.h rename to drivers/media/platform/msm/vidc/fixedpoint.h diff --git a/drivers/media/platform/msm/vidc/governors/Kconfig b/drivers/media/platform/msm/vidc/governors/Kconfig deleted file mode 100644 index a8526c4441c9..000000000000 --- a/drivers/media/platform/msm/vidc/governors/Kconfig +++ /dev/null @@ -1,6 +0,0 @@ -menuconfig MSM_VIDC_LEGACY_GOVERNORS - tristate "Clock and bandwidth governors for QTI MSM V4L2 based video driver" - depends on MSM_VIDC_LEGACY_V4L2 && PM_DEVFREQ - help - Chooses a set of devfreq governors aimed at providing accurate bandwidth - or clock frequency values for MSM V4L2 video driver. diff --git a/drivers/media/platform/msm/vidc/governors/Makefile b/drivers/media/platform/msm/vidc/governors/Makefile deleted file mode 100644 index f8ae4549e1a9..000000000000 --- a/drivers/media/platform/msm/vidc/governors/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -ccflags-y := -I$(srctree)/drivers/devfreq/ \ - -I$(srctree)/drivers/media/platform/msm/vidc/ \ - -I$(srctree)/drivers/media/platform/msm/vidc/governors/ - -msm-vidc-dyn-gov-objs := msm_vidc_dyn_gov.o - -msm-vidc-ar50-dyn-gov-objs := msm_vidc_ar50_dyn_gov.o - -obj-$(CONFIG_MSM_VIDC_LEGACY_GOVERNORS) := msm-vidc-dyn-gov.o msm-vidc-ar50-dyn-gov.o diff --git a/drivers/media/platform/msm/vidc/governors/msm_vidc_ar50_dyn_gov.c b/drivers/media/platform/msm/vidc/msm_vidc_ar50_dyn_gov.c similarity index 87% rename from drivers/media/platform/msm/vidc/governors/msm_vidc_ar50_dyn_gov.c rename to drivers/media/platform/msm/vidc/msm_vidc_ar50_dyn_gov.c index fdf2b7ef0651..6f0e89cc4c0e 100644 --- a/drivers/media/platform/msm/vidc/governors/msm_vidc_ar50_dyn_gov.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_ar50_dyn_gov.c @@ -11,29 +11,24 @@ */ #include -#include "governor.h" +#include "msm_vidc_debug.h" #include "fixedpoint.h" #include "msm_vidc_internal.h" -#include "msm_vidc_debug.h" #include "vidc_hfi_api.h" #define COMPRESSION_RATIO_MAX 5 -static bool debug; -module_param(debug, bool, 0644); - -enum governor_mode { - GOVERNOR_DDR, - GOVERNOR_LLCC, -}; +static bool debug_ar50; +module_param(debug_ar50, bool, 0644); -struct governor { - enum governor_mode mode; - struct devfreq_governor devfreq_gov; +enum vidc_bus_type { + PERF, + DDR, + LLCC, }; /* - * Minimum dimensions that the governor is willing to calculate - * bandwidth for. This means that anything bandwidth(0, 0) == + * Minimum dimensions for which to calculate bandwidth. + * This means that anything bandwidth(0, 0) == * bandwidth(BASELINE_DIMENSIONS.width, BASELINE_DIMENSIONS.height) */ static const struct { @@ -43,15 +38,6 @@ static const struct { .height = 720, }; -/* - * These are hardcoded AB values that the governor votes for in certain - * situations, where a certain bus frequency is desired. It isn't exactly - * scalable since different platforms have different bus widths, but we'll - * deal with that in the future. - */ -static const unsigned long NOMINAL_BW_MBPS = 6000 /* ideally 320 Mhz */, - SVS_BW_MBPS = 2000 /* ideally 100 Mhz */; - /* 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) @@ -216,6 +202,16 @@ static struct lut { }, }; +static u32 get_type_frm_name(char *name) +{ + if (!strcmp(name, "venus-ar50-llcc")) + return LLCC; + else if (!strcmp(name, "venus-ar50-ddr")) + return DDR; + else + return PERF; +} + static struct lut const *__lut(int width, int height, int fps) { int frame_size = height * width, c = 0; @@ -288,7 +284,7 @@ static void __dump(struct dump dump[], int len) } static unsigned long __calculate_vpe(struct vidc_bus_vote_data *d, - enum governor_mode gm) + enum vidc_bus_type type) { return 0; } @@ -323,7 +319,7 @@ static int __bpp(enum hal_uncompressed_format f) } static unsigned long __calculate_decoder(struct vidc_bus_vote_data *d, - enum governor_mode gm) + enum vidc_bus_type type) { /* * XXX: Don't fool around with any of the hardcoded numbers unless you @@ -506,7 +502,7 @@ static unsigned long __calculate_decoder(struct vidc_bus_vote_data *d, llc.total = llc.dpb_read + llc.opb_read + ddr.total; /* Dump all the variables for easier debugging */ - if (debug) { + if (debug_ar50) { struct dump dump[] = { {"DECODER PARAMETERS", "", DUMP_HEADER_MAGIC}, {"LCU size", "%d", lcu_size}, @@ -568,11 +564,11 @@ static unsigned long __calculate_decoder(struct vidc_bus_vote_data *d, __dump(dump, ARRAY_SIZE(dump)); } - switch (gm) { - case GOVERNOR_DDR: + switch (type) { + case DDR: ret = kbps(fp_round(ddr.total)); break; - case GOVERNOR_LLCC: + case LLCC: ret = kbps(fp_round(llc.total)); break; default: @@ -583,7 +579,7 @@ static unsigned long __calculate_decoder(struct vidc_bus_vote_data *d, } static unsigned long __calculate_encoder(struct vidc_bus_vote_data *d, - enum governor_mode gm) + enum vidc_bus_type type) { /* * XXX: Don't fool around with any of the hardcoded numbers unless you @@ -792,7 +788,7 @@ static unsigned long __calculate_encoder(struct vidc_bus_vote_data *d, qsmmu_bw_overhead_factor = FP(1, 3, 100); ddr.total = fp_mult(ddr.total, qsmmu_bw_overhead_factor); - if (debug) { + if (debug_ar50) { struct dump dump[] = { {"ENCODER PARAMETERS", "", DUMP_HEADER_MAGIC}, {"width", "%d", width}, @@ -839,11 +835,11 @@ static unsigned long __calculate_encoder(struct vidc_bus_vote_data *d, __dump(dump, ARRAY_SIZE(dump)); } - switch (gm) { - case GOVERNOR_DDR: + switch (type) { + case DDR: ret = kbps(fp_round(ddr.total)); break; - case GOVERNOR_LLCC: + case LLCC: ret = kbps(fp_round(llc.total)); break; default: @@ -854,40 +850,34 @@ static unsigned long __calculate_encoder(struct vidc_bus_vote_data *d, } static unsigned long __calculate(struct vidc_bus_vote_data *d, - enum governor_mode gm) + enum vidc_bus_type type) { - unsigned long (*calc[])(struct vidc_bus_vote_data *, - enum governor_mode) = { - [HAL_VIDEO_DOMAIN_VPE] = __calculate_vpe, - [HAL_VIDEO_DOMAIN_ENCODER] = __calculate_encoder, - [HAL_VIDEO_DOMAIN_DECODER] = __calculate_decoder, - }; - - if (d->domain >= ARRAY_SIZE(calc)) { - dprintk(VIDC_ERR, "%s: invalid domain %d\n", - __func__, d->domain); - return 0; + unsigned long value = 0; + + switch (d->domain) { + case HAL_VIDEO_DOMAIN_VPE: + value = __calculate_vpe(d, type); + break; + case HAL_VIDEO_DOMAIN_ENCODER: + value = __calculate_encoder(d, type); + break; + case HAL_VIDEO_DOMAIN_DECODER: + value = __calculate_decoder(d, type); + break; + default: + dprintk(VIDC_ERR, "Unknown Domain"); } - return calc[d->domain](d, gm); -} + return value; +} -static int __get_target_freq(struct devfreq *dev, unsigned long *freq) +unsigned long __calc_bw_ar50(struct bus_info *bus, + struct msm_vidc_gov_data *vidc_data) { unsigned long ab_kbps = 0, c = 0; - struct devfreq_dev_status stats = {0}; - struct msm_vidc_gov_data *vidc_data = NULL; - struct governor *gov = NULL; - - if (!dev || !freq) - return -EINVAL; - - gov = container_of(dev->governor, - struct governor, devfreq_gov); - dev->profile->get_dev_status(dev->dev.parent, &stats); - vidc_data = (struct msm_vidc_gov_data *)stats.private_data; + enum vidc_bus_type type; - if (!vidc_data || !vidc_data->data_count) + if (!vidc_data || !vidc_data->data_count || !vidc_data->data) goto exit; for (c = 0; c < vidc_data->data_count; ++c) { @@ -897,82 +887,12 @@ static int __get_target_freq(struct devfreq *dev, unsigned long *freq) } } + type = get_type_frm_name(bus->name); + for (c = 0; c < vidc_data->data_count; ++c) - ab_kbps += __calculate(&vidc_data->data[c], gov->mode); + ab_kbps += __calculate(&vidc_data->data[c], type); exit: - *freq = clamp(ab_kbps, dev->min_freq, dev->max_freq ?: UINT_MAX); - trace_msm_vidc_perf_bus_vote(gov->devfreq_gov.name, *freq); - return 0; -} - -static int __event_handler(struct devfreq *devfreq, unsigned int event, - void *data) -{ - int rc = 0; - - if (!devfreq) - return -EINVAL; - - switch (event) { - case DEVFREQ_GOV_START: - mutex_lock(&devfreq->lock); - rc = update_devfreq(devfreq); - mutex_unlock(&devfreq->lock); - break; - } - - return rc; -} - -static struct governor governors[] = { - { - .mode = GOVERNOR_DDR, - .devfreq_gov = { - .name = "vidc-ar50-ddr", - .get_target_freq = __get_target_freq, - .event_handler = __event_handler, - }, - }, - { - .mode = GOVERNOR_LLCC, - .devfreq_gov = { - .name = "vidc-ar50-llcc", - .get_target_freq = __get_target_freq, - .event_handler = __event_handler, - }, - }, -}; - -static int __init msm_vidc_ar50_bw_gov_init(void) -{ - int c = 0, rc = 0; - - for (c = 0; c < ARRAY_SIZE(governors); ++c) { - dprintk(VIDC_DBG, "Adding governor %s\n", - governors[c].devfreq_gov.name); - - rc = devfreq_add_governor(&governors[c].devfreq_gov); - if (rc) { - dprintk(VIDC_ERR, "Error adding governor %s: %d\n", - governors[c].devfreq_gov.name, rc); - break; - } - } - - return rc; -} -module_init(msm_vidc_ar50_bw_gov_init); - -static void __exit msm_vidc_ar50_bw_gov_exit(void) -{ - int c = 0; - - for (c = 0; c < ARRAY_SIZE(governors); ++c) { - dprintk(VIDC_DBG, "Removing governor %s\n", - governors[c].devfreq_gov.name); - devfreq_remove_governor(&governors[c].devfreq_gov); - } + trace_msm_vidc_perf_bus_vote(bus->name, ab_kbps); + return ab_kbps; } -module_exit(msm_vidc_ar50_bw_gov_exit); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c b/drivers/media/platform/msm/vidc/msm_vidc_dyn_gov.c similarity index 88% rename from drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c rename to drivers/media/platform/msm/vidc/msm_vidc_dyn_gov.c index c434e864d6da..7571cda9f0e9 100644 --- a/drivers/media/platform/msm/vidc/governors/msm_vidc_dyn_gov.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_dyn_gov.c @@ -11,29 +11,24 @@ */ #include -#include "governor.h" +#include "msm_vidc_debug.h" #include "fixedpoint.h" #include "msm_vidc_internal.h" -#include "msm_vidc_debug.h" #include "vidc_hfi_api.h" #define COMPRESSION_RATIO_MAX 5 static bool debug; module_param(debug, bool, 0644); -enum governor_mode { - GOVERNOR_DDR, - GOVERNOR_LLCC, -}; - -struct governor { - enum governor_mode mode; - struct devfreq_governor devfreq_gov; +enum vidc_bus_type { + PERF, + DDR, + LLCC, }; /* - * Minimum dimensions that the governor is willing to calculate - * bandwidth for. This means that anything bandwidth(0, 0) == + * Minimum dimensions for which to calculate bandwidth. + * This means that anything bandwidth(0, 0) == * bandwidth(BASELINE_DIMENSIONS.width, BASELINE_DIMENSIONS.height) */ static const struct { @@ -43,15 +38,6 @@ static const struct { .height = 720, }; -/* - * These are hardcoded AB values that the governor votes for in certain - * situations, where a certain bus frequency is desired. It isn't exactly - * scalable since different platforms have different bus widths, but we'll - * deal with that in the future. - */ -const unsigned long NOMINAL_BW_MBPS = 6000 /* ideally 320 Mhz */, - SVS_BW_MBPS = 2000 /* ideally 100 Mhz */; - /* 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) @@ -216,6 +202,16 @@ static struct lut { }, }; +static 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; +} + static struct lut const *__lut(int width, int height, int fps) { int frame_size = height * width, c = 0; @@ -288,21 +284,21 @@ static void __dump(struct dump dump[], int len) } static unsigned long __calculate_vpe(struct vidc_bus_vote_data *d, - enum governor_mode gm) + enum vidc_bus_type type) { return 0; } static unsigned long __calculate_cvp(struct vidc_bus_vote_data *d, - enum governor_mode gm) + enum vidc_bus_type type) { unsigned long ret = 0; - switch (gm) { - case GOVERNOR_DDR: + switch (type) { + case DDR: ret = d->ddr_bw; break; - case GOVERNOR_LLCC: + case LLCC: ret = d->sys_cache_bw; break; default: @@ -343,7 +339,7 @@ static int __bpp(enum hal_uncompressed_format f) } static unsigned long __calculate_decoder(struct vidc_bus_vote_data *d, - enum governor_mode gm) + enum vidc_bus_type type) { /* * XXX: Don't fool around with any of the hardcoded numbers unless you @@ -583,11 +579,11 @@ static unsigned long __calculate_decoder(struct vidc_bus_vote_data *d, __dump(dump, ARRAY_SIZE(dump)); } - switch (gm) { - case GOVERNOR_DDR: + switch (type) { + case DDR: ret = kbps(fp_round(ddr.total)); break; - case GOVERNOR_LLCC: + case LLCC: ret = kbps(fp_round(llc.total)); break; default: @@ -598,7 +594,7 @@ static unsigned long __calculate_decoder(struct vidc_bus_vote_data *d, } static unsigned long __calculate_encoder(struct vidc_bus_vote_data *d, - enum governor_mode gm) + enum vidc_bus_type type) { /* * XXX: Don't fool around with any of the hardcoded numbers unless you @@ -880,11 +876,11 @@ static unsigned long __calculate_encoder(struct vidc_bus_vote_data *d, __dump(dump, ARRAY_SIZE(dump)); } - switch (gm) { - case GOVERNOR_DDR: + switch (type) { + case DDR: ret = kbps(fp_round(ddr.total)); break; - case GOVERNOR_LLCC: + case LLCC: ret = kbps(fp_round(llc.total)); break; default: @@ -895,41 +891,37 @@ static unsigned long __calculate_encoder(struct vidc_bus_vote_data *d, } static unsigned long __calculate(struct vidc_bus_vote_data *d, - enum governor_mode gm) + enum vidc_bus_type type) { - unsigned long (*calc[])(struct vidc_bus_vote_data *, - enum governor_mode) = { - [HAL_VIDEO_DOMAIN_VPE] = __calculate_vpe, - [HAL_VIDEO_DOMAIN_ENCODER] = __calculate_encoder, - [HAL_VIDEO_DOMAIN_DECODER] = __calculate_decoder, - [HAL_VIDEO_DOMAIN_CVP] = __calculate_cvp, - }; - - if (d->domain >= ARRAY_SIZE(calc)) { - dprintk(VIDC_ERR, "%s: invalid domain %d\n", - __func__, d->domain); - return 0; + unsigned long value = 0; + + switch (d->domain) { + case HAL_VIDEO_DOMAIN_VPE: + value = __calculate_vpe(d, type); + break; + case HAL_VIDEO_DOMAIN_ENCODER: + value = __calculate_encoder(d, type); + break; + case HAL_VIDEO_DOMAIN_DECODER: + value = __calculate_decoder(d, type); + break; + case HAL_VIDEO_DOMAIN_CVP: + value = __calculate_cvp(d, type); + break; + default: + dprintk(VIDC_ERR, "Unknown Domain"); } - return calc[d->domain](d, gm); -} + return value; +} -static int __get_target_freq(struct devfreq *dev, unsigned long *freq) +unsigned long __calc_bw(struct bus_info *bus, + struct msm_vidc_gov_data *vidc_data) { unsigned long ab_kbps = 0, c = 0; - struct devfreq_dev_status stats = {0}; - struct msm_vidc_gov_data *vidc_data = NULL; - struct governor *gov = NULL; - - if (!dev || !freq) - return -EINVAL; + enum vidc_bus_type type; - gov = container_of(dev->governor, - struct governor, devfreq_gov); - dev->profile->get_dev_status(dev->dev.parent, &stats); - vidc_data = (struct msm_vidc_gov_data *)stats.private_data; - - if (!vidc_data || !vidc_data->data_count) + if (!vidc_data || !vidc_data->data_count || !vidc_data->data) goto exit; for (c = 0; c < vidc_data->data_count; ++c) { @@ -939,82 +931,12 @@ static int __get_target_freq(struct devfreq *dev, unsigned long *freq) } } + type = get_type_frm_name(bus->name); + for (c = 0; c < vidc_data->data_count; ++c) - ab_kbps += __calculate(&vidc_data->data[c], gov->mode); + ab_kbps += __calculate(&vidc_data->data[c], type); exit: - *freq = clamp(ab_kbps, dev->min_freq, dev->max_freq ?: UINT_MAX); - trace_msm_vidc_perf_bus_vote(gov->devfreq_gov.name, *freq); - return 0; -} - -static int __event_handler(struct devfreq *devfreq, unsigned int event, - void *data) -{ - int rc = 0; - - if (!devfreq) - return -EINVAL; - - switch (event) { - case DEVFREQ_GOV_START: - mutex_lock(&devfreq->lock); - rc = update_devfreq(devfreq); - mutex_unlock(&devfreq->lock); - break; - } - - return rc; -} - -static struct governor governors[] = { - { - .mode = GOVERNOR_DDR, - .devfreq_gov = { - .name = "msm-vidc-ddr", - .get_target_freq = __get_target_freq, - .event_handler = __event_handler, - }, - }, - { - .mode = GOVERNOR_LLCC, - .devfreq_gov = { - .name = "msm-vidc-llcc", - .get_target_freq = __get_target_freq, - .event_handler = __event_handler, - }, - }, -}; - -static int __init msm_vidc_bw_gov_init(void) -{ - int c = 0, rc = 0; - - for (c = 0; c < ARRAY_SIZE(governors); ++c) { - dprintk(VIDC_DBG, "Adding governor %s\n", - governors[c].devfreq_gov.name); - - rc = devfreq_add_governor(&governors[c].devfreq_gov); - if (rc) { - dprintk(VIDC_ERR, "Error adding governor %s: %d\n", - governors[c].devfreq_gov.name, rc); - break; - } - } - - return rc; -} -module_init(msm_vidc_bw_gov_init); - -static void __exit msm_vidc_bw_gov_exit(void) -{ - int c = 0; - - for (c = 0; c < ARRAY_SIZE(governors); ++c) { - dprintk(VIDC_DBG, "Removing governor %s\n", - governors[c].devfreq_gov.name); - devfreq_remove_governor(&governors[c].devfreq_gov); - } + trace_msm_vidc_perf_bus_vote(bus->name, ab_kbps); + return ab_kbps; } -module_exit(msm_vidc_bw_gov_exit); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c index 31cc5c4ebf4b..a55ad394dfdc 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c @@ -436,16 +436,10 @@ static int msm_vidc_populate_bus(struct device *dev, goto err_bus; } - rc = of_property_read_string(dev->of_node, "qcom,bus-governor", - &bus->governor); - if (rc) { - rc = 0; - dprintk(VIDC_DBG, - "'qcom,bus-governor' not found, default to performance governor\n"); - bus->governor = PERF_GOV; - } + rc = of_property_read_string(dev->of_node, "qcom,mode", + &bus->mode); - if (!strcmp(bus->governor, PERF_GOV)) + if (!strcmp(bus->mode, PERF_GOV)) bus->is_prfm_gov_used = true; rc = of_property_read_u32_array(dev->of_node, "qcom,bus-range-kbps", @@ -463,8 +457,8 @@ static int msm_vidc_populate_bus(struct device *dev, buses->count++; bus->dev = dev; - dprintk(VIDC_DBG, "Found bus %s [%d->%d] with governor %s\n", - bus->name, bus->master, bus->slave, bus->governor); + dprintk(VIDC_DBG, "Found bus %s [%d->%d] with mode %s\n", + bus->name, bus->master, bus->slave, bus->mode); err_bus: return rc; } diff --git a/drivers/media/platform/msm/vidc/msm_vidc_resources.h b/drivers/media/platform/msm/vidc/msm_vidc_resources.h index 6475d87d5c4c..790e88c647f5 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_resources.h +++ b/drivers/media/platform/msm/vidc/msm_vidc_resources.h @@ -14,7 +14,6 @@ #ifndef __MSM_VIDC_RESOURCES_H__ #define __MSM_VIDC_RESOURCES_H__ -#include #include #include "msm_vidc.h" #include @@ -103,12 +102,10 @@ struct bus_info { int master; int slave; unsigned int range[2]; - const char *governor; struct device *dev; - struct devfreq_dev_profile devfreq_prof; - struct devfreq *devfreq; struct msm_bus_client_handle *client; bool is_prfm_gov_used; + const char *mode; }; struct bus_set { diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c index 83d54ceb26f3..9b601e0dc5f1 100644 --- a/drivers/media/platform/msm/vidc/venus_hfi.c +++ b/drivers/media/platform/msm/vidc/venus_hfi.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include @@ -985,84 +984,24 @@ static void __set_threshold_registers(struct venus_hfi_device *device) dprintk(VIDC_ERR, "Failed to restore threshold values\n"); } -static int __devfreq_target(struct device *devfreq_dev, - unsigned long *freq, u32 flags) +static int __vote_bandwidth(struct bus_info *bus, + unsigned long *freq) { int rc = 0; uint64_t ab = 0; - struct bus_info *bus = NULL, *temp = NULL; - struct venus_hfi_device *device = dev_get_drvdata(devfreq_dev); - venus_hfi_for_each_bus(device, temp) { - if (temp->dev == devfreq_dev) { - bus = temp; - break; - } - } - - if (!bus) { - rc = -EBADHANDLE; - goto err_unknown_device; - } - - /* - * Clamp for all non zero frequencies. This clamp is necessary to stop - * devfreq driver from spamming - Couldn't update frequency - logs, if - * the scaled ab value is not part of the frequency table. - */ if (*freq) *freq = clamp_t(typeof(*freq), *freq, bus->range[0], bus->range[1]); - /* we expect governors to provide values in kBps form, convert to Bps */ + /* Bus Driver expects values in Bps */ ab = *freq * 1000; + dprintk(VIDC_PROF, "Voting bus %s to ab %llu\n", bus->name, ab); rc = msm_bus_scale_update_bw(bus->client, ab, 0); - if (rc) { - dprintk(VIDC_ERR, "Failed voting bus %s to ab %llu\n: %d", + if (rc) + dprintk(VIDC_ERR, "Failed voting bus %s to ab %llu, rc=%d\n", bus->name, ab, rc); - goto err_unknown_device; - } - - dprintk(VIDC_PROF, "Voting bus %s to ab %llu\n", bus->name, ab); - - return 0; -err_unknown_device: - return rc; -} - -static int __devfreq_get_status(struct device *devfreq_dev, - struct devfreq_dev_status *stat) -{ - int rc = 0; - struct bus_info *bus = NULL, *temp = NULL; - struct venus_hfi_device *device = dev_get_drvdata(devfreq_dev); - - venus_hfi_for_each_bus(device, temp) { - if (temp->dev == devfreq_dev) { - bus = temp; - break; - } - } - - if (!bus) { - rc = -EBADHANDLE; - goto err_unknown_device; - } - - *stat = (struct devfreq_dev_status) { - .private_data = &device->bus_vote, - /* - * Put in dummy place holder values for upstream govs, our - * custom gov only needs .private_data. We should fill this in - * properly if we can actually measure busy_time accurately - * (which we can't at the moment) - */ - .total_time = 1, - .busy_time = 1, - .current_frequency = 0, - }; -err_unknown_device: return rc; } @@ -1070,21 +1009,19 @@ static int __unvote_buses(struct venus_hfi_device *device) { int rc = 0; struct bus_info *bus = NULL; + unsigned long freq = 0, zero = 0; kfree(device->bus_vote.data); device->bus_vote.data = NULL; device->bus_vote.data_count = 0; venus_hfi_for_each_bus(device, bus) { - unsigned long zero = 0; - if (!bus->is_prfm_gov_used) { - mutex_lock(&bus->devfreq->lock); - rc = update_devfreq(bus->devfreq); - mutex_unlock(&bus->devfreq->lock); + freq = __calc_bw(bus, &device->bus_vote); + rc = __vote_bandwidth(bus, &freq); } else - rc = __devfreq_target(bus->dev, &zero, 0); + rc = __vote_bandwidth(bus, &zero); if (rc) goto err_unknown_device; @@ -1100,6 +1037,7 @@ static int __vote_buses(struct venus_hfi_device *device, int rc = 0; struct bus_info *bus = NULL; struct vidc_bus_vote_data *new_data = NULL; + unsigned long freq = 0; if (!num_data) { dprintk(VIDC_DBG, "No vote data available\n"); @@ -1122,17 +1060,18 @@ static int __vote_buses(struct venus_hfi_device *device, device->bus_vote.data_count = num_data; venus_hfi_for_each_bus(device, bus) { - if (bus && bus->devfreq) { + if (bus) { if (!bus->is_prfm_gov_used) { - mutex_lock(&bus->devfreq->lock); - rc = update_devfreq(bus->devfreq); - mutex_unlock(&bus->devfreq->lock); - if (rc) - goto err_no_mem; + freq = __calc_bw(bus, &device->bus_vote); } else { - bus->devfreq->nb.notifier_call( - &bus->devfreq->nb, 0, NULL); + freq = bus->range[1]; + dprintk(VIDC_DBG, "%s %s perf Vote %u\n", + __func__, bus->name, + bus->range[1]); } + rc = __vote_bandwidth(bus, &freq); + } else { + dprintk(VIDC_ERR, "No BUS to Vote\n"); } } @@ -4071,10 +4010,6 @@ static void __deinit_bus(struct venus_hfi_device *device) device->bus_vote = DEFAULT_BUS_VOTE; venus_hfi_for_each_bus_reverse(device, bus) { - devfreq_remove_device(bus->devfreq); - bus->devfreq = NULL; - dev_set_drvdata(bus->dev, NULL); - msm_bus_scale_unregister(bus->client); bus->client = NULL; } @@ -4089,33 +4024,14 @@ static int __init_bus(struct venus_hfi_device *device) return -EINVAL; venus_hfi_for_each_bus(device, bus) { - struct devfreq_dev_profile profile = { - .initial_freq = 0, - .polling_ms = INT_MAX, - .freq_table = NULL, - .max_state = 0, - .target = __devfreq_target, - .get_dev_status = __devfreq_get_status, - .exit = NULL, - }; - - if (!strcmp(bus->governor, "msm-vidc-llcc")) { + if (!strcmp(bus->mode, "msm-vidc-llcc")) { if (msm_vidc_syscache_disable) { dprintk(VIDC_DBG, "Skipping LLC bus init %s: %s\n", - bus->name, bus->governor); + bus->name, bus->mode); continue; } } - - /* - * This is stupid, but there's no other easy way to ahold - * of struct bus_info in venus_hfi_devfreq_*() - */ - WARN(dev_get_drvdata(bus->dev), "%s's drvdata already set\n", - dev_name(bus->dev)); - dev_set_drvdata(bus->dev, device); - bus->client = msm_bus_scale_register(bus->master, bus->slave, bus->name, false); if (IS_ERR_OR_NULL(bus->client)) { @@ -4125,24 +4041,6 @@ static int __init_bus(struct venus_hfi_device *device) bus->client = NULL; goto err_add_dev; } - - bus->devfreq_prof = profile; - bus->devfreq = devfreq_add_device(bus->dev, - &bus->devfreq_prof, bus->governor, NULL); - if (IS_ERR_OR_NULL(bus->devfreq)) { - rc = PTR_ERR(bus->devfreq) ?: -EBADHANDLE; - dprintk(VIDC_ERR, - "Failed to add devfreq device for bus %s and governor %s: %d\n", - bus->name, bus->governor, rc); - bus->devfreq = NULL; - goto err_add_dev; - } - - /* - * Devfreq starts monitoring immediately, since we are just - * initializing stuff at this point, force it to suspend - */ - devfreq_suspend_device(bus->devfreq); } return 0; diff --git a/drivers/media/platform/msm/vidc/venus_hfi.h b/drivers/media/platform/msm/vidc/venus_hfi.h index 1ba14db390b7..04ae650ac9f3 100644 --- a/drivers/media/platform/msm/vidc/venus_hfi.h +++ b/drivers/media/platform/msm/vidc/venus_hfi.h @@ -50,6 +50,9 @@ #define VIDC_MAX_SUBCACHES 4 #define VIDC_MAX_SUBCACHE_SIZE 52 +extern unsigned long __calc_bw(struct bus_info *bus, + struct msm_vidc_gov_data *vidc_data); + struct hfi_queue_table_header { u32 qtbl_version; u32 qtbl_size; From 5bf465fb710c435516bc82040f8aa91446c33960 Mon Sep 17 00:00:00 2001 From: Amit Shekhar Date: Fri, 19 Apr 2019 17:08:30 -0700 Subject: [PATCH 132/356] msm: vidc: avoid null pointer dereference during bus voting Avoid null pointer dereference to fix video SSR usecase failures. Change-Id: I8bf00673ed9fb2e013bd2c5e8be8860d9d741ec4 CRs-Fixed: 2438294 Signed-off-by: Amit Shekhar --- drivers/media/platform/msm/vidc/venus_hfi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c index 9b601e0dc5f1..5e09145eb0f6 100644 --- a/drivers/media/platform/msm/vidc/venus_hfi.c +++ b/drivers/media/platform/msm/vidc/venus_hfi.c @@ -1060,7 +1060,7 @@ static int __vote_buses(struct venus_hfi_device *device, device->bus_vote.data_count = num_data; venus_hfi_for_each_bus(device, bus) { - if (bus) { + if (bus && bus->client) { if (!bus->is_prfm_gov_used) { freq = __calc_bw(bus, &device->bus_vote); } else { From 303c25569a1a8ca29547abc87a232bc95f28b7ec Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Wed, 23 Aug 2023 17:11:43 +0000 Subject: [PATCH 133/356] msm: vidc: Allow to use ar50 bw governor --- drivers/media/platform/msm/vidc/msm_vidc_res_parse.c | 3 +++ drivers/media/platform/msm/vidc/msm_vidc_resources.h | 1 + drivers/media/platform/msm/vidc/venus_hfi.c | 10 ++++++++-- drivers/media/platform/msm/vidc/venus_hfi.h | 2 ++ 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c index a55ad394dfdc..c60ead7eb47f 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_res_parse.c @@ -442,6 +442,9 @@ static int msm_vidc_populate_bus(struct device *dev, if (!strcmp(bus->mode, PERF_GOV)) bus->is_prfm_gov_used = true; + if (strstr(bus->mode, "ar50")) + bus->is_ar50_gov_used = true; + rc = of_property_read_u32_array(dev->of_node, "qcom,bus-range-kbps", range, ARRAY_SIZE(range)); if (rc) { diff --git a/drivers/media/platform/msm/vidc/msm_vidc_resources.h b/drivers/media/platform/msm/vidc/msm_vidc_resources.h index 790e88c647f5..b85131e1c527 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_resources.h +++ b/drivers/media/platform/msm/vidc/msm_vidc_resources.h @@ -104,6 +104,7 @@ struct bus_info { unsigned int range[2]; struct device *dev; struct msm_bus_client_handle *client; + bool is_ar50_gov_used; bool is_prfm_gov_used; const char *mode; }; diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c index 5e09145eb0f6..a9e70ea37edd 100644 --- a/drivers/media/platform/msm/vidc/venus_hfi.c +++ b/drivers/media/platform/msm/vidc/venus_hfi.c @@ -1017,7 +1017,10 @@ static int __unvote_buses(struct venus_hfi_device *device) venus_hfi_for_each_bus(device, bus) { if (!bus->is_prfm_gov_used) { - freq = __calc_bw(bus, &device->bus_vote); + if (bus->is_ar50_gov_used) + freq = __calc_bw_ar50(bus, &device->bus_vote); + else + freq = __calc_bw(bus, &device->bus_vote); rc = __vote_bandwidth(bus, &freq); } else @@ -1062,7 +1065,10 @@ static int __vote_buses(struct venus_hfi_device *device, venus_hfi_for_each_bus(device, bus) { if (bus && bus->client) { if (!bus->is_prfm_gov_used) { - freq = __calc_bw(bus, &device->bus_vote); + if (bus->is_ar50_gov_used) + freq = __calc_bw_ar50(bus, &device->bus_vote); + else + freq = __calc_bw(bus, &device->bus_vote); } else { freq = bus->range[1]; dprintk(VIDC_DBG, "%s %s perf Vote %u\n", diff --git a/drivers/media/platform/msm/vidc/venus_hfi.h b/drivers/media/platform/msm/vidc/venus_hfi.h index 04ae650ac9f3..1d6d0e033a23 100644 --- a/drivers/media/platform/msm/vidc/venus_hfi.h +++ b/drivers/media/platform/msm/vidc/venus_hfi.h @@ -52,6 +52,8 @@ extern unsigned long __calc_bw(struct bus_info *bus, struct msm_vidc_gov_data *vidc_data); +extern unsigned long __calc_bw_ar50(struct bus_info *bus, + struct msm_vidc_gov_data *vidc_data); struct hfi_queue_table_header { u32 qtbl_version; From a8926451d78b769109d2ac665b75ff8f0ccf4def Mon Sep 17 00:00:00 2001 From: "Angelo G. Del Regno" Date: Tue, 4 Jun 2019 10:35:23 +0200 Subject: [PATCH 134/356] media: msm: vidc: Add clock configuration function for VPU4 These register writes were missing on the VPU4 clock-on config, but they are needed for some SoCs to correctly initialize the Venus. --- drivers/media/platform/msm/vidc/venus_hfi.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c index a9e70ea37edd..96b3e1c97bd9 100644 --- a/drivers/media/platform/msm/vidc/venus_hfi.c +++ b/drivers/media/platform/msm/vidc/venus_hfi.c @@ -113,6 +113,7 @@ static int __power_collapse(struct venus_hfi_device *device, bool force); static int venus_hfi_noc_error_info(void *dev); static void interrupt_init_vpu4(struct venus_hfi_device *device); +static void clock_config_on_enable_vpu4(struct venus_hfi_device *device); static void interrupt_init_vpu5(struct venus_hfi_device *device); static void setup_dsp_uc_memmap_vpu5(struct venus_hfi_device *device); static void clock_config_on_enable_vpu5(struct venus_hfi_device *device); @@ -120,7 +121,7 @@ static void clock_config_on_enable_vpu5(struct venus_hfi_device *device); struct venus_hfi_vpu_ops vpu4_ops = { .interrupt_init = interrupt_init_vpu4, .setup_dsp_uc_memmap = NULL, - .clock_config_on_enable = NULL, + .clock_config_on_enable = clock_config_on_enable_vpu4, }; struct venus_hfi_vpu_ops vpu5_ops = { @@ -4560,6 +4561,12 @@ static void interrupt_init_vpu4(struct venus_hfi_device *device) VIDC_WRAPPER_INTR_MASK_A2HVCODEC_BMSK); } +static void clock_config_on_enable_vpu4(struct venus_hfi_device *device) +{ + __write_register(device, VIDC_WRAPPER_CLOCK_CONFIG, 0); + __write_register(device, VIDC_WRAPPER_CPU_CLOCK_CONFIG, 0); +} + static void setup_dsp_uc_memmap_vpu5(struct venus_hfi_device *device) { /* initialize DSP QTBL & UCREGION with CPU queues */ From 27b51100b9a26e66180a6c410ebea5994832a3cd Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Fri, 22 Nov 2019 14:21:58 +0100 Subject: [PATCH 135/356] msm: vidc: Add platform exclusions for unsupported features Legacy SoCs have got old VE firmwares and some of the features in this vidc driver release are unsupported by these. We need it working as soon as possible, so adopt this dirty way of dealing with it. --- drivers/media/platform/msm/vidc/msm_vdec.c | 10 ++++++++-- drivers/media/platform/msm/vidc/msm_venc.c | 4 ++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c index ecbc73c54920..f0c40928aa6e 100644 --- a/drivers/media/platform/msm/vidc/msm_vdec.c +++ b/drivers/media/platform/msm/vidc/msm_vdec.c @@ -83,8 +83,10 @@ static const char *const vp9_level[] = { "4.1", "5.0", "5.1", +#ifdef VDEC_VP9_LEVEL61_AVAILABLE "6.0", "6.1", +#endif }; static const char *const mpeg2_profile[] = { @@ -252,8 +254,8 @@ static struct msm_vidc_ctrl msm_vdec_ctrls[] = { .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, + .maximum = V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_51, + .default_value = V4L2_MPEG_VIDC_VIDEO_VP9_LEVEL_51, .menu_skip_mask = 0, .qmenu = vp9_level, .flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY, @@ -597,7 +599,9 @@ static bool msm_vidc_check_for_vp9d_overload(struct msm_vidc_core *core) int msm_vdec_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f) { struct msm_vidc_format *fmt = NULL; +#ifdef VDEC_FORMAT_CONSTRAINTS_SUPPORTED struct msm_vidc_format_constraint *fmt_constraint = NULL; +#endif struct hal_frame_size frame_sz; unsigned int extra_idx = 0; int rc = 0; @@ -645,6 +649,7 @@ int msm_vdec_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f) msm_comm_get_hal_output_buffer(inst), f->fmt.pix_mp.pixelformat); +#ifdef VDEC_FORMAT_CONSTRAINTS_SUPPORTED fmt_constraint = msm_comm_get_pixel_fmt_constraints(dec_pix_format_constraints, ARRAY_SIZE(dec_pix_format_constraints), @@ -666,6 +671,7 @@ int msm_vdec_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f) goto err_invalid_fmt; } } +#endif inst->clk_data.opb_fourcc = f->fmt.pix_mp.pixelformat; if (msm_comm_get_stream_output_mode(inst) == diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c index 135a513989a7..a9e37f20b8b5 100644 --- a/drivers/media/platform/msm/vidc/msm_venc.c +++ b/drivers/media/platform/msm/vidc/msm_venc.c @@ -1162,6 +1162,7 @@ static struct msm_vidc_ctrl msm_venc_ctrls[] = { ), .qmenu = mpeg_video_stream_format, }, +#ifdef VENC_BITRATE_SAVINGS_AVAILABLE { .id = V4L2_CID_MPEG_VIDC_VENC_BITRATE_SAVINGS, .name = "Enable/Disable bitrate savings", @@ -1171,6 +1172,8 @@ static struct msm_vidc_ctrl msm_venc_ctrls[] = { .default_value = V4L2_MPEG_MSM_VIDC_ENABLE, .step = 1, }, +#endif +#ifdef VENC_ROI_TYPE_AVAILABLE { .id = V4L2_CID_MPEG_VIDC_VIDEO_ROI_TYPE, .name = "ROI Type", @@ -1185,6 +1188,7 @@ static struct msm_vidc_ctrl msm_venc_ctrls[] = { ), .qmenu = roi_map_type, }, +#endif { .id = V4L2_CID_MPEG_VIDC_VENC_COMPLEXITY, .name = "Encoder complexity", From 3c032ba96523dd243f507edcf6b1c3d7f5aeb1ea Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Mon, 25 Nov 2019 13:33:54 +0100 Subject: [PATCH 136/356] media: msm: vidc: platform: Fix sdm845 properties Add fw cycles and fw-vpp-cycles for correct calculation of HFR and VPP usecases. Also, fix the power collapse delay and hw response timeout for older firmwares. --- .../media/platform/msm/vidc/msm_vidc_platform.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/msm/vidc/msm_vidc_platform.c b/drivers/media/platform/msm/vidc/msm_vidc_platform.c index 0470055e24b3..16ff0836ff63 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_platform.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_platform.c @@ -652,7 +652,7 @@ static struct msm_vidc_common_data sdm845_common_data[] = { }, { .key = "qcom,max-secure-instances", - .value = 3, + .value = 2, }, { .key = "qcom,max-hw-load", @@ -676,11 +676,11 @@ static struct msm_vidc_common_data sdm845_common_data[] = { }, { .key = "qcom,power-collapse-delay", - .value = 500, + .value = 1500, }, { .key = "qcom,hw-resp-timeout", - .value = 250, + .value = 1000, }, { .key = "qcom,debug-timeout", @@ -690,6 +690,14 @@ static struct msm_vidc_common_data sdm845_common_data[] = { .key = "qcom,dcvs", .value = 1, }, + { + .key = "qcom,fw-cycles", + .value = 733003, + }, + { + .key = "qcom,fw-vpp-cycles", + .value = 225975, + }, }; static struct msm_vidc_common_data sdm670_common_data_v0[] = { From f1f8432ef3524e70699b303f242de1dc31ee9a77 Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Wed, 27 Nov 2019 13:13:07 +0100 Subject: [PATCH 137/356] uapi: media: msm_vidc_utils: Compatibility for old Venus MISR struct Some targets need to use a different structure for the MISR informations, since that goes back and forth to the Venus firmware, which is old on these targets and obviously cannot understand a different struct when sending/receiving packed data. --- include/uapi/media/msm_vidc_utils.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/include/uapi/media/msm_vidc_utils.h b/include/uapi/media/msm_vidc_utils.h index 67e1289a9cbb..c7a304add779 100644 --- a/include/uapi/media/msm_vidc_utils.h +++ b/include/uapi/media/msm_vidc_utils.h @@ -4,6 +4,10 @@ #include +#if defined(CONFIG_ARCH_SDM845) +#define VENUS_USES_LEGACY_MISR_INFO +#endif + #define MSM_VIDC_HAL_INTERLACE_COLOR_FORMAT_NV12 0x2 #define MSM_VIDC_HAL_INTERLACE_COLOR_FORMAT_NV12_UBWC 0x8002 #define MSM_VIDC_EXTRADATA_FRAME_QP_ADV 0x1 @@ -67,6 +71,14 @@ struct msm_vidc_input_crop_payload { unsigned int height; }; +#ifdef VENUS_USES_LEGACY_MISR_INFO +struct msm_vidc_misr_info { + unsigned int misr_dpb_luma; + unsigned int misr_dpb_chroma; + unsigned int misr_opb_luma; + unsigned int misr_opb_chroma; +}; +#else struct msm_vidc_misr_info { unsigned int misr_set; unsigned int misr_dpb_luma[8]; @@ -74,6 +86,8 @@ struct msm_vidc_misr_info { unsigned int misr_opb_luma[8]; unsigned int misr_opb_chroma[8]; }; +#endif + struct msm_vidc_output_crop_payload { unsigned int size; unsigned int version; From 1338b39f60ff701a5d7911f065cf73d27e358f7c Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Fri, 9 Jun 2023 02:49:49 +0000 Subject: [PATCH 138/356] Revert "msm: media: uapi: Redefine NV12 format with different alignment" This reverts commit 4e5d64083e8fb75ef05c7107a3e6027dabc5e606. --- include/uapi/media/msm_media_info.h | 43 ++++++----------------------- 1 file changed, 8 insertions(+), 35 deletions(-) diff --git a/include/uapi/media/msm_media_info.h b/include/uapi/media/msm_media_info.h index 5c309676a9ef..3b9793e4a33a 100644 --- a/include/uapi/media/msm_media_info.h +++ b/include/uapi/media/msm_media_info.h @@ -2,23 +2,6 @@ #ifndef __MSM_MEDIA_INFO_H__ #define __MSM_MEDIA_INFO_H__ -#include - -#if __BITS_PER_LONG == 64 -#define NV12_STRIDE_ALIGNMENT 512 -#define NV12_SCANLINE_ALIGNMENT 512 -#else -#define NV12_STRIDE_ALIGNMENT 128 -#define NV12_SCANLINE_ALIGNMENT 32 -#endif - -#ifdef VENUS_USE_64BIT_ALIGNMENT -#undef NV12_STRIDE_ALIGNMENT -#undef NV12_SCANLINE_ALIGNMENT -#define NV12_STRIDE_ALIGNMENT 512 -#define NV12_SCANLINE_ALIGNMENT 512 -#endif - /* Width and Height should be multiple of 16 */ #define INTERLACE_WIDTH_MAX 1920 #define INTERLACE_HEIGHT_MAX 1920 @@ -62,10 +45,10 @@ enum color_fmts { * . . . . . . . . . . . . . . . . V * . . . . . . . . . . . . . . . . --> Buffer size alignment * - * Y_Stride : Width aligned to 512 or 128 - * UV_Stride : Width aligned to 512 or 128 - * Y_Scanlines: Height aligned to 512 or 32 - * UV_Scanlines: Height/2 aligned to 256 or 16 + * Y_Stride : Width aligned to 512 + * UV_Stride : Width aligned to 512 + * Y_Scanlines: Height aligned to 512 + * UV_Scanlines: Height/2 aligned to 256 * Total size = align(Y_Stride * Y_Scanlines * + UV_Stride * UV_Scanlines, 4096) */ @@ -132,10 +115,10 @@ enum color_fmts { * . . . . . . . . . . . . . . . . V * . . . . . . . . . . . . . . . . --> Padding & Buffer size alignment * - * Y_Stride : Width aligned to 512 or 128 - * UV_Stride : Width aligned to 512 or 128 - * Y_Scanlines: Height aligned to 512 or 32 - * UV_Scanlines: Height/2 aligned to 256 or 16 + * Y_Stride : Width aligned to 512 + * UV_Stride : Width aligned to 512 + * Y_Scanlines: Height aligned to 512 + * UV_Scanlines: Height/2 aligned to 256 * Total size = align(Y_Stride * Y_Scanlines * + UV_Stride * UV_Scanlines, 4096) */ @@ -846,9 +829,6 @@ static inline unsigned int VENUS_Y_STRIDE(unsigned int color_fmt, switch (color_fmt) { case COLOR_FMT_NV12: case COLOR_FMT_NV21: - alignment = NV12_STRIDE_ALIGNMENT; - stride = MSM_MEDIA_ALIGN(width, alignment); - break; case COLOR_FMT_NV12_512: alignment = 512; stride = MSM_MEDIA_ALIGN(width, alignment); @@ -893,9 +873,6 @@ static inline unsigned int VENUS_UV_STRIDE(unsigned int color_fmt, switch (color_fmt) { case COLOR_FMT_NV21: case COLOR_FMT_NV12: - alignment = NV12_STRIDE_ALIGNMENT; - stride = MSM_MEDIA_ALIGN(width, alignment); - break; case COLOR_FMT_NV12_512: alignment = 512; stride = MSM_MEDIA_ALIGN(width, alignment); @@ -940,8 +917,6 @@ static inline unsigned int VENUS_Y_SCANLINES(unsigned int color_fmt, switch (color_fmt) { case COLOR_FMT_NV12: case COLOR_FMT_NV21: - alignment = NV12_SCANLINE_ALIGNMENT; - break; case COLOR_FMT_NV12_512: alignment = 512; break; @@ -980,8 +955,6 @@ static inline unsigned int VENUS_UV_SCANLINES(unsigned int color_fmt, switch (color_fmt) { case COLOR_FMT_NV21: case COLOR_FMT_NV12: - alignment = NV12_SCANLINE_ALIGNMENT/2; - break; case COLOR_FMT_NV12_512: alignment = 256; break; From 6e010f57600a6562f821bf75af24c901a38aa95f Mon Sep 17 00:00:00 2001 From: Suprith Malligere Shankaregowda Date: Thu, 15 Oct 2020 10:38:29 +0530 Subject: [PATCH 139/356] msm: vidc: Use older alignments(128x32) for NV12 format Use older alignments(128x32) for NV12 format. Change-Id: Ieac31148a8a9120b36e6d290f1384d6aacc06ec2 --- include/uapi/media/msm_media_info.h | 32 ++++++++++++++--------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/include/uapi/media/msm_media_info.h b/include/uapi/media/msm_media_info.h index 3b9793e4a33a..9d0a0a25db43 100644 --- a/include/uapi/media/msm_media_info.h +++ b/include/uapi/media/msm_media_info.h @@ -45,10 +45,10 @@ enum color_fmts { * . . . . . . . . . . . . . . . . V * . . . . . . . . . . . . . . . . --> Buffer size alignment * - * Y_Stride : Width aligned to 512 - * UV_Stride : Width aligned to 512 - * Y_Scanlines: Height aligned to 512 - * UV_Scanlines: Height/2 aligned to 256 + * Y_Stride : Width aligned to 128 + * UV_Stride : Width aligned to 128 + * Y_Scanlines: Height aligned to 32 + * UV_Scanlines: Height/2 aligned to 16 * Total size = align(Y_Stride * Y_Scanlines * + UV_Stride * UV_Scanlines, 4096) */ @@ -115,10 +115,10 @@ enum color_fmts { * . . . . . . . . . . . . . . . . V * . . . . . . . . . . . . . . . . --> Padding & Buffer size alignment * - * Y_Stride : Width aligned to 512 - * UV_Stride : Width aligned to 512 - * Y_Scanlines: Height aligned to 512 - * UV_Scanlines: Height/2 aligned to 256 + * Y_Stride : Width aligned to 128 + * UV_Stride : Width aligned to 128 + * Y_Scanlines: Height aligned to 32 + * UV_Scanlines: Height/2 aligned to 16 * Total size = align(Y_Stride * Y_Scanlines * + UV_Stride * UV_Scanlines, 4096) */ @@ -827,12 +827,12 @@ static inline unsigned int VENUS_Y_STRIDE(unsigned int color_fmt, goto invalid_input; switch (color_fmt) { - case COLOR_FMT_NV12: - case COLOR_FMT_NV21: case COLOR_FMT_NV12_512: alignment = 512; stride = MSM_MEDIA_ALIGN(width, alignment); break; + case COLOR_FMT_NV21: + case COLOR_FMT_NV12: case COLOR_FMT_NV12_128: case COLOR_FMT_NV12_UBWC: alignment = 128; @@ -871,12 +871,12 @@ static inline unsigned int VENUS_UV_STRIDE(unsigned int color_fmt, goto invalid_input; switch (color_fmt) { - case COLOR_FMT_NV21: - case COLOR_FMT_NV12: case COLOR_FMT_NV12_512: alignment = 512; stride = MSM_MEDIA_ALIGN(width, alignment); break; + case COLOR_FMT_NV21: + case COLOR_FMT_NV12: case COLOR_FMT_NV12_128: case COLOR_FMT_NV12_UBWC: alignment = 128; @@ -915,11 +915,11 @@ static inline unsigned int VENUS_Y_SCANLINES(unsigned int color_fmt, goto invalid_input; switch (color_fmt) { - case COLOR_FMT_NV12: - case COLOR_FMT_NV21: case COLOR_FMT_NV12_512: alignment = 512; break; + case COLOR_FMT_NV21: + case COLOR_FMT_NV12: case COLOR_FMT_NV12_128: case COLOR_FMT_NV12_UBWC: case COLOR_FMT_P010: @@ -953,11 +953,11 @@ static inline unsigned int VENUS_UV_SCANLINES(unsigned int color_fmt, goto invalid_input; switch (color_fmt) { - case COLOR_FMT_NV21: - case COLOR_FMT_NV12: case COLOR_FMT_NV12_512: alignment = 256; break; + case COLOR_FMT_NV21: + case COLOR_FMT_NV12: case COLOR_FMT_NV12_128: case COLOR_FMT_NV12_BPP10_UBWC: case COLOR_FMT_P010_UBWC: From 75ba2934a973087d8d99031ad9cceee3525a706b Mon Sep 17 00:00:00 2001 From: Maheshwar Ajja Date: Mon, 17 Jun 2019 19:53:50 -0700 Subject: [PATCH 140/356] msm: vidc: do not allow queue buffer in flush Client is not supposed to queue buffer while driver is in flush. Return error if client queue buffer in flush to avoid possible deadlock issues in driver due to release buffer reference event processing. Change-Id: Ica2ff40e428f82b9f6d3aa1314f7bf7d322375bd Signed-off-by: Maheshwar Ajja --- drivers/media/platform/msm/vidc/msm_vidc.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c index cd5823ab0598..6d59e43e447d 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc.c +++ b/drivers/media/platform/msm/vidc/msm_vidc.c @@ -529,6 +529,11 @@ int msm_vidc_qbuf(void *instance, struct v4l2_buffer *b) } mutex_lock(&q->lock); + if (inst->in_flush && is_decode_session(inst) && + b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + dprintk(VIDC_ERR, "%s: in flush, discarding qbuf\n", __func__); + return -EINVAL; + } for (i = 0; i < b->length; i++) { b->m.planes[i].m.fd = b->m.planes[i].reserved[0]; From 1f4703f2310c2c6fd3441505412e816d459692fe Mon Sep 17 00:00:00 2001 From: Govindaraj Rajagopal Date: Wed, 31 Jul 2019 20:17:08 +0530 Subject: [PATCH 141/356] msm: vidc: add check to ensure buffer size is 4K aligned Input and output buffer size must be 4K aligned for both encoder and decoder session. So reject the session during msm_vidc_qbuf, if alloc_len is not 4K aligned. Change-Id: If555f26f1658ce50e12a8533cb9d59134da0aa81 Signed-off-by: Govindaraj Rajagopal --- drivers/media/platform/msm/vidc/msm_vidc.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c index 6d59e43e447d..bede8145b796 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc.c +++ b/drivers/media/platform/msm/vidc/msm_vidc.c @@ -521,6 +521,12 @@ int msm_vidc_qbuf(void *instance, struct v4l2_buffer *b) return -EINVAL; } + if (!IS_ALIGNED(b->m.planes[0].length, SZ_4K)) { + dprintk(VIDC_ERR, "qbuf: %x: buffer size not 4K aligned - %u\n", + hash32_ptr(inst->session), b->m.planes[0].length); + return -EINVAL; + } + q = msm_comm_get_vb2q(inst, b->type); if (!q) { dprintk(VIDC_ERR, From 519aa928fa778915d56b51290f27386d34ddcb17 Mon Sep 17 00:00:00 2001 From: Govindaraj Rajagopal Date: Fri, 2 Aug 2019 15:47:19 +0530 Subject: [PATCH 142/356] msm: vidc: do not allow qbuf during flush 1. Don't allow qbuf (etb & ftb), if flush is issued to (encoder & decoder) input port. 2. Don't allow qbuf (etb & ftb), if flush is issued to encoder output port 3. Don't qbuf (ftb), if flush is issued to decoder output port 4. Allow qbuf (etb), if flush is issued to decoder output port to handle decoder reconfig. Change-Id: I08a6a10612cc1a14ad164c55c5c8e54550c84845 Signed-off-by: Govindaraj Rajagopal --- drivers/media/platform/msm/vidc/msm_vidc.c | 7 +++-- .../media/platform/msm/vidc/msm_vidc_common.c | 28 +++++++++++++------ .../platform/msm/vidc/msm_vidc_internal.h | 1 + 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c index bede8145b796..4885ac07d291 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc.c +++ b/drivers/media/platform/msm/vidc/msm_vidc.c @@ -535,9 +535,10 @@ int msm_vidc_qbuf(void *instance, struct v4l2_buffer *b) } mutex_lock(&q->lock); - if (inst->in_flush && is_decode_session(inst) && - b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - dprintk(VIDC_ERR, "%s: in flush, discarding qbuf\n", __func__); + if ((inst->out_flush && b->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) || inst->in_flush) { + dprintk(VIDC_ERR, + "%s: %x: in flush, discarding qbuf, type %u, index %u\n", + __func__, hash32_ptr(inst->session), b->type, b->index); return -EINVAL; } diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c index 631b3f890139..82d25ee75e3b 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c @@ -2100,19 +2100,22 @@ static void handle_session_flush(enum hal_command_response cmd, void *data) } } } - inst->in_flush = false; 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_QCOM_CMD_FLUSH_OUTPUT; break; case HAL_FLUSH_OUTPUT: + inst->out_flush = false; ptr[0] = V4L2_QCOM_CMD_FLUSH_CAPTURE; break; case HAL_FLUSH_ALL: + inst->in_flush = false; + inst->out_flush = false; ptr[0] |= V4L2_QCOM_CMD_FLUSH_CAPTURE; ptr[0] |= V4L2_QCOM_CMD_FLUSH_OUTPUT; break; @@ -5316,14 +5319,20 @@ int msm_comm_flush(struct msm_vidc_inst *inst, u32 flags) core = inst->core; hdev = core->device; - ip_flush = flags & V4L2_QCOM_CMD_FLUSH_OUTPUT; - op_flush = flags & V4L2_QCOM_CMD_FLUSH_CAPTURE; + ip_flush = !!(flags & V4L2_QCOM_CMD_FLUSH_OUTPUT); + op_flush = !!(flags & V4L2_QCOM_CMD_FLUSH_CAPTURE); if (ip_flush && !op_flush) { dprintk(VIDC_WARN, "Input only flush not supported, making it flush all\n"); op_flush = true; - return 0; + goto exit; + } + + if ((inst->in_flush && ip_flush) || (inst->out_flush && op_flush)) { + dprintk(VIDC_WARN, "%s: %x : Already in flush\n", + __func__, hash32_ptr(inst->session)); + goto exit; } msm_clock_data_reset(inst); @@ -5333,7 +5342,7 @@ int msm_comm_flush(struct msm_vidc_inst *inst, u32 flags) "Core %pK and inst %pK are in bad state\n", core, inst); msm_comm_flush_in_invalid_state(inst); - return 0; + goto exit; } if (ip_flush) @@ -5342,7 +5351,8 @@ int msm_comm_flush(struct msm_vidc_inst *inst, u32 flags) mutex_lock(&inst->bufq[CAPTURE_PORT].lock); /* enable in flush */ - inst->in_flush = true; + 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) { @@ -5404,10 +5414,12 @@ int msm_comm_flush(struct msm_vidc_inst *inst, u32 flags) dprintk(VIDC_ERR, "Sending flush to firmware failed, flush out all buffers\n"); msm_comm_flush_in_invalid_state(inst); - /* disable in_flush */ + /* disable in_flush & out_flush */ inst->in_flush = false; + inst->out_flush = false; } +exit: return rc; } @@ -6899,7 +6911,7 @@ void handle_release_buffer_reference(struct msm_vidc_inst *inst, goto unlock; /* buffer found means client queued the buffer already */ - if (inst->in_reconfig || inst->in_flush) { + if (inst->in_reconfig || inst->out_flush) { print_vidc_buffer(VIDC_DBG, "rbr flush buf", inst, mbuf); msm_comm_flush_vidc_buffer(inst, mbuf); msm_comm_unmap_vidc_buffer(inst, mbuf); diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h index 3ef56ab63951..47b369a62184 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h +++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h @@ -487,6 +487,7 @@ struct msm_vidc_inst { int bit_depth; struct kref kref; bool in_flush; + bool out_flush; u32 pic_struct; u32 colour_space; u32 profile; From ca0da7056a3dd946e6d2fc52ec3a891451dcfd2d Mon Sep 17 00:00:00 2001 From: Govindaraj Rajagopal Date: Wed, 1 Apr 2020 13:13:42 +0530 Subject: [PATCH 143/356] msm: vidc: do not update inst state for map failure Currently for map failure inst->state updated to MSM_VIDC_CORE_INVALID. So during flush driver issues session_abort to firmware. So firmware asserts and sends sys_error back. So added change to avoid updating inst->state. Change-Id: I30f90726d21cb13bf5a27dd3d259a8d026260746 Signed-off-by: Govindaraj Rajagopal --- drivers/media/platform/msm/vidc/msm_vidc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c index 4885ac07d291..27aa2bd039e7 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc.c +++ b/drivers/media/platform/msm/vidc/msm_vidc.c @@ -1563,7 +1563,9 @@ static void msm_vidc_buf_queue(struct vb2_buffer *vb2) rc = msm_vidc_queue_buf(inst, vb2); if (rc) { print_vb2_buffer(VIDC_ERR, "failed vb2-qbuf", inst, vb2); - msm_comm_generate_session_error(inst); + vb2_buffer_done(vb2, VB2_BUF_STATE_DONE); + msm_vidc_queue_v4l2_event(inst, + V4L2_EVENT_MSM_VIDC_SYS_ERROR); } } From da832a6a35ec17a253a0de0aa34d5c1027c60824 Mon Sep 17 00:00:00 2001 From: Priyanka Gujjula Date: Wed, 17 Jul 2019 15:32:03 +0530 Subject: [PATCH 144/356] msm: vidc: remove key frame flag usage from ebd Remove HAL_BUFFERFLAG_SYNCFRAME flag usage support from hfi_msg_session_empty_buffer_done_packet and its corresponding usage in handle_ebd. Change-Id: I2dafd35a462a443e6efa165cbf46d4b78833c765 Signed-off-by: Priyanka Gujjula --- .../platform/msm/vidc/hfi_response_handler.c | 17 +---------------- .../media/platform/msm/vidc/msm_vidc_common.c | 2 -- drivers/media/platform/msm/vidc/vidc_hfi.h | 1 + .../media/platform/msm/vidc/vidc_hfi_helper.h | 4 ---- 4 files changed, 2 insertions(+), 22 deletions(-) diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c index cb804b175024..a35945e0c500 100644 --- a/drivers/media/platform/msm/vidc/hfi_response_handler.c +++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c @@ -1572,8 +1572,6 @@ static int hfi_process_session_etb_done(u32 device_id, { struct hfi_msg_session_empty_buffer_done_packet *pkt = _pkt; struct msm_vidc_cb_data_done data_done = {0}; - struct hfi_picture_type *hfi_picture_type = NULL; - u32 is_sync_frame; dprintk(VIDC_DBG, "RECEIVED: SESSION_ETB_DONE[%#x]\n", pkt->session_id); @@ -1595,24 +1593,11 @@ static int hfi_process_session_etb_done(u32 device_id, 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); - is_sync_frame = pkt->rgData[0]; - if (is_sync_frame) { - if (pkt->size < - sizeof(struct hfi_msg_session_empty_buffer_done_packet) - + sizeof(struct hfi_picture_type)) - goto bad_packet_size; - hfi_picture_type = (struct hfi_picture_type *)&pkt->rgData[1]; - if (hfi_picture_type->picture_type) - data_done.input_done.flags = - hfi_picture_type->picture_type; - else - dprintk(VIDC_DBG, - "Non-Sync frame sent for H264/HEVC\n"); - } trace_msm_v4l2_vidc_buffer_event_end("ETB", (u32)pkt->packet_buffer, -1, -1, diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c index 82d25ee75e3b..b9e5f089f278 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c @@ -2549,8 +2549,6 @@ static void handle_ebd(enum hal_command_response cmd, void *data) dprintk(VIDC_INFO, "Failed : Corrupted input stream\n"); mbuf->vvb.flags |= V4L2_BUF_FLAG_DATA_CORRUPT; } - if (empty_buf_done->flags & HAL_BUFFERFLAG_SYNCFRAME) - mbuf->vvb.flags |= V4L2_BUF_FLAG_KEYFRAME; extra_idx = EXTRADATA_IDX(inst->bufq[OUTPUT_PORT].num_planes); if (extra_idx && extra_idx < VIDEO_MAX_PLANES) diff --git a/drivers/media/platform/msm/vidc/vidc_hfi.h b/drivers/media/platform/msm/vidc/vidc_hfi.h index 8a1a7cec757b..41d10d5caf43 100644 --- a/drivers/media/platform/msm/vidc/vidc_hfi.h +++ b/drivers/media/platform/msm/vidc/vidc_hfi.h @@ -613,6 +613,7 @@ struct hfi_msg_session_empty_buffer_done_packet { 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]; }; diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h index b9c2e90313d0..4b1d838ac138 100644 --- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h +++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h @@ -669,10 +669,6 @@ struct hfi_bit_depth { u32 bit_depth; }; -struct hfi_picture_type { - u32 picture_type; -}; - /* Base Offset for UBWC color formats */ #define HFI_COLOR_FORMAT_UBWC_BASE (0x8000) /* Base Offset for 10-bit color formats */ From cef0f014b3020ce2cf615b5127e61e858b35a7e0 Mon Sep 17 00:00:00 2001 From: Govindaraj Rajagopal Date: Mon, 20 Jan 2020 14:42:22 +0530 Subject: [PATCH 145/356] msm: vidc: reduce max_packets count to 480 Currently max_packets is configured as 1000, but max outstanding packets will not exceed more than 480(16 clients x 30 pkts/client). Change-Id: I8c074e08c959473c20450bc7d62486362ba81b47 Signed-off-by: Govindaraj Rajagopal --- drivers/media/platform/msm/vidc/venus_hfi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c index 96b3e1c97bd9..c531f0a9fa87 100644 --- a/drivers/media/platform/msm/vidc/venus_hfi.c +++ b/drivers/media/platform/msm/vidc/venus_hfi.c @@ -83,7 +83,7 @@ const struct msm_vidc_gov_data DEFAULT_BUS_VOTE = { .data_count = 0, }; -const int max_packets = 1000; +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); From 25b9e5b2f79e3039b3dc0f6d52a46639a3947582 Mon Sep 17 00:00:00 2001 From: Swetha Chikkaboraiah Date: Fri, 13 Aug 2021 09:40:52 +0530 Subject: [PATCH 146/356] msm: vidc: Fix compilation error with new sdclang 12 Fix the compilation error with sdclang 12.0. Change-Id: If6b5caf655568b0d4ee12a71927df9476f3b4c55 Signed-off-by: Swetha Chikkaboraiah --- drivers/media/platform/msm/vidc/venus_hfi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c index c531f0a9fa87..9e506bd703ac 100644 --- a/drivers/media/platform/msm/vidc/venus_hfi.c +++ b/drivers/media/platform/msm/vidc/venus_hfi.c @@ -164,7 +164,7 @@ static void __dump_packet(u8 *packet, enum vidc_msg_prio log_level) * row must contain enough for 0xdeadbaad * 8 to be converted into * "de ad ba ab " * 8 + '\0' */ - char row[3 * row_size]; + char row[96]; /*char row[3 * row_size];*/ for (c = 0; c * row_size < packet_size; ++c) { int bytes_to_read = ((c + 1) * row_size > packet_size) ? From d8e0feb1dcfba04f4fbb04a3eaae8efd1155451c Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Wed, 23 Aug 2023 17:40:44 +0000 Subject: [PATCH 147/356] ARM64: dts: sdm845: Switch to ar50 vidc governor --- arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi b/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi index 0b05270f85a9..649932c8b548 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi @@ -52,10 +52,10 @@ venus_bus_ddr { compatible = "qcom,msm-vidc,bus"; - label = "venus-ddr"; + label = "venus-ar50-ddr"; qcom,bus-master = ; qcom,bus-slave = ; - qcom,mode = "venus-ddr"; + qcom,mode = "venus-ar50-ddr"; qcom,bus-range-kbps = <1000 3388000>; }; arm9_bus_ddr { @@ -68,10 +68,10 @@ }; venus_bus_llcc { compatible = "qcom,msm-vidc,bus"; - label = "venus-llcc"; + label = "venus-ar50-llcc"; qcom,bus-master = ; qcom,bus-slave = ; - qcom,mode = "venus-llcc"; + qcom,mode = "venus-ar50-llcc"; qcom,bus-range-kbps = <17000 3388000>; }; From 097be2dadc1c508c4724b6dceb0ae6bb07c5408c Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Fri, 22 Nov 2019 14:56:02 +0100 Subject: [PATCH 148/356] arm64: DT: SDM845: Add memory region for CDSP and assign to VIDC The SDM845 SoC has got a CDSP and we can allocate a DMA pool and use it for vidc to get more performance. --- arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi | 6 ++++++ arch/arm64/boot/dts/qcom/sdm845.dtsi | 8 ++++++++ 2 files changed, 14 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi b/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi index 649932c8b548..c39c677574b1 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-vidc.dtsi @@ -132,5 +132,11 @@ virtual-addr-pool = <0x1000000 0x24800000>; qcom,secure-context-bank; }; + + /* Memory Heaps */ + qcom,msm-vidc,mem_cdsp { + compatible = "qcom,msm-vidc,mem-cdsp"; + memory-region = <&cdsp_mem>; + }; }; }; diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index c12573352478..eddbcf5b704a 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -630,6 +630,14 @@ size = <0 0x1000000>; }; + cdsp_mem: cdsp_region { + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; + reusable; + alignment = <0x0 0x400000>; + size = <0x0 0x400000>; + }; + qseecom_ta_mem: qseecom_ta_region { compatible = "shared-dma-pool"; alloc-ranges = <0 0x00000000 0 0xffffffff>; From 004b76d49d8a43bdcbc1bfe7539d242222173fe8 Mon Sep 17 00:00:00 2001 From: Paras Nagda Date: Mon, 24 Feb 2020 17:50:49 +0530 Subject: [PATCH 149/356] media: v4l2-ctrls: Add missing entry in header_mode Add missing entry in header_mode qmenu array to avoid NULL dereference. Change-Id: I4c930c82c806c72853ac0383c0413d682cb0e86a Signed-off-by: Paras Nagda --- drivers/media/v4l2-core/v4l2-ctrls.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index d21bdc0d8f20..03c97747f965 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -312,6 +312,7 @@ const char * const *v4l2_ctrl_get_menu(u32 id) static const char * const header_mode[] = { "Separate Buffer", "Joined With 1st Frame", + "Joined with I Frame", NULL, }; static const char * const multi_slice[] = { From cf87130f0ee71b9b72d404286103e32b7ebcc8e8 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Mon, 4 Aug 2025 00:51:04 +0000 Subject: [PATCH 150/356] media: v4l2-ctrls: Add RC OFF entry to mpeg_video_bitrate_mode Removed in commit ce5b533e26aa, but we need it to avoid NULL dereference when using C2 media HAL made for kernel 4.14. --- drivers/media/v4l2-core/v4l2-ctrls.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index 03c97747f965..d05d43f2e269 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -202,6 +202,7 @@ const char * const *v4l2_ctrl_get_menu(u32 id) "Variable Bitrate", "Constant Bitrate", "Maximum Bitrate", + "RC OFF", "CBR VFR", "MBR VFR", "Constant Quality", From 9739c3c00e59e2d931cc13ecf5257f7e41af3f2b Mon Sep 17 00:00:00 2001 From: Hemant Kumar Date: Wed, 22 Nov 2017 13:53:08 -0800 Subject: [PATCH 151/356] usb: phy-msm-qusb-v2: Add support to control external pull down Add phy driver call back to enable external pull down on D+ line in host mode. External pull-down is only needed during port reset before enabling high speed terminations. Pull-down will be disabled 20ms after its enabled in timer function. Change-Id: Id2a4e34b4937dc63d3e20cd48f5d586bbcb7599a Signed-off-by: Hemant Kumar Signed-off-by: Vamsi Krishna Samavedam --- drivers/usb/phy/phy-msm-qusb-v2.c | 68 +++++++++++++++++++++++++++++++ include/linux/usb/phy.h | 11 +++++ 2 files changed, 79 insertions(+) diff --git a/drivers/usb/phy/phy-msm-qusb-v2.c b/drivers/usb/phy/phy-msm-qusb-v2.c index 47d49c92c671..f3f6c0603b1d 100644 --- a/drivers/usb/phy/phy-msm-qusb-v2.c +++ b/drivers/usb/phy/phy-msm-qusb-v2.c @@ -19,6 +19,7 @@ #include #include #include +#include /* QUSB2PHY_PWR_CTRL1 register related bits */ #define PWR_CTRL1_POWR_DOWN BIT(0) @@ -131,6 +132,10 @@ struct qusb_phy { struct regulator_desc dpdm_rdesc; struct regulator_dev *dpdm_rdev; + struct pinctrl *pinctrl; + struct pinctrl_state *atest_usb13_suspend; + struct pinctrl_state *atest_usb13_active; + /* emulation targets specific */ void __iomem *emu_phy_base; bool emulation; @@ -147,6 +152,8 @@ struct qusb_phy { u8 bias_ctrl2; bool override_bias_ctrl2; + + struct hrtimer timer; }; static void qusb_phy_enable_clocks(struct qusb_phy *qphy, bool on) @@ -668,6 +675,42 @@ static int qusb_phy_init(struct usb_phy *phy) return 0; } +static enum hrtimer_restart qusb_dis_ext_pulldown_timer(struct hrtimer *timer) +{ + struct qusb_phy *qphy = container_of(timer, struct qusb_phy, timer); + int ret = 0; + + if (qphy->pinctrl && qphy->atest_usb13_suspend) { + ret = pinctrl_select_state(qphy->pinctrl, + qphy->atest_usb13_suspend); + if (ret < 0) + dev_err(qphy->phy.dev, + "pinctrl state suspend select failed\n"); + } + + return HRTIMER_NORESTART; +} + +static void qusb_phy_enable_ext_pulldown(struct usb_phy *phy) +{ + struct qusb_phy *qphy = container_of(phy, struct qusb_phy, phy); + int ret = 0; + + dev_dbg(phy->dev, "%s\n", __func__); + + if (qphy->pinctrl && qphy->atest_usb13_active) { + ret = pinctrl_select_state(qphy->pinctrl, + qphy->atest_usb13_active); + if (ret < 0) { + dev_err(phy->dev, + "pinctrl state active select failed\n"); + return; + } + + hrtimer_start(&qphy->timer, ms_to_ktime(10), HRTIMER_MODE_REL); + } +} + static void qusb_phy_shutdown(struct usb_phy *phy) { struct qusb_phy *qphy = container_of(phy, struct qusb_phy, phy); @@ -1305,6 +1348,30 @@ static int qusb_phy_probe(struct platform_device *pdev) if (ret) return ret; + qphy->pinctrl = devm_pinctrl_get(dev); + if (IS_ERR(qphy->pinctrl)) { + ret = PTR_ERR(qphy->pinctrl); + if (ret == -EPROBE_DEFER) + return ret; + dev_err(dev, "pinctrl not available\n"); + goto skip_pinctrl_config; + } + qphy->atest_usb13_suspend = pinctrl_lookup_state(qphy->pinctrl, + "atest_usb13_suspend"); + if (IS_ERR(qphy->atest_usb13_suspend)) { + dev_err(dev, "pinctrl lookup atest_usb13_suspend failed\n"); + goto skip_pinctrl_config; + } + + qphy->atest_usb13_active = pinctrl_lookup_state(qphy->pinctrl, + "atest_usb13_active"); + if (IS_ERR(qphy->atest_usb13_active)) + dev_err(dev, "pinctrl lookup atest_usb13_active failed\n"); + + hrtimer_init(&qphy->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + qphy->timer.function = qusb_dis_ext_pulldown_timer; + +skip_pinctrl_config: mutex_init(&qphy->lock); platform_set_drvdata(pdev, qphy); @@ -1316,6 +1383,7 @@ static int qusb_phy_probe(struct platform_device *pdev) qphy->phy.notify_connect = qusb_phy_notify_connect; qphy->phy.notify_disconnect = qusb_phy_notify_disconnect; qphy->phy.drive_dp_pulse = msm_qusb_phy_drive_dp_pulse; + qphy->phy.start_port_reset = qusb_phy_enable_ext_pulldown; ret = usb_add_phy_dev(&qphy->phy); if (ret) diff --git a/include/linux/usb/phy.h b/include/linux/usb/phy.h index 7b2a7c313391..dfcfa2fe93b4 100644 --- a/include/linux/usb/phy.h +++ b/include/linux/usb/phy.h @@ -146,6 +146,8 @@ struct usb_phy { /* enable/disable VBUS */ int (*set_vbus)(struct usb_phy *x, int on); + /* callback to indicate port is being reset or reset the port */ + void (*start_port_reset)(struct usb_phy *x); /* effective for B devices, ignored for A-peripheral */ int (*set_power)(struct usb_phy *x, @@ -240,6 +242,15 @@ usb_phy_vbus_off(struct usb_phy *x) return x->set_vbus(x, false); } +static inline void +usb_phy_start_port_reset(struct usb_phy *x) +{ + if (!x || !x->start_port_reset) + return; + + x->start_port_reset(x); +} + static inline int usb_phy_reset(struct usb_phy *x) { From ba005e57d78bb9b0cf0ff801b83559d419b713d8 Mon Sep 17 00:00:00 2001 From: Vijayavardhan Vennapusa Date: Tue, 18 Dec 2018 12:20:02 +0530 Subject: [PATCH 152/356] usb: phy-msm-qusb-v2: Add support for enabling external pull down for USB2 port Add support for enabling external pull down for USB2 port so that USB HS devices detection works without any issues. Change-Id: Id5ac67bfbcb7b2485e59e31c594fe9462e95079c Signed-off-by: Vijayavardhan Vennapusa --- drivers/usb/phy/phy-msm-qusb-v2.c | 37 ++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/drivers/usb/phy/phy-msm-qusb-v2.c b/drivers/usb/phy/phy-msm-qusb-v2.c index f3f6c0603b1d..73427ae945db 100644 --- a/drivers/usb/phy/phy-msm-qusb-v2.c +++ b/drivers/usb/phy/phy-msm-qusb-v2.c @@ -133,8 +133,8 @@ struct qusb_phy { struct regulator_dev *dpdm_rdev; struct pinctrl *pinctrl; - struct pinctrl_state *atest_usb13_suspend; - struct pinctrl_state *atest_usb13_active; + struct pinctrl_state *atest_usb_suspend; + struct pinctrl_state *atest_usb_active; /* emulation targets specific */ void __iomem *emu_phy_base; @@ -680,9 +680,9 @@ static enum hrtimer_restart qusb_dis_ext_pulldown_timer(struct hrtimer *timer) struct qusb_phy *qphy = container_of(timer, struct qusb_phy, timer); int ret = 0; - if (qphy->pinctrl && qphy->atest_usb13_suspend) { + if (qphy->pinctrl && qphy->atest_usb_suspend) { ret = pinctrl_select_state(qphy->pinctrl, - qphy->atest_usb13_suspend); + qphy->atest_usb_suspend); if (ret < 0) dev_err(qphy->phy.dev, "pinctrl state suspend select failed\n"); @@ -698,9 +698,9 @@ static void qusb_phy_enable_ext_pulldown(struct usb_phy *phy) dev_dbg(phy->dev, "%s\n", __func__); - if (qphy->pinctrl && qphy->atest_usb13_active) { + if (qphy->pinctrl && qphy->atest_usb_active) { ret = pinctrl_select_state(qphy->pinctrl, - qphy->atest_usb13_active); + qphy->atest_usb_active); if (ret < 0) { dev_err(phy->dev, "pinctrl state active select failed\n"); @@ -1356,17 +1356,28 @@ static int qusb_phy_probe(struct platform_device *pdev) dev_err(dev, "pinctrl not available\n"); goto skip_pinctrl_config; } - qphy->atest_usb13_suspend = pinctrl_lookup_state(qphy->pinctrl, + qphy->atest_usb_suspend = pinctrl_lookup_state(qphy->pinctrl, "atest_usb13_suspend"); - if (IS_ERR(qphy->atest_usb13_suspend)) { - dev_err(dev, "pinctrl lookup atest_usb13_suspend failed\n"); - goto skip_pinctrl_config; + + if (IS_ERR(qphy->atest_usb_suspend) && + PTR_ERR(qphy->atest_usb_suspend) == -ENODEV) { + qphy->atest_usb_suspend = pinctrl_lookup_state(qphy->pinctrl, + "suspend"); + if (IS_ERR(qphy->atest_usb_suspend)) { + dev_err(dev, "pinctrl lookup suspend failed\n"); + goto skip_pinctrl_config; + } } - qphy->atest_usb13_active = pinctrl_lookup_state(qphy->pinctrl, + qphy->atest_usb_active = pinctrl_lookup_state(qphy->pinctrl, "atest_usb13_active"); - if (IS_ERR(qphy->atest_usb13_active)) - dev_err(dev, "pinctrl lookup atest_usb13_active failed\n"); + if (IS_ERR(qphy->atest_usb_active) && + PTR_ERR(qphy->atest_usb_active) == -ENODEV) { + qphy->atest_usb_active = pinctrl_lookup_state(qphy->pinctrl, + "active"); + if (IS_ERR(qphy->atest_usb_active)) + dev_err(dev, "pinctrl lookup active failed\n"); + } hrtimer_init(&qphy->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); qphy->timer.function = qusb_dis_ext_pulldown_timer; From 2d92f51cbdb3c866d618bc6cabd7a085006cf51c Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Sat, 8 Apr 2023 23:59:54 +0000 Subject: [PATCH 153/356] usb: phy-msm-qusb-v2: Add missing pinctrl header Apparently this was included somewhere else on 4.9 --- drivers/usb/phy/phy-msm-qusb-v2.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/phy/phy-msm-qusb-v2.c b/drivers/usb/phy/phy-msm-qusb-v2.c index 73427ae945db..dd21f2a64c7f 100644 --- a/drivers/usb/phy/phy-msm-qusb-v2.c +++ b/drivers/usb/phy/phy-msm-qusb-v2.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include From 247a7cac2cc105d25182c58d5e8aa571395cebec Mon Sep 17 00:00:00 2001 From: Hemant Kumar Date: Tue, 28 Nov 2017 16:03:07 -0800 Subject: [PATCH 154/356] usb: host: xhci: Enable pull-down on DP while port reset Enable external pull down on DP line while port reset in progress. This helps to reduce the voltage on D+ line in case of a high speed detection handshake. Change-Id: I68991d6a3dc7227036bf111c04f10ef75daa4b26 Signed-off-by: Hemant Kumar Signed-off-by: Vamsi Krishna Samavedam --- drivers/usb/host/xhci-hub.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 7219ff7df74b..1b72fc37e23a 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" @@ -1191,6 +1192,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 test_mode = 0; struct xhci_hub *rhub; struct xhci_port **ports; + enum usb_device_speed s = hcd->self.root_hub->speed; rhub = xhci_get_rhub(hcd); ports = rhub->ports; @@ -1443,6 +1445,10 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, writel(temp, ports[wIndex]->addr); temp = readl(ports[wIndex]->addr); + + if (s == USB_SPEED_HIGH) + usb_phy_start_port_reset(hcd->usb_phy); + xhci_dbg(xhci, "set port reset, actual port %d status = 0x%x\n", wIndex, temp); break; case USB_PORT_FEAT_REMOTE_WAKE_MASK: From 7c69daa833a0b599c83fd3909acfbe25c5fddb17 Mon Sep 17 00:00:00 2001 From: MrArtemSid Date: Thu, 4 Nov 2021 21:57:28 +0400 Subject: [PATCH 155/356] arm64: dts: qcom: pmi8998: Update haptics node from pm660 haptics node was taken from pm660.dtsi changes applied to it: - changed interrupts from <0x1...> to <0x3...> as in pmi8998 - added qcom,pmic-revid --- arch/arm64/boot/dts/qcom/pmi8998.dtsi | 43 ++++++++++----------------- 1 file changed, 16 insertions(+), 27 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/pmi8998.dtsi b/arch/arm64/boot/dts/qcom/pmi8998.dtsi index fe497c651166..ee258231d68d 100644 --- a/arch/arm64/boot/dts/qcom/pmi8998.dtsi +++ b/arch/arm64/boot/dts/qcom/pmi8998.dtsi @@ -664,7 +664,7 @@ }; - pmi8998_haptics: qcom,haptics@c000 { + pmi8998_haptics: qcom,haptic@c000 { compatible = "qcom,haptics"; reg = <0xc000 0x100>; interrupts = <0x3 0xc0 0x0 IRQ_TYPE_EDGE_BOTH>, @@ -672,20 +672,21 @@ interrupt-names = "hap-sc-irq", "hap-play-irq"; qcom,actuator-type = "lra"; qcom,vmax-mv = <3200>; + // qcom,lra-high-z = "opt1"; Need to implement that later qcom,play-rate-us = <6667>; qcom,lra-resonance-sig-shape = "sine"; qcom,lra-auto-resonance-mode = "qwd"; qcom,lra-allow-variable-play-rate; + qcom,pmic-revid = <&pmi8998_revid>; + status = "disabled"; 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-pattern = [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,wf-brake-pattern = [01 00 00 00]; qcom,lra-auto-resonance-disable; }; @@ -693,10 +694,9 @@ /* 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-pattern = [7e 7e 02 02 02 02 02 02]; + qcom,wf-play-rate-us = <7143>; + qcom,wf-repeat-count = <2>; qcom,wf-s-repeat-count = <1>; qcom,lra-auto-resonance-disable; }; @@ -705,11 +705,8 @@ /* 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,wf-pattern = [7e 7e]; + qcom,wf-play-rate-us = <4000>; qcom,lra-auto-resonance-disable; }; @@ -717,11 +714,8 @@ /* THUD */ qcom,effect-id = <3>; qcom,wf-vmax-mv = <3600>; - qcom,wf-pattern = [3e 3e 3e 3e 3e 3e 3e 3e]; + qcom,wf-pattern = [7e 7e 7e]; 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; }; @@ -729,11 +723,8 @@ /* 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,wf-pattern = [7e 7e]; + qcom,wf-play-rate-us = <5000>; qcom,lra-auto-resonance-disable; }; @@ -741,11 +732,9 @@ /* HEAVY CLICK */ qcom,effect-id = <5>; qcom,wf-vmax-mv = <3600>; - qcom,wf-pattern = [3e 3e 3e 3e 3e 3e 3e 3e]; + qcom,wf-pattern = [7e 7e 7e]; 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,wf-brake-pattern = [03 00 00 00]; qcom,lra-auto-resonance-disable; }; }; From 9c387fb8fd2e8f441130b0d4c246b06ae8f91e47 Mon Sep 17 00:00:00 2001 From: Quallenauge Date: Mon, 21 Sep 2020 22:19:01 +0200 Subject: [PATCH 156/356] qti-haptics: Add support for parsing pmic-revid. Change-Id: I61f21cfc24940c9cb087160e4f82f46a70e33a06 --- drivers/input/misc/qti-haptics.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/input/misc/qti-haptics.c b/drivers/input/misc/qti-haptics.c index dac72b3e9e46..6ad9c26d9a4f 100644 --- a/drivers/input/misc/qti-haptics.c +++ b/drivers/input/misc/qti-haptics.c @@ -22,6 +22,7 @@ #include #include #include +#include enum actutor_type { ACT_LRA, @@ -203,6 +204,7 @@ struct qti_hap_chip { struct platform_device *pdev; struct device *dev; struct regmap *regmap; + struct pmic_revid_data *revid; struct input_dev *input_dev; struct qti_hap_config config; struct qti_hap_play_info play; @@ -1410,6 +1412,7 @@ static int qti_haptics_parse_dt(struct qti_hap_chip *chip) { struct qti_hap_config *config = &chip->config; const struct device_node *node = chip->dev->of_node; + struct device_node *revid_node; const char *str; int rc = 0, tmp; @@ -1420,6 +1423,25 @@ static int qti_haptics_parse_dt(struct qti_hap_chip *chip) } chip->reg_base = (u16)tmp; + revid_node = of_parse_phandle(node, "qcom,pmic-revid", 0); + if (!revid_node) { + pr_err("Missing qcom,pmic-revid property\n"); + return -EINVAL; + } + + chip->revid = get_revid_data(revid_node); + of_node_put(revid_node); + if (IS_ERR_OR_NULL(chip->revid)) { + pr_err("Unable to get pmic_revid rc=%ld\n", + PTR_ERR(chip->revid)); + /* + * the revid peripheral must be registered, any failure + * here only indicates that the rev-id module has not + * probed yet. + */ + return -EPROBE_DEFER; + } + chip->sc_irq = platform_get_irq_byname(chip->pdev, "hap-sc-irq"); if (chip->sc_irq < 0) { dev_err(chip->dev, "Failed to get hap-sc-irq\n"); From d91c26ed008eed11ec2389432eb6493b4f540c23 Mon Sep 17 00:00:00 2001 From: Quallenauge Date: Mon, 21 Sep 2020 22:19:01 +0200 Subject: [PATCH 157/356] qti-haptics: Add support for pre-PM660 pmic. The behavior/values were taken from 3.18 stock kernel release. Change-Id: I2ad16bcc8abadcde48989eb87ec02c28be1f5a06 --- drivers/input/misc/qti-haptics.c | 77 +++++++++++++++++++++++++++----- 1 file changed, 65 insertions(+), 12 deletions(-) diff --git a/drivers/input/misc/qti-haptics.c b/drivers/input/misc/qti-haptics.c index 6ad9c26d9a4f..29819f3a1d8a 100644 --- a/drivers/input/misc/qti-haptics.c +++ b/drivers/input/misc/qti-haptics.c @@ -34,11 +34,28 @@ enum lra_res_sig_shape { RES_SIG_SQUARE, }; +enum hap_auto_res_mode { + HAP_AUTO_RES_NONE, + HAP_AUTO_RES_ZXD, + HAP_AUTO_RES_QWD, + HAP_AUTO_RES_MAX_QWD, + HAP_AUTO_RES_ZXD_EOP, +}; + enum lra_auto_res_mode { AUTO_RES_MODE_ZXD, AUTO_RES_MODE_QWD, }; + +/* high Z option lines */ +enum hap_high_z { + HAP_LRA_HIGH_Z_NONE, /* opt0 for PM660 */ + HAP_LRA_HIGH_Z_OPT1, + HAP_LRA_HIGH_Z_OPT2, + HAP_LRA_HIGH_Z_OPT3, +}; + enum wf_src { INT_WF_VMAX, INT_WF_BUFFER, @@ -112,6 +129,16 @@ enum haptics_custom_effect_param { #define HAP_WF_SOURCE_AUDIO (2 << HAP_WF_SOURCE_SHIFT) #define HAP_WF_SOURCE_PWM (3 << HAP_WF_SOURCE_SHIFT) +/* For pmi8998 */ +#define LRA_AUTO_RES_MODE_MASK GENMASK(6, 4) +#define LRA_AUTO_RES_MODE_SHIFT 4 +#define LRA_HIGH_Z_MASK GENMASK(3, 2) +#define LRA_HIGH_Z_SHIFT 2 +#define LRA_RES_CAL_MASK GENMASK(1, 0) +#define HAP_RES_CAL_PERIOD_MIN 4 +#define HAP_RES_CAL_PERIOD_MAX 32 + +/* For pm660 */ #define REG_HAP_AUTO_RES_CFG 0x4F #define HAP_AUTO_RES_MODE_BIT BIT(7) #define HAP_AUTO_RES_MODE_SHIFT 7 @@ -194,7 +221,7 @@ struct qti_hap_play_info { struct qti_hap_config { enum actutor_type act_type; enum lra_res_sig_shape lra_shape; - enum lra_auto_res_mode lra_auto_res_mode; + u8 lra_auto_res_mode; u16 vmax_mv; u16 play_rate_us; bool lra_allow_variable_play_rate; @@ -1126,10 +1153,17 @@ static int qti_haptics_hw_init(struct qti_hap_chip *chip) return rc; } - addr = REG_HAP_AUTO_RES_CFG; - mask = HAP_AUTO_RES_MODE_BIT | HAP_CAL_EOP_EN_BIT | HAP_CAL_PERIOD_MASK; - val = config->lra_auto_res_mode << HAP_AUTO_RES_MODE_SHIFT; - val |= HAP_CAL_EOP_EN_BIT | HAP_CAL_OPT3_EVERY_8_PERIOD; + if (chip->revid->pmic_subtype == PM660_SUBTYPE) { + addr = REG_HAP_AUTO_RES_CFG; + mask = HAP_AUTO_RES_MODE_BIT | HAP_CAL_EOP_EN_BIT | HAP_CAL_PERIOD_MASK; + val = config->lra_auto_res_mode << HAP_AUTO_RES_MODE_SHIFT; + val |= HAP_CAL_EOP_EN_BIT | HAP_CAL_OPT3_EVERY_8_PERIOD; + } else { + addr = REG_HAP_AUTO_RES_CFG; + mask = LRA_AUTO_RES_MODE_MASK | LRA_HIGH_Z_MASK | LRA_RES_CAL_MASK; + val |= (config->lra_auto_res_mode << LRA_AUTO_RES_MODE_SHIFT); + val |= (HAP_LRA_HIGH_Z_OPT3 << LRA_HIGH_Z_SHIFT); + } rc = qti_haptics_masked_write(chip, addr, mask, val); if (rc < 0) { dev_err(chip->dev, "set AUTO_RES_CFG failed, rc=%d\n", rc); @@ -1394,14 +1428,33 @@ static int qti_haptics_lra_parse_dt(struct qti_hap_chip *chip) rc = of_property_read_string(node, "qcom,lra-auto-resonance-mode", &str); if (!rc) { - if (strcmp(str, "zxd") == 0) { - config->lra_auto_res_mode = AUTO_RES_MODE_ZXD; - } else if (strcmp(str, "qwd") == 0) { - config->lra_auto_res_mode = AUTO_RES_MODE_QWD; + if (chip->revid->pmic_subtype == PM660_SUBTYPE) { + config->lra_auto_res_mode = + AUTO_RES_MODE_QWD; + if (strcmp(str, "zxd") == 0) + config->lra_auto_res_mode = + AUTO_RES_MODE_ZXD; + else if (strcmp(str, "qwd") == 0) + config->lra_auto_res_mode = + AUTO_RES_MODE_QWD; } else { - dev_err(chip->dev, "Invalid auto resonance mode: %s\n", - str); - return -EINVAL; + config->lra_auto_res_mode = + HAP_AUTO_RES_ZXD_EOP; + if (strcmp(str, "none") == 0) + config->lra_auto_res_mode = + HAP_AUTO_RES_NONE; + else if (strcmp(str, "zxd") == 0) + config->lra_auto_res_mode = + HAP_AUTO_RES_ZXD; + else if (strcmp(str, "qwd") == 0) + config->lra_auto_res_mode = + HAP_AUTO_RES_QWD; + else if (strcmp(str, "max-qwd") == 0) + config->lra_auto_res_mode = + HAP_AUTO_RES_MAX_QWD; + else + config->lra_auto_res_mode = + HAP_AUTO_RES_ZXD_EOP; } } From 8f98aa7185d167164cf2b845b1addddf5378d409 Mon Sep 17 00:00:00 2001 From: me-cafebabe <87921983+me-cafebabe@users.noreply.github.com> Date: Tue, 18 May 2021 20:31:55 +0800 Subject: [PATCH 158/356] input: qti-haptics: Add null check to time_us variable Avoid crashes when the value is negative. Co-authored-by: Jebaitedneko <16777012+Jebaitedneko@users.noreply.github.com> --- drivers/input/misc/qti-haptics.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/input/misc/qti-haptics.c b/drivers/input/misc/qti-haptics.c index 29819f3a1d8a..ad0aaf41307b 100644 --- a/drivers/input/misc/qti-haptics.c +++ b/drivers/input/misc/qti-haptics.c @@ -881,6 +881,8 @@ static int qti_haptics_upload_effect(struct input_dev *dev, if (hrtimer_active(&chip->hap_disable_timer)) { rem = hrtimer_get_remaining(&chip->hap_disable_timer); time_us = ktime_to_us(rem); + if (time_us <= 0) + time_us = 100; dev_dbg(chip->dev, "waiting for playing clear sequence: %lld us\n", time_us); usleep_range(time_us, time_us + 100); From b515241e32833d1170742ce6f082ceafc7dcaaab Mon Sep 17 00:00:00 2001 From: "Angelo G. Del Regno" Date: Wed, 27 Mar 2019 18:16:45 +0100 Subject: [PATCH 159/356] clk: dispcc-sdm845: Do not gate by default DSI, pixel, byte clocks Disable clock gating by default for the DSI, pixel and byte: now the SDE driver is responsible of selectively enabling clock gating for each of these clocks by setting the single corresponding bit. --- drivers/clk/qcom/dispcc-sdm845.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/qcom/dispcc-sdm845.c b/drivers/clk/qcom/dispcc-sdm845.c index 0c9709da7297..7379f8b21f28 100644 --- a/drivers/clk/qcom/dispcc-sdm845.c +++ b/drivers/clk/qcom/dispcc-sdm845.c @@ -1123,7 +1123,7 @@ static int disp_cc_sdm845_probe(struct platform_device *pdev) clk_fabia_pll_configure(&disp_cc_pll0, regmap, &disp_cc_pll0_config); /* Enable clock gating for DSI and MDP clocks */ - regmap_update_bits(regmap, DISP_CC_MISC_CMD, 0x7f0, 0x7f0); + regmap_update_bits(regmap, DISP_CC_MISC_CMD, 0x10, 0x10); ret = disp_cc_sdm845_fixup(pdev, regmap); if (ret) From 2c02ee8553413a5c1d2bf147837a1c84d923a5c2 Mon Sep 17 00:00:00 2001 From: "Angelo G. Del Regno" Date: Thu, 11 Jul 2019 18:03:10 +0200 Subject: [PATCH 160/356] clk: qcom: dispcc-sdm845: Do not configure the PLL twice When we probe the driver, we want to run clk_fabia_pll_configure on the PLL0 of the display clock controller. In the case of SDM845v2 and SDM670 though, the configure function is ran twice: first it configures it for SDM845v1, then it does that again for SDM845v2 or SDM670. Move the configure call to the fixup function, so that we just configure it once and correctly. --- drivers/clk/qcom/dispcc-sdm845.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/clk/qcom/dispcc-sdm845.c b/drivers/clk/qcom/dispcc-sdm845.c index 7379f8b21f28..0a13e8b0dca6 100644 --- a/drivers/clk/qcom/dispcc-sdm845.c +++ b/drivers/clk/qcom/dispcc-sdm845.c @@ -1097,6 +1097,9 @@ static int disp_cc_sdm845_fixup(struct platform_device *pdev, disp_cc_sdm845_fixup_sdm845v2(regmap); else if (!strcmp(compat, "qcom,dispcc-sdm670")) disp_cc_sdm845_fixup_sdm670(regmap); + else + clk_fabia_pll_configure(&disp_cc_pll0, regmap, + &disp_cc_pll0_config); return 0; } @@ -1120,15 +1123,13 @@ static int disp_cc_sdm845_probe(struct platform_device *pdev) return PTR_ERR(vdd_cx.regulator[0]); } - clk_fabia_pll_configure(&disp_cc_pll0, regmap, &disp_cc_pll0_config); - - /* Enable clock gating for DSI and MDP clocks */ - regmap_update_bits(regmap, DISP_CC_MISC_CMD, 0x10, 0x10); - ret = disp_cc_sdm845_fixup(pdev, regmap); if (ret) return ret; + /* Enable clock gating for DSI and MDP clocks */ + regmap_update_bits(regmap, DISP_CC_MISC_CMD, 0x10, 0x10); + ret = qcom_cc_really_probe(pdev, &disp_cc_sdm845_desc, regmap); if (ret) { dev_err(&pdev->dev, "Failed to register Display CC clocks\n"); From a14e23068d7d9270096db6e53fdca43e88c489a4 Mon Sep 17 00:00:00 2001 From: "Angelo G. Del Regno" Date: Fri, 12 Jul 2019 12:42:44 +0200 Subject: [PATCH 161/356] clk: qcom: aop-qmp: Add support for v1 AOP clocks Due to HW limitations on v1, the qdss_ao clock was not supported by the clock driver on AOP. This is needed for SDM845. --- drivers/clk/qcom/clk-aop-qmp.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/clk/qcom/clk-aop-qmp.c b/drivers/clk/qcom/clk-aop-qmp.c index 0f7b77d01228..3956cfb41726 100644 --- a/drivers/clk/qcom/clk-aop-qmp.c +++ b/drivers/clk/qcom/clk-aop-qmp.c @@ -256,6 +256,15 @@ static struct notifier_block aop_qmp_clk_panic_notifier = { .priority = 1, }; +/* + * Due to HW limitations on v1, the qdss_ao clock was not supported by the clock + * driver on AOP. + */ +static void aop_qmp_fixup_v1(void) +{ + aop_qmp_clk_hws[QDSS_AO_CLK] = NULL; +} + static int qmp_update_client(struct clk_hw *hw, struct device *dev, struct mbox_chan **mbox) { @@ -314,6 +323,9 @@ static int aop_qmp_clk_probe(struct platform_device *pdev) clk_data->clk_num = num_clks; + if (of_device_is_compatible(pdev->dev.of_node, "qcom,aop-qmp-clk-v1")) + aop_qmp_fixup_v1(); + for (i = 1; i < num_clks; i++) { if (!aop_qmp_clk_hws[i]) continue; @@ -366,6 +378,7 @@ static int aop_qmp_clk_probe(struct platform_device *pdev) static const struct of_device_id aop_qmp_clk_of_match[] = { { .compatible = "qcom,aop-qmp-clk", }, + { .compatible = "qcom,aop-qmp-clk-v1" }, {} }; From 5ae50b10b9d3042519e19742d293c161d7b4afe7 Mon Sep 17 00:00:00 2001 From: "Angelo G. Del Regno" Date: Thu, 13 Jun 2019 11:25:31 +0200 Subject: [PATCH 162/356] iio: adc: qcom-spmi-vadc: Use right ratiometric range for SDM845 The ratiometric range for SDM845 is 1875mV instead of the standard 1800mV: address this as fast as possible by adding a of_machine_is_compatible conditional codepath to vary theratiometric range value for this machine. --- drivers/iio/adc/qcom-spmi-vadc.c | 6 +++++- drivers/iio/adc/qcom-vadc-common.h | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/iio/adc/qcom-spmi-vadc.c b/drivers/iio/adc/qcom-spmi-vadc.c index d27246cb3cb6..e3b832139fe9 100644 --- a/drivers/iio/adc/qcom-spmi-vadc.c +++ b/drivers/iio/adc/qcom-spmi-vadc.c @@ -353,9 +353,13 @@ static int vadc_measure_ref_points(struct vadc_priv *vadc) { struct vadc_channel_prop *prop; u16 read_1, read_2; + int ratiometric_range = VADC_RATIOMETRIC_RANGE; int ret; - vadc->graph[VADC_CALIB_RATIOMETRIC].dx = VADC_RATIOMETRIC_RANGE; + if (of_machine_is_compatible("qcom,sdm845")) + ratiometric_range = VADC_RATIOMETRIC_RANGE_8998; + + vadc->graph[VADC_CALIB_RATIOMETRIC].dx = ratiometric_range; vadc->graph[VADC_CALIB_ABSOLUTE].dx = VADC_ABSOLUTE_RANGE_UV; prop = vadc_get_channel(vadc, VADC_REF_1250MV); diff --git a/drivers/iio/adc/qcom-vadc-common.h b/drivers/iio/adc/qcom-vadc-common.h index e0ff98bf5f15..d313b9b53b0b 100644 --- a/drivers/iio/adc/qcom-vadc-common.h +++ b/drivers/iio/adc/qcom-vadc-common.h @@ -16,6 +16,7 @@ #define VADC_ABSOLUTE_RANGE_UV 625000 #define VADC_RATIOMETRIC_RANGE 1800 +#define VADC_RATIOMETRIC_RANGE_8998 1875 #define VADC_DEF_PRESCALING 0 /* 1:1 */ #define VADC_DEF_DECIMATION 0 /* 512 */ From c6465d5861b9a5f0594974bcfce6fe7dbeaed4b6 Mon Sep 17 00:00:00 2001 From: Asha Magadi Venkateshamurthy Date: Wed, 14 Oct 2020 17:10:00 +0530 Subject: [PATCH 163/356] ARM: dts: msm: Update energy cost for SDM845 SDM845 uses LEGACY_ENERGY_MODEL. Removing deprecated CLUSTER_COST and idle cost from energy-cost. Change-Id: Iaa8a31727e5d234c7c450d0f5668b1440a68526d --- arch/arm64/boot/dts/qcom/sdm845-v2.dtsi | 74 ---------------------- arch/arm64/boot/dts/qcom/sdm845.dtsi | 83 +++---------------------- 2 files changed, 8 insertions(+), 149 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi index 89cc6d26f39f..e2223560b2a0 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi @@ -490,9 +490,6 @@ 1689600 141 1766400 160 >; - idle-cost-data = < - 10 8 6 4 - >; }; CPU_COST_1: core-cost1 { busy-cost-data = < @@ -533,77 +530,6 @@ 2841600 50000 2956800 60000 >; - idle-cost-data = < - 100 80 60 40 - >; - }; - CLUSTER_COST_0: cluster-cost0 { - busy-cost-data = < - 300000 3 - 403200 4 - 480000 4 - 576000 4 - 652800 5 - 748800 5 - 825600 6 - 902400 7 - 979200 7 - 1056000 8 - 1132800 9 - 1228800 9 - 1324800 10 - 1420800 11 - 1516800 12 - 1612800 13 - 1689600 15 - 1766400 17 - >; - idle-cost-data = < - 4 3 2 1 - >; - }; - CLUSTER_COST_1: cluster-cost1 { - busy-cost-data = < - 300000 24 - 403200 24 - 480000 25 - 576000 25 - 652800 26 - 748800 27 - 825600 28 - 902400 29 - 979200 30 - 1056000 32 - 1132800 34 - 1209600 37 - 1286400 40 - 1363200 45 - 1459200 50 - 1536000 57 - 1612800 64 - 1689600 74 - 1766400 84 - 1843200 96 - 1920000 106 - 1996800 113 - 2092800 120 - 2169600 125 - 2246400 127 - 2323200 130 - 2400000 135 - 2476800 140 - 2553600 145 - 2649600 150 - 2745600 155 - 2764800 160 - 2784000 165 - 2803200 170 - 2841600 180 - 2956800 190 - >; - idle-cost-data = < - 4 3 2 1 - >; }; }; diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index eddbcf5b704a..c918debcde27 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -59,7 +59,7 @@ qcom,lmh-dcvs = <&lmh_dcvs0>; #cooling-cells = <2>; next-level-cache = <&L2_0>; - sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>; + sched-energy-costs = <&CPU_COST_0>; L2_0: l2-cache { compatible = "arm,arch-cache"; cache-size = <0x20000>; @@ -96,7 +96,7 @@ qcom,lmh-dcvs = <&lmh_dcvs0>; #cooling-cells = <2>; next-level-cache = <&L2_100>; - sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>; + sched-energy-costs = <&CPU_COST_0>; L2_100: l2-cache { compatible = "arm,arch-cache"; cache-size = <0x20000>; @@ -127,7 +127,7 @@ qcom,lmh-dcvs = <&lmh_dcvs0>; #cooling-cells = <2>; next-level-cache = <&L2_200>; - sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>; + sched-energy-costs = <&CPU_COST_0>; L2_200: l2-cache { compatible = "arm,arch-cache"; cache-size = <0x20000>; @@ -158,7 +158,7 @@ qcom,lmh-dcvs = <&lmh_dcvs0>; #cooling-cells = <2>; next-level-cache = <&L2_300>; - sched-energy-costs = <&CPU_COST_0 &CLUSTER_COST_0>; + sched-energy-costs = <&CPU_COST_0>; L2_300: l2-cache { compatible = "arm,arch-cache"; cache-size = <0x20000>; @@ -189,7 +189,7 @@ qcom,lmh-dcvs = <&lmh_dcvs1>; #cooling-cells = <2>; next-level-cache = <&L2_400>; - sched-energy-costs = <&CPU_COST_1 &CLUSTER_COST_1>; + sched-energy-costs = <&CPU_COST_1>; L2_400: l2-cache { compatible = "arm,arch-cache"; cache-size = <0x40000>; @@ -220,7 +220,7 @@ qcom,lmh-dcvs = <&lmh_dcvs1>; #cooling-cells = <2>; next-level-cache = <&L2_500>; - sched-energy-costs = <&CPU_COST_1 &CLUSTER_COST_1>; + sched-energy-costs = <&CPU_COST_1>; L2_500: l2-cache { compatible = "arm,arch-cache"; cache-size = <0x40000>; @@ -251,7 +251,7 @@ qcom,lmh-dcvs = <&lmh_dcvs1>; #cooling-cells = <2>; next-level-cache = <&L2_600>; - sched-energy-costs = <&CPU_COST_1 &CLUSTER_COST_1>; + sched-energy-costs = <&CPU_COST_1>; L2_600: l2-cache { compatible = "arm,arch-cache"; cache-size = <0x40000>; @@ -282,7 +282,7 @@ qcom,lmh-dcvs = <&lmh_dcvs1>; #cooling-cells = <2>; next-level-cache = <&L2_700>; - sched-energy-costs = <&CPU_COST_1 &CLUSTER_COST_1>; + sched-energy-costs = <&CPU_COST_1>; L2_700: l2-cache { compatible = "arm,arch-cache"; cache-size = <0x40000>; @@ -368,9 +368,6 @@ 1708800 186 /* speedbin 0,1 */ 1747200 201 /* speedbin 2 */ >; - idle-cost-data = < - 22 18 14 12 - >; }; CPU_COST_1: core-cost1 { busy-cost-data = < @@ -401,70 +398,6 @@ 2112000 1308 /* speedbin 2 */ 2208000 1363 /* speedbin 2 */ >; - idle-cost-data = < - 100 80 60 40 - >; - }; - CLUSTER_COST_0: cluster-cost0 { - busy-cost-data = < - 300000 3 - 422400 4 - 499200 4 - 576000 4 - 652800 5 - 748800 5 - 825600 6 - 902400 7 - 979200 7 - 1056000 8 - 1132800 9 - 1209600 9 - 1286400 10 - 1363200 11 - 1440000 12 - 1516800 13 - 1593600 15 - 1651200 17 /* speedbin 0,1 */ - 1670400 19 /* speedbin 2 */ - 1708800 21 /* speedbin 0,1 */ - 1747200 23 /* speedbin 2 */ - >; - idle-cost-data = < - 4 3 2 1 - >; - }; - CLUSTER_COST_1: cluster-cost1 { - busy-cost-data = < - 300000 24 - 422400 24 - 499200 25 - 576000 25 - 652800 26 - 729600 27 - 806400 28 - 883200 29 - 960000 30 - 1036800 32 - 1113600 34 - 1190400 37 - 1267200 40 - 1344000 45 - 1420800 50 - 1497600 57 - 1574400 64 - 1651200 74 - 1728000 84 - 1804800 96 - 1881600 106 - 1958400 113 - 2035000 120 /* speedbin 1,2 */ - 2092000 125 /* speedbin 1 */ - 2112000 127 /* speedbin 2 */ - 2208000 130 /* speedbin 2 */ - >; - idle-cost-data = < - 4 3 2 1 - >; }; }; /* energy-costs */ From d2047b2d5a2381ccca40c51270d54c55c30637b6 Mon Sep 17 00:00:00 2001 From: Sayali Lokhande Date: Thu, 31 Jan 2019 15:03:34 +0530 Subject: [PATCH 164/356] scsi: ufs: Update condition for setting PA_TXHSADAPTTYPE Attribute PA_TXHSADAPTTYPE(0x15d4) is added in unipro version 1.8 onwards for UFS HS G4 support. On older version's (which do not support G4), ufshcd_dme_set for attr 0x15d4 always fails with INVALID_MIB_ATTRIBUTE and fails QMVS validation. This change uses correct condition check before setting UFS adapt type attribute. Change-Id: I3c8ff1b3b2aff2aba86cf0d812e50d90466ccd18 Signed-off-by: Sayali Lokhande --- drivers/scsi/ufs/ufshcd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index a1c7b1d05a6d..c7ac560c1cde 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -5026,9 +5026,9 @@ int ufshcd_dme_set_attr(struct ufs_hba *hba, u32 attr_sel, } while (ret && peer && --retries); if (ret) - dev_err(hba->dev, "%s: attr-id 0x%x val 0x%x failed %d retries\n", + dev_err(hba->dev, "%s: attr-id 0x%x val 0x%x failed %d retries, err %d\n", set, UIC_GET_ATTR_ID(attr_sel), mib_val, - UFS_UIC_COMMAND_RETRIES - retries); + UFS_UIC_COMMAND_RETRIES - retries, ret); return ret; } @@ -5601,7 +5601,7 @@ int ufshcd_change_power_mode(struct ufs_hba *hba, /* INITIAL ADAPT */ ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXHSADAPTTYPE), PA_INITIAL_ADAPT); - } else { + } else if (hba->ufs_version >= UFSHCI_VERSION_30) { /* NO ADAPT */ ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXHSADAPTTYPE), PA_NO_ADAPT); } From 73436078fa888e6f079cf94ea2c0505bf83505fe Mon Sep 17 00:00:00 2001 From: Yumi Yukimura Date: Sat, 17 Feb 2024 23:27:48 +0800 Subject: [PATCH 165/356] msm: usb_bam: Bring back parsing of "qcom,ignore-core-reset-ack" dt property This was removed as part of msm-4.14 commit 9c3fadb7efc7f ("msm: usb_bam: remove HSUSB/HSIC support"). However, It doesn't remove the usage of `usb_bam_data->ignore_core_reset_ack`. As I've seen so far, This property is used by MSM8917/37/53/96/98 and SDM429/439/660/670/845 in their stock kernels. Change-Id: I758f5a6071c9b52f3d452413bd6200607fed39a8 --- drivers/platform/msm/usb_bam.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c index 2f0dd8f282df..7ff5fcfd3915 100644 --- a/drivers/platform/msm/usb_bam.c +++ b/drivers/platform/msm/usb_bam.c @@ -2927,6 +2927,9 @@ static struct msm_usb_bam_data *usb_bam_dt_to_data( else usb_bam_data->usb_bam_fifo_baseaddr = addr; + usb_bam_data->ignore_core_reset_ack = of_property_read_bool(node, + "qcom,ignore-core-reset-ack"); + usb_bam_data->disable_clk_gating = of_property_read_bool(node, "qcom,disable-clk-gating"); From 1b0426b1b162dadc2b2aadcb062155f84385e531 Mon Sep 17 00:00:00 2001 From: Gopala Krishna Nuthaki Date: Tue, 17 Jun 2025 09:43:08 +0500 Subject: [PATCH 166/356] drivers: thermal: tsens: Cache the trip temperature Cache the trip temperature for the thermal framework to read. Once the trip occurs the temperature at which the trip or trip clear is cached till the thermal framework sets a new trip value. This will ensure that the thermal framework will read the exact temperature as the driver and it cannot go out of sync. Reset cached temperature value just after thermal framework notification in tsens irq handler. Change-Id: I279f08e76f2cbf7f25e3187abfc3c8effbffc388 Signed-off-by: Gopala Krishna Nuthaki --- drivers/thermal/msm-tsens.c | 2 ++ drivers/thermal/tsens.h | 1 + drivers/thermal/tsens2xxx.c | 7 +++++++ 3 files changed, 10 insertions(+) diff --git a/drivers/thermal/msm-tsens.c b/drivers/thermal/msm-tsens.c index d79e32fd291f..ea136b008f41 100644 --- a/drivers/thermal/msm-tsens.c +++ b/drivers/thermal/msm-tsens.c @@ -212,6 +212,7 @@ static int tsens_thermal_zone_register(struct tsens_device *tmdev) for (i = 0; i < TSENS_MAX_SENSORS; i++) { tmdev->sensor[i].tmdev = tmdev; tmdev->sensor[i].hw_id = i; + tmdev->sensor[i].cached_temp = INT_MIN; if (tmdev->ops->sensor_en(tmdev, i)) { tmdev->sensor[i].tzd = devm_thermal_zone_of_sensor_register( @@ -264,6 +265,7 @@ static void tsens_therm_fwk_notify(struct work_struct *work) TSENS_DBG(tmdev, "Controller %pK\n", &tmdev->phys_addr_tm); for (i = 0; i < TSENS_MAX_SENSORS; i++) { + tmdev->sensor[i].cached_temp = INT_MIN; if (tmdev->ops->sensor_en(tmdev, i)) { rc = tsens_get_temp(&tmdev->sensor[i], &temp); if (rc) { diff --git a/drivers/thermal/tsens.h b/drivers/thermal/tsens.h index 4398615857d0..f023620297b7 100644 --- a/drivers/thermal/tsens.h +++ b/drivers/thermal/tsens.h @@ -137,6 +137,7 @@ struct tsens_sensor { struct tsens_context thr_state; int offset; int slope; + int cached_temp; }; /** diff --git a/drivers/thermal/tsens2xxx.c b/drivers/thermal/tsens2xxx.c index ea78f9048e1f..b6e1cd33795b 100644 --- a/drivers/thermal/tsens2xxx.c +++ b/drivers/thermal/tsens2xxx.c @@ -155,6 +155,11 @@ static int tsens2xxx_get_temp(struct tsens_sensor *sensor, int *temp) sensor_addr = TSENS_TM_SN_STATUS(tmdev->tsens_tm_addr); trdy = TSENS_TM_TRDY(tmdev->tsens_tm_addr); + if (sensor->cached_temp != INT_MIN) { + *temp = sensor->cached_temp; + goto dbg; + } + code = readl_relaxed_no_log(trdy); if (!((code & TSENS_TM_TRDY_FIRST_ROUND_COMPLETE) >> @@ -762,10 +767,12 @@ static irqreturn_t tsens_tm_irq_thread(int irq, void *data) if (upper_thr || lower_thr) { /* Use id for multiple controllers */ + tm->sensor[i].cached_temp = temp; pr_debug("sensor:%d trigger temp (%d degC)\n", tm->sensor[i].hw_id, temp); of_thermal_handle_trip_temp(tm->sensor[i].tzd, temp); } + tm->sensor[i].cached_temp = INT_MIN; } /* Disable monitoring sensor trip threshold for triggered sensor */ From 1b3753fbc2c4d1485ca40a8c426d7b05ac9b989d Mon Sep 17 00:00:00 2001 From: duckyduckg Date: Thu, 19 Jun 2025 00:41:19 +0500 Subject: [PATCH 167/356] drivers: tty: msm_geni_serial: fix stop rx sequence and irq deadlock fix stale delay 1ms which is 10ms. decrease uart port to 6, originally i set it to 10,8 but uart misbehaved while bluetooth is in use. Signed-off-by: duckyduckg --- drivers/tty/serial/msm_geni_serial.c | 59 ++++++++++------------------ 1 file changed, 21 insertions(+), 38 deletions(-) diff --git a/drivers/tty/serial/msm_geni_serial.c b/drivers/tty/serial/msm_geni_serial.c index 5d745def2354..40df2f1e8c11 100644 --- a/drivers/tty/serial/msm_geni_serial.c +++ b/drivers/tty/serial/msm_geni_serial.c @@ -105,9 +105,9 @@ #define STALE_TIMEOUT (16) #define STALE_COUNT (DEFAULT_BITS_PER_CHAR * STALE_TIMEOUT) #define SEC_TO_USEC (1000000) -#define STALE_DELAY (1000) //10msec +#define STALE_DELAY (10000) //10msec #define DEFAULT_BITS_PER_CHAR (10) -#define GENI_UART_NR_PORTS (15) +#define GENI_UART_NR_PORTS (6) #define GENI_UART_CONS_PORTS (1) #define DEF_FIFO_DEPTH_WORDS (16) #define DEF_TX_WM (2) @@ -272,6 +272,7 @@ static int msm_geni_serial_get_ver_info(struct uart_port *uport); static void msm_geni_serial_set_manual_flow(bool enable, struct msm_geni_serial_port *port); static bool handle_rx_dma_xfer(u32 s_irq_status, struct uart_port *uport); +static void msm_geni_serial_allow_rx(struct msm_geni_serial_port *port); static int uart_line_id; static bool is_earlycon; @@ -1539,7 +1540,6 @@ static int stop_rx_sequencer(struct uart_port *uport) bool is_rx_active; u32 dma_rx_status, s_irq_status; int usage_count; - int iter = 0; IPC_LOG_MSG(port->ipc_log_misc, "%s\n", __func__); @@ -1553,19 +1553,13 @@ static int stop_rx_sequencer(struct uart_port *uport) } if (!uart_console(uport)) { - if (!port->bypass_flow_control) - msm_geni_serial_set_manual_flow(false, port); /* * Wait for the stale timeout around 10msec to happen * if there is any data pending in the rx fifo. - * This will help to handle incoming rx data in - * stop_rx_sequencer for interrupt latency or - * system delay cases. + * This will help to handle incoming rx data in stop_rx_sequencer + * for interrupt latency or system delay cases. */ - while (iter < STALE_DELAY) { - iter++; - udelay(10); - } + udelay(STALE_DELAY); dma_rx_status = geni_read_reg_nolog(uport->membase, SE_DMA_RX_IRQ_STAT); @@ -1584,8 +1578,7 @@ static int stop_rx_sequencer(struct uart_port *uport) IPC_LOG_MSG(port->ipc_log_misc, "%s: Interrupt delay\n", __func__); handle_rx_dma_xfer(s_irq_status, uport); - if (pm_runtime_enabled(uport->dev) && - !port->ioctl_count) { + if (!port->ioctl_count) { usage_count = atomic_read( &uport->dev->power.usage_count); IPC_LOG_MSG(port->ipc_log_misc, @@ -1629,10 +1622,10 @@ static int stop_rx_sequencer(struct uart_port *uport) IPC_LOG_MSG(port->console_log, "%s cancel failed timeout:%d is_rx_active:%d 0x%x\n", __func__, timeout, is_rx_active, geni_status); - geni_se_dump_dbg_regs(&port->serial_rsc, - uport->membase, port->ipc_log_misc); msm_geni_update_uart_error_code(port, UART_ERROR_RX_CANCEL_FAIL); + geni_se_dump_dbg_regs(&port->serial_rsc, + uport->membase, port->ipc_log_misc); /* * Possible that stop_rx is called from system resume context @@ -1646,22 +1639,6 @@ static int stop_rx_sequencer(struct uart_port *uport) } port->s_cmd_done = false; - /* Check if Cancel Interrupt arrived but irq is delayed */ - s_irq_status = geni_read_reg(uport->membase, - SE_GENI_S_IRQ_STATUS); - if (s_irq_status & S_CMD_CANCEL_EN) { - /* Clear delayed Cancel IRQ */ - geni_write_reg(S_CMD_CANCEL_EN, uport->membase, - SE_GENI_S_IRQ_CLEAR); - IPC_LOG_MSG(port->ipc_log_misc, - "%s Cancel Command succeeded 0x%x\n", - __func__, s_irq_status); - /* Reset the error code and skip abort operation */ - msm_geni_update_uart_error_code(port, - UART_ERROR_DEFAULT); - goto exit_enable_irq; - } - reinit_completion(&port->s_cmd_timeout); geni_abort_s_cmd(uport->membase); /* Ensure this goes through before polling. */ @@ -1685,6 +1662,9 @@ static int stop_rx_sequencer(struct uart_port *uport) geni_se_dump_dbg_regs(&port->serial_rsc, uport->membase, port->ipc_log_misc); } + msm_geni_serial_allow_rx(port); + geni_write_reg(FORCE_DEFAULT, uport->membase, + GENI_FORCE_DEFAULT_REG); if (port->xfer_mode == SE_DMA) { port->s_cmd_done = false; @@ -1702,14 +1682,12 @@ static int stop_rx_sequencer(struct uart_port *uport) } } } -exit_enable_irq: + /* Enable the interrupts once the cancel operation is done. */ msm_geni_serial_enable_interrupts(uport); port->s_cmd = false; exit_rx_seq: - if (!uart_console(uport) && !port->bypass_flow_control) - msm_geni_serial_set_manual_flow(true, port); geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS); IPC_LOG_MSG(port->ipc_log_misc, "%s: End 0x%x dma_dbg:0x%x\n", @@ -3685,13 +3663,18 @@ static int msm_geni_serial_probe(struct platform_device *pdev) INIT_WORK(&dev_port->work, msm_geni_serial_worker); } + /* + * In abrupt kill scenarios, previous state of the uart causing runtime + * resume, lead to spinlock bug in stop_rx_sequencer, so initializing it + * before + */ + if (!is_console) + spin_lock_init(&dev_port->rx_lock); + ret = uart_add_one_port(drv, uport); if (ret) goto exit_workqueue_destroy; - if (!uart_console(uport)) - spin_lock_init(&dev_port->rx_lock); - /* * Earlyconsole to kernel console will switch happen after * uart_add_one_port. Hence marking is_earlycon to false here. From 0f5cc7f48451f7074b72df688d031063e15c4223 Mon Sep 17 00:00:00 2001 From: duckyduckg Date: Thu, 19 Jun 2025 01:42:21 +0500 Subject: [PATCH 168/356] drivers: tty: msm_geni_serial: fix rx_lock deadlock Signed-off-by: duckyduckg --- drivers/tty/serial/msm_geni_serial.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/msm_geni_serial.c b/drivers/tty/serial/msm_geni_serial.c index 40df2f1e8c11..00aa944e9111 100644 --- a/drivers/tty/serial/msm_geni_serial.c +++ b/drivers/tty/serial/msm_geni_serial.c @@ -2044,8 +2044,9 @@ static bool handle_rx_dma_xfer(u32 s_irq_status, struct uart_port *uport) bool drop_rx = false; struct msm_geni_serial_port *msm_port = GET_DEV_PORT(uport); u32 dma_rx_status; + unsigned long lock_flags; - spin_lock(&msm_port->rx_lock); + spin_lock_irqsave(&msm_port->rx_lock, lock_flags); dma_rx_status = geni_read_reg_nolog(uport->membase, SE_DMA_RX_IRQ_STAT); @@ -2111,7 +2112,7 @@ static bool handle_rx_dma_xfer(u32 s_irq_status, struct uart_port *uport) if (s_irq_status & (S_CMD_CANCEL_EN | S_CMD_ABORT_EN)) ret = true; - spin_unlock(&msm_port->rx_lock); + spin_unlock_irqrestore(&msm_port->rx_lock, lock_flags); return ret; } From 23feb8445b3eea55eaf9e8f546f051e1989a25c2 Mon Sep 17 00:00:00 2001 From: Chandana Kishori Chiluveru Date: Thu, 19 Jun 2025 12:06:48 +0500 Subject: [PATCH 169/356] Backport: serial: msm_geni_serial: Bailout from wait_for_transfers_inflight This change is to avoid potential race btw stop rx and incoming SOC RX data in parallel. During suspend path wait_for_transfers_inflight() logic will check for TX/RX data pending for completion. Check for RX_LEN_IN status in wait_for_transfers_inflight() and return -EBUSY to avoid race between stop_rx and SOC RX data. Change-Id: I28702d3dc11ee4b6d3fe5b4bad9a19099d8cf725 Signed-off-by: Chandana Kishori Chiluveru Signed-off-by: duckyduckg --- drivers/tty/serial/msm_geni_serial.c | 39 +++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/drivers/tty/serial/msm_geni_serial.c b/drivers/tty/serial/msm_geni_serial.c index 00aa944e9111..16ef53a3b465 100644 --- a/drivers/tty/serial/msm_geni_serial.c +++ b/drivers/tty/serial/msm_geni_serial.c @@ -522,16 +522,17 @@ static bool check_transfers_inflight(struct uart_port *uport) return xfer_on; } -static void wait_for_transfers_inflight(struct uart_port *uport) +static int wait_for_transfers_inflight(struct uart_port *uport) { int iter = 0; struct msm_geni_serial_port *port = GET_DEV_PORT(uport); unsigned int geni_status; + u32 rx_len_in = 0; geni_status = geni_read_reg_nolog(uport->membase, SE_GENI_STATUS); /* Possible stop rx is called before this. */ if (!(geni_status & S_GENI_CMD_ACTIVE)) - return; + return 0; while (iter < WAIT_XFER_MAX_ITER) { if (check_transfers_inflight(uport)) { @@ -543,9 +544,18 @@ static void wait_for_transfers_inflight(struct uart_port *uport) } } if (check_transfers_inflight(uport)) { + rx_len_in = + geni_read_reg_nolog(uport->membase, SE_DMA_RX_LEN_IN); + if (rx_len_in) { + IPC_LOG_MSG(port->ipc_log_misc, + "%s: Bailout rx_len_in is set\n", + __func__); + return -EBUSY; + } geni_se_dump_dbg_regs(&port->serial_rsc, uport->membase, port->ipc_log_misc); } + return 0; } static int vote_clock_on(struct uart_port *uport) @@ -594,7 +604,7 @@ static int vote_clock_off(struct uart_port *uport) __func__, port->ioctl_count); return -EPERM; } - wait_for_transfers_inflight(uport); + ret = wait_for_transfers_inflight(uport); if (ret) { IPC_LOG_MSG(port->ipc_log_pwr, "%s wait_for_transfer_inflight return ret: %d", @@ -664,6 +674,7 @@ static int msm_geni_serial_ioctl(struct uart_port *uport, unsigned int cmd, static void msm_geni_serial_break_ctl(struct uart_port *uport, int ctl) { struct msm_geni_serial_port *port = GET_DEV_PORT(uport); + int ret = 0; if (!uart_console(uport) && device_pending_suspend(uport)) { IPC_LOG_MSG(port->ipc_log_misc, @@ -673,7 +684,11 @@ static void msm_geni_serial_break_ctl(struct uart_port *uport, int ctl) } if (ctl) { - wait_for_transfers_inflight(uport); + ret = wait_for_transfers_inflight(uport); + if (ret) + IPC_LOG_MSG(port->ipc_log_misc, + "%s: wait_for_transfer_inflight return ret:%d\n", + __func__, ret); geni_setup_m_cmd(uport->membase, UART_START_BREAK, 0); } else { geni_setup_m_cmd(uport->membase, UART_STOP_BREAK, 0); @@ -2420,7 +2435,11 @@ static void msm_geni_serial_shutdown(struct uart_port *uport) disable_irq(uport->irq); } else { msm_geni_serial_power_on(uport); - wait_for_transfers_inflight(uport); + ret = wait_for_transfers_inflight(uport); + if (ret) + IPC_LOG_MSG(msm_port->ipc_log_misc, + "%s: wait_for_transfer_inflight return ret:%d\n", + __func__, ret); msm_geni_serial_stop_tx(uport); } @@ -3750,7 +3769,15 @@ static int msm_geni_serial_runtime_suspend(struct device *dev) SE_GENI_STATUS); IPC_LOG_MSG(port->ipc_log_pwr, "%s: Start\n", __func__); - wait_for_transfers_inflight(&port->uport); + ret = wait_for_transfers_inflight(&port->uport); + if (ret) { + IPC_LOG_MSG(port->ipc_log_pwr, + "%s: wait_for_transfer_inflight return ret:%d\n", + __func__, ret); + /* Flow on from UART */ + msm_geni_serial_allow_rx(port); + return -EBUSY; + } /* * Manual RFR On. * Stop Rx. From 041e4d2d65d77fd6a6a3345cfbe7f7167012d6c0 Mon Sep 17 00:00:00 2001 From: duckyduckg Date: Fri, 20 Jun 2025 11:56:16 +0500 Subject: [PATCH 170/356] drivers: tty: serial: msm_geni_serial: exit early when reset is detected and handled Signed-off-by: duckyduckg --- drivers/tty/serial/msm_geni_serial.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/tty/serial/msm_geni_serial.c b/drivers/tty/serial/msm_geni_serial.c index 16ef53a3b465..1bc8b9bb0476 100644 --- a/drivers/tty/serial/msm_geni_serial.c +++ b/drivers/tty/serial/msm_geni_serial.c @@ -2073,6 +2073,7 @@ static bool handle_rx_dma_xfer(u32 s_irq_status, struct uart_port *uport) IPC_LOG_MSG(msm_port->ipc_log_misc, "%s.Reset done. 0x%x.\n", __func__, dma_rx_status); ret = true; + goto exit; } if (dma_rx_status & UART_DMA_RX_ERRS) { @@ -2127,6 +2128,7 @@ static bool handle_rx_dma_xfer(u32 s_irq_status, struct uart_port *uport) if (s_irq_status & (S_CMD_CANCEL_EN | S_CMD_ABORT_EN)) ret = true; +exit: spin_unlock_irqrestore(&msm_port->rx_lock, lock_flags); return ret; } From d51b7b1e2ba372fc114e2e62b246df7f2ee8cdaa Mon Sep 17 00:00:00 2001 From: duckyduckg Date: Sat, 21 Jun 2025 21:25:08 +0500 Subject: [PATCH 171/356] clk: qcom: debugcc-sdm845: fix regmap type in GCC for 4.19 * add defines for legacy debugcc sdm845 driver from msm 4.14 * add custom macro to fix **regmap incompatibility because 4.19 uses *regmap. Signed-off-by: duckyduckg --- drivers/clk/qcom/clk-debug.h | 66 +++++++++++++++++++++++++++++++ drivers/clk/qcom/debugcc-sdm845.c | 37 ++++++++--------- 2 files changed, 85 insertions(+), 18 deletions(-) diff --git a/drivers/clk/qcom/clk-debug.h b/drivers/clk/qcom/clk-debug.h index d9e70ce8caf9..ff5cf5718002 100644 --- a/drivers/clk/qcom/clk-debug.h +++ b/drivers/clk/qcom/clk-debug.h @@ -36,6 +36,63 @@ struct measure_clk_data { u32 xo_div4_cbcr; }; +#ifdef CONFIG_MSM_DEBUGCC_SDM845 +/** + * List of Debug clock controllers. + */ +enum debug_cc { + GCC, + CAM_CC, + DISP_CC, + NPU_CC, + GPU_CC, + VIDEO_CC, + CPU_CC, + MC_CC, + MAX_NUM_CC, + CPU, +}; + +/** + * struct clk_src - Structure of clock source for debug mux + * + * @parents: clock name to be used as parent for debug mux. + * @prim_mux_sel: debug mux index at global clock controller. + * @prim_mux_div_val: PLL post-divider setting for the primary mux. + * @dbg_cc: indicates the clock controller for recursive debug + * clock controllers. + * @dbg_cc_mux_sel: indicates the debug mux index at recursive debug mux. + * @mux_sel_mask: indicates the mask for the mux selection. + * @mux_sel_shift: indicates the shift required for mux selection. + * @post_div_mask: indicates the post div mask to be used at recursive + * debug mux. + * @post_div_shift: indicates the shift required for post divider + * configuration. + * @post_div_val: indicates the post div value to be used at recursive + * debug mux. + * @mux_offset: the debug mux offset. + * @post_div_offset: register with post-divider settings for the debug mux. + * @cbcr_offset: branch register to turn on debug mux. + * @misc_div_val: includes any pre-set dividers in the measurement logic. + */ +struct clk_src { + const char *parents; + int prim_mux_sel; + u32 prim_mux_div_val; + enum debug_cc dbg_cc; + int dbg_cc_mux_sel; + u32 mux_sel_mask; + u32 mux_sel_shift; + u32 post_div_mask; + u32 post_div_shift; + u32 post_div_val; + u32 mux_offset; + u32 post_div_offset; + u32 cbcr_offset; + u32 misc_div_val; +}; +#endif + /** * struct clk_debug_mux - Structure of clock debug mux * @@ -63,6 +120,9 @@ struct measure_clk_data { * @hw: handle between common and hardware-specific interfaces. */ struct clk_debug_mux { +#ifdef CONFIG_MSM_DEBUGCC_SDM845 + struct clk_src *parent; +#endif int *mux_sels; int *pre_div_vals; int num_parents; @@ -82,6 +142,12 @@ struct clk_debug_mux { struct clk_hw hw; }; +#ifdef CONFIG_MSM_DEBUGCC_SDM845 +#define MUX_SRC_LIST(...) \ + .parent = (struct clk_src[]){__VA_ARGS__}, \ + .num_parents = ARRAY_SIZE(((struct clk_src[]){__VA_ARGS__})) +#endif + #define to_clk_measure(_hw) container_of((_hw), struct clk_debug_mux, hw) extern const struct clk_ops clk_debug_mux_ops; diff --git a/drivers/clk/qcom/debugcc-sdm845.c b/drivers/clk/qcom/debugcc-sdm845.c index 3c1121f6a17a..4a96312bb502 100644 --- a/drivers/clk/qcom/debugcc-sdm845.c +++ b/drivers/clk/qcom/debugcc-sdm845.c @@ -790,6 +790,7 @@ static const struct of_device_id clk_debug_match_table[] = { {} }; +#define GCC_REGMAP(_mux, _index) ((struct regmap **)(_mux)->regmap)[_index] static int clk_debug_845_probe(struct platform_device *pdev) { struct clk *clk; @@ -822,62 +823,62 @@ static int clk_debug_845_probe(struct platform_device *pdev) return -ENOMEM; if (of_get_property(pdev->dev.of_node, "qcom,gcc", NULL)) { - gcc_debug_mux.regmap[GCC] = + GCC_REGMAP(&gcc_debug_mux, GCC) = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "qcom,gcc"); - if (IS_ERR(gcc_debug_mux.regmap[GCC])) { + if (IS_ERR(GCC_REGMAP(&gcc_debug_mux, GCC))) { pr_err("Failed to map qcom,gcc\n"); - return PTR_ERR(gcc_debug_mux.regmap[GCC]); + return PTR_ERR(GCC_REGMAP(&gcc_debug_mux, GCC)); } } if (of_get_property(pdev->dev.of_node, "qcom,dispcc", NULL)) { - gcc_debug_mux.regmap[DISP_CC] = + GCC_REGMAP(&gcc_debug_mux, DISP_CC) = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "qcom,dispcc"); - if (IS_ERR(gcc_debug_mux.regmap[DISP_CC])) { + if (IS_ERR(GCC_REGMAP(&gcc_debug_mux, DISP_CC))) { pr_err("Failed to map qcom,dispcc\n"); - return PTR_ERR(gcc_debug_mux.regmap[DISP_CC]); + return PTR_ERR(GCC_REGMAP(&gcc_debug_mux, DISP_CC)); } } if (of_get_property(pdev->dev.of_node, "qcom,videocc", NULL)) { - gcc_debug_mux.regmap[VIDEO_CC] = + GCC_REGMAP(&gcc_debug_mux, VIDEO_CC) = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "qcom,videocc"); - if (IS_ERR(gcc_debug_mux.regmap[VIDEO_CC])) { + if (IS_ERR(GCC_REGMAP(&gcc_debug_mux, VIDEO_CC))) { pr_err("Failed to map qcom,videocc\n"); - return PTR_ERR(gcc_debug_mux.regmap[VIDEO_CC]); + return PTR_ERR(GCC_REGMAP(&gcc_debug_mux, VIDEO_CC)); } } if (of_get_property(pdev->dev.of_node, "qcom,camcc", NULL)) { - gcc_debug_mux.regmap[CAM_CC] = + GCC_REGMAP(&gcc_debug_mux, CAM_CC) = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "qcom,camcc"); - if (IS_ERR(gcc_debug_mux.regmap[CAM_CC])) { + if (IS_ERR(GCC_REGMAP(&gcc_debug_mux, CAM_CC))) { pr_err("Failed to map qcom,camcc\n"); - return PTR_ERR(gcc_debug_mux.regmap[CAM_CC]); + return PTR_ERR(GCC_REGMAP(&gcc_debug_mux, CAM_CC)); } } if (of_get_property(pdev->dev.of_node, "qcom,gpucc", NULL)) { - gcc_debug_mux.regmap[GPU_CC] = + GCC_REGMAP(&gcc_debug_mux, GPU_CC) = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "qcom,gpucc"); - if (IS_ERR(gcc_debug_mux.regmap[GPU_CC])) { + if (IS_ERR(GCC_REGMAP(&gcc_debug_mux, GPU_CC))) { pr_err("Failed to map qcom,gpucc\n"); - return PTR_ERR(gcc_debug_mux.regmap[GPU_CC]); + return PTR_ERR(GCC_REGMAP(&gcc_debug_mux, GPU_CC)); } } if (of_get_property(pdev->dev.of_node, "qcom,cpucc", NULL)) { - gcc_debug_mux.regmap[CPU] = + GCC_REGMAP(&gcc_debug_mux, CPU) = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "qcom,cpucc"); - if (IS_ERR(gcc_debug_mux.regmap[CPU])) { + if (IS_ERR(GCC_REGMAP(&gcc_debug_mux, CPU))) { pr_err("Failed to map qcom,cpucc\n"); - return PTR_ERR(gcc_debug_mux.regmap[CPU]); + return PTR_ERR(GCC_REGMAP(&gcc_debug_mux, CPU)); } } From 72fed20f38005d808fed134040a584303a5ad772 Mon Sep 17 00:00:00 2001 From: duckyduckg Date: Sun, 22 Jun 2025 08:08:46 +0500 Subject: [PATCH 172/356] clk: qcom: debugcc-sdm845: add bandwidth voting * from debugcc kona fixes random kernel panic when debugcc driver is used. Signed-off-by: duckyduckg --- drivers/clk/qcom/debugcc-sdm845.c | 48 +++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/drivers/clk/qcom/debugcc-sdm845.c b/drivers/clk/qcom/debugcc-sdm845.c index 4a96312bb502..fc45aa657602 100644 --- a/drivers/clk/qcom/debugcc-sdm845.c +++ b/drivers/clk/qcom/debugcc-sdm845.c @@ -15,9 +15,51 @@ #include #include #include +#include +#include #include "clk-debug.h" +#define MSM_BUS_VECTOR(_src, _dst, _ab, _ib) \ +{ \ + .src = _src, \ + .dst = _dst, \ + .ab = _ab, \ + .ib = _ib, \ +} + +static struct msm_bus_vectors clk_measure_vectors[] = { + MSM_BUS_VECTOR(MSM_BUS_MASTER_AMPSS_M0, + MSM_BUS_SLAVE_CAMERA_CFG, 0, 0), + MSM_BUS_VECTOR(MSM_BUS_MASTER_AMPSS_M0, + MSM_BUS_SLAVE_VENUS_CFG, 0, 0), + MSM_BUS_VECTOR(MSM_BUS_MASTER_AMPSS_M0, + MSM_BUS_SLAVE_DISPLAY_CFG, 0, 0), + MSM_BUS_VECTOR(MSM_BUS_MASTER_AMPSS_M0, + MSM_BUS_SLAVE_CAMERA_CFG, 0, 1), + MSM_BUS_VECTOR(MSM_BUS_MASTER_AMPSS_M0, + MSM_BUS_SLAVE_VENUS_CFG, 0, 1), + MSM_BUS_VECTOR(MSM_BUS_MASTER_AMPSS_M0, + MSM_BUS_SLAVE_DISPLAY_CFG, 0, 1), +}; + +static struct msm_bus_paths clk_measure_usecases[] = { + { + .num_paths = 3, + .vectors = &clk_measure_vectors[0], + }, + { + .num_paths = 3, + .vectors = &clk_measure_vectors[3], + } +}; + +static struct msm_bus_scale_pdata clk_measure_scale_table = { + .usecase = clk_measure_usecases, + .num_usecases = ARRAY_SIZE(clk_measure_usecases), + .name = "clk_measure", +}; + static struct measure_clk_data debug_mux_priv = { .ctl_reg = 0x62024, .status_reg = 0x62028, @@ -882,6 +924,12 @@ static int clk_debug_845_probe(struct platform_device *pdev) } } + gcc_debug_mux.bus_cl_id = + msm_bus_scale_register_client(&clk_measure_scale_table); + + if (!gcc_debug_mux.bus_cl_id) + return -EPROBE_DEFER; + clk = devm_clk_register(&pdev->dev, &gcc_debug_mux.hw); if (IS_ERR(clk)) { dev_err(&pdev->dev, "Unable to register GCC debug mux\n"); From 4e04ac8c94558c48de4b882478cdb442fc0e0cd8 Mon Sep 17 00:00:00 2001 From: Raghavendra Kakarla Date: Wed, 19 Feb 2020 12:36:47 +0530 Subject: [PATCH 173/356] ARM: dts: msm: Disable IPI prediction for sdm845 Disable IPI prediction algorithm to kick in for sdm845. Change-Id: I683101ce965a43c5625bd725260e617ff8ddff6f Signed-off-by: Raghavendra Kakarla --- arch/arm64/boot/dts/qcom/sdm845-pm.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi index e25180c4a43e..d772a31fd912 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-pm.dtsi @@ -47,6 +47,7 @@ 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 */ @@ -89,6 +90,7 @@ qcom,ref-stddev = <100>; qcom,tmr-add = <100>; qcom,ref-premature-cnt = <3>; + qcom,disable-ipi-prediction; qcom,cpu = <&CPU4 &CPU5 &CPU6 &CPU7>; qcom,pm-cpu-level@0 { /* C1 */ From b1416818092e0bc99f16b6acb55cfbb1bb940791 Mon Sep 17 00:00:00 2001 From: voidanix Date: Mon, 13 Jan 2025 11:14:31 +0500 Subject: [PATCH 174/356] ARM64: dts: sdm845: Enable legacy LMH props Devices running sdm845 and older require two props to achieve performance comparable to the one on older kernels. Many thanks to Roberto Sartori for pointing out the issue. Tested on akatsuki to confirm the findings. Link: sonyxperiadev/kernel#2585 Signed-off-by: voidanix --- arch/arm64/boot/dts/qcom/sdm845.dtsi | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index c918debcde27..b9f4c317314c 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -4073,6 +4073,8 @@ <0x17d43000 0x1000>; qcom,affinity = <0>; #thermal-sensor-cells = <0>; + qcom,plat-mitigation-disable; + qcom,legacy-lmh-enable; }; lmh_dcvs1: qcom,limits-dcvs@1 { @@ -4084,6 +4086,8 @@ #thermal-sensor-cells = <0>; isens_vref-supply = <&pm8998_l1_ao>; isens-vref-settings = <880000 880000 20000>; + qcom,plat-mitigation-disable; + qcom,legacy-lmh-enable; }; wil6210: qcom,wil6210 { From 491746cddec10c35e320d5af3d1c54ca1665e4b7 Mon Sep 17 00:00:00 2001 From: Asha Magadi Venkateshamurthy Date: Fri, 24 Jul 2020 09:07:34 +0530 Subject: [PATCH 175/356] ARM: dts: qcom: Enable cpu isolate cooling devices for SDM845 Enable CPU core isolation cooling devices for SDM845. Change-Id: Id494f062bd1722ec8c73e04dabc55e597255aeca --- arch/arm64/boot/dts/qcom/pmi8998.dtsi | 32 +++-------- arch/arm64/boot/dts/qcom/sdm845.dtsi | 80 ++++++++++++++++++--------- 2 files changed, 62 insertions(+), 50 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/pmi8998.dtsi b/arch/arm64/boot/dts/qcom/pmi8998.dtsi index ee258231d68d..76c77f16056f 100644 --- a/arch/arm64/boot/dts/qcom/pmi8998.dtsi +++ b/arch/arm64/boot/dts/qcom/pmi8998.dtsi @@ -790,27 +790,19 @@ cooling-maps { vbat_cpu4 { trip = <&low_vbat>; - cooling-device = - <&CPU4 THERMAL_MAX_LIMIT - THERMAL_MAX_LIMIT>; + cooling-device = <&cpu4_isolate 1 1>; }; vbat_cpu5 { trip = <&low_vbat>; - cooling-device = - <&CPU5 THERMAL_MAX_LIMIT - THERMAL_MAX_LIMIT>; + cooling-device = <&cpu5_isolate 1 1>; }; vbat_map6 { trip = <&low_vbat>; - cooling-device = - <&CPU6 THERMAL_MAX_LIMIT - THERMAL_MAX_LIMIT>; + cooling-device = <&cpu6_isolate 1 1>; }; vbat_map7 { trip = <&low_vbat>; - cooling-device = - <&CPU7 THERMAL_MAX_LIMIT - THERMAL_MAX_LIMIT>; + cooling-device = <&cpu7_isolate 1 1>; }; }; }; @@ -864,27 +856,19 @@ cooling-maps { soc_cpu4 { trip = <&low_soc>; - cooling-device = - <&CPU4 THERMAL_MAX_LIMIT - THERMAL_MAX_LIMIT>; + cooling-device = <&cpu4_isolate 1 1>; }; soc_cpu5 { trip = <&low_soc>; - cooling-device = - <&CPU5 THERMAL_MAX_LIMIT - THERMAL_MAX_LIMIT>; + cooling-device = <&cpu5_isolate 1 1>; }; soc_map6 { trip = <&low_soc>; - cooling-device = - <&CPU6 THERMAL_MAX_LIMIT - THERMAL_MAX_LIMIT>; + cooling-device = <&cpu6_isolate 1 1>; }; soc_map7 { trip = <&low_soc>; - cooling-device = - <&CPU7 THERMAL_MAX_LIMIT - THERMAL_MAX_LIMIT>; + cooling-device = <&cpu7_isolate 1 1>; }; }; }; diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index b9f4c317314c..ab7b13437b04 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -3669,9 +3669,7 @@ cooling-maps { emerg_cdev0 { trip = <&emerg_config0>; - cooling-device = - <&CPU0 THERMAL_MAX_LIMIT - THERMAL_MAX_LIMIT>; + cooling-device = <&cpu0_isolate 1 1>; }; }; }; @@ -3692,9 +3690,7 @@ cooling-maps { emerg_cdev1 { trip = <&emerg_config1>; - cooling-device = - <&CPU1 THERMAL_MAX_LIMIT - THERMAL_MAX_LIMIT>; + cooling-device = <&cpu1_isolate 1 1>; }; }; }; @@ -3715,9 +3711,7 @@ cooling-maps { emerg_cdev2 { trip = <&emerg_config2>; - cooling-device = - <&CPU2 THERMAL_MAX_LIMIT - THERMAL_MAX_LIMIT>; + cooling-device = <&cpu2_isolate 1 1>; }; }; }; @@ -3738,9 +3732,7 @@ cooling-maps { emerg_cdev3 { trip = <&emerg_config3>; - cooling-device = - <&CPU3 THERMAL_MAX_LIMIT - THERMAL_MAX_LIMIT>; + cooling-device = <&cpu3_isolate 1 1>; }; }; }; @@ -3761,9 +3753,7 @@ cooling-maps { emerg_cdev4 { trip = <&emerg_config4>; - cooling-device = - <&CPU4 THERMAL_MAX_LIMIT - THERMAL_MAX_LIMIT>; + cooling-device = <&cpu4_isolate 1 1>; }; }; }; @@ -3784,9 +3774,7 @@ cooling-maps { emerg_cdev5 { trip = <&emerg_config5>; - cooling-device = - <&CPU5 THERMAL_MAX_LIMIT - THERMAL_MAX_LIMIT>; + cooling-device = <&cpu5_isolate 1 1>; }; }; }; @@ -3807,9 +3795,7 @@ cooling-maps { emerg_cdev6 { trip = <&emerg_config6>; - cooling-device = - <&CPU6 THERMAL_MAX_LIMIT - THERMAL_MAX_LIMIT>; + cooling-device = <&cpu6_isolate 1 1>; }; }; }; @@ -3830,9 +3816,7 @@ cooling-maps { emerg_cdev7 { trip = <&emerg_config7>; - cooling-device = - <&CPU7 THERMAL_MAX_LIMIT - THERMAL_MAX_LIMIT>; + cooling-device = <&cpu7_isolate 1 1>; }; }; }; @@ -4073,8 +4057,8 @@ <0x17d43000 0x1000>; qcom,affinity = <0>; #thermal-sensor-cells = <0>; - qcom,plat-mitigation-disable; qcom,legacy-lmh-enable; + qcom,no-cooling-device-register; }; lmh_dcvs1: qcom,limits-dcvs@1 { @@ -4086,8 +4070,52 @@ #thermal-sensor-cells = <0>; isens_vref-supply = <&pm8998_l1_ao>; isens-vref-settings = <880000 880000 20000>; - qcom,plat-mitigation-disable; qcom,legacy-lmh-enable; + qcom,no-cooling-device-register; + }; + + + qcom,cpu-isolation { + compatible = "qcom,cpu-isolate"; + cpu0_isolate: cpu0-isolate { + qcom,cpu = <&CPU0>; + #cooling-cells = <2>; + }; + + cpu1_isolate: cpu1-isolate { + qcom,cpu = <&CPU1>; + #cooling-cells = <2>; + }; + + cpu2_isolate: cpu2-isolate { + qcom,cpu = <&CPU2>; + #cooling-cells = <2>; + }; + + cpu3_isolate: cpu3-isolate { + qcom,cpu = <&CPU3>; + #cooling-cells = <2>; + }; + + cpu4_isolate: cpu4-isolate { + qcom,cpu = <&CPU4>; + #cooling-cells = <2>; + }; + + cpu5_isolate: cpu5-isolate { + qcom,cpu = <&CPU5>; + #cooling-cells = <2>; + }; + + cpu6_isolate: cpu6-isolate { + qcom,cpu = <&CPU6>; + #cooling-cells = <2>; + }; + + cpu7_isolate: cpu7-isolate { + qcom,cpu = <&CPU7>; + #cooling-cells = <2>; + }; }; wil6210: qcom,wil6210 { From c47501ade8be0dc5d27a6e633c37c7dda28ec7f1 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Wed, 13 Aug 2025 20:43:17 +0000 Subject: [PATCH 176/356] ARM64: dts: sdm845: Update LMH isens_vref properties for kernel 4.19 --- arch/arm64/boot/dts/qcom/sdm845.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index ab7b13437b04..0b7d8d5a5453 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -4068,8 +4068,8 @@ reg = <0x17d70800 0x1000>, <0x17d45800 0x1000>; #thermal-sensor-cells = <0>; - isens_vref-supply = <&pm8998_l1_ao>; - isens-vref-settings = <880000 880000 20000>; + isens_vref_0p8-supply = <&pm8998_l1_ao>; + isens-vref-0p8-settings = <880000 880000 20000>; qcom,legacy-lmh-enable; qcom,no-cooling-device-register; }; From f9c9d863aecb17843192fdb4e5b06dbbee2a5725 Mon Sep 17 00:00:00 2001 From: Danny Lin Date: Thu, 11 Jun 2020 18:47:55 -0700 Subject: [PATCH 177/356] ion: Add compatibility with legacy Ion v1 ABI Kernel 4.12 revamped the Ion ABI [1], rendering it incompatible with blobs made to work with the old "v1" ABI. This commit implements the old ABI by mapping legacy Ion handles to dma-buf fds and adding simple implementations of the ioctls that no longer exist. The alloc ioctl's arguments struct has changed and none of the other ioctls conflict, so this implementation is compatible with blobs using both the v1 and v2 ABIs. dma-buf allocations are automatically freed when no references to the fd remain, so the FREE ioctl doesn't need to do anything meaningful. However, newer blobs using libion will call FREE with a handle of 0 to check which ABI the kernel implements and decide whether to use v1 or v2. Because we want to use v2 as much as possible for efficiency, FREE needs to return -ENOTTY to pretend that it doesn't exist if it detects that the call was made by libion for probing the ABI, so it is not truly a no-op. Support for cache maintenance operations and 32-bit clients will be added later. [1] https://source.android.com/devices/architecture/kernel/ion_abi_changes Co-authored-by: dianlujitao Signed-off-by: Danny Lin Signed-off-by: Subhajeet Muhuri --- drivers/staging/android/ion/Kconfig | 6 + drivers/staging/android/ion/Makefile | 3 + drivers/staging/android/ion/compat_ion.c | 159 +++++++++++++++++++++++ drivers/staging/android/ion/compat_ion.h | 29 +++++ drivers/staging/android/ion/ion-ioctl.c | 48 +++++++ drivers/staging/android/ion/ion.c | 5 + drivers/staging/android/ion/ion_legacy.h | 101 ++++++++++++++ 7 files changed, 351 insertions(+) create mode 100644 drivers/staging/android/ion/compat_ion.c create mode 100644 drivers/staging/android/ion/compat_ion.h create mode 100644 drivers/staging/android/ion/ion_legacy.h diff --git a/drivers/staging/android/ion/Kconfig b/drivers/staging/android/ion/Kconfig index 813407f45741..d7d8a38c3765 100644 --- a/drivers/staging/android/ion/Kconfig +++ b/drivers/staging/android/ion/Kconfig @@ -11,6 +11,12 @@ menuconfig ION If you're not using Android its probably safe to say N here. +config ION_LEGACY + bool "Legacy ion" + depends on ION + help + Choose this option to enable the legacy ion. If in doubt, say N. + config ION_SYSTEM_HEAP bool "Ion system heap" depends on ION diff --git a/drivers/staging/android/ion/Makefile b/drivers/staging/android/ion/Makefile index dc638f080d7f..2b6d1525cea3 100644 --- a/drivers/staging/android/ion/Makefile +++ b/drivers/staging/android/ion/Makefile @@ -5,3 +5,6 @@ obj-$(CONFIG_ION) += ion.o ion-ioctl.o ion_heap.o \ ion_system_secure_heap.o ion_cma_heap.o \ ion_secure_util.o ion_cma_secure_heap.o msm/ +ifdef CONFIG_COMPAT +obj-$(CONFIG_ION_LEGACY) += compat_ion.o +endif diff --git a/drivers/staging/android/ion/compat_ion.c b/drivers/staging/android/ion/compat_ion.c new file mode 100644 index 000000000000..057810447f42 --- /dev/null +++ b/drivers/staging/android/ion/compat_ion.c @@ -0,0 +1,159 @@ +/* + * drivers/staging/android/ion/compat_ion.c + * + * Copyright (C) 2013 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 "ion.h" +#include "compat_ion.h" +#include "ion_legacy.h" + +/* See drivers/staging/android/uapi/ion.h for the definition of these structs */ +struct compat_ion_old_allocation_data { + compat_size_t len; + compat_size_t align; + compat_uint_t heap_id_mask; + compat_uint_t flags; + compat_int_t handle; +}; + +struct compat_ion_handle_data { + compat_int_t handle; +}; + +#define COMPAT_ION_IOC_ALLOC _IOWR(ION_IOC_MAGIC, 0, \ + struct compat_ion_old_allocation_data) +#define COMPAT_ION_IOC_FREE _IOWR(ION_IOC_MAGIC, 1, \ + struct compat_ion_handle_data) + +static int compat_get_ion_allocation_data( + struct compat_ion_old_allocation_data __user *data32, + struct ion_old_allocation_data __user *data) +{ + compat_size_t s; + compat_uint_t u; + compat_int_t i; + int err; + + err = get_user(s, &data32->len); + err |= put_user(s, &data->len); + err |= get_user(s, &data32->align); + err |= put_user(s, &data->align); + err |= get_user(u, &data32->heap_id_mask); + err |= put_user(u, &data->heap_id_mask); + err |= get_user(u, &data32->flags); + err |= put_user(u, &data->flags); + err |= get_user(i, &data32->handle); + err |= put_user(i, &data->handle); + + return err; +} + +static int compat_get_ion_handle_data( + struct compat_ion_handle_data __user *data32, + struct ion_handle_data __user *data) +{ + compat_int_t i; + int err; + + err = get_user(i, &data32->handle); + err |= put_user(i, &data->handle); + + return err; +} + +static int compat_put_ion_allocation_data( + struct compat_ion_old_allocation_data __user *data32, + struct ion_old_allocation_data __user *data) +{ + compat_size_t s; + compat_uint_t u; + compat_int_t i; + int err; + + err = get_user(s, &data->len); + err |= put_user(s, &data32->len); + err |= get_user(s, &data->align); + err |= put_user(s, &data32->align); + err |= get_user(u, &data->heap_id_mask); + err |= put_user(u, &data32->heap_id_mask); + err |= get_user(u, &data->flags); + err |= put_user(u, &data32->flags); + err |= get_user(i, &data->handle); + err |= put_user(i, &data32->handle); + + return err; +} + +long compat_ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + long ret; + + if (!filp->f_op->unlocked_ioctl) + return -ENOTTY; + + switch (cmd) { + case COMPAT_ION_IOC_ALLOC: + { + struct compat_ion_old_allocation_data __user *data32; + struct ion_old_allocation_data __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (!data) + return -EFAULT; + + err = compat_get_ion_allocation_data(data32, data); + if (err) + return err; + ret = filp->f_op->unlocked_ioctl(filp, ION_OLD_IOC_ALLOC, + (unsigned long)data); + err = compat_put_ion_allocation_data(data32, data); + return ret ? ret : err; + } + case COMPAT_ION_IOC_FREE: + { + struct compat_ion_handle_data __user *data32; + struct ion_handle_data __user *data; + int err; + + data32 = compat_ptr(arg); + data = compat_alloc_user_space(sizeof(*data)); + if (!data) + return -EFAULT; + + err = compat_get_ion_handle_data(data32, data); + if (err) + return err; + + return filp->f_op->unlocked_ioctl(filp, ION_IOC_FREE, + (unsigned long)data); + } + case ION_IOC_SHARE: + case ION_IOC_MAP: + case ION_IOC_IMPORT: + case ION_IOC_ALLOC: + case ION_IOC_HEAP_QUERY: + case ION_IOC_PREFETCH: + case ION_IOC_DRAIN: + return filp->f_op->unlocked_ioctl(filp, cmd, + (unsigned long)compat_ptr(arg)); + default: + return -ENOIOCTLCMD; + } +} diff --git a/drivers/staging/android/ion/compat_ion.h b/drivers/staging/android/ion/compat_ion.h new file mode 100644 index 000000000000..9da8f917670b --- /dev/null +++ b/drivers/staging/android/ion/compat_ion.h @@ -0,0 +1,29 @@ +/* + * drivers/staging/android/ion/compat_ion.h + * + * Copyright (C) 2013 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. + * + */ + +#ifndef _LINUX_COMPAT_ION_H +#define _LINUX_COMPAT_ION_H + +#if IS_ENABLED(CONFIG_COMPAT) + +long compat_ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); + +#else + +#define compat_ion_ioctl NULL + +#endif /* CONFIG_COMPAT */ +#endif /* _LINUX_COMPAT_ION_H */ diff --git a/drivers/staging/android/ion/ion-ioctl.c b/drivers/staging/android/ion/ion-ioctl.c index cba8f04df9f3..acf483fe3154 100644 --- a/drivers/staging/android/ion/ion-ioctl.c +++ b/drivers/staging/android/ion/ion-ioctl.c @@ -11,10 +11,19 @@ #include "ion.h" #include "ion_system_secure_heap.h" +#ifdef CONFIG_ION_LEGACY +#include "ion_legacy.h" +#endif + union ion_ioctl_arg { struct ion_allocation_data allocation; struct ion_heap_query query; struct ion_prefetch_data prefetch_data; +#ifdef CONFIG_ION_LEGACY + struct ion_fd_data fd; + struct ion_old_allocation_data old_allocation; + struct ion_handle_data handle; +#endif }; static int validate_ioctl_arg(unsigned int cmd, union ion_ioctl_arg *arg) @@ -37,6 +46,10 @@ static int validate_ioctl_arg(unsigned int cmd, union ion_ioctl_arg *arg) static unsigned int ion_ioctl_dir(unsigned int cmd) { switch (cmd) { +#ifdef CONFIG_ION_LEGACY + case ION_IOC_FREE: + return _IOC_WRITE; +#endif default: return _IOC_DIR(cmd); } @@ -115,6 +128,41 @@ long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) return ret; break; } +#ifdef CONFIG_ION_LEGACY + case ION_OLD_IOC_ALLOC: + { + int fd; + + fd = ion_alloc_fd(data.old_allocation.len, + data.old_allocation.heap_id_mask, + data.old_allocation.flags); + if (fd < 0) + return fd; + + data.old_allocation.handle = fd; + + break; + } + case ION_IOC_FREE: + /* + * libion passes 0 as the handle to check for this ioctl's + * existence and expects -ENOTTY on kernel 4.12+ as an indicator + * of having a new ION ABI. We want to use new ION as much as + * possible, so pretend that this ioctl doesn't exist when + * libion checks for it. + */ + if (!data.handle.handle) + ret = -ENOTTY; + + break; + case ION_IOC_SHARE: + case ION_IOC_MAP: + data.fd.fd = data.fd.handle; + break; + case ION_IOC_IMPORT: + data.fd.handle = data.fd.fd; + break; +#endif default: return -ENOTTY; } diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index 729f3d1ed2e3..cd653bfa238c 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -37,6 +37,7 @@ #include "ion.h" #include "ion_secure_util.h" +#include "compat_ion.h" static struct ion_device *internal_dev; static atomic_long_t total_heap_bytes; @@ -1194,7 +1195,11 @@ int ion_query_heaps(struct ion_heap_query *query) static const struct file_operations ion_fops = { .owner = THIS_MODULE, .unlocked_ioctl = ion_ioctl, +#ifdef CONFIG_ION_LEGACY + .compat_ioctl = compat_ion_ioctl, +#else .compat_ioctl = compat_ptr_ioctl, +#endif }; static int ion_debug_heap_show(struct seq_file *s, void *unused) diff --git a/drivers/staging/android/ion/ion_legacy.h b/drivers/staging/android/ion/ion_legacy.h new file mode 100644 index 000000000000..a4b78963e83b --- /dev/null +++ b/drivers/staging/android/ion/ion_legacy.h @@ -0,0 +1,101 @@ +#ifndef _ION_LEGACY_H +#define _ION_LEGACY_H + +#ifdef CONFIG_ION_LEGACY + +#include "../uapi/ion.h" + +typedef int ion_user_handle_t; + +/** + * struct ion_old_allocation_data - metadata passed from legacy (pre-4.12 kernel) + * userspace for allocations + * @len: size of the allocation + * @align: required alignment of the allocation + * @heap_id_mask: mask of heap ids to allocate from + * @flags: flags passed to heap + * @handle: pointer that will be populated with a cookie to use to + * refer to this allocation + * + * Provided by userspace as an argument to the ioctl + */ +struct ion_old_allocation_data { + size_t len; + size_t align; + unsigned int heap_id_mask; + unsigned int flags; + ion_user_handle_t handle; +}; + +/** + * struct ion_fd_data - metadata passed to/from userspace for a handle/fd pair + * @handle: a handle + * @fd: a file descriptor representing that handle + * + * For ION_IOC_SHARE or ION_IOC_MAP userspace populates the handle field with + * the handle returned from ion alloc, and the kernel returns the file + * descriptor to share or map in the fd field. For ION_IOC_IMPORT, userspace + * provides the file descriptor and the kernel returns the handle. + */ +struct ion_fd_data { + ion_user_handle_t handle; + int fd; +}; + +/** + * struct ion_handle_data - a handle passed to/from the kernel + * @handle: a handle + */ +struct ion_handle_data { + ion_user_handle_t handle; +}; + +/** + * DOC: ION_OLD_IOC_ALLOC - allocate memory (pre-4.12 version) + * + * Takes an ion_old_allocation_data struct and returns it with the handle field + * populated with the opaque handle for the allocation. + */ +#define ION_OLD_IOC_ALLOC _IOWR(ION_IOC_MAGIC, 0, \ + struct ion_old_allocation_data) + +/** + * DOC: ION_IOC_FREE - free memory + * + * Takes an ion_handle_data struct and frees the handle. + */ +#define ION_IOC_FREE _IOWR(ION_IOC_MAGIC, 1, struct ion_handle_data) + +/** + * DOC: ION_IOC_MAP - get a file descriptor to mmap + * + * Takes an ion_fd_data struct with the handle field populated with a valid + * opaque handle. Returns the struct with the fd field set to a file + * descriptor open in the current address space. This file descriptor + * can then be used as an argument to mmap. + */ +#define ION_IOC_MAP _IOWR(ION_IOC_MAGIC, 2, struct ion_fd_data) + +/** + * DOC: ION_IOC_SHARE - creates a file descriptor to use to share an allocation + * + * Takes an ion_fd_data struct with the handle field populated with a valid + * opaque handle. Returns the struct with the fd field set to a file + * descriptor open in the current address space. This file descriptor + * can then be passed to another process. The corresponding opaque handle can + * be retrieved via ION_IOC_IMPORT. + */ +#define ION_IOC_SHARE _IOWR(ION_IOC_MAGIC, 4, struct ion_fd_data) + +/** + * DOC: ION_IOC_IMPORT - imports a shared file descriptor + * + * Takes an ion_fd_data struct with the fd field populated with a valid file + * descriptor obtained from ION_IOC_SHARE and returns the struct with the handle + * filed set to the corresponding opaque handle. + */ +#define ION_IOC_IMPORT _IOWR(ION_IOC_MAGIC, 5, struct ion_fd_data) + +#endif /* CONFIG_ION_LEGACY */ + +#endif /* _ION_LEGACY_H */ From 2b5dd7d2d3942ab13be8850d939ff30769c3c36a Mon Sep 17 00:00:00 2001 From: duckyduckG Date: Wed, 26 Feb 2025 16:33:55 +0500 Subject: [PATCH 178/356] drivers: soc: Import legacy spcom driver from msm-4.14 * As of commit "soc: qcom: spcom: Fix pr_debug errors". Signed-off-by: duckyduckg --- drivers/soc/qcom/Kconfig | 13 + drivers/soc/qcom/Makefile | 1 + drivers/soc/qcom/spcom-legacy.c | 2215 +++++++++++++++++++++++++++++++ 3 files changed, 2229 insertions(+) create mode 100644 drivers/soc/qcom/spcom-legacy.c diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index eb6517668c70..3bde0c2a3108 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -666,6 +666,19 @@ config MSM_SPCOM spcom provides clients/server API, although currently only one client or server is allowed per logical channel. +config MSM_SPCOM_LEGACY + depends on QCOM_GLINK + bool "Secure Processor Communication over GLINK" + help + spcom driver allows loading Secure Processor Applications and + sending messages to Secure Processor Applications. + spcom provides interface to both user space app and kernel driver. + It is using glink as the transport layer, which provides multiple + logical channels over single physical channel. + The physical layer is based on shared memory and interrupts. + spcom provides clients/server API, although currently only one client + or server is allowed per logical channel. + config QSEE_IPC_IRQ bool "QSEE interrupt manager" help diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 3fe90e5ab8e5..d18ccb6f9a2c 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -51,6 +51,7 @@ obj-$(CONFIG_MSM_PIL_SSR_GENERIC) += subsys-pil-tz.o obj-$(CONFIG_MEM_SHARE_QMI_SERVICE) += memshare/ obj-$(CONFIG_MSM_PIL) += peripheral-loader.o obj-$(CONFIG_MSM_SPCOM) += spcom.o +obj-$(CONFIG_MSM_SPCOM_LEGACY) += spcom-legacy.o obj-$(CONFIG_MSM_CDSP_LOADER) += qdsp6v2/ obj-$(CONFIG_MSM_JTAGV8) += jtagv8.o jtagv8-etm.o obj-$(CONFIG_QCOM_SMCINVOKE) += smcinvoke.o diff --git a/drivers/soc/qcom/spcom-legacy.c b/drivers/soc/qcom/spcom-legacy.c new file mode 100644 index 000000000000..c51bff9d445f --- /dev/null +++ b/drivers/soc/qcom/spcom-legacy.c @@ -0,0 +1,2215 @@ +/* + * Copyright (c) 2015-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. + */ + +/* + * Secure-Processor-Communication (SPCOM). + * + * This driver provides communication to Secure Processor (SP) + * over RPMSG framework. + * + * It provides interface to userspace spcomlib. + * + * Userspace application shall use spcomlib for communication with SP. Userspace + * application can be either client or server. spcomlib shall use write() file + * operation to send data, and read() file operation to read data. + * + * This driver uses RPMSG with glink-spss as a transport layer. + * This driver exposes "/dev/" file node for each rpmsg logical + * channel. + * This driver exposes "/dev/spcom" file node for some debug/control command. + * The predefined channel "/dev/sp_kernel" is used for loading SP application + * from HLOS. + * This driver exposes "/dev/sp_ssr" file node to allow user space poll for SSR. + * After the remote SP App is loaded, this driver exposes a new file node + * "/dev/" for the matching HLOS App to use. + * The access to predefined file nodes and dynamically allocated file nodes is + * restricted by using unix group and SELinux. + * + * No message routing is used, but using the rpmsg/G-Link "multiplexing" feature + * to use a dedicated logical channel for HLOS and SP Application-Pair. + * + * Each HLOS/SP Application can be either Client or Server or both, + * Messaging is allways point-to-point between 2 HLOS<=>SP applications. + * Each channel exclusevly used by single Client or Server. + * + * User Space Request & Response are synchronous. + * read() & write() operations are blocking until completed or terminated. + */ +#define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__ + +#include /* min() */ +#include /* MODULE_LICENSE */ +#include /* class_create() */ +#include /* kzalloc() */ +#include /* file_operations */ +#include /* cdev_add() */ +#include /* EINVAL, ETIMEDOUT */ +#include /* pr_err() */ +#include /* BIT(x) */ +#include /* wait_for_completion_timeout() */ +#include /* POLLOUT */ +#include +#include /* of_property_count_strings() */ +#include +#include /* msleep() */ +#include +#include +#include +#include +#include +#include +#include + +/** + * Request buffer size. + * Any large data (multiply of 4KB) is provided by temp buffer in DDR. + * Request shall provide the temp buffer physical address (align to 4KB). + * Maximum request/response size of 268 is used to accommodate APDU size. + * From kernel spcom driver perspective a PAGE_SIZE of 4K + * is the actual maximum size for a single read/write file operation. + */ +#define SPCOM_MAX_RESPONSE_SIZE 268 + +/* SPCOM driver name */ +#define DEVICE_NAME "spcom" + +/* maximum ION buffers should be >= SPCOM_MAX_CHANNELS */ +#define SPCOM_MAX_ION_BUF_PER_CH (SPCOM_MAX_CHANNELS + 4) + +/* maximum ION buffer per send request/response command */ +#define SPCOM_MAX_ION_BUF_PER_CMD SPCOM_MAX_ION_BUF + +/* Maximum command size */ +#define SPCOM_MAX_COMMAND_SIZE (PAGE_SIZE) + +/* Maximum input size */ +#define SPCOM_MAX_READ_SIZE (PAGE_SIZE) + +/* Current Process ID */ +#define current_pid() ((u32)(current->pid)) + +/* + * After both sides get CONNECTED, + * there is a race between one side queueing rx buffer and the other side + * trying to call glink_tx() , this race is only on the 1st tx. + * Do tx retry with some delay to allow the other side to queue rx buffer. + */ +#define TX_RETRY_DELAY_MSEC 100 + +/* SPCOM_MAX_REQUEST_SIZE-or-SPCOM_MAX_RESPONSE_SIZE + header */ +#define SPCOM_RX_BUF_SIZE 300 + +/* + * Initial transaction id, use non-zero nonce for debug. + * Incremented by client on request, and copied back by server on response. + */ +#define INITIAL_TXN_ID 0x12345678 + +/** + * struct spcom_msg_hdr - Request/Response message header between HLOS and SP. + * + * This header is proceeding any request specific parameters. + * The transaction id is used to match request with response. + * Note: rpmsg API provides the rx/tx data size, so user payload size is + * calculated by reducing the header size. + */ +struct spcom_msg_hdr { + uint32_t reserved; /* for future use */ + uint32_t txn_id; /* transaction id */ + char buf[0]; /* Variable buffer size, must be last field */ +} __packed; + +/** + * struct spcom_client - Client handle + */ +struct spcom_client { + struct spcom_channel *ch; +}; + +/** + * struct spcom_server - Server handle + */ +struct spcom_server { + struct spcom_channel *ch; +}; + +/** + * struct spcom_channel - channel context + */ +struct spcom_channel { + char name[SPCOM_CHANNEL_NAME_SIZE]; + struct mutex lock; + uint32_t txn_id; /* incrementing nonce per client request */ + bool is_server; /* for txn_id and response_timeout_msec */ + bool comm_role_undefined; /* is true on channel creation, before */ + /* first tx/rx on channel */ + uint32_t response_timeout_msec; /* for client only */ + + /* char dev */ + struct cdev *cdev; + struct device *dev; + struct device_attribute attr; + + /* rpmsg */ + struct rpmsg_driver *rpdrv; + struct rpmsg_device *rpdev; + + /* Events notification */ + struct completion rx_done; + struct completion connect; + + /* + * Only one client or server per channel. + * Only one rx/tx transaction at a time (request + response). + */ + bool is_busy; + + u32 pid; /* debug only to find user space application */ + + /* abort flags */ + bool rpmsg_abort; + + /* rx data info */ + size_t actual_rx_size; /* actual data size received */ + void *rpmsg_rx_buf; + + /* shared buffer lock/unlock support */ + int dmabuf_fd_table[SPCOM_MAX_ION_BUF_PER_CH]; + struct dma_buf *dmabuf_handle_table[SPCOM_MAX_ION_BUF_PER_CH]; +}; + +/** + * struct rx_buff_list - holds rx rpmsg data, before it will be consumed + * by spcom_signal_rx_done worker, item per rx packet + */ +struct rx_buff_list { + struct list_head list; + + void *rpmsg_rx_buf; + int rx_buf_size; + struct spcom_channel *ch; +}; + +/** + * struct spcom_device - device state structure. + */ +struct spcom_device { + char predefined_ch_name[SPCOM_MAX_CHANNELS][SPCOM_CHANNEL_NAME_SIZE]; + + /* char device info */ + struct cdev cdev; + dev_t device_no; + struct class *driver_class; + struct device *class_dev; + struct platform_device *pdev; + + /* rpmsg channels */ + struct spcom_channel channels[SPCOM_MAX_CHANNELS]; + atomic_t chdev_count; + + struct completion rpmsg_state_change; + atomic_t rpmsg_dev_count; + + /* rx data path */ + struct list_head rx_list_head; + spinlock_t rx_lock; +}; + +/* Device Driver State */ +static struct spcom_device *spcom_dev; + +/* static functions declaration */ +static int spcom_create_channel_chardev(const char *name); +static struct spcom_channel *spcom_find_channel_by_name(const char *name); +static int spcom_register_rpmsg_drv(struct spcom_channel *ch); +static int spcom_unregister_rpmsg_drv(struct spcom_channel *ch); + +/** + * spcom_is_channel_open() - channel is open on this side. + * + * Channel is fully connected, when rpmsg driver is registered and + * rpmsg device probed + */ +static inline bool spcom_is_channel_open(struct spcom_channel *ch) +{ + return ch->rpdrv != NULL; +} + +/** + * spcom_is_channel_connected() - channel is fully connected by both sides. + */ +static inline bool spcom_is_channel_connected(struct spcom_channel *ch) +{ + /* Channel must be open before it gets connected */ + if (!spcom_is_channel_open(ch)) + return false; + + return ch->rpdev != NULL; +} + +/** + * spcom_create_predefined_channels_chardev() - expose predefined channels to + * user space. + * + * Predefined channels list is provided by device tree. Typically, it is for + * known servers on remote side that are not loaded by the HLOS + */ +static int spcom_create_predefined_channels_chardev(void) +{ + int i; + int ret; + static bool is_predefined_created; + + if (is_predefined_created) + return 0; + + for (i = 0; i < SPCOM_MAX_CHANNELS; i++) { + const char *name = spcom_dev->predefined_ch_name[i]; + + if (name[0] == 0) + break; + ret = spcom_create_channel_chardev(name); + if (ret) { + pr_err("failed to create chardev [%s], ret [%d].\n", + name, ret); + return -EFAULT; + } + } + + is_predefined_created = true; + + return 0; +} + +/*======================================================================*/ +/* UTILITIES */ +/*======================================================================*/ + +/** + * spcom_init_channel() - initialize channel state. + * + * @ch: channel state struct pointer + * @name: channel name + */ +static int spcom_init_channel(struct spcom_channel *ch, const char *name) +{ + if (!ch || !name || !name[0]) { + pr_err("invalid parameters.\n"); + return -EINVAL; + } + + strlcpy(ch->name, name, SPCOM_CHANNEL_NAME_SIZE); + + init_completion(&ch->rx_done); + init_completion(&ch->connect); + + mutex_init(&ch->lock); + ch->rpdrv = NULL; + ch->rpdev = NULL; + ch->actual_rx_size = 0; + ch->is_busy = false; + ch->txn_id = INITIAL_TXN_ID; /* use non-zero nonce for debug */ + ch->pid = 0; + ch->rpmsg_abort = false; + ch->rpmsg_rx_buf = NULL; + ch->comm_role_undefined = true; + + return 0; +} + +/** + * spcom_find_channel_by_name() - find a channel by name. + * + * @name: channel name + * + * Return: a channel state struct. + */ +static struct spcom_channel *spcom_find_channel_by_name(const char *name) +{ + int i; + + for (i = 0 ; i < ARRAY_SIZE(spcom_dev->channels); i++) { + struct spcom_channel *ch = &spcom_dev->channels[i]; + + if (strcmp(ch->name, name) == 0) + return ch; + } + + return NULL; +} + +/** + * spcom_rx() - wait for received data until timeout, unless pending rx data is + * already ready + * + * @ch: channel state struct pointer + * @buf: buffer pointer + * @size: buffer size + * + * Return: size in bytes on success, negative value on failure. + */ +static int spcom_rx(struct spcom_channel *ch, + void *buf, + uint32_t size, + uint32_t timeout_msec) +{ + unsigned long jiffies = msecs_to_jiffies(timeout_msec); + long timeleft = 1; + int ret = 0; + + mutex_lock(&ch->lock); + + /* check for already pending data */ + if (!ch->actual_rx_size) { + reinit_completion(&ch->rx_done); + + mutex_unlock(&ch->lock); /* unlock while waiting */ + /* wait for rx response */ + pr_debug("wait for rx done, timeout_msec=%d\n", timeout_msec); + if (timeout_msec) + timeleft = wait_for_completion_interruptible_timeout( + &ch->rx_done, jiffies); + else + ret = wait_for_completion_interruptible(&ch->rx_done); + + mutex_lock(&ch->lock); + if (timeout_msec && timeleft == 0) { + ch->txn_id++; /* to drop expired rx packet later */ + pr_err("rx_done timeout expired %d ms, set txn_id=%d\n", + timeout_msec, ch->txn_id); + ret = -ETIMEDOUT; + goto exit_err; + } else if (ch->rpmsg_abort) { + pr_warn("rpmsg channel is closing\n"); + ret = -ERESTART; + goto exit_err; + } else if (ret < 0 || timeleft == -ERESTARTSYS) { + pr_debug("wait interrupted: ret=%d, timeleft=%ld\n", + ret, timeleft); + if (timeleft == -ERESTARTSYS) + ret = -ERESTARTSYS; + goto exit_err; + } else if (ch->actual_rx_size) { + pr_debug("actual_rx_size is [%zu], txn_id %d\n", + ch->actual_rx_size, ch->txn_id); + } else { + pr_err("actual_rx_size is zero.\n"); + ret = -EFAULT; + goto exit_err; + } + } else { + pr_debug("pending data size [%zu], requested size [%u], ch->txn_id %d\n", + ch->actual_rx_size, size, ch->txn_id); + } + if (!ch->rpmsg_rx_buf) { + pr_err("invalid rpmsg_rx_buf.\n"); + ret = -ENOMEM; + goto exit_err; + } + + size = min_t(size_t, ch->actual_rx_size, size); + memcpy(buf, ch->rpmsg_rx_buf, size); + + pr_debug("copy size [%d].\n", (int) size); + + memset(ch->rpmsg_rx_buf, 0, ch->actual_rx_size); + kfree((void *)ch->rpmsg_rx_buf); + ch->rpmsg_rx_buf = NULL; + ch->actual_rx_size = 0; + + mutex_unlock(&ch->lock); + + return size; +exit_err: + mutex_unlock(&ch->lock); + return ret; +} + +/** + * spcom_get_next_request_size() - get request size. + * already ready + * + * @ch: channel state struct pointer + * + * Server needs the size of the next request to allocate a request buffer. + * Initially used intent-request, however this complicated the remote side, + * so both sides are not using glink_tx() with INTENT_REQ anymore. + * + * Return: size in bytes on success, negative value on failure. + */ +static int spcom_get_next_request_size(struct spcom_channel *ch) +{ + int size = -1; + int ret = 0; + + /* NOTE: Remote clients might not be connected yet.*/ + mutex_lock(&ch->lock); + reinit_completion(&ch->rx_done); + + /* check if already got it via callback */ + if (ch->actual_rx_size) { + pr_debug("next-req-size already ready ch [%s] size [%zu]\n", + ch->name, ch->actual_rx_size); + ret = -EFAULT; + goto exit_ready; + } + mutex_unlock(&ch->lock); /* unlock while waiting */ + + pr_debug("Wait for Rx Done, ch [%s].\n", ch->name); + ret = wait_for_completion_interruptible(&ch->rx_done); + if (ret < 0) { + pr_debug("ch [%s]:interrupted wait ret=%d\n", + ch->name, ret); + goto exit_error; + } + + mutex_lock(&ch->lock); /* re-lock after waiting */ + + if (ch->actual_rx_size == 0) { + pr_err("invalid rx size [%zu] ch [%s]\n", + ch->actual_rx_size, ch->name); + mutex_unlock(&ch->lock); + ret = -EFAULT; + goto exit_error; + } + +exit_ready: + /* actual_rx_size not exeeds SPCOM_RX_BUF_SIZE*/ + size = (int)ch->actual_rx_size; + if (size > sizeof(struct spcom_msg_hdr)) { + size -= sizeof(struct spcom_msg_hdr); + } else { + pr_err("rx size [%d] too small.\n", size); + ret = -EFAULT; + mutex_unlock(&ch->lock); + goto exit_error; + } + + mutex_unlock(&ch->lock); + return size; + +exit_error: + return ret; +} + +/*======================================================================*/ +/* USER SPACE commands handling */ +/*======================================================================*/ + +/** + * spcom_handle_create_channel_command() - Handle Create Channel command from + * user space. + * + * @cmd_buf: command buffer. + * @cmd_size: command buffer size. + * + * Return: 0 on successful operation, negative value otherwise. + */ +static int spcom_handle_create_channel_command(void *cmd_buf, int cmd_size) +{ + int ret = 0; + struct spcom_user_create_channel_command *cmd = cmd_buf; + const char *ch_name; + const size_t maxlen = sizeof(cmd->ch_name); + + if (cmd_size != sizeof(*cmd)) { + pr_err("cmd_size [%d] , expected [%d].\n", + (int) cmd_size, (int) sizeof(*cmd)); + return -EINVAL; + } + + ch_name = cmd->ch_name; + if (strnlen(cmd->ch_name, maxlen) == maxlen) { + pr_err("channel name is not NULL terminated\n"); + return -EINVAL; + } + + pr_debug("ch_name [%s].\n", ch_name); + + ret = spcom_create_channel_chardev(ch_name); + + return ret; +} + +/** + * spcom_handle_restart_sp_command() - Handle Restart SP command from + * user space. + * + * Return: 0 on successful operation, negative value otherwise. + */ +static int spcom_handle_restart_sp_command(void) +{ + void *subsystem_get_retval = NULL; + + pr_debug("restart - PIL FW loading process initiated\n"); + + subsystem_get_retval = subsystem_get("spss"); + if (!subsystem_get_retval) { + pr_err("restart - unable to trigger PIL process for FW loading\n"); + return -EINVAL; + } + + pr_debug("restart - PIL FW loading process is complete\n"); + return 0; +} + +/** + * spcom_handle_send_command() - Handle send request/response from user space. + * + * @buf: command buffer. + * @buf_size: command buffer size. + * + * Return: 0 on successful operation, negative value otherwise. + */ +static int spcom_handle_send_command(struct spcom_channel *ch, + void *cmd_buf, int size) +{ + int ret = 0; + struct spcom_send_command *cmd = cmd_buf; + uint32_t buf_size; + void *buf; + struct spcom_msg_hdr *hdr; + void *tx_buf; + int tx_buf_size; + uint32_t timeout_msec; + int time_msec = 0; + + pr_debug("send req/resp ch [%s] size [%d] .\n", ch->name, size); + + /* + * check that cmd buf size is at least struct size, + * to allow access to struct fields. + */ + if (size < sizeof(*cmd)) { + pr_err("ch [%s] invalid cmd buf.\n", + ch->name); + return -EINVAL; + } + + /* Check if remote side connect */ + if (!spcom_is_channel_connected(ch)) { + pr_err("ch [%s] remote side not connect.\n", ch->name); + return -ENOTCONN; + } + + /* parse command buffer */ + buf = &cmd->buf; + buf_size = cmd->buf_size; + timeout_msec = cmd->timeout_msec; + + /* Check param validity */ + if (buf_size > SPCOM_MAX_RESPONSE_SIZE) { + pr_err("ch [%s] invalid buf size [%d].\n", + ch->name, buf_size); + return -EINVAL; + } + if (size != sizeof(*cmd) + buf_size) { + pr_err("ch [%s] invalid cmd size [%d].\n", + ch->name, size); + return -EINVAL; + } + + /* Allocate Buffers*/ + tx_buf_size = sizeof(*hdr) + buf_size; + tx_buf = kzalloc(tx_buf_size, GFP_KERNEL); + if (!tx_buf) + return -ENOMEM; + + /* Prepare Tx Buf */ + hdr = tx_buf; + + mutex_lock(&ch->lock); + if (ch->comm_role_undefined) { + pr_debug("ch [%s] send first -> it is client\n", ch->name); + ch->comm_role_undefined = false; + ch->is_server = false; + } + + if (!ch->is_server) { + ch->txn_id++; /* client sets the request txn_id */ + ch->response_timeout_msec = timeout_msec; + } + hdr->txn_id = ch->txn_id; + + /* user buf */ + memcpy(hdr->buf, buf, buf_size); + + time_msec = 0; + do { + if (ch->rpmsg_abort) { + pr_err("ch [%s] aborted\n", ch->name); + ret = -ECANCELED; + break; + } + /* may fail when RX intent not queued by SP */ + ret = rpmsg_trysend(ch->rpdev->ept, tx_buf, tx_buf_size); + if (ret == 0) + break; + time_msec += TX_RETRY_DELAY_MSEC; + mutex_unlock(&ch->lock); + msleep(TX_RETRY_DELAY_MSEC); + mutex_lock(&ch->lock); + } while ((ret == -EBUSY || ret == -EAGAIN) && time_msec < timeout_msec); + if (ret) + pr_err("ch [%s] rpmsg_trysend() error (%d), timeout_msec=%d\n", + ch->name, ret, timeout_msec); + mutex_unlock(&ch->lock); + + kfree(tx_buf); + return ret; +} + +/** + * modify_ion_addr() - replace the ION buffer virtual address with physical + * address in a request or response buffer. + * + * @buf: buffer to modify + * @buf_size: buffer size + * @ion_info: ION buffer info such as FD and offset in buffer. + * + * Return: 0 on successful operation, negative value otherwise. + */ +static int modify_ion_addr(void *buf, + uint32_t buf_size, + struct spcom_ion_info ion_info) +{ + struct dma_buf *dma_buf; + struct dma_buf_attachment *attach; + struct sg_table *sg = NULL; + dma_addr_t phy_addr = 0; + int fd, ret = 0; + uint32_t buf_offset; + char *ptr = (char *)buf; + + fd = ion_info.fd; + buf_offset = ion_info.buf_offset; + ptr += buf_offset; + + if (fd < 0) { + pr_err("invalid fd [%d].\n", fd); + return -ENODEV; + } + + if (buf_size < sizeof(uint64_t)) { + pr_err("buf size too small [%d].\n", buf_size); + return -ENODEV; + } + + if (buf_offset % sizeof(uint64_t)) + pr_debug("offset [%d] is NOT 64-bit aligned.\n", buf_offset); + else + pr_debug("offset [%d] is 64-bit aligned.\n", buf_offset); + + if (buf_offset > buf_size - sizeof(uint64_t)) { + pr_err("invalid buf_offset [%d].\n", buf_offset); + return -ENODEV; + } + + dma_buf = dma_buf_get(fd); + if (IS_ERR_OR_NULL(dma_buf)) { + pr_err("fail to get dma buf handle.\n"); + return -EINVAL; + } + pr_debug("dma_buf handle ok.\n"); + attach = dma_buf_attach(dma_buf, &spcom_dev->pdev->dev); + if (IS_ERR_OR_NULL(attach)) { + ret = PTR_ERR(attach); + pr_err("fail to attach dma buf %d\n", ret); + dma_buf_put(dma_buf); + goto mem_map_table_failed; + } + + sg = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL); + if (IS_ERR_OR_NULL(sg)) { + ret = PTR_ERR(sg); + pr_err("fail to get sg table of dma buf %d\n", ret); + goto mem_map_table_failed; + } + if (sg->sgl) { + phy_addr = sg->sgl->dma_address; + } else { + pr_err("sgl is NULL\n"); + ret = -ENOMEM; + goto mem_map_sg_failed; + } + + /* Set the physical address at the buffer offset */ + pr_debug("ion phys addr = [0x%lx].\n", (long int) phy_addr); + memcpy(ptr, &phy_addr, sizeof(phy_addr)); + +mem_map_sg_failed: + dma_buf_unmap_attachment(attach, sg, DMA_BIDIRECTIONAL); +mem_map_table_failed: + dma_buf_detach(dma_buf, attach); + dma_buf_put(dma_buf); + + return ret; +} + +/** + * spcom_handle_send_modified_command() - send a request/response with ION + * buffer address. Modify the request/response by replacing the ION buffer + * virtual address with the physical address. + * + * @ch: channel pointer + * @cmd_buf: User space command buffer + * @size: size of user command buffer + * + * Return: 0 on successful operation, negative value otherwise. + */ +static int spcom_handle_send_modified_command(struct spcom_channel *ch, + void *cmd_buf, int size) +{ + int ret = 0; + struct spcom_user_send_modified_command *cmd = cmd_buf; + uint32_t buf_size; + void *buf; + struct spcom_msg_hdr *hdr; + void *tx_buf; + int tx_buf_size; + struct spcom_ion_info ion_info[SPCOM_MAX_ION_BUF_PER_CMD]; + int i; + uint32_t timeout_msec; + int time_msec = 0; + + pr_debug("send req/resp ch [%s] size [%d] .\n", ch->name, size); + + /* + * check that cmd buf size is at least struct size, + * to allow access to struct fields. + */ + if (size < sizeof(*cmd)) { + pr_err("ch [%s] invalid cmd buf.\n", + ch->name); + return -EINVAL; + } + + /* Check if remote side connect */ + if (!spcom_is_channel_connected(ch)) { + pr_err("ch [%s] remote side not connect.\n", ch->name); + return -ENOTCONN; + } + + /* parse command buffer */ + buf = &cmd->buf; + buf_size = cmd->buf_size; + timeout_msec = cmd->timeout_msec; + memcpy(ion_info, cmd->ion_info, sizeof(ion_info)); + + /* Check param validity */ + if (buf_size > SPCOM_MAX_RESPONSE_SIZE) { + pr_err("ch [%s] invalid buf size [%d].\n", + ch->name, buf_size); + return -EINVAL; + } + if (size != sizeof(*cmd) + buf_size) { + pr_err("ch [%s] invalid cmd size [%d].\n", + ch->name, size); + return -EINVAL; + } + + /* Allocate Buffers*/ + tx_buf_size = sizeof(*hdr) + buf_size; + tx_buf = kzalloc(tx_buf_size, GFP_KERNEL); + if (!tx_buf) + return -ENOMEM; + + /* Prepare Tx Buf */ + hdr = tx_buf; + + mutex_lock(&ch->lock); + if (ch->comm_role_undefined) { + pr_debug("ch [%s] send first -> it is client\n", ch->name); + ch->comm_role_undefined = false; + ch->is_server = false; + } + if (!ch->is_server) { + ch->txn_id++; /* client sets the request txn_id */ + ch->response_timeout_msec = timeout_msec; + } + hdr->txn_id = ch->txn_id; + + /* user buf */ + memcpy(hdr->buf, buf, buf_size); + + for (i = 0 ; i < ARRAY_SIZE(ion_info) ; i++) { + if (ion_info[i].fd >= 0) { + ret = modify_ion_addr(hdr->buf, buf_size, ion_info[i]); + if (ret < 0) { + mutex_unlock(&ch->lock); + pr_err("modify_ion_addr() error [%d].\n", ret); + memset(tx_buf, 0, tx_buf_size); + kfree(tx_buf); + return -EFAULT; + } + } + } + + time_msec = 0; + do { + if (ch->rpmsg_abort) { + pr_err("ch [%s] aborted\n", ch->name); + ret = -ECANCELED; + break; + } + /* may fail when RX intent not queued by SP */ + ret = rpmsg_trysend(ch->rpdev->ept, tx_buf, tx_buf_size); + if (ret == 0) + break; + time_msec += TX_RETRY_DELAY_MSEC; + mutex_unlock(&ch->lock); + msleep(TX_RETRY_DELAY_MSEC); + mutex_lock(&ch->lock); + } while ((ret == -EBUSY || ret == -EAGAIN) && time_msec < timeout_msec); + if (ret) + pr_err("ch [%s] rpmsg_trysend() error (%d), timeout_msec=%d\n", + ch->name, ret, timeout_msec); + + mutex_unlock(&ch->lock); + memset(tx_buf, 0, tx_buf_size); + kfree(tx_buf); + return ret; +} + + +/** + * spcom_handle_lock_ion_buf_command() - Lock an shared buffer. + * + * Lock an shared buffer, prevent it from being free if the userspace App crash, + * while it is used by the remote subsystem. + */ +static int spcom_handle_lock_ion_buf_command(struct spcom_channel *ch, + void *cmd_buf, int size) +{ + struct spcom_user_command *cmd = cmd_buf; + int fd; + int i; + struct dma_buf *dma_buf; + + if (size != sizeof(*cmd)) { + pr_err("cmd size [%d] , expected [%d].\n", + (int) size, (int) sizeof(*cmd)); + return -EINVAL; + } + + if (cmd->arg > (unsigned int)INT_MAX) { + pr_err("int overflow [%u]\n", cmd->arg); + return -EINVAL; + } + fd = cmd->arg; + + dma_buf = dma_buf_get(fd); + if (IS_ERR_OR_NULL(dma_buf)) { + pr_err("fail to get dma buf handle.\n"); + return -EINVAL; + } + pr_debug("dma_buf referenced ok.\n"); + + /* shared buf lock doesn't involve any rx/tx data to SP. */ + mutex_lock(&ch->lock); + + /* Check if this shared buffer is already locked */ + for (i = 0 ; i < ARRAY_SIZE(ch->dmabuf_handle_table) ; i++) { + if (ch->dmabuf_handle_table[i] == dma_buf) { + pr_debug("fd [%d] shared buf is already locked.\n", fd); + /* decrement back the ref count */ + mutex_unlock(&ch->lock); + dma_buf_put(dma_buf); + return -EINVAL; + } + } + + /* Store the dma_buf handle */ + for (i = 0 ; i < ARRAY_SIZE(ch->dmabuf_handle_table) ; i++) { + if (ch->dmabuf_handle_table[i] == NULL) { + ch->dmabuf_handle_table[i] = dma_buf; + ch->dmabuf_fd_table[i] = fd; + pr_debug("ch [%s] locked ion buf #%d fd [%d] dma_buf=%pK\n", + ch->name, i, + ch->dmabuf_fd_table[i], + ch->dmabuf_handle_table[i]); + mutex_unlock(&ch->lock); + return 0; + } + } + + mutex_unlock(&ch->lock); + /* decrement back the ref count */ + dma_buf_put(dma_buf); + pr_err("no free entry to store ion handle of fd [%d].\n", fd); + + return -EFAULT; +} + +/** + * spcom_handle_unlock_ion_buf_command() - Unlock an ION buffer. + * + * Unlock an ION buffer, let it be free, when it is no longer being used by + * the remote subsystem. + */ +static int spcom_handle_unlock_ion_buf_command(struct spcom_channel *ch, + void *cmd_buf, int size) +{ + int i; + struct spcom_user_command *cmd = cmd_buf; + int fd; + bool found = false; + struct dma_buf *dma_buf; + + if (size != sizeof(*cmd)) { + pr_err("cmd size [%d], expected [%d]\n", + (int)size, (int)sizeof(*cmd)); + return -EINVAL; + } + if (cmd->arg > (unsigned int)INT_MAX) { + pr_err("int overflow [%u]\n", cmd->arg); + return -EINVAL; + } + fd = cmd->arg; + + pr_debug("Unlock ion buf ch [%s] fd [%d].\n", ch->name, fd); + + dma_buf = dma_buf_get(fd); + if (IS_ERR_OR_NULL(dma_buf)) { + pr_err("fail to get dma buf handle\n"); + return -EINVAL; + } + dma_buf_put(dma_buf); + pr_debug("dma_buf referenced ok\n"); + + /* shared buf unlock doesn't involve any rx/tx data to SP. */ + mutex_lock(&ch->lock); + if (fd == (int) SPCOM_ION_FD_UNLOCK_ALL) { + pr_debug("unlocked ALL ion buf ch [%s].\n", ch->name); + found = true; + /* unlock all buf */ + for (i = 0; i < ARRAY_SIZE(ch->dmabuf_handle_table); i++) { + if (ch->dmabuf_handle_table[i] != NULL) { + pr_debug("unlocked ion buf #%d fd [%d]\n", + i, ch->dmabuf_fd_table[i]); + dma_buf_put(ch->dmabuf_handle_table[i]); + ch->dmabuf_handle_table[i] = NULL; + ch->dmabuf_fd_table[i] = -1; + } + } + } else { + /* unlock specific buf */ + for (i = 0 ; i < ARRAY_SIZE(ch->dmabuf_handle_table) ; i++) { + if (!ch->dmabuf_handle_table[i]) + continue; + if (ch->dmabuf_handle_table[i] == dma_buf) { + pr_debug("ch [%s] unlocked ion buf #%d fd [%d] dma_buf=%pK\n", + ch->name, i, + ch->dmabuf_fd_table[i], + ch->dmabuf_handle_table[i]); + dma_buf_put(ch->dmabuf_handle_table[i]); + ch->dmabuf_handle_table[i] = NULL; + ch->dmabuf_fd_table[i] = -1; + found = true; + break; + } + } + } + mutex_unlock(&ch->lock); + + if (!found) { + pr_err("ch [%s] fd [%d] was not found.\n", ch->name, fd); + return -ENODEV; + } + + return 0; +} + +/** + * spcom_handle_write() - Handle user space write commands. + * + * @buf: command buffer. + * @buf_size: command buffer size. + * + * Return: 0 on successful operation, negative value otherwise. + */ +static int spcom_handle_write(struct spcom_channel *ch, + void *buf, + int buf_size) +{ + int ret = 0; + struct spcom_user_command *cmd = NULL; + int cmd_id = 0; + + /* Minimal command should have command-id and argument */ + if (buf_size < sizeof(struct spcom_user_command)) { + pr_err("Command buffer size [%d] too small\n", buf_size); + return -EINVAL; + } + + cmd = (struct spcom_user_command *)buf; + cmd_id = (int) cmd->cmd_id; + + pr_debug("cmd_id [0x%x]\n", cmd_id); + + if (!ch && cmd_id != SPCOM_CMD_CREATE_CHANNEL + && cmd_id != SPCOM_CMD_RESTART_SP) { + pr_err("channel context is null\n"); + return -EINVAL; + } + + switch (cmd_id) { + case SPCOM_CMD_SEND: + ret = spcom_handle_send_command(ch, buf, buf_size); + break; + case SPCOM_CMD_SEND_MODIFIED: + ret = spcom_handle_send_modified_command(ch, buf, buf_size); + break; + case SPCOM_CMD_LOCK_ION_BUF: + ret = spcom_handle_lock_ion_buf_command(ch, buf, buf_size); + break; + case SPCOM_CMD_UNLOCK_ION_BUF: + ret = spcom_handle_unlock_ion_buf_command(ch, buf, buf_size); + break; + case SPCOM_CMD_CREATE_CHANNEL: + ret = spcom_handle_create_channel_command(buf, buf_size); + break; + case SPCOM_CMD_RESTART_SP: + ret = spcom_handle_restart_sp_command(); + break; + default: + pr_err("Invalid Command Id [0x%x].\n", (int) cmd->cmd_id); + ret = -EINVAL; + } + + return ret; +} + +/** + * spcom_handle_get_req_size() - Handle user space get request size command + * + * @ch: channel handle + * @buf: command buffer. + * @size: command buffer size. + * + * Return: size in bytes on success, negative value on failure. + */ +static int spcom_handle_get_req_size(struct spcom_channel *ch, + void *buf, + uint32_t size) +{ + int ret = -1; + uint32_t next_req_size = 0; + + if (size < sizeof(next_req_size)) { + pr_err("buf size [%d] too small.\n", (int) size); + return -EINVAL; + } + + ret = spcom_get_next_request_size(ch); + if (ret < 0) + return ret; + next_req_size = (uint32_t) ret; + + memcpy(buf, &next_req_size, sizeof(next_req_size)); + pr_debug("next_req_size [%d].\n", next_req_size); + + return sizeof(next_req_size); /* can't exceed user buffer size */ +} + +/** + * spcom_handle_read_req_resp() - Handle user space get request/response command + * + * @ch: channel handle + * @buf: command buffer. + * @size: command buffer size. + * + * Return: size in bytes on success, negative value on failure. + */ +static int spcom_handle_read_req_resp(struct spcom_channel *ch, + void *buf, + uint32_t size) +{ + int ret; + struct spcom_msg_hdr *hdr; + void *rx_buf; + int rx_buf_size; + uint32_t timeout_msec = 0; /* client only */ + + /* Check if remote side connect */ + if (!spcom_is_channel_connected(ch)) { + pr_err("ch [%s] remote side not connect.\n", ch->name); + return -ENOTCONN; + } + + /* Check param validity */ + if (size > SPCOM_MAX_RESPONSE_SIZE) { + pr_err("ch [%s] invalid size [%d].\n", + ch->name, size); + return -EINVAL; + } + + /* Allocate Buffers*/ + rx_buf_size = sizeof(*hdr) + size; + rx_buf = kzalloc(rx_buf_size, GFP_KERNEL); + if (!rx_buf) + return -ENOMEM; + + /* + * client response timeout depends on the request + * handling time on the remote side . + */ + if (!ch->is_server) { + timeout_msec = ch->response_timeout_msec; + pr_debug("response_timeout_msec = %d.\n", (int) timeout_msec); + } + + ret = spcom_rx(ch, rx_buf, rx_buf_size, timeout_msec); + if (ret < 0) { + pr_err("rx error %d.\n", ret); + goto exit_err; + } else { + size = ret; /* actual_rx_size */ + } + + hdr = rx_buf; + + if (ch->is_server) { + ch->txn_id = hdr->txn_id; + pr_debug("request txn_id [0x%x].\n", ch->txn_id); + } + + /* copy data to user without the header */ + if (size > sizeof(*hdr)) { + size -= sizeof(*hdr); + memcpy(buf, hdr->buf, size); + } else { + pr_err("rx size [%d] too small.\n", size); + ret = -EFAULT; + goto exit_err; + } + + kfree(rx_buf); + return size; +exit_err: + kfree(rx_buf); + return ret; +} + +/** + * spcom_handle_read() - Handle user space read request/response or + * request-size command + * + * @ch: channel handle + * @buf: command buffer. + * @size: command buffer size. + * + * A special size SPCOM_GET_NEXT_REQUEST_SIZE, which is bigger than the max + * response/request tells the kernel that user space only need the size. + * + * Return: size in bytes on success, negative value on failure. + */ +static int spcom_handle_read(struct spcom_channel *ch, + void *buf, + uint32_t size) +{ + int ret = -1; + + if (size == SPCOM_GET_NEXT_REQUEST_SIZE) { + pr_debug("get next request size, ch [%s].\n", ch->name); + ch->is_server = true; + ret = spcom_handle_get_req_size(ch, buf, size); + } else { + pr_debug("get request/response, ch [%s].\n", ch->name); + ret = spcom_handle_read_req_resp(ch, buf, size); + } + + pr_debug("ch [%s] , size = %d.\n", ch->name, size); + + return ret; +} + +/*======================================================================*/ +/* CHAR DEVICE USER SPACE INTERFACE */ +/*======================================================================*/ + +/** + * file_to_filename() - get the filename from file pointer. + * + * @filp: file pointer + * + * it is used for debug prints. + * + * Return: filename string or "unknown". + */ +static char *file_to_filename(struct file *filp) +{ + struct dentry *dentry = NULL; + char *filename = NULL; + + if (!filp || !filp->f_path.dentry) + return "unknown"; + + dentry = filp->f_path.dentry; + filename = dentry->d_iname; + + return filename; +} + +/** + * spcom_device_open() - handle channel file open() from user space. + * + * @filp: file pointer + * + * The file name (without path) is the channel name. + * Register rpmsg driver matching with channel name. + * Store the channel context in the file private date pointer for future + * read/write/close operations. + */ +static int spcom_device_open(struct inode *inode, struct file *filp) +{ + struct spcom_channel *ch; + int ret; + const char *name = file_to_filename(filp); + u32 pid = current_pid(); + + pr_debug("open file [%s].\n", name); + + if (strcmp(name, "unknown") == 0) { + pr_err("name is unknown\n"); + return -EINVAL; + } + + if (strcmp(name, DEVICE_NAME) == 0) { + pr_debug("root dir skipped.\n"); + return 0; + } + + if (strcmp(name, "sp_ssr") == 0) { + pr_debug("sp_ssr dev node skipped.\n"); + return 0; + } + + ch = spcom_find_channel_by_name(name); + if (!ch) { + pr_err("channel %s doesn't exist, load App first.\n", name); + return -ENODEV; + } + + mutex_lock(&ch->lock); + if (!spcom_is_channel_open(ch)) { + reinit_completion(&ch->connect); + /* channel was closed need to register drv again */ + ret = spcom_register_rpmsg_drv(ch); + if (ret < 0) { + pr_err("register rpmsg driver failed %d\n", ret); + mutex_unlock(&ch->lock); + return ret; + } + } + /* only one client/server may use the channel */ + if (ch->is_busy) { + pr_err("channel [%s] is BUSY, already in use by pid [%d].\n", + name, ch->pid); + mutex_unlock(&ch->lock); + return -EBUSY; + } + + ch->is_busy = true; + ch->pid = pid; + mutex_unlock(&ch->lock); + + filp->private_data = ch; + return 0; +} + +/** + * spcom_device_release() - handle channel file close() from user space. + * + * @filp: file pointer + * + * The file name (without path) is the channel name. + * Open the relevant glink channel. + * Store the channel context in the file private + * date pointer for future read/write/close + * operations. + */ +static int spcom_device_release(struct inode *inode, struct file *filp) +{ + struct spcom_channel *ch; + const char *name = file_to_filename(filp); + int ret = 0; + + if (strcmp(name, "unknown") == 0) { + pr_err("name is unknown\n"); + return -EINVAL; + } + + if (strcmp(name, DEVICE_NAME) == 0) { + pr_debug("root dir skipped.\n"); + return 0; + } + + if (strcmp(name, "sp_ssr") == 0) { + pr_debug("sp_ssr dev node skipped.\n"); + return 0; + } + + ch = filp->private_data; + if (!ch) { + pr_debug("ch is NULL, file name %s.\n", file_to_filename(filp)); + return -ENODEV; + } + + mutex_lock(&ch->lock); + /* channel might be already closed or disconnected */ + if (!spcom_is_channel_open(ch)) { + pr_debug("ch [%s] already closed.\n", name); + mutex_unlock(&ch->lock); + return 0; + } + + ch->is_busy = false; + ch->pid = 0; + if (ch->rpmsg_rx_buf) { + pr_debug("ch [%s] discarting unconsumed rx packet actual_rx_size=%lu\n", + name, ch->actual_rx_size); + kfree(ch->rpmsg_rx_buf); + ch->rpmsg_rx_buf = NULL; + } + ch->actual_rx_size = 0; + mutex_unlock(&ch->lock); + filp->private_data = NULL; + + return ret; +} + +/** + * spcom_device_write() - handle channel file write() from user space. + * + * @filp: file pointer + * + * Return: On Success - same size as number of bytes to write. + * On Failure - negative value. + */ +static ssize_t spcom_device_write(struct file *filp, + const char __user *user_buff, + size_t size, loff_t *f_pos) +{ + int ret; + char *buf; + struct spcom_channel *ch; + const char *name = file_to_filename(filp); + int buf_size = 0; + + if (!user_buff || !f_pos || !filp) { + pr_err("invalid null parameters.\n"); + return -EINVAL; + } + + if (*f_pos != 0) { + pr_err("offset should be zero, no sparse buffer.\n"); + return -EINVAL; + } + + if (!name) { + pr_err("name is NULL\n"); + return -EINVAL; + } + pr_debug("write file [%s] size [%d] pos [%d].\n", + name, (int) size, (int) *f_pos); + + if (strcmp(name, "unknown") == 0) { + pr_err("name is unknown\n"); + return -EINVAL; + } + + ch = filp->private_data; + if (!ch) { + if (strcmp(name, DEVICE_NAME) != 0) { + pr_err("invalid ch pointer, command not allowed.\n"); + return -EINVAL; + } + pr_debug("control device - no channel context.\n"); + } else { + /* Check if remote side connect */ + if (!spcom_is_channel_connected(ch)) { + pr_err("ch [%s] remote side not connect.\n", ch->name); + return -ENOTCONN; + } + } + + if (size > SPCOM_MAX_COMMAND_SIZE) { + pr_err("size [%d] > max size [%d].\n", + (int) size, (int) SPCOM_MAX_COMMAND_SIZE); + return -EINVAL; + } + buf_size = size; /* explicit casting size_t to int */ + buf = kzalloc(size, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + ret = copy_from_user(buf, user_buff, size); + if (ret) { + pr_err("Unable to copy from user (err %d).\n", ret); + kfree(buf); + return -EFAULT; + } + + ret = spcom_handle_write(ch, buf, buf_size); + if (ret) { + pr_err("handle command error [%d].\n", ret); + kfree(buf); + return ret; + } + + kfree(buf); + + return size; +} + +/** + * spcom_device_read() - handle channel file read() from user space. + * + * @filp: file pointer + * + * Return: number of bytes to read on success, negative value on + * failure. + */ +static ssize_t spcom_device_read(struct file *filp, char __user *user_buff, + size_t size, loff_t *f_pos) +{ + int ret = 0; + int actual_size = 0; + char *buf; + struct spcom_channel *ch; + const char *name = file_to_filename(filp); + uint32_t buf_size = 0; + + pr_debug("read file [%s], size = %d bytes.\n", name, (int) size); + + if (strcmp(name, "unknown") == 0) { + pr_err("name is unknown\n"); + return -EINVAL; + } + + if (!user_buff || !f_pos || + (size == 0) || (size > SPCOM_MAX_READ_SIZE)) { + pr_err("invalid parameters.\n"); + return -EINVAL; + } + buf_size = size; /* explicit casting size_t to uint32_t */ + + ch = filp->private_data; + + if (ch == NULL) { + pr_err("invalid ch pointer, file [%s].\n", name); + return -EINVAL; + } + + if (!spcom_is_channel_open(ch)) { + pr_err("ch is not open, file [%s].\n", name); + return -EINVAL; + } + + buf = kzalloc(size, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + ret = spcom_handle_read(ch, buf, buf_size); + if (ret < 0) { + if (ret != -ERESTARTSYS) + pr_err("read error [%d].\n", ret); + kfree(buf); + return ret; + } + actual_size = ret; + if ((actual_size == 0) || (actual_size > size)) { + pr_err("invalid actual_size [%d].\n", actual_size); + kfree(buf); + return -EFAULT; + } + + ret = copy_to_user(user_buff, buf, actual_size); + if (ret) { + pr_err("Unable to copy to user, err = %d.\n", ret); + kfree(buf); + return -EFAULT; + } + + kfree(buf); + pr_debug("ch [%s] ret [%d].\n", name, (int) actual_size); + + return actual_size; +} + +/** + * spcom_device_poll() - handle channel file poll() from user space. + * + * @filp: file pointer + * + * This allows user space to wait/check for channel connection, + * or wait for SSR event. + * + * Return: event bitmask on success, set POLLERR on failure. + */ +static unsigned int spcom_device_poll(struct file *filp, + struct poll_table_struct *poll_table) +{ + /* + * when user call with timeout -1 for blocking mode, + * any bit must be set in response + */ + unsigned int ret = SPCOM_POLL_READY_FLAG; + unsigned long mask; + struct spcom_channel *ch; + const char *name = file_to_filename(filp); + bool wait = false; + bool done = false; + /* Event types always implicitly polled for */ + unsigned long reserved = POLLERR | POLLHUP | POLLNVAL; + int ready = 0; + + if (strcmp(name, "unknown") == 0) { + pr_err("name is unknown\n"); + return -EINVAL; + } + + if (!poll_table) { + pr_err("invalid parameters.\n"); + return -EINVAL; + } + + ch = filp->private_data; + mask = poll_requested_events(poll_table); + + pr_debug("== ch [%s] mask [0x%x] ==.\n", name, (int) mask); + + /* user space API has poll use "short" and not "long" */ + mask &= 0x0000FFFF; + + wait = mask & SPCOM_POLL_WAIT_FLAG; + if (wait) + pr_debug("ch [%s] wait for event flag is ON.\n", name); + + // mask will be used in output, clean input bits + mask &= (unsigned long)~SPCOM_POLL_WAIT_FLAG; + mask &= (unsigned long)~SPCOM_POLL_READY_FLAG; + mask &= (unsigned long)~reserved; + + switch (mask) { + case SPCOM_POLL_LINK_STATE: + pr_debug("ch [%s] SPCOM_POLL_LINK_STATE.\n", name); + if (wait) { + reinit_completion(&spcom_dev->rpmsg_state_change); + ready = wait_for_completion_interruptible( + &spcom_dev->rpmsg_state_change); + pr_debug("ch [%s] poll LINK_STATE signaled.\n", name); + } + done = atomic_read(&spcom_dev->rpmsg_dev_count) > 0; + break; + case SPCOM_POLL_CH_CONNECT: + /* + * ch is not expected to be NULL since user must call open() + * to get FD before it can call poll(). + * open() will fail if no ch related to the char-device. + */ + if (ch == NULL) { + pr_err("invalid ch pointer, file [%s].\n", name); + return POLLERR; + } + pr_debug("ch [%s] SPCOM_POLL_CH_CONNECT.\n", name); + if (wait) { + reinit_completion(&ch->connect); + ready = wait_for_completion_interruptible(&ch->connect); + pr_debug("ch [%s] poll CH_CONNECT signaled.\n", name); + } + mutex_lock(&ch->lock); + done = (ch->rpdev != NULL); + pr_debug("ch [%s] reported done=%d\n", name, done); + mutex_unlock(&ch->lock); + break; + default: + pr_err("ch [%s] poll, invalid mask [0x%x].\n", + name, (int) mask); + ret = POLLERR; + break; + } + + if (ready < 0) { /* wait was interrupted */ + pr_debug("ch [%s] poll interrupted, ret [%d].\n", name, ready); + ret = POLLERR | SPCOM_POLL_READY_FLAG | mask; + } + if (done) + ret |= mask; + + pr_debug("ch [%s] poll, mask = 0x%x, ret=0x%x.\n", + name, (int) mask, ret); + + return ret; +} + +/* file operation supported from user space */ +static const struct file_operations fops = { + .owner = THIS_MODULE, + .read = spcom_device_read, + .poll = spcom_device_poll, + .write = spcom_device_write, + .open = spcom_device_open, + .release = spcom_device_release, +}; + +/** + * spcom_create_channel_chardev() - Create a channel char-dev node file + * for user space interface + */ +static int spcom_create_channel_chardev(const char *name) +{ + int ret; + struct device *dev; + struct spcom_channel *ch; + dev_t devt; + struct class *cls = spcom_dev->driver_class; + struct device *parent = spcom_dev->class_dev; + void *priv; + struct cdev *cdev; + + pr_debug("Add channel [%s].\n", name); + + ch = spcom_find_channel_by_name(name); + if (ch) { + pr_err("channel [%s] already exist.\n", name); + return -EBUSY; + } + + ch = spcom_find_channel_by_name(""); /* find reserved channel */ + if (!ch) { + pr_err("no free channel.\n"); + return -ENODEV; + } + + ret = spcom_init_channel(ch, name); + if (ret < 0) { + pr_err("can't init channel %d\n", ret); + return ret; + } + + ret = spcom_register_rpmsg_drv(ch); + if (ret < 0) { + pr_err("register rpmsg driver failed %d\n", ret); + goto exit_destroy_channel; + } + + cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); + if (!cdev) { + ret = -ENOMEM; + goto exit_unregister_drv; + } + + devt = spcom_dev->device_no + atomic_read(&spcom_dev->chdev_count); + priv = ch; + dev = device_create(cls, parent, devt, priv, name); + if (IS_ERR(dev)) { + pr_err("device_create failed.\n"); + ret = -ENODEV; + goto exit_free_cdev; + } + + cdev_init(cdev, &fops); + cdev->owner = THIS_MODULE; + + ret = cdev_add(cdev, devt, 1); + if (ret < 0) { + pr_err("cdev_add failed %d\n", ret); + ret = -ENODEV; + goto exit_destroy_device; + } + atomic_inc(&spcom_dev->chdev_count); + mutex_lock(&ch->lock); + ch->cdev = cdev; + ch->dev = dev; + mutex_unlock(&ch->lock); + + return 0; + +exit_destroy_device: + device_destroy(spcom_dev->driver_class, devt); +exit_free_cdev: + kfree(cdev); +exit_unregister_drv: + ret = spcom_unregister_rpmsg_drv(ch); + if (ret != 0) + pr_err("can't unregister rpmsg drv %d\n", ret); +exit_destroy_channel: + // empty channel leaves free slot for next time + mutex_lock(&ch->lock); + memset(ch->name, 0, SPCOM_CHANNEL_NAME_SIZE); + mutex_unlock(&ch->lock); + return -EFAULT; +} + +static int __init spcom_register_chardev(void) +{ + int ret; + unsigned int baseminor = 0; + unsigned int count = 1; + void *priv = spcom_dev; + + ret = alloc_chrdev_region(&spcom_dev->device_no, baseminor, count, + DEVICE_NAME); + if (ret < 0) { + pr_err("alloc_chrdev_region failed %d\n", ret); + return ret; + } + + spcom_dev->driver_class = class_create(THIS_MODULE, DEVICE_NAME); + if (IS_ERR(spcom_dev->driver_class)) { + ret = -ENOMEM; + pr_err("class_create failed %d\n", ret); + goto exit_unreg_chrdev_region; + } + + spcom_dev->class_dev = device_create(spcom_dev->driver_class, NULL, + spcom_dev->device_no, priv, + DEVICE_NAME); + + if (IS_ERR(spcom_dev->class_dev)) { + pr_err("class_device_create failed %d\n", ret); + ret = -ENOMEM; + goto exit_destroy_class; + } + + cdev_init(&spcom_dev->cdev, &fops); + spcom_dev->cdev.owner = THIS_MODULE; + + ret = cdev_add(&spcom_dev->cdev, + MKDEV(MAJOR(spcom_dev->device_no), 0), + SPCOM_MAX_CHANNELS); + if (ret < 0) { + pr_err("cdev_add failed %d\n", ret); + goto exit_destroy_device; + } + + pr_debug("char device created.\n"); + + return 0; + +exit_destroy_device: + device_destroy(spcom_dev->driver_class, spcom_dev->device_no); +exit_destroy_class: + class_destroy(spcom_dev->driver_class); +exit_unreg_chrdev_region: + unregister_chrdev_region(spcom_dev->device_no, 1); + return ret; +} + +static void spcom_unregister_chrdev(void) +{ + cdev_del(&spcom_dev->cdev); + device_destroy(spcom_dev->driver_class, spcom_dev->device_no); + class_destroy(spcom_dev->driver_class); + unregister_chrdev_region(spcom_dev->device_no, + atomic_read(&spcom_dev->chdev_count)); + +} + +static int spcom_parse_dt(struct device_node *np) +{ + int ret; + const char *propname = "qcom,spcom-ch-names"; + int num_ch; + int i; + const char *name; + + num_ch = of_property_count_strings(np, propname); + if (num_ch < 0) { + pr_err("wrong format of predefined channels definition [%d].\n", + num_ch); + return num_ch; + } + if (num_ch > ARRAY_SIZE(spcom_dev->predefined_ch_name)) { + pr_err("too many predefined channels [%d].\n", num_ch); + return -EINVAL; + } + + pr_debug("num of predefined channels [%d].\n", num_ch); + for (i = 0; i < num_ch; i++) { + ret = of_property_read_string_index(np, propname, i, &name); + if (ret) { + pr_err("failed to read DT channel [%d] name .\n", i); + return -EFAULT; + } + strlcpy(spcom_dev->predefined_ch_name[i], + name, + sizeof(spcom_dev->predefined_ch_name[i])); + + pr_debug("found ch [%s].\n", name); + } + + return num_ch; +} + +/* + * the function is running on system workqueue context, + * processes delayed (by rpmsg rx callback) packets: + * each paket belong to its destination spcom channel ch + */ +static void spcom_signal_rx_done(struct work_struct *ignored) +{ + struct spcom_channel *ch; + struct rx_buff_list *rx_item; + struct spcom_msg_hdr *hdr; + unsigned long flags; + + spin_lock_irqsave(&spcom_dev->rx_lock, flags); + while (!list_empty(&spcom_dev->rx_list_head)) { + /* detach last entry */ + rx_item = list_last_entry(&spcom_dev->rx_list_head, + struct rx_buff_list, list); + list_del(&rx_item->list); + spin_unlock_irqrestore(&spcom_dev->rx_lock, flags); + + if (!rx_item) { + pr_err("empty entry in pending rx list\n"); + spin_lock_irqsave(&spcom_dev->rx_lock, flags); + continue; + } + ch = rx_item->ch; + hdr = (struct spcom_msg_hdr *)rx_item->rpmsg_rx_buf; + mutex_lock(&ch->lock); + + if (ch->comm_role_undefined) { + ch->comm_role_undefined = false; + ch->is_server = true; + ch->txn_id = hdr->txn_id; + pr_debug("ch [%s] first packet txn_id=%d, it is server\n", + ch->name, ch->txn_id); + } + + if (ch->rpmsg_abort) { + if (ch->rpmsg_rx_buf) { + pr_debug("ch [%s] rx aborted free %lu bytes\n", + ch->name, ch->actual_rx_size); + kfree(ch->rpmsg_rx_buf); + ch->actual_rx_size = 0; + } + goto rx_aborted; + } + if (ch->rpmsg_rx_buf) { + pr_err("ch [%s] previous buffer not consumed %lu bytes\n", + ch->name, ch->actual_rx_size); + kfree(ch->rpmsg_rx_buf); + ch->rpmsg_rx_buf = NULL; + ch->actual_rx_size = 0; + } + if (!ch->is_server && (hdr->txn_id != ch->txn_id)) { + pr_err("ch [%s] rx dropped txn_id %d, ch->txn_id %d\n", + ch->name, hdr->txn_id, ch->txn_id); + goto rx_aborted; + } + ch->rpmsg_rx_buf = rx_item->rpmsg_rx_buf; + ch->actual_rx_size = rx_item->rx_buf_size; + complete_all(&ch->rx_done); + mutex_unlock(&ch->lock); + + kfree(rx_item); + + /* lock for the next list entry */ + spin_lock_irqsave(&spcom_dev->rx_lock, flags); + } + spin_unlock_irqrestore(&spcom_dev->rx_lock, flags); + return; +rx_aborted: + mutex_unlock(&ch->lock); + kfree(rx_item->rpmsg_rx_buf); + kfree(rx_item); +} + +static int spcom_rpdev_cb(struct rpmsg_device *rpdev, + void *data, int len, void *priv, u32 src) +{ + struct spcom_channel *ch; + static DECLARE_WORK(rpmsg_rx_consumer, spcom_signal_rx_done); + struct rx_buff_list *rx_item; + unsigned long flags; + + if (!rpdev || !data) { + pr_err("rpdev or data is NULL\n"); + return -EINVAL; + } + pr_debug("incoming msg from %s\n", rpdev->id.name); + ch = dev_get_drvdata(&rpdev->dev); + if (!ch) { + pr_err("%s: invalid ch\n", __func__); + return -EINVAL; + } + if (len > SPCOM_RX_BUF_SIZE || len <= 0) { + pr_err("got msg size %d, max allowed %d\n", + len, SPCOM_RX_BUF_SIZE); + return -EINVAL; + } + + rx_item = kzalloc(sizeof(*rx_item), GFP_ATOMIC); + if (!rx_item) + return -ENOMEM; + + rx_item->rpmsg_rx_buf = kzalloc(len, GFP_ATOMIC); + if (!rx_item->rpmsg_rx_buf) { + kfree(rx_item); + return -ENOMEM; + } + memcpy(rx_item->rpmsg_rx_buf, data, len); + rx_item->rx_buf_size = len; + rx_item->ch = ch; + + spin_lock_irqsave(&spcom_dev->rx_lock, flags); + list_add(&rx_item->list, &spcom_dev->rx_list_head); + spin_unlock_irqrestore(&spcom_dev->rx_lock, flags); + pr_debug("signaling rx item for %s, received %d bytes\n", + rpdev->id.name, len); + + schedule_work(&rpmsg_rx_consumer); + return 0; +} + +static int spcom_rpdev_probe(struct rpmsg_device *rpdev) +{ + const char *name; + struct spcom_channel *ch; + + if (!rpdev) { + pr_err("rpdev is NULL\n"); + return -EINVAL; + } + name = rpdev->id.name; + pr_debug("new channel %s rpmsg_device arrived\n", name); + ch = spcom_find_channel_by_name(name); + if (!ch) { + pr_err("channel %s not found\n", name); + return -ENODEV; + } + mutex_lock(&ch->lock); + ch->rpdev = rpdev; + ch->rpmsg_abort = false; + ch->txn_id = INITIAL_TXN_ID; + complete_all(&ch->connect); + mutex_unlock(&ch->lock); + + dev_set_drvdata(&rpdev->dev, ch); + + /* used to evaluate underlying transport link up/down */ + atomic_inc(&spcom_dev->rpmsg_dev_count); + if (atomic_read(&spcom_dev->rpmsg_dev_count) == 1) + complete_all(&spcom_dev->rpmsg_state_change); + + return 0; +} + +static void spcom_rpdev_remove(struct rpmsg_device *rpdev) +{ + struct spcom_channel *ch; + int i; + + if (!rpdev) { + pr_err("rpdev is NULL\n"); + return; + } + + dev_info(&rpdev->dev, "rpmsg device %s removed\n", rpdev->id.name); + ch = dev_get_drvdata(&rpdev->dev); + if (!ch) { + pr_err("channel %s not found\n", rpdev->id.name); + return; + } + + mutex_lock(&ch->lock); + // unlock all ion buffers of sp_kernel channel + if (strcmp(ch->name, "sp_kernel") == 0) { + for (i = 0; i < ARRAY_SIZE(ch->dmabuf_handle_table); i++) { + if (ch->dmabuf_handle_table[i] != NULL) { + pr_debug("unlocked ion buf #%d fd [%d].\n", + i, ch->dmabuf_fd_table[i]); + dma_buf_put(ch->dmabuf_handle_table[i]); + ch->dmabuf_handle_table[i] = NULL; + ch->dmabuf_fd_table[i] = -1; + } + } + } + + ch->rpdev = NULL; + ch->rpmsg_abort = true; + ch->txn_id = 0; + complete_all(&ch->rx_done); + mutex_unlock(&ch->lock); + + /* used to evaluate underlying transport link up/down */ + if (atomic_dec_and_test(&spcom_dev->rpmsg_dev_count)) + complete_all(&spcom_dev->rpmsg_state_change); + +} + +/* register rpmsg driver to match with channel ch_name */ +static int spcom_register_rpmsg_drv(struct spcom_channel *ch) +{ + struct rpmsg_driver *rpdrv; + struct rpmsg_device_id *match; + char *drv_name; + int ret; + + if (ch->rpdrv) { + pr_err("ch:%s, rpmsg driver %s already registered\n", ch->name, + ch->rpdrv->id_table->name); + return -ENODEV; + } + + rpdrv = kzalloc(sizeof(*rpdrv), GFP_KERNEL); + if (!rpdrv) + return -ENOMEM; + + /* zalloc array of two to NULL terminate the match list */ + match = kzalloc(2 * sizeof(*match), GFP_KERNEL); + if (!match) { + kfree(rpdrv); + return -ENOMEM; + } + snprintf(match->name, RPMSG_NAME_SIZE, "%s", ch->name); + + drv_name = kasprintf(GFP_KERNEL, "%s_%s", "spcom_rpmsg_drv", ch->name); + if (!drv_name) { + pr_err("can't allocate drv_name for %s\n", ch->name); + kfree(rpdrv); + kfree(match); + return -ENOMEM; + } + + rpdrv->probe = spcom_rpdev_probe; + rpdrv->remove = spcom_rpdev_remove; + rpdrv->callback = spcom_rpdev_cb; + rpdrv->id_table = match; + rpdrv->drv.name = drv_name; + ret = register_rpmsg_driver(rpdrv); + if (ret) { + pr_err("can't register rpmsg_driver for %s\n", ch->name); + kfree(rpdrv); + kfree(match); + kfree(drv_name); + return ret; + } + mutex_lock(&ch->lock); + ch->rpdrv = rpdrv; + ch->rpmsg_abort = false; + mutex_unlock(&ch->lock); + + return 0; +} + +static int spcom_unregister_rpmsg_drv(struct spcom_channel *ch) +{ + if (!ch->rpdrv) + return -ENODEV; + unregister_rpmsg_driver(ch->rpdrv); + + mutex_lock(&ch->lock); + kfree(ch->rpdrv->drv.name); + kfree((void *)ch->rpdrv->id_table); + kfree(ch->rpdrv); + ch->rpdrv = NULL; + ch->rpmsg_abort = true; /* will unblock spcom_rx() */ + mutex_unlock(&ch->lock); + return 0; +} + +static int spcom_probe(struct platform_device *pdev) +{ + int ret; + struct spcom_device *dev = NULL; + struct device_node *np; + + if (!pdev) { + pr_err("invalid pdev.\n"); + return -ENODEV; + } + + np = pdev->dev.of_node; + if (!np) { + pr_err("invalid DT node.\n"); + return -EINVAL; + } + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (dev == NULL) + return -ENOMEM; + + spcom_dev = dev; + spcom_dev->pdev = pdev; + /* start counting exposed channel char devices from 1 */ + atomic_set(&spcom_dev->chdev_count, 1); + init_completion(&spcom_dev->rpmsg_state_change); + atomic_set(&spcom_dev->rpmsg_dev_count, 0); + + INIT_LIST_HEAD(&spcom_dev->rx_list_head); + spin_lock_init(&spcom_dev->rx_lock); + + ret = spcom_register_chardev(); + if (ret) { + pr_err("create character device failed.\n"); + goto fail_while_chardev_reg; + } + + ret = spcom_parse_dt(np); + if (ret < 0) + goto fail_reg_chardev; + + ret = spcom_create_predefined_channels_chardev(); + if (ret < 0) { + pr_err("create character device failed.\n"); + goto fail_reg_chardev; + } + pr_debug("Driver Initialization ok.\n"); + return 0; + +fail_reg_chardev: + pr_err("failed to init driver\n"); + spcom_unregister_chrdev(); +fail_while_chardev_reg: + kfree(dev); + spcom_dev = NULL; + + return -ENODEV; +} + +static const struct of_device_id spcom_match_table[] = { + { .compatible = "qcom,spcom", }, + { }, +}; + +static struct platform_driver spcom_driver = { + .probe = spcom_probe, + .driver = { + .name = DEVICE_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(spcom_match_table), + }, +}; + +static int __init spcom_init(void) +{ + int ret; + + pr_info("spcom driver version 2.1 23-April-2018.\n"); + + ret = platform_driver_register(&spcom_driver); + if (ret) + pr_err("spcom_driver register failed %d\n", ret); + + return ret; +} +module_init(spcom_init); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Secure Processor Communication"); From c8fc59961016b5d1fc7fcf8a329a33c42070bfba Mon Sep 17 00:00:00 2001 From: Nick Desaulniers Date: Fri, 30 Aug 2019 13:34:59 -0700 Subject: [PATCH 179/356] soc: qcom: spcom-legacy: fix section mismatch warning The KASAN builds have started producing the warning: WARNING: vmlinux.o(.text+0x8cad78): Section mismatch in reference from the function spcom_probe() to the function .init.text:spcom_register_chardev() The function spcom_probe() references the function __init spcom_register_chardev(). This is often because spcom_probe lacks a __init annotation or the annotation of spcom_register_chardev is wrong. Indeed, spcom_register_chardev is called from the non-__init spcom_probe, so marking spcom_register_chardev __init is dangerous. Bug: 139442076 Change-Id: I8feff354bcea8171d8f8130cfa8a230439efc9b0 Signed-off-by: Nick Desaulniers --- drivers/soc/qcom/spcom-legacy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soc/qcom/spcom-legacy.c b/drivers/soc/qcom/spcom-legacy.c index c51bff9d445f..64fb72f8a393 100644 --- a/drivers/soc/qcom/spcom-legacy.c +++ b/drivers/soc/qcom/spcom-legacy.c @@ -1753,7 +1753,7 @@ static int spcom_create_channel_chardev(const char *name) return -EFAULT; } -static int __init spcom_register_chardev(void) +static int spcom_register_chardev(void) { int ret; unsigned int baseminor = 0; From 7f8924e295ee7afdff311302688493e990a67c18 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Fri, 1 Aug 2025 03:26:31 +0000 Subject: [PATCH 180/356] teachpack: audio: Enable CONFIG_WCD_SPI_DMA_MASKING for sdm845 --- techpack/audio/config/sdm845auto.conf | 1 + techpack/audio/config/sdm845autoconf.h | 1 + 2 files changed, 2 insertions(+) diff --git a/techpack/audio/config/sdm845auto.conf b/techpack/audio/config/sdm845auto.conf index b3457a42064d..9933bc303cd0 100644 --- a/techpack/audio/config/sdm845auto.conf +++ b/techpack/audio/config/sdm845auto.conf @@ -35,3 +35,4 @@ export CONFIG_SND_SOC_MSM_STUB=y export CONFIG_WCD_DSP_GLINK=y export CONFIG_MSM_AVTIMER=y export CONFIG_SND_SOC_MSM_HDMI_CODEC_RX=y +export CONFIG_WCD_SPI_DMA_MASKING=y diff --git a/techpack/audio/config/sdm845autoconf.h b/techpack/audio/config/sdm845autoconf.h index 8c00cfebe514..709b07e0fd7e 100644 --- a/techpack/audio/config/sdm845autoconf.h +++ b/techpack/audio/config/sdm845autoconf.h @@ -39,3 +39,4 @@ #define CONFIG_WCD_DSP_GLINK 1 #define CONFIG_MSM_AVTIMER 1 #define CONFIG_SND_SOC_MSM_HDMI_CODEC_RX 1 +#define CONFIG_WCD_SPI_DMA_MASKING 1 From 6c3c9a51b841d180ee9e2a14b1fce0ca2dfb9e6f Mon Sep 17 00:00:00 2001 From: Meng Wang Date: Mon, 18 Mar 2019 10:49:50 +0800 Subject: [PATCH 181/356] techpack: asoc: sdm845: add afe loopback support in machine driver Add machine driver change for AFE RX to TX loopback. Change-Id: Icd77092867e93bd1da76b1ba22c61091a2d1c8f4 Signed-off-by: Meng Wang --- techpack/audio/asoc/sdm845.c | 77 +++++++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 2 deletions(-) diff --git a/techpack/audio/asoc/sdm845.c b/techpack/audio/asoc/sdm845.c index 883c06509ea5..e6c90e5d28a3 100644 --- a/techpack/audio/asoc/sdm845.c +++ b/techpack/audio/asoc/sdm845.c @@ -161,6 +161,10 @@ struct msm_pinctrl_info { static atomic_t pinctrl_ref_count; +enum { + AFE_LOOPBACK_TX_IDX = 0, + AFE_LOOPBACK_TX_IDX_MAX, +}; struct msm_asoc_mach_data { u32 mclk_freq; int us_euro_gpio; /* used by gpio driver API */ @@ -458,6 +462,10 @@ static struct dev_config aux_pcm_tx_cfg[] = { [QUAT_AUX_PCM] = {SAMPLING_RATE_8KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, }; +static struct dev_config afe_loopback_tx_cfg[] = { + [AFE_LOOPBACK_TX_IDX] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, +}; + static int msm_vi_feed_tx_ch = 2; static const char *const slim_rx_ch_text[] = {"One", "Two"}; static const char *const slim_tx_ch_text[] = {"One", "Two", "Three", "Four", @@ -509,6 +517,7 @@ static const char *const mi2s_ch_text[] = {"One", "Two", "Three", "Four", "Eight"}; static const char *const hifi_text[] = {"Off", "On"}; static const char *const qos_text[] = {"Disable", "Enable"}; +static const char *const afe_loopback_tx_ch_text[] = {"One", "Two"}; static SOC_ENUM_SINGLE_EXT_DECL(slim_0_rx_chs, slim_rx_ch_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_2_rx_chs, slim_rx_ch_text); @@ -576,6 +585,7 @@ static SOC_ENUM_SINGLE_EXT_DECL(aux_pcm_rx_format, bit_format_text); static SOC_ENUM_SINGLE_EXT_DECL(aux_pcm_tx_format, bit_format_text); static SOC_ENUM_SINGLE_EXT_DECL(hifi_function, hifi_text); static SOC_ENUM_SINGLE_EXT_DECL(qos_vote, qos_text); +static SOC_ENUM_SINGLE_EXT_DECL(afe_loopback_tx_chs, afe_loopback_tx_ch_text); static struct platform_device *spdev; static int msm_hifi_control; @@ -973,6 +983,28 @@ static int slim_tx_bit_format_put(struct snd_kcontrol *kcontrol, return 0; } +static int afe_loopback_tx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: afe_loopback_tx_ch = %d\n", __func__, + afe_loopback_tx_cfg[0].channels); + ucontrol->value.enumerated.item[0] = + afe_loopback_tx_cfg[0].channels - 1; + + return 0; +} + +static int afe_loopback_tx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + afe_loopback_tx_cfg[0].channels = + ucontrol->value.enumerated.item[0] + 1; + pr_debug("%s: afe_loopback_tx_ch = %d\n", __func__, + afe_loopback_tx_cfg[0].channels); + + return 1; +} + static int msm_slim_rx_ch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -3188,6 +3220,9 @@ static const struct snd_kcontrol_new msm_snd_controls[] = { msm_qos_ctl_put), SOC_SINGLE_MULTI_EXT("TDM Slot Map", SND_SOC_NOPM, 0, 255, 0, 4, NULL, tdm_slot_map_put), + SOC_ENUM_EXT("AFE_LOOPBACK_TX Channels", afe_loopback_tx_chs, + afe_loopback_tx_ch_get, afe_loopback_tx_ch_put), + }; static int msm_snd_enable_codec_ext_clk(struct snd_soc_component *component, @@ -3404,7 +3439,7 @@ static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); int rc = 0; - int idx; + int idx = 0; void *config = NULL; struct snd_soc_component *component = NULL; struct snd_soc_dai *codec_dai = rtd->codec_dai; @@ -3729,6 +3764,14 @@ static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, mi2s_tx_cfg[QUAT_MI2S].channels; break; + case MSM_BACKEND_DAI_AFE_LOOPBACK_TX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + afe_loopback_tx_cfg[idx].bit_format); + rate->min = rate->max = afe_loopback_tx_cfg[idx].sample_rate; + channels->min = channels->max = + afe_loopback_tx_cfg[idx].channels; + break; + default: rate->min = rate->max = SAMPLING_RATE_48KHZ; break; @@ -6483,6 +6526,23 @@ static struct snd_soc_dai_link msm_auxpcm_be_dai_links[] = { }, }; +static struct snd_soc_dai_link msm_afe_rxtx_lb_be_dai_link[] = { + { + .name = LPASS_BE_AFE_LOOPBACK_TX, + .stream_name = "AFE Loopback Capture", + .cpu_dai_name = "msm-dai-q6-dev.24577", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_AFE_LOOPBACK_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, +}; + static struct snd_soc_dai_link msm_tavil_snd_card_dai_links[ ARRAY_SIZE(msm_common_dai_links) + ARRAY_SIZE(msm_tavil_fe_dai_links) + @@ -6492,7 +6552,8 @@ static struct snd_soc_dai_link msm_tavil_snd_card_dai_links[ ARRAY_SIZE(msm_wcn_be_dai_links) + ARRAY_SIZE(ext_disp_be_dai_link) + ARRAY_SIZE(msm_mi2s_be_dai_links) + - ARRAY_SIZE(msm_auxpcm_be_dai_links)]; + ARRAY_SIZE(msm_auxpcm_be_dai_links) + + ARRAY_SIZE(msm_afe_rxtx_lb_be_dai_link)]; static int msm_snd_card_tavil_late_probe(struct snd_soc_card *card) { @@ -6794,6 +6855,8 @@ static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev) struct snd_soc_dai_link *dailink; int len_1, len_2, len_3, len_4; int total_links; + int rc = 0; + u32 val = 0; const struct of_device_id *match; match = of_match_node(sdm845_asoc_machine_of_match, dev->of_node); @@ -6858,6 +6921,16 @@ static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev) sizeof(msm_auxpcm_be_dai_links)); total_links += ARRAY_SIZE(msm_auxpcm_be_dai_links); } + + rc = of_property_read_u32(dev->of_node, "qcom,afe-rxtx-lb", + &val); + if (!rc && val) { + memcpy(msm_tavil_snd_card_dai_links + total_links, + msm_afe_rxtx_lb_be_dai_link, + sizeof(msm_afe_rxtx_lb_be_dai_link)); + total_links += + ARRAY_SIZE(msm_afe_rxtx_lb_be_dai_link); + } dailink = msm_tavil_snd_card_dai_links; } else if (!strcmp(match->data, "stub_codec")) { card = &snd_soc_card_stub_msm; From 7000547562516b8d66f71bb466ebe173e184a7ca Mon Sep 17 00:00:00 2001 From: Prasad Kumpatla Date: Fri, 6 Dec 2019 16:08:14 +0530 Subject: [PATCH 182/356] techpack: asoc: sdm845: set format param mask for SLIM_7_TX backend Enable format mask for SLIM_7_TX backend to fix hardware params setting failure on sdm845 target. Change-Id: I00d7f8a2613c4b396196222e7e6256f896d58cc6 Signed-off-by: Prasad Kumpatla --- techpack/audio/asoc/sdm845.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/techpack/audio/asoc/sdm845.c b/techpack/audio/asoc/sdm845.c index e6c90e5d28a3..a0e700ab136e 100644 --- a/techpack/audio/asoc/sdm845.c +++ b/techpack/audio/asoc/sdm845.c @@ -3519,6 +3519,8 @@ static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, break; case MSM_BACKEND_DAI_SLIMBUS_7_TX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + slim_tx_cfg[SLIM_TX_7].bit_format); rate->min = rate->max = slim_tx_cfg[SLIM_TX_7].sample_rate; channels->min = channels->max = slim_tx_cfg[SLIM_TX_7].channels; From e5e99294a871ad4b95043328e910208d39202150 Mon Sep 17 00:00:00 2001 From: Sudheer Papothi Date: Fri, 17 May 2019 01:49:27 +0530 Subject: [PATCH 183/356] techpack: ASoC: sdm845: Avoid static route between cpu and codec dai Currently ASoC core creates a static route b/w playback/capture widgets of cpu and codec dai if they are part of the same dai-link. However this will cause codec path to get powered up first followed by the backend dai start during device switch use-case where the front-end is not closed, leading to audio playback failure if either bit-width or sample rate is different. Set the dynamic bit of backend dai dailink to update the backend parameters before codec path setup. Change-Id: Ic80755a5672849f527d5d696d31174a62997aca2 Signed-off-by: Sudheer Papothi --- techpack/audio/asoc/sdm845.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/techpack/audio/asoc/sdm845.c b/techpack/audio/asoc/sdm845.c index a0e700ab136e..d55708813afd 100644 --- a/techpack/audio/asoc/sdm845.c +++ b/techpack/audio/asoc/sdm845.c @@ -5884,6 +5884,7 @@ static struct snd_soc_dai_link msm_common_be_dai_links[] = { .platform_name = "msm-pcm-routing", .codec_name = "msm-stub-codec.1", .codec_dai_name = "msm-stub-rx", + .dynamic_be = 1, .no_pcm = 1, .dpcm_playback = 1, .id = MSM_BACKEND_DAI_USB_RX, @@ -6040,6 +6041,7 @@ static struct snd_soc_dai_link msm_tavil_be_dai_links[] = { .platform_name = "msm-pcm-routing", .codec_name = "tavil_codec", .codec_dai_name = "tavil_rx1", + .dynamic_be = 1, .no_pcm = 1, .dpcm_playback = 1, .id = MSM_BACKEND_DAI_SLIMBUS_0_RX, @@ -6057,6 +6059,7 @@ static struct snd_soc_dai_link msm_tavil_be_dai_links[] = { .platform_name = "msm-pcm-routing", .codec_name = "tavil_codec", .codec_dai_name = "tavil_tx1", + .dynamic_be = 1, .no_pcm = 1, .dpcm_capture = 1, .id = MSM_BACKEND_DAI_SLIMBUS_0_TX, @@ -6071,6 +6074,7 @@ static struct snd_soc_dai_link msm_tavil_be_dai_links[] = { .platform_name = "msm-pcm-routing", .codec_name = "tavil_codec", .codec_dai_name = "tavil_rx1", + .dynamic_be = 1, .no_pcm = 1, .dpcm_playback = 1, .id = MSM_BACKEND_DAI_SLIMBUS_1_RX, @@ -6087,6 +6091,7 @@ static struct snd_soc_dai_link msm_tavil_be_dai_links[] = { .platform_name = "msm-pcm-routing", .codec_name = "tavil_codec", .codec_dai_name = "tavil_tx3", + .dynamic_be = 1, .no_pcm = 1, .dpcm_capture = 1, .id = MSM_BACKEND_DAI_SLIMBUS_1_TX, @@ -6101,6 +6106,7 @@ static struct snd_soc_dai_link msm_tavil_be_dai_links[] = { .platform_name = "msm-pcm-routing", .codec_name = "tavil_codec", .codec_dai_name = "tavil_rx2", + .dynamic_be = 1, .no_pcm = 1, .dpcm_playback = 1, .id = MSM_BACKEND_DAI_SLIMBUS_2_RX, @@ -6116,6 +6122,7 @@ static struct snd_soc_dai_link msm_tavil_be_dai_links[] = { .platform_name = "msm-pcm-routing", .codec_name = "tavil_codec", .codec_dai_name = "tavil_rx1", + .dynamic_be = 1, .no_pcm = 1, .dpcm_playback = 1, .id = MSM_BACKEND_DAI_SLIMBUS_3_RX, @@ -6132,6 +6139,7 @@ static struct snd_soc_dai_link msm_tavil_be_dai_links[] = { .platform_name = "msm-pcm-routing", .codec_name = "tavil_codec", .codec_dai_name = "tavil_tx1", + .dynamic_be = 1, .no_pcm = 1, .dpcm_capture = 1, .id = MSM_BACKEND_DAI_SLIMBUS_3_TX, @@ -6146,6 +6154,7 @@ static struct snd_soc_dai_link msm_tavil_be_dai_links[] = { .platform_name = "msm-pcm-routing", .codec_name = "tavil_codec", .codec_dai_name = "tavil_rx1", + .dynamic_be = 1, .no_pcm = 1, .dpcm_playback = 1, .id = MSM_BACKEND_DAI_SLIMBUS_4_RX, @@ -6162,6 +6171,7 @@ static struct snd_soc_dai_link msm_tavil_be_dai_links[] = { .platform_name = "msm-pcm-routing", .codec_name = "tavil_codec", .codec_dai_name = "tavil_rx3", + .dynamic_be = 1, .no_pcm = 1, .dpcm_playback = 1, .id = MSM_BACKEND_DAI_SLIMBUS_5_RX, @@ -6179,6 +6189,7 @@ static struct snd_soc_dai_link msm_tavil_be_dai_links[] = { .platform_name = "msm-pcm-routing", .codec_name = "tavil_codec", .codec_dai_name = "tavil_mad1", + .dynamic_be = 1, .no_pcm = 1, .dpcm_capture = 1, .id = MSM_BACKEND_DAI_SLIMBUS_5_TX, @@ -6193,6 +6204,7 @@ static struct snd_soc_dai_link msm_tavil_be_dai_links[] = { .platform_name = "msm-pcm-routing", .codec_name = "tavil_codec", .codec_dai_name = "tavil_rx4", + .dynamic_be = 1, .no_pcm = 1, .dpcm_playback = 1, .id = MSM_BACKEND_DAI_SLIMBUS_6_RX, @@ -6210,6 +6222,7 @@ static struct snd_soc_dai_link msm_tavil_be_dai_links[] = { .platform_name = "msm-pcm-routing", .codec_name = "tavil_codec", .codec_dai_name = "tavil_vifeedback", + .dynamic_be = 1, .id = MSM_BACKEND_DAI_SLIMBUS_4_TX, .be_hw_params_fixup = msm_be_hw_params_fixup, .ops = &msm_be_ops, @@ -6232,6 +6245,7 @@ static struct snd_soc_dai_link msm_wcn_be_dai_links[] = { * supported usecase information */ .codec_dai_name = "btfm_bt_sco_a2dp_slim_rx", + .dynamic_be = 1, .no_pcm = 1, .dpcm_playback = 1, .id = MSM_BACKEND_DAI_SLIMBUS_7_RX, @@ -6248,6 +6262,7 @@ static struct snd_soc_dai_link msm_wcn_be_dai_links[] = { .platform_name = "msm-pcm-routing", .codec_name = "btfmslim_slave", .codec_dai_name = "btfm_bt_sco_slim_tx", + .dynamic_be = 1, .no_pcm = 1, .dpcm_capture = 1, .id = MSM_BACKEND_DAI_SLIMBUS_7_TX, @@ -6262,6 +6277,7 @@ static struct snd_soc_dai_link msm_wcn_be_dai_links[] = { .platform_name = "msm-pcm-routing", .codec_name = "btfmslim_slave", .codec_dai_name = "btfm_fm_slim_tx", + .dynamic_be = 1, .no_pcm = 1, .dpcm_capture = 1, .id = MSM_BACKEND_DAI_SLIMBUS_8_TX, @@ -6298,6 +6314,7 @@ static struct snd_soc_dai_link msm_mi2s_be_dai_links[] = { .platform_name = "msm-pcm-routing", .codec_name = "msm-stub-codec.1", .codec_dai_name = "msm-stub-rx", + .dynamic_be = 1, .no_pcm = 1, .dpcm_playback = 1, .id = MSM_BACKEND_DAI_PRI_MI2S_RX, @@ -6313,6 +6330,7 @@ static struct snd_soc_dai_link msm_mi2s_be_dai_links[] = { .platform_name = "msm-pcm-routing", .codec_name = "msm-stub-codec.1", .codec_dai_name = "msm-stub-tx", + .dynamic_be = 1, .no_pcm = 1, .dpcm_capture = 1, .id = MSM_BACKEND_DAI_PRI_MI2S_TX, @@ -6327,6 +6345,7 @@ static struct snd_soc_dai_link msm_mi2s_be_dai_links[] = { .platform_name = "msm-pcm-routing", .codec_name = "msm-stub-codec.1", .codec_dai_name = "msm-stub-rx", + .dynamic_be = 1, .no_pcm = 1, .dpcm_playback = 1, .id = MSM_BACKEND_DAI_SECONDARY_MI2S_RX, @@ -6342,6 +6361,7 @@ static struct snd_soc_dai_link msm_mi2s_be_dai_links[] = { .platform_name = "msm-pcm-routing", .codec_name = "msm-stub-codec.1", .codec_dai_name = "msm-stub-tx", + .dynamic_be = 1, .no_pcm = 1, .dpcm_capture = 1, .id = MSM_BACKEND_DAI_SECONDARY_MI2S_TX, @@ -6356,6 +6376,7 @@ static struct snd_soc_dai_link msm_mi2s_be_dai_links[] = { .platform_name = "msm-pcm-routing", .codec_name = "msm-stub-codec.1", .codec_dai_name = "msm-stub-rx", + .dynamic_be = 1, .no_pcm = 1, .dpcm_playback = 1, .id = MSM_BACKEND_DAI_TERTIARY_MI2S_RX, @@ -6371,6 +6392,7 @@ static struct snd_soc_dai_link msm_mi2s_be_dai_links[] = { .platform_name = "msm-pcm-routing", .codec_name = "msm-stub-codec.1", .codec_dai_name = "msm-stub-tx", + .dynamic_be = 1, .no_pcm = 1, .dpcm_capture = 1, .id = MSM_BACKEND_DAI_TERTIARY_MI2S_TX, @@ -6385,6 +6407,7 @@ static struct snd_soc_dai_link msm_mi2s_be_dai_links[] = { .platform_name = "msm-pcm-routing", .codec_name = "msm-stub-codec.1", .codec_dai_name = "msm-stub-rx", + .dynamic_be = 1, .no_pcm = 1, .dpcm_playback = 1, .id = MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, @@ -6400,6 +6423,7 @@ static struct snd_soc_dai_link msm_mi2s_be_dai_links[] = { .platform_name = "msm-pcm-routing", .codec_name = "msm-stub-codec.1", .codec_dai_name = "msm-stub-tx", + .dynamic_be = 1, .no_pcm = 1, .dpcm_capture = 1, .id = MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, From 9a6b26371e455d553ef799c8ad60d73bc6d19e66 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Sun, 2 Apr 2023 12:05:21 +0000 Subject: [PATCH 184/356] ARM64: configs: Copy kona-perf_defconfig to sdm845-perf_defconfig --- .../configs/vendor/sdm845-perf_defconfig | 724 ++++++++++++++++++ 1 file changed, 724 insertions(+) create mode 100644 arch/arm64/configs/vendor/sdm845-perf_defconfig diff --git a/arch/arm64/configs/vendor/sdm845-perf_defconfig b/arch/arm64/configs/vendor/sdm845-perf_defconfig new file mode 100644 index 000000000000..14df20c6e974 --- /dev/null +++ b/arch/arm64/configs/vendor/sdm845-perf_defconfig @@ -0,0 +1,724 @@ +CONFIG_LOCALVERSION="-perf" +CONFIG_AUDIT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_PREEMPT=y +CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_SCHED_WALT=y +CONFIG_TASKSTATS=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_PSI=y +CONFIG_RCU_EXPERT=y +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_RCU_NOCB_CPU=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_IKHEADERS=y +CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 +CONFIG_CGROUPS=y +CONFIG_MEMCG=y +CONFIG_MEMCG_SWAP=y +CONFIG_BLK_CGROUP=y +CONFIG_CGROUP_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_PID_NS is not set +CONFIG_SCHED_TUNE=y +CONFIG_BLK_DEV_INITRD=y +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_LZ4 is not set +# CONFIG_FHANDLE is not set +CONFIG_KALLSYMS_ALL=y +CONFIG_BPF_LSM=y +CONFIG_BPF_SYSCALL=y +CONFIG_BPF_JIT_ALWAYS_ON=y +CONFIG_USERFAULTFD=y +# CONFIG_RSEQ is not set +CONFIG_EMBEDDED=y +# CONFIG_SLUB_DEBUG is not set +# CONFIG_COMPAT_BRK is not set +CONFIG_SLAB_FREELIST_RANDOM=y +CONFIG_SLAB_FREELIST_HARDENED=y +CONFIG_PROFILING=y +# CONFIG_ZONE_DMA32 is not set +CONFIG_ARCH_QCOM=y +CONFIG_ARCH_KONA=y +CONFIG_PCI=y +CONFIG_PCI_MSM=y +CONFIG_PCI_MSM_MSI=y +CONFIG_SCHED_MC=y +CONFIG_NR_CPUS=8 +CONFIG_SECCOMP=y +CONFIG_OKL4_GUEST=y +# CONFIG_UNMAP_KERNEL_AT_EL0 is not set +CONFIG_ARM64_SSBD=y +CONFIG_ARMV8_DEPRECATED=y +CONFIG_SWP_EMULATION=y +CONFIG_CP15_BARRIER_EMULATION=y +CONFIG_SETEND_EMULATION=y +CONFIG_ARM64_SW_TTBR0_PAN=y +# CONFIG_ARM64_VHE is not set +CONFIG_RANDOMIZE_BASE=y +CONFIG_CMDLINE="cgroup_disable=pressure" +CONFIG_CMDLINE_EXTEND=y +# CONFIG_EFI is not set +CONFIG_BUILD_ARM64_UNCOMPRESSED_KERNEL=y +CONFIG_KRYO_PMU_WORKAROUND=y +CONFIG_BUILD_ARM64_DT_OVERLAY=y +CONFIG_COMPAT=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_ENERGY_MODEL=y +CONFIG_CPU_IDLE=y +CONFIG_ARM_CPUIDLE=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_FREQ_TIMES=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_BOOST=y +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y +CONFIG_ARM_QCOM_CPUFREQ_HW=y +CONFIG_CRYPTO_SHA1_ARM64_CE=y +CONFIG_CRYPTO_SHA2_ARM64_CE=y +CONFIG_CRYPTO_GHASH_ARM64_CE=y +CONFIG_CRYPTO_AES_ARM64_CE_CCM=y +CONFIG_CRYPTO_AES_ARM64_CE_BLK=y +CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y +CONFIG_JUMP_LABEL=y +CONFIG_PANIC_ON_REFCOUNT_ERROR=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_BLK_INLINE_ENCRYPTION=y +CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_CFQ_GROUP_IOSCHED=y +CONFIG_IOSCHED_BFQ=y +CONFIG_BFQ_GROUP_IOSCHED=y +CONFIG_GKI_HIDDEN_GPU_CONFIGS=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_DEFAULT_MMAP_MIN_ADDR=32768 +CONFIG_CMA=y +CONFIG_CMA_AREAS=16 +CONFIG_ZSMALLOC=y +CONFIG_BALANCE_ANON_FILE_RECLAIM=y +CONFIG_HAVE_USERSPACE_LOW_MEMORY_KILLER=y +CONFIG_MEMFD_ASHMEM_SHIM=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=y +CONFIG_XFRM_INTERFACE=y +CONFIG_XFRM_MIGRATE=y +CONFIG_XFRM_STATISTICS=y +CONFIG_NET_KEY=y +CONFIG_XDP_SOCKETS=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_NET_IPGRE_DEMUX=y +CONFIG_SYN_COOKIES=y +CONFIG_NET_IPVTI=y +CONFIG_INET_AH=y +CONFIG_INET_ESP=y +CONFIG_INET_IPCOMP=y +CONFIG_INET_UDP_DIAG=y +CONFIG_INET_DIAG_DESTROY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_VTI=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_SUBTREES=y +CONFIG_NETFILTER=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_DSCP=y +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_NOTRACK=y +CONFIG_NETFILTER_XT_TARGET_TEE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_BPF=y +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_DSCP=y +CONFIG_NETFILTER_XT_MATCH_ESP=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +# CONFIG_NETFILTER_XT_MATCH_L2TP is not set +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y +CONFIG_NETFILTER_XT_MATCH_OWNER=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_RPFILTER=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_NAT=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_MATCH_RPFILTER=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +CONFIG_BRIDGE_NF_EBTABLES=y +CONFIG_BRIDGE_EBT_BROUTE=y +CONFIG_IP_SCTP=y +CONFIG_L2TP=y +CONFIG_L2TP_V3=y +CONFIG_L2TP_IP=y +CONFIG_L2TP_ETH=y +CONFIG_BRIDGE=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_PRIO=y +CONFIG_NET_SCH_MULTIQ=y +CONFIG_NET_SCH_TBF=y +CONFIG_NET_SCH_NETEM=y +CONFIG_NET_SCH_INGRESS=y +CONFIG_NET_CLS_FW=y +CONFIG_NET_CLS_U32=y +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_FLOW=y +CONFIG_NET_CLS_BPF=y +CONFIG_NET_CLS_MATCHALL=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_CMP=y +CONFIG_NET_EMATCH_NBYTE=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_EMATCH_META=y +CONFIG_NET_EMATCH_TEXT=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_POLICE=y +CONFIG_NET_ACT_GACT=y +CONFIG_NET_ACT_MIRRED=y +CONFIG_NET_ACT_SKBEDIT=y +CONFIG_NET_ACT_BPF=y +CONFIG_QRTR=y +CONFIG_QRTR_SMD=y +CONFIG_QRTR_MHI=y +CONFIG_BPF_JIT=y +CONFIG_SOCKEV_NLMCAST=y +CONFIG_CAN=y +CONFIG_CAN_MCP25XXFD=y +CONFIG_BT=y +CONFIG_MSM_BT_POWER=y +CONFIG_BT_SLIM_QCA6390=y +CONFIG_CFG80211=y +CONFIG_CFG80211_INTERNAL_REGDB=y +CONFIG_RFKILL=y +CONFIG_NFC_NQ=y +CONFIG_FW_LOADER_USER_HELPER=y +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +# CONFIG_FW_CACHE is not set +CONFIG_REGMAP_WCD_IRQ=y +CONFIG_DMA_CMA=y +CONFIG_MHI_BUS=y +CONFIG_MHI_QCOM=y +CONFIG_MHI_NETDEV=y +CONFIG_MHI_UCI=y +CONFIG_MHI_SATELLITE=y +CONFIG_ZRAM=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_LOOP_MIN_COUNT=16 +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_HDCP_QSEECOM=y +CONFIG_QSEECOM=y +CONFIG_UID_SYS_STATS=y +CONFIG_OKL4_USER_VIRQ=y +CONFIG_QTI_XR_SMRTVWR_MISC=y +CONFIG_QTI_MAXIM_FAN_CONTROLLER=y +CONFIG_KINECTICS_XR_NORDIC=y +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_SG=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_UFSHCD=y +CONFIG_SCSI_UFSHCD_PLATFORM=y +CONFIG_SCSI_UFS_QCOM=y +CONFIG_SCSI_UFS_CRYPTO=y +CONFIG_SCSI_UFS_CRYPTO_QTI=y +CONFIG_MD=y +CONFIG_BLK_DEV_DM=y +CONFIG_DM_CRYPT=y +CONFIG_DM_DEFAULT_KEY=y +CONFIG_DM_SNAPSHOT=y +CONFIG_DM_UEVENT=y +CONFIG_DM_VERITY=y +CONFIG_DM_VERITY_FEC=y +CONFIG_DM_BOW=y +CONFIG_NETDEVICES=y +CONFIG_BONDING=y +CONFIG_DUMMY=y +CONFIG_WIREGUARD=y +CONFIG_TUN=y +CONFIG_VETH=y +CONFIG_AQFWD=y +CONFIG_IGB=y +CONFIG_SKY2=y +CONFIG_RMNET=y +CONFIG_SMSC911X=y +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_MPPE=y +CONFIG_PPTP=y +CONFIG_PPPOL2TP=y +CONFIG_USB_RTL8150=y +CONFIG_USB_RTL8152=y +CONFIG_USB_LAN78XX=y +CONFIG_USB_USBNET=y +CONFIG_WCNSS_MEM_PRE_ALLOC=y +CONFIG_CLD_LL_CORE=y +CONFIG_CNSS2=y +CONFIG_CNSS2_QMI=y +CONFIG_CNSS_ASYNC=y +CONFIG_BUS_AUTO_SUSPEND=y +CONFIG_CNSS_GENL=y +CONFIG_INPUT_EVDEV=y +CONFIG_KEYBOARD_GPIO=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_JOYSTICK=y +CONFIG_JOYSTICK_XPAD=y +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +CONFIG_INPUT_TABLET=y +CONFIG_TABLET_USB_ACECAD=y +CONFIG_TABLET_USB_AIPTEK=y +CONFIG_TABLET_USB_GTCO=y +CONFIG_TABLET_USB_HANWANG=y +CONFIG_TABLET_USB_KBTAB=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_FTS=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_QPNP_POWER_ON=y +CONFIG_INPUT_QTI_HAPTICS=y +CONFIG_INPUT_UINPUT=y +# CONFIG_SERIO_SERPORT is not set +# CONFIG_VT is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_DEVMEM is not set +CONFIG_SERIAL_MSM_GENI=y +CONFIG_SERIAL_MSM_GENI_HALF_SAMPLING=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_MSM_LEGACY=y +# CONFIG_DEVPORT is not set +CONFIG_DIAG_CHAR=y +CONFIG_MSM_ADSPRPC=y +CONFIG_OKL4_PIPE=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_QCOM_GENI=y +CONFIG_I3C=y +CONFIG_I3C_MASTER_QCOM_GENI=y +CONFIG_SPI=y +CONFIG_SPI_QCOM_GENI=y +CONFIG_SPI_SPIDEV=y +CONFIG_SPMI=y +CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y +CONFIG_PINCTRL_SX150X=y +CONFIG_PINCTRL_QCOM_SPMI_PMIC=y +CONFIG_PINCTRL_KONA=y +CONFIG_GPIO_SYSFS=y +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_QPNP_FG_GEN4=y +CONFIG_HL6111R=y +CONFIG_THERMAL=y +CONFIG_THERMAL_WRITABLE_TRIPS=y +CONFIG_THERMAL_GOV_USER_SPACE=y +CONFIG_THERMAL_GOV_LOW_LIMITS=y +CONFIG_CPU_THERMAL=y +CONFIG_DEVFREQ_THERMAL=y +CONFIG_QCOM_SPMI_TEMP_ALARM=y +CONFIG_THERMAL_TSENS=y +CONFIG_QTI_ADC_TM=y +CONFIG_QTI_VIRTUAL_SENSOR=y +CONFIG_QTI_QMI_SENSOR=y +CONFIG_QTI_BCL_PMIC5=y +CONFIG_QTI_BCL_SOC_DRIVER=y +CONFIG_QTI_QMI_COOLING_DEVICE=y +CONFIG_QTI_THERMAL_LIMITS_DCVS=y +CONFIG_QTI_CPU_ISOLATE_COOLING_DEVICE=y +CONFIG_QTI_LIMITS_ISENSE_CDSP=y +CONFIG_MFD_I2C_PMIC=y +CONFIG_MFD_SPMI_PMIC=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_PROXY_CONSUMER=y +CONFIG_REGULATOR_QPNP_AMOLED=y +CONFIG_REGULATOR_QPNP_LCDB=y +CONFIG_REGULATOR_REFGEN=y +CONFIG_REGULATOR_RPMH=y +CONFIG_REGULATOR_STUB=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y +CONFIG_MEDIA_RADIO_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +CONFIG_VIDEO_ADV_DEBUG=y +CONFIG_VIDEO_FIXED_MINOR_RANGES=y +CONFIG_MEDIA_USB_SUPPORT=y +CONFIG_USB_VIDEO_CLASS=y +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_MSM_CVP_V4L2=y +CONFIG_MSM_NPU=y +CONFIG_MSM_GLOBAL_SYNX=y +CONFIG_VIDEO_V4L2_VIDEOBUF2_CORE=y +CONFIG_I2C_RTC6226_QCA=y +CONFIG_DRM=y +CONFIG_DRM_LONTIUM_LT9611UXC=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +# CONFIG_LCD_CLASS_DEVICE is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_QCOM_SPMI_WLED=y +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_USB_AUDIO=y +CONFIG_SND_USB_AUDIO_QMI=y +CONFIG_SND_SOC=y +CONFIG_HIDRAW=y +CONFIG_UHID=y +CONFIG_HID_APPLE=y +CONFIG_HID_DRAGONRISE=y +CONFIG_DRAGONRISE_FF=y +CONFIG_HID_ELECOM=y +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MULTITOUCH=y +CONFIG_HID_NINTENDO=y +CONFIG_HID_PANTHERLORD=y +CONFIG_PANTHERLORD_FF=y +CONFIG_HID_PLANTRONICS=y +CONFIG_HID_PLAYSTATION=y +CONFIG_PLAYSTATION_FF=y +CONFIG_HID_SONY=y +CONFIG_SONY_FF=y +CONFIG_HID_STEAM=y +CONFIG_HID_GREENASIA=y +CONFIG_GREENASIA_FF=y +CONFIG_HID_WACOM=y +CONFIG_HID_WIIMOTE=y +CONFIG_USB_HIDDEV=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_ACM=y +CONFIG_USB_STORAGE=y +CONFIG_USB_DWC3=y +CONFIG_USB_DWC3_MSM=y +CONFIG_USB_ISP1760=y +CONFIG_USB_ISP1760_HOST_ROLE=y +CONFIG_USB_SERIAL=y +CONFIG_USB_SERIAL_CP210X=y +CONFIG_USB_SERIAL_FTDI_SIO=y +CONFIG_USB_EHSET_TEST_FIXTURE=y +CONFIG_USB_LINK_LAYER_TEST=y +CONFIG_USB_REDRIVER_NB7VPQ904M=y +CONFIG_NOP_USB_XCEIV=y +CONFIG_USB_MSM_SSPHY_QMP=y +CONFIG_MSM_HSUSB_PHY=y +CONFIG_USB_QCOM_EMU_PHY=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_VBUS_DRAW=900 +CONFIG_USB_CONFIGFS=y +CONFIG_USB_CONFIGFS_UEVENT=y +CONFIG_USB_CONFIGFS_NCM=y +CONFIG_USB_CONFIGFS_MASS_STORAGE=y +CONFIG_USB_CONFIGFS_F_FS=y +CONFIG_USB_CONFIGFS_F_ACC=y +CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y +CONFIG_USB_CONFIGFS_F_UAC1=y +CONFIG_USB_CONFIGFS_F_UAC2=y +CONFIG_USB_CONFIGFS_F_MIDI=y +CONFIG_USB_CONFIGFS_F_HID=y +CONFIG_USB_CONFIGFS_F_UVC=y +CONFIG_USB_CONFIGFS_F_DIAG=y +CONFIG_USB_CONFIGFS_F_CDEV=y +CONFIG_USB_CONFIGFS_F_CCID=y +CONFIG_USB_CONFIGFS_F_QDSS=y +CONFIG_USB_CONFIGFS_F_GSI=y +CONFIG_USB_CONFIGFS_F_MTP=y +CONFIG_USB_CONFIGFS_F_PTP=y +CONFIG_TYPEC=y +CONFIG_USB_PD_POLICY=y +CONFIG_QPNP_USB_PDPHY=y +CONFIG_MMC=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_MSM=y +CONFIG_MMC_CQHCI_CRYPTO=y +CONFIG_MMC_CQHCI_CRYPTO_QTI=y +CONFIG_LEDS_QTI_TRI_LED=y +CONFIG_LEDS_QPNP_FLASH_V2=y +CONFIG_LEDS_TRIGGER_TIMER=y +CONFIG_EDAC=y +CONFIG_EDAC_KRYO_ARM64=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_PM8XXX=y +CONFIG_DMADEVICES=y +CONFIG_QCOM_GPI_DMA=y +CONFIG_UIO=y +CONFIG_STAGING=y +CONFIG_ASHMEM=y +CONFIG_ION=y +CONFIG_ION_POOL_AUTO_REFILL=y +CONFIG_QPNP_REVID=y +CONFIG_SPS=y +CONFIG_SPS_SUPPORT_NDP_BAM=y +CONFIG_GSI_REGISTER_VERSION_2=y +CONFIG_IPA3=y +CONFIG_IPA_WDI_UNIFIED_API=y +CONFIG_RMNET_IPA3=y +CONFIG_RNDIS_IPA=y +CONFIG_IPA3_MHI_PRIME_MANAGER=y +CONFIG_USB_BAM=y +CONFIG_QCOM_GENI_SE=y +CONFIG_IPA3_REGDUMP=y +CONFIG_QCOM_CLK_RPMH=y +CONFIG_SPMI_PMIC_CLKDIV=y +CONFIG_MSM_CLK_AOP_QMP=y +CONFIG_MSM_VIDEOCC_KONA=y +CONFIG_MSM_DISPCC_KONA=y +CONFIG_MSM_CAMCC_KONA=y +CONFIG_MSM_GPUCC_KONA=y +CONFIG_MSM_NPUCC_KONA=y +CONFIG_HWSPINLOCK=y +CONFIG_HWSPINLOCK_QCOM=y +CONFIG_MAILBOX=y +CONFIG_QCOM_APCS_IPC=y +CONFIG_MSM_QMP=y +CONFIG_IOMMU_IO_PGTABLE_FAST=y +CONFIG_ARM_SMMU=y +CONFIG_QCOM_LAZY_MAPPING=y +CONFIG_RPMSG_CHAR=y +CONFIG_RPMSG_QCOM_GLINK_SMEM=y +CONFIG_RPMSG_QCOM_GLINK_SPSS=y +CONFIG_QCOM_COMMAND_DB=y +CONFIG_QCOM_RUN_QUEUE_STATS=y +CONFIG_MSM_QBT_HANDLER=y +CONFIG_QCOM_IPCC=y +CONFIG_QCOM_LLCC=y +CONFIG_QCOM_KONA_LLCC=y +CONFIG_QCOM_MDT_LOADER=y +CONFIG_QPNP_PBS=y +CONFIG_QCOM_QMI_HELPERS=y +CONFIG_QCOM_QMI_RMNET=y +CONFIG_QCOM_QMI_DFC=y +CONFIG_RMNET_CTL=y +CONFIG_QCOM_QMI_POWER_COLLAPSE=y +CONFIG_QCOM_RPMH=y +CONFIG_QCOM_SMEM=y +CONFIG_QCOM_EARLY_RANDOM=y +CONFIG_QCOM_MEMORY_DUMP_V2=y +CONFIG_QCOM_SMP2P=y +CONFIG_SETUP_SSR_NOTIF_TIMEOUTS=y +CONFIG_SSR_SYSMON_NOTIF_TIMEOUT=20000 +CONFIG_SSR_SUBSYS_NOTIF_TIMEOUT=20000 +CONFIG_PANIC_ON_SSR_NOTIF_TIMEOUT=y +CONFIG_QCOM_SECURE_BUFFER=y +CONFIG_MSM_SERVICE_LOCATOR=y +CONFIG_MSM_SERVICE_NOTIFIER=y +CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_PIL=y +CONFIG_MSM_SYSMON_QMI_COMM=y +CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_MSM_BOOT_STATS=y +CONFIG_QCOM_DCC_V2=y +CONFIG_QCOM_EUD=y +CONFIG_QCOM_FSA4480_I2C=y +CONFIG_QCOM_WATCHDOG_V2=y +CONFIG_QCOM_INITIAL_LOGBUF=y +CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y +CONFIG_QCOM_BUS_SCALING=y +CONFIG_QCOM_BUS_CONFIG_RPMH=y +CONFIG_MSM_SPCOM=y +CONFIG_MSM_SPSS_UTILS=y +CONFIG_QSEE_IPC_IRQ_BRIDGE=y +CONFIG_QCOM_GLINK=y +CONFIG_QCOM_GLINK_PKT=y +CONFIG_QCOM_SMP2P_SLEEPSTATE=y +CONFIG_QCOM_QDSS_BRIDGE=y +CONFIG_MSM_CDSP_LOADER=y +CONFIG_QCOM_SMCINVOKE=y +CONFIG_MSM_EVENT_TIMER=y +CONFIG_MSM_PM=y +CONFIG_QTI_RPM_STATS_LOG=y +CONFIG_QTI_DDR_STATS_LOG=y +CONFIG_QTEE_SHM_BRIDGE=y +CONFIG_MSM_PERFORMANCE=y +CONFIG_QCOM_CDSP_RM=y +CONFIG_QCOM_QHEE_ENABLE_MEM_PROTECTION=y +CONFIG_QTI_CRYPTO_COMMON=y +CONFIG_QTI_CRYPTO_TZ=y +CONFIG_DEVFREQ_GOV_PASSIVE=y +CONFIG_QCOM_BIMC_BWMON=y +CONFIG_ARM_MEMLAT_MON=y +CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y +CONFIG_DEVFREQ_GOV_QCOM_CACHE_HWMON=y +CONFIG_DEVFREQ_GOV_MEMLAT=y +CONFIG_DEVFREQ_GOV_CDSPL3=y +CONFIG_ARM_QCOM_DEVFREQ_FW=y +CONFIG_DEVFREQ_SIMPLE_DEV=y +CONFIG_QCOM_DEVFREQ_DEVBW=y +CONFIG_ARM_QCOM_DEVFREQ_QOSLAT=y +CONFIG_DEVFREQ_GOV_STATICMAP=y +CONFIG_EXTCON_USB_GPIO=y +CONFIG_IIO=y +CONFIG_QCOM_SPMI_ADC5=y +CONFIG_CH101_I2C=y +CONFIG_ADS7052_TDK_THERMISTOR=y +CONFIG_PWM=y +CONFIG_PWM_QTI_LPG=y +CONFIG_QCOM_PDC=y +CONFIG_ARM_DSU_PMU=y +CONFIG_QCOM_LLCC_PMU=y +CONFIG_RAS=y +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_BINDERFS=y +CONFIG_ANDROID_VENDOR_HOOKS=y +# CONFIG_NVMEM_SYSFS is not set +CONFIG_QCOM_QFPROM=y +CONFIG_NVMEM_SPMI_SDAM=y +CONFIG_SLIMBUS_MSM_NGD=y +CONFIG_ESOC=y +CONFIG_ESOC_DEV=y +CONFIG_ESOC_CLIENT=y +CONFIG_ESOC_MDM_4x=y +CONFIG_ESOC_MDM_DRV=y +CONFIG_SENSORS_SSC=y +CONFIG_QCOM_KGSL=y +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_F2FS_FS=y +CONFIG_F2FS_FS_SECURITY=y +CONFIG_F2FS_UNFAIR_RWSEM=y +CONFIG_FS_ENCRYPTION=y +CONFIG_FS_ENCRYPTION_INLINE_CRYPT=y +CONFIG_FS_VERITY=y +CONFIG_FS_VERITY_BUILTIN_SIGNATURES=y +CONFIG_QUOTA=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +CONFIG_QFMT_V2=y +CONFIG_FUSE_FS=y +CONFIG_OVERLAY_FS=y +CONFIG_INCREMENTAL_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_SDCARD_FS=y +CONFIG_EROFS_FS=y +CONFIG_EROFS_FS_PCPU_KTHREAD=y +CONFIG_EROFS_FS_PCPU_KTHREAD_HIPRI=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +CONFIG_UNICODE=y +CONFIG_SECURITY=y +CONFIG_SECURITY_NETWORK=y +CONFIG_HARDENED_USERCOPY=y +CONFIG_STATIC_USERMODEHELPER=y +CONFIG_STATIC_USERMODEHELPER_PATH="" +CONFIG_SECURITY_SELINUX=y +CONFIG_INIT_ON_ALLOC_DEFAULT_ON=y +CONFIG_CRYPTO_CCM=y +CONFIG_CRYPTO_GCM=y +CONFIG_CRYPTO_CHACHA20POLY1305=y +CONFIG_CRYPTO_XCBC=y +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_LZ4=y +CONFIG_CRYPTO_ANSI_CPRNG=y +CONFIG_CRYPTO_DRBG_HASH=y +CONFIG_CRYPTO_DRBG_CTR=y +CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y +CONFIG_CRYPTO_DEV_QCRYPTO=y +CONFIG_CRYPTO_DEV_QCEDEV=y +CONFIG_CRYPTO_DEV_QCOM_ICE=y +CONFIG_PRINTK_TIME=y +CONFIG_DEBUG_INFO=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_PANIC_TIMEOUT=-1 +CONFIG_SCHEDSTATS=y +CONFIG_SCHED_STACK_END_CHECK=y +# CONFIG_DEBUG_PREEMPT is not set +CONFIG_IPC_LOGGING=y +CONFIG_BUG_ON_DATA_CORRUPTION=y +CONFIG_CC_WERROR=y +CONFIG_DEBUG_ALIGN_RODATA=y From 8ad689434d063658494e970f8403e0e45ed3d730 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Sun, 2 Apr 2023 12:57:58 +0000 Subject: [PATCH 185/356] ARM64: configs: Initial kona -> sdm845 conversion --- .../configs/vendor/sdm845-perf_defconfig | 99 ++++++------------- 1 file changed, 28 insertions(+), 71 deletions(-) diff --git a/arch/arm64/configs/vendor/sdm845-perf_defconfig b/arch/arm64/configs/vendor/sdm845-perf_defconfig index 14df20c6e974..ac26e71dad63 100644 --- a/arch/arm64/configs/vendor/sdm845-perf_defconfig +++ b/arch/arm64/configs/vendor/sdm845-perf_defconfig @@ -48,7 +48,7 @@ CONFIG_SLAB_FREELIST_HARDENED=y CONFIG_PROFILING=y # CONFIG_ZONE_DMA32 is not set CONFIG_ARCH_QCOM=y -CONFIG_ARCH_KONA=y +CONFIG_ARCH_SDM845=y CONFIG_PCI=y CONFIG_PCI_MSM=y CONFIG_PCI_MSM_MSI=y @@ -68,7 +68,6 @@ CONFIG_RANDOMIZE_BASE=y CONFIG_CMDLINE="cgroup_disable=pressure" CONFIG_CMDLINE_EXTEND=y # CONFIG_EFI is not set -CONFIG_BUILD_ARM64_UNCOMPRESSED_KERNEL=y CONFIG_KRYO_PMU_WORKAROUND=y CONFIG_BUILD_ARM64_DT_OVERLAY=y CONFIG_COMPAT=y @@ -85,7 +84,6 @@ CONFIG_CPU_FREQ_GOV_POWERSAVE=y CONFIG_CPU_FREQ_GOV_USERSPACE=y CONFIG_CPU_BOOST=y CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y -CONFIG_ARM_QCOM_CPUFREQ_HW=y CONFIG_CRYPTO_SHA1_ARM64_CE=y CONFIG_CRYPTO_SHA2_ARM64_CE=y CONFIG_CRYPTO_GHASH_ARM64_CE=y @@ -107,7 +105,6 @@ CONFIG_GKI_HIDDEN_GPU_CONFIGS=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_DEFAULT_MMAP_MIN_ADDR=32768 CONFIG_CMA=y -CONFIG_CMA_AREAS=16 CONFIG_ZSMALLOC=y CONFIG_BALANCE_ANON_FILE_RECLAIM=y CONFIG_HAVE_USERSPACE_LOW_MEMORY_KILLER=y @@ -262,14 +259,11 @@ CONFIG_NET_ACT_SKBEDIT=y CONFIG_NET_ACT_BPF=y CONFIG_QRTR=y CONFIG_QRTR_SMD=y -CONFIG_QRTR_MHI=y CONFIG_BPF_JIT=y CONFIG_SOCKEV_NLMCAST=y -CONFIG_CAN=y -CONFIG_CAN_MCP25XXFD=y CONFIG_BT=y CONFIG_MSM_BT_POWER=y -CONFIG_BT_SLIM_QCA6390=y +CONFIG_BTFM_SLIM_WCN3990=y CONFIG_CFG80211=y CONFIG_CFG80211_INTERNAL_REGDB=y CONFIG_RFKILL=y @@ -279,11 +273,6 @@ CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y # CONFIG_FW_CACHE is not set CONFIG_REGMAP_WCD_IRQ=y CONFIG_DMA_CMA=y -CONFIG_MHI_BUS=y -CONFIG_MHI_QCOM=y -CONFIG_MHI_NETDEV=y -CONFIG_MHI_UCI=y -CONFIG_MHI_SATELLITE=y CONFIG_ZRAM=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_LOOP_MIN_COUNT=16 @@ -292,10 +281,8 @@ CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_HDCP_QSEECOM=y CONFIG_QSEECOM=y CONFIG_UID_SYS_STATS=y +CONFIG_QPNP_MISC=y CONFIG_OKL4_USER_VIRQ=y -CONFIG_QTI_XR_SMRTVWR_MISC=y -CONFIG_QTI_MAXIM_FAN_CONTROLLER=y -CONFIG_KINECTICS_XR_NORDIC=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_SG=y @@ -322,8 +309,6 @@ CONFIG_DUMMY=y CONFIG_WIREGUARD=y CONFIG_TUN=y CONFIG_VETH=y -CONFIG_AQFWD=y -CONFIG_IGB=y CONFIG_SKY2=y CONFIG_RMNET=y CONFIG_SMSC911X=y @@ -339,10 +324,6 @@ CONFIG_USB_LAN78XX=y CONFIG_USB_USBNET=y CONFIG_WCNSS_MEM_PRE_ALLOC=y CONFIG_CLD_LL_CORE=y -CONFIG_CNSS2=y -CONFIG_CNSS2_QMI=y -CONFIG_CNSS_ASYNC=y -CONFIG_BUS_AUTO_SUSPEND=y CONFIG_CNSS_GENL=y CONFIG_INPUT_EVDEV=y CONFIG_KEYBOARD_GPIO=y @@ -368,7 +349,6 @@ CONFIG_INPUT_UINPUT=y # CONFIG_LEGACY_PTYS is not set # CONFIG_DEVMEM is not set CONFIG_SERIAL_MSM_GENI=y -CONFIG_SERIAL_MSM_GENI_HALF_SAMPLING=y CONFIG_HW_RANDOM=y CONFIG_HW_RANDOM_MSM_LEGACY=y # CONFIG_DEVPORT is not set @@ -377,26 +357,20 @@ CONFIG_MSM_ADSPRPC=y CONFIG_OKL4_PIPE=y CONFIG_I2C_CHARDEV=y CONFIG_I2C_QCOM_GENI=y -CONFIG_I3C=y -CONFIG_I3C_MASTER_QCOM_GENI=y CONFIG_SPI=y CONFIG_SPI_QCOM_GENI=y CONFIG_SPI_SPIDEV=y CONFIG_SPMI=y CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y -CONFIG_PINCTRL_SX150X=y CONFIG_PINCTRL_QCOM_SPMI_PMIC=y -CONFIG_PINCTRL_KONA=y +CONFIG_PINCTRL_SDM845=y CONFIG_GPIO_SYSFS=y 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_QPNP_SMB2=y CONFIG_SMB1355_SLAVE_CHARGER=y -CONFIG_QPNP_QNOVO5=y -CONFIG_QPNP_FG_GEN4=y -CONFIG_HL6111R=y +CONFIG_QPNP_FG_GEN3=y CONFIG_THERMAL=y CONFIG_THERMAL_WRITABLE_TRIPS=y CONFIG_THERMAL_GOV_USER_SPACE=y @@ -407,20 +381,18 @@ CONFIG_QCOM_SPMI_TEMP_ALARM=y CONFIG_THERMAL_TSENS=y CONFIG_QTI_ADC_TM=y CONFIG_QTI_VIRTUAL_SENSOR=y -CONFIG_QTI_QMI_SENSOR=y -CONFIG_QTI_BCL_PMIC5=y -CONFIG_QTI_BCL_SOC_DRIVER=y CONFIG_QTI_QMI_COOLING_DEVICE=y CONFIG_QTI_THERMAL_LIMITS_DCVS=y +CONFIG_QTI_AOP_REG_COOLING_DEVICE=y +CONFIG_REGULATOR_COOLING_DEVICE=y +CONFIG_MSM_BCL_PERIPHERAL_CTL=y CONFIG_QTI_CPU_ISOLATE_COOLING_DEVICE=y -CONFIG_QTI_LIMITS_ISENSE_CDSP=y CONFIG_MFD_I2C_PMIC=y CONFIG_MFD_SPMI_PMIC=y CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_PROXY_CONSUMER=y -CONFIG_REGULATOR_QPNP_AMOLED=y -CONFIG_REGULATOR_QPNP_LCDB=y +CONFIG_REGULATOR_QPNP_LABIBB=y CONFIG_REGULATOR_REFGEN=y CONFIG_REGULATOR_RPMH=y CONFIG_REGULATOR_STUB=y @@ -435,13 +407,8 @@ CONFIG_VIDEO_FIXED_MINOR_RANGES=y CONFIG_MEDIA_USB_SUPPORT=y CONFIG_USB_VIDEO_CLASS=y CONFIG_V4L_PLATFORM_DRIVERS=y -CONFIG_MSM_CVP_V4L2=y -CONFIG_MSM_NPU=y -CONFIG_MSM_GLOBAL_SYNX=y CONFIG_VIDEO_V4L2_VIDEOBUF2_CORE=y -CONFIG_I2C_RTC6226_QCA=y CONFIG_DRM=y -CONFIG_DRM_LONTIUM_LT9611UXC=y CONFIG_BACKLIGHT_LCD_SUPPORT=y # CONFIG_LCD_CLASS_DEVICE is not set CONFIG_BACKLIGHT_CLASS_DEVICE=y @@ -452,7 +419,6 @@ CONFIG_SND_DYNAMIC_MINORS=y CONFIG_SND_USB_AUDIO=y CONFIG_SND_USB_AUDIO_QMI=y CONFIG_SND_SOC=y -CONFIG_HIDRAW=y CONFIG_UHID=y CONFIG_HID_APPLE=y CONFIG_HID_DRAGONRISE=y @@ -488,11 +454,9 @@ CONFIG_USB_SERIAL_CP210X=y CONFIG_USB_SERIAL_FTDI_SIO=y CONFIG_USB_EHSET_TEST_FIXTURE=y CONFIG_USB_LINK_LAYER_TEST=y -CONFIG_USB_REDRIVER_NB7VPQ904M=y CONFIG_NOP_USB_XCEIV=y CONFIG_USB_MSM_SSPHY_QMP=y -CONFIG_MSM_HSUSB_PHY=y -CONFIG_USB_QCOM_EMU_PHY=y +CONFIG_MSM_QUSB_PHY=y CONFIG_USB_GADGET=y CONFIG_USB_GADGET_VBUS_DRAW=900 CONFIG_USB_CONFIGFS=y @@ -535,6 +499,7 @@ CONFIG_RTC_DRV_PM8XXX=y CONFIG_DMADEVICES=y CONFIG_QCOM_GPI_DMA=y CONFIG_UIO=y +CONFIG_UIO_MSM_SHAREDMEM=y CONFIG_STAGING=y CONFIG_ASHMEM=y CONFIG_ION=y @@ -542,23 +507,21 @@ CONFIG_ION_POOL_AUTO_REFILL=y CONFIG_QPNP_REVID=y CONFIG_SPS=y CONFIG_SPS_SUPPORT_NDP_BAM=y -CONFIG_GSI_REGISTER_VERSION_2=y CONFIG_IPA3=y CONFIG_IPA_WDI_UNIFIED_API=y CONFIG_RMNET_IPA3=y CONFIG_RNDIS_IPA=y -CONFIG_IPA3_MHI_PRIME_MANAGER=y CONFIG_USB_BAM=y CONFIG_QCOM_GENI_SE=y -CONFIG_IPA3_REGDUMP=y CONFIG_QCOM_CLK_RPMH=y CONFIG_SPMI_PMIC_CLKDIV=y CONFIG_MSM_CLK_AOP_QMP=y -CONFIG_MSM_VIDEOCC_KONA=y -CONFIG_MSM_DISPCC_KONA=y -CONFIG_MSM_CAMCC_KONA=y -CONFIG_MSM_GPUCC_KONA=y -CONFIG_MSM_NPUCC_KONA=y +CONFIG_MSM_GCC_SDM845=y +CONFIG_MSM_VIDEOCC_SDM845=y +CONFIG_MSM_DISPCC_SDM845=y +CONFIG_MSM_CAMCC_SDM845=y +CONFIG_MSM_GPUCC_SDM845=y +CONFIG_CLOCK_CPU_OSM_SDM845=y CONFIG_HWSPINLOCK=y CONFIG_HWSPINLOCK_QCOM=y CONFIG_MAILBOX=y @@ -570,24 +533,22 @@ CONFIG_QCOM_LAZY_MAPPING=y CONFIG_RPMSG_CHAR=y CONFIG_RPMSG_QCOM_GLINK_SMEM=y CONFIG_RPMSG_QCOM_GLINK_SPSS=y +CONFIG_RPMSG_QCOM_GLINK_SPI=y CONFIG_QCOM_COMMAND_DB=y CONFIG_QCOM_RUN_QUEUE_STATS=y -CONFIG_MSM_QBT_HANDLER=y -CONFIG_QCOM_IPCC=y CONFIG_QCOM_LLCC=y -CONFIG_QCOM_KONA_LLCC=y +CONFIG_QCOM_SDM845_LLCC=y CONFIG_QCOM_MDT_LOADER=y -CONFIG_QPNP_PBS=y CONFIG_QCOM_QMI_HELPERS=y CONFIG_QCOM_QMI_RMNET=y CONFIG_QCOM_QMI_DFC=y -CONFIG_RMNET_CTL=y CONFIG_QCOM_QMI_POWER_COLLAPSE=y CONFIG_QCOM_RPMH=y CONFIG_QCOM_SMEM=y CONFIG_QCOM_EARLY_RANDOM=y CONFIG_QCOM_MEMORY_DUMP_V2=y CONFIG_QCOM_SMP2P=y +CONFIG_MSM_PIL_MSS_QDSP6V5=y CONFIG_SETUP_SSR_NOTIF_TIMEOUTS=y CONFIG_SSR_SYSMON_NOTIF_TIMEOUT=20000 CONFIG_SSR_SUBSYS_NOTIF_TIMEOUT=20000 @@ -608,25 +569,25 @@ CONFIG_QCOM_INITIAL_LOGBUF=y CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y CONFIG_QCOM_BUS_SCALING=y CONFIG_QCOM_BUS_CONFIG_RPMH=y -CONFIG_MSM_SPCOM=y +CONFIG_MSM_SPCOM_LEGACY=y CONFIG_MSM_SPSS_UTILS=y CONFIG_QSEE_IPC_IRQ_BRIDGE=y CONFIG_QCOM_GLINK=y CONFIG_QCOM_GLINK_PKT=y CONFIG_QCOM_SMP2P_SLEEPSTATE=y -CONFIG_QCOM_QDSS_BRIDGE=y CONFIG_MSM_CDSP_LOADER=y CONFIG_QCOM_SMCINVOKE=y CONFIG_MSM_EVENT_TIMER=y CONFIG_MSM_PM=y CONFIG_QTI_RPM_STATS_LOG=y -CONFIG_QTI_DDR_STATS_LOG=y CONFIG_QTEE_SHM_BRIDGE=y +CONFIG_MEM_SHARE_QMI_SERVICE=y CONFIG_MSM_PERFORMANCE=y CONFIG_QCOM_CDSP_RM=y -CONFIG_QCOM_QHEE_ENABLE_MEM_PROTECTION=y CONFIG_QTI_CRYPTO_COMMON=y CONFIG_QTI_CRYPTO_TZ=y +CONFIG_ICNSS=y +CONFIG_ICNSS_QMI=y CONFIG_DEVFREQ_GOV_PASSIVE=y CONFIG_QCOM_BIMC_BWMON=y CONFIG_ARM_MEMLAT_MON=y @@ -634,21 +595,16 @@ CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y CONFIG_DEVFREQ_GOV_QCOM_CACHE_HWMON=y CONFIG_DEVFREQ_GOV_MEMLAT=y CONFIG_DEVFREQ_GOV_CDSPL3=y -CONFIG_ARM_QCOM_DEVFREQ_FW=y CONFIG_DEVFREQ_SIMPLE_DEV=y CONFIG_QCOM_DEVFREQ_DEVBW=y -CONFIG_ARM_QCOM_DEVFREQ_QOSLAT=y -CONFIG_DEVFREQ_GOV_STATICMAP=y CONFIG_EXTCON_USB_GPIO=y CONFIG_IIO=y CONFIG_QCOM_SPMI_ADC5=y -CONFIG_CH101_I2C=y -CONFIG_ADS7052_TDK_THERMISTOR=y +CONFIG_QCOM_RRADC=y CONFIG_PWM=y CONFIG_PWM_QTI_LPG=y +CONFIG_ARM_GIC_V3_ACL=y CONFIG_QCOM_PDC=y -CONFIG_ARM_DSU_PMU=y -CONFIG_QCOM_LLCC_PMU=y CONFIG_RAS=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y @@ -665,6 +621,7 @@ CONFIG_ESOC_MDM_4x=y CONFIG_ESOC_MDM_DRV=y CONFIG_SENSORS_SSC=y CONFIG_QCOM_KGSL=y +CONFIG_LEGACY_ENERGY_MODEL_DT=y CONFIG_EXT4_FS=y CONFIG_EXT4_FS_POSIX_ACL=y CONFIG_EXT4_FS_SECURITY=y From 68d1a868bb2984125d3e173d14f1f5088c99ce6d Mon Sep 17 00:00:00 2001 From: MrArtemSid Date: Sun, 31 Oct 2021 23:45:40 +0400 Subject: [PATCH 186/356] defconfig: sdm845-perf: Enable CONFIG_ION_LEGACY --- arch/arm64/configs/vendor/sdm845-perf_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/vendor/sdm845-perf_defconfig b/arch/arm64/configs/vendor/sdm845-perf_defconfig index ac26e71dad63..2daf609ab62c 100644 --- a/arch/arm64/configs/vendor/sdm845-perf_defconfig +++ b/arch/arm64/configs/vendor/sdm845-perf_defconfig @@ -504,6 +504,7 @@ CONFIG_STAGING=y CONFIG_ASHMEM=y CONFIG_ION=y CONFIG_ION_POOL_AUTO_REFILL=y +CONFIG_ION_LEGACY=y CONFIG_QPNP_REVID=y CONFIG_SPS=y CONFIG_SPS_SUPPORT_NDP_BAM=y From ce7bfbc96a46b76d7f2224f916103c7ee1b79109 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Sun, 11 Jun 2023 15:40:18 +0000 Subject: [PATCH 187/356] ARM64: configs: sdm845: Enable legacy vidc driver --- arch/arm64/configs/vendor/sdm845-perf_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/vendor/sdm845-perf_defconfig b/arch/arm64/configs/vendor/sdm845-perf_defconfig index 2daf609ab62c..ae2813b564a0 100644 --- a/arch/arm64/configs/vendor/sdm845-perf_defconfig +++ b/arch/arm64/configs/vendor/sdm845-perf_defconfig @@ -407,6 +407,7 @@ CONFIG_VIDEO_FIXED_MINOR_RANGES=y CONFIG_MEDIA_USB_SUPPORT=y CONFIG_USB_VIDEO_CLASS=y CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_MSM_VIDC_LEGACY_V4L2=y CONFIG_VIDEO_V4L2_VIDEOBUF2_CORE=y CONFIG_DRM=y CONFIG_BACKLIGHT_LCD_SUPPORT=y From cfffce32da3804151f8a7f1beeb9f8e5b14f02ed Mon Sep 17 00:00:00 2001 From: duckyduckg Date: Fri, 13 Jun 2025 13:47:51 +0500 Subject: [PATCH 188/356] ARM64: dts: pm8005: update compatible node to spmi driver also add required temperature threshold. Signed-off-by: duckyduckg --- arch/arm64/boot/dts/qcom/pm8005.dtsi | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/pm8005.dtsi b/arch/arm64/boot/dts/qcom/pm8005.dtsi index a4f8d99c134a..ca974db9053c 100644 --- a/arch/arm64/boot/dts/qcom/pm8005.dtsi +++ b/arch/arm64/boot/dts/qcom/pm8005.dtsi @@ -3,8 +3,11 @@ * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. */ -#include #include +#include +#include +#include +#include &spmi_bus { qcom,pm8005@4 { @@ -19,11 +22,12 @@ }; pm8005_tz: qcom,temp-alarm@2400 { - compatible = "qcom,qpnp-temp-alarm"; + compatible = "qcom,spmi-temp-alarm"; reg = <0x2400 0x100>; interrupts = <0x4 0x24 0x0 IRQ_TYPE_EDGE_RISING>; label = "pm8005_tz"; #thermal-sensor-cells = <0>; + qcom,temperature-threshold-set = <1>; }; pm8005_gpios: pinctrl@c000 { From 0c82353d2a23ffa6779805dee49edeb2b48b6526 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Sat, 16 Aug 2025 15:51:52 +0000 Subject: [PATCH 189/356] ARM64: dts: sdm845: Kang SDE UBWC props from lagoon --- arch/arm64/boot/dts/qcom/sdm845-sde.dtsi | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi index 1c3c090dc098..46ed48b27e87 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi @@ -130,6 +130,9 @@ qcom,sde-mixer-blendstages = <0xb>; qcom,sde-highest-bank-bit = <0x2>; qcom,sde-ubwc-version = <0x200>; + qcom,sde-ubwc-swizzle = <0x6>; + qcom,sde-ubwc-bw-calc-version = <0x1>; + qcom,sde-ubwc-static = <0x1e>; qcom,sde-smart-panel-align-mode = <0xc>; qcom,sde-panic-per-pipe; qcom,sde-has-cdp; From e76910d05d1538721f78fb41ab4aee475f23656c Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Sun, 17 Aug 2025 16:11:00 +0000 Subject: [PATCH 190/356] ARM64: dts: pmi8998: Use the correct name for the tri-led node --- arch/arm64/boot/dts/qcom/pmi8998.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/pmi8998.dtsi b/arch/arm64/boot/dts/qcom/pmi8998.dtsi index 76c77f16056f..1b7efd5c51ba 100644 --- a/arch/arm64/boot/dts/qcom/pmi8998.dtsi +++ b/arch/arm64/boot/dts/qcom/pmi8998.dtsi @@ -418,7 +418,7 @@ }; }; - pmi8998_rgb_led: qcom,pwms@d000 { + pmi8998_rgb_led: qcom,leds@d000 { compatible = "qcom,tri-led"; reg = <0xd000 0x100>; From d6b476a2d4c78cfb758e0b4f4f0ad4f89ce48d6c Mon Sep 17 00:00:00 2001 From: duckyduckG Date: Tue, 7 Oct 2025 18:37:31 +0500 Subject: [PATCH 191/356] thermal: qcom: adc-tm5: add static number of channels NOTE: This change is not by me but from Pavel Dubrova. * pm8998 does not support reading channels thus define static 8 channels. --- drivers/thermal/qcom/adc-tm5.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/thermal/qcom/adc-tm5.c b/drivers/thermal/qcom/adc-tm5.c index c66f6c087db7..a0caa98e4653 100644 --- a/drivers/thermal/qcom/adc-tm5.c +++ b/drivers/thermal/qcom/adc-tm5.c @@ -63,6 +63,10 @@ #define ADC_TM_Mn_DATA1(n) ((n * 2) + 0xa1) #define ADC_TM_DATA_SHIFT 8 +#if defined(CONFIG_ARCH_SDM845) +#define ADC_TM_NUM_CHANNELS 8 +#endif + static struct adc_tm_trip_reg_type adc_tm_ch_data[] = { [ADC_TM_CHAN0] = {ADC_TM_M0_ADC_CH_SEL_CTL}, [ADC_TM_CHAN1] = {ADC_TM_M1_ADC_CH_SEL_CTL}, @@ -1054,7 +1058,11 @@ static int adc_tm5_init(struct adc_tm_chip *chip, uint32_t dt_chans) return ret; } +#if !defined(CONFIG_ARCH_SDM845) if (dt_chans > channels_available) { +#else + if (dt_chans > ADC_TM_NUM_CHANNELS) { +#endif pr_err("More nodes than channels supported:%d\n", channels_available); return -EINVAL; From 36cbdf4d8cecaebb99490c81ee2fa9c76d594922 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Sun, 17 Oct 2021 18:34:01 -0400 Subject: [PATCH 192/356] thermal: bcl_peripheral: Get battery percentage from bms --- drivers/thermal/qcom/bcl_peripheral.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/thermal/qcom/bcl_peripheral.c b/drivers/thermal/qcom/bcl_peripheral.c index a9cf4f5e1155..432c1abd58dd 100644 --- a/drivers/thermal/qcom/bcl_peripheral.c +++ b/drivers/thermal/qcom/bcl_peripheral.c @@ -514,7 +514,7 @@ static int bcl_read_soc(void *data, int *val) *val = 100; if (!batt_psy) - batt_psy = power_supply_get_by_name("battery"); + batt_psy = power_supply_get_by_name("bms"); if (batt_psy) { err = power_supply_get_property(batt_psy, POWER_SUPPLY_PROP_CAPACITY, &ret); @@ -559,7 +559,7 @@ static int battery_supply_callback(struct notifier_block *nb, { struct power_supply *psy = data; - if (strcmp(psy->desc->name, "battery")) + if (strcmp(psy->desc->name, "bms")) return NOTIFY_OK; schedule_work(&bcl_perph->soc_eval_work); From 4cbe7102c7d48b6d8addb522ec0a431c8edb60b1 Mon Sep 17 00:00:00 2001 From: duckyduckG Date: Tue, 7 Oct 2025 21:58:53 +0500 Subject: [PATCH 193/356] power: qcom: supply: add qnovo driver from msm 4.9 as of 'commit <3dc939306eff6f2acad430c60022bde944362ef9> ("power: qpnp-qnovo: Enable auto FG ESR extraction in CV charging")' also class_attrs is deprecated so update it for kernel 4.19 --- .../bindings/power/supply/qcom/qpnp-qnovo.txt | 33 + drivers/power/supply/qcom/Kconfig | 9 + drivers/power/supply/qcom/Makefile | 1 + drivers/power/supply/qcom/qpnp-qnovo.c | 1817 +++++++++++++++++ 4 files changed, 1860 insertions(+) create mode 100644 arch/arm64/boot/dts/vendor/bindings/power/supply/qcom/qpnp-qnovo.txt create mode 100644 drivers/power/supply/qcom/qpnp-qnovo.c diff --git a/arch/arm64/boot/dts/vendor/bindings/power/supply/qcom/qpnp-qnovo.txt b/arch/arm64/boot/dts/vendor/bindings/power/supply/qcom/qpnp-qnovo.txt new file mode 100644 index 000000000000..8f35e56816ce --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/power/supply/qcom/qpnp-qnovo.txt @@ -0,0 +1,33 @@ +QPNP Qnovo pulse engine + +QPNP Qnovo is a pulse charging engine which works in tandem with the QPNP SMB2 +Charger device. It configures the QPNP SMB2 charger to charge/discharge as per +pulse characteristics. + +The QPNP Qnovo pulse engine has a single peripheral assigned to it. + +Required properties: +- compatible: Must be "qcom,qpnp-qnovo" +- qcom,pmic-revid: Should specify the phandle of PMIC + revid module. This is used to identify + the PMIC subtype. + +- reg: The address for this peripheral +- interrupts: Specifies the interrupt associated with the peripheral. +- interrupt-names: Specifies the interrupt name for the peripheral. Qnovo + peripheral has only one interrupt "ptrain-done". + +Optional Properties: +- qcom,external-rsense: To indicate whether the platform uses external or + internal rsense for measuring battery current. +- qcom,enable-for-dc: To enable qnovo for dc charging path. + +Example: + + qcom,qpnp-qnovo@1500 { + compatible = "qcom,qpnp-qnovo"; + reg = <0x1500 0x100>; + interrupts = <0x2 0x15 0x0 IRQ_TYPE_NONE>; + interrupt-names = "ptrain-done"; + qcom,pmic-revid = <&pmi8998_revid>; + }; diff --git a/drivers/power/supply/qcom/Kconfig b/drivers/power/supply/qcom/Kconfig index 9581455fc4d2..b6671064abcc 100644 --- a/drivers/power/supply/qcom/Kconfig +++ b/drivers/power/supply/qcom/Kconfig @@ -113,6 +113,15 @@ config SMB1355_SLAVE_CHARGER The driver reports the charger status via the power supply framework. A charger status change triggers an IRQ via the device STAT pin. +config QPNP_QNOVO + bool "QPNP QNOVO driver" + depends on MFD_SPMI_PMIC + help + Say Y here to enable the Qnovo pulse charging engine. Qnovo driver + accepts pulse parameters via sysfs entries and programs the hardware + module. It also allows userspace code to read diagnostics of voltage + and current measured during certain phases of the pulses. + config QPNP_QNOVO5 bool "QPNP QNOVO5 driver" depends on MFD_SPMI_PMIC diff --git a/drivers/power/supply/qcom/Makefile b/drivers/power/supply/qcom/Makefile index b9cc5e6b00f2..dac497096c5a 100644 --- a/drivers/power/supply/qcom/Makefile +++ b/drivers/power/supply/qcom/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_SMB1351_USB_CHARGER) += smb1351-charger.o pmic-voter.o battery.o obj-$(CONFIG_QPNP_SMB2) += step-chg-jeita.o battery.o qpnp-smb2.o smb-lib.o pmic-voter.o storm-watch.o obj-$(CONFIG_SMB138X_CHARGER) += step-chg-jeita.o smb138x-charger.o smb-lib.o pmic-voter.o storm-watch.o battery.o obj-$(CONFIG_QPNP_FG_GEN3) += qpnp-fg-gen3.o fg-memif.o fg-util.o +obj-$(CONFIG_QPNP_QNOVO) += qpnp-qnovo.o battery.o pmic-voter.o obj-$(CONFIG_QPNP_QNOVO5) += qpnp-qnovo5.o battery.o pmic-voter.o obj-$(CONFIG_QPNP_FG_GEN4) += qpnp-fg-gen4.o fg-memif.o fg-util.o fg-alg.o pmic-voter.o obj-$(CONFIG_QPNP_QG) += qpnp-qg.o pmic-voter.o qg-util.o qg-soc.o qg-sdam.o qg-battery-profile.o qg-profile-lib.o fg-alg.o diff --git a/drivers/power/supply/qcom/qpnp-qnovo.c b/drivers/power/supply/qcom/qpnp-qnovo.c new file mode 100644 index 000000000000..10875c2b7016 --- /dev/null +++ b/drivers/power/supply/qcom/qpnp-qnovo.c @@ -0,0 +1,1817 @@ +/* Copyright (c) 2016-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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define QNOVO_REVISION1 0x00 +#define QNOVO_REVISION2 0x01 +#define QNOVO_PERPH_TYPE 0x04 +#define QNOVO_PERPH_SUBTYPE 0x05 +#define QNOVO_PTTIME_STS 0x07 +#define QNOVO_PTRAIN_STS 0x08 +#define QNOVO_ERROR_STS 0x09 +#define QNOVO_ERROR_BIT BIT(0) +#define QNOVO_ERROR_STS2 0x0A +#define QNOVO_ERROR_CHARGING_DISABLED BIT(1) +#define QNOVO_INT_RT_STS 0x10 +#define QNOVO_INT_SET_TYPE 0x11 +#define QNOVO_INT_POLARITY_HIGH 0x12 +#define QNOVO_INT_POLARITY_LOW 0x13 +#define QNOVO_INT_LATCHED_CLR 0x14 +#define QNOVO_INT_EN_SET 0x15 +#define QNOVO_INT_EN_CLR 0x16 +#define QNOVO_INT_LATCHED_STS 0x18 +#define QNOVO_INT_PENDING_STS 0x19 +#define QNOVO_INT_MID_SEL 0x1A +#define QNOVO_INT_PRIORITY 0x1B +#define QNOVO_PE_CTRL 0x40 +#define QNOVO_PREST1_CTRL 0x41 +#define QNOVO_PPULS1_LSB_CTRL 0x42 +#define QNOVO_PPULS1_MSB_CTRL 0x43 +#define QNOVO_NREST1_CTRL 0x44 +#define QNOVO_NPULS1_CTRL 0x45 +#define QNOVO_PPCNT_CTRL 0x46 +#define QNOVO_VLIM1_LSB_CTRL 0x47 +#define QNOVO_VLIM1_MSB_CTRL 0x48 +#define QNOVO_PTRAIN_EN 0x49 +#define QNOVO_PTRAIN_EN_BIT BIT(0) +#define QNOVO_PE_CTRL2 0x4A +#define QNOVO_PREST2_LSB_CTRL 0x50 +#define QNOVO_PREST2_MSB_CTRL 0x51 +#define QNOVO_PPULS2_LSB_CTRL 0x52 +#define QNOVO_PPULS2_MSB_CTRL 0x53 +#define QNOVO_NREST2_CTRL 0x54 +#define QNOVO_NPULS2_CTRL 0x55 +#define QNOVO_VLIM2_LSB_CTRL 0x56 +#define QNOVO_VLIM2_MSB_CTRL 0x57 +#define QNOVO_PVOLT1_LSB 0x60 +#define QNOVO_PVOLT1_MSB 0x61 +#define QNOVO_PCUR1_LSB 0x62 +#define QNOVO_PCUR1_MSB 0x63 +#define QNOVO_PVOLT2_LSB 0x70 +#define QNOVO_PVOLT2_MSB 0x71 +#define QNOVO_RVOLT2_LSB 0x72 +#define QNOVO_RVOLT2_MSB 0x73 +#define QNOVO_PCUR2_LSB 0x74 +#define QNOVO_PCUR2_MSB 0x75 +#define QNOVO_SCNT 0x80 +#define QNOVO_VMAX_LSB 0x90 +#define QNOVO_VMAX_MSB 0x91 +#define QNOVO_SNUM 0x92 + +/* Registers ending in 0 imply external rsense */ +#define QNOVO_IADC_OFFSET_0 0xA0 +#define QNOVO_IADC_OFFSET_1 0xA1 +#define QNOVO_IADC_GAIN_0 0xA2 +#define QNOVO_IADC_GAIN_1 0xA3 +#define QNOVO_VADC_OFFSET 0xA4 +#define QNOVO_VADC_GAIN 0xA5 +#define QNOVO_IADC_GAIN_2 0xA6 +#define QNOVO_SPARE 0xA7 +#define QNOVO_STRM_CTRL 0xA8 +#define QNOVO_IADC_OFFSET_OVR_VAL 0xA9 +#define QNOVO_IADC_OFFSET_OVR 0xAA + +#define QNOVO_DISABLE_CHARGING 0xAB +#define ERR_SWITCHER_DISABLED BIT(7) +#define ERR_JEITA_SOFT_CONDITION BIT(6) +#define ERR_BAT_OV BIT(5) +#define ERR_CV_MODE BIT(4) +#define ERR_BATTERY_MISSING BIT(3) +#define ERR_SAFETY_TIMER_EXPIRED BIT(2) +#define ERR_CHARGING_DISABLED BIT(1) +#define ERR_JEITA_HARD_CONDITION BIT(0) + +#define QNOVO_TR_IADC_OFFSET_0 0xF1 +#define QNOVO_TR_IADC_OFFSET_1 0xF2 + +#define DRV_MAJOR_VERSION 1 +#define DRV_MINOR_VERSION 0 + +#define IADC_LSB_NA 2441400 +#define VADC_LSB_NA 1220700 +#define GAIN_LSB_FACTOR 976560 + +#define USER_VOTER "user_voter" +#define SHUTDOWN_VOTER "user_voter" +#define OK_TO_QNOVO_VOTER "ok_to_qnovo_voter" + +#define QNOVO_VOTER "qnovo_voter" +#define FG_AVAILABLE_VOTER "FG_AVAILABLE_VOTER" +#define QNOVO_OVERALL_VOTER "QNOVO_OVERALL_VOTER" +#define QNI_PT_VOTER "QNI_PT_VOTER" +#define ESR_VOTER "ESR_VOTER" + +#define HW_OK_TO_QNOVO_VOTER "HW_OK_TO_QNOVO_VOTER" +#define CHG_READY_VOTER "CHG_READY_VOTER" +#define USB_READY_VOTER "USB_READY_VOTER" +#define DC_READY_VOTER "DC_READY_VOTER" + +#define PT_RESTART_VOTER "PT_RESTART_VOTER" +#define REG_WRITE_VOTER "REG_WRITE_VOTER" + +#define CLASS_ATTR_IDX_RO(_name, _func) \ +static ssize_t _name##_show(struct class *c, struct class_attribute *attr, \ + char *ubuf) \ +{ \ + return _func##_show(c, attr, ubuf); \ +}; \ +static CLASS_ATTR_RO(_name) + +#define CLASS_ATTR_IDX_RW(_name, _func) \ +static ssize_t _name##_show(struct class *c, struct class_attribute *attr, \ + char *ubuf) \ +{ \ + return _func##_show(c, attr, ubuf); \ +}; \ +static ssize_t _name##_store(struct class *c, struct class_attribute *attr, \ + const char *ubuf, size_t count) \ +{ \ + return _func##_store(c, attr, ubuf, count); \ +}; \ +static CLASS_ATTR_RW(_name) + +struct qnovo_dt_props { + bool external_rsense; + struct device_node *revid_dev_node; + bool enable_for_dc; +}; + +struct qnovo { + int base; + struct mutex write_lock; + struct regmap *regmap; + struct qnovo_dt_props dt; + struct device *dev; + struct votable *disable_votable; + struct votable *pt_dis_votable; + struct votable *not_ok_to_qnovo_votable; + struct votable *chg_ready_votable; + struct votable *awake_votable; + struct votable *auto_esr_votable; + struct class qnovo_class; + struct pmic_revid_data *pmic_rev_id; + u32 wa_flags; + s64 external_offset_nA; + s64 internal_offset_nA; + s64 offset_nV; + s64 external_i_gain_mega; + s64 internal_i_gain_mega; + s64 v_gain_mega; + struct notifier_block nb; + struct power_supply *batt_psy; + struct power_supply *bms_psy; + struct power_supply *usb_psy; + struct power_supply *dc_psy; + struct work_struct status_change_work; + int fv_uV_request; + int fcc_uA_request; + int usb_present; + int dc_present; + struct delayed_work usb_debounce_work; + struct delayed_work dc_debounce_work; + + struct delayed_work ptrain_restart_work; +}; + +static int debug_mask; +module_param_named(debug_mask, debug_mask, int, 0600); + +#define qnovo_dbg(chip, reason, fmt, ...) \ + do { \ + if (debug_mask & (reason)) \ + dev_info(chip->dev, fmt, ##__VA_ARGS__); \ + else \ + dev_dbg(chip->dev, fmt, ##__VA_ARGS__); \ + } while (0) + +static bool is_secure(struct qnovo *chip, int addr) +{ + /* assume everything above 0x40 is secure */ + return (bool)(addr >= 0x40); +} + +static int qnovo_read(struct qnovo *chip, u16 addr, u8 *buf, int len) +{ + return regmap_bulk_read(chip->regmap, chip->base + addr, buf, len); +} + +static int qnovo_masked_write(struct qnovo *chip, u16 addr, u8 mask, u8 val) +{ + int rc = 0; + + mutex_lock(&chip->write_lock); + if (is_secure(chip, addr)) { + rc = regmap_write(chip->regmap, + ((chip->base + addr) & ~(0xFF)) | 0xD0, 0xA5); + if (rc < 0) + goto unlock; + } + + rc = regmap_update_bits(chip->regmap, chip->base + addr, mask, val); + +unlock: + mutex_unlock(&chip->write_lock); + return rc; +} + +static int qnovo_write(struct qnovo *chip, u16 addr, u8 *buf, int len) +{ + int i, rc = 0; + bool is_start_secure, is_end_secure; + + is_start_secure = is_secure(chip, addr); + is_end_secure = is_secure(chip, addr + len); + + if (!is_start_secure && !is_end_secure) { + mutex_lock(&chip->write_lock); + rc = regmap_bulk_write(chip->regmap, chip->base + addr, + buf, len); + goto unlock; + } + + mutex_lock(&chip->write_lock); + for (i = addr; i < addr + len; i++) { + if (is_secure(chip, i)) { + rc = regmap_write(chip->regmap, + ((chip->base + i) & ~(0xFF)) | 0xD0, 0xA5); + if (rc < 0) + goto unlock; + } + rc = regmap_write(chip->regmap, chip->base + i, buf[i - addr]); + if (rc < 0) + goto unlock; + } + +unlock: + mutex_unlock(&chip->write_lock); + return rc; +} + +static bool is_batt_available(struct qnovo *chip) +{ + if (!chip->batt_psy) + chip->batt_psy = power_supply_get_by_name("battery"); + + if (!chip->batt_psy) + return false; + + return true; +} + +static bool is_fg_available(struct qnovo *chip) +{ + if (!chip->bms_psy) + chip->bms_psy = power_supply_get_by_name("bms"); + + if (!chip->bms_psy) + return false; + + return true; +} + +static bool is_usb_available(struct qnovo *chip) +{ + if (!chip->usb_psy) + chip->usb_psy = power_supply_get_by_name("usb"); + + if (!chip->usb_psy) + return false; + + return true; +} + +static bool is_dc_available(struct qnovo *chip) +{ + if (!chip->dc_psy) + chip->dc_psy = power_supply_get_by_name("dc"); + + if (!chip->dc_psy) + return false; + + return true; +} + +static int qnovo_batt_psy_update(struct qnovo *chip, bool disable) +{ + union power_supply_propval pval = {0}; + int rc = 0; + + if (!is_batt_available(chip)) + return -EINVAL; + + if (chip->fv_uV_request != -EINVAL) { + pval.intval = disable ? -EINVAL : chip->fv_uV_request; + rc = power_supply_set_property(chip->batt_psy, + POWER_SUPPLY_PROP_VOLTAGE_QNOVO, + &pval); + if (rc < 0) { + pr_err("Couldn't set prop qnovo_fv rc = %d\n", rc); + return -EINVAL; + } + } + + if (chip->fcc_uA_request != -EINVAL) { + pval.intval = disable ? -EINVAL : chip->fcc_uA_request; + rc = power_supply_set_property(chip->batt_psy, + POWER_SUPPLY_PROP_CURRENT_QNOVO, + &pval); + if (rc < 0) { + pr_err("Couldn't set prop qnovo_fcc rc = %d\n", rc); + return -EINVAL; + } + } + + return rc; +} + +static int qnovo_disable_cb(struct votable *votable, void *data, int disable, + const char *client) +{ + struct qnovo *chip = data; + union power_supply_propval pval = {0}; + int rc; + + if (!is_batt_available(chip)) + return -EINVAL; + + pval.intval = !disable; + rc = power_supply_set_property(chip->batt_psy, + POWER_SUPPLY_PROP_CHARGE_QNOVO_ENABLE, + &pval); + if (rc < 0) { + pr_err("Couldn't set prop qnovo_enable rc = %d\n", rc); + return -EINVAL; + } + + vote(chip->auto_esr_votable, QNOVO_OVERALL_VOTER, disable, 0); + + vote(chip->pt_dis_votable, QNOVO_OVERALL_VOTER, disable, 0); + rc = qnovo_batt_psy_update(chip, disable); + return rc; +} + +static int pt_dis_votable_cb(struct votable *votable, void *data, int disable, + const char *client) +{ + struct qnovo *chip = data; + int rc; + + if (disable) { + cancel_delayed_work_sync(&chip->ptrain_restart_work); + vote(chip->awake_votable, PT_RESTART_VOTER, false, 0); + } + + rc = qnovo_masked_write(chip, QNOVO_PTRAIN_EN, QNOVO_PTRAIN_EN_BIT, + (bool)disable ? 0 : QNOVO_PTRAIN_EN_BIT); + if (rc < 0) { + dev_err(chip->dev, "Couldn't %s pulse train rc=%d\n", + (bool)disable ? "disable" : "enable", rc); + return rc; + } + + if (!disable) { + vote(chip->awake_votable, PT_RESTART_VOTER, true, 0); + schedule_delayed_work(&chip->ptrain_restart_work, + msecs_to_jiffies(20)); + } + + return 0; +} + +static int not_ok_to_qnovo_cb(struct votable *votable, void *data, + int not_ok_to_qnovo, + const char *client) +{ + struct qnovo *chip = data; + + vote(chip->disable_votable, OK_TO_QNOVO_VOTER, not_ok_to_qnovo, 0); + if (not_ok_to_qnovo) + vote(chip->disable_votable, USER_VOTER, true, 0); + + kobject_uevent(&chip->dev->kobj, KOBJ_CHANGE); + return 0; +} + +static int chg_ready_cb(struct votable *votable, void *data, int ready, + const char *client) +{ + struct qnovo *chip = data; + + vote(chip->not_ok_to_qnovo_votable, CHG_READY_VOTER, !ready, 0); + + return 0; +} + +static int awake_cb(struct votable *votable, void *data, int awake, + const char *client) +{ + struct qnovo *chip = data; + + if (awake) + pm_stay_awake(chip->dev); + else + pm_relax(chip->dev); + + return 0; +} + +static int auto_esr_cb(struct votable *votable, void *data, int auto_esr, + const char *client) +{ + struct qnovo *chip = data; + union power_supply_propval pval = {0}; + + pval.intval = !auto_esr; + if (is_fg_available(chip)) + power_supply_set_property(chip->bms_psy, + POWER_SUPPLY_PROP_CHARGE_QNOVO_ENABLE, + &pval); + + return 0; +} + +static void pe_ctrl2_write_cb(struct qnovo *chip, u8 *val) +{ + if (get_effective_result(chip->disable_votable) == 0) + vote(chip->auto_esr_votable, REG_WRITE_VOTER, (*val == 0), 0); +} + +static int qnovo_parse_dt(struct qnovo *chip) +{ + struct device_node *node = chip->dev->of_node; + int rc; + + if (!node) { + pr_err("device tree node missing\n"); + return -EINVAL; + } + + rc = of_property_read_u32(node, "reg", &chip->base); + if (rc < 0) { + pr_err("Couldn't read base rc = %d\n", rc); + return rc; + } + + chip->dt.external_rsense = of_property_read_bool(node, + "qcom,external-rsense"); + + chip->dt.revid_dev_node = of_parse_phandle(node, "qcom,pmic-revid", 0); + if (!chip->dt.revid_dev_node) { + pr_err("Missing qcom,pmic-revid property - driver failed\n"); + return -EINVAL; + } + chip->dt.enable_for_dc = of_property_read_bool(node, + "qcom,enable-for-dc"); + + return 0; +} + +enum { + VER = 0, + OK_TO_QNOVO, + QNOVO_ENABLE, + PT_ENABLE, + FV_REQUEST, + FCC_REQUEST, + PE_CTRL_REG, + PE_CTRL2_REG, + PTRAIN_STS_REG, + INT_RT_STS_REG, + ERR_STS2_REG, + PREST1, + PPULS1, + NREST1, + NPULS1, + PPCNT, + VLIM1, + PVOLT1, + PCUR1, + PTTIME, + PREST2, + PPULS2, + NREST2, + NPULS2, + VLIM2, + PVOLT2, + RVOLT2, + PCUR2, + SCNT, + VMAX, + SNUM, + VBATT, + IBATT, + BATTTEMP, + BATTSOC, +}; + +struct param_info { + char *name; + int start_addr; + int num_regs; + int reg_to_unit_multiplier; + int reg_to_unit_divider; + int reg_to_unit_offset; + int min_val; + int max_val; + void (*callback)(struct qnovo *chip, u8 *val); + char *units_str; +}; + +static struct param_info params[] = { + [PT_ENABLE] = { + .name = "PT_ENABLE", + .start_addr = QNOVO_PTRAIN_EN, + .num_regs = 1, + .units_str = "", + }, + [FV_REQUEST] = { + .units_str = "uV", + }, + [FCC_REQUEST] = { + .units_str = "uA", + }, + [PE_CTRL_REG] = { + .name = "CTRL_REG", + .start_addr = QNOVO_PE_CTRL, + .num_regs = 1, + .units_str = "", + }, + [PE_CTRL2_REG] = { + .name = "PE_CTRL2_REG", + .start_addr = QNOVO_PE_CTRL2, + .num_regs = 1, + .callback = pe_ctrl2_write_cb, + .units_str = "", + }, + [PTRAIN_STS_REG] = { + .name = "PTRAIN_STS", + .start_addr = QNOVO_PTRAIN_STS, + .num_regs = 1, + .units_str = "", + }, + [INT_RT_STS_REG] = { + .name = "INT_RT_STS", + .start_addr = QNOVO_INT_RT_STS, + .num_regs = 1, + .units_str = "", + }, + [ERR_STS2_REG] = { + .name = "RAW_CHGR_ERR", + .start_addr = QNOVO_ERROR_STS2, + .num_regs = 1, + .units_str = "", + }, + [PREST1] = { + .name = "PREST1", + .start_addr = QNOVO_PREST1_CTRL, + .num_regs = 1, + .reg_to_unit_multiplier = 5, + .reg_to_unit_divider = 1, + .min_val = 5, + .max_val = 255, + .units_str = "mS", + }, + [PPULS1] = { + .name = "PPULS1", + .start_addr = QNOVO_PPULS1_LSB_CTRL, + .num_regs = 2, + .reg_to_unit_multiplier = 1600, /* converts to uC */ + .reg_to_unit_divider = 1, + .min_val = 30000, + .max_val = 65535000, + .units_str = "uC", + }, + [NREST1] = { + .name = "NREST1", + .start_addr = QNOVO_NREST1_CTRL, + .num_regs = 1, + .reg_to_unit_multiplier = 5, + .reg_to_unit_divider = 1, + .min_val = 5, + .max_val = 255, + .units_str = "mS", + }, + [NPULS1] = { + .name = "NPULS1", + .start_addr = QNOVO_NPULS1_CTRL, + .num_regs = 1, + .reg_to_unit_multiplier = 5, + .reg_to_unit_divider = 1, + .min_val = 0, + .max_val = 255, + .units_str = "mS", + }, + [PPCNT] = { + .name = "PPCNT", + .start_addr = QNOVO_PPCNT_CTRL, + .num_regs = 1, + .reg_to_unit_multiplier = 1, + .reg_to_unit_divider = 1, + .min_val = 1, + .max_val = 255, + .units_str = "pulses", + }, + [VLIM1] = { + .name = "VLIM1", + .start_addr = QNOVO_VLIM1_LSB_CTRL, + .num_regs = 2, + .reg_to_unit_multiplier = 610350, /* converts to nV */ + .reg_to_unit_divider = 1, + .min_val = 2200000, + .max_val = 4500000, + .units_str = "uV", + }, + [PVOLT1] = { + .name = "PVOLT1", + .start_addr = QNOVO_PVOLT1_LSB, + .num_regs = 2, + .reg_to_unit_multiplier = 610350, /* converts to nV */ + .reg_to_unit_divider = 1, + .units_str = "uV", + }, + [PCUR1] = { + .name = "PCUR1", + .start_addr = QNOVO_PCUR1_LSB, + .num_regs = 2, + .reg_to_unit_multiplier = 1220700, /* converts to nA */ + .reg_to_unit_divider = 1, + .units_str = "uA", + }, + [PTTIME] = { + .name = "PTTIME", + .start_addr = QNOVO_PTTIME_STS, + .num_regs = 1, + .reg_to_unit_multiplier = 2, + .reg_to_unit_divider = 1, + .units_str = "S", + }, + [PREST2] = { + .name = "PREST2", + .start_addr = QNOVO_PREST2_LSB_CTRL, + .num_regs = 2, + .reg_to_unit_multiplier = 5, + .reg_to_unit_divider = 1, + .min_val = 5, + .max_val = 65535, + .units_str = "mS", + }, + [PPULS2] = { + .name = "PPULS2", + .start_addr = QNOVO_PPULS2_LSB_CTRL, + .num_regs = 2, + .reg_to_unit_multiplier = 1600, /* converts to uC */ + .reg_to_unit_divider = 1, + .min_val = 30000, + .max_val = 65535000, + .units_str = "uC", + }, + [NREST2] = { + .name = "NREST2", + .start_addr = QNOVO_NREST2_CTRL, + .num_regs = 1, + .reg_to_unit_multiplier = 5, + .reg_to_unit_divider = 1, + .reg_to_unit_offset = -5, + .min_val = 5, + .max_val = 255, + .units_str = "mS", + }, + [NPULS2] = { + .name = "NPULS2", + .start_addr = QNOVO_NPULS2_CTRL, + .num_regs = 1, + .reg_to_unit_multiplier = 5, + .reg_to_unit_divider = 1, + .min_val = 0, + .max_val = 255, + .units_str = "mS", + }, + [VLIM2] = { + .name = "VLIM2", + .start_addr = QNOVO_VLIM2_LSB_CTRL, + .num_regs = 2, + .reg_to_unit_multiplier = 610350, /* converts to nV */ + .reg_to_unit_divider = 1, + .min_val = 2200000, + .max_val = 4500000, + .units_str = "uV", + }, + [PVOLT2] = { + .name = "PVOLT2", + .start_addr = QNOVO_PVOLT2_LSB, + .num_regs = 2, + .reg_to_unit_multiplier = 610350, /* converts to nV */ + .reg_to_unit_divider = 1, + .units_str = "uV", + }, + [RVOLT2] = { + .name = "RVOLT2", + .start_addr = QNOVO_RVOLT2_LSB, + .num_regs = 2, + .reg_to_unit_multiplier = 610350, + .reg_to_unit_divider = 1, + .units_str = "uV", + }, + [PCUR2] = { + .name = "PCUR2", + .start_addr = QNOVO_PCUR2_LSB, + .num_regs = 2, + .reg_to_unit_multiplier = 1220700, /* converts to nA */ + .reg_to_unit_divider = 1, + .units_str = "uA", + }, + [SCNT] = { + .name = "SCNT", + .start_addr = QNOVO_SCNT, + .num_regs = 1, + .reg_to_unit_multiplier = 1, + .reg_to_unit_divider = 1, + .min_val = 0, + .max_val = 255, + .units_str = "pulses", + }, + [VMAX] = { + .name = "VMAX", + .start_addr = QNOVO_VMAX_LSB, + .num_regs = 2, + .reg_to_unit_multiplier = 814000, /* converts to nV */ + .reg_to_unit_divider = 1, + .units_str = "uV", + }, + [SNUM] = { + .name = "SNUM", + .start_addr = QNOVO_SNUM, + .num_regs = 1, + .reg_to_unit_multiplier = 1, + .reg_to_unit_divider = 1, + .units_str = "pulses", + }, + [VBATT] = { + .name = "POWER_SUPPLY_PROP_VOLTAGE_NOW", + .start_addr = POWER_SUPPLY_PROP_VOLTAGE_NOW, + .units_str = "uV", + }, + [IBATT] = { + .name = "POWER_SUPPLY_PROP_CURRENT_NOW", + .start_addr = POWER_SUPPLY_PROP_CURRENT_NOW, + .units_str = "uA", + }, + [BATTTEMP] = { + .name = "POWER_SUPPLY_PROP_TEMP", + .start_addr = POWER_SUPPLY_PROP_TEMP, + .units_str = "uV", + }, + [BATTSOC] = { + .name = "POWER_SUPPLY_PROP_CAPACITY", + .start_addr = POWER_SUPPLY_PROP_CAPACITY, + .units_str = "%", + }, +}; + +static struct attribute *qnovo_class_attrs[]; + +static ssize_t version_show(struct class *c, struct class_attribute *attr, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d.%d\n", + DRV_MAJOR_VERSION, DRV_MINOR_VERSION); +} +static CLASS_ATTR_RO(version); + +static ssize_t ok_to_qnovo_show(struct class *c, struct class_attribute *attr, + char *buf) +{ + struct qnovo *chip = container_of(c, struct qnovo, qnovo_class); + int val = get_effective_result(chip->not_ok_to_qnovo_votable); + + return snprintf(buf, PAGE_SIZE, "%d\n", !val); +} +static CLASS_ATTR_RO(ok_to_qnovo); + +static ssize_t qnovo_enable_show(struct class *c, struct class_attribute *attr, + char *ubuf) +{ + struct qnovo *chip = container_of(c, struct qnovo, qnovo_class); + int val = get_effective_result(chip->disable_votable); + + return snprintf(ubuf, PAGE_SIZE, "%d\n", !val); +} + +static ssize_t qnovo_enable_store(struct class *c, struct class_attribute *attr, + const char *ubuf, size_t count) +{ + struct qnovo *chip = container_of(c, struct qnovo, qnovo_class); + unsigned long val; + + if (kstrtoul(ubuf, 0, &val)) + return -EINVAL; + + vote(chip->disable_votable, USER_VOTER, !val, 0); + + return count; +} +static CLASS_ATTR_RW(qnovo_enable); + +static ssize_t pt_enable_show(struct class *c, struct class_attribute *attr, + char *ubuf) +{ + struct qnovo *chip = container_of(c, struct qnovo, qnovo_class); + int val = get_effective_result(chip->pt_dis_votable); + + return snprintf(ubuf, PAGE_SIZE, "%d\n", !val); +} + +static ssize_t pt_enable_store(struct class *c, struct class_attribute *attr, + const char *ubuf, size_t count) +{ + struct qnovo *chip = container_of(c, struct qnovo, qnovo_class); + unsigned long val; + + if (kstrtoul(ubuf, 0, &val)) + return -EINVAL; + + /* val being 0, userspace wishes to disable pt so vote true */ + vote(chip->pt_dis_votable, QNI_PT_VOTER, val ? false : true, 0); + + return count; +} +static CLASS_ATTR_RW(pt_enable); + + +static ssize_t val_show(struct class *c, struct class_attribute *attr, + char *ubuf) +{ + struct qnovo *chip = container_of(c, struct qnovo, qnovo_class); + int i = &attr->attr - *qnovo_class_attrs; + int val = 0; + + if (i == FV_REQUEST) + val = chip->fv_uV_request; + + if (i == FCC_REQUEST) + val = chip->fcc_uA_request; + + return snprintf(ubuf, PAGE_SIZE, "%d\n", val); +} + +static ssize_t val_store(struct class *c, struct class_attribute *attr, + const char *ubuf, size_t count) +{ + struct qnovo *chip = container_of(c, struct qnovo, qnovo_class); + int i = &attr->attr - *qnovo_class_attrs; + unsigned long val; + + if (kstrtoul(ubuf, 0, &val)) + return -EINVAL; + + if (i == FV_REQUEST) + chip->fv_uV_request = val; + + if (i == FCC_REQUEST) + chip->fcc_uA_request = val; + + if (!get_effective_result(chip->disable_votable)) + qnovo_batt_psy_update(chip, false); + + return count; +} + +static ssize_t reg_show(struct class *c, struct class_attribute *attr, + char *ubuf) +{ + int i = &attr->attr - *qnovo_class_attrs; + struct qnovo *chip = container_of(c, struct qnovo, qnovo_class); + u8 buf[2] = {0, 0}; + u16 regval; + int rc; + + rc = qnovo_read(chip, params[i].start_addr, buf, params[i].num_regs); + if (rc < 0) { + pr_err("Couldn't read %s rc = %d\n", params[i].name, rc); + return -EINVAL; + } + regval = buf[1] << 8 | buf[0]; + + return snprintf(ubuf, PAGE_SIZE, "0x%04x\n", regval); +} + +static ssize_t reg_store(struct class *c, struct class_attribute *attr, + const char *ubuf, size_t count) +{ + int i = &attr->attr - *qnovo_class_attrs; + struct qnovo *chip = container_of(c, struct qnovo, qnovo_class); + u8 buf[2] = {0, 0}; + unsigned long val; + int rc; + + if (kstrtoul(ubuf, 0, &val)) + return -EINVAL; + + buf[0] = val & 0xFF; + buf[1] = (val >> 8) & 0xFF; + + rc = qnovo_write(chip, params[i].start_addr, buf, params[i].num_regs); + if (rc < 0) { + pr_err("Couldn't write %s rc = %d\n", params[i].name, rc); + return -EINVAL; + } + + if (params[i].callback) + params[i].callback(chip, buf); + + return count; +} + +static ssize_t time_show(struct class *c, struct class_attribute *attr, + char *ubuf) +{ + int i = &attr->attr - *qnovo_class_attrs; + struct qnovo *chip = container_of(c, struct qnovo, qnovo_class); + u8 buf[2] = {0, 0}; + u16 regval; + int val; + int rc; + + rc = qnovo_read(chip, params[i].start_addr, buf, params[i].num_regs); + if (rc < 0) { + pr_err("Couldn't read %s rc = %d\n", params[i].name, rc); + return -EINVAL; + } + regval = buf[1] << 8 | buf[0]; + + val = ((regval * params[i].reg_to_unit_multiplier) + / params[i].reg_to_unit_divider) + - params[i].reg_to_unit_offset; + + return snprintf(ubuf, PAGE_SIZE, "%d\n", val); +} + +static ssize_t time_store(struct class *c, struct class_attribute *attr, + const char *ubuf, size_t count) +{ + int i = &attr->attr - *qnovo_class_attrs; + struct qnovo *chip = container_of(c, struct qnovo, qnovo_class); + u8 buf[2] = {0, 0}; + u16 regval; + unsigned long val; + int rc; + + if (kstrtoul(ubuf, 0, &val)) + return -EINVAL; + + if (val < params[i].min_val || val > params[i].max_val) { + pr_err("Out of Range %d%s for %s\n", (int)val, + params[i].units_str, + params[i].name); + return -ERANGE; + } + + regval = (((int)val + params[i].reg_to_unit_offset) + * params[i].reg_to_unit_divider) + / params[i].reg_to_unit_multiplier; + buf[0] = regval & 0xFF; + buf[1] = (regval >> 8) & 0xFF; + + rc = qnovo_write(chip, params[i].start_addr, buf, params[i].num_regs); + if (rc < 0) { + pr_err("Couldn't write %s rc = %d\n", params[i].name, rc); + return -EINVAL; + } + + return count; +} + +static ssize_t current_show(struct class *c, struct class_attribute *attr, + char *ubuf) +{ + int i = &attr->attr - *qnovo_class_attrs; + struct qnovo *chip = container_of(c, struct qnovo, qnovo_class); + u8 buf[2] = {0, 0}; + int rc; + int comp_val_uA; + s64 regval_nA; + s64 gain, offset_nA, comp_val_nA; + + rc = qnovo_read(chip, params[i].start_addr, buf, params[i].num_regs); + if (rc < 0) { + pr_err("Couldn't read %s rc = %d\n", params[i].name, rc); + return -EINVAL; + } + + if (buf[1] & BIT(5)) + buf[1] |= GENMASK(7, 6); + + regval_nA = (s16)(buf[1] << 8 | buf[0]); + regval_nA = div_s64(regval_nA * params[i].reg_to_unit_multiplier, + params[i].reg_to_unit_divider) + - params[i].reg_to_unit_offset; + + if (chip->dt.external_rsense) { + offset_nA = chip->external_offset_nA; + gain = chip->external_i_gain_mega; + } else { + offset_nA = chip->internal_offset_nA; + gain = chip->internal_i_gain_mega; + } + + comp_val_nA = div_s64(regval_nA * gain, 1000000) - offset_nA; + comp_val_uA = div_s64(comp_val_nA, 1000); + + return snprintf(ubuf, PAGE_SIZE, "%d\n", comp_val_uA); +} + +static ssize_t voltage_show(struct class *c, struct class_attribute *attr, + char *ubuf) +{ + int i = &attr->attr - *qnovo_class_attrs; + struct qnovo *chip = container_of(c, struct qnovo, qnovo_class); + u8 buf[2] = {0, 0}; + int rc; + int comp_val_uV; + s64 regval_nV; + s64 gain, offset_nV, comp_val_nV; + + rc = qnovo_read(chip, params[i].start_addr, buf, params[i].num_regs); + if (rc < 0) { + pr_err("Couldn't read %s rc = %d\n", params[i].name, rc); + return -EINVAL; + } + regval_nV = buf[1] << 8 | buf[0]; + regval_nV = div_s64(regval_nV * params[i].reg_to_unit_multiplier, + params[i].reg_to_unit_divider) + - params[i].reg_to_unit_offset; + + offset_nV = chip->offset_nV; + gain = chip->v_gain_mega; + + comp_val_nV = div_s64(regval_nV * gain, 1000000) + offset_nV; + comp_val_uV = div_s64(comp_val_nV, 1000); + + return snprintf(ubuf, PAGE_SIZE, "%d\n", comp_val_uV); +} + +static ssize_t voltage_store(struct class *c, struct class_attribute *attr, + const char *ubuf, size_t count) +{ + int i = &attr->attr - *qnovo_class_attrs; + struct qnovo *chip = container_of(c, struct qnovo, qnovo_class); + u8 buf[2] = {0, 0}; + int rc; + unsigned long val_uV; + s64 regval_nV; + s64 gain, offset_nV; + + if (kstrtoul(ubuf, 0, &val_uV)) + return -EINVAL; + + if (val_uV < params[i].min_val || val_uV > params[i].max_val) { + pr_err("Out of Range %d%s for %s\n", (int)val_uV, + params[i].units_str, + params[i].name); + return -ERANGE; + } + + offset_nV = chip->offset_nV; + gain = chip->v_gain_mega; + + regval_nV = (s64)val_uV * 1000 - offset_nV; + regval_nV = div_s64(regval_nV * 1000000, gain); + + regval_nV = div_s64((regval_nV + params[i].reg_to_unit_offset) + * params[i].reg_to_unit_divider, + params[i].reg_to_unit_multiplier); + buf[0] = regval_nV & 0xFF; + buf[1] = ((u64)regval_nV >> 8) & 0xFF; + + rc = qnovo_write(chip, params[i].start_addr, buf, params[i].num_regs); + if (rc < 0) { + pr_err("Couldn't write %s rc = %d\n", params[i].name, rc); + return -EINVAL; + } + + return count; +} + +static ssize_t coulomb_show(struct class *c, struct class_attribute *attr, + char *ubuf) +{ + int i = &attr->attr - *qnovo_class_attrs; + struct qnovo *chip = container_of(c, struct qnovo, qnovo_class); + u8 buf[2] = {0, 0}; + int rc; + int comp_val_uC; + s64 regval_uC, gain; + + rc = qnovo_read(chip, params[i].start_addr, buf, params[i].num_regs); + if (rc < 0) { + pr_err("Couldn't read %s rc = %d\n", params[i].name, rc); + return -EINVAL; + } + regval_uC = buf[1] << 8 | buf[0]; + regval_uC = div_s64(regval_uC * params[i].reg_to_unit_multiplier, + params[i].reg_to_unit_divider) + - params[i].reg_to_unit_offset; + + if (chip->dt.external_rsense) + gain = chip->external_i_gain_mega; + else + gain = chip->internal_i_gain_mega; + + comp_val_uC = div_s64(regval_uC * gain, 1000000); + return snprintf(ubuf, PAGE_SIZE, "%d\n", comp_val_uC); +} + +static ssize_t coulomb_store(struct class *c, struct class_attribute *attr, + const char *ubuf, size_t count) +{ + int i = &attr->attr - *qnovo_class_attrs; + struct qnovo *chip = container_of(c, struct qnovo, qnovo_class); + u8 buf[2] = {0, 0}; + int rc; + unsigned long val_uC; + s64 regval; + s64 gain; + + if (kstrtoul(ubuf, 0, &val_uC)) + return -EINVAL; + + if (val_uC < params[i].min_val || val_uC > params[i].max_val) { + pr_err("Out of Range %d%s for %s\n", (int)val_uC, + params[i].units_str, + params[i].name); + return -ERANGE; + } + + if (chip->dt.external_rsense) + gain = chip->external_i_gain_mega; + else + gain = chip->internal_i_gain_mega; + + regval = div_s64((s64)val_uC * 1000000, gain); + + regval = div_s64((regval + params[i].reg_to_unit_offset) + * params[i].reg_to_unit_divider, + params[i].reg_to_unit_multiplier); + + buf[0] = regval & 0xFF; + buf[1] = ((u64)regval >> 8) & 0xFF; + + rc = qnovo_write(chip, params[i].start_addr, buf, params[i].num_regs); + if (rc < 0) { + pr_err("Couldn't write %s rc = %d\n", params[i].name, rc); + return -EINVAL; + } + + return count; +} + +static ssize_t batt_prop_show(struct class *c, struct class_attribute *attr, + char *ubuf) +{ + int i = &attr->attr - *qnovo_class_attrs; + struct qnovo *chip = container_of(c, struct qnovo, qnovo_class); + int rc = -EINVAL; + int prop = params[i].start_addr; + union power_supply_propval pval = {0}; + + if (!is_batt_available(chip)) + return -EINVAL; + + rc = power_supply_get_property(chip->batt_psy, prop, &pval); + if (rc < 0) { + pr_err("Couldn't read battery prop %s rc = %d\n", + params[i].name, rc); + return -EINVAL; + } + + return snprintf(ubuf, PAGE_SIZE, "%d\n", pval.intval); +} + +CLASS_ATTR_IDX_RW(fv_uV_request, val); +CLASS_ATTR_IDX_RW(fcc_uA_request, val); +CLASS_ATTR_IDX_RW(PE_CTRL_REG, reg); +CLASS_ATTR_IDX_RW(PE_CTRL2_REG, reg); +CLASS_ATTR_IDX_RO(PTRAIN_STS_REG, reg); +CLASS_ATTR_IDX_RO(INT_RT_STS_REG, reg); +CLASS_ATTR_IDX_RO(ERR_STS2_REG, reg); +CLASS_ATTR_IDX_RW(PREST1_mS, time); +CLASS_ATTR_IDX_RW(PPULS1_uC, coulomb); +CLASS_ATTR_IDX_RW(NREST1_mS, time); +CLASS_ATTR_IDX_RW(NPULS1_mS, time); +CLASS_ATTR_IDX_RW(PPCNT, time); +CLASS_ATTR_IDX_RW(VLIM1_uV, voltage); +CLASS_ATTR_IDX_RO(PVOLT1_uV, voltage); +CLASS_ATTR_IDX_RO(PCUR1_uA, current); +CLASS_ATTR_IDX_RO(PTTIME_S, time); +CLASS_ATTR_IDX_RW(PREST2_mS, time); +CLASS_ATTR_IDX_RW(PPULS2_uC, coulomb); +CLASS_ATTR_IDX_RW(NREST2_mS, time); +CLASS_ATTR_IDX_RW(NPULS2_mS, time); +CLASS_ATTR_IDX_RW(VLIM2_uV, voltage); +CLASS_ATTR_IDX_RO(PVOLT2_uV, voltage); +CLASS_ATTR_IDX_RO(RVOLT2_uV, voltage); +CLASS_ATTR_IDX_RO(PCUR2_uA, current); +CLASS_ATTR_IDX_RW(SCNT, time); +CLASS_ATTR_IDX_RO(VMAX_uV, voltage); +CLASS_ATTR_IDX_RO(SNUM, time); +CLASS_ATTR_IDX_RO(VBATT_uV, batt_prop); +CLASS_ATTR_IDX_RO(IBATT_uA, batt_prop); +CLASS_ATTR_IDX_RO(BATTTEMP_deciDegC, batt_prop); +CLASS_ATTR_IDX_RO(BATTSOC, batt_prop); + +static struct attribute *qnovo_class_attrs[] = { + [VER] = &class_attr_version.attr, + [OK_TO_QNOVO] = &class_attr_ok_to_qnovo.attr, + [QNOVO_ENABLE] = &class_attr_qnovo_enable.attr, + [PT_ENABLE] = &class_attr_pt_enable.attr, + [FV_REQUEST] = &class_attr_fv_uV_request.attr, + [FCC_REQUEST] = &class_attr_fcc_uA_request.attr, + [PE_CTRL_REG] = &class_attr_PE_CTRL_REG.attr, + [PE_CTRL2_REG] = &class_attr_PE_CTRL2_REG.attr, + [PTRAIN_STS_REG] = &class_attr_PTRAIN_STS_REG.attr, + [INT_RT_STS_REG] = &class_attr_INT_RT_STS_REG.attr, + [ERR_STS2_REG] = &class_attr_ERR_STS2_REG.attr, + [PREST1] = &class_attr_PREST1_mS.attr, + [PPULS1] = &class_attr_PPULS1_uC.attr, + [NREST1] = &class_attr_NREST1_mS.attr, + [NPULS1] = &class_attr_NPULS1_mS.attr, + [PPCNT] = &class_attr_PPCNT.attr, + [VLIM1] = &class_attr_VLIM1_uV.attr, + [PVOLT1] = &class_attr_PVOLT1_uV.attr, + [PCUR1] = &class_attr_PCUR1_uA.attr, + [PTTIME] = &class_attr_PTTIME_S.attr, + [PREST2] = &class_attr_PREST2_mS.attr, + [PPULS2] = &class_attr_PPULS2_uC.attr, + [NREST2] = &class_attr_NREST2_mS.attr, + [NPULS2] = &class_attr_NPULS2_mS.attr, + [VLIM2] = &class_attr_VLIM2_uV.attr, + [PVOLT2] = &class_attr_PVOLT2_uV.attr, + [RVOLT2] = &class_attr_RVOLT2_uV.attr, + [PCUR2] = &class_attr_PCUR2_uA.attr, + [SCNT] = &class_attr_SCNT.attr, + [VMAX] = &class_attr_VMAX_uV.attr, + [SNUM] = &class_attr_SNUM.attr, + [VBATT] = &class_attr_VBATT_uV.attr, + [IBATT] = &class_attr_IBATT_uA.attr, + [BATTTEMP] = &class_attr_BATTTEMP_deciDegC.attr, + [BATTSOC] = &class_attr_BATTSOC.attr, + NULL, +}; +ATTRIBUTE_GROUPS(qnovo_class); + +static int qnovo_update_status(struct qnovo *chip) +{ + u8 val = 0; + int rc; + bool hw_ok_to_qnovo; + + rc = qnovo_read(chip, QNOVO_ERROR_STS2, &val, 1); + if (rc < 0) { + pr_err("Couldn't read error sts rc = %d\n", rc); + hw_ok_to_qnovo = false; + } else { + /* + * For CV mode keep qnovo enabled, userspace is expected to + * disable it after few runs + */ + hw_ok_to_qnovo = (val == ERR_CV_MODE || val == 0) ? + true : false; + } + + vote(chip->not_ok_to_qnovo_votable, HW_OK_TO_QNOVO_VOTER, + !hw_ok_to_qnovo, 0); + return 0; +} + +static void usb_debounce_work(struct work_struct *work) +{ + struct qnovo *chip = container_of(work, + struct qnovo, usb_debounce_work.work); + + vote(chip->chg_ready_votable, USB_READY_VOTER, true, 0); + vote(chip->awake_votable, USB_READY_VOTER, false, 0); +} + +static void dc_debounce_work(struct work_struct *work) +{ + struct qnovo *chip = container_of(work, + struct qnovo, dc_debounce_work.work); + + vote(chip->chg_ready_votable, DC_READY_VOTER, true, 0); + vote(chip->awake_votable, DC_READY_VOTER, false, 0); +} + +#define DEBOUNCE_MS 15000 /* 15 seconds */ +static void status_change_work(struct work_struct *work) +{ + struct qnovo *chip = container_of(work, + struct qnovo, status_change_work); + union power_supply_propval pval; + bool usb_present = false, dc_present = false; + int rc; + + if (is_fg_available(chip)) + vote(chip->disable_votable, FG_AVAILABLE_VOTER, false, 0); + + if (is_usb_available(chip)) { + rc = power_supply_get_property(chip->usb_psy, + POWER_SUPPLY_PROP_PRESENT, &pval); + usb_present = (rc < 0) ? 0 : pval.intval; + } + + if (chip->usb_present && !usb_present) { + /* removal */ + chip->usb_present = 0; + cancel_delayed_work_sync(&chip->usb_debounce_work); + vote(chip->awake_votable, USB_READY_VOTER, false, 0); + vote(chip->chg_ready_votable, USB_READY_VOTER, false, 0); + } else if (!chip->usb_present && usb_present) { + /* insertion */ + chip->usb_present = 1; + vote(chip->awake_votable, USB_READY_VOTER, true, 0); + schedule_delayed_work(&chip->usb_debounce_work, + msecs_to_jiffies(DEBOUNCE_MS)); + } + + if (is_dc_available(chip)) { + rc = power_supply_get_property(chip->dc_psy, + POWER_SUPPLY_PROP_PRESENT, + &pval); + dc_present = (rc < 0) ? 0 : pval.intval; + } + + if (usb_present) + dc_present = 0; + + /* disable qnovo for dc path by forcing dc_present = 0 always */ + if (!chip->dt.enable_for_dc) + dc_present = 0; + + if (chip->dc_present && !dc_present) { + /* removal */ + chip->dc_present = 0; + cancel_delayed_work_sync(&chip->dc_debounce_work); + vote(chip->awake_votable, DC_READY_VOTER, false, 0); + vote(chip->chg_ready_votable, DC_READY_VOTER, false, 0); + } else if (!chip->dc_present && dc_present) { + /* insertion */ + chip->dc_present = 1; + vote(chip->awake_votable, DC_READY_VOTER, true, 0); + schedule_delayed_work(&chip->dc_debounce_work, + msecs_to_jiffies(DEBOUNCE_MS)); + } + + qnovo_update_status(chip); +} + +static void ptrain_restart_work(struct work_struct *work) +{ + struct qnovo *chip = container_of(work, + struct qnovo, ptrain_restart_work.work); + u8 pt_t1, pt_t2; + int rc; + u8 pt_en; + + rc = qnovo_read(chip, QNOVO_PTRAIN_EN, &pt_en, 1); + if (rc < 0) { + dev_err(chip->dev, "Couldn't read QNOVO_PTRAIN_EN rc = %d\n", + rc); + goto clean_up; + } + + if (!pt_en) { + rc = qnovo_masked_write(chip, QNOVO_PTRAIN_EN, + QNOVO_PTRAIN_EN_BIT, QNOVO_PTRAIN_EN_BIT); + if (rc < 0) { + dev_err(chip->dev, "Couldn't enable pulse train rc=%d\n", + rc); + goto clean_up; + } + /* sleep 20ms for the pulse trains to restart and settle */ + msleep(20); + } + + rc = qnovo_read(chip, QNOVO_PTTIME_STS, &pt_t1, 1); + if (rc < 0) { + dev_err(chip->dev, "Couldn't read QNOVO_PTTIME_STS rc = %d\n", + rc); + goto clean_up; + } + + /* pttime increments every 2 seconds */ + msleep(2100); + + rc = qnovo_read(chip, QNOVO_PTTIME_STS, &pt_t2, 1); + if (rc < 0) { + dev_err(chip->dev, "Couldn't read QNOVO_PTTIME_STS rc = %d\n", + rc); + goto clean_up; + } + + if (pt_t1 != pt_t2) + goto clean_up; + + /* Toggle pt enable to restart pulse train */ + rc = qnovo_masked_write(chip, QNOVO_PTRAIN_EN, QNOVO_PTRAIN_EN_BIT, 0); + if (rc < 0) { + dev_err(chip->dev, "Couldn't disable pulse train rc=%d\n", rc); + goto clean_up; + } + msleep(1000); + rc = qnovo_masked_write(chip, QNOVO_PTRAIN_EN, QNOVO_PTRAIN_EN_BIT, + QNOVO_PTRAIN_EN_BIT); + if (rc < 0) { + dev_err(chip->dev, "Couldn't enable pulse train rc=%d\n", rc); + goto clean_up; + } + +clean_up: + vote(chip->awake_votable, PT_RESTART_VOTER, false, 0); +} + +static int qnovo_notifier_call(struct notifier_block *nb, + unsigned long ev, void *v) +{ + struct power_supply *psy = v; + struct qnovo *chip = container_of(nb, struct qnovo, nb); + + if (ev != PSY_EVENT_PROP_CHANGED) + return NOTIFY_OK; + + if (strcmp(psy->desc->name, "battery") == 0 + || strcmp(psy->desc->name, "bms") == 0 + || strcmp(psy->desc->name, "usb") == 0 + || strcmp(psy->desc->name, "dc") == 0) + schedule_work(&chip->status_change_work); + + return NOTIFY_OK; +} + +static irqreturn_t handle_ptrain_done(int irq, void *data) +{ + struct qnovo *chip = data; + union power_supply_propval pval = {0}; + + qnovo_update_status(chip); + + /* + * hw resets pt_en bit once ptrain_done triggers. + * vote on behalf of QNI to disable it such that + * once QNI enables it, the votable state changes + * and the callback that sets it is indeed invoked + */ + vote(chip->pt_dis_votable, QNI_PT_VOTER, true, 0); + + vote(chip->pt_dis_votable, ESR_VOTER, true, 0); + if (is_fg_available(chip) + && !get_client_vote(chip->disable_votable, USER_VOTER) + && !get_effective_result(chip->not_ok_to_qnovo_votable)) + power_supply_set_property(chip->bms_psy, + POWER_SUPPLY_PROP_RESISTANCE, + &pval); + + vote(chip->pt_dis_votable, ESR_VOTER, false, 0); + kobject_uevent(&chip->dev->kobj, KOBJ_CHANGE); + return IRQ_HANDLED; +} + +static int qnovo_hw_init(struct qnovo *chip) +{ + int rc; + u8 iadc_offset_external, iadc_offset_internal; + u8 iadc_gain_external, iadc_gain_internal; + u8 vadc_offset, vadc_gain; + u8 val; + + vote(chip->chg_ready_votable, USB_READY_VOTER, false, 0); + vote(chip->chg_ready_votable, DC_READY_VOTER, false, 0); + + vote(chip->disable_votable, USER_VOTER, true, 0); + vote(chip->disable_votable, FG_AVAILABLE_VOTER, true, 0); + + vote(chip->pt_dis_votable, QNI_PT_VOTER, true, 0); + vote(chip->pt_dis_votable, QNOVO_OVERALL_VOTER, true, 0); + vote(chip->pt_dis_votable, ESR_VOTER, false, 0); + + vote(chip->auto_esr_votable, QNOVO_OVERALL_VOTER, true, 0); + + val = 0; + rc = qnovo_write(chip, QNOVO_STRM_CTRL, &val, 1); + if (rc < 0) { + pr_err("Couldn't write iadc bitstream control rc = %d\n", rc); + return rc; + } + + rc = qnovo_read(chip, QNOVO_IADC_OFFSET_0, &iadc_offset_external, 1); + if (rc < 0) { + pr_err("Couldn't read iadc exernal offset rc = %d\n", rc); + return rc; + } + + /* stored as an 8 bit 2's complement signed integer */ + val = -1 * iadc_offset_external; + rc = qnovo_write(chip, QNOVO_TR_IADC_OFFSET_0, &val, 1); + if (rc < 0) { + pr_err("Couldn't write iadc offset rc = %d\n", rc); + return rc; + } + + rc = qnovo_read(chip, QNOVO_IADC_OFFSET_1, &iadc_offset_internal, 1); + if (rc < 0) { + pr_err("Couldn't read iadc internal offset rc = %d\n", rc); + return rc; + } + + /* stored as an 8 bit 2's complement signed integer */ + val = -1 * iadc_offset_internal; + rc = qnovo_write(chip, QNOVO_TR_IADC_OFFSET_1, &val, 1); + if (rc < 0) { + pr_err("Couldn't write iadc offset rc = %d\n", rc); + return rc; + } + + rc = qnovo_read(chip, QNOVO_IADC_GAIN_0, &iadc_gain_external, 1); + if (rc < 0) { + pr_err("Couldn't read iadc external gain rc = %d\n", rc); + return rc; + } + + rc = qnovo_read(chip, QNOVO_IADC_GAIN_1, &iadc_gain_internal, 1); + if (rc < 0) { + pr_err("Couldn't read iadc internal gain rc = %d\n", rc); + return rc; + } + + rc = qnovo_read(chip, QNOVO_VADC_OFFSET, &vadc_offset, 1); + if (rc < 0) { + pr_err("Couldn't read vadc offset rc = %d\n", rc); + return rc; + } + + rc = qnovo_read(chip, QNOVO_VADC_GAIN, &vadc_gain, 1); + if (rc < 0) { + pr_err("Couldn't read vadc external gain rc = %d\n", rc); + return rc; + } + + chip->external_offset_nA = (s64)(s8)iadc_offset_external * IADC_LSB_NA; + chip->internal_offset_nA = (s64)(s8)iadc_offset_internal * IADC_LSB_NA; + chip->offset_nV = (s64)(s8)vadc_offset * VADC_LSB_NA; + chip->external_i_gain_mega + = 1000000000 + (s64)(s8)iadc_gain_external * GAIN_LSB_FACTOR; + chip->external_i_gain_mega + = div_s64(chip->external_i_gain_mega, 1000); + chip->internal_i_gain_mega + = 1000000000 + (s64)(s8)iadc_gain_internal * GAIN_LSB_FACTOR; + chip->internal_i_gain_mega + = div_s64(chip->internal_i_gain_mega, 1000); + chip->v_gain_mega = 1000000000 + (s64)(s8)vadc_gain * GAIN_LSB_FACTOR; + chip->v_gain_mega = div_s64(chip->v_gain_mega, 1000); + + /* allow charger error conditions to disable qnovo, CV mode excluded */ + val = ERR_SWITCHER_DISABLED | ERR_JEITA_SOFT_CONDITION | ERR_BAT_OV | + ERR_BATTERY_MISSING | ERR_SAFETY_TIMER_EXPIRED | + ERR_CHARGING_DISABLED | ERR_JEITA_HARD_CONDITION; + rc = qnovo_write(chip, QNOVO_DISABLE_CHARGING, &val, 1); + if (rc < 0) { + pr_err("Couldn't write QNOVO_DISABLE_CHARGING rc = %d\n", rc); + return rc; + } + + return 0; +} + +static int qnovo_register_notifier(struct qnovo *chip) +{ + int rc; + + chip->nb.notifier_call = qnovo_notifier_call; + rc = power_supply_reg_notifier(&chip->nb); + if (rc < 0) { + pr_err("Couldn't register psy notifier rc = %d\n", rc); + return rc; + } + + return 0; +} + +static int qnovo_determine_initial_status(struct qnovo *chip) +{ + status_change_work(&chip->status_change_work); + return 0; +} + +static int qnovo_request_interrupts(struct qnovo *chip) +{ + int rc = 0; + int irq_ptrain_done = of_irq_get_byname(chip->dev->of_node, + "ptrain-done"); + + rc = devm_request_threaded_irq(chip->dev, irq_ptrain_done, NULL, + handle_ptrain_done, + IRQF_ONESHOT, "ptrain-done", chip); + if (rc < 0) { + pr_err("Couldn't request irq %d rc = %d\n", + irq_ptrain_done, rc); + return rc; + } + + enable_irq_wake(irq_ptrain_done); + + return rc; +} + +static int qnovo_probe(struct platform_device *pdev) +{ + struct qnovo *chip; + int rc = 0; + + chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->fv_uV_request = -EINVAL; + chip->fcc_uA_request = -EINVAL; + chip->dev = &pdev->dev; + mutex_init(&chip->write_lock); + + chip->regmap = dev_get_regmap(chip->dev->parent, NULL); + if (!chip->regmap) { + pr_err("parent regmap is missing\n"); + return -EINVAL; + } + + rc = qnovo_parse_dt(chip); + if (rc < 0) { + pr_err("Couldn't parse device tree rc=%d\n", rc); + return rc; + } + + /* set driver data before resources request it */ + platform_set_drvdata(pdev, chip); + + chip->disable_votable = create_votable("QNOVO_DISABLE", VOTE_SET_ANY, + qnovo_disable_cb, chip); + if (IS_ERR(chip->disable_votable)) { + rc = PTR_ERR(chip->disable_votable); + goto cleanup; + } + + chip->pt_dis_votable = create_votable("QNOVO_PT_DIS", VOTE_SET_ANY, + pt_dis_votable_cb, chip); + if (IS_ERR(chip->pt_dis_votable)) { + rc = PTR_ERR(chip->pt_dis_votable); + goto destroy_disable_votable; + } + + chip->not_ok_to_qnovo_votable = create_votable("QNOVO_NOT_OK", + VOTE_SET_ANY, + not_ok_to_qnovo_cb, chip); + if (IS_ERR(chip->not_ok_to_qnovo_votable)) { + rc = PTR_ERR(chip->not_ok_to_qnovo_votable); + goto destroy_pt_dis_votable; + } + + chip->chg_ready_votable = create_votable("QNOVO_CHG_READY", + VOTE_SET_ANY, + chg_ready_cb, chip); + if (IS_ERR(chip->chg_ready_votable)) { + rc = PTR_ERR(chip->chg_ready_votable); + goto destroy_not_ok_to_qnovo_votable; + } + + chip->awake_votable = create_votable("QNOVO_AWAKE", VOTE_SET_ANY, + awake_cb, chip); + if (IS_ERR(chip->awake_votable)) { + rc = PTR_ERR(chip->awake_votable); + goto destroy_chg_ready_votable; + } + + chip->auto_esr_votable = create_votable("AUTO_ESR", VOTE_SET_ANY, + auto_esr_cb, chip); + if (IS_ERR(chip->auto_esr_votable)) { + rc = PTR_ERR(chip->auto_esr_votable); + goto destroy_auto_esr_votable; + } + + INIT_WORK(&chip->status_change_work, status_change_work); + INIT_DELAYED_WORK(&chip->dc_debounce_work, dc_debounce_work); + INIT_DELAYED_WORK(&chip->usb_debounce_work, usb_debounce_work); + INIT_DELAYED_WORK(&chip->ptrain_restart_work, ptrain_restart_work); + + rc = qnovo_hw_init(chip); + if (rc < 0) { + pr_err("Couldn't initialize hardware rc=%d\n", rc); + goto destroy_awake_votable; + } + + rc = qnovo_register_notifier(chip); + if (rc < 0) { + pr_err("Couldn't register psy notifier rc = %d\n", rc); + goto unreg_notifier; + } + + rc = qnovo_determine_initial_status(chip); + if (rc < 0) { + pr_err("Couldn't determine initial status rc=%d\n", rc); + goto unreg_notifier; + } + + rc = qnovo_request_interrupts(chip); + if (rc < 0) { + pr_err("Couldn't request interrupts rc=%d\n", rc); + goto unreg_notifier; + } + chip->qnovo_class.name = "qnovo", + chip->qnovo_class.owner = THIS_MODULE, + chip->qnovo_class.class_groups = qnovo_class_groups; + + rc = class_register(&chip->qnovo_class); + if (rc < 0) { + pr_err("couldn't register qnovo sysfs class rc = %d\n", rc); + goto unreg_notifier; + } + + device_init_wakeup(chip->dev, true); + + return rc; + +unreg_notifier: + power_supply_unreg_notifier(&chip->nb); +destroy_auto_esr_votable: + destroy_votable(chip->auto_esr_votable); +destroy_awake_votable: + destroy_votable(chip->awake_votable); +destroy_chg_ready_votable: + destroy_votable(chip->chg_ready_votable); +destroy_not_ok_to_qnovo_votable: + destroy_votable(chip->not_ok_to_qnovo_votable); +destroy_pt_dis_votable: + destroy_votable(chip->pt_dis_votable); +destroy_disable_votable: + destroy_votable(chip->disable_votable); +cleanup: + platform_set_drvdata(pdev, NULL); + return rc; +} + +static int qnovo_remove(struct platform_device *pdev) +{ + struct qnovo *chip = platform_get_drvdata(pdev); + + class_unregister(&chip->qnovo_class); + power_supply_unreg_notifier(&chip->nb); + destroy_votable(chip->chg_ready_votable); + destroy_votable(chip->not_ok_to_qnovo_votable); + destroy_votable(chip->pt_dis_votable); + destroy_votable(chip->disable_votable); + platform_set_drvdata(pdev, NULL); + return 0; +} + +static void qnovo_shutdown(struct platform_device *pdev) +{ + struct qnovo *chip = platform_get_drvdata(pdev); + + vote(chip->not_ok_to_qnovo_votable, SHUTDOWN_VOTER, true, 0); +} + +static const struct of_device_id match_table[] = { + { .compatible = "qcom,qpnp-qnovo", }, + { }, +}; + +static struct platform_driver qnovo_driver = { + .driver = { + .name = "qcom,qnovo-driver", + .owner = THIS_MODULE, + .of_match_table = match_table, + }, + .probe = qnovo_probe, + .remove = qnovo_remove, + .shutdown = qnovo_shutdown, +}; +module_platform_driver(qnovo_driver); + +MODULE_DESCRIPTION("QPNP Qnovo Driver"); +MODULE_LICENSE("GPL v2"); From 1cfc1e158ff2a4d8a7226637e661bbcfa3649f5f Mon Sep 17 00:00:00 2001 From: duckyduckG Date: Tue, 7 Oct 2025 23:26:12 +0500 Subject: [PATCH 194/356] arm64: configs: sdm845: enable qnovo driver --- arch/arm64/configs/vendor/sdm845-perf_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/vendor/sdm845-perf_defconfig b/arch/arm64/configs/vendor/sdm845-perf_defconfig index ae2813b564a0..60d34c6e68ea 100644 --- a/arch/arm64/configs/vendor/sdm845-perf_defconfig +++ b/arch/arm64/configs/vendor/sdm845-perf_defconfig @@ -370,6 +370,7 @@ CONFIG_POWER_RESET_XGENE=y CONFIG_POWER_RESET_SYSCON=y CONFIG_QPNP_SMB2=y CONFIG_SMB1355_SLAVE_CHARGER=y +CONFIG_QPNP_QNOVO=y CONFIG_QPNP_FG_GEN3=y CONFIG_THERMAL=y CONFIG_THERMAL_WRITABLE_TRIPS=y From 407208ac37f108829e44b319038e7324ea9e8a2e Mon Sep 17 00:00:00 2001 From: duckyduckG Date: Wed, 8 Oct 2025 15:05:48 +0500 Subject: [PATCH 195/356] power: qcom: battery: don't check FCC upper limit for smb2 * it is only supported on smb5. --- drivers/power/supply/qcom/battery.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c index ec45b7d1c502..caad31163fbf 100644 --- a/drivers/power/supply/qcom/battery.c +++ b/drivers/power/supply/qcom/battery.c @@ -1400,6 +1400,7 @@ static int pl_disable_vote_callback(struct votable *votable, chip->fcc_stepper_enable = pval.intval; pr_debug("FCC Stepper %s\n", pval.intval ? "enabled" : "disabled"); +#if !defined(CONFIG_QPNP_SMB2) rc = power_supply_get_property(chip->main_psy, POWER_SUPPLY_PROP_MAIN_FCC_MAX, &pval); if (rc < 0) { @@ -1409,6 +1410,7 @@ static int pl_disable_vote_callback(struct votable *votable, } else if (pval.intval > 0) { chip->main_fcc_max = pval.intval; } +#endif if (chip->fcc_stepper_enable) { cancel_delayed_work_sync(&chip->fcc_stepper_work); From 6c6ee174ad54b6833fa5f94b1a09a73b26606e72 Mon Sep 17 00:00:00 2001 From: duckyduckG Date: Wed, 8 Oct 2025 15:21:18 +0500 Subject: [PATCH 196/356] platform: msm: add QPNP Coincell driver from msm 4.9 as of 'commit <8885f793f0b28d3ddfba498e7f0e247f35cd84c7> ("drivers: add a snapshot of various QPNP PMIC peripheral drivers")' --- .../bindings/platform/msm/qpnp-coincell.txt | 44 +++ drivers/platform/msm/Kconfig | 10 + drivers/platform/msm/Makefile | 1 + drivers/platform/msm/qpnp-coincell.c | 283 ++++++++++++++++++ 4 files changed, 338 insertions(+) create mode 100644 arch/arm64/boot/dts/vendor/bindings/platform/msm/qpnp-coincell.txt create mode 100644 drivers/platform/msm/qpnp-coincell.c diff --git a/arch/arm64/boot/dts/vendor/bindings/platform/msm/qpnp-coincell.txt b/arch/arm64/boot/dts/vendor/bindings/platform/msm/qpnp-coincell.txt new file mode 100644 index 000000000000..4d55f0cecefe --- /dev/null +++ b/arch/arm64/boot/dts/vendor/bindings/platform/msm/qpnp-coincell.txt @@ -0,0 +1,44 @@ +Qualcomm Technologies, Inc. QPNP Coincell - coincell battery charger devices + +Required properties: +- compatible: Must be "qcom,qpnp-coincell". +- reg: Specifies the SPMI address and size for this coincell device. + +Required structure: +- A qcom,qpnp-coincell node must be a child of an SPMI node that has specified + the spmi-slave-container property. + +Optional properties: +- qcom,rset-ohms: Specifies the resistance of the current limiting + resistor in ohms. Four values are supported: + 800, 1200, 1700, and 2100. +- qcom,vset-millivolts: Specifies the coincell charging voltage in millivolts. + Four values are supported: 2500, 3000, 3100, and 3200. +- qcom,charge-enable: Specifies if coincell charging should be enabled or not. + 0 = disable charging, 1 = enabled charging + +If any of the optional properties are not specified, then the hardware default +values for the unspecified properties will be used instead. + +Example: + qcom,spmi@fc4c0000 { + #address-cells = <1>; + #size-cells = <0>; + interrupt-controller; + #interrupt-cells = <3>; + + qcom,pm8941@1 { + spmi-slave-container; + reg = <0x1>; + #address-cells = <1>; + #size-cells = <1>; + + qcom,coincell@2800 { + compatible = "qcom,qpnp-coincell"; + reg = <0x2800 0x100>; + qcom,rset-ohms = <800>; + qcom,vset-millivolts = <3100>; + qcom,charge-enable = <1>; + }; + }; + }; diff --git a/drivers/platform/msm/Kconfig b/drivers/platform/msm/Kconfig index 273ed10ecd3b..4e08effdaf0d 100644 --- a/drivers/platform/msm/Kconfig +++ b/drivers/platform/msm/Kconfig @@ -13,6 +13,16 @@ config MSM_EXT_DISPLAY This should be enabled to support audio & video over HDMI or DP for hot pluggable sink devices. +config QPNP_COINCELL + tristate "QPNP coincell charger support" + depends on SPMI + help + This driver supports the QPNP coincell peripheral found inside of + Qualcomm Technologies, Inc. QPNP PMIC devices. The coincell charger + provides a means to charge a coincell battery or backup capacitor + which is used to maintain PMIC register state when the main battery is + removed from the mobile device. + config QPNP_REVID tristate "QPNP Revision ID Peripheral" depends on SPMI diff --git a/drivers/platform/msm/Makefile b/drivers/platform/msm/Makefile index c16fd2aae52c..e2baa428984a 100644 --- a/drivers/platform/msm/Makefile +++ b/drivers/platform/msm/Makefile @@ -12,4 +12,5 @@ obj-$(CONFIG_IPA) += ipa/ obj-$(CONFIG_IPA3) += ipa/ obj-$(CONFIG_USB_BAM) += usb_bam.o obj-$(CONFIG_QCOM_GENI_SE) += qcom-geni-se.o +obj-$(CONFIG_QPNP_COINCELL) += qpnp-coincell.o obj-$(CONFIG_MSM_11AD) += msm_11ad/ diff --git a/drivers/platform/msm/qpnp-coincell.c b/drivers/platform/msm/qpnp-coincell.c new file mode 100644 index 000000000000..b427f43e76df --- /dev/null +++ b/drivers/platform/msm/qpnp-coincell.c @@ -0,0 +1,283 @@ +/* Copyright (c) 2013-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. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define QPNP_COINCELL_DRIVER_NAME "qcom,qpnp-coincell" + +struct qpnp_coincell { + struct platform_device *pdev; + struct regmap *regmap; + u16 base_addr; +}; + +#define QPNP_COINCELL_REG_TYPE 0x04 +#define QPNP_COINCELL_REG_SUBTYPE 0x05 +#define QPNP_COINCELL_REG_RSET 0x44 +#define QPNP_COINCELL_REG_VSET 0x45 +#define QPNP_COINCELL_REG_ENABLE 0x46 + +#define QPNP_COINCELL_TYPE 0x02 +#define QPNP_COINCELL_SUBTYPE 0x20 +#define QPNP_COINCELL_ENABLE 0x80 +#define QPNP_COINCELL_DISABLE 0x00 + +static const int qpnp_rset_map[] = {2100, 1700, 1200, 800}; +static const int qpnp_vset_map[] = {2500, 3200, 3100, 3000}; + +static int qpnp_coincell_set_resistance(struct qpnp_coincell *chip, int rset) +{ + int i, rc; + u8 reg; + + for (i = 0; i < ARRAY_SIZE(qpnp_rset_map); i++) + if (rset == qpnp_rset_map[i]) + break; + + if (i >= ARRAY_SIZE(qpnp_rset_map)) { + pr_err("invalid rset=%d value\n", rset); + return -EINVAL; + } + + reg = i; + rc = regmap_write(chip->regmap, + chip->base_addr + QPNP_COINCELL_REG_RSET, reg); + if (rc) + dev_err(&chip->pdev->dev, + "%s: could not write to RSET register, rc=%d\n", + __func__, rc); + + return rc; +} + +static int qpnp_coincell_set_voltage(struct qpnp_coincell *chip, int vset) +{ + int i, rc; + u8 reg; + + for (i = 0; i < ARRAY_SIZE(qpnp_vset_map); i++) + if (vset == qpnp_vset_map[i]) + break; + + if (i >= ARRAY_SIZE(qpnp_vset_map)) { + pr_err("invalid vset=%d value\n", vset); + return -EINVAL; + } + + reg = i; + rc = regmap_write(chip->regmap, + chip->base_addr + QPNP_COINCELL_REG_VSET, reg); + if (rc) + dev_err(&chip->pdev->dev, + "%s: could not write to VSET register, rc=%d\n", + __func__, rc); + + return rc; +} + +static int qpnp_coincell_set_charge(struct qpnp_coincell *chip, bool enabled) +{ + int rc; + u8 reg; + + reg = enabled ? QPNP_COINCELL_ENABLE : QPNP_COINCELL_DISABLE; + rc = regmap_write(chip->regmap, + chip->base_addr + QPNP_COINCELL_REG_ENABLE, reg); + if (rc) + dev_err(&chip->pdev->dev, + "%s: could not write to ENABLE register, rc=%d\n", + __func__, rc); + + return rc; +} + +static void qpnp_coincell_charger_show_state(struct qpnp_coincell *chip) +{ + int rc, rset, vset, temp; + bool enabled; + u8 reg[QPNP_COINCELL_REG_ENABLE - QPNP_COINCELL_REG_RSET + 1]; + + rc = regmap_bulk_read(chip->regmap, + chip->base_addr + QPNP_COINCELL_REG_RSET, reg, + ARRAY_SIZE(reg)); + if (rc) { + dev_err(&chip->pdev->dev, + "%s: could not read RSET register, rc=%d\n", + __func__, rc); + return; + } + + temp = reg[QPNP_COINCELL_REG_RSET - QPNP_COINCELL_REG_RSET]; + if (temp >= ARRAY_SIZE(qpnp_rset_map)) { + dev_err(&chip->pdev->dev, + "unknown RSET=0x%02X register value\n", + temp); + return; + } + rset = qpnp_rset_map[temp]; + + temp = reg[QPNP_COINCELL_REG_VSET - QPNP_COINCELL_REG_RSET]; + if (temp >= ARRAY_SIZE(qpnp_vset_map)) { + dev_err(&chip->pdev->dev, + "unknown VSET=0x%02X register value\n", + temp); + return; + } + vset = qpnp_vset_map[temp]; + + temp = reg[QPNP_COINCELL_REG_ENABLE - QPNP_COINCELL_REG_RSET]; + enabled = temp & QPNP_COINCELL_ENABLE; + + pr_info("enabled=%c, voltage=%d mV, resistance=%d ohm\n", + (enabled ? 'Y' : 'N'), vset, rset); +} + +static int qpnp_coincell_check_type(struct qpnp_coincell *chip) +{ + int rc; + u8 type[2]; + + rc = regmap_bulk_read(chip->regmap, + chip->base_addr + QPNP_COINCELL_REG_TYPE, type, + 2); + if (rc) { + dev_err(&chip->pdev->dev, + "%s: could not read type register, rc=%d\n", + __func__, rc); + return rc; + } + + if (type[0] != QPNP_COINCELL_TYPE || type[1] != QPNP_COINCELL_SUBTYPE) { + dev_err(&chip->pdev->dev, + "%s: invalid type=0x%02X or subtype=0x%02X register value\n", + __func__, type[0], type[1]); + return -ENODEV; + } + + return rc; +} + +static int qpnp_coincell_probe(struct platform_device *pdev) +{ + struct device_node *node = pdev->dev.of_node; + struct qpnp_coincell *chip; + unsigned int base; + u32 temp; + int rc = 0; + + if (!node) { + dev_err(&pdev->dev, "%s: device node missing\n", __func__); + return -ENODEV; + } + + chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!chip->regmap) { + dev_err(&pdev->dev, "Couldn't get parent's regmap\n"); + return -EINVAL; + } + chip->pdev = pdev; + + rc = of_property_read_u32(pdev->dev.of_node, "reg", &base); + if (rc < 0) { + dev_err(&pdev->dev, + "Couldn't find reg in node = %s rc = %d\n", + pdev->dev.of_node->full_name, rc); + return rc; + } + chip->base_addr = base; + + rc = qpnp_coincell_check_type(chip); + if (rc) + return rc; + + rc = of_property_read_u32(node, "qcom,rset-ohms", &temp); + if (!rc) { + rc = qpnp_coincell_set_resistance(chip, temp); + if (rc) + return rc; + } + + rc = of_property_read_u32(node, "qcom,vset-millivolts", &temp); + if (!rc) { + rc = qpnp_coincell_set_voltage(chip, temp); + if (rc) + return rc; + } + + rc = of_property_read_u32(node, "qcom,charge-enable", &temp); + if (!rc) { + rc = qpnp_coincell_set_charge(chip, temp); + if (rc) + return rc; + } + + qpnp_coincell_charger_show_state(chip); + + return 0; +} + +static int qpnp_coincell_remove(struct platform_device *pdev) +{ + return 0; +} + +static const struct of_device_id qpnp_coincell_match_table[] = { + { .compatible = QPNP_COINCELL_DRIVER_NAME, }, + {} +}; + +static const struct platform_device_id qpnp_coincell_id[] = { + { QPNP_COINCELL_DRIVER_NAME, 0 }, + {} +}; +MODULE_DEVICE_TABLE(spmi, qpnp_coincell_id); + +static struct platform_driver qpnp_coincell_driver = { + .driver = { + .name = QPNP_COINCELL_DRIVER_NAME, + .of_match_table = qpnp_coincell_match_table, + .owner = THIS_MODULE, + }, + .probe = qpnp_coincell_probe, + .remove = qpnp_coincell_remove, + .id_table = qpnp_coincell_id, +}; + +static int __init qpnp_coincell_init(void) +{ + return platform_driver_register(&qpnp_coincell_driver); +} + +static void __exit qpnp_coincell_exit(void) +{ + platform_driver_unregister(&qpnp_coincell_driver); +} + +MODULE_DESCRIPTION("QPNP PMIC coincell charger driver"); +MODULE_LICENSE("GPL v2"); + +module_init(qpnp_coincell_init); +module_exit(qpnp_coincell_exit); From ba9a4c362469e6e94e3c41e1d1e5506ae3199cb4 Mon Sep 17 00:00:00 2001 From: duckyduckG Date: Wed, 8 Oct 2025 15:26:11 +0500 Subject: [PATCH 197/356] arm64: configs: sdm845: enable QPNP Coincell --- arch/arm64/configs/vendor/sdm845-perf_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/vendor/sdm845-perf_defconfig b/arch/arm64/configs/vendor/sdm845-perf_defconfig index 60d34c6e68ea..04c75e4b83fa 100644 --- a/arch/arm64/configs/vendor/sdm845-perf_defconfig +++ b/arch/arm64/configs/vendor/sdm845-perf_defconfig @@ -507,6 +507,7 @@ CONFIG_ASHMEM=y CONFIG_ION=y CONFIG_ION_POOL_AUTO_REFILL=y CONFIG_ION_LEGACY=y +CONFIG_QPNP_COINCELL=y CONFIG_QPNP_REVID=y CONFIG_SPS=y CONFIG_SPS_SUPPORT_NDP_BAM=y From f2bc59a2265ace444fe2933978bc77017988d139 Mon Sep 17 00:00:00 2001 From: duckyduckG Date: Wed, 8 Oct 2025 15:33:07 +0500 Subject: [PATCH 198/356] platform: msm: qpnp-coincell: Use module_platform_driver --- drivers/platform/msm/qpnp-coincell.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/platform/msm/qpnp-coincell.c b/drivers/platform/msm/qpnp-coincell.c index b427f43e76df..d8b570d2915b 100644 --- a/drivers/platform/msm/qpnp-coincell.c +++ b/drivers/platform/msm/qpnp-coincell.c @@ -266,18 +266,7 @@ static struct platform_driver qpnp_coincell_driver = { .id_table = qpnp_coincell_id, }; -static int __init qpnp_coincell_init(void) -{ - return platform_driver_register(&qpnp_coincell_driver); -} - -static void __exit qpnp_coincell_exit(void) -{ - platform_driver_unregister(&qpnp_coincell_driver); -} +module_platform_driver(qpnp_coincell_driver); MODULE_DESCRIPTION("QPNP PMIC coincell charger driver"); MODULE_LICENSE("GPL v2"); - -module_init(qpnp_coincell_init); -module_exit(qpnp_coincell_exit); From d4f498c211a0510f4cbcac7fb5210c1ac8f4c2de Mon Sep 17 00:00:00 2001 From: duckyduckG Date: Sat, 11 Oct 2025 15:05:18 +0500 Subject: [PATCH 199/356] net: add rmnet_data driver taken from msm 4.14 as of 'commit ("net: rmnet_data: ignore pkts coming with wrong epconfig")' also update for kernel 4.19 --- include/net/rmnet_config.h | 7 + include/uapi/linux/net_map.h | 8 + net/Kconfig | 1 + net/Makefile | 1 + net/rmnet_data/Kconfig | 29 + net/rmnet_data/Makefile | 14 + net/rmnet_data/rmnet_data_config.c | 1301 ++++++++++++++++++++++++++ net/rmnet_data/rmnet_data_config.h | 132 +++ net/rmnet_data/rmnet_data_handlers.c | 771 +++++++++++++++ net/rmnet_data/rmnet_data_handlers.h | 23 + net/rmnet_data/rmnet_data_main.c | 59 ++ net/rmnet_data/rmnet_data_private.h | 76 ++ net/rmnet_data/rmnet_data_stats.c | 119 +++ net/rmnet_data/rmnet_data_stats.h | 62 ++ net/rmnet_data/rmnet_data_trace.h | 358 +++++++ net/rmnet_data/rmnet_data_vnd.c | 1061 +++++++++++++++++++++ net/rmnet_data/rmnet_data_vnd.h | 37 + net/rmnet_data/rmnet_map.h | 153 +++ net/rmnet_data/rmnet_map_command.c | 205 ++++ net/rmnet_data/rmnet_map_data.c | 781 ++++++++++++++++ 20 files changed, 5198 insertions(+) create mode 100644 include/uapi/linux/net_map.h create mode 100644 net/rmnet_data/Kconfig create mode 100644 net/rmnet_data/Makefile create mode 100644 net/rmnet_data/rmnet_data_config.c create mode 100644 net/rmnet_data/rmnet_data_config.h create mode 100644 net/rmnet_data/rmnet_data_handlers.c create mode 100644 net/rmnet_data/rmnet_data_handlers.h create mode 100644 net/rmnet_data/rmnet_data_main.c create mode 100644 net/rmnet_data/rmnet_data_private.h create mode 100644 net/rmnet_data/rmnet_data_stats.c create mode 100644 net/rmnet_data/rmnet_data_stats.h create mode 100644 net/rmnet_data/rmnet_data_trace.h create mode 100644 net/rmnet_data/rmnet_data_vnd.c create mode 100644 net/rmnet_data/rmnet_data_vnd.h create mode 100644 net/rmnet_data/rmnet_map.h create mode 100644 net/rmnet_data/rmnet_map_command.c create mode 100644 net/rmnet_data/rmnet_map_data.c diff --git a/include/net/rmnet_config.h b/include/net/rmnet_config.h index 051ddc62d735..2d7d02d5c62b 100644 --- a/include/net/rmnet_config.h +++ b/include/net/rmnet_config.h @@ -7,6 +7,13 @@ #ifndef _RMNET_CONFIG_H_ #define _RMNET_CONFIG_H_ +#include + +struct rmnet_phys_ep_conf_s { + void (*recycle)(struct sk_buff *); /* Destruct function */ + void *config; +}; + struct rmnet_map_header_s { #ifndef RMNET_USE_BIG_ENDIAN_STRUCTS uint8_t pad_len:6; diff --git a/include/uapi/linux/net_map.h b/include/uapi/linux/net_map.h new file mode 100644 index 000000000000..a5d6d589db19 --- /dev/null +++ b/include/uapi/linux/net_map.h @@ -0,0 +1,8 @@ +#ifndef _NET_MAP_H_ +#define _NET_MAP_H_ + +#define RMNET_IP_VER_MASK 0xF0 +#define RMNET_IPV4 0x40 +#define RMNET_IPV6 0x60 + +#endif /* _NET_MAP_H_ */ diff --git a/net/Kconfig b/net/Kconfig index 2ba11ce2bf12..256934bec52b 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -234,6 +234,7 @@ source "net/switchdev/Kconfig" source "net/l3mdev/Kconfig" source "net/qrtr/Kconfig" source "net/ncsi/Kconfig" +source "net/rmnet_data/Kconfig" config RPS bool diff --git a/net/Makefile b/net/Makefile index 177b6fbac29c..b2a2f3b72a67 100644 --- a/net/Makefile +++ b/net/Makefile @@ -86,3 +86,4 @@ endif obj-$(CONFIG_QRTR) += qrtr/ obj-$(CONFIG_NET_NCSI) += ncsi/ obj-$(CONFIG_XDP_SOCKETS) += xdp/ +obj-$(CONFIG_RMNET_DATA) += rmnet_data/ diff --git a/net/rmnet_data/Kconfig b/net/rmnet_data/Kconfig new file mode 100644 index 000000000000..36d581771cb9 --- /dev/null +++ b/net/rmnet_data/Kconfig @@ -0,0 +1,29 @@ +# +# RMNET Data and MAP driver +# + +menuconfig RMNET_DATA + depends on NETDEVICES + bool "RmNet Data and MAP driver" + ---help--- + If you say Y here, then the rmnet_data module will be statically + compiled into the kernel. The rmnet data module provides MAP + functionality for embedded and bridged traffic. +if RMNET_DATA + +config RMNET_DATA_FC + bool "RmNet Data Flow Control" + depends on NET_SCHED && NET_SCH_PRIO + ---help--- + Say Y here if you want RmNet data to handle in-band flow control and + ioctl based flow control. This depends on net scheduler and prio queue + capability being present in the kernel. In-band flow control requires + MAP protocol be used. +config RMNET_DATA_DEBUG_PKT + bool "Packet Debug Logging" + ---help--- + Say Y here if you want RmNet data to be able to log packets in main + system log. This should not be enabled on production builds as it can + impact system performance. Note that simply enabling it here will not + enable the logging; it must be enabled at run-time as well. +endif # RMNET_DATA diff --git a/net/rmnet_data/Makefile b/net/rmnet_data/Makefile new file mode 100644 index 000000000000..ccb8b5b76d6c --- /dev/null +++ b/net/rmnet_data/Makefile @@ -0,0 +1,14 @@ +# +# Makefile for the RMNET Data module +# + +rmnet_data-y := rmnet_data_main.o +rmnet_data-y += rmnet_data_config.o +rmnet_data-y += rmnet_data_vnd.o +rmnet_data-y += rmnet_data_handlers.o +rmnet_data-y += rmnet_map_data.o +rmnet_data-y += rmnet_map_command.o +rmnet_data-y += rmnet_data_stats.o +obj-$(CONFIG_RMNET_DATA) += rmnet_data.o + +CFLAGS_rmnet_data_main.o := -I$(src) diff --git a/net/rmnet_data/rmnet_data_config.c b/net/rmnet_data/rmnet_data_config.c new file mode 100644 index 000000000000..c117e506d36e --- /dev/null +++ b/net/rmnet_data/rmnet_data_config.c @@ -0,0 +1,1301 @@ +/* Copyright (c) 2013-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. + * + * RMNET Data configuration engine + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "rmnet_data_config.h" +#include "rmnet_data_handlers.h" +#include "rmnet_data_vnd.h" +#include "rmnet_data_private.h" +#include "rmnet_data_trace.h" +#include "rmnet_map.h" + +RMNET_LOG_MODULE(RMNET_DATA_LOGMASK_CONFIG); + +/* Local Definitions and Declarations */ +static struct sock *nl_socket_handle; + +#ifndef RMNET_KERNEL_PRE_3_8 +static struct netlink_kernel_cfg rmnet_netlink_cfg = { + .input = rmnet_config_netlink_msg_handler +}; +#endif + +static struct notifier_block rmnet_dev_notifier = { + .notifier_call = rmnet_config_notify_cb, + .next = 0, + .priority = 0 +}; + +struct rmnet_free_vnd_work { + struct work_struct work; + int vnd_id[RMNET_DATA_MAX_VND]; + int count; +}; + +/* Init and Cleanup */ + +#ifdef RMNET_KERNEL_PRE_3_8 +static struct sock *_rmnet_config_start_netlink(void) +{ + return netlink_kernel_create(&init_net, + RMNET_NETLINK_PROTO, + 0, + rmnet_config_netlink_msg_handler, + NULL, + THIS_MODULE); +} +#else +static struct sock *_rmnet_config_start_netlink(void) +{ + return netlink_kernel_create(&init_net, + RMNET_NETLINK_PROTO, + &rmnet_netlink_cfg); +} +#endif /* RMNET_KERNEL_PRE_3_8 */ + +/* rmnet_config_init() - Startup init + * + * Registers netlink protocol with kernel and opens socket. Netlink handler is + * registered with kernel. + */ +int rmnet_config_init(void) +{ + int rc; + + nl_socket_handle = _rmnet_config_start_netlink(); + if (!nl_socket_handle) { + LOGE("%s", "Failed to init netlink socket"); + return RMNET_INIT_ERROR; + } + + rc = register_netdevice_notifier(&rmnet_dev_notifier); + if (rc != 0) { + LOGE("Failed to register device notifier; rc=%d", rc); + /* TODO: Cleanup the nl socket */ + return RMNET_INIT_ERROR; + } + + return 0; +} + +/* rmnet_config_exit() - Cleans up all netlink related resources */ +void rmnet_config_exit(void) +{ + int rc; + + netlink_kernel_release(nl_socket_handle); + rc = unregister_netdevice_notifier(&rmnet_dev_notifier); + if (rc != 0) + LOGE("Failed to unregister device notifier; rc=%d", rc); +} + +/* Helper Functions */ + +/* _rmnet_is_physical_endpoint_associated() - Determines if device is associated + * @dev: Device to get check + * + * Compares device rx_handler callback pointer against known function + * + * Return: + * - 1 if associated + * - 0 if NOT associated + */ +static inline int _rmnet_is_physical_endpoint_associated(struct net_device *dev) +{ + rx_handler_func_t *rx_handler; + + rx_handler = rcu_dereference(dev->rx_handler); + + if (rx_handler == rmnet_data_rx_handler) + return 1; + else + return 0; +} + +/* _rmnet_get_phys_ep_config() - Get physical ep config for an associated device + * @dev: Device to get endpoint configuration from + * + * Return: + * - pointer to configuration if successful + * - 0 (null) if device is not associated + */ +struct rmnet_phys_ep_config *_rmnet_get_phys_ep_config + (struct net_device *dev) +{ + struct rmnet_phys_ep_conf_s *_rmnet_phys_ep_config; + + if (_rmnet_is_physical_endpoint_associated(dev)) { + _rmnet_phys_ep_config = (struct rmnet_phys_ep_conf_s *) + rcu_dereference(dev->rx_handler_data); + if (_rmnet_phys_ep_config && _rmnet_phys_ep_config->config) + return (struct rmnet_phys_ep_config *) + _rmnet_phys_ep_config->config; + else + return 0; + } else { + return 0; + } +} + +/* _rmnet_get_logical_ep() - Gets the logical end point configuration + * structure for a network device + * @dev: Device to get endpoint configuration from + * @config_id: Logical endpoint id on device + * Retrieves the logical_endpoint_config structure. + * + * Return: + * - End point configuration structure + * - NULL in case of an error + */ +struct rmnet_logical_ep_conf_s *_rmnet_get_logical_ep(struct net_device *dev, + int config_id) +{ + struct rmnet_phys_ep_config *config; + struct rmnet_logical_ep_conf_s *epconfig_l; + + if (rmnet_vnd_is_vnd(dev)) { + epconfig_l = rmnet_vnd_get_le_config(dev); + } else { + config = _rmnet_get_phys_ep_config(dev); + + if (!config) + return NULL; + + if (config_id == RMNET_LOCAL_LOGICAL_ENDPOINT) + epconfig_l = &config->local_ep; + else + epconfig_l = &config->muxed_ep[config_id]; + } + + return epconfig_l; +} + +/* Netlink Handler */ +static void _rmnet_netlink_set_link_egress_data_format + (struct rmnet_nl_msg_s *rmnet_header, + struct rmnet_nl_msg_s *resp_rmnet) +{ + struct net_device *dev; + + if (!rmnet_header || !resp_rmnet) + return; + + resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNCODE; + dev = dev_get_by_name(&init_net, rmnet_header->data_format.dev); + + if (!dev) { + resp_rmnet->return_code = RMNET_CONFIG_NO_SUCH_DEVICE; + return; + } + + resp_rmnet->return_code = + rmnet_set_egress_data_format(dev, + rmnet_header->data_format.flags, + rmnet_header->data_format.agg_size, + rmnet_header->data_format.agg_count + ); + dev_put(dev); +} + +static void _rmnet_netlink_set_link_ingress_data_format + (struct rmnet_nl_msg_s *rmnet_header, + struct rmnet_nl_msg_s *resp_rmnet) +{ + struct net_device *dev; + + if (!rmnet_header || !resp_rmnet) + return; + + resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNCODE; + + dev = dev_get_by_name(&init_net, rmnet_header->data_format.dev); + if (!dev) { + resp_rmnet->return_code = RMNET_CONFIG_NO_SUCH_DEVICE; + return; + } + + resp_rmnet->return_code = rmnet_set_ingress_data_format( + dev, + rmnet_header->data_format.flags, + rmnet_header->data_format.tail_spacing); + dev_put(dev); +} + +static void _rmnet_netlink_set_logical_ep_config + (struct rmnet_nl_msg_s *rmnet_header, + struct rmnet_nl_msg_s *resp_rmnet) +{ + struct net_device *dev, *dev2; + + if (!rmnet_header || !resp_rmnet) + return; + + resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNCODE; + if (rmnet_header->local_ep_config.ep_id < -1 || + rmnet_header->local_ep_config.ep_id > 254) { + resp_rmnet->return_code = RMNET_CONFIG_BAD_ARGUMENTS; + return; + } + + dev = dev_get_by_name(&init_net, + rmnet_header->local_ep_config.dev); + + dev2 = dev_get_by_name(&init_net, + rmnet_header->local_ep_config.next_dev); + + if (dev && dev2) + resp_rmnet->return_code = + rmnet_set_logical_endpoint_config( + dev, + rmnet_header->local_ep_config.ep_id, + rmnet_header->local_ep_config.operating_mode, + dev2); + else + resp_rmnet->return_code = RMNET_CONFIG_NO_SUCH_DEVICE; + + if (dev) + dev_put(dev); + if (dev2) + dev_put(dev2); +} + +static void _rmnet_netlink_unset_logical_ep_config + (struct rmnet_nl_msg_s *rmnet_header, + struct rmnet_nl_msg_s *resp_rmnet) +{ + struct net_device *dev; + + if (!rmnet_header || !resp_rmnet) + return; + + resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNCODE; + if (rmnet_header->local_ep_config.ep_id < -1 || + rmnet_header->local_ep_config.ep_id > 254) { + resp_rmnet->return_code = RMNET_CONFIG_BAD_ARGUMENTS; + return; + } + + dev = dev_get_by_name(&init_net, + rmnet_header->local_ep_config.dev); + + if (dev) { + resp_rmnet->return_code = + rmnet_unset_logical_endpoint_config( + dev, + rmnet_header->local_ep_config.ep_id); + dev_put(dev); + } else { + resp_rmnet->return_code = RMNET_CONFIG_NO_SUCH_DEVICE; + } +} + +static void _rmnet_netlink_get_logical_ep_config + (struct rmnet_nl_msg_s *rmnet_header, + struct rmnet_nl_msg_s *resp_rmnet) +{ + struct net_device *dev; + + if (!rmnet_header || !resp_rmnet) + return; + + resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNCODE; + if (rmnet_header->local_ep_config.ep_id < -1 || + rmnet_header->local_ep_config.ep_id > 254) { + resp_rmnet->return_code = RMNET_CONFIG_BAD_ARGUMENTS; + return; + } + + dev = dev_get_by_name(&init_net, + rmnet_header->local_ep_config.dev); + + if (dev) { + resp_rmnet->return_code = + rmnet_get_logical_endpoint_config( + dev, + rmnet_header->local_ep_config.ep_id, + &resp_rmnet->local_ep_config.operating_mode, + resp_rmnet->local_ep_config.next_dev, + sizeof(resp_rmnet->local_ep_config.next_dev)); + } else { + resp_rmnet->return_code = RMNET_CONFIG_NO_SUCH_DEVICE; + return; + } + + if (resp_rmnet->return_code == RMNET_CONFIG_OK) { + /* Begin Data */ + resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNDATA; + resp_rmnet->arg_length = sizeof(((struct rmnet_nl_msg_s *)0) + ->local_ep_config); + } + dev_put(dev); +} + +static void _rmnet_netlink_associate_network_device + (struct rmnet_nl_msg_s *rmnet_header, + struct rmnet_nl_msg_s *resp_rmnet) +{ + struct net_device *dev; + + if (!rmnet_header || !resp_rmnet) + return; + + resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNCODE; + + dev = dev_get_by_name(&init_net, rmnet_header->data); + if (!dev) { + resp_rmnet->return_code = RMNET_CONFIG_NO_SUCH_DEVICE; + return; + } + + resp_rmnet->return_code = rmnet_associate_network_device(dev); + dev_put(dev); +} + +static void _rmnet_netlink_unassociate_network_device + (struct rmnet_nl_msg_s *rmnet_header, + struct rmnet_nl_msg_s *resp_rmnet) +{ + struct net_device *dev; + + if (!rmnet_header || !resp_rmnet) + return; + + resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNCODE; + + dev = dev_get_by_name(&init_net, rmnet_header->data); + if (!dev) { + resp_rmnet->return_code = RMNET_CONFIG_NO_SUCH_DEVICE; + return; + } + + resp_rmnet->return_code = rmnet_unassociate_network_device(dev); + dev_put(dev); +} + +static void _rmnet_netlink_get_network_device_associated + (struct rmnet_nl_msg_s *rmnet_header, + struct rmnet_nl_msg_s *resp_rmnet) +{ + struct net_device *dev; + + if (!rmnet_header || !resp_rmnet) + return; + + resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNCODE; + + dev = dev_get_by_name(&init_net, rmnet_header->data); + if (!dev) { + resp_rmnet->return_code = RMNET_CONFIG_NO_SUCH_DEVICE; + return; + } + + resp_rmnet->return_code = _rmnet_is_physical_endpoint_associated(dev); + resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNDATA; + dev_put(dev); +} + +static void _rmnet_netlink_get_link_egress_data_format + (struct rmnet_nl_msg_s *rmnet_header, + struct rmnet_nl_msg_s *resp_rmnet) +{ + struct net_device *dev; + struct rmnet_phys_ep_config *config; + + if (!rmnet_header || !resp_rmnet) + return; + + resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNCODE; + + dev = dev_get_by_name(&init_net, rmnet_header->data_format.dev); + if (!dev) { + resp_rmnet->return_code = RMNET_CONFIG_NO_SUCH_DEVICE; + return; + } + + config = _rmnet_get_phys_ep_config(dev); + if (!config) { + resp_rmnet->return_code = RMNET_CONFIG_INVALID_REQUEST; + dev_put(dev); + return; + } + + /* Begin Data */ + resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNDATA; + resp_rmnet->arg_length = sizeof(((struct rmnet_nl_msg_s *)0) + ->data_format); + resp_rmnet->data_format.flags = config->egress_data_format; + resp_rmnet->data_format.agg_count = config->egress_agg_count; + resp_rmnet->data_format.agg_size = config->egress_agg_size; + dev_put(dev); +} + +static void _rmnet_netlink_get_link_ingress_data_format + (struct rmnet_nl_msg_s *rmnet_header, + struct rmnet_nl_msg_s *resp_rmnet) +{ + struct net_device *dev; + struct rmnet_phys_ep_config *config; + + if (!rmnet_header || !resp_rmnet) + return; + + resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNCODE; + + dev = dev_get_by_name(&init_net, rmnet_header->data_format.dev); + if (!dev) { + resp_rmnet->return_code = RMNET_CONFIG_NO_SUCH_DEVICE; + return; + } + + config = _rmnet_get_phys_ep_config(dev); + if (!config) { + resp_rmnet->return_code = RMNET_CONFIG_INVALID_REQUEST; + dev_put(dev); + return; + } + + /* Begin Data */ + resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNDATA; + resp_rmnet->arg_length = sizeof(((struct rmnet_nl_msg_s *)0) + ->data_format); + resp_rmnet->data_format.flags = config->ingress_data_format; + resp_rmnet->data_format.tail_spacing = config->tail_spacing; + dev_put(dev); +} + +static void _rmnet_netlink_get_vnd_name + (struct rmnet_nl_msg_s *rmnet_header, + struct rmnet_nl_msg_s *resp_rmnet) +{ + int r; + + if (!rmnet_header || !resp_rmnet) + return; + + resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNCODE; + + r = rmnet_vnd_get_name(rmnet_header->vnd.id, resp_rmnet->vnd.vnd_name, + RMNET_MAX_STR_LEN); + + if (r != 0) { + resp_rmnet->return_code = RMNET_CONFIG_INVALID_REQUEST; + return; + } + + /* Begin Data */ + resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNDATA; + resp_rmnet->arg_length = sizeof(((struct rmnet_nl_msg_s *)0)->vnd); +} + +static void _rmnet_netlink_add_del_vnd_tc_flow + (u32 command, + struct rmnet_nl_msg_s *rmnet_header, + struct rmnet_nl_msg_s *resp_rmnet) +{ + u32 id; + u32 map_flow_id; + u32 tc_flow_id; + + if (!rmnet_header || !resp_rmnet) + return; + + resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNCODE; + + id = rmnet_header->flow_control.id; + map_flow_id = rmnet_header->flow_control.map_flow_id; + tc_flow_id = rmnet_header->flow_control.tc_flow_id; + + switch (command) { + case RMNET_NETLINK_ADD_VND_TC_FLOW: + resp_rmnet->return_code = rmnet_vnd_add_tc_flow(id, + map_flow_id, + tc_flow_id); + break; + case RMNET_NETLINK_DEL_VND_TC_FLOW: + resp_rmnet->return_code = rmnet_vnd_del_tc_flow(id, + map_flow_id, + tc_flow_id); + break; + default: + LOGM("Called with unhandled command %d", command); + resp_rmnet->return_code = RMNET_CONFIG_INVALID_REQUEST; + break; + } +} + +/* rmnet_config_netlink_msg_handler() - Netlink message handler callback + * @skb: Packet containing netlink messages + * + * Standard kernel-expected format for a netlink message handler. Processes SKBs + * which contain RmNet data specific netlink messages. + */ +void rmnet_config_netlink_msg_handler(struct sk_buff *skb) +{ + struct nlmsghdr *nlmsg_header, *resp_nlmsg; + struct rmnet_nl_msg_s *rmnet_header, *resp_rmnet; + int return_pid, response_data_length; + struct sk_buff *skb_response; + + response_data_length = 0; + nlmsg_header = (struct nlmsghdr *)skb->data; + rmnet_header = (struct rmnet_nl_msg_s *)nlmsg_data(nlmsg_header); + + if (!nlmsg_header->nlmsg_pid || + (nlmsg_header->nlmsg_len < sizeof(struct nlmsghdr) + + sizeof(struct rmnet_nl_msg_s))) + return; + + LOGL("Netlink message pid=%d, seq=%d, length=%d, rmnet_type=%d", + nlmsg_header->nlmsg_pid, + nlmsg_header->nlmsg_seq, + nlmsg_header->nlmsg_len, + rmnet_header->message_type); + + return_pid = nlmsg_header->nlmsg_pid; + + skb_response = nlmsg_new(sizeof(struct nlmsghdr) + + sizeof(struct rmnet_nl_msg_s), + GFP_KERNEL); + + if (!skb_response) { + LOGH("%s", "Failed to allocate response buffer"); + return; + } + + resp_nlmsg = nlmsg_put(skb_response, + 0, + nlmsg_header->nlmsg_seq, + NLMSG_DONE, + sizeof(struct rmnet_nl_msg_s), + 0); + + resp_rmnet = nlmsg_data(resp_nlmsg); + + if (!resp_rmnet) + return; + + resp_rmnet->message_type = rmnet_header->message_type; + rtnl_lock(); + switch (rmnet_header->message_type) { + case RMNET_NETLINK_ASSOCIATE_NETWORK_DEVICE: + _rmnet_netlink_associate_network_device + (rmnet_header, resp_rmnet); + break; + + case RMNET_NETLINK_UNASSOCIATE_NETWORK_DEVICE: + _rmnet_netlink_unassociate_network_device + (rmnet_header, resp_rmnet); + break; + + case RMNET_NETLINK_GET_NETWORK_DEVICE_ASSOCIATED: + _rmnet_netlink_get_network_device_associated + (rmnet_header, resp_rmnet); + break; + + case RMNET_NETLINK_SET_LINK_EGRESS_DATA_FORMAT: + _rmnet_netlink_set_link_egress_data_format + (rmnet_header, resp_rmnet); + break; + + case RMNET_NETLINK_GET_LINK_EGRESS_DATA_FORMAT: + _rmnet_netlink_get_link_egress_data_format + (rmnet_header, resp_rmnet); + break; + + case RMNET_NETLINK_SET_LINK_INGRESS_DATA_FORMAT: + _rmnet_netlink_set_link_ingress_data_format + (rmnet_header, resp_rmnet); + break; + + case RMNET_NETLINK_GET_LINK_INGRESS_DATA_FORMAT: + _rmnet_netlink_get_link_ingress_data_format + (rmnet_header, resp_rmnet); + break; + + case RMNET_NETLINK_SET_LOGICAL_EP_CONFIG: + _rmnet_netlink_set_logical_ep_config(rmnet_header, resp_rmnet); + break; + + case RMNET_NETLINK_UNSET_LOGICAL_EP_CONFIG: + _rmnet_netlink_unset_logical_ep_config(rmnet_header, + resp_rmnet); + break; + + case RMNET_NETLINK_GET_LOGICAL_EP_CONFIG: + _rmnet_netlink_get_logical_ep_config(rmnet_header, resp_rmnet); + break; + + case RMNET_NETLINK_NEW_VND: + resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNCODE; + resp_rmnet->return_code = + rmnet_create_vnd(rmnet_header->vnd.id); + break; + + case RMNET_NETLINK_NEW_VND_WITH_PREFIX: + resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNCODE; + resp_rmnet->return_code = rmnet_create_vnd_prefix( + rmnet_header->vnd.id, + rmnet_header->vnd.vnd_name); + break; + + case RMNET_NETLINK_NEW_VND_WITH_NAME: + resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNCODE; + resp_rmnet->return_code = rmnet_create_vnd_name( + rmnet_header->vnd.id, + rmnet_header->vnd.vnd_name); + break; + + case RMNET_NETLINK_FREE_VND: + resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNCODE; + /* Please check rmnet_vnd_free_dev documentation regarding + * the below locking sequence + */ + rtnl_unlock(); + resp_rmnet->return_code = rmnet_free_vnd(rmnet_header->vnd.id); + rtnl_lock(); + break; + + case RMNET_NETLINK_GET_VND_NAME: + _rmnet_netlink_get_vnd_name(rmnet_header, resp_rmnet); + break; + + case RMNET_NETLINK_DEL_VND_TC_FLOW: + case RMNET_NETLINK_ADD_VND_TC_FLOW: + _rmnet_netlink_add_del_vnd_tc_flow(rmnet_header->message_type, + rmnet_header, + resp_rmnet); + break; + + default: + resp_rmnet->crd = RMNET_NETLINK_MSG_RETURNCODE; + resp_rmnet->return_code = RMNET_CONFIG_UNKNOWN_MESSAGE; + break; + } + rtnl_unlock(); + nlmsg_unicast(nl_socket_handle, skb_response, return_pid); + LOGD("%s", "Done processing command"); +} + +/* Configuration API */ + +/* rmnet_unassociate_network_device() - Unassociate network device + * @dev: Device to unassociate + * + * Frees all structures generate for device. Unregisters rx_handler + * todo: needs to do some sanity verification first (is device in use, etc...) + * + * Return: + * - RMNET_CONFIG_OK if successful + * - RMNET_CONFIG_NO_SUCH_DEVICE dev is null + * - RMNET_CONFIG_INVALID_REQUEST if device is not already associated + * - RMNET_CONFIG_DEVICE_IN_USE if device has logical ep that wasn't unset + * - RMNET_CONFIG_UNKNOWN_ERROR net_device private section is null + */ +int rmnet_unassociate_network_device(struct net_device *dev) +{ + struct rmnet_phys_ep_conf_s *config; + int config_id = RMNET_LOCAL_LOGICAL_ENDPOINT; + struct rmnet_logical_ep_conf_s *epconfig_l; + + ASSERT_RTNL(); + + LOGL("(%s);", dev->name); + + if (!dev) + return RMNET_CONFIG_NO_SUCH_DEVICE; + + if (!_rmnet_is_physical_endpoint_associated(dev)) + return RMNET_CONFIG_INVALID_REQUEST; + + for (; config_id < RMNET_DATA_MAX_LOGICAL_EP; config_id++) { + epconfig_l = _rmnet_get_logical_ep(dev, config_id); + if (epconfig_l && epconfig_l->refcount) + return RMNET_CONFIG_DEVICE_IN_USE; + } + + config = (struct rmnet_phys_ep_conf_s *) + rcu_dereference(dev->rx_handler_data); + + if (!config) + return RMNET_CONFIG_UNKNOWN_ERROR; + + kfree(config); + + netdev_rx_handler_unregister(dev); + + /* Explicitly release the reference from the device */ + dev_put(dev); + trace_rmnet_unassociate(dev); + return RMNET_CONFIG_OK; +} + +/* rmnet_set_ingress_data_format() - Set ingress data format on network device + * @dev: Device to ingress data format on + * @egress_data_format: 32-bit unsigned bitmask of ingress format + * + * Network device must already have association with RmNet Data driver + * + * Return: + * - RMNET_CONFIG_OK if successful + * - RMNET_CONFIG_NO_SUCH_DEVICE dev is null + * - RMNET_CONFIG_UNKNOWN_ERROR net_device private section is null + */ +int rmnet_set_ingress_data_format(struct net_device *dev, + u32 ingress_data_format, + uint8_t tail_spacing) +{ + struct rmnet_phys_ep_config *config; + + ASSERT_RTNL(); + + LOGL("(%s,0x%08X);", dev->name, ingress_data_format); + + if (!dev) + return RMNET_CONFIG_NO_SUCH_DEVICE; + + config = _rmnet_get_phys_ep_config(dev); + + if (!config) + return RMNET_CONFIG_INVALID_REQUEST; + + config->ingress_data_format = ingress_data_format; + config->tail_spacing = tail_spacing; + + return RMNET_CONFIG_OK; +} + +/* rmnet_set_egress_data_format() - Set egress data format on network device + * @dev: Device to egress data format on + * @egress_data_format: 32-bit unsigned bitmask of egress format + * + * Network device must already have association with RmNet Data driver + * todo: Bounds check on agg_* + * + * Return: + * - RMNET_CONFIG_OK if successful + * - RMNET_CONFIG_NO_SUCH_DEVICE dev is null + * - RMNET_CONFIG_UNKNOWN_ERROR net_device private section is null + */ +int rmnet_set_egress_data_format(struct net_device *dev, + u32 egress_data_format, + u16 agg_size, + u16 agg_count) +{ + struct rmnet_phys_ep_config *config; + + ASSERT_RTNL(); + + LOGL("(%s,0x%08X, %d, %d);", + dev->name, egress_data_format, agg_size, agg_count); + + if (!dev) + return RMNET_CONFIG_NO_SUCH_DEVICE; + + config = _rmnet_get_phys_ep_config(dev); + + if (!config) + return RMNET_CONFIG_UNKNOWN_ERROR; + + config->egress_data_format = egress_data_format; + config->egress_agg_size = agg_size; + config->egress_agg_count = agg_count; + + return RMNET_CONFIG_OK; +} + +/* rmnet_associate_network_device() - Associate network device + * @dev: Device to register with RmNet data + * + * Typically used on physical network devices. Registers RX handler and private + * metadata structures. + * + * Return: + * - RMNET_CONFIG_OK if successful + * - RMNET_CONFIG_NO_SUCH_DEVICE dev is null + * - RMNET_CONFIG_INVALID_REQUEST if the device to be associated is a vnd + * - RMNET_CONFIG_DEVICE_IN_USE if dev rx_handler is already filled + * - RMNET_CONFIG_DEVICE_IN_USE if netdev_rx_handler_register() fails + */ +int rmnet_associate_network_device(struct net_device *dev) +{ + struct rmnet_phys_ep_conf_s *config; + struct rmnet_phys_ep_config *conf; + int rc; + + ASSERT_RTNL(); + + LOGL("(%s);\n", dev->name); + + if (!dev) + return RMNET_CONFIG_NO_SUCH_DEVICE; + + if (_rmnet_is_physical_endpoint_associated(dev)) { + LOGM("%s is already regestered", dev->name); + return RMNET_CONFIG_DEVICE_IN_USE; + } + + if (rmnet_vnd_is_vnd(dev)) { + LOGM("%s is a vnd", dev->name); + return RMNET_CONFIG_INVALID_REQUEST; + } + + config = kmalloc(sizeof(*config), GFP_ATOMIC); + conf = kmalloc(sizeof(*conf), GFP_ATOMIC); + + if (!config || !conf) + return RMNET_CONFIG_NOMEM; + + memset(config, 0, sizeof(struct rmnet_phys_ep_conf_s)); + memset(conf, 0, sizeof(struct rmnet_phys_ep_config)); + + config->config = conf; + conf->dev = dev; + spin_lock_init(&conf->agg_lock); + config->recycle = kfree_skb; + hrtimer_init(&conf->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + conf->hrtimer.function = rmnet_map_flush_packet_queue; + rc = netdev_rx_handler_register(dev, rmnet_data_rx_handler, config); + + if (rc) { + LOGM("netdev_rx_handler_register returns %d", rc); + kfree(config); + kfree(conf); + return RMNET_CONFIG_DEVICE_IN_USE; + } + + /* Explicitly hold a reference to the device */ + dev_hold(dev); + trace_rmnet_associate(dev); + return RMNET_CONFIG_OK; +} + +/* _rmnet_set_logical_endpoint_config() - Set logical endpoing config on device + * @dev: Device to set endpoint configuration on + * @config_id: logical endpoint id on device + * @epconfig: endpoing configuration structure to set + * + * Return: + * - RMNET_CONFIG_OK if successful + * - RMNET_CONFIG_UNKNOWN_ERROR net_device private section is null + * - RMNET_CONFIG_NO_SUCH_DEVICE if device to set config on is null + * - RMNET_CONFIG_DEVICE_IN_USE if device already has a logical ep + * - RMNET_CONFIG_BAD_ARGUMENTS if logical endpoint id is out of range + */ +int _rmnet_set_logical_endpoint_config(struct net_device *dev, + int config_id, + struct rmnet_logical_ep_conf_s *epconfig) +{ + struct rmnet_logical_ep_conf_s *epconfig_l; + + ASSERT_RTNL(); + + if (!dev) + return RMNET_CONFIG_NO_SUCH_DEVICE; + + if (config_id < RMNET_LOCAL_LOGICAL_ENDPOINT || + config_id >= RMNET_DATA_MAX_LOGICAL_EP) + return RMNET_CONFIG_BAD_ARGUMENTS; + + epconfig_l = _rmnet_get_logical_ep(dev, config_id); + + if (!epconfig_l) + return RMNET_CONFIG_UNKNOWN_ERROR; + + if (epconfig_l->refcount) + return RMNET_CONFIG_DEVICE_IN_USE; + + memcpy(epconfig_l, epconfig, sizeof(struct rmnet_logical_ep_conf_s)); + if (config_id == RMNET_LOCAL_LOGICAL_ENDPOINT) + epconfig_l->mux_id = 0; + else + epconfig_l->mux_id = config_id; + + /* Explicitly hold a reference to the egress device */ + dev_hold(epconfig_l->egress_dev); + return RMNET_CONFIG_OK; +} + +/* _rmnet_unset_logical_endpoint_config() - Un-set the logical endpoing config + * on device + * @dev: Device to set endpoint configuration on + * @config_id: logical endpoint id on device + * + * Return: + * - RMNET_CONFIG_OK if successful + * - RMNET_CONFIG_UNKNOWN_ERROR net_device private section is null + * - RMNET_CONFIG_NO_SUCH_DEVICE if device to set config on is null + * - RMNET_CONFIG_BAD_ARGUMENTS if logical endpoint id is out of range + */ +int _rmnet_unset_logical_endpoint_config(struct net_device *dev, + int config_id) +{ + struct rmnet_logical_ep_conf_s *epconfig_l = 0; + + ASSERT_RTNL(); + + if (!dev) + return RMNET_CONFIG_NO_SUCH_DEVICE; + + if (config_id < RMNET_LOCAL_LOGICAL_ENDPOINT || + config_id >= RMNET_DATA_MAX_LOGICAL_EP) + return RMNET_CONFIG_BAD_ARGUMENTS; + + epconfig_l = _rmnet_get_logical_ep(dev, config_id); + + if (!epconfig_l || !epconfig_l->refcount) + return RMNET_CONFIG_NO_SUCH_DEVICE; + + /* Explicitly release the reference from the egress device */ + dev_put(epconfig_l->egress_dev); + memset(epconfig_l, 0, sizeof(struct rmnet_logical_ep_conf_s)); + + return RMNET_CONFIG_OK; +} + +/* rmnet_set_logical_endpoint_config() - Set logical endpoint config on a device + * @dev: Device to set endpoint configuration on + * @config_id: logical endpoint id on device + * @rmnet_mode: endpoint mode. Values from: rmnet_config_endpoint_modes_e + * @egress_device: device node to forward packet to once done processing in + * ingress/egress handlers + * + * Creates a logical_endpoint_config structure and fills in the information from + * function arguments. Calls _rmnet_set_logical_endpoint_config() to finish + * configuration. Network device must already have association with RmNet Data + * driver + * + * Return: + * - RMNET_CONFIG_OK if successful + * - RMNET_CONFIG_BAD_EGRESS_DEVICE if egress device is null + * - RMNET_CONFIG_BAD_EGRESS_DEVICE if egress device is not handled by + * RmNet data module + * - RMNET_CONFIG_UNKNOWN_ERROR net_device private section is null + * - RMNET_CONFIG_NO_SUCH_DEVICE if device to set config on is null + * - RMNET_CONFIG_BAD_ARGUMENTS if logical endpoint id is out of range + */ +int rmnet_set_logical_endpoint_config(struct net_device *dev, + int config_id, + u8 rmnet_mode, + struct net_device *egress_dev) +{ + struct rmnet_logical_ep_conf_s epconfig; + + LOGL("(%s, %d, %d, %s);", + dev->name, config_id, rmnet_mode, egress_dev->name); + + if (!egress_dev || + ((!_rmnet_is_physical_endpoint_associated(egress_dev)) && + (!rmnet_vnd_is_vnd(egress_dev)))) { + return RMNET_CONFIG_BAD_EGRESS_DEVICE; + } + + memset(&epconfig, 0, sizeof(struct rmnet_logical_ep_conf_s)); + epconfig.refcount = 1; + epconfig.rmnet_mode = rmnet_mode; + epconfig.egress_dev = egress_dev; + + return _rmnet_set_logical_endpoint_config(dev, config_id, &epconfig); +} + +/* rmnet_unset_logical_endpoint_config() - Un-set logical endpoing configuration + * on a device + * @dev: Device to set endpoint configuration on + * @config_id: logical endpoint id on device + * + * Retrieves the logical_endpoint_config structure and frees the egress device. + * Network device must already have association with RmNet Data driver + * + * Return: + * - RMNET_CONFIG_OK if successful + * - RMNET_CONFIG_UNKNOWN_ERROR net_device private section is null + * - RMNET_CONFIG_NO_SUCH_DEVICE device is not associated + * - RMNET_CONFIG_BAD_ARGUMENTS if logical endpoint id is out of range + */ +int rmnet_unset_logical_endpoint_config(struct net_device *dev, + int config_id) +{ + LOGL("(%s, %d);", dev->name, config_id); + + if (!dev || ((!_rmnet_is_physical_endpoint_associated(dev)) && + (!rmnet_vnd_is_vnd(dev)))) { + return RMNET_CONFIG_NO_SUCH_DEVICE; + } + + return _rmnet_unset_logical_endpoint_config(dev, config_id); +} + +/* rmnet_get_logical_endpoint_config() - Gets logical endpoing configuration + * for a device + * @dev: Device to get endpoint configuration on + * @config_id: logical endpoint id on device + * @rmnet_mode: (I/O) logical endpoint mode + * @egress_dev_name: (I/O) logical endpoint egress device name + * @egress_dev_name_size: The maximal size of the I/O egress_dev_name + * + * Retrieves the logical_endpoint_config structure. + * Network device must already have association with RmNet Data driver + * + * Return: + * - RMNET_CONFIG_OK if successful + * - RMNET_CONFIG_UNKNOWN_ERROR net_device private section is null + * - RMNET_CONFIG_NO_SUCH_DEVICE device is not associated + * - RMNET_CONFIG_BAD_ARGUMENTS if logical endpoint id is out of range or + * if the provided buffer size for egress dev name is too short + */ +int rmnet_get_logical_endpoint_config(struct net_device *dev, + int config_id, + u8 *rmnet_mode, + u8 *egress_dev_name, + size_t egress_dev_name_size) +{ + struct rmnet_logical_ep_conf_s *epconfig_l = 0; + size_t strlcpy_res = 0; + + LOGL("(%s, %d);", dev->name, config_id); + + if (!egress_dev_name || !rmnet_mode) + return RMNET_CONFIG_BAD_ARGUMENTS; + if (config_id < RMNET_LOCAL_LOGICAL_ENDPOINT || + config_id >= RMNET_DATA_MAX_LOGICAL_EP) + return RMNET_CONFIG_BAD_ARGUMENTS; + + epconfig_l = _rmnet_get_logical_ep(dev, config_id); + + if (!epconfig_l || !epconfig_l->refcount) + return RMNET_CONFIG_NO_SUCH_DEVICE; + + *rmnet_mode = epconfig_l->rmnet_mode; + + strlcpy_res = strlcpy(egress_dev_name, epconfig_l->egress_dev->name, + egress_dev_name_size); + + if (strlcpy_res >= egress_dev_name_size) + return RMNET_CONFIG_BAD_ARGUMENTS; + + return RMNET_CONFIG_OK; +} + +/* rmnet_create_vnd() - Create virtual network device node + * @id: RmNet virtual device node id + * + * Return: + * - result of rmnet_vnd_create_dev() + */ +int rmnet_create_vnd(int id) +{ + struct net_device *dev; + + ASSERT_RTNL(); + LOGL("(%d);", id); + return rmnet_vnd_create_dev(id, &dev, NULL, 0); +} + +/* rmnet_create_vnd_prefix() - Create virtual network device node + * @id: RmNet virtual device node id + * @prefix: String prefix for device name + * + * Return: + * - result of rmnet_vnd_create_dev() + */ +int rmnet_create_vnd_prefix(int id, const char *prefix) +{ + struct net_device *dev; + + ASSERT_RTNL(); + LOGL("(%d, \"%s\");", id, prefix); + return rmnet_vnd_create_dev(id, &dev, prefix, 0); +} + +/** + * rmnet_create_vnd_name() - Create virtual network device node + * @id: RmNet virtual device node id + * @prefix: String prefix for device name + * + * Return: + * - result of rmnet_vnd_create_dev() + */ +int rmnet_create_vnd_name(int id, const char *name) +{ + struct net_device *dev; + + ASSERT_RTNL(); + LOGL("(%d, \"%s\");", id, name); + return rmnet_vnd_create_dev(id, &dev, name, 1); +} + +/* rmnet_free_vnd() - Free virtual network device node + * @id: RmNet virtual device node id + * + * Return: + * - result of rmnet_vnd_free_dev() + */ +int rmnet_free_vnd(int id) +{ + LOGL("(%d);", id); + return rmnet_vnd_free_dev(id); +} + +static void _rmnet_free_vnd_later(struct work_struct *work) +{ + int i; + struct rmnet_free_vnd_work *fwork; + + fwork = container_of(work, struct rmnet_free_vnd_work, work); + + for (i = 0; i < fwork->count; i++) + rmnet_free_vnd(fwork->vnd_id[i]); + kfree(fwork); +} + +/* rmnet_force_unassociate_device() - Force a device to unassociate + * @dev: Device to unassociate + * + * Return: + * - void + */ +static void rmnet_force_unassociate_device(struct net_device *dev) +{ + int i, j; + struct net_device *vndev; + struct rmnet_phys_ep_config *config; + struct rmnet_logical_ep_conf_s *cfg; + struct rmnet_free_vnd_work *vnd_work; + + ASSERT_RTNL(); + + if (!dev) + return; + + if (!_rmnet_is_physical_endpoint_associated(dev)) { + LOGM("%s", "Called on unassociated device, skipping"); + return; + } + + trace_rmnet_unregister_cb_clear_vnds(dev); + vnd_work = kmalloc(sizeof(*vnd_work), GFP_KERNEL); + if (!vnd_work) { + LOGH("%s", "Out of Memory"); + return; + } + INIT_WORK(&vnd_work->work, _rmnet_free_vnd_later); + vnd_work->count = 0; + + /* Check the VNDs for offending mappings */ + for (i = 0, j = 0; i < RMNET_DATA_MAX_VND && + j < RMNET_DATA_MAX_VND; i++) { + vndev = rmnet_vnd_get_by_id(i); + if (!vndev) { + LOGL("VND %d not in use; skipping", i); + continue; + } + cfg = rmnet_vnd_get_le_config(vndev); + if (!cfg) { + LOGH("Got NULL config from VND %d", i); + continue; + } + if (cfg->refcount && (cfg->egress_dev == dev)) { + /* Make sure the device is down before clearing any of + * the mappings. Otherwise we could see a potential + * race condition if packets are actively being + * transmitted. + */ + dev_close(vndev); + rmnet_unset_logical_endpoint_config + (vndev, RMNET_LOCAL_LOGICAL_ENDPOINT); + vnd_work->vnd_id[j] = i; + j++; + } + } + if (j > 0) { + vnd_work->count = j; + schedule_work(&vnd_work->work); + } else { + kfree(vnd_work); + } + + config = _rmnet_get_phys_ep_config(dev); + + if (config) { + unsigned long flags; + + hrtimer_cancel(&config->hrtimer); + spin_lock_irqsave(&config->agg_lock, flags); + if (config->agg_state == RMNET_MAP_TXFER_SCHEDULED) { + if (config->agg_skb) { + kfree_skb(config->agg_skb); + config->agg_skb = NULL; + config->agg_count = 0; + memset(&config->agg_time, 0, + sizeof(struct timespec)); + } + config->agg_state = RMNET_MAP_AGG_IDLE; + } + spin_unlock_irqrestore(&config->agg_lock, flags); + + cfg = &config->local_ep; + + if (cfg && cfg->refcount) + rmnet_unset_logical_endpoint_config + (cfg->egress_dev, RMNET_LOCAL_LOGICAL_ENDPOINT); + } + + /* Clear the mappings on the phys ep */ + trace_rmnet_unregister_cb_clear_lepcs(dev); + rmnet_unset_logical_endpoint_config(dev, RMNET_LOCAL_LOGICAL_ENDPOINT); + for (i = 0; i < RMNET_DATA_MAX_LOGICAL_EP; i++) + rmnet_unset_logical_endpoint_config(dev, i); + rmnet_unassociate_network_device(dev); +} + +/* rmnet_config_notify_cb() - Callback for netdevice notifier chain + * @nb: Notifier block data + * @event: Netdevice notifier event ID + * @data: Contains a net device for which we are getting notified + * + * Return: + * - result of NOTIFY_DONE() + */ +int rmnet_config_notify_cb(struct notifier_block *nb, + unsigned long event, void *data) +{ + struct net_device *dev = netdev_notifier_info_to_dev(data); + + if (!dev) + return NOTIFY_DONE; + + LOGL("(..., %lu, %s)", event, dev->name); + + switch (event) { + case NETDEV_UNREGISTER: + trace_rmnet_unregister_cb_entry(dev); + LOGH("Kernel is trying to unregister %s", dev->name); + rmnet_force_unassociate_device(dev); + trace_rmnet_unregister_cb_exit(dev); + break; + + default: + trace_rmnet_unregister_cb_unhandled(dev); + LOGD("Unhandeled event [%lu]", event); + break; + } + + return NOTIFY_DONE; +} diff --git a/net/rmnet_data/rmnet_data_config.h b/net/rmnet_data/rmnet_data_config.h new file mode 100644 index 000000000000..5e3a6cd1867f --- /dev/null +++ b/net/rmnet_data/rmnet_data_config.h @@ -0,0 +1,132 @@ +/* Copyright (c) 2013-2014, 2016-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. + * + * RMNET Data configuration engine + */ + +#include +#include +#include +#include +#include + +#ifndef _RMNET_DATA_CONFIG_H_ +#define _RMNET_DATA_CONFIG_H_ + +#define RMNET_DATA_MAX_LOGICAL_EP 256 + +/** + * struct rmnet_logical_ep_conf_s - Logical end-point configuration + * + * @refcount: Reference count for this endpoint. 0 signifies the endpoint is not + * configured for use + * @rmnet_mode: Specifies how the traffic should be finally delivered. Possible + * options are available in enum rmnet_config_endpoint_modes_e + * @mux_id: Virtual channel ID used by MAP protocol + * @egress_dev: Next device to deliver the packet to. Exact usage of this + * parmeter depends on the rmnet_mode + */ +struct rmnet_logical_ep_conf_s { + u8 refcount; + u8 rmnet_mode; + u8 mux_id; + struct timespec flush_time; + unsigned int flush_byte_count; + struct net_device *egress_dev; +}; + +/** + * struct rmnet_phys_ep_conf_s - Physical endpoint configuration + * One instance of this structure is instantiated for each net_device associated + * with rmnet_data. + * + * @dev: The device which is associated with rmnet_data. Corresponds to this + * specific instance of rmnet_phys_ep_conf_s + * @local_ep: Default non-muxed endpoint. Used for non-MAP protocols/formats + * @muxed_ep: All multiplexed logical endpoints associated with this device + * @ingress_data_format: RMNET_INGRESS_FORMAT_* flags from rmnet_data.h + * @egress_data_format: RMNET_EGRESS_FORMAT_* flags from rmnet_data.h + * + * @egress_agg_size: Maximum size (bytes) of data which should be aggregated + * @egress_agg_count: Maximum count (packets) of data which should be aggregated + * Smaller of the two parameters above are chosen for + * aggregation + * @tail_spacing: Guaranteed padding (bytes) when de-aggregating ingress frames + * @agg_time: Wall clock time when aggregated frame was created + * @agg_last: Last time the aggregation routing was invoked + */ +struct rmnet_phys_ep_config { + struct net_device *dev; + struct rmnet_logical_ep_conf_s local_ep; + struct rmnet_logical_ep_conf_s muxed_ep[RMNET_DATA_MAX_LOGICAL_EP]; + u32 ingress_data_format; + u32 egress_data_format; + + /* MAP specific */ + u16 egress_agg_size; + u16 egress_agg_count; + u8 tail_spacing; + /* MAP aggregation state machine + * - This is not sctrictly configuration and is updated at runtime + * Make sure all of these are protected by the agg_lock + */ + spinlock_t agg_lock; + struct sk_buff *agg_skb; + u8 agg_state; + u8 agg_count; + struct timespec agg_time; + struct timespec agg_last; + struct hrtimer hrtimer; +}; + +int rmnet_config_init(void); +void rmnet_config_exit(void); + +int rmnet_unassociate_network_device(struct net_device *dev); +int rmnet_set_ingress_data_format(struct net_device *dev, + u32 ingress_data_format, + u8 tail_spacing); +int rmnet_set_egress_data_format(struct net_device *dev, + u32 egress_data_format, + u16 agg_size, + u16 agg_count); +int rmnet_associate_network_device(struct net_device *dev); +int _rmnet_set_logical_endpoint_config + (struct net_device *dev, int config_id, + struct rmnet_logical_ep_conf_s *epconfig); +int rmnet_set_logical_endpoint_config(struct net_device *dev, + int config_id, + u8 rmnet_mode, + struct net_device *egress_dev); +int _rmnet_unset_logical_endpoint_config(struct net_device *dev, + int config_id); +int rmnet_unset_logical_endpoint_config(struct net_device *dev, + int config_id); +int _rmnet_get_logical_endpoint_config + (struct net_device *dev, int config_id, + struct rmnet_logical_ep_conf_s *epconfig); +int rmnet_get_logical_endpoint_config(struct net_device *dev, + int config_id, + u8 *rmnet_mode, + u8 *egress_dev_name, + size_t egress_dev_name_size); +void rmnet_config_netlink_msg_handler (struct sk_buff *skb); +int rmnet_config_notify_cb(struct notifier_block *nb, + unsigned long event, void *data); +int rmnet_create_vnd(int id); +int rmnet_create_vnd_prefix(int id, const char *name); +int rmnet_create_vnd_name(int id, const char *name); +int rmnet_free_vnd(int id); + +struct rmnet_phys_ep_config *_rmnet_get_phys_ep_config + (struct net_device *dev); + +#endif /* _RMNET_DATA_CONFIG_H_ */ diff --git a/net/rmnet_data/rmnet_data_handlers.c b/net/rmnet_data/rmnet_data_handlers.c new file mode 100644 index 000000000000..c26be78375f8 --- /dev/null +++ b/net/rmnet_data/rmnet_data_handlers.c @@ -0,0 +1,771 @@ +/* Copyright (c) 2013-2018, 2020 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. + * + * RMNET Data ingress/egress handler + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "rmnet_data_private.h" +#include "rmnet_data_config.h" +#include "rmnet_data_vnd.h" +#include "rmnet_map.h" +#include "rmnet_data_stats.h" +#include "rmnet_data_trace.h" +#include "rmnet_data_handlers.h" + +RMNET_LOG_MODULE(RMNET_DATA_LOGMASK_HANDLER); + +#ifdef CONFIG_RMNET_DATA_DEBUG_PKT +unsigned int dump_pkt_rx; +module_param(dump_pkt_rx, uint, 0644); +MODULE_PARM_DESC(dump_pkt_rx, "Dump packets entering ingress handler"); + +unsigned int dump_pkt_tx; +module_param(dump_pkt_tx, uint, 0644); +MODULE_PARM_DESC(dump_pkt_tx, "Dump packets exiting egress handler"); +#endif /* CONFIG_RMNET_DATA_DEBUG_PKT */ + +/* Time in nano seconds. This number must be less that a second. */ +long gro_flush_time __read_mostly = 10000L; +module_param(gro_flush_time, long, 0644); +MODULE_PARM_DESC(gro_flush_time, "Flush GRO when spaced more than this"); + +unsigned int gro_min_byte_thresh __read_mostly = 7500; +module_param(gro_min_byte_thresh, uint, 0644); +MODULE_PARM_DESC(gro_min_byte_thresh, "Min byte thresh to change flush time"); + +unsigned int dynamic_gro_on __read_mostly = 1; +module_param(dynamic_gro_on, uint, 0644); +MODULE_PARM_DESC(dynamic_gro_on, "Toggle to turn on dynamic gro logic"); + +unsigned int upper_flush_time __read_mostly = 15000; +module_param(upper_flush_time, uint, 0644); +MODULE_PARM_DESC(upper_flush_time, "Upper limit on flush time"); + +unsigned int upper_byte_limit __read_mostly = 10500; +module_param(upper_byte_limit, uint, 0644); +MODULE_PARM_DESC(upper_byte_limit, "Upper byte limit"); + +#define RMNET_DATA_IP_VERSION_4 0x40 +#define RMNET_DATA_IP_VERSION_6 0x60 + +#define RMNET_DATA_GRO_RCV_FAIL 0 +#define RMNET_DATA_GRO_RCV_PASS 1 + +/* Helper Functions */ + +/* __rmnet_data_set_skb_proto() - Set skb->protocol field + * @skb: packet being modified + * + * Peek at the first byte of the packet and set the protocol. There is not + * good way to determine if a packet has a MAP header. As of writing this, + * the reserved bit in the MAP frame will prevent it from overlapping with + * IPv4/IPv6 frames. This could change in the future! + */ +static inline void __rmnet_data_set_skb_proto(struct sk_buff *skb) +{ + switch (skb->data[0] & 0xF0) { + case RMNET_DATA_IP_VERSION_4: + skb->protocol = htons(ETH_P_IP); + break; + case RMNET_DATA_IP_VERSION_6: + skb->protocol = htons(ETH_P_IPV6); + break; + default: + skb->protocol = htons(ETH_P_MAP); + break; + } +} + +#ifdef CONFIG_RMNET_DATA_DEBUG_PKT +/* rmnet_print_packet() - Print packet / diagnostics + * @skb: Packet to print + * @printlen: Number of bytes to print + * @dev: Name of interface + * @dir: Character representing direction (e.g.. 'r' for receive) + * + * This function prints out raw bytes in an SKB. Use of this will have major + * performance impacts and may even trigger watchdog resets if too much is being + * printed. Hence, this should always be compiled out unless absolutely needed. + */ +void rmnet_print_packet(const struct sk_buff *skb, const char *dev, char dir) +{ + char buffer[200]; + unsigned int len, printlen; + int i, buffloc = 0; + + switch (dir) { + case 'r': + printlen = dump_pkt_rx; + break; + + case 't': + printlen = dump_pkt_tx; + break; + + default: + printlen = 0; + break; + } + + if (!printlen) + return; + + pr_err("[%s][%c] - PKT skb->len=%d skb->head=%pK skb->data=%pK\n", + dev, dir, skb->len, (void *)skb->head, (void *)skb->data); + pr_err("[%s][%c] - PKT skb->tail=%pK skb->end=%pK\n", + dev, dir, skb_tail_pointer(skb), skb_end_pointer(skb)); + + if (skb->len > 0) + len = skb->len; + else + len = ((unsigned int)(uintptr_t)skb->end) - + ((unsigned int)(uintptr_t)skb->data); + + pr_err("[%s][%c] - PKT len: %d, printing first %d bytes\n", + dev, dir, len, printlen); + + memset(buffer, 0, sizeof(buffer)); + for (i = 0; (i < printlen) && (i < len); i++) { + if ((i % 16) == 0) { + pr_err("[%s][%c] - PKT%s\n", dev, dir, buffer); + memset(buffer, 0, sizeof(buffer)); + buffloc = 0; + buffloc += snprintf(&buffer[buffloc], + sizeof(buffer) - buffloc, "%04X:", + i); + } + + buffloc += snprintf(&buffer[buffloc], sizeof(buffer) - buffloc, + " %02x", skb->data[i]); + } + pr_err("[%s][%c] - PKT%s\n", dev, dir, buffer); +} +#else +void rmnet_print_packet(const struct sk_buff *skb, const char *dev, char dir) +{ +} +#endif /* CONFIG_RMNET_DATA_DEBUG_PKT */ + +/* Generic handler */ + +/* rmnet_bridge_handler() - Bridge related functionality + * + * Return: + * - RX_HANDLER_CONSUMED in all cases + */ +static rx_handler_result_t rmnet_bridge_handler + (struct sk_buff *skb, struct rmnet_logical_ep_conf_s *ep) +{ + if (!ep->egress_dev) { + LOGD("Missing egress device for packet arriving on %s", + skb->dev->name); + rmnet_kfree_skb(skb, RMNET_STATS_SKBFREE_BRDG_NO_EGRESS); + } else { + rmnet_data_egress_handler(skb, ep); + } + + return RX_HANDLER_CONSUMED; +} + +/* RX/TX Fixup */ + +/* rmnet_vnd_rx_fixup() - Virtual Network Device receive fixup hook + * @skb: Socket buffer ("packet") to modify + * @dev: Virtual network device + * + * Additional VND specific packet processing for ingress packets + * + * Return: void + */ +static void rmnet_vnd_rx_fixup(struct sk_buff *skb, struct net_device *dev) +{ + dev->stats.rx_packets++; + dev->stats.rx_bytes += skb->len; +} + +/* rmnet_vnd_tx_fixup() - Virtual Network Device transmic fixup hook + * @skb: Socket buffer ("packet") to modify + * @dev: Virtual network device + * + * Additional VND specific packet processing for egress packets + * + * Return: void + */ +static void rmnet_vnd_tx_fixup(struct sk_buff *skb, struct net_device *dev) +{ + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; +} + +/* rmnet_check_skb_can_gro() - Check is skb can be passed through GRO handler + * + * Determines whether to pass the skb to the GRO handler napi_gro_receive() or + * handle normally by passing to netif_receive_skb(). + * + * Warning: + * This assumes that only TCP packets can be coalesced by the GRO handler which + * is not true in general. We lose the ability to use GRO for cases like UDP + * encapsulation protocols. + * + * Return: + * - RMNET_DATA_GRO_RCV_FAIL if packet is sent to netif_receive_skb() + * - RMNET_DATA_GRO_RCV_PASS if packet is sent to napi_gro_receive() + */ +static int rmnet_check_skb_can_gro(struct sk_buff *skb) +{ + switch (skb->data[0] & 0xF0) { + case RMNET_DATA_IP_VERSION_4: + if (ip_hdr(skb)->protocol == IPPROTO_TCP) + return RMNET_DATA_GRO_RCV_PASS; + break; + case RMNET_DATA_IP_VERSION_6: + if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP) + return RMNET_DATA_GRO_RCV_PASS; + /* Fall through */ + } + + return RMNET_DATA_GRO_RCV_FAIL; +} + +/* rmnet_optional_gro_flush() - Check if GRO handler needs to flush now + * + * Determines whether GRO handler needs to flush packets which it has + * coalesced so far. + * + * Tuning this parameter will trade TCP slow start performance for GRO coalesce + * ratio. + */ +static void rmnet_optional_gro_flush(struct napi_struct *napi, + struct rmnet_logical_ep_conf_s *ep, + unsigned int skb_size) +{ + struct timespec curr_time, diff; + + if (!gro_flush_time) + return; + + if (unlikely(ep->flush_time.tv_sec == 0)) { + getnstimeofday(&ep->flush_time); + ep->flush_byte_count = 0; + } else { + getnstimeofday(&(curr_time)); + diff = timespec_sub(curr_time, ep->flush_time); + ep->flush_byte_count += skb_size; + + if (dynamic_gro_on) { + if ((!(diff.tv_sec > 0) || diff.tv_nsec <= + gro_flush_time) && + ep->flush_byte_count >= + gro_min_byte_thresh) { + /* Processed many bytes in a small time window. + * No longer need to flush so often and we can + * increase our byte limit + */ + gro_flush_time = upper_flush_time; + gro_min_byte_thresh = upper_byte_limit; + } else if ((diff.tv_sec > 0 || + diff.tv_nsec > gro_flush_time) && + ep->flush_byte_count < + gro_min_byte_thresh) { + /* We have not hit our time limit and we are not + * receive many bytes. Demote ourselves to the + * lowest limits and flush + */ + napi_gro_flush(napi, false); + getnstimeofday(&ep->flush_time); + ep->flush_byte_count = 0; + gro_flush_time = 10000L; + gro_min_byte_thresh = 7500L; + } else if ((diff.tv_sec > 0 || + diff.tv_nsec > gro_flush_time) && + ep->flush_byte_count >= + gro_min_byte_thresh) { + /* Above byte and time limt, therefore we can + * move/maintain our limits to be the max + * and flush + */ + napi_gro_flush(napi, false); + getnstimeofday(&ep->flush_time); + ep->flush_byte_count = 0; + gro_flush_time = upper_flush_time; + gro_min_byte_thresh = upper_byte_limit; + } + /* else, below time limit and below + * byte thresh, so change nothing + */ + } else if (diff.tv_sec > 0 || + diff.tv_nsec >= gro_flush_time) { + napi_gro_flush(napi, false); + getnstimeofday(&ep->flush_time); + ep->flush_byte_count = 0; + } + } +} + +/* __rmnet_deliver_skb() - Deliver skb + * + * Determines where to deliver skb. Options are: consume by network stack, + * pass to bridge handler, or pass to virtual network device + * + * Return: + * - RX_HANDLER_CONSUMED if packet forwarded or dropped + * - RX_HANDLER_PASS if packet is to be consumed by network stack as-is + */ +static rx_handler_result_t __rmnet_deliver_skb + (struct sk_buff *skb, struct rmnet_logical_ep_conf_s *ep) +{ + struct napi_struct *napi = NULL; + gro_result_t gro_res; + unsigned int skb_size; + + trace___rmnet_deliver_skb(skb); + switch (ep->rmnet_mode) { + case RMNET_EPMODE_VND: + skb_reset_transport_header(skb); + skb_reset_network_header(skb); + rmnet_vnd_rx_fixup(skb, skb->dev); + + skb->pkt_type = PACKET_HOST; + skb_set_mac_header(skb, 0); + + if (rmnet_check_skb_can_gro(skb) && + (skb->dev->features & NETIF_F_GRO)) { + napi = get_current_napi_context(); + + skb_size = skb->len; + gro_res = napi_gro_receive(napi, skb); + trace_rmnet_gro_downlink(gro_res); + rmnet_optional_gro_flush(napi, ep, skb_size); + } else{ + netif_receive_skb(skb); + } + return RX_HANDLER_CONSUMED; + + case RMNET_EPMODE_NONE: + return RX_HANDLER_PASS; + + case RMNET_EPMODE_BRIDGE: + return rmnet_bridge_handler(skb, ep); + + default: + LOGD("Unknown ep mode %d", ep->rmnet_mode); + rmnet_kfree_skb(skb, RMNET_STATS_SKBFREE_DELIVER_NO_EP); + return RX_HANDLER_CONSUMED; + } +} + +/* rmnet_ingress_deliver_packet() - Ingress handler for raw IP and bridged + * MAP packets. + * @skb: Packet needing a destination. + * @config: Physical end point configuration that the packet arrived on. + * + * Return: + * - RX_HANDLER_CONSUMED if packet forwarded/dropped + * - RX_HANDLER_PASS if packet should be passed up the stack by caller + */ +static rx_handler_result_t rmnet_ingress_deliver_packet + (struct sk_buff *skb, struct rmnet_phys_ep_config *config) +{ + if (!config) { + LOGD("%s", "NULL physical EP provided"); + kfree_skb(skb); + return RX_HANDLER_CONSUMED; + } + + if (!(config->local_ep.refcount)) { + LOGD("Packet on %s has no local endpoint configuration", + skb->dev->name); + rmnet_kfree_skb(skb, RMNET_STATS_SKBFREE_IPINGRESS_NO_EP); + return RX_HANDLER_CONSUMED; + } + + skb->dev = config->local_ep.egress_dev; + + return __rmnet_deliver_skb(skb, &config->local_ep); +} + +/* MAP handler */ + +/* _rmnet_map_ingress_handler() - Actual MAP ingress handler + * @skb: Packet being received + * @config: Physical endpoint configuration for the ingress device + * + * Most MAP ingress functions are processed here. Packets are processed + * individually; aggregated packets should use rmnet_map_ingress_handler() + * + * Return: + * - RX_HANDLER_CONSUMED if packet is dropped + * - result of __rmnet_deliver_skb() for all other cases + */ +static rx_handler_result_t _rmnet_map_ingress_handler + (struct sk_buff *skb, struct rmnet_phys_ep_config *config) +{ + struct rmnet_logical_ep_conf_s *ep; + u8 mux_id; + u16 len; + int ckresult; + + if (RMNET_MAP_GET_CD_BIT(skb)) { + if (config->ingress_data_format + & RMNET_INGRESS_FORMAT_MAP_COMMANDS) + return rmnet_data_map_command(skb, config); + + LOGM("MAP command packet on %s; %s", skb->dev->name, + "Not configured for MAP commands"); + rmnet_kfree_skb(skb, + RMNET_STATS_SKBFREE_INGRESS_NOT_EXPECT_MAPC); + return RX_HANDLER_CONSUMED; + } + + mux_id = RMNET_MAP_GET_MUX_ID(skb); + len = RMNET_MAP_GET_LENGTH(skb) + - RMNET_MAP_GET_PAD(skb) + - config->tail_spacing; + + if (mux_id >= RMNET_DATA_MAX_LOGICAL_EP) { + LOGD("Got packet on %s with bad mux id %d", + skb->dev->name, mux_id); + rmnet_kfree_skb(skb, RMNET_STATS_SKBFREE_MAPINGRESS_BAD_MUX); + return RX_HANDLER_CONSUMED; + } + + ep = &config->muxed_ep[mux_id]; + + if (!ep->refcount) { + LOGE("Packet on %s:%d; has no logical endpoint config", + skb->dev->name, mux_id); + + rmnet_kfree_skb(skb, RMNET_STATS_SKBFREE_MAPINGRESS_MUX_NO_EP); + return RX_HANDLER_CONSUMED; + } + + skb->dev = ep->egress_dev; + + if ((config->ingress_data_format & RMNET_INGRESS_FORMAT_MAP_CKSUMV3) || + (config->ingress_data_format & RMNET_INGRESS_FORMAT_MAP_CKSUMV4)) { + ckresult = rmnet_map_data_checksum_downlink_packet(skb); + trace_rmnet_map_checksum_downlink_packet(skb, ckresult); + rmnet_stats_dl_checksum(ckresult); + if (likely((ckresult == RMNET_MAP_CHECKSUM_OK) || + (ckresult == RMNET_MAP_CHECKSUM_SKIPPED))) + skb->ip_summed |= CHECKSUM_UNNECESSARY; + else if (ckresult != + RMNET_MAP_CHECKSUM_ERR_UNKNOWN_IP_VERSION && + ckresult != RMNET_MAP_CHECKSUM_VALIDATION_FAILED && + ckresult != RMNET_MAP_CHECKSUM_ERR_UNKNOWN_TRANSPORT && + ckresult != RMNET_MAP_CHECKSUM_VALID_FLAG_NOT_SET && + ckresult != RMNET_MAP_CHECKSUM_FRAGMENTED_PACKET) { + rmnet_kfree_skb + (skb, RMNET_STATS_SKBFREE_INGRESS_BAD_MAP_CKSUM); + return RX_HANDLER_CONSUMED; + } + } + + /* Subtract MAP header */ + skb_pull(skb, sizeof(struct rmnet_map_header_s)); + skb_trim(skb, len); + __rmnet_data_set_skb_proto(skb); + return __rmnet_deliver_skb(skb, ep); +} + +/* rmnet_map_ingress_handler() - MAP ingress handler + * @skb: Packet being received + * @config: Physical endpoint configuration for the ingress device + * + * Called if and only if MAP is configured in the ingress device's ingress data + * format. Deaggregation is done here, actual MAP processing is done in + * _rmnet_map_ingress_handler(). + * + * Return: + * - RX_HANDLER_CONSUMED for aggregated packets + * - RX_HANDLER_CONSUMED for dropped packets + * - result of _rmnet_map_ingress_handler() for all other cases + */ +static rx_handler_result_t rmnet_map_ingress_handler + (struct sk_buff *skb, struct rmnet_phys_ep_config *config) +{ + struct sk_buff *skbn; + int rc; + + if (config->ingress_data_format & RMNET_INGRESS_FORMAT_DEAGGREGATION) { + trace_rmnet_start_deaggregation(skb); + while ((skbn = rmnet_data_map_deaggregate(skb, config)) != 0) + _rmnet_map_ingress_handler(skbn, config); + + rmnet_kfree_skb(skb, RMNET_STATS_SKBFREE_MAPINGRESS_AGGBUF); + rc = RX_HANDLER_CONSUMED; + } else { + rc = _rmnet_map_ingress_handler(skb, config); + } + + return rc; +} + +/* rmnet_map_egress_handler() - MAP egress handler + * @skb: Packet being sent + * @config: Physical endpoint configuration for the egress device + * @ep: logical endpoint configuration of the packet originator + * (e.g.. RmNet virtual network device) + * @orig_dev: The originator vnd device + * + * Called if and only if MAP is configured in the egress device's egress data + * format. Will expand skb if there is insufficient headroom for MAP protocol. + * Note: headroomexpansion will incur a performance penalty. + * + * Return: + * - 0 on success + * - 1 on failure + */ +static int rmnet_map_egress_handler(struct sk_buff *skb, + struct rmnet_phys_ep_config *config, + struct rmnet_logical_ep_conf_s *ep, + struct net_device *orig_dev) +{ + int required_headroom, additional_header_length, ckresult; + struct rmnet_map_header_s *map_header; + int non_linear_skb; + int csum_required = (config->egress_data_format & + RMNET_EGRESS_FORMAT_MAP_CKSUMV3) || + (config->egress_data_format & + RMNET_EGRESS_FORMAT_MAP_CKSUMV4); + + additional_header_length = 0; + + required_headroom = sizeof(struct rmnet_map_header_s); + if (csum_required) { + required_headroom += + sizeof(struct rmnet_map_ul_checksum_header_s); + additional_header_length += + sizeof(struct rmnet_map_ul_checksum_header_s); + } + + LOGD("headroom of %d bytes", required_headroom); + + if (skb_headroom(skb) < required_headroom) { + LOGE("Not enough headroom for %d bytes", required_headroom); + kfree_skb(skb); + return 1; + } + + if (csum_required) { + ckresult = rmnet_map_data_checksum_uplink_packet + (skb, orig_dev, config->egress_data_format); + trace_rmnet_map_checksum_uplink_packet(orig_dev, ckresult); + rmnet_stats_ul_checksum(ckresult); + } + + non_linear_skb = (orig_dev->features & NETIF_F_GSO) && + skb_is_nonlinear(skb); + + if ((!(config->egress_data_format & + RMNET_EGRESS_FORMAT_AGGREGATION)) || csum_required || + non_linear_skb) + map_header = rmnet_data_map_add_map_header + (skb, additional_header_length, RMNET_MAP_NO_PAD_BYTES); + else + map_header = rmnet_data_map_add_map_header + (skb, additional_header_length, RMNET_MAP_ADD_PAD_BYTES); + + if (!map_header) { + LOGD("%s", "Failed to add MAP header to egress packet"); + kfree_skb(skb); + return 1; + } + + if (config->egress_data_format & RMNET_EGRESS_FORMAT_MUXING) { + if (ep->mux_id == 0xff) + map_header->mux_id = 0; + else + map_header->mux_id = ep->mux_id; + } + + skb->protocol = htons(ETH_P_MAP); + + if (config->egress_data_format & RMNET_EGRESS_FORMAT_AGGREGATION) { + if (rmnet_ul_aggregation_skip(skb, required_headroom)) + return RMNET_MAP_SUCCESS; + + if (non_linear_skb) + if (unlikely(__skb_linearize(skb))) + return RMNET_MAP_SUCCESS; + + rmnet_map_aggregate(skb, config); + return RMNET_MAP_CONSUMED; + } + + return RMNET_MAP_SUCCESS; +} + +/* Ingress / Egress Entry Points */ + +/* rmnet_ingress_handler() - Ingress handler entry point + * @skb: Packet being received + * + * Processes packet as per ingress data format for receiving device. Logical + * endpoint is determined from packet inspection. Packet is then sent to the + * egress device listed in the logical endpoint configuration. + * + * Return: + * - RX_HANDLER_PASS if packet is not processed by handler (caller must + * deal with the packet) + * - RX_HANDLER_CONSUMED if packet is forwarded or processed by MAP + */ +rx_handler_result_t rmnet_ingress_handler(struct sk_buff *skb) +{ + struct rmnet_phys_ep_config *config; + struct net_device *dev; + int rc; + + if (!skb) + return RX_HANDLER_CONSUMED; + + dev = skb->dev; + trace_rmnet_ingress_handler(skb); + rmnet_print_packet(skb, dev->name, 'r'); + + config = _rmnet_get_phys_ep_config(skb->dev); + + if (!config) { + LOGD("%s is not associated with rmnet_data", skb->dev->name); + kfree_skb(skb); + return RX_HANDLER_CONSUMED; + } + + /* Sometimes devices operate in ethernet mode even thouth there is no + * ethernet header. This causes the skb->protocol to contain a bogus + * value and the skb->data pointer to be off by 14 bytes. Fix it if + * configured to do so + */ + if (config->ingress_data_format & RMNET_INGRESS_FIX_ETHERNET) { + skb_push(skb, RMNET_ETHERNET_HEADER_LENGTH); + __rmnet_data_set_skb_proto(skb); + } + + if (config->ingress_data_format & RMNET_INGRESS_FORMAT_MAP) { + rc = rmnet_map_ingress_handler(skb, config); + } else { + switch (ntohs(skb->protocol)) { + case ETH_P_MAP: + if (config->local_ep.rmnet_mode == + RMNET_EPMODE_BRIDGE) { + rc = rmnet_ingress_deliver_packet(skb, config); + } else { + LOGD("MAP packet on %s; MAP not set", + dev->name); + rmnet_kfree_skb + (skb, + RMNET_STATS_SKBFREE_INGRESS_NOT_EXPECT_MAPD); + rc = RX_HANDLER_CONSUMED; + } + break; + + case ETH_P_ARP: + case ETH_P_IP: + case ETH_P_IPV6: + rc = rmnet_ingress_deliver_packet(skb, config); + break; + + default: + LOGD("Unknown skb->proto 0x%04X\n", + ntohs(skb->protocol) & 0xFFFF); + rc = RX_HANDLER_PASS; + } + } + + return rc; +} + +/* rmnet_data_rx_handler() - Rx handler callback registered with kernel + * @pskb: Packet to be processed by rx handler + * + * Standard kernel-expected footprint for rx handlers. Calls + * rmnet_ingress_handler with correctly formatted arguments + * + * Return: + * - Whatever rmnet_ingress_handler() returns + */ +rx_handler_result_t rmnet_data_rx_handler(struct sk_buff **pskb) +{ + return rmnet_ingress_handler(*pskb); +} + +/* rmnet_data_egress_handler() - Egress handler entry point + * @skb: packet to transmit + * @ep: logical endpoint configuration of the packet originator + * (e.g.. RmNet virtual network device) + * + * Modifies packet as per logical endpoint configuration and egress data format + * for egress device configured in logical endpoint. Packet is then transmitted + * on the egress device. + */ +void rmnet_data_egress_handler(struct sk_buff *skb, + struct rmnet_logical_ep_conf_s *ep) +{ + struct rmnet_phys_ep_config *config; + struct net_device *orig_dev; + int rc; + + orig_dev = skb->dev; + skb->dev = ep->egress_dev; + + config = _rmnet_get_phys_ep_config(skb->dev); + + if (!config) { + LOGD("%s is not associated with rmnet_data", skb->dev->name); + kfree_skb(skb); + return; + } + + LOGD("Packet going out on %s with egress format 0x%08X", + skb->dev->name, config->egress_data_format); + + if (ep->rmnet_mode == RMNET_EPMODE_VND) + rmnet_vnd_tx_fixup(skb, orig_dev); + + if (config->egress_data_format & RMNET_EGRESS_FORMAT_MAP) { + switch (rmnet_map_egress_handler(skb, config, ep, orig_dev)) { + case RMNET_MAP_CONSUMED: + LOGD("%s", "MAP process consumed packet"); + return; + + case RMNET_MAP_SUCCESS: + break; + + default: + LOGD("MAP egress failed on packet on %s", + skb->dev->name); + rmnet_kfree_skb(skb, RMNET_STATS_SKBFREE_EGR_MAPFAIL); + return; + } + } + + rmnet_print_packet(skb, skb->dev->name, 't'); + trace_rmnet_egress_handler(skb); + + if (config->egress_data_format & RMNET_EGRESS_FORMAT__RESERVED__) + skb_push(skb, RMNET_ETHERNET_HEADER_LENGTH); + + rc = dev_queue_xmit(skb); + if (rc != 0) { + LOGD("Failed to queue packet for transmission on [%s]", + skb->dev->name); + } + rmnet_stats_queue_xmit(rc, RMNET_STATS_QUEUE_XMIT_EGRESS); +} diff --git a/net/rmnet_data/rmnet_data_handlers.h b/net/rmnet_data/rmnet_data_handlers.h new file mode 100644 index 000000000000..a61266703e05 --- /dev/null +++ b/net/rmnet_data/rmnet_data_handlers.h @@ -0,0 +1,23 @@ +/* Copyright (c) 2013, 2016 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. + * + * RMNET Data ingress/egress handler + */ + +#ifndef _RMNET_DATA_HANDLERS_H_ +#define _RMNET_DATA_HANDLERS_H_ + +void rmnet_data_egress_handler(struct sk_buff *skb, + struct rmnet_logical_ep_conf_s *ep); + +rx_handler_result_t rmnet_data_rx_handler(struct sk_buff **pskb); + +#endif /* _RMNET_DATA_HANDLERS_H_ */ diff --git a/net/rmnet_data/rmnet_data_main.c b/net/rmnet_data/rmnet_data_main.c new file mode 100644 index 000000000000..b5baa6f9410f --- /dev/null +++ b/net/rmnet_data/rmnet_data_main.c @@ -0,0 +1,59 @@ +/* Copyright (c) 2013-2014, 2016 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. + * + * + * RMNET Data generic framework + */ + +#include +#include +#include +#include "rmnet_data_private.h" +#include "rmnet_data_config.h" +#include "rmnet_data_vnd.h" + +/* Trace Points */ +#define CREATE_TRACE_POINTS +#include "rmnet_data_trace.h" + +/* Module Parameters */ +unsigned int rmnet_data_log_level = RMNET_LOG_LVL_ERR | RMNET_LOG_LVL_HI; +module_param(rmnet_data_log_level, uint, 0644); +MODULE_PARM_DESC(log_level, "Logging level"); + +unsigned int rmnet_data_log_module_mask; +module_param(rmnet_data_log_module_mask, uint, 0644); +MODULE_PARM_DESC(rmnet_data_log_module_mask, "Logging module mask"); + +/* Startup/Shutdown */ + +/* rmnet_init() - Module initialization + * + * todo: check for (and init) startup errors + */ +static int __init rmnet_init(void) +{ + rmnet_config_init(); + rmnet_vnd_init(); + + LOGL("%s", "RMNET Data driver loaded successfully"); + return 0; +} + +static void __exit rmnet_exit(void) +{ + rmnet_config_exit(); + rmnet_vnd_exit(); +} + +module_init(rmnet_init) +module_exit(rmnet_exit) +MODULE_LICENSE("GPL v2"); diff --git a/net/rmnet_data/rmnet_data_private.h b/net/rmnet_data/rmnet_data_private.h new file mode 100644 index 000000000000..0ac68cbd8ffa --- /dev/null +++ b/net/rmnet_data/rmnet_data_private.h @@ -0,0 +1,76 @@ +/* Copyright (c) 2013-2014, 2016 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 _RMNET_DATA_PRIVATE_H_ +#define _RMNET_DATA_PRIVATE_H_ + +#define RMNET_DATA_MAX_VND 32 +#define RMNET_DATA_MAX_PACKET_SIZE 16384 +#define RMNET_DATA_DFLT_PACKET_SIZE 1500 +#define RMNET_DATA_DEV_NAME_STR "rmnet_data" +#define RMNET_DATA_NEEDED_HEADROOM 16 +#define RMNET_DATA_TX_QUEUE_LEN 1000 +#define RMNET_ETHERNET_HEADER_LENGTH 14 + +extern unsigned int rmnet_data_log_level; +extern unsigned int rmnet_data_log_module_mask; + +#define RMNET_INIT_OK 0 +#define RMNET_INIT_ERROR 1 + +#define RMNET_LOG_LVL_DBG BIT(4) +#define RMNET_LOG_LVL_LOW BIT(3) +#define RMNET_LOG_LVL_MED BIT(2) +#define RMNET_LOG_LVL_HI BIT(1) +#define RMNET_LOG_LVL_ERR BIT(0) + +#define RMNET_LOG_MODULE(X) \ + static u32 rmnet_mod_mask = X + +#define RMNET_DATA_LOGMASK_CONFIG BIT(0) +#define RMNET_DATA_LOGMASK_HANDLER BIT(1) +#define RMNET_DATA_LOGMASK_VND BIT(2) +#define RMNET_DATA_LOGMASK_MAPD BIT(3) +#define RMNET_DATA_LOGMASK_MAPC BIT(4) + +#define LOGE(fmt, ...) do { if (rmnet_data_log_level & RMNET_LOG_LVL_ERR) \ + pr_err("[RMNET:ERR] %s(): " fmt "\n", __func__, \ + ##__VA_ARGS__); \ + } while (0) + +#define LOGH(fmt, ...) do { if (rmnet_data_log_level & RMNET_LOG_LVL_HI) \ + pr_err("[RMNET:HI] %s(): " fmt "\n", __func__, \ + ##__VA_ARGS__); \ + } while (0) + +#define LOGM(fmt, ...) do { if (rmnet_data_log_level & RMNET_LOG_LVL_MED) \ + pr_warn("[RMNET:MED] %s(): " fmt "\n", __func__, \ + ##__VA_ARGS__); \ + } while (0) + +#define LOGL(fmt, ...) do { if (unlikely \ + (rmnet_data_log_level & RMNET_LOG_LVL_LOW)) \ + pr_notice("[RMNET:LOW] %s(): " fmt "\n", __func__, \ + ##__VA_ARGS__); \ + } while (0) + +/* Don't use pr_debug as it is compiled out of the kernel. We can be sure of + * minimal impact as LOGD is not enabled by default. + */ +#define LOGD(fmt, ...) do { if (unlikely( \ + (rmnet_data_log_level & RMNET_LOG_LVL_DBG) && \ + (rmnet_data_log_module_mask & rmnet_mod_mask))) \ + pr_notice("[RMNET:DBG] %s(): " fmt "\n", __func__, \ + ##__VA_ARGS__); \ + } while (0) + +#endif /* _RMNET_DATA_PRIVATE_H_ */ diff --git a/net/rmnet_data/rmnet_data_stats.c b/net/rmnet_data/rmnet_data_stats.c new file mode 100644 index 000000000000..db74c4fd03c5 --- /dev/null +++ b/net/rmnet_data/rmnet_data_stats.c @@ -0,0 +1,119 @@ +/* Copyright (c) 2014, 2016 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. + * + * + * RMNET Data statistics + */ + +#include +#include +#include +#include +#include +#include +#include +#include "rmnet_data_private.h" +#include "rmnet_data_stats.h" +#include "rmnet_data_config.h" +#include "rmnet_map.h" + +enum rmnet_deagg_e { + RMNET_STATS_AGG_BUFF, + RMNET_STATS_AGG_PKT, + RMNET_STATS_AGG_MAX +}; + +static DEFINE_SPINLOCK(rmnet_skb_free_lock); +unsigned long int skb_free[RMNET_STATS_SKBFREE_MAX]; +module_param_array(skb_free, ulong, 0, 0444); +MODULE_PARM_DESC(skb_free, "SKBs dropped or freed"); + +static DEFINE_SPINLOCK(rmnet_queue_xmit_lock); +unsigned long int queue_xmit[RMNET_STATS_QUEUE_XMIT_MAX * 2]; +module_param_array(queue_xmit, ulong, 0, 0444); +MODULE_PARM_DESC(queue_xmit, "SKBs queued for transmit"); + +static DEFINE_SPINLOCK(rmnet_agg_count); +unsigned long int agg_count[RMNET_STATS_AGG_MAX]; +module_param_array(agg_count, ulong, 0, 0444); +MODULE_PARM_DESC(agg_count, "SKBs Aggregated"); + +static DEFINE_SPINLOCK(rmnet_checksum_dl_stats); +unsigned long int checksum_dl_stats[RMNET_MAP_CHECKSUM_ENUM_LENGTH]; +module_param_array(checksum_dl_stats, ulong, 0, 0444); +MODULE_PARM_DESC(checksum_dl_stats, "Downlink Checksum Statistics"); + +static DEFINE_SPINLOCK(rmnet_checksum_ul_stats); +unsigned long int checksum_ul_stats[RMNET_MAP_CHECKSUM_ENUM_LENGTH]; +module_param_array(checksum_ul_stats, ulong, 0, 0444); +MODULE_PARM_DESC(checksum_ul_stats, "Uplink Checksum Statistics"); + +void rmnet_kfree_skb(struct sk_buff *skb, unsigned int reason) +{ + unsigned long flags; + + if (reason >= RMNET_STATS_SKBFREE_MAX) + reason = RMNET_STATS_SKBFREE_UNKNOWN; + + spin_lock_irqsave(&rmnet_skb_free_lock, flags); + skb_free[reason]++; + spin_unlock_irqrestore(&rmnet_skb_free_lock, flags); + + kfree_skb(skb); +} + +void rmnet_stats_queue_xmit(int rc, unsigned int reason) +{ + unsigned long flags; + + if (rc != 0) + reason += RMNET_STATS_QUEUE_XMIT_MAX; + if (reason >= RMNET_STATS_QUEUE_XMIT_MAX * 2) + reason = RMNET_STATS_SKBFREE_UNKNOWN; + + spin_lock_irqsave(&rmnet_queue_xmit_lock, flags); + queue_xmit[reason]++; + spin_unlock_irqrestore(&rmnet_queue_xmit_lock, flags); +} + +void rmnet_stats_agg_pkts(int aggcount) +{ + unsigned long flags; + + spin_lock_irqsave(&rmnet_agg_count, flags); + agg_count[RMNET_STATS_AGG_BUFF]++; + agg_count[RMNET_STATS_AGG_PKT] += aggcount; + spin_unlock_irqrestore(&rmnet_agg_count, flags); +} + +void rmnet_stats_dl_checksum(unsigned int rc) +{ + unsigned long flags; + + if (rc >= RMNET_MAP_CHECKSUM_ENUM_LENGTH) + rc = RMNET_MAP_CHECKSUM_ERR_UNKNOWN; + + spin_lock_irqsave(&rmnet_checksum_dl_stats, flags); + checksum_dl_stats[rc]++; + spin_unlock_irqrestore(&rmnet_checksum_dl_stats, flags); +} + +void rmnet_stats_ul_checksum(unsigned int rc) +{ + unsigned long flags; + + if (rc >= RMNET_MAP_CHECKSUM_ENUM_LENGTH) + rc = RMNET_MAP_CHECKSUM_ERR_UNKNOWN; + + spin_lock_irqsave(&rmnet_checksum_ul_stats, flags); + checksum_ul_stats[rc]++; + spin_unlock_irqrestore(&rmnet_checksum_ul_stats, flags); +} diff --git a/net/rmnet_data/rmnet_data_stats.h b/net/rmnet_data/rmnet_data_stats.h new file mode 100644 index 000000000000..e3350ef566ca --- /dev/null +++ b/net/rmnet_data/rmnet_data_stats.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2014, 2016 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. + * + * + * RMNET Data statistics + * + */ + +#ifndef _RMNET_DATA_STATS_H_ +#define _RMNET_DATA_STATS_H_ + +enum rmnet_skb_free_e { + RMNET_STATS_SKBFREE_UNKNOWN, + RMNET_STATS_SKBFREE_BRDG_NO_EGRESS, + RMNET_STATS_SKBFREE_DELIVER_NO_EP, + RMNET_STATS_SKBFREE_IPINGRESS_NO_EP, + RMNET_STATS_SKBFREE_MAPINGRESS_BAD_MUX, + RMNET_STATS_SKBFREE_MAPINGRESS_MUX_NO_EP, + RMNET_STATS_SKBFREE_MAPINGRESS_AGGBUF, + RMNET_STATS_SKBFREE_INGRESS_NOT_EXPECT_MAPD, + RMNET_STATS_SKBFREE_INGRESS_NOT_EXPECT_MAPC, + RMNET_STATS_SKBFREE_EGR_MAPFAIL, + RMNET_STATS_SKBFREE_VND_NO_EGRESS, + RMNET_STATS_SKBFREE_MAPC_BAD_MUX, + RMNET_STATS_SKBFREE_MAPC_MUX_NO_EP, + RMNET_STATS_SKBFREE_AGG_CPY_EXPAND, + RMNET_STATS_SKBFREE_AGG_INTO_BUFF, + RMNET_STATS_SKBFREE_DEAGG_MALFORMED, + RMNET_STATS_SKBFREE_DEAGG_CLONE_FAIL, + RMNET_STATS_SKBFREE_DEAGG_UNKNOWN_IP_TYPE, + RMNET_STATS_SKBFREE_DEAGG_DATA_LEN_0, + RMNET_STATS_SKBFREE_INGRESS_BAD_MAP_CKSUM, + RMNET_STATS_SKBFREE_MAPC_UNSUPPORTED, + RMNET_STATS_SKBFREE_MAX +}; + +enum rmnet_queue_xmit_e { + RMNET_STATS_QUEUE_XMIT_UNKNOWN, + RMNET_STATS_QUEUE_XMIT_EGRESS, + RMNET_STATS_QUEUE_XMIT_AGG_FILL_BUFFER, + RMNET_STATS_QUEUE_XMIT_AGG_TIMEOUT, + RMNET_STATS_QUEUE_XMIT_AGG_CPY_EXP_FAIL, + RMNET_STATS_QUEUE_XMIT_AGG_SKIP, + RMNET_STATS_QUEUE_XMIT_MAX +}; + +void rmnet_kfree_skb(struct sk_buff *skb, unsigned int reason); +void rmnet_stats_queue_xmit(int rc, unsigned int reason); +void rmnet_stats_deagg_pkts(int aggcount); +void rmnet_stats_agg_pkts(int aggcount); +void rmnet_stats_dl_checksum(unsigned int rc); +void rmnet_stats_ul_checksum(unsigned int rc); +#endif /* _RMNET_DATA_STATS_H_ */ diff --git a/net/rmnet_data/rmnet_data_trace.h b/net/rmnet_data/rmnet_data_trace.h new file mode 100644 index 000000000000..7c3aa9a5a01f --- /dev/null +++ b/net/rmnet_data/rmnet_data_trace.h @@ -0,0 +1,358 @@ +/* Copyright (c) 2014-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. + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM rmnet_data +#define TRACE_INCLUDE_FILE rmnet_data_trace + +#if !defined(_TRACE_MSM_LOW_POWER_H_) || defined(TRACE_HEADER_MULTI_READ) +#define _RMNET_DATA_TRACE_H_ + +#include +#include +#include + +DECLARE_EVENT_CLASS + (rmnet_handler_template, + + TP_PROTO(struct sk_buff *skb), + + TP_ARGS(skb), + + TP_STRUCT__entry( + __field(void *, skbaddr) + __field(unsigned int, len) + __string(name, skb->dev->name) + ), + + TP_fast_assign( + __entry->skbaddr = skb; + __entry->len = skb->len; + __assign_str(name, skb->dev->name); + ), + + TP_printk("dev=%s skbaddr=%pK len=%u", + __get_str(name), __entry->skbaddr, __entry->len) +) + +DEFINE_EVENT + (rmnet_handler_template, rmnet_egress_handler, + + TP_PROTO(struct sk_buff *skb), + + TP_ARGS(skb) +); + +DEFINE_EVENT + (rmnet_handler_template, rmnet_ingress_handler, + + TP_PROTO(struct sk_buff *skb), + + TP_ARGS(skb) +); + +DEFINE_EVENT + (rmnet_handler_template, rmnet_vnd_start_xmit, + + TP_PROTO(struct sk_buff *skb), + + TP_ARGS(skb) +); + +DEFINE_EVENT + (rmnet_handler_template, __rmnet_deliver_skb, + + TP_PROTO(struct sk_buff *skb), + + TP_ARGS(skb) +); + +DECLARE_EVENT_CLASS + (rmnet_tc_fc_template, + + TP_PROTO(u32 tcm_handle, int qdisc_len, int is_enable), + + TP_ARGS(tcm_handle, qdisc_len, is_enable), + + TP_STRUCT__entry( + __field(u32, handle) + __field(int, qlen) + __field(int, enable) + ), + + TP_fast_assign( + __entry->handle = tcm_handle; + __entry->qlen = qdisc_len; + __entry->enable = is_enable; + ), + + TP_printk("tcm_handle=%d qdisc length=%d flow %s", + __entry->handle, __entry->qlen, + __entry->enable ? "enable" : "disable") +) + +DEFINE_EVENT + (rmnet_tc_fc_template, rmnet_fc_qmi, + + TP_PROTO(u32 tcm_handle, int qdisc_len, int is_enable), + + TP_ARGS(tcm_handle, qdisc_len, is_enable) +); + +DEFINE_EVENT + (rmnet_tc_fc_template, rmnet_fc_map, + + TP_PROTO(u32 tcm_handle, int qdisc_len, int is_enable), + + TP_ARGS(tcm_handle, qdisc_len, is_enable) +); + +DECLARE_EVENT_CLASS + (rmnet_aggregation_template, + + TP_PROTO(struct sk_buff *skb, int num_agg_pakcets), + + TP_ARGS(skb, num_agg_pakcets), + + TP_STRUCT__entry( + __field(void *, skbaddr) + __field(unsigned int, len) + __string(name, skb->dev->name) + __field(int, num) + ), + + TP_fast_assign( + __entry->skbaddr = skb; + __entry->len = skb->len; + __assign_str(name, skb->dev->name); + __entry->num = num_agg_pakcets; + ), + + TP_printk("dev=%s skbaddr=%pK len=%u agg_count: %d", + __get_str(name), __entry->skbaddr, __entry->len, + __entry->num) +) + +DEFINE_EVENT + (rmnet_aggregation_template, rmnet_map_aggregate, + + TP_PROTO(struct sk_buff *skb, int num_agg_pakcets), + + TP_ARGS(skb, num_agg_pakcets) +); + +DEFINE_EVENT + (rmnet_aggregation_template, rmnet_map_flush_packet_queue, + + TP_PROTO(struct sk_buff *skb, int num_agg_pakcets), + + TP_ARGS(skb, num_agg_pakcets) +); + +TRACE_EVENT + (rmnet_start_aggregation, + + TP_PROTO(struct sk_buff *skb), + + TP_ARGS(skb), + + TP_STRUCT__entry( + __string(name, skb->dev->name) + ), + + TP_fast_assign( + __assign_str(name, skb->dev->name); + ), + + TP_printk("dev: %s, aggregated first packet", __get_str(name)) +) + +TRACE_EVENT + (rmnet_start_deaggregation, + + TP_PROTO(struct sk_buff *skb), + + TP_ARGS(skb), + + TP_STRUCT__entry( + __string(name, skb->dev->name) + ), + + TP_fast_assign( + __assign_str(name, skb->dev->name); + ), + + TP_printk("dev: %s, deaggregated first packet", __get_str(name)) +) + +TRACE_EVENT + (rmnet_end_deaggregation, + + TP_PROTO(struct sk_buff *skb, int num_deagg_packets), + + TP_ARGS(skb, num_deagg_packets), + + TP_STRUCT__entry( + __string(name, skb->dev->name) + __field(int, num) + ), + + TP_fast_assign( + __assign_str(name, skb->dev->name); + __entry->num = num_deagg_packets; + ), + + TP_printk("dev: %s, deaggregate end count: %d", + __get_str(name), __entry->num) +) + +TRACE_EVENT + (rmnet_map_checksum_downlink_packet, + + TP_PROTO(struct sk_buff *skb, int ckresult), + + TP_ARGS(skb, ckresult), + + TP_STRUCT__entry( + __string(name, skb->dev->name) + __field(int, res) + ), + + TP_fast_assign( + __assign_str(name, skb->dev->name); + __entry->res = ckresult; + ), + + TP_printk("DL checksum on dev=%s, res: %d", + __get_str(name), __entry->res) +) + +TRACE_EVENT + (rmnet_map_checksum_uplink_packet, + + TP_PROTO(struct net_device *dev, int ckresult), + + TP_ARGS(dev, ckresult), + + TP_STRUCT__entry( + __string(name, dev->name) + __field(int, res) + ), + + TP_fast_assign( + __assign_str(name, dev->name); + __entry->res = ckresult; + ), + + TP_printk("UL checksum on dev=%s, res: %d", + __get_str(name), __entry->res) +) + +DECLARE_EVENT_CLASS + (rmnet_physdev_action_template, + + TP_PROTO(struct net_device *dev), + + TP_ARGS(dev), + + TP_STRUCT__entry( + __string(name, dev->name) + ), + + TP_fast_assign( + __assign_str(name, dev->name); + ), + + TP_printk("Physical dev=%s", __get_str(name)) +) + +DEFINE_EVENT + (rmnet_physdev_action_template, rmnet_unregister_cb_unhandled, + + TP_PROTO(struct net_device *dev), + + TP_ARGS(dev) +); + +DEFINE_EVENT + (rmnet_physdev_action_template, rmnet_unregister_cb_entry, + + TP_PROTO(struct net_device *dev), + + TP_ARGS(dev) +); + +DEFINE_EVENT + (rmnet_physdev_action_template, rmnet_unregister_cb_exit, + + TP_PROTO(struct net_device *dev), + + TP_ARGS(dev) +); + +DEFINE_EVENT + (rmnet_physdev_action_template, rmnet_unregister_cb_clear_vnds, + + TP_PROTO(struct net_device *dev), + + TP_ARGS(dev) +); + +DEFINE_EVENT + (rmnet_physdev_action_template, rmnet_unregister_cb_clear_lepcs, + + TP_PROTO(struct net_device *dev), + + TP_ARGS(dev) +); + +DEFINE_EVENT + (rmnet_physdev_action_template, rmnet_associate, + + TP_PROTO(struct net_device *dev), + + TP_ARGS(dev) +); + +DEFINE_EVENT + (rmnet_physdev_action_template, rmnet_unassociate, + + TP_PROTO(struct net_device *dev), + + TP_ARGS(dev) +); + +TRACE_EVENT + (rmnet_gro_downlink, + + TP_PROTO(gro_result_t gro_res), + + TP_ARGS(gro_res), + + TP_STRUCT__entry( + __field(gro_result_t, res) + ), + + TP_fast_assign( + __entry->res = gro_res; + ), + + TP_printk("GRO res: %d", __entry->res) +) + +#endif /* _RMNET_DATA_TRACE_H_ */ + +/* This part must be outside protection */ +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#include + diff --git a/net/rmnet_data/rmnet_data_vnd.c b/net/rmnet_data/rmnet_data_vnd.c new file mode 100644 index 000000000000..1d7d4f6d7bd7 --- /dev/null +++ b/net/rmnet_data/rmnet_data_vnd.c @@ -0,0 +1,1061 @@ +/* Copyright (c) 2013-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. + * + * + * RMNET Data virtual network driver + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "rmnet_data_config.h" +#include "rmnet_data_handlers.h" +#include "rmnet_data_private.h" +#include "rmnet_map.h" +#include "rmnet_data_vnd.h" +#include "rmnet_data_stats.h" +#include "rmnet_data_trace.h" + +RMNET_LOG_MODULE(RMNET_DATA_LOGMASK_VND); + +#define RMNET_MAP_FLOW_NUM_TC_HANDLE 3 +#define RMNET_VND_UF_ACTION_ADD 0 +#define RMNET_VND_UF_ACTION_DEL 1 +enum { + RMNET_VND_UPDATE_FLOW_OK, + RMNET_VND_UPDATE_FLOW_NO_ACTION, + RMNET_VND_UPDATE_FLOW_NO_MORE_ROOM, + RMNET_VND_UPDATE_FLOW_NO_VALID_LEFT +}; + +struct net_device *rmnet_devices[RMNET_DATA_MAX_VND]; + +struct rmnet_map_flow_mapping_s { + struct list_head list; + u32 map_flow_id; + u32 tc_flow_valid[RMNET_MAP_FLOW_NUM_TC_HANDLE]; + u32 tc_flow_id[RMNET_MAP_FLOW_NUM_TC_HANDLE]; + atomic_t v4_seq; + atomic_t v6_seq; +}; + +struct rmnet_vnd_private_s { + u32 qos_version; + struct rmnet_logical_ep_conf_s local_ep; + + rwlock_t flow_map_lock; + struct list_head flow_head; + struct rmnet_map_flow_mapping_s root_flow; +}; + +#define RMNET_VND_FC_QUEUED 0 +#define RMNET_VND_FC_NOT_ENABLED 1 +#define RMNET_VND_FC_KMALLOC_ERR 2 + +/* Helper Functions */ + +/* rmnet_vnd_add_qos_header() - Adds QoS header to front of skb->data + * @skb: Socket buffer ("packet") to modify + * @dev: Egress interface + * + * Does not check for sufficient headroom! Caller must make sure there is enough + * headroom. + */ +static void rmnet_vnd_add_qos_header(struct sk_buff *skb, + struct net_device *dev, + uint32_t qos_version) +{ + struct QMI_QOS_HDR_S *qmih; + struct qmi_qos_hdr8_s *qmi8h; + + if (qos_version & RMNET_IOCTL_QOS_MODE_6) { + qmih = (struct QMI_QOS_HDR_S *) + skb_push(skb, sizeof(struct QMI_QOS_HDR_S)); + qmih->version = 1; + qmih->flags = 0; + qmih->flow_id = skb->mark; + } else if (qos_version & RMNET_IOCTL_QOS_MODE_8) { + qmi8h = (struct qmi_qos_hdr8_s *) + skb_push(skb, sizeof(struct qmi_qos_hdr8_s)); + /* Flags are 0 always */ + qmi8h->hdr.version = 0; + qmi8h->hdr.flags = 0; + memset(qmi8h->reserved, 0, sizeof(qmi8h->reserved)); + qmi8h->hdr.flow_id = skb->mark; + } else { + LOGD("%s(): Bad QoS version configured\n", __func__); + } +} + +/* Network Device Operations */ + +/* rmnet_vnd_start_xmit() - Transmit NDO callback + * @skb: Socket buffer ("packet") being sent from network stack + * @dev: Virtual Network Device + * + * Standard network driver operations hook to transmit packets on virtual + * network device. Called by network stack. Packet is not transmitted directly + * from here; instead it is given to the rmnet egress handler. + * + * Return: + * - NETDEV_TX_OK under all cirumstances (cannot block/fail) + */ +static netdev_tx_t rmnet_vnd_start_xmit(struct sk_buff *skb, + struct net_device *dev) +{ + struct rmnet_vnd_private_s *dev_conf; + + trace_rmnet_vnd_start_xmit(skb); + dev_conf = (struct rmnet_vnd_private_s *)netdev_priv(dev); + if (dev_conf->local_ep.egress_dev) { + /* QoS header should come after MAP header */ + if (dev_conf->qos_version) + rmnet_vnd_add_qos_header(skb, + dev, + dev_conf->qos_version); + skb_orphan(skb); + rmnet_data_egress_handler(skb, &dev_conf->local_ep); + } else { + dev->stats.tx_dropped++; + rmnet_kfree_skb(skb, RMNET_STATS_SKBFREE_VND_NO_EGRESS); + } + return NETDEV_TX_OK; +} + +/* rmnet_vnd_change_mtu() - Change MTU NDO callback + * @dev: Virtual network device + * @new_mtu: New MTU value to set (in bytes) + * + * Standard network driver operations hook to set the MTU. Called by kernel to + * set the device MTU. Checks if desired MTU is less than zero or greater than + * RMNET_DATA_MAX_PACKET_SIZE; + * + * Return: + * - 0 if successful + * - -EINVAL if new_mtu is out of range + */ +static int rmnet_vnd_change_mtu(struct net_device *dev, int new_mtu) +{ + if (new_mtu < 0 || new_mtu > RMNET_DATA_MAX_PACKET_SIZE) + return -EINVAL; + + dev->mtu = new_mtu; + return 0; +} + +#ifdef CONFIG_RMNET_DATA_FC +static int _rmnet_vnd_do_qos_ioctl(struct net_device *dev, + struct ifreq *ifr, + int cmd) +{ + struct rmnet_vnd_private_s *dev_conf; + int rc, qdisc_len = 0; + struct rmnet_ioctl_data_s ioctl_data; + + rc = 0; + dev_conf = (struct rmnet_vnd_private_s *)netdev_priv(dev); + + switch (cmd) { + case RMNET_IOCTL_SET_QOS_ENABLE: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + LOGM("RMNET_IOCTL_SET_QOS_ENABLE on %s", dev->name); + if (!dev_conf->qos_version) + dev_conf->qos_version = RMNET_IOCTL_QOS_MODE_6; + break; + + case RMNET_IOCTL_SET_QOS_DISABLE: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + LOGM("RMNET_IOCTL_SET_QOS_DISABLE on %s", dev->name); + dev_conf->qos_version = 0; + break; + + case RMNET_IOCTL_GET_QOS: /* Get QoS header state */ + LOGM("RMNET_IOCTL_GET_QOS on %s", dev->name); + ioctl_data.u.operation_mode = (dev_conf->qos_version == + RMNET_IOCTL_QOS_MODE_6); + if (copy_to_user(ifr->ifr_ifru.ifru_data, &ioctl_data, + sizeof(struct rmnet_ioctl_data_s))) + rc = -EFAULT; + break; + + case RMNET_IOCTL_FLOW_ENABLE: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + LOGL("RMNET_IOCTL_FLOW_ENABLE on %s", dev->name); + if (copy_from_user(&ioctl_data, ifr->ifr_ifru.ifru_data, + sizeof(struct rmnet_ioctl_data_s))) { + rc = -EFAULT; + break; + } + qdisc_len = tc_qdisc_flow_control(dev, + ioctl_data.u.tcm_handle, 1); + trace_rmnet_fc_qmi(ioctl_data.u.tcm_handle, qdisc_len, 1); + break; + + case RMNET_IOCTL_FLOW_DISABLE: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + LOGL("RMNET_IOCTL_FLOW_DISABLE on %s", dev->name); + if (copy_from_user(&ioctl_data, ifr->ifr_ifru.ifru_data, + sizeof(struct rmnet_ioctl_data_s))) { + rc = -EFAULT; + break; + } + qdisc_len = tc_qdisc_flow_control(dev, + ioctl_data.u.tcm_handle, 0); + trace_rmnet_fc_qmi(ioctl_data.u.tcm_handle, qdisc_len, 0); + break; + + default: + rc = -EINVAL; + } + + return rc; +} + +struct rmnet_vnd_fc_work { + struct work_struct work; + struct net_device *dev; + u32 tc_handle; + int enable; +}; + +static void _rmnet_vnd_wq_flow_control(struct work_struct *work) +{ + struct rmnet_vnd_fc_work *fcwork; + int qdisc_len = 0; + + fcwork = (struct rmnet_vnd_fc_work *)work; + + rtnl_lock(); + qdisc_len = tc_qdisc_flow_control(fcwork->dev, fcwork->tc_handle, + fcwork->enable); + trace_rmnet_fc_map(fcwork->tc_handle, qdisc_len, fcwork->enable); + rtnl_unlock(); + + LOGL("[%s] handle:%08X enable:%d", + fcwork->dev->name, fcwork->tc_handle, fcwork->enable); + + kfree(work); +} + +static int _rmnet_vnd_do_flow_control(struct net_device *dev, + u32 tc_handle, + int enable) +{ + struct rmnet_vnd_fc_work *fcwork; + + fcwork = kmalloc(sizeof(*fcwork), GFP_ATOMIC); + if (!fcwork) + return RMNET_VND_FC_KMALLOC_ERR; + memset(fcwork, 0, sizeof(struct rmnet_vnd_fc_work)); + + INIT_WORK((struct work_struct *)fcwork, _rmnet_vnd_wq_flow_control); + fcwork->dev = dev; + fcwork->tc_handle = tc_handle; + fcwork->enable = enable; + + schedule_work((struct work_struct *)fcwork); + return RMNET_VND_FC_QUEUED; +} +#else +static int _rmnet_vnd_do_qos_ioctl(struct net_device *dev, + struct ifreq *ifr, + int cmd) +{ + return -EINVAL; +} + +static inline int _rmnet_vnd_do_flow_control(struct net_device *dev, + u32 tc_handle, + int enable) +{ + LOGD("[%s] called with no QoS support", dev->name); + return RMNET_VND_FC_NOT_ENABLED; +} +#endif /* CONFIG_RMNET_DATA_FC */ + +static int rmnet_vnd_ioctl_extended(struct net_device *dev, struct ifreq *ifr) +{ + struct rmnet_vnd_private_s *dev_conf; + struct rmnet_ioctl_extended_s ext_cmd; + int rc = 0; + + dev_conf = (struct rmnet_vnd_private_s *)netdev_priv(dev); + + rc = copy_from_user(&ext_cmd, ifr->ifr_ifru.ifru_data, + sizeof(struct rmnet_ioctl_extended_s)); + if (rc) { + LOGM("%s(): copy_from_user() failed\n", __func__); + return rc; + } + + switch (ext_cmd.extended_ioctl) { + case RMNET_IOCTL_GET_SUPPORTED_FEATURES: + ext_cmd.u.data = 0; + break; + + case RMNET_IOCTL_GET_DRIVER_NAME: + strlcpy(ext_cmd.u.if_name, "rmnet_data", + sizeof(ext_cmd.u.if_name)); + break; + + case RMNET_IOCTL_GET_SUPPORTED_QOS_MODES: + ext_cmd.u.data = RMNET_IOCTL_QOS_MODE_6 + | RMNET_IOCTL_QOS_MODE_8; + break; + + case RMNET_IOCTL_GET_QOS_VERSION: + ext_cmd.u.data = dev_conf->qos_version; + break; + + case RMNET_IOCTL_SET_QOS_VERSION: + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (ext_cmd.u.data == RMNET_IOCTL_QOS_MODE_6 || + ext_cmd.u.data == RMNET_IOCTL_QOS_MODE_8 || + ext_cmd.u.data == 0) { + dev_conf->qos_version = ext_cmd.u.data; + } else { + rc = -EINVAL; + goto done; + } + break; + + default: + rc = -EINVAL; + goto done; + } + + rc = copy_to_user(ifr->ifr_ifru.ifru_data, &ext_cmd, + sizeof(struct rmnet_ioctl_extended_s)); + if (rc) + LOGM("%s(): copy_to_user() failed\n", __func__); + +done: + return rc; +} + +/* rmnet_vnd_ioctl() - IOCTL NDO callback + * @dev: Virtual network device + * @ifreq: User data + * @cmd: IOCTL command value + * + * Standard network driver operations hook to process IOCTLs. Called by kernel + * to process non-stanard IOCTLs for device + * + * Return: + * - 0 if successful + * - -EINVAL if unknown IOCTL + */ +static int rmnet_vnd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + struct rmnet_vnd_private_s *dev_conf; + int rc; + struct rmnet_ioctl_data_s ioctl_data; + + rc = 0; + dev_conf = (struct rmnet_vnd_private_s *)netdev_priv(dev); + + rc = _rmnet_vnd_do_qos_ioctl(dev, ifr, cmd); + if (rc != -EINVAL) + return rc; + rc = 0; /* Reset rc as it may contain -EINVAL from above */ + + switch (cmd) { + case RMNET_IOCTL_OPEN: /* Do nothing. Support legacy behavior */ + LOGM("RMNET_IOCTL_OPEN on %s (ignored)", dev->name); + break; + + case RMNET_IOCTL_CLOSE: /* Do nothing. Support legacy behavior */ + LOGM("RMNET_IOCTL_CLOSE on %s (ignored)", dev->name); + break; + + case RMNET_IOCTL_SET_LLP_ETHERNET: + LOGM("RMNET_IOCTL_SET_LLP_ETHERNET on %s (no support)", + dev->name); + rc = -EINVAL; + break; + + case RMNET_IOCTL_SET_LLP_IP: /* Do nothing. Support legacy behavior */ + LOGM("RMNET_IOCTL_SET_LLP_IP on %s (ignored)", dev->name); + break; + + case RMNET_IOCTL_GET_LLP: /* Always return IP mode */ + LOGM("RMNET_IOCTL_GET_LLP on %s", dev->name); + ioctl_data.u.operation_mode = RMNET_MODE_LLP_IP; + if (copy_to_user(ifr->ifr_ifru.ifru_data, &ioctl_data, + sizeof(struct rmnet_ioctl_data_s))) + rc = -EFAULT; + break; + + case RMNET_IOCTL_EXTENDED: + rc = rmnet_vnd_ioctl_extended(dev, ifr); + break; + + default: + LOGM("Unknown IOCTL 0x%08X", cmd); + rc = -EINVAL; + } + + return rc; +} + +static const struct net_device_ops rmnet_data_vnd_ops = { + .ndo_init = 0, + .ndo_start_xmit = rmnet_vnd_start_xmit, + .ndo_do_ioctl = rmnet_vnd_ioctl, + .ndo_change_mtu = rmnet_vnd_change_mtu, + .ndo_set_mac_address = 0, + .ndo_validate_addr = 0, +}; + +/* rmnet_vnd_setup() - net_device initialization callback + * @dev: Virtual network device + * + * Called by kernel whenever a new rmnet_data device is created. Sets MTU, + * flags, ARP type, needed headroom, etc... + */ +static void rmnet_vnd_setup(struct net_device *dev) +{ + struct rmnet_vnd_private_s *dev_conf; + + LOGM("Setting up device %s", dev->name); + + /* Clear out private data */ + dev_conf = (struct rmnet_vnd_private_s *)netdev_priv(dev); + memset(dev_conf, 0, sizeof(struct rmnet_vnd_private_s)); + + dev->netdev_ops = &rmnet_data_vnd_ops; + dev->mtu = RMNET_DATA_DFLT_PACKET_SIZE; + dev->needed_headroom = RMNET_DATA_NEEDED_HEADROOM; + random_ether_addr(dev->dev_addr); + dev->tx_queue_len = RMNET_DATA_TX_QUEUE_LEN; + + /* Raw IP mode */ + dev->header_ops = 0; /* No header */ + dev->type = ARPHRD_RAWIP; + dev->hard_header_len = 0; + dev->flags &= ~(IFF_BROADCAST | IFF_MULTICAST); + + /* Flow control */ + rwlock_init(&dev_conf->flow_map_lock); + INIT_LIST_HEAD(&dev_conf->flow_head); +} + +/* rmnet_vnd_setup() - net_device initialization helper function + * @dev: Virtual network device + * + * Called during device initialization. Disables GRO. + */ +static void rmnet_vnd_disable_offload(struct net_device *dev) +{ + dev->wanted_features &= ~NETIF_F_GRO; + __netdev_update_features(dev); +} + +/* Exposed API */ + +/* rmnet_vnd_exit() - Shutdown cleanup hook + * + * Called by RmNet main on module unload. Cleans up data structures and + * unregisters/frees net_devices. + */ +void rmnet_vnd_exit(void) +{ + int i; + + for (i = 0; i < RMNET_DATA_MAX_VND; i++) + if (rmnet_devices[i]) { + unregister_netdev(rmnet_devices[i]); + free_netdev(rmnet_devices[i]); + } +} + +/* rmnet_vnd_init() - Init hook + * + * Called by RmNet main on module load. Initializes data structures + */ +int rmnet_vnd_init(void) +{ + memset(rmnet_devices, 0, + sizeof(struct net_device *) * RMNET_DATA_MAX_VND); + return 0; +} + +/* rmnet_vnd_create_dev() - Create a new virtual network device node. + * @id: Virtual device node id + * @new_device: Pointer to newly created device node + * @prefix: Device name prefix + * + * Allocates structures for new virtual network devices. Sets the name of the + * new device and registers it with the network stack. Device will appear in + * ifconfig list after this is called. If the prefix is null, then + * RMNET_DATA_DEV_NAME_STR will be assumed. + * + * Return: + * - 0 if successful + * - RMNET_CONFIG_BAD_ARGUMENTS if id is out of range or prefix is too long + * - RMNET_CONFIG_DEVICE_IN_USE if id already in use + * - RMNET_CONFIG_NOMEM if net_device allocation failed + * - RMNET_CONFIG_UNKNOWN_ERROR if register_netdevice() fails + */ +int rmnet_vnd_create_dev(int id, struct net_device **new_device, + const char *prefix, int use_name) +{ + struct net_device *dev; + char dev_prefix[IFNAMSIZ]; + int p, rc = 0; + + if (id < 0 || id >= RMNET_DATA_MAX_VND) { + *new_device = 0; + return RMNET_CONFIG_BAD_ARGUMENTS; + } + + if (rmnet_devices[id] != 0) { + *new_device = 0; + return RMNET_CONFIG_DEVICE_IN_USE; + } + + if (!prefix && !use_name) + p = scnprintf(dev_prefix, IFNAMSIZ, "%s%%d", + RMNET_DATA_DEV_NAME_STR); + else if (prefix && use_name) + p = scnprintf(dev_prefix, IFNAMSIZ, "%s", prefix); + else if (prefix && !use_name) + p = scnprintf(dev_prefix, IFNAMSIZ, "%s%%d", prefix); + else + return RMNET_CONFIG_BAD_ARGUMENTS; + + if (p >= (IFNAMSIZ - 1)) { + LOGE("Specified prefix longer than IFNAMSIZ"); + return RMNET_CONFIG_BAD_ARGUMENTS; + } + + dev = alloc_netdev(sizeof(struct rmnet_vnd_private_s), + dev_prefix, + use_name ? NET_NAME_UNKNOWN : NET_NAME_ENUM, + rmnet_vnd_setup); + if (!dev) { + LOGE("Failed to to allocate netdev for id %d", id); + *new_device = 0; + return RMNET_CONFIG_NOMEM; + } + + if (!prefix) { + /* Configuring DL checksum offload on rmnet_data interfaces */ + dev->hw_features = NETIF_F_RXCSUM; + /* Configuring UL checksum offload on rmnet_data interfaces */ + dev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; + /* Configuring GRO on rmnet_data interfaces */ + dev->hw_features |= NETIF_F_GRO; + /* Configuring Scatter-Gather on rmnet_data interfaces */ + dev->hw_features |= NETIF_F_SG; + /* Configuring GSO on rmnet_data interfaces */ + dev->hw_features |= NETIF_F_GSO; + dev->hw_features |= NETIF_F_GSO_UDP_TUNNEL; + dev->hw_features |= NETIF_F_GSO_UDP_TUNNEL_CSUM; + } + + rc = register_netdevice(dev); + if (rc != 0) { + LOGE("Failed to to register netdev [%s]", dev->name); + free_netdev(dev); + *new_device = 0; + rc = RMNET_CONFIG_UNKNOWN_ERROR; + } else { + rmnet_devices[id] = dev; + *new_device = dev; + LOGM("Registered device %s", dev->name); + } + + rmnet_vnd_disable_offload(dev); + + return rc; +} + +/* rmnet_vnd_free_dev() - free a virtual network device node. + * @id: Virtual device node id + * + * Unregisters the virtual network device node and frees it. + * unregister_netdev locks the rtnl mutex, so the mutex must not be locked + * by the caller of the function. unregister_netdev enqueues the request to + * unregister the device into a TODO queue. The requests in the TODO queue + * are only done after rtnl mutex is unlocked, therefore free_netdev has to + * called after unlocking rtnl mutex. + * + * Return: + * - 0 if successful + * - RMNET_CONFIG_NO_SUCH_DEVICE if id is invalid or not in range + * - RMNET_CONFIG_DEVICE_IN_USE if device has logical ep that wasn't unset + */ +int rmnet_vnd_free_dev(int id) +{ + struct rmnet_logical_ep_conf_s *epconfig_l; + struct net_device *dev; + + rtnl_lock(); + if ((id < 0) || (id >= RMNET_DATA_MAX_VND) || !rmnet_devices[id]) { + rtnl_unlock(); + LOGM("Invalid id [%d]", id); + return RMNET_CONFIG_NO_SUCH_DEVICE; + } + + epconfig_l = rmnet_vnd_get_le_config(rmnet_devices[id]); + if (epconfig_l && epconfig_l->refcount) { + rtnl_unlock(); + return RMNET_CONFIG_DEVICE_IN_USE; + } + + dev = rmnet_devices[id]; + rmnet_devices[id] = 0; + rtnl_unlock(); + + if (dev) { + unregister_netdev(dev); + free_netdev(dev); + return 0; + } else { + return RMNET_CONFIG_NO_SUCH_DEVICE; + } +} + +/* rmnet_vnd_get_name() - Gets the string name of a VND based on ID + * @id: Virtual device node id + * @name: Buffer to store name of virtual device node + * @name_len: Length of name buffer + * + * Copies the name of the virtual device node into the users buffer. Will throw + * an error if the buffer is null, or too small to hold the device name. + * + * Return: + * - 0 if successful + * - -EINVAL if name is null + * - -EINVAL if id is invalid or not in range + * - -EINVAL if name is too small to hold things + */ +int rmnet_vnd_get_name(int id, char *name, int name_len) +{ + int p; + + if (!name) { + LOGM("%s", "Bad arguments; name buffer null"); + return -EINVAL; + } + + if ((id < 0) || (id >= RMNET_DATA_MAX_VND) || !rmnet_devices[id]) { + LOGM("Invalid id [%d]", id); + return -EINVAL; + } + + p = strlcpy(name, rmnet_devices[id]->name, name_len); + if (p >= name_len) { + LOGM("Buffer to small (%d) to fit device name", name_len); + return -EINVAL; + } + LOGL("Found mapping [%d]->\"%s\"", id, name); + + return 0; +} + +/* rmnet_vnd_is_vnd() - Determine if net_device is RmNet owned virtual devices + * @dev: Network device to test + * + * Searches through list of known RmNet virtual devices. This function is O(n) + * and should not be used in the data path. + * + * Return: + * - 0 if device is not RmNet virtual device + * - 1 if device is RmNet virtual device + */ +int rmnet_vnd_is_vnd(struct net_device *dev) +{ + /* This is not an efficient search, but, this will only be called in + * a configuration context, and the list is small. + */ + int i; + + if (!dev) + return 0; + + for (i = 0; i < RMNET_DATA_MAX_VND; i++) + if (dev == rmnet_devices[i]) + return i + 1; + + return 0; +} + +/* rmnet_vnd_get_le_config() - Get the logical endpoint configuration + * @dev: Virtual device node + * + * Gets the logical endpoint configuration for a RmNet virtual network device + * node. Caller should confirm that devices is a RmNet VND before calling. + * + * Return: + * - Pointer to logical endpoint configuration structure + * - 0 (null) if dev is null + */ +struct rmnet_logical_ep_conf_s *rmnet_vnd_get_le_config(struct net_device *dev) +{ + struct rmnet_vnd_private_s *dev_conf; + + if (!dev) + return 0; + + dev_conf = (struct rmnet_vnd_private_s *)netdev_priv(dev); + if (!dev_conf) + return 0; + + return &dev_conf->local_ep; +} + +/* _rmnet_vnd_get_flow_map() - Gets object representing a MAP flow handle + * @dev_conf: Private configuration structure for virtual network device + * @map_flow: MAP flow handle IF + * + * Loops through available flow mappings and compares the MAP flow handle. + * Returns when mapping is found. + * + * Return: + * - Null if no mapping was found + * - Pointer to mapping otherwise + */ +static struct rmnet_map_flow_mapping_s *_rmnet_vnd_get_flow_map + (struct rmnet_vnd_private_s *dev_conf, + u32 map_flow) +{ + struct list_head *p; + struct rmnet_map_flow_mapping_s *itm; + + list_for_each(p, &dev_conf->flow_head) { + itm = list_entry(p, struct rmnet_map_flow_mapping_s, list); + + if (unlikely(!itm)) + return 0; + + if (itm->map_flow_id == map_flow) + return itm; + } + return 0; +} + +/* _rmnet_vnd_update_flow_map() - Add or remove individual TC flow handles + * @action: One of RMNET_VND_UF_ACTION_ADD / RMNET_VND_UF_ACTION_DEL + * @itm: Flow mapping object + * @map_flow: TC flow handle + * + * RMNET_VND_UF_ACTION_ADD: + * Will check for a free mapping slot in the mapping object. If one is found, + * valid for that slot will be set to 1 and the value will be set. + * + * RMNET_VND_UF_ACTION_DEL: + * Will check for matching tc handle. If found, valid for that slot will be + * set to 0 and the value will also be zeroed. + * + * Return: + * - RMNET_VND_UPDATE_FLOW_OK tc flow handle is added/removed ok + * - RMNET_VND_UPDATE_FLOW_NO_MORE_ROOM if there are no more tc handles + * - RMNET_VND_UPDATE_FLOW_NO_VALID_LEFT if flow mapping is now empty + * - RMNET_VND_UPDATE_FLOW_NO_ACTION if no action was taken + */ +static int _rmnet_vnd_update_flow_map(u8 action, + struct rmnet_map_flow_mapping_s *itm, + u32 tc_flow) +{ + int rc, i, j; + + rc = RMNET_VND_UPDATE_FLOW_OK; + + switch (action) { + case RMNET_VND_UF_ACTION_ADD: + rc = RMNET_VND_UPDATE_FLOW_NO_MORE_ROOM; + for (i = 0; i < RMNET_MAP_FLOW_NUM_TC_HANDLE; i++) { + if (itm->tc_flow_valid[i] == 0) { + itm->tc_flow_valid[i] = 1; + itm->tc_flow_id[i] = tc_flow; + rc = RMNET_VND_UPDATE_FLOW_OK; + LOGD("{%pK}->tc_flow_id[%d]=%08X", + itm, i, tc_flow); + break; + } + } + break; + + case RMNET_VND_UF_ACTION_DEL: + j = 0; + rc = RMNET_VND_UPDATE_FLOW_OK; + for (i = 0; i < RMNET_MAP_FLOW_NUM_TC_HANDLE; i++) { + if (itm->tc_flow_valid[i] == 1) { + if (itm->tc_flow_id[i] == tc_flow) { + itm->tc_flow_valid[i] = 0; + itm->tc_flow_id[i] = 0; + j++; + LOGD("{%pK}->tc_flow_id[%d]=0", itm, i); + } + } else { + j++; + } + } + if (j == RMNET_MAP_FLOW_NUM_TC_HANDLE) + rc = RMNET_VND_UPDATE_FLOW_NO_VALID_LEFT; + break; + + default: + rc = RMNET_VND_UPDATE_FLOW_NO_ACTION; + break; + } + return rc; +} + +/* rmnet_vnd_add_tc_flow() - Add a MAP/TC flow handle mapping + * @id: Virtual network device ID + * @map_flow: MAP flow handle + * @tc_flow: TC flow handle + * + * Checkes for an existing flow mapping object corresponding to map_flow. If one + * is found, then it will try to add to the existing mapping object. Otherwise, + * a new mapping object is created. + * + * Return: + * - RMNET_CONFIG_OK if successful + * - RMNET_CONFIG_TC_HANDLE_FULL if there is no more room in the map object + * - RMNET_CONFIG_NOMEM failed to allocate a new map object + */ +int rmnet_vnd_add_tc_flow(u32 id, u32 map_flow, u32 tc_flow) +{ + struct rmnet_map_flow_mapping_s *itm; + struct net_device *dev; + struct rmnet_vnd_private_s *dev_conf; + int r; + unsigned long flags; + + if ((id < 0) || (id >= RMNET_DATA_MAX_VND) || !rmnet_devices[id]) { + LOGM("Invalid VND id [%d]", id); + return RMNET_CONFIG_NO_SUCH_DEVICE; + } + + dev = rmnet_devices[id]; + dev_conf = (struct rmnet_vnd_private_s *)netdev_priv(dev); + + if (!dev_conf) + return RMNET_CONFIG_NO_SUCH_DEVICE; + + write_lock_irqsave(&dev_conf->flow_map_lock, flags); + itm = _rmnet_vnd_get_flow_map(dev_conf, map_flow); + if (itm) { + r = _rmnet_vnd_update_flow_map(RMNET_VND_UF_ACTION_ADD, + itm, tc_flow); + if (r != RMNET_VND_UPDATE_FLOW_OK) { + write_unlock_irqrestore(&dev_conf->flow_map_lock, + flags); + return RMNET_CONFIG_TC_HANDLE_FULL; + } + write_unlock_irqrestore(&dev_conf->flow_map_lock, flags); + return RMNET_CONFIG_OK; + } + write_unlock_irqrestore(&dev_conf->flow_map_lock, flags); + + itm = kmalloc(sizeof(*itm), GFP_KERNEL); + + if (!itm) { + LOGM("%s", "Failure allocating flow mapping"); + return RMNET_CONFIG_NOMEM; + } + memset(itm, 0, sizeof(struct rmnet_map_flow_mapping_s)); + + itm->map_flow_id = map_flow; + itm->tc_flow_valid[0] = 1; + itm->tc_flow_id[0] = tc_flow; + + /* How can we dynamically init these safely? Kernel only provides static + * initializers for atomic_t + */ + itm->v4_seq.counter = 0; /* Init is broken: ATOMIC_INIT(0); */ + itm->v6_seq.counter = 0; /* Init is broken: ATOMIC_INIT(0); */ + + write_lock_irqsave(&dev_conf->flow_map_lock, flags); + list_add(&itm->list, &dev_conf->flow_head); + write_unlock_irqrestore(&dev_conf->flow_map_lock, flags); + + LOGD("Created flow mapping [%s][0x%08X][0x%08X]@%pK", + dev->name, itm->map_flow_id, itm->tc_flow_id[0], itm); + + return RMNET_CONFIG_OK; +} + +/* rmnet_vnd_del_tc_flow() - Delete a MAP/TC flow handle mapping + * @id: Virtual network device ID + * @map_flow: MAP flow handle + * @tc_flow: TC flow handle + * + * Checkes for an existing flow mapping object corresponding to map_flow. If one + * is found, then it will try to remove the existing tc_flow mapping. If the + * mapping object no longer contains any mappings, then it is freed. Otherwise + * the mapping object is left in the list + * + * Return: + * - RMNET_CONFIG_OK if successful or if there was no such tc_flow + * - RMNET_CONFIG_INVALID_REQUEST if there is no such map_flow + */ +int rmnet_vnd_del_tc_flow(u32 id, u32 map_flow, u32 tc_flow) +{ + struct rmnet_vnd_private_s *dev_conf; + struct net_device *dev; + struct rmnet_map_flow_mapping_s *itm; + int r; + unsigned long flags; + int rc = RMNET_CONFIG_OK; + + if ((id < 0) || (id >= RMNET_DATA_MAX_VND) || !rmnet_devices[id]) { + LOGM("Invalid VND id [%d]", id); + return RMNET_CONFIG_NO_SUCH_DEVICE; + } + + dev = rmnet_devices[id]; + dev_conf = (struct rmnet_vnd_private_s *)netdev_priv(dev); + + if (!dev_conf) + return RMNET_CONFIG_NO_SUCH_DEVICE; + + r = RMNET_VND_UPDATE_FLOW_NO_ACTION; + write_lock_irqsave(&dev_conf->flow_map_lock, flags); + itm = _rmnet_vnd_get_flow_map(dev_conf, map_flow); + if (!itm) { + rc = RMNET_CONFIG_INVALID_REQUEST; + } else { + r = _rmnet_vnd_update_flow_map(RMNET_VND_UF_ACTION_DEL, + itm, tc_flow); + if (r == RMNET_VND_UPDATE_FLOW_NO_VALID_LEFT) + list_del(&itm->list); + } + write_unlock_irqrestore(&dev_conf->flow_map_lock, flags); + + if (r == RMNET_VND_UPDATE_FLOW_NO_VALID_LEFT) { + if (itm) + LOGD("Removed flow mapping [%s][0x%08X]@%pK", + dev->name, itm->map_flow_id, itm); + kfree(itm); + } + + return rc; +} + +/* rmnet_data_vnd_do_flow_control() - Process flow control request + * @dev: Virtual network device node to do lookup on + * @map_flow_id: Flow ID from MAP message + * @v4_seq: pointer to IPv4 indication sequence number + * @v6_seq: pointer to IPv6 indication sequence number + * @enable: boolean to enable/disable flow. + * + * Return: + * - 0 if successful + * - 1 if no mapping is found + * - 2 if dev is not RmNet virtual network device node + */ +int rmnet_data_vnd_do_flow_control(struct net_device *dev, + u32 map_flow_id, + u16 v4_seq, + u16 v6_seq, + int enable) +{ + struct rmnet_vnd_private_s *dev_conf; + struct rmnet_map_flow_mapping_s *itm; + int do_fc, error, i; + + error = 0; + do_fc = 0; + + if (unlikely(!dev)) + return 2; + + if (!rmnet_vnd_is_vnd(dev)) + return 2; + + dev_conf = (struct rmnet_vnd_private_s *)netdev_priv(dev); + + if (unlikely(!dev_conf)) + return 2; + + read_lock(&dev_conf->flow_map_lock); + if (map_flow_id == 0xFFFFFFFF) { + itm = &dev_conf->root_flow; + goto nolookup; + } + + itm = _rmnet_vnd_get_flow_map(dev_conf, map_flow_id); + + if (!itm) { + LOGL("Got flow control request for unknown flow %08X", + map_flow_id); + goto fcdone; + } + +nolookup: + if (v4_seq == 0 || v4_seq >= atomic_read(&itm->v4_seq)) { + atomic_set(&itm->v4_seq, v4_seq); + if (map_flow_id == 0xFFFFFFFF) { + LOGD("Setting VND TX queue state to %d", enable); + /* Although we expect similar number of enable/disable + * commands, optimize for the disable. That is more + * latency sensitive than enable + */ + if (unlikely(enable)) + netif_wake_queue(dev); + else + netif_stop_queue(dev); + trace_rmnet_fc_map(0xFFFFFFFF, 0, enable); + goto fcdone; + } + for (i = 0; i < RMNET_MAP_FLOW_NUM_TC_HANDLE; i++) { + if (itm->tc_flow_valid[i] == 1) { + LOGD("Found [%s][0x%08X][%d:0x%08X]", + dev->name, itm->map_flow_id, i, + itm->tc_flow_id[i]); + + _rmnet_vnd_do_flow_control(dev, + itm->tc_flow_id[i], + enable); + } + } + } else { + LOGD("Internal seq(%hd) higher than called(%hd)", + atomic_read(&itm->v4_seq), v4_seq); + } + +fcdone: + read_unlock(&dev_conf->flow_map_lock); + + return error; +} + +/* rmnet_vnd_get_by_id() - Get VND by array index ID + * @id: Virtual network deice id [0:RMNET_DATA_MAX_VND] + * + * Return: + * - 0 if no device or ID out of range + * - otherwise return pointer to VND net_device struct + */ +struct net_device *rmnet_vnd_get_by_id(int id) +{ + if (id < 0 || id >= RMNET_DATA_MAX_VND) { + LOGE("Bug; VND ID out of bounds"); + return 0; + } + return rmnet_devices[id]; +} diff --git a/net/rmnet_data/rmnet_data_vnd.h b/net/rmnet_data/rmnet_data_vnd.h new file mode 100644 index 000000000000..a121d5472bb2 --- /dev/null +++ b/net/rmnet_data/rmnet_data_vnd.h @@ -0,0 +1,37 @@ +/* Copyright (c) 2013-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. + * + * RMNET Data Virtual Network Device APIs + */ + +#include + +#ifndef _RMNET_DATA_VND_H_ +#define _RMNET_DATA_VND_H_ + +int rmnet_data_vnd_do_flow_control(struct net_device *dev, + u32 map_flow_id, + u16 v4_seq, + u16 v6_seq, + int enable); +struct rmnet_logical_ep_conf_s *rmnet_vnd_get_le_config(struct net_device *dev); +int rmnet_vnd_get_name(int id, char *name, int name_len); +int rmnet_vnd_create_dev(int id, struct net_device **new_device, + const char *prefix, int use_name); +int rmnet_vnd_free_dev(int id); +int rmnet_vnd_is_vnd(struct net_device *dev); +int rmnet_vnd_add_tc_flow(u32 id, u32 map_flow, u32 tc_flow); +int rmnet_vnd_del_tc_flow(u32 id, u32 map_flow, u32 tc_flow); +int rmnet_vnd_init(void); +void rmnet_vnd_exit(void); +struct net_device *rmnet_vnd_get_by_id(int id); + +#endif /* _RMNET_DATA_VND_H_ */ diff --git a/net/rmnet_data/rmnet_map.h b/net/rmnet_data/rmnet_map.h new file mode 100644 index 000000000000..4f074415e7c1 --- /dev/null +++ b/net/rmnet_data/rmnet_map.h @@ -0,0 +1,153 @@ +/* Copyright (c) 2013-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. + */ + +#include +#include +#include + +#ifndef _RMNET_MAP_H_ +#define _RMNET_MAP_H_ + +struct rmnet_map_control_command_s { + u8 command_name; +#ifndef RMNET_USE_BIG_ENDIAN_STRUCTS + u8 cmd_type:2; + u8 reserved:6; +#else + u8 reserved:6; + u8 cmd_type:2; +#endif /* RMNET_USE_BIG_ENDIAN_STRUCTS */ + u16 reserved2; + u32 transaction_id; + union { + u8 data[65528]; + struct { +#ifndef RMNET_USE_BIG_ENDIAN_STRUCTS + u16 ip_family:2; + u16 reserved:14; +#else + u16 reserved:14; + u16 ip_family:2; +#endif /* RMNET_USE_BIG_ENDIAN_STRUCTS */ + u16 flow_control_seq_num; + u32 qos_id; + } flow_control; + }; +} __aligned(1); + +struct rmnet_map_dl_checksum_trailer_s { + unsigned char reserved_h; +#if defined(__LITTLE_ENDIAN_BITFIELD) + unsigned char valid:1; + unsigned char reserved_l:7; +#elif defined(__BIG_ENDIAN_BITFIELD) + unsigned char reserved_l:7; + unsigned char valid:1; +#else +#error "Please fix " +#endif + unsigned short checksum_start_offset; + unsigned short checksum_length; + unsigned short checksum_value; +} __aligned(1); + +struct rmnet_map_ul_checksum_header_s { + unsigned short checksum_start_offset; +#if defined(__LITTLE_ENDIAN_BITFIELD) + unsigned short checksum_insert_offset:14; + unsigned short udp_ip4_ind:1; + unsigned short cks_en:1; +#elif defined(__BIG_ENDIAN_BITFIELD) + unsigned short cks_en:1; + unsigned short udp_ip4_ind:1; + unsigned short checksum_insert_offset:14; +#else +#error "Please fix " +#endif +} __aligned(1); + +enum rmnet_map_results_e { + RMNET_MAP_SUCCESS, + RMNET_MAP_CONSUMED, + RMNET_MAP_GENERAL_FAILURE, + RMNET_MAP_NOT_ENABLED, + RMNET_MAP_FAILED_AGGREGATION, + RMNET_MAP_FAILED_MUX +}; + +enum rmnet_map_mux_errors_e { + RMNET_MAP_MUX_SUCCESS, + RMNET_MAP_MUX_INVALID_MUX_ID, + RMNET_MAP_MUX_INVALID_PAD_LENGTH, + RMNET_MAP_MUX_INVALID_PKT_LENGTH, + /* This should always be the last element */ + RMNET_MAP_MUX_ENUM_LENGTH +}; + +enum rmnet_map_checksum_errors_e { + RMNET_MAP_CHECKSUM_OK, + RMNET_MAP_CHECKSUM_VALID_FLAG_NOT_SET, + RMNET_MAP_CHECKSUM_VALIDATION_FAILED, + RMNET_MAP_CHECKSUM_ERR_UNKNOWN, + RMNET_MAP_CHECKSUM_ERR_NOT_DATA_PACKET, + RMNET_MAP_CHECKSUM_ERR_BAD_BUFFER, + RMNET_MAP_CHECKSUM_ERR_UNKNOWN_IP_VERSION, + RMNET_MAP_CHECKSUM_ERR_UNKNOWN_TRANSPORT, + RMNET_MAP_CHECKSUM_FRAGMENTED_PACKET, + RMNET_MAP_CHECKSUM_SKIPPED, + RMNET_MAP_CHECKSUM_SW, + /* This should always be the last element */ + RMNET_MAP_CHECKSUM_ENUM_LENGTH +}; + +enum rmnet_map_commands_e { + RMNET_MAP_COMMAND_NONE, + RMNET_MAP_COMMAND_FLOW_DISABLE, + RMNET_MAP_COMMAND_FLOW_ENABLE, + /* These should always be the last 2 elements */ + RMNET_MAP_COMMAND_UNKNOWN, + RMNET_MAP_COMMAND_ENUM_LENGTH +}; + +enum rmnet_map_agg_state_e { + RMNET_MAP_AGG_IDLE, + RMNET_MAP_TXFER_SCHEDULED +}; + +#define RMNET_MAP_COMMAND_REQUEST 0 +#define RMNET_MAP_COMMAND_ACK 1 +#define RMNET_MAP_COMMAND_UNSUPPORTED 2 +#define RMNET_MAP_COMMAND_INVALID 3 + +#define RMNET_MAP_NO_PAD_BYTES 0 +#define RMNET_MAP_ADD_PAD_BYTES 1 + +uint8_t rmnet_map_demultiplex(struct sk_buff *skb); +struct sk_buff* +rmnet_data_map_deaggregate(struct sk_buff *skb, + struct rmnet_phys_ep_config *config); + +struct rmnet_map_header_s *rmnet_data_map_add_map_header(struct sk_buff *skb, + int hdrlen, int pad); +rx_handler_result_t +rmnet_data_map_command(struct sk_buff *skb, + struct rmnet_phys_ep_config *config); +void rmnet_map_aggregate(struct sk_buff *skb, + struct rmnet_phys_ep_config *config); + +int rmnet_map_data_checksum_downlink_packet(struct sk_buff *skb); +int rmnet_map_data_checksum_uplink_packet(struct sk_buff *skb, + struct net_device *orig_dev, + u32 egress_data_format); +int rmnet_ul_aggregation_skip(struct sk_buff *skb, int offset); +enum hrtimer_restart rmnet_map_flush_packet_queue(struct hrtimer *t); +#endif /* _RMNET_MAP_H_ */ diff --git a/net/rmnet_data/rmnet_map_command.c b/net/rmnet_data/rmnet_map_command.c new file mode 100644 index 000000000000..e6c7811d3478 --- /dev/null +++ b/net/rmnet_data/rmnet_map_command.c @@ -0,0 +1,205 @@ +/* Copyright (c) 2013-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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "rmnet_data_config.h" +#include "rmnet_map.h" +#include "rmnet_data_private.h" +#include "rmnet_data_vnd.h" +#include "rmnet_data_stats.h" + +RMNET_LOG_MODULE(RMNET_DATA_LOGMASK_MAPC); + +unsigned long int rmnet_map_command_stats[RMNET_MAP_COMMAND_ENUM_LENGTH]; +module_param_array(rmnet_map_command_stats, ulong, 0, 0444); +MODULE_PARM_DESC(rmnet_map_command_stats, "MAP command statistics"); + +/* rmnet_map_do_flow_control() - Process MAP flow control command + * @skb: Socket buffer containing the MAP flow control message + * @config: Physical end-point configuration of ingress device + * @enable: boolean for enable/disable + * + * Process in-band MAP flow control messages. Assumes mux ID is mapped to a + * RmNet Data vitrual network device. + * + * Return: + * - RMNET_MAP_COMMAND_UNSUPPORTED on any error + * - RMNET_MAP_COMMAND_ACK on success + */ +static uint8_t rmnet_map_do_flow_control(struct sk_buff *skb, + struct rmnet_phys_ep_config *config, + int enable) +{ + struct rmnet_map_control_command_s *cmd; + struct net_device *vnd; + struct rmnet_logical_ep_conf_s *ep; + u8 mux_id; + u16 ip_family; + u16 fc_seq; + u32 qos_id; + int r; + + if (unlikely(!skb || !config)) + return RX_HANDLER_CONSUMED; + + mux_id = RMNET_MAP_GET_MUX_ID(skb); + cmd = RMNET_MAP_GET_CMD_START(skb); + + if (mux_id >= RMNET_DATA_MAX_LOGICAL_EP) { + LOGD("Got packet on %s with bad mux id %d", + skb->dev->name, mux_id); + rmnet_kfree_skb(skb, RMNET_STATS_SKBFREE_MAPC_BAD_MUX); + return RX_HANDLER_CONSUMED; + } + + ep = &config->muxed_ep[mux_id]; + + if (!ep->refcount) { + LOGD("Packet on %s:%d; has no logical endpoint config", + skb->dev->name, mux_id); + + rmnet_kfree_skb(skb, RMNET_STATS_SKBFREE_MAPC_MUX_NO_EP); + return RX_HANDLER_CONSUMED; + } + + vnd = ep->egress_dev; + + ip_family = cmd->flow_control.ip_family; + fc_seq = ntohs(cmd->flow_control.flow_control_seq_num); + qos_id = ntohl(cmd->flow_control.qos_id); + + /* Ignore the ip family and pass the sequence number for both v4 and v6 + * sequence. User space does not support creating dedicated flows for + * the 2 protocols + */ + r = rmnet_data_vnd_do_flow_control(vnd, qos_id, fc_seq, fc_seq, enable); + LOGD("dev:%s, qos_id:0x%08X, ip_family:%hd, fc_seq %hd, en:%d", + skb->dev->name, qos_id, ip_family & 3, fc_seq, enable); + + if (r) { + rmnet_kfree_skb(skb, RMNET_STATS_SKBFREE_MAPC_UNSUPPORTED); + return RMNET_MAP_COMMAND_UNSUPPORTED; + } else { + return RMNET_MAP_COMMAND_ACK; + } +} + +/* rmnet_map_send_ack() - Send N/ACK message for MAP commands + * @skb: Socket buffer containing the MAP command message + * @type: N/ACK message selector + * @config: Physical end-point configuration of ingress device + * + * skb is modified to contain the message type selector. The message is then + * transmitted on skb->dev. Note that this function grabs global Tx lock on + * skb->dev for latency reasons. + * + * Return: + * - void + */ +static void rmnet_map_send_ack(struct sk_buff *skb, + unsigned char type, + struct rmnet_phys_ep_config *config) +{ + struct rmnet_map_control_command_s *cmd; + int xmit_status; + int rc; + + if (unlikely(!skb)) + return; + + skb->protocol = htons(ETH_P_MAP); + + if ((config->ingress_data_format & RMNET_INGRESS_FORMAT_MAP_CKSUMV3) || + (config->ingress_data_format & RMNET_INGRESS_FORMAT_MAP_CKSUMV4)) { + if (unlikely(skb->len < (sizeof(struct rmnet_map_header_s) + + + RMNET_MAP_GET_LENGTH(skb) + + sizeof(struct rmnet_map_dl_checksum_trailer_s)))) { + rmnet_stats_dl_checksum( + RMNET_MAP_CHECKSUM_ERR_BAD_BUFFER); + return; + } + + skb_trim(skb, skb->len - + sizeof(struct rmnet_map_dl_checksum_trailer_s)); + } + + cmd = RMNET_MAP_GET_CMD_START(skb); + cmd->cmd_type = type & 0x03; + + netif_tx_lock(skb->dev); + xmit_status = skb->dev->netdev_ops->ndo_start_xmit(skb, skb->dev); + netif_tx_unlock(skb->dev); + + LOGD("MAP command ACK=%hhu sent with rc: %d", type & 0x03, xmit_status); + + if (xmit_status != NETDEV_TX_OK) { + rc = dev_queue_xmit(skb); + if (rc != 0) { + LOGD("Failed to queue packet for transmission on [%s]", + skb->dev->name); + } + } +} + +/* rmnet_data_map_command() - Entry point for handling MAP commands + * @skb: Socket buffer containing the MAP command message + * @config: Physical end-point configuration of ingress device + * + * Process MAP command frame and send N/ACK message as appropriate. Message cmd + * name is decoded here and appropriate handler is called. + * + * Return: + * - RX_HANDLER_CONSUMED. Command frames are always consumed. + */ +rx_handler_result_t rmnet_data_map_command(struct sk_buff *skb, + struct rmnet_phys_ep_config *config) +{ + struct rmnet_map_control_command_s *cmd; + unsigned char command_name; + unsigned char rc = 0; + + if (unlikely(!skb)) + return RX_HANDLER_CONSUMED; + + cmd = RMNET_MAP_GET_CMD_START(skb); + command_name = cmd->command_name; + + if (command_name < RMNET_MAP_COMMAND_ENUM_LENGTH) + rmnet_map_command_stats[command_name]++; + + switch (command_name) { + case RMNET_MAP_COMMAND_FLOW_ENABLE: + rc = rmnet_map_do_flow_control(skb, config, 1); + break; + + case RMNET_MAP_COMMAND_FLOW_DISABLE: + rc = rmnet_map_do_flow_control(skb, config, 0); + break; + + default: + rmnet_map_command_stats[RMNET_MAP_COMMAND_UNKNOWN]++; + LOGM("Uknown MAP command: %d", command_name); + rc = RMNET_MAP_COMMAND_UNSUPPORTED; + rmnet_kfree_skb(skb, RMNET_STATS_SKBFREE_MAPC_UNSUPPORTED); + break; + } + if (rc == RMNET_MAP_COMMAND_ACK) + rmnet_map_send_ack(skb, rc, config); + return RX_HANDLER_CONSUMED; +} diff --git a/net/rmnet_data/rmnet_map_data.c b/net/rmnet_data/rmnet_map_data.c new file mode 100644 index 000000000000..4a8dae6969eb --- /dev/null +++ b/net/rmnet_data/rmnet_map_data.c @@ -0,0 +1,781 @@ +/* Copyright (c) 2013-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. + * + * RMNET Data MAP protocol + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "rmnet_data_config.h" +#include "rmnet_map.h" +#include "rmnet_data_private.h" +#include "rmnet_data_stats.h" +#include "rmnet_data_trace.h" + +RMNET_LOG_MODULE(RMNET_DATA_LOGMASK_MAPD); + +/* Local Definitions */ + +long agg_time_limit __read_mostly = 1000000L; +module_param(agg_time_limit, long, 0644); +MODULE_PARM_DESC(agg_time_limit, "Maximum time packets sit in the agg buf"); + +long agg_bypass_time __read_mostly = 10000000L; +module_param(agg_bypass_time, long, 0644); +MODULE_PARM_DESC(agg_bypass_time, "Skip agg when apart spaced more than this"); + +struct agg_work { + struct work_struct work; + struct rmnet_phys_ep_config *config; +}; + +#define RMNET_MAP_DEAGGR_SPACING 64 +#define RMNET_MAP_DEAGGR_HEADROOM (RMNET_MAP_DEAGGR_SPACING / 2) + +/* rmnet_data_map_add_map_header() - Adds MAP header to front of skb->data + * @skb: Socket buffer ("packet") to modify + * @hdrlen: Number of bytes of header data which should not be included in + * MAP length field + * @pad: Specify if padding the MAP packet to make it 4 byte aligned is + * necessary + * + * Padding is calculated and set appropriately in MAP header. Mux ID is + * initialized to 0. + * + * Return: + * - Pointer to MAP structure + * - 0 (null) if insufficient headroom + * - 0 (null) if insufficient tailroom for padding bytes + */ +struct rmnet_map_header_s *rmnet_data_map_add_map_header(struct sk_buff *skb, + int hdrlen, int pad) +{ + u32 padding, map_datalen; + u8 *padbytes; + struct rmnet_map_header_s *map_header; + + if (skb_headroom(skb) < sizeof(struct rmnet_map_header_s)) + return 0; + + map_datalen = skb->len - hdrlen; + map_header = (struct rmnet_map_header_s *) + skb_push(skb, sizeof(struct rmnet_map_header_s)); + memset(map_header, 0, sizeof(struct rmnet_map_header_s)); + + if (pad == RMNET_MAP_NO_PAD_BYTES) { + map_header->pkt_len = htons(map_datalen); + return map_header; + } + + padding = ALIGN(map_datalen, 4) - map_datalen; + + if (padding == 0) + goto done; + + if (skb_tailroom(skb) < padding) + return 0; + + padbytes = (u8 *)skb_put(skb, padding); + LOGD("pad: %d", padding); + memset(padbytes, 0, padding); + +done: + map_header->pkt_len = htons(map_datalen + padding); + map_header->pad_len = padding & 0x3F; + + return map_header; +} + +/* rmnet_data_map_deaggregate() - Deaggregates a single packet + * @skb: Source socket buffer containing multiple MAP frames + * @config: Physical endpoint configuration of the ingress device + * + * A whole new buffer is allocated for each portion of an aggregated frame. + * Caller should keep calling deaggregate() on the source skb until 0 is + * returned, indicating that there are no more packets to deaggregate. Caller + * is responsible for freeing the original skb. + * + * Return: + * - Pointer to new skb + * - 0 (null) if no more aggregated packets + */ +struct sk_buff *rmnet_data_map_deaggregate(struct sk_buff *skb, + struct rmnet_phys_ep_config *config) +{ + struct sk_buff *skbn; + struct rmnet_map_header_s *maph; + u32 packet_len; + + if (skb->len == 0) + return 0; + + maph = (struct rmnet_map_header_s *)skb->data; + packet_len = ntohs(maph->pkt_len) + sizeof(struct rmnet_map_header_s); + + if ((config->ingress_data_format & RMNET_INGRESS_FORMAT_MAP_CKSUMV3) || + (config->ingress_data_format & RMNET_INGRESS_FORMAT_MAP_CKSUMV4)) + packet_len += sizeof(struct rmnet_map_dl_checksum_trailer_s); + + if ((((int)skb->len) - ((int)packet_len)) < 0) { + LOGM("%s", "Got malformed packet. Dropping"); + return 0; + } + + skbn = alloc_skb(packet_len + RMNET_MAP_DEAGGR_SPACING, GFP_ATOMIC); + if (!skbn) + return 0; + + skbn->dev = skb->dev; + skb_reserve(skbn, RMNET_MAP_DEAGGR_HEADROOM); + skb_put(skbn, packet_len); + memcpy(skbn->data, skb->data, packet_len); + skb_pull(skb, packet_len); + + /* Some hardware can send us empty frames. Catch them */ + if (ntohs(maph->pkt_len) == 0) { + LOGD("Dropping empty MAP frame"); + rmnet_kfree_skb(skbn, RMNET_STATS_SKBFREE_DEAGG_DATA_LEN_0); + return 0; + } + + return skbn; +} + +static void rmnet_map_flush_packet_work(struct work_struct *work) +{ + struct rmnet_phys_ep_config *config; + struct agg_work *real_work; + int rc, agg_count = 0; + unsigned long flags; + struct sk_buff *skb; + + real_work = (struct agg_work *)work; + config = real_work->config; + skb = NULL; + + LOGD("%s", "Entering flush thread"); + spin_lock_irqsave(&config->agg_lock, flags); + if (likely(config->agg_state == RMNET_MAP_TXFER_SCHEDULED)) { + /* Buffer may have already been shipped out */ + if (likely(config->agg_skb)) { + rmnet_stats_agg_pkts(config->agg_count); + if (config->agg_count > 1) + LOGL("Agg count: %d", config->agg_count); + skb = config->agg_skb; + agg_count = config->agg_count; + config->agg_skb = NULL; + config->agg_count = 0; + memset(&config->agg_time, 0, sizeof(struct timespec)); + } + config->agg_state = RMNET_MAP_AGG_IDLE; + } + + spin_unlock_irqrestore(&config->agg_lock, flags); + if (skb) { + trace_rmnet_map_flush_packet_queue(skb, agg_count); + rc = dev_queue_xmit(skb); + rmnet_stats_queue_xmit(rc, RMNET_STATS_QUEUE_XMIT_AGG_TIMEOUT); + } + + kfree(work); +} + +/* rmnet_map_flush_packet_queue() - Transmits aggregeted frame on timeout + * + * This function is scheduled to run in a specified number of ns after + * the last frame transmitted by the network stack. When run, the buffer + * containing aggregated packets is finally transmitted on the underlying link. + * + */ +enum hrtimer_restart rmnet_map_flush_packet_queue(struct hrtimer *t) +{ + struct rmnet_phys_ep_config *config; + struct agg_work *work; + + config = container_of(t, struct rmnet_phys_ep_config, hrtimer); + + work = kmalloc(sizeof(*work), GFP_ATOMIC); + if (!work) { + config->agg_state = RMNET_MAP_AGG_IDLE; + + return HRTIMER_NORESTART; + } + + INIT_WORK(&work->work, rmnet_map_flush_packet_work); + work->config = config; + schedule_work((struct work_struct *)work); + return HRTIMER_NORESTART; +} + +/* rmnet_map_aggregate() - Software aggregates multiple packets. + * @skb: current packet being transmitted + * @config: Physical endpoint configuration of the ingress device + * + * Aggregates multiple SKBs into a single large SKB for transmission. MAP + * protocol is used to separate the packets in the buffer. This function + * consumes the argument SKB and should not be further processed by any other + * function. + */ +void rmnet_map_aggregate(struct sk_buff *skb, + struct rmnet_phys_ep_config *config) +{ + u8 *dest_buff; + unsigned long flags; + struct sk_buff *agg_skb; + struct timespec diff, last; + int size, rc, agg_count = 0; + + if (!skb || !config) + return; + +new_packet: + spin_lock_irqsave(&config->agg_lock, flags); + memcpy(&last, &config->agg_last, sizeof(struct timespec)); + getnstimeofday(&config->agg_last); + + if (!config->agg_skb) { + /* Check to see if we should agg first. If the traffic is very + * sparse, don't aggregate. We will need to tune this later + */ + diff = timespec_sub(config->agg_last, last); + + if ((diff.tv_sec > 0) || (diff.tv_nsec > agg_bypass_time)) { + spin_unlock_irqrestore(&config->agg_lock, flags); + LOGL("delta t: %ld.%09lu\tcount: bypass", diff.tv_sec, + diff.tv_nsec); + rmnet_stats_agg_pkts(1); + trace_rmnet_map_aggregate(skb, 0); + rc = dev_queue_xmit(skb); + rmnet_stats_queue_xmit(rc, + RMNET_STATS_QUEUE_XMIT_AGG_SKIP); + return; + } + + size = config->egress_agg_size - skb->len; + config->agg_skb = skb_copy_expand(skb, 0, size, GFP_ATOMIC); + if (!config->agg_skb) { + config->agg_skb = 0; + config->agg_count = 0; + memset(&config->agg_time, 0, sizeof(struct timespec)); + spin_unlock_irqrestore(&config->agg_lock, flags); + rmnet_stats_agg_pkts(1); + trace_rmnet_map_aggregate(skb, 0); + rc = dev_queue_xmit(skb); + rmnet_stats_queue_xmit + (rc, + RMNET_STATS_QUEUE_XMIT_AGG_CPY_EXP_FAIL); + return; + } + config->agg_count = 1; + getnstimeofday(&config->agg_time); + trace_rmnet_start_aggregation(skb); + rmnet_kfree_skb(skb, RMNET_STATS_SKBFREE_AGG_CPY_EXPAND); + goto schedule; + } + diff = timespec_sub(config->agg_last, config->agg_time); + + if (skb->len > (config->egress_agg_size - config->agg_skb->len) || + (config->agg_count >= config->egress_agg_count) || + (diff.tv_sec > 0) || (diff.tv_nsec > agg_time_limit)) { + rmnet_stats_agg_pkts(config->agg_count); + agg_skb = config->agg_skb; + agg_count = config->agg_count; + config->agg_skb = 0; + config->agg_count = 0; + memset(&config->agg_time, 0, sizeof(struct timespec)); + config->agg_state = RMNET_MAP_AGG_IDLE; + spin_unlock_irqrestore(&config->agg_lock, flags); + hrtimer_cancel(&config->hrtimer); + LOGL("delta t: %ld.%09lu\tcount: %d", diff.tv_sec, + diff.tv_nsec, agg_count); + trace_rmnet_map_aggregate(skb, agg_count); + rc = dev_queue_xmit(agg_skb); + rmnet_stats_queue_xmit(rc, + RMNET_STATS_QUEUE_XMIT_AGG_FILL_BUFFER); + goto new_packet; + } + + dest_buff = skb_put(config->agg_skb, skb->len); + memcpy(dest_buff, skb->data, skb->len); + config->agg_count++; + rmnet_kfree_skb(skb, RMNET_STATS_SKBFREE_AGG_INTO_BUFF); + +schedule: + if (config->agg_state != RMNET_MAP_TXFER_SCHEDULED) { + config->agg_state = RMNET_MAP_TXFER_SCHEDULED; + hrtimer_start(&config->hrtimer, ns_to_ktime(3000000), + HRTIMER_MODE_REL); + } + spin_unlock_irqrestore(&config->agg_lock, flags); +} + +/* Checksum Offload */ + +static inline u16 *rmnet_map_get_checksum_field(unsigned char protocol, + const void *txporthdr) +{ + u16 *check = 0; + + switch (protocol) { + case IPPROTO_TCP: + check = &(((struct tcphdr *)txporthdr)->check); + break; + + case IPPROTO_UDP: + check = &(((struct udphdr *)txporthdr)->check); + break; + + default: + check = 0; + break; + } + + return check; +} + +static inline u16 rmnet_map_add_checksums(u16 val1, u16 val2) +{ + int sum = val1 + val2; + + sum = (((sum & 0xFFFF0000) >> 16) + sum) & 0x0000FFFF; + return (u16)(sum & 0x0000FFFF); +} + +static inline u16 rmnet_map_subtract_checksums(u16 val1, u16 val2) +{ + return rmnet_map_add_checksums(val1, ~val2); +} + +/* rmnet_map_validate_ipv4_packet_checksum() - Validates TCP/UDP checksum + * value for IPv4 packet + * @map_payload: Pointer to the beginning of the map payload + * @cksum_trailer: Pointer to the checksum trailer + * + * Validates the TCP/UDP checksum for the packet using the checksum value + * from the checksum trailer added to the packet. + * The validation formula is the following: + * 1. Performs 1's complement over the checksum value from the trailer + * 2. Computes 1's complement checksum over IPv4 header and subtracts it from + * the value from step 1 + * 3. Computes 1's complement checksum over IPv4 pseudo header and adds it to + * the value from step 2 + * 4. Subtracts the checksum value from the TCP/UDP header from the value from + * step 3 + * 5. Compares the value from step 4 to the checksum value from the TCP/UDP + * header + * + * Fragmentation and tunneling are not supported. + * + * Return: 0 is validation succeeded. + */ +static int rmnet_map_validate_ipv4_packet_checksum + (unsigned char *map_payload, + struct rmnet_map_dl_checksum_trailer_s *cksum_trailer) +{ + struct iphdr *ip4h; + u16 *checksum_field; + void *txporthdr; + u16 pseudo_checksum; + u16 ip_hdr_checksum; + u16 checksum_value; + u16 ip_payload_checksum; + u16 ip_pseudo_payload_checksum; + u16 checksum_value_final; + + ip4h = (struct iphdr *)map_payload; + if ((ntohs(ip4h->frag_off) & IP_MF) || + ((ntohs(ip4h->frag_off) & IP_OFFSET) > 0)) + return RMNET_MAP_CHECKSUM_FRAGMENTED_PACKET; + + txporthdr = map_payload + ip4h->ihl * 4; + + checksum_field = rmnet_map_get_checksum_field(ip4h->protocol, + txporthdr); + + if (unlikely(!checksum_field)) + return RMNET_MAP_CHECKSUM_ERR_UNKNOWN_TRANSPORT; + + /* RFC 768 - Skip IPv4 UDP packets where sender checksum field is 0 */ + if ((*checksum_field == 0) && (ip4h->protocol == IPPROTO_UDP)) + return RMNET_MAP_CHECKSUM_SKIPPED; + + checksum_value = ~ntohs(cksum_trailer->checksum_value); + ip_hdr_checksum = ~ip_fast_csum(ip4h, (int)ip4h->ihl); + ip_payload_checksum = rmnet_map_subtract_checksums(checksum_value, + ip_hdr_checksum); + + pseudo_checksum = ~ntohs(csum_tcpudp_magic(ip4h->saddr, ip4h->daddr, + (u16)(ntohs(ip4h->tot_len) - ip4h->ihl * 4), + (u16)ip4h->protocol, 0)); + ip_pseudo_payload_checksum = rmnet_map_add_checksums( + ip_payload_checksum, pseudo_checksum); + + checksum_value_final = ~rmnet_map_subtract_checksums( + ip_pseudo_payload_checksum, ntohs(*checksum_field)); + + if (unlikely(checksum_value_final == 0)) { + switch (ip4h->protocol) { + case IPPROTO_UDP: + /* RFC 768 */ + LOGD("DL4 1's complement rule for UDP checksum 0"); + checksum_value_final = ~checksum_value_final; + break; + + case IPPROTO_TCP: + if (*checksum_field == 0xFFFF) { + LOGD( + "DL4 Non-RFC compliant TCP checksum found"); + checksum_value_final = ~checksum_value_final; + } + break; + } + } + + LOGD( + "DL4 cksum: ~HW: %04X, field: %04X, pseudo header: %04X, final: %04X", + ~ntohs(cksum_trailer->checksum_value), ntohs(*checksum_field), + pseudo_checksum, checksum_value_final); + + if (checksum_value_final == ntohs(*checksum_field)) + return RMNET_MAP_CHECKSUM_OK; + else + return RMNET_MAP_CHECKSUM_VALIDATION_FAILED; +} + +/* rmnet_map_validate_ipv6_packet_checksum() - Validates TCP/UDP checksum + * value for IPv6 packet + * @map_payload: Pointer to the beginning of the map payload + * @cksum_trailer: Pointer to the checksum trailer + * + * Validates the TCP/UDP checksum for the packet using the checksum value + * from the checksum trailer added to the packet. + * The validation formula is the following: + * 1. Performs 1's complement over the checksum value from the trailer + * 2. Computes 1's complement checksum over IPv6 header and subtracts it from + * the value from step 1 + * 3. Computes 1's complement checksum over IPv6 pseudo header and adds it to + * the value from step 2 + * 4. Subtracts the checksum value from the TCP/UDP header from the value from + * step 3 + * 5. Compares the value from step 4 to the checksum value from the TCP/UDP + * header + * + * Fragmentation, extension headers and tunneling are not supported. + * + * Return: 0 is validation succeeded. + */ +static int rmnet_map_validate_ipv6_packet_checksum + (unsigned char *map_payload, + struct rmnet_map_dl_checksum_trailer_s *cksum_trailer) +{ + struct ipv6hdr *ip6h; + u16 *checksum_field; + void *txporthdr; + u16 pseudo_checksum; + u16 ip_hdr_checksum; + u16 checksum_value; + u16 ip_payload_checksum; + u16 ip_pseudo_payload_checksum; + u16 checksum_value_final; + u32 length; + + ip6h = (struct ipv6hdr *)map_payload; + + txporthdr = map_payload + sizeof(struct ipv6hdr); + checksum_field = rmnet_map_get_checksum_field(ip6h->nexthdr, + txporthdr); + + if (unlikely(!checksum_field)) + return RMNET_MAP_CHECKSUM_ERR_UNKNOWN_TRANSPORT; + + checksum_value = ~ntohs(cksum_trailer->checksum_value); + ip_hdr_checksum = ~ntohs(ip_compute_csum(ip6h, + (int)(txporthdr - (void *)map_payload))); + ip_payload_checksum = rmnet_map_subtract_checksums + (checksum_value, ip_hdr_checksum); + + length = (ip6h->nexthdr == IPPROTO_UDP) ? + ntohs(((struct udphdr *)txporthdr)->len) : + ntohs(ip6h->payload_len); + pseudo_checksum = ~ntohs(csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr, + length, ip6h->nexthdr, 0)); + ip_pseudo_payload_checksum = rmnet_map_add_checksums( + ip_payload_checksum, pseudo_checksum); + + checksum_value_final = ~rmnet_map_subtract_checksums( + ip_pseudo_payload_checksum, ntohs(*checksum_field)); + + if (unlikely(checksum_value_final == 0)) { + switch (ip6h->nexthdr) { + case IPPROTO_UDP: + /* RFC 2460 section 8.1 */ + LOGD("DL6 One's complement rule for UDP checksum 0"); + checksum_value_final = ~checksum_value_final; + break; + + case IPPROTO_TCP: + if (*checksum_field == 0xFFFF) { + LOGD( + "DL6 Non-RFC compliant TCP checksum found"); + checksum_value_final = ~checksum_value_final; + } + break; + } + } + + LOGD( + "DL6 cksum: ~HW: %04X, field: %04X, pseudo header: %04X, final: %04X", + ~ntohs(cksum_trailer->checksum_value), ntohs(*checksum_field), + pseudo_checksum, checksum_value_final); + + if (checksum_value_final == ntohs(*checksum_field)) + return RMNET_MAP_CHECKSUM_OK; + else + return RMNET_MAP_CHECKSUM_VALIDATION_FAILED; + } + +/* rmnet_map_data_checksum_downlink_packet() - Validates checksum on + * a downlink packet + * @skb: Pointer to the packet's skb. + * + * Validates packet checksums. Function takes a pointer to + * the beginning of a buffer which contains the entire MAP + * frame: MAP header + IP payload + padding + checksum trailer. + * Currently, only IPv4 and IPv6 are supported along with + * TCP & UDP. Fragmented or tunneled packets are not supported. + * + * Return: + * - RMNET_MAP_CHECKSUM_OK: Validation of checksum succeeded. + * - RMNET_MAP_CHECKSUM_ERR_BAD_BUFFER: Skb buffer given is corrupted. + * - RMNET_MAP_CHECKSUM_VALID_FLAG_NOT_SET: Valid flag is not set in the + * checksum trailer. + * - RMNET_MAP_CHECKSUM_FRAGMENTED_PACKET: The packet is a fragment. + * - RMNET_MAP_CHECKSUM_ERR_UNKNOWN_TRANSPORT: The transport header is + * not TCP/UDP. + * - RMNET_MAP_CHECKSUM_ERR_UNKNOWN_IP_VERSION: Unrecognized IP header. + * - RMNET_MAP_CHECKSUM_VALIDATION_FAILED: In case the validation failed. + */ +int rmnet_map_data_checksum_downlink_packet(struct sk_buff *skb) +{ + struct rmnet_map_dl_checksum_trailer_s *cksum_trailer; + unsigned int data_len; + unsigned char *map_payload; + unsigned char ip_version; + + data_len = RMNET_MAP_GET_LENGTH(skb); + + if (unlikely(skb->len < (sizeof(struct rmnet_map_header_s) + data_len + + sizeof(struct rmnet_map_dl_checksum_trailer_s)))) + return RMNET_MAP_CHECKSUM_ERR_BAD_BUFFER; + + cksum_trailer = (struct rmnet_map_dl_checksum_trailer_s *) + (skb->data + data_len + + sizeof(struct rmnet_map_header_s)); + + if (unlikely(!ntohs(cksum_trailer->valid))) + return RMNET_MAP_CHECKSUM_VALID_FLAG_NOT_SET; + + map_payload = (unsigned char *)(skb->data + + sizeof(struct rmnet_map_header_s)); + + ip_version = (*map_payload & 0xF0) >> 4; + if (ip_version == 0x04) + return rmnet_map_validate_ipv4_packet_checksum(map_payload, + cksum_trailer); + else if (ip_version == 0x06) + return rmnet_map_validate_ipv6_packet_checksum(map_payload, + cksum_trailer); + + return RMNET_MAP_CHECKSUM_ERR_UNKNOWN_IP_VERSION; +} + +static void rmnet_map_fill_ipv4_packet_ul_checksum_header + (void *iphdr, struct rmnet_map_ul_checksum_header_s *ul_header, + struct sk_buff *skb) +{ + struct iphdr *ip4h = (struct iphdr *)iphdr; + unsigned short *hdr = (unsigned short *)ul_header; + + ul_header->checksum_start_offset = htons((unsigned short) + (skb_transport_header(skb) - (unsigned char *)iphdr)); + ul_header->checksum_insert_offset = skb->csum_offset; + ul_header->cks_en = 1; + if (ip4h->protocol == IPPROTO_UDP) + ul_header->udp_ip4_ind = 1; + else + ul_header->udp_ip4_ind = 0; + /* Changing checksum_insert_offset to network order */ + hdr++; + *hdr = htons(*hdr); + skb->ip_summed = CHECKSUM_NONE; +} + +static void rmnet_map_fill_ipv6_packet_ul_checksum_header + (void *iphdr, struct rmnet_map_ul_checksum_header_s *ul_header, + struct sk_buff *skb) +{ + unsigned short *hdr = (unsigned short *)ul_header; + + ul_header->checksum_start_offset = htons((unsigned short) + (skb_transport_header(skb) - (unsigned char *)iphdr)); + ul_header->checksum_insert_offset = skb->csum_offset; + ul_header->cks_en = 1; + ul_header->udp_ip4_ind = 0; + /* Changing checksum_insert_offset to network order */ + hdr++; + *hdr = htons(*hdr); + skb->ip_summed = CHECKSUM_NONE; +} + +static void rmnet_map_complement_ipv4_txporthdr_csum_field(void *iphdr) +{ + struct iphdr *ip4h = (struct iphdr *)iphdr; + void *txporthdr; + u16 *csum; + + txporthdr = iphdr + ip4h->ihl * 4; + + if ((ip4h->protocol == IPPROTO_TCP) || + (ip4h->protocol == IPPROTO_UDP)) { + csum = (u16 *)rmnet_map_get_checksum_field(ip4h->protocol, + txporthdr); + *csum = ~(*csum); + } +} + +static void rmnet_map_complement_ipv6_txporthdr_csum_field(void *ip6hdr) +{ + struct ipv6hdr *ip6h = (struct ipv6hdr *)ip6hdr; + void *txporthdr; + u16 *csum; + + txporthdr = ip6hdr + sizeof(struct ipv6hdr); + + if ((ip6h->nexthdr == IPPROTO_TCP) || (ip6h->nexthdr == IPPROTO_UDP)) { + csum = (u16 *)rmnet_map_get_checksum_field(ip6h->nexthdr, + txporthdr); + *csum = ~(*csum); + } +} + +/* rmnet_map_checksum_uplink_packet() - Generates UL checksum + * meta info header + * @skb: Pointer to the packet's skb. + * + * Generates UL checksum meta info header for IPv4 and IPv6 over TCP and UDP + * packets that are supported for UL checksum offload. + * + * Return: + * - RMNET_MAP_CHECKSUM_OK: Validation of checksum succeeded. + * - RMNET_MAP_CHECKSUM_ERR_UNKNOWN_IP_VERSION: Unrecognized IP header. + * - RMNET_MAP_CHECKSUM_SW: Unsupported packet for UL checksum offload. + */ +int rmnet_map_data_checksum_uplink_packet(struct sk_buff *skb, + struct net_device *orig_dev, + u32 egress_data_format) +{ + unsigned char ip_version; + struct rmnet_map_ul_checksum_header_s *ul_header; + void *iphdr; + int ret; + + ul_header = (struct rmnet_map_ul_checksum_header_s *) + skb_push(skb, sizeof(struct rmnet_map_ul_checksum_header_s)); + + if (unlikely(!(orig_dev->features & + (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM)))) { + ret = RMNET_MAP_CHECKSUM_SW; + goto sw_checksum; + } + + if (skb->ip_summed == CHECKSUM_PARTIAL) { + iphdr = (char *)ul_header + + sizeof(struct rmnet_map_ul_checksum_header_s); + ip_version = (*(char *)iphdr & 0xF0) >> 4; + if (ip_version == 0x04) { + rmnet_map_fill_ipv4_packet_ul_checksum_header + (iphdr, ul_header, skb); + if (egress_data_format & + RMNET_EGRESS_FORMAT_MAP_CKSUMV4) + rmnet_map_complement_ipv4_txporthdr_csum_field( + iphdr); + ret = RMNET_MAP_CHECKSUM_OK; + goto done; + } else if (ip_version == 0x06) { + rmnet_map_fill_ipv6_packet_ul_checksum_header + (iphdr, ul_header, skb); + if (egress_data_format & + RMNET_EGRESS_FORMAT_MAP_CKSUMV4) + rmnet_map_complement_ipv6_txporthdr_csum_field( + iphdr); + ret = RMNET_MAP_CHECKSUM_OK; + goto done; + } else { + ret = RMNET_MAP_CHECKSUM_ERR_UNKNOWN_IP_VERSION; + goto sw_checksum; + } + } else { + ret = RMNET_MAP_CHECKSUM_SW; + goto sw_checksum; + } + +sw_checksum: + ul_header->checksum_start_offset = 0; + ul_header->checksum_insert_offset = 0; + ul_header->cks_en = 0; + ul_header->udp_ip4_ind = 0; +done: + return ret; +} + +int rmnet_ul_aggregation_skip(struct sk_buff *skb, int offset) +{ + unsigned char *packet_start = skb->data + offset; + int is_icmp = 0; + + if (skb->data[offset] >> 4 == 0x04) { + struct iphdr *ip4h = (struct iphdr *)(packet_start); + + if (ip4h->protocol == IPPROTO_ICMP) + is_icmp = 1; + } else if ((skb->data[offset]) >> 4 == 0x06) { + struct ipv6hdr *ip6h = (struct ipv6hdr *)(packet_start); + + if (ip6h->nexthdr == IPPROTO_ICMPV6) { + is_icmp = 1; + } else if (ip6h->nexthdr == NEXTHDR_FRAGMENT) { + struct frag_hdr *frag; + + frag = (struct frag_hdr *)(packet_start + + sizeof(struct ipv6hdr)); + if (frag->nexthdr == IPPROTO_ICMPV6) + is_icmp = 1; + } + } + + return is_icmp; +} From 0b108b7c562000800719573fea29aad3f21ac8ea Mon Sep 17 00:00:00 2001 From: duckyduckG Date: Sat, 11 Oct 2025 15:16:37 +0500 Subject: [PATCH 200/356] arm64: configs: sdm845: enable rmnet_data driver --- arch/arm64/configs/vendor/sdm845-perf_defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/configs/vendor/sdm845-perf_defconfig b/arch/arm64/configs/vendor/sdm845-perf_defconfig index 04c75e4b83fa..cc5aaa8c5aa2 100644 --- a/arch/arm64/configs/vendor/sdm845-perf_defconfig +++ b/arch/arm64/configs/vendor/sdm845-perf_defconfig @@ -311,6 +311,8 @@ CONFIG_TUN=y CONFIG_VETH=y CONFIG_SKY2=y CONFIG_RMNET=y +CONFIG_RMNET_DATA=y +CONFIG_RMNET_DATA_FC=y CONFIG_SMSC911X=y CONFIG_PPP=y CONFIG_PPP_BSDCOMP=y From 2ef8c78d2b0c664c3aae19270ad0cd63bc4ccd6a Mon Sep 17 00:00:00 2001 From: Kaustubh Pandey Date: Sat, 11 Oct 2025 15:18:59 +0500 Subject: [PATCH 201/356] net: rmnet: add ioctl support for IP route utility Add a new define to support rmnet ioctl for IP ROUTE. Change-Id: Ie95eea114d698a53a7c85bce0be9a5823f11ed80 Signed-off-by: Kaustubh Pandey --- include/uapi/linux/msm_rmnet.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/uapi/linux/msm_rmnet.h b/include/uapi/linux/msm_rmnet.h index 5c3ec42599e2..e5d70a7e3969 100644 --- a/include/uapi/linux/msm_rmnet.h +++ b/include/uapi/linux/msm_rmnet.h @@ -82,6 +82,7 @@ #define RMNET_IOCTL_EGRESS_FORMAT_AGGREGATION (1<<2) #define RMNET_IOCTL_EGRESS_FORMAT_MUXING (1<<3) #define RMNET_IOCTL_EGRESS_FORMAT_CHECKSUM (1<<4) +#define RMNET_IOCTL_EGRESS_FORMAT_IP_ROUTE (1<<5) /* Input values for the RMNET_IOCTL_SET_INGRESS_DATA_FORMAT IOCTL */ #define RMNET_IOCTL_INGRESS_FORMAT_MAP (1<<1) @@ -89,6 +90,7 @@ #define RMNET_IOCTL_INGRESS_FORMAT_DEMUXING (1<<3) #define RMNET_IOCTL_INGRESS_FORMAT_CHECKSUM (1<<4) #define RMNET_IOCTL_INGRESS_FORMAT_AGG_DATA (1<<5) +#define RMNET_IOCTL_INGRESS_FORMAT_IP_ROUTE (1<<6) /* Input values for the RMNET_IOCTL_SET_OFFLOAD */ #define RMNET_IOCTL_OFFLOAD_FORMAT_NONE (0) From abb6ec6bf19d6ac84e72ea059103f0c56129c841 Mon Sep 17 00:00:00 2001 From: Sivakanth vaka Date: Sat, 11 Oct 2025 15:33:22 +0500 Subject: [PATCH 202/356] msm: ipa3: Standalone CV2X changes remove QMAP aggregation to Support Cv2X on WAN pipe by for standalone usecases. Change-Id: Iea68c9428ec653f192ec03e4a03da1556a77f5fe Signed-off-by: sivakanth reddy vaka --- drivers/platform/msm/ipa/ipa_v3/ipa_dp.c | 5 ++- drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c | 49 +++++++++++++++------ include/linux/ipa.h | 2 + 3 files changed, 42 insertions(+), 14 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c index 84023764bb28..c5020d846b32 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c @@ -3884,7 +3884,10 @@ static int ipa3_assign_policy(struct ipa_sys_connect_params *in, IPA_GENERIC_RX_BUFF_BASE_SZ); sys->get_skb = ipa3_get_skb_ipa_rx; sys->free_skb = ipa3_free_skb_rx; - in->ipa_ep_cfg.aggr.aggr_en = IPA_ENABLE_AGGR; + if (in->bypass_agg) + in->ipa_ep_cfg.aggr.aggr_en = IPA_BYPASS_AGGR; + else + in->ipa_ep_cfg.aggr.aggr_en = IPA_ENABLE_AGGR; if (in->client == IPA_CLIENT_APPS_WAN_COAL_CONS) in->ipa_ep_cfg.aggr.aggr = IPA_COALESCE; else diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c index 93cff5708f73..d4858d77c64e 100644 --- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c @@ -160,6 +160,7 @@ struct rmnet_ipa3_context { atomic_t ap_suspend; bool ipa_config_is_apq; bool ipa_mhi_aggr_formet_set; + bool no_qmap_config; }; static struct rmnet_ipa3_context *rmnet_ipa3_ctx; @@ -1236,7 +1237,8 @@ static int ipa3_wwan_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } - if (skb->protocol != htons(ETH_P_MAP)) { + if (skb->protocol != htons(ETH_P_MAP) && + (!rmnet_ipa3_ctx->no_qmap_config)) { IPAWANDBG_LOW ("SW filtering out none QMAP packet received from %s", current->comm); @@ -1257,17 +1259,22 @@ static int ipa3_wwan_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_BUSY; } if (netif_queue_stopped(dev)) { - if (qmap_check && - atomic_read(&wwan_ptr->outstanding_pkts) < - rmnet_ipa3_ctx->outstanding_high_ctl) { - IPAWANERR("[%s]Queue stop, send ctrl pkts\n", - dev->name); - goto send; - } else { - IPAWANERR("[%s]fatal: %s stopped\n", dev->name, - __func__); + if (rmnet_ipa3_ctx->no_qmap_config) { spin_unlock_irqrestore(&wwan_ptr->lock, flags); return NETDEV_TX_BUSY; + } else { + if (qmap_check && + atomic_read(&wwan_ptr->outstanding_pkts) < + rmnet_ipa3_ctx->outstanding_high_ctl) { + IPAWANERR("[%s]Queue stop, send ctrl pkts\n", + dev->name); + goto send; + } else { + IPAWANERR("[%s]fatal: %s stopped\n", dev->name, + __func__); + spin_unlock_irqrestore(&wwan_ptr->lock, flags); + return NETDEV_TX_BUSY; + } } } /* checking High WM hit */ @@ -1428,7 +1435,8 @@ static void apps_ipa_packet_receive_notify(void *priv, IPAWANDBG_LOW("Rx packet was received"); skb->dev = IPA_NETDEV(); - skb->protocol = htons(ETH_P_MAP); + if (!rmnet_ipa3_ctx->no_qmap_config) + skb->protocol = htons(ETH_P_MAP); skb_set_mac_header(skb, 0); if (ipa3_rmnet_res.ipa_napi_enable) { @@ -1503,6 +1511,12 @@ static int handle3_ingress_format(struct net_device *dev, IPAWANDBG("DL chksum set\n"); } + + if ((in->u.data) & RMNET_IOCTL_INGRESS_FORMAT_IP_ROUTE) { + rmnet_ipa3_ctx->no_qmap_config = true; + ipa_wan_ep_cfg->bypass_agg = true; + } + if ((in->u.data) & RMNET_IOCTL_INGRESS_FORMAT_AGG_DATA) { IPAWANDBG("get AGG size %d count %d\n", in->u.ingress_format.agg_size, @@ -1525,8 +1539,11 @@ static int handle3_ingress_format(struct net_device *dev, ipa_wan_ep_cfg->ipa_ep_cfg.hdr.hdr_len = 8; rmnet_ipa3_ctx->dl_csum_offload_enabled = true; } else { - ipa_wan_ep_cfg->ipa_ep_cfg.hdr.hdr_len = 4; rmnet_ipa3_ctx->dl_csum_offload_enabled = false; + if (rmnet_ipa3_ctx->no_qmap_config) + ipa_wan_ep_cfg->ipa_ep_cfg.hdr.hdr_len = 0; + else + ipa_wan_ep_cfg->ipa_ep_cfg.hdr.hdr_len = 4; } ipa_wan_ep_cfg->ipa_ep_cfg.hdr.hdr_ofst_metadata_valid = 1; @@ -1629,6 +1646,9 @@ static int handle3_egress_format(struct net_device *dev, return -EFAULT; } + if ((e->u.data) & RMNET_IOCTL_EGRESS_FORMAT_IP_ROUTE) + rmnet_ipa3_ctx->no_qmap_config = true; + ipa_wan_ep_cfg = &rmnet_ipa3_ctx->apps_to_ipa_ep_cfg; if ((e->u.data) & RMNET_IOCTL_EGRESS_FORMAT_CHECKSUM) { IPAWANDBG("UL chksum set\n"); @@ -1637,7 +1657,10 @@ static int handle3_egress_format(struct net_device *dev, IPA_ENABLE_CS_OFFLOAD_UL; ipa_wan_ep_cfg->ipa_ep_cfg.cfg.cs_metadata_hdr_offset = 1; } else { - ipa_wan_ep_cfg->ipa_ep_cfg.hdr.hdr_len = 4; + if (rmnet_ipa3_ctx->no_qmap_config) + ipa_wan_ep_cfg->ipa_ep_cfg.hdr.hdr_len = 0; + else + ipa_wan_ep_cfg->ipa_ep_cfg.hdr.hdr_len = 4; } if ((e->u.data) & RMNET_IOCTL_EGRESS_FORMAT_AGGREGATION) { diff --git a/include/linux/ipa.h b/include/linux/ipa.h index afc380d35e07..2903ac2de57e 100644 --- a/include/linux/ipa.h +++ b/include/linux/ipa.h @@ -684,6 +684,7 @@ struct ipa_ext_intf { * by IPA driver * @keep_ipa_awake: when true, IPA will not be clock gated * @napi_enabled: when true, IPA call client callback to start polling + * @bypass_agg: when true, IPA bypasses the aggregation */ struct ipa_sys_connect_params { struct ipa_ep_cfg ipa_ep_cfg; @@ -696,6 +697,7 @@ struct ipa_sys_connect_params { struct napi_struct *napi_obj; bool napi_enabled; bool recycle_enabled; + bool bypass_agg; }; /** From 9ab77143a859e5456d339bfb663ddd4a4e25a06f Mon Sep 17 00:00:00 2001 From: duckyduckG Date: Sun, 5 Oct 2025 17:47:40 +0500 Subject: [PATCH 203/356] ARM64: dts: sdm845: add mailbox client in qmp --- arch/arm64/boot/dts/qcom/sdm845.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index 0b7d8d5a5453..d393417f54ac 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -2150,6 +2150,8 @@ reg = <0xc300000 0x100000>, <0x1799000c 0x4>; reg-names = "msgram", "irq-reg-base"; + mboxes = <&apss_shared 0>; + mbox-names = "aop_qmp"; qcom,irq-mask = <0x1>; interrupts = ; qcom,early-boot; From 52102b58219d97b45464bfe0a4fd54bc42e5c23d Mon Sep 17 00:00:00 2001 From: duckyduckG Date: Thu, 16 Oct 2025 22:48:55 +0500 Subject: [PATCH 204/356] dts: qcom: sdm845: update kryo3xx-erp compatible name it changed to arm64-kryo-cpu-erp on current driver. --- arch/arm64/boot/dts/qcom/sdm845.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index d393417f54ac..60b33105bb3e 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -2086,7 +2086,7 @@ }; kryo3xx-erp { - compatible = "arm,arm64-kryo3xx-cpu-erp"; + compatible = "arm,arm64-kryo-cpu-erp"; interrupts = , , , From 5e05ae2cbf6f54ebc135a34ad820610d77015f6a Mon Sep 17 00:00:00 2001 From: David Dai Date: Fri, 2 May 2025 00:51:10 +0500 Subject: [PATCH 205/356] clk: qcom: cpu-osm-sdm845: move set policy->cpu flag to end of init In order to circumvent a race condition where one CPU may access the frequency table of the policy of another CPU while it's hotplugging, move setting of the policy->cpu flag to the end of the init osm operator after it initializes its frequency table. Change-Id: I4b02caa4995387c16a6db8b8eb9de7271f23c2f6 Signed-off-by: David Dai Signed-off-by: duckyduckg --- drivers/clk/qcom/clk-cpu-osm-sdm845.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/clk/qcom/clk-cpu-osm-sdm845.c b/drivers/clk/qcom/clk-cpu-osm-sdm845.c index b1afa58cf851..f322c241c158 100644 --- a/drivers/clk/qcom/clk-cpu-osm-sdm845.c +++ b/drivers/clk/qcom/clk-cpu-osm-sdm845.c @@ -89,6 +89,7 @@ struct clk_osm { u32 prev_cycle_counter; u32 max_core_count; u32 mx_turbo_freq; + cpumask_t related_cpus; }; static bool is_sdm845v1; @@ -673,7 +674,7 @@ static struct clk_osm *osm_configure_policy(struct cpufreq_policy *policy) if (parent != c_parent) continue; - cpumask_set_cpu(cpu, policy->cpus); + cpumask_set_cpu(cpu, &c->related_cpus); if (n->core_num == 0) first = n; } @@ -798,6 +799,7 @@ static int osm_cpufreq_cpu_init(struct cpufreq_policy *policy) policy->freq_table = table; policy->driver_data = c; + cpumask_copy(policy->cpus, &c->related_cpus); return 0; } From c3428b7aa9c31eea5656bd7080c1ad3b1de36305 Mon Sep 17 00:00:00 2001 From: duckyduckG Date: Tue, 17 Jun 2025 23:20:28 +0500 Subject: [PATCH 206/356] clk: qcom: cpu-osm-sdm845: Set dvfs_possible_from_any_cpu cpufreq driver flag remote cpufreq updates are supported on sdm845 so, set dvfs_possible_from_any_cpu cpufreq driver flag Signed-off-by: duckyduckg --- drivers/clk/qcom/clk-cpu-osm-sdm845.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/qcom/clk-cpu-osm-sdm845.c b/drivers/clk/qcom/clk-cpu-osm-sdm845.c index f322c241c158..0a5506a847de 100644 --- a/drivers/clk/qcom/clk-cpu-osm-sdm845.c +++ b/drivers/clk/qcom/clk-cpu-osm-sdm845.c @@ -799,6 +799,7 @@ static int osm_cpufreq_cpu_init(struct cpufreq_policy *policy) policy->freq_table = table; policy->driver_data = c; + policy->dvfs_possible_from_any_cpu = true; cpumask_copy(policy->cpus, &c->related_cpus); return 0; } From 9f5df5444d120ab4d840c80f921a990f93e590dd Mon Sep 17 00:00:00 2001 From: Pavankumar Kondeti Date: Sun, 3 Aug 2025 21:42:53 +0500 Subject: [PATCH 207/356] clk: qcom: cpu-osm-sdm845: Notify the current frequency to the topology driver The topology driver keeps track of the current capacity of a CPU and make it available via arch_scale_freq_capacity(). The PELT load tracking in the scheduler and energy-aware task placement are the clients of this API. Hence notify the new frequency to the topology driver during frequency transition. Change-Id: Ia0890956f59082496e7d5d7ba8a9c09b343e44ec Signed-off-by: Pavankumar Kondeti --- drivers/clk/qcom/clk-cpu-osm-sdm845.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/clk/qcom/clk-cpu-osm-sdm845.c b/drivers/clk/qcom/clk-cpu-osm-sdm845.c index 0a5506a847de..cf46e15d305e 100644 --- a/drivers/clk/qcom/clk-cpu-osm-sdm845.c +++ b/drivers/clk/qcom/clk-cpu-osm-sdm845.c @@ -708,6 +708,9 @@ osm_cpufreq_target_index(struct cpufreq_policy *policy, unsigned int index) struct clk_osm *c = policy->driver_data; osm_set_index(c, index); + arch_set_freq_scale(policy->related_cpus, + policy->freq_table[index].frequency, + policy->cpuinfo.max_freq); return 0; } From d297ad6c74fcb8c69f7b91d2381fd41956adffd5 Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Mon, 13 Oct 2025 13:58:41 +0500 Subject: [PATCH 208/356] arm64: dts: qcom: sdm845: Add heap region for qseecom Add qseecom_mem region for qseecom device node. Signed-off-by: Pavel Dubrova --- arch/arm64/boot/dts/qcom/sdm845.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index 60b33105bb3e..42b13a160dfe 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -2582,6 +2582,7 @@ compatible = "qcom,qseecom"; reg = <0x86d00000 0x2200000>; reg-names = "secapp-region"; + memory-region = <&qseecom_mem>; qcom,hlos-num-ce-hw-instances = <1>; qcom,hlos-ce-hw-instance = <0>; qcom,qsee-ce-hw-instance = <0>; From 4be2faf041920322a82bbb710045a51c3a4a2e46 Mon Sep 17 00:00:00 2001 From: duckyduckG Date: Sat, 4 Oct 2025 00:53:23 +0500 Subject: [PATCH 209/356] clk: qcom: use fixed_freq_src for clk_determine RCG_UPDATE_BEFORE_PLL is not compatible with legacy platforms such as sdm845 and sm8150. Introduced in: d2725470b652 clk: qcom: clk-rcg2: Support update of RCG src/prediv --- drivers/clk/qcom/clk-rcg2.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c index dd77d6cc2590..4bed505c54b8 100644 --- a/drivers/clk/qcom/clk-rcg2.c +++ b/drivers/clk/qcom/clk-rcg2.c @@ -311,6 +311,7 @@ clk_rcg2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) return rrate; } +#if !defined(CONFIG_ARCH_SDM845) static int _determine_parent_and_update_div(struct clk_hw *hw, const struct freq_tbl *f, struct clk_hw *parent) { @@ -380,6 +381,7 @@ static int _determine_parent_and_update_div(struct clk_hw *hw, return ret; } +#endif static int _freq_tbl_determine_rate(struct clk_hw *hw, const struct freq_tbl *f, struct clk_rate_request *req, @@ -389,6 +391,9 @@ static int _freq_tbl_determine_rate(struct clk_hw *hw, const struct freq_tbl *f, struct clk_hw *p; struct clk_rcg2 *rcg = to_clk_rcg2(hw); int index, ret = 0; +#if defined(CONFIG_ARCH_SDM845) + struct clk_rate_request parent_req = { }; +#endif switch (policy) { case FLOOR: @@ -410,11 +415,15 @@ static int _freq_tbl_determine_rate(struct clk_hw *hw, const struct freq_tbl *f, clk_flags = clk_hw_get_flags(hw); p = clk_hw_get_parent_by_index(hw, index); +#if !defined(CONFIG_ARCH_SDM845) if (!p) return -EINVAL; +#endif if (clk_flags & CLK_SET_RATE_PARENT) { +#if !defined(CONFIG_ARCH_SDM845) rate = f->freq; +#endif if (f->pre_div) { if (!rate) rate = req->rate; @@ -435,6 +444,7 @@ static int _freq_tbl_determine_rate(struct clk_hw *hw, const struct freq_tbl *f, req->best_parent_rate = rate; req->rate = f->freq; +#if !defined(CONFIG_ARCH_SDM845) if ((rcg->flags & RCG_UPDATE_BEFORE_PLL) && (clk_flags & CLK_SET_RATE_PARENT)) { @@ -445,6 +455,22 @@ static int _freq_tbl_determine_rate(struct clk_hw *hw, const struct freq_tbl *f, if (ret) pr_err("Failed to update the div value\n"); } +#else + if (f->src_freq != FIXED_FREQ_SRC) { + rate = parent_req.rate = f->src_freq; + parent_req.best_parent_hw = p; + ret = __clk_determine_rate(p, &parent_req); + if (ret) + return ret; + + ret = clk_set_rate(p->clk, parent_req.rate); + if (ret) { + pr_err("Failed set rate(%lu) on parent for non-fixed source\n", + parent_req.rate); + return ret; + } + } +#endif return ret; } From 112c273b9ad35459035437bde015ac6f8f9dd309 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Tue, 3 Mar 2026 00:36:55 +0000 Subject: [PATCH 210/356] msm: vidc: remove unsupported operating rate for sdm845 * breaks encoding is some apps like mcpro24fps --- drivers/media/platform/msm/vidc/msm_venc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c index a9e37f20b8b5..e02fbd765f96 100644 --- a/drivers/media/platform/msm/vidc/msm_venc.c +++ b/drivers/media/platform/msm/vidc/msm_venc.c @@ -1338,7 +1338,9 @@ int msm_venc_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) int rc = 0; struct hal_request_iframe request_iframe; struct hal_bitrate bitrate; +#ifndef CONFIG_ARCH_SDM845 struct hal_operating_rate operating_rate; +#endif struct hal_profile_level profile_level; enum hal_h264_entropy h264_entropy; struct hal_intra_period intra_period; @@ -2093,10 +2095,12 @@ int msm_venc_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) ctrl->val >> 16); inst->clk_data.operating_rate = ctrl->val; inst->clk_data.turbo_mode = false; +#ifndef CONFIG_ARCH_SDM845 property_id = HAL_CONFIG_OPERATING_RATE; operating_rate.operating_rate = inst->clk_data.operating_rate; pdata = &operating_rate; +#endif } break; case V4L2_CID_MPEG_VIDC_VIDEO_VENC_BITRATE_TYPE: From 5ea3ef8f9141b150a4adf6548cce05de3200c9c3 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Wed, 26 Nov 2025 14:21:48 +0000 Subject: [PATCH 211/356] techpack: sde: Set rotator OT limit for sdm845 Change-Id: I3984393c1a3c041ae1d503503b04ac6bf95bc034 --- techpack/display/rotator/sde_rotator_base.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/techpack/display/rotator/sde_rotator_base.c b/techpack/display/rotator/sde_rotator_base.c index 3cf850753aca..fd893b4103ff 100644 --- a/techpack/display/rotator/sde_rotator_base.c +++ b/techpack/display/rotator/sde_rotator_base.c @@ -255,7 +255,8 @@ u32 sde_mdp_get_ot_limit(u32 width, u32 height, u32 pixfmt, u32 fps, u32 is_rd) ot_lim = 16; } } else if (IS_SDE_MAJOR_SAME(mdata->mdss_version, - SDE_MDP_HW_REV_600) || is_yuv) { + SDE_MDP_HW_REV_600) || IS_SDE_MAJOR_SAME(mdata->mdss_version, + SDE_MDP_HW_REV_400) || is_yuv) { if (res <= (RES_1080p * 30)) ot_lim = 2; else if (res <= (RES_1080p * 60)) From 54a57badf427b50fbd9839deaacf1034cf100c55 Mon Sep 17 00:00:00 2001 From: MrArtemSid Date: Mon, 13 Oct 2025 13:52:33 +0500 Subject: [PATCH 212/356] arm64: dts: qcom-sdm845: sdm845: Add CDSP L3 governor --- arch/arm64/boot/dts/qcom/sdm845.dtsi | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index 42b13a160dfe..f21640e9ceed 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -2389,6 +2389,11 @@ 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 = <100>; From 5809b2266341341d615076021d9f0284da66152d Mon Sep 17 00:00:00 2001 From: Will McVicker Date: Mon, 13 Oct 2025 14:10:53 +0500 Subject: [PATCH 213/356] ARM: dts: qcom: sdm845: disable coresight for sdm845 Coresight is used for debugging purposes. When the debugging configs are disabled, having these included causes power regressions due to clks being left on. So lets disable all the coresight DT entries by default. Change-Id: Ie525c42a462eeb12092bdba2918674df72a33255 Signed-off-by: Will McVicker Bug: 156429236 Test: compile, verify list of probed devices Original-Change-Id: I84f9c874f2f5e8720ced23c7b4268d1b536b96a7 --- arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi | 32 ------------------------ arch/arm64/boot/dts/qcom/sdm845.dtsi | 9 ++++++- 2 files changed, 8 insertions(+), 33 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi b/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi index 249e60f2ccc0..8bb45ce5b084 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-gpu.dtsi @@ -123,38 +123,6 @@ /* GPU related llc slices */ cache-slice-names = "gpu", "gpuhtw"; - qcom,gpu-coresights { - #address-cells = <1>; - #size-cells = <0>; - compatible = "qcom,gpu-coresight"; - - status = "disabled"; - - qcom,gpu-coresight@0 { - reg = <0>; - coresight-name = "coresight-gfx"; - coresight-atid = <50>; - port { - gfx_out_funnel_in2: endpoint { - remote-endpoint = - <&funnel_in2_in_gfx>; - }; - }; - }; - - qcom,gpu-coresight@1 { - reg = <1>; - coresight-name = "coresight-gfx-cx"; - coresight-atid = <51>; - port { - gfx_cx_out_funnel_in2: endpoint { - remote-endpoint = - <&funnel_in2_in_gfx_cx>; - }; - }; - }; - }; - qcom,l3-pwrlevels { #address-cells = <1>; #size-cells = <0>; diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index f21640e9ceed..42d8494ff0ff 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -656,6 +656,7 @@ clock-names = "core_clk"; qcom,coresight-jtagmm-cpu = <&CPU0>; + status = "disabled"; }; jtag_mm1: jtagmm@7140000 { @@ -667,6 +668,7 @@ clock-names = "core_clk"; qcom,coresight-jtagmm-cpu = <&CPU1>; + status = "disabled"; }; jtag_mm2: jtagmm@7240000 { @@ -678,6 +680,7 @@ clock-names = "core_clk"; qcom,coresight-jtagmm-cpu = <&CPU2>; + status = "disabled"; }; jtag_mm3: jtagmm@7340000 { @@ -689,6 +692,7 @@ clock-names = "core_clk"; qcom,coresight-jtagmm-cpu = <&CPU3>; + status = "disabled"; }; jtag_mm4: jtagmm@7440000 { @@ -700,6 +704,7 @@ clock-names = "core_clk"; qcom,coresight-jtagmm-cpu = <&CPU4>; + status = "disabled"; }; jtag_mm5: jtagmm@7540000 { @@ -711,6 +716,7 @@ clock-names = "core_clk"; qcom,coresight-jtagmm-cpu = <&CPU5>; + status = "disabled"; }; jtag_mm6: jtagmm@7640000 { @@ -722,6 +728,7 @@ clock-names = "core_clk"; qcom,coresight-jtagmm-cpu = <&CPU6>; + status = "disabled"; }; jtag_mm7: jtagmm@7740000 { @@ -733,6 +740,7 @@ clock-names = "core_clk"; qcom,coresight-jtagmm-cpu = <&CPU7>; + status = "disabled"; }; intc: interrupt-controller@17a00000 { @@ -4269,7 +4277,6 @@ #include "pm8998.dtsi" #include "pm8005.dtsi" #include "sdm845-regulator.dtsi" -#include "sdm845-coresight.dtsi" #include "msm-arm-smmu-sdm845.dtsi" #include "sdm845-ion.dtsi" #include "sdm845-smp2p.dtsi" From bc2fa78be1e7b2c86623d942d64ff5983caeae58 Mon Sep 17 00:00:00 2001 From: Prasad Sodagudi Date: Mon, 13 Oct 2025 14:23:53 +0500 Subject: [PATCH 214/356] dts: qcom: sdm845: Add rcu_nocbs kernel parameter to chosen node Use per CPU NOCB threads to process RCU callbacks, rather than processing the callbacks in softirq context. So add rcu_nocbs kernel parameter to chosen node, so that 0-7 cores offloads rcu callbacks processing to kthreads instead of softirqs. Change-Id: If1c86979cf80166458563cd3df2e3f6784c64e9b Signed-off-by: Prasad Sodagudi --- arch/arm64/boot/dts/qcom/sdm845.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index 42d8494ff0ff..1bf2666fadf1 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -407,7 +407,7 @@ }; chosen { - bootargs = "rcupdate.rcu_expedited=1"; + bootargs = "rcupdate.rcu_expedited=1 rcu_nocbs=0-7"; }; soc: soc { }; From dce2818ff85ea33f721d659cc2b79e1f06aa70c0 Mon Sep 17 00:00:00 2001 From: Vinayak Menon Date: Mon, 13 Oct 2025 14:33:01 +0500 Subject: [PATCH 215/356] ARM64: dts: msm: disable memcg kernel and socket accounting on sdm845 Disable memcg kernel and socket accounting on sdm845 since memory cgroups is used in this target as a means of user space task grouping based on oom_score_adj, and controlling the userspace memory consumed by tasks. Kernel and socket memory accounting is not considered. Since memcg is created per process on this target enabling kernel accounting results in the creation of numerous kmem caches resulting in significant overhead. Change-Id: I2caad9ce6cca5846b6183a0f0753977db54a660d Signed-off-by: Vinayak Menon --- arch/arm64/boot/dts/qcom/sdm845.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index 1bf2666fadf1..c768c1d0d178 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -407,7 +407,7 @@ }; chosen { - bootargs = "rcupdate.rcu_expedited=1 rcu_nocbs=0-7"; + bootargs = "rcupdate.rcu_expedited=1 rcu_nocbs=0-7 cgroup.memory=nokmem,nosocket"; }; soc: soc { }; From 446647bd4373faf3dfaa42d7d21cf4044484f43d Mon Sep 17 00:00:00 2001 From: duckyduckG Date: Thu, 4 Dec 2025 10:44:53 +0500 Subject: [PATCH 216/356] dts: qcom: sdm845: Disable kpti and ssbd --- arch/arm64/boot/dts/qcom/sdm845.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index c768c1d0d178..084f7969a49a 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -407,7 +407,7 @@ }; chosen { - bootargs = "rcupdate.rcu_expedited=1 rcu_nocbs=0-7 cgroup.memory=nokmem,nosocket"; + bootargs = "rcupdate.rcu_expedited=1 rcu_nocbs=0-7 cgroup.memory=nokmem,nosocket kpti=0 ssbd=force-off"; }; soc: soc { }; From 1e93cab617e6f84ba5271e210ff0c4bb680f2bc1 Mon Sep 17 00:00:00 2001 From: MrArtemSid Date: Mon, 1 Dec 2025 15:12:17 +0500 Subject: [PATCH 217/356] ARM64: dts: qcom: sdm845: Add cpufreq-hw support ref: - https://github.com/torvalds/linux/commit/c604b82a09ce3244add85064f8538d45f879a980 - https://github.com/Beryllium-4-19-Project/android_kernel_xiaomi_sdm845/blob/beryllium-los21-master/arch/arm64/boot/dts/vendor/bindings/cpufreq/cpufreq-qcom-hw.txt - https://www.mail-archive.com/linux-kernel@vger.kernel.org/msg1692418.html --- arch/arm64/boot/dts/qcom/sdm845.dtsi | 79 +++++++++++++++------------- 1 file changed, 43 insertions(+), 36 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index 084f7969a49a..9109ded3ccac 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -54,6 +54,7 @@ reg = <0x0 0x0>; enable-method = "psci"; capacity-dmips-mhz = <1024>; + qcom,freq-domain = <&cpufreq_hw 0 4>; cache-size = <0x8000>; cpu-release-addr = <0x0 0x90000000>; qcom,lmh-dcvs = <&lmh_dcvs0>; @@ -91,6 +92,7 @@ reg = <0x0 0x100>; enable-method = "psci"; capacity-dmips-mhz = <1024>; + qcom,freq-domain = <&cpufreq_hw 0 4>; cache-size = <0x8000>; cpu-release-addr = <0x0 0x90000000>; qcom,lmh-dcvs = <&lmh_dcvs0>; @@ -122,6 +124,7 @@ reg = <0x0 0x200>; enable-method = "psci"; capacity-dmips-mhz = <1024>; + qcom,freq-domain = <&cpufreq_hw 0 4>; cache-size = <0x8000>; cpu-release-addr = <0x0 0x90000000>; qcom,lmh-dcvs = <&lmh_dcvs0>; @@ -153,6 +156,7 @@ reg = <0x0 0x300>; enable-method = "psci"; capacity-dmips-mhz = <1024>; + qcom,freq-domain = <&cpufreq_hw 0 4>; cache-size = <0x8000>; cpu-release-addr = <0x0 0x90000000>; qcom,lmh-dcvs = <&lmh_dcvs0>; @@ -184,6 +188,7 @@ reg = <0x0 0x400>; enable-method = "psci"; capacity-dmips-mhz = <1740>; + qcom,freq-domain = <&cpufreq_hw 1 4>; cache-size = <0x20000>; cpu-release-addr = <0x0 0x90000000>; qcom,lmh-dcvs = <&lmh_dcvs1>; @@ -215,6 +220,7 @@ reg = <0x0 0x500>; enable-method = "psci"; capacity-dmips-mhz = <1740>; + qcom,freq-domain = <&cpufreq_hw 1 4>; cache-size = <0x20000>; cpu-release-addr = <0x0 0x90000000>; qcom,lmh-dcvs = <&lmh_dcvs1>; @@ -246,6 +252,7 @@ reg = <0x0 0x600>; enable-method = "psci"; capacity-dmips-mhz = <1740>; + qcom,freq-domain = <&cpufreq_hw 1 4>; cache-size = <0x20000>; cpu-release-addr = <0x0 0x90000000>; qcom,lmh-dcvs = <&lmh_dcvs1>; @@ -277,6 +284,7 @@ reg = <0x0 0x700>; enable-method = "psci"; capacity-dmips-mhz = <1740>; + qcom,freq-domain = <&cpufreq_hw 1 4>; cache-size = <0x20000>; cpu-release-addr = <0x0 0x90000000>; qcom,lmh-dcvs = <&lmh_dcvs1>; @@ -925,6 +933,26 @@ }; }; + qcom,devfreq-l3 { + compatible = "qcom,devfreq-fw"; + reg = <0x17d41000 0x4>, <0x17d43110 0x500>, <0x17d43920 0x4>; + reg-names = "en-base", "ftbl-base", "perf-base"; + + qcom,ftbl-row-size = <32>; + + cpu0_l3: qcom,cpu0-cpu-l3-lat { + compatible = "qcom,devfreq-fw-voter"; + }; + + cpu4_l3: qcom,cpu4-cpu-l3-lat { + compatible = "qcom,devfreq-fw-voter"; + }; + + cdsp_l3: qcom,cdsp-cdsp-l3-lat { + compatible = "qcom,devfreq-fw-voter"; + }; + }; + llcc_bw_opp_table: llcc-bw-opp-table { compatible = "operating-points-v2"; BW_OPP_ENTRY( 150, 16); /* 2288 MB/s */ @@ -1122,27 +1150,6 @@ operating-points-v2 = <&keepalive_opp_table>; }; - cpu0_l3: qcom,cpu0-cpu-l3-lat { - compatible = "devfreq-simple-dev"; - clock-names = "devfreq_clk"; - clocks = <&clock_cpucc L3_CLUSTER0_VOTE_CLK>; - governor = "performance"; - }; - - cpu4_l3: qcom,cpu4-cpu-l3-lat { - compatible = "devfreq-simple-dev"; - clock-names = "devfreq_clk"; - clocks = <&clock_cpucc L3_CLUSTER1_VOTE_CLK>; - governor = "performance"; - }; - - cdsp_l3: qcom,cdsp-cdsp-l3-lat { - compatible = "devfreq-simple-dev"; - clock-names = "devfreq_clk"; - clocks = <&clock_cpucc L3_MISC_VOTE_CLK>; - governor = "powersave"; - }; - cpu_pmu: cpu-pmu { compatible = "arm,armv8-pmuv3"; qcom,irq-is-percpu; @@ -1227,20 +1234,9 @@ reg = <0x17970018 0x4>; }; - clock_cpucc: qcom,cpucc@0x17d41000 { - compatible = "qcom,clk-cpu-osm"; - reg = <0x17d41000 0x1400>, - <0x17d43000 0x1400>, - <0x17d45800 0x1400>; - reg-names = "osm_l3_base", "osm_pwrcl_base", "osm_perfcl_base"; - vdd_l3_mx_ao-supply = <&pm8998_s6_level_ao>; - vdd_pwrcl_mx_ao-supply = <&pm8998_s6_level_ao>; - - qcom,mx-turbo-freq = <1478400000 1689600000 3300000001>; - l3-devs = <&cpu0_l3 &cpu4_l3 &cdsp_l3 &msm_gpu>; - - clock-names = "xo_ao"; - clocks = <&clock_rpmh RPMH_CXO_CLK_A>; + clock_cpucc: qcom,cpucc { + compatible = "qcom,dummycc"; + clock-output-names = "cpucc_clocks"; #clock-cells = <1>; }; @@ -1265,6 +1261,17 @@ mbox-names = "qdss_clk"; }; + cpufreq_hw: qcom,cpufreq-hw { + compatible = "qcom,cpufreq-hw"; + reg = <0x17d43000 0x1400>, <0x17d45800 0x1400>; + reg-names = "freq-domain0", "freq-domain1"; + + clocks = <&clock_rpmh RPMH_CXO_CLK>, <&clock_gcc GPLL0>; + clock-names = "xo", "alternate"; + qcom,no-accumulative-counter; + #freq-domain-cells = <2>; + }; + ufsphy_mem: ufsphy_mem@1d87000 { reg = <0x1d87000 0xda8>, <0x1d90000 0x8000>; /* PHY regs */ reg-names = "phy_mem", "ufs_ice"; @@ -4065,7 +4072,7 @@ }; }; -&clock_cpucc { +&cpufreq_hw { lmh_dcvs0: qcom,limits-dcvs@0 { compatible = "qcom,msm-hw-limits"; interrupts = ; From c75eda9836c7889616755819df207e271d11eca7 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Sat, 6 Dec 2025 02:23:15 +0500 Subject: [PATCH 218/356] arm64: dts: sdm845: Add dynamic CPU power coefficients Add dynamic power coefficients for the Silver and Gold CPU cores of the Qualcomm SDM845. Signed-off-by: Matthias Kaehlcke Reviewed-by: Douglas Anderson Reviewed-by: Amit Kucheria Signed-off-by: Bjorn Andersson --- arch/arm64/boot/dts/qcom/sdm845.dtsi | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index 9109ded3ccac..b6e3ce0a9ff2 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -54,6 +54,7 @@ reg = <0x0 0x0>; enable-method = "psci"; capacity-dmips-mhz = <1024>; + dynamic-power-coefficient = <100>; qcom,freq-domain = <&cpufreq_hw 0 4>; cache-size = <0x8000>; cpu-release-addr = <0x0 0x90000000>; @@ -92,6 +93,7 @@ reg = <0x0 0x100>; enable-method = "psci"; capacity-dmips-mhz = <1024>; + dynamic-power-coefficient = <100>; qcom,freq-domain = <&cpufreq_hw 0 4>; cache-size = <0x8000>; cpu-release-addr = <0x0 0x90000000>; @@ -124,6 +126,7 @@ reg = <0x0 0x200>; enable-method = "psci"; capacity-dmips-mhz = <1024>; + dynamic-power-coefficient = <100>; qcom,freq-domain = <&cpufreq_hw 0 4>; cache-size = <0x8000>; cpu-release-addr = <0x0 0x90000000>; @@ -156,6 +159,7 @@ reg = <0x0 0x300>; enable-method = "psci"; capacity-dmips-mhz = <1024>; + dynamic-power-coefficient = <100>; qcom,freq-domain = <&cpufreq_hw 0 4>; cache-size = <0x8000>; cpu-release-addr = <0x0 0x90000000>; @@ -188,6 +192,7 @@ reg = <0x0 0x400>; enable-method = "psci"; capacity-dmips-mhz = <1740>; + dynamic-power-coefficient = <396>; qcom,freq-domain = <&cpufreq_hw 1 4>; cache-size = <0x20000>; cpu-release-addr = <0x0 0x90000000>; @@ -220,6 +225,7 @@ reg = <0x0 0x500>; enable-method = "psci"; capacity-dmips-mhz = <1740>; + dynamic-power-coefficient = <396>; qcom,freq-domain = <&cpufreq_hw 1 4>; cache-size = <0x20000>; cpu-release-addr = <0x0 0x90000000>; @@ -252,6 +258,7 @@ reg = <0x0 0x600>; enable-method = "psci"; capacity-dmips-mhz = <1740>; + dynamic-power-coefficient = <396>; qcom,freq-domain = <&cpufreq_hw 1 4>; cache-size = <0x20000>; cpu-release-addr = <0x0 0x90000000>; @@ -284,6 +291,7 @@ reg = <0x0 0x700>; enable-method = "psci"; capacity-dmips-mhz = <1740>; + dynamic-power-coefficient = <396>; qcom,freq-domain = <&cpufreq_hw 1 4>; cache-size = <0x20000>; cpu-release-addr = <0x0 0x90000000>; From 2fe0a2db83e135bfe1a13a8ac5fac620e6ecb640 Mon Sep 17 00:00:00 2001 From: duckyduckG Date: Mon, 1 Dec 2025 15:26:58 +0500 Subject: [PATCH 219/356] arm64: dts: qcom: sdm845: remove deprecated energy-costs --- arch/arm64/boot/dts/qcom/sdm845-v2.dtsi | 65 ----------------------- arch/arm64/boot/dts/qcom/sdm845.dtsi | 68 ------------------------- 2 files changed, 133 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi index e2223560b2a0..b6710863ef5f 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi @@ -468,71 +468,6 @@ }; }; -&energy_costs { - CPU_COST_0: core-cost0 { - busy-cost-data = < - 300000 12 - 403200 17 - 480000 21 - 576000 27 - 652800 31 - 748800 37 - 825600 42 - 902400 47 - 979200 52 - 1056000 57 - 1132800 62 - 1228800 70 - 1324800 78 - 1420800 89 - 1516800 103 - 1612800 122 - 1689600 141 - 1766400 160 - >; - }; - CPU_COST_1: core-cost1 { - busy-cost-data = < - 300000 189 - 403200 523 - 480000 763 - 576000 1052 - 652800 1273 - 748800 1536 - 825600 1736 - 902400 1926 - 979200 2108 - 1056000 2284 - 1132800 2456 - 1209600 2628 - 1286400 2804 - 1363200 2992 - 1459200 3255 - 1536000 3499 - 1612800 3786 - 1689600 4128 - 1766400 4535 - 1843200 5019 - 1920000 5583 - 1996800 6226 - 2092800 7120 - 2169600 7876 - 2246400 8628 - 2323200 9344 - 2400000 10030 - 2476800 10806 - 2553600 12045 - 2649600 15686 - 2745600 25586 - 2764800 30000 - 2784000 35000 - 2803200 40000 - 2841600 50000 - 2956800 60000 - >; - }; -}; - &gpu_gx_gdsc { domain-addr = <&gpu_gx_domain_addr>; sw-reset = <&gpu_gx_sw_reset>; diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index b6e3ce0a9ff2..cfbe04cf1125 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -61,7 +61,6 @@ qcom,lmh-dcvs = <&lmh_dcvs0>; #cooling-cells = <2>; next-level-cache = <&L2_0>; - sched-energy-costs = <&CPU_COST_0>; L2_0: l2-cache { compatible = "arm,arch-cache"; cache-size = <0x20000>; @@ -100,7 +99,6 @@ qcom,lmh-dcvs = <&lmh_dcvs0>; #cooling-cells = <2>; next-level-cache = <&L2_100>; - sched-energy-costs = <&CPU_COST_0>; L2_100: l2-cache { compatible = "arm,arch-cache"; cache-size = <0x20000>; @@ -133,7 +131,6 @@ qcom,lmh-dcvs = <&lmh_dcvs0>; #cooling-cells = <2>; next-level-cache = <&L2_200>; - sched-energy-costs = <&CPU_COST_0>; L2_200: l2-cache { compatible = "arm,arch-cache"; cache-size = <0x20000>; @@ -166,7 +163,6 @@ qcom,lmh-dcvs = <&lmh_dcvs0>; #cooling-cells = <2>; next-level-cache = <&L2_300>; - sched-energy-costs = <&CPU_COST_0>; L2_300: l2-cache { compatible = "arm,arch-cache"; cache-size = <0x20000>; @@ -199,7 +195,6 @@ qcom,lmh-dcvs = <&lmh_dcvs1>; #cooling-cells = <2>; next-level-cache = <&L2_400>; - sched-energy-costs = <&CPU_COST_1>; L2_400: l2-cache { compatible = "arm,arch-cache"; cache-size = <0x40000>; @@ -232,7 +227,6 @@ qcom,lmh-dcvs = <&lmh_dcvs1>; #cooling-cells = <2>; next-level-cache = <&L2_500>; - sched-energy-costs = <&CPU_COST_1>; L2_500: l2-cache { compatible = "arm,arch-cache"; cache-size = <0x40000>; @@ -265,7 +259,6 @@ qcom,lmh-dcvs = <&lmh_dcvs1>; #cooling-cells = <2>; next-level-cache = <&L2_600>; - sched-energy-costs = <&CPU_COST_1>; L2_600: l2-cache { compatible = "arm,arch-cache"; cache-size = <0x40000>; @@ -298,7 +291,6 @@ qcom,lmh-dcvs = <&lmh_dcvs1>; #cooling-cells = <2>; next-level-cache = <&L2_700>; - sched-energy-costs = <&CPU_COST_1>; L2_700: l2-cache { compatible = "arm,arch-cache"; cache-size = <0x40000>; @@ -357,66 +349,6 @@ }; }; - energy_costs: energy-costs { - compatible = "sched-energy"; - - CPU_COST_0: core-cost0 { - busy-cost-data = < - 300000 31 - 422400 38 - 499200 42 - 576000 46 - 652800 51 - 748800 58 - 825600 64 - 902400 70 - 979200 76 - 1056000 83 - 1132800 90 - 1209600 97 - 1286400 105 - 1363200 114 - 1440000 124 - 1516800 136 - 1593600 152 - 1651200 167 /* speedbin 0,1 */ - 1670400 173 /* speedbin 2 */ - 1708800 186 /* speedbin 0,1 */ - 1747200 201 /* speedbin 2 */ - >; - }; - CPU_COST_1: core-cost1 { - busy-cost-data = < - 300000 258 - 422400 260 - 499200 261 - 576000 263 - 652800 267 - 729600 272 - 806400 280 - 883200 291 - 960000 305 - 1036800 324 - 1113600 348 - 1190400 378 - 1267200 415 - 1344000 460 - 1420800 513 - 1497600 576 - 1574400 649 - 1651200 732 - 1728000 824 - 1804800 923 - 1881600 1027 - 1958400 1131 - 2035000 1228 /* speedbin 1,2 */ - 2092000 1290 /* speedbin 1 */ - 2112000 1308 /* speedbin 2 */ - 2208000 1363 /* speedbin 2 */ - >; - }; - }; /* energy-costs */ - psci { compatible = "arm,psci-1.0"; method = "smc"; From bbfc7960219f080de74c30d5568690649538d7d2 Mon Sep 17 00:00:00 2001 From: duckyduckG Date: Sat, 7 Feb 2026 23:43:47 +0000 Subject: [PATCH 220/356] arm64: configs: sdm845: Switch to cpufreq-hw --- arch/arm64/configs/vendor/sdm845-perf_defconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/configs/vendor/sdm845-perf_defconfig b/arch/arm64/configs/vendor/sdm845-perf_defconfig index cc5aaa8c5aa2..51b3327b36bc 100644 --- a/arch/arm64/configs/vendor/sdm845-perf_defconfig +++ b/arch/arm64/configs/vendor/sdm845-perf_defconfig @@ -84,6 +84,7 @@ CONFIG_CPU_FREQ_GOV_POWERSAVE=y CONFIG_CPU_FREQ_GOV_USERSPACE=y CONFIG_CPU_BOOST=y CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y +CONFIG_ARM_QCOM_CPUFREQ_HW=y CONFIG_CRYPTO_SHA1_ARM64_CE=y CONFIG_CRYPTO_SHA2_ARM64_CE=y CONFIG_CRYPTO_GHASH_ARM64_CE=y @@ -527,7 +528,6 @@ CONFIG_MSM_VIDEOCC_SDM845=y CONFIG_MSM_DISPCC_SDM845=y CONFIG_MSM_CAMCC_SDM845=y CONFIG_MSM_GPUCC_SDM845=y -CONFIG_CLOCK_CPU_OSM_SDM845=y CONFIG_HWSPINLOCK=y CONFIG_HWSPINLOCK_QCOM=y CONFIG_MAILBOX=y @@ -601,6 +601,7 @@ CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y CONFIG_DEVFREQ_GOV_QCOM_CACHE_HWMON=y CONFIG_DEVFREQ_GOV_MEMLAT=y CONFIG_DEVFREQ_GOV_CDSPL3=y +CONFIG_ARM_QCOM_DEVFREQ_FW=y CONFIG_DEVFREQ_SIMPLE_DEV=y CONFIG_QCOM_DEVFREQ_DEVBW=y CONFIG_EXTCON_USB_GPIO=y @@ -627,7 +628,6 @@ CONFIG_ESOC_MDM_4x=y CONFIG_ESOC_MDM_DRV=y CONFIG_SENSORS_SSC=y CONFIG_QCOM_KGSL=y -CONFIG_LEGACY_ENERGY_MODEL_DT=y CONFIG_EXT4_FS=y CONFIG_EXT4_FS_POSIX_ACL=y CONFIG_EXT4_FS_SECURITY=y From 05f25343fc39ac8aa62f8354abae154c609406a7 Mon Sep 17 00:00:00 2001 From: LuK1337 Date: Wed, 6 Nov 2019 18:14:55 +0100 Subject: [PATCH 221/356] arm64: dts: Import OnePlus 6/6T DTS EdwinMoq: Adapt for 4.19 Change-Id: I5710f64e9b107d68892cdc87031af73e8f35542e --- arch/arm64/boot/dts/qcom/Makefile | 68 +- .../boot/dts/qcom/OP-batterydata-3300mah.dtsi | 80 + .../boot/dts/qcom/OP-batterydata-3700mah.dtsi | 80 + .../boot/dts/qcom/dsi-panel-samsung_dsc.dtsi | 447 +++ .../qcom/dsi-panel-samsung_s6e3fc1_cmd.dtsi | 215 ++ .../qcom/dsi-panel-samsung_s6e3fc2x01.dtsi | 437 +++ .../qcom/dsi-panel-samsung_sefeg01_s_cmd.dtsi | 390 +++ .../qcom/dsi-panel-samsung_sofef00_m_cmd.dtsi | 336 +++ .../dsi-panel-samsung_sofef00_m_video.dtsi | 76 + .../boot/dts/qcom/enchilada-dvt-backup.dtsi | 23 + .../boot/dts/qcom/enchilada-dvt-usb30.dtsi | 62 + .../enchilada-dvt-v2.1-backup-overlay.dts | 33 + .../dts/qcom/enchilada-dvt-v2.1-overlay.dts | 33 + .../qcom/enchilada-dvt-v2.1-usb30-overlay.dts | 33 + arch/arm64/boot/dts/qcom/enchilada-dvt.dtsi | 23 + arch/arm64/boot/dts/qcom/enchilada-evt2.dtsi | 144 + .../dts/qcom/enchilada-mp-v2.1-overlay.dts | 33 + arch/arm64/boot/dts/qcom/enchilada-mp.dtsi | 23 + .../boot/dts/qcom/enchilada-pvt-backup.dtsi | 55 + .../enchilada-pvt-v2.1-backup-overlay.dts | 33 + .../dts/qcom/enchilada-pvt-v2.1-overlay.dts | 33 + arch/arm64/boot/dts/qcom/enchilada-pvt.dtsi | 24 + arch/arm64/boot/dts/qcom/enchilada-t0.dtsi | 122 + arch/arm64/boot/dts/qcom/enchilada.dtsi | 2111 +++++++++++++++ arch/arm64/boot/dts/qcom/fajita-dvt-bu.dtsi | 20 + .../dts/qcom/fajita-dvt-v2.1-bu-overlay.dts | 33 + .../boot/dts/qcom/fajita-dvt-v2.1-overlay.dts | 33 + arch/arm64/boot/dts/qcom/fajita-dvt.dtsi | 20 + arch/arm64/boot/dts/qcom/fajita-mp-spec.dtsi | 36 + .../dts/qcom/fajita-mp-v2.1-spec-overlay.dts | 33 + arch/arm64/boot/dts/qcom/fajita-pvt-bu.dtsi | 20 + arch/arm64/boot/dts/qcom/fajita-pvt-spec.dtsi | 32 + arch/arm64/boot/dts/qcom/fajita-pvt-v1.dtsi | 20 + .../dts/qcom/fajita-pvt-v2.1-bu-overlay.dts | 33 + .../boot/dts/qcom/fajita-pvt-v2.1-overlay.dts | 33 + .../dts/qcom/fajita-pvt-v2.1-spec-overlay.dts | 33 + .../dts/qcom/fajita-pvt-v2.1-v1-overlay.dts | 33 + arch/arm64/boot/dts/qcom/fajita-pvt.dtsi | 20 + arch/arm64/boot/dts/qcom/fajita.dtsi | 2396 +++++++++++++++++ .../boot/dts/qcom/sdm845-670-usb-common.dtsi | 4 +- .../boot/dts/qcom/sdm845-audio-overlay.dtsi | 28 +- arch/arm64/boot/dts/qcom/sdm845-audio.dtsi | 15 +- .../dts/qcom/sdm845-camera-sensor-mtp.dtsi | 453 ---- .../boot/dts/qcom/sdm845-mtp-overlay.dts | 4 +- arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi | 10 +- arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi | 15 +- arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi | 3 +- arch/arm64/boot/dts/qcom/sdm845-sde.dtsi | 4 +- .../boot/dts/qcom/sdm845-v2-mtp-overlay.dts | 6 +- .../boot/dts/qcom/sdm845-v2.1-mtp-overlay.dts | 4 +- arch/arm64/boot/dts/qcom/sdm845-v2.dts | 2 +- arch/arm64/boot/dts/qcom/sdm845-v2.dtsi | 1 + arch/arm64/boot/dts/qcom/sdm845.dts | 3 +- arch/arm64/boot/dts/qcom/sdm845.dtsi | 9 +- .../boot/dts/qcom/sdm845_enchilada_soc.dtsi | 47 + 55 files changed, 7817 insertions(+), 500 deletions(-) create mode 100644 arch/arm64/boot/dts/qcom/OP-batterydata-3300mah.dtsi create mode 100644 arch/arm64/boot/dts/qcom/OP-batterydata-3700mah.dtsi create mode 100644 arch/arm64/boot/dts/qcom/dsi-panel-samsung_dsc.dtsi create mode 100644 arch/arm64/boot/dts/qcom/dsi-panel-samsung_s6e3fc1_cmd.dtsi create mode 100644 arch/arm64/boot/dts/qcom/dsi-panel-samsung_s6e3fc2x01.dtsi create mode 100644 arch/arm64/boot/dts/qcom/dsi-panel-samsung_sefeg01_s_cmd.dtsi create mode 100644 arch/arm64/boot/dts/qcom/dsi-panel-samsung_sofef00_m_cmd.dtsi create mode 100644 arch/arm64/boot/dts/qcom/dsi-panel-samsung_sofef00_m_video.dtsi create mode 100644 arch/arm64/boot/dts/qcom/enchilada-dvt-backup.dtsi create mode 100644 arch/arm64/boot/dts/qcom/enchilada-dvt-usb30.dtsi create mode 100644 arch/arm64/boot/dts/qcom/enchilada-dvt-v2.1-backup-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/enchilada-dvt-v2.1-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/enchilada-dvt-v2.1-usb30-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/enchilada-dvt.dtsi create mode 100644 arch/arm64/boot/dts/qcom/enchilada-evt2.dtsi create mode 100644 arch/arm64/boot/dts/qcom/enchilada-mp-v2.1-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/enchilada-mp.dtsi create mode 100644 arch/arm64/boot/dts/qcom/enchilada-pvt-backup.dtsi create mode 100644 arch/arm64/boot/dts/qcom/enchilada-pvt-v2.1-backup-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/enchilada-pvt-v2.1-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/enchilada-pvt.dtsi create mode 100644 arch/arm64/boot/dts/qcom/enchilada-t0.dtsi create mode 100644 arch/arm64/boot/dts/qcom/enchilada.dtsi create mode 100644 arch/arm64/boot/dts/qcom/fajita-dvt-bu.dtsi create mode 100644 arch/arm64/boot/dts/qcom/fajita-dvt-v2.1-bu-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/fajita-dvt-v2.1-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/fajita-dvt.dtsi create mode 100644 arch/arm64/boot/dts/qcom/fajita-mp-spec.dtsi create mode 100644 arch/arm64/boot/dts/qcom/fajita-mp-v2.1-spec-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/fajita-pvt-bu.dtsi create mode 100644 arch/arm64/boot/dts/qcom/fajita-pvt-spec.dtsi create mode 100644 arch/arm64/boot/dts/qcom/fajita-pvt-v1.dtsi create mode 100644 arch/arm64/boot/dts/qcom/fajita-pvt-v2.1-bu-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/fajita-pvt-v2.1-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/fajita-pvt-v2.1-spec-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/fajita-pvt-v2.1-v1-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/fajita-pvt.dtsi create mode 100644 arch/arm64/boot/dts/qcom/fajita.dtsi create mode 100644 arch/arm64/boot/dts/qcom/sdm845_enchilada_soc.dtsi diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index 48c84598f20c..f88a9dc6ccc4 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -1,12 +1,66 @@ # SPDX-License-Identifier: GPL-2.0 -dtb-$(CONFIG_ARCH_QCOM) += apq8016-sbc.dtb -dtb-$(CONFIG_ARCH_QCOM) += apq8096-db820c.dtb -dtb-$(CONFIG_ARCH_QCOM) += ipq8074-hk01.dtb -dtb-$(CONFIG_ARCH_QCOM) += msm8916-mtp.dtb -dtb-$(CONFIG_ARCH_QCOM) += msm8992-bullhead-rev-101.dtb -dtb-$(CONFIG_ARCH_QCOM) += msm8994-angler-rev-101.dtb -dtb-$(CONFIG_ARCH_QCOM) += msm8996-mtp.dtb +# dtb-$(CONFIG_ARCH_QCOM) += apq8016-sbc.dtb +# dtb-$(CONFIG_ARCH_QCOM) += apq8096-db820c.dtb +# dtb-$(CONFIG_ARCH_QCOM) += ipq8074-hk01.dtb +# dtb-$(CONFIG_ARCH_QCOM) += msm8916-mtp.dtb +# dtb-$(CONFIG_ARCH_QCOM) += msm8992-bullhead-rev-101.dtb +# dtb-$(CONFIG_ARCH_QCOM) += msm8994-angler-rev-101.dtb +# dtb-$(CONFIG_ARCH_QCOM) += msm8996-mtp.dtb + +ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) +dtbo-$(CONFIG_ARCH_QCOM) += \ + sdm845-mtp-overlay.dtbo \ + sdm845-v2-mtp-overlay.dtbo \ + sdm845-v2.1-mtp-overlay.dtbo \ + enchilada-evb-v2.1-overlay.dtbo \ + enchilada-t0-v2.1-overlay.dtbo \ + enchilada-evt1-v2.1-overlay.dtbo \ + enchilada-evt2-v2.1-overlay.dtbo \ + enchilada-evt2-cxo-v2.1-overlay.dtbo \ + enchilada-dvt-v2.1-overlay.dtbo \ + enchilada-dvt-v2.1-backup-overlay.dtbo \ + enchilada-dvt-v2.1-usb30-overlay.dtbo \ + enchilada-pvt-v2.1-overlay.dtbo \ + enchilada-pvt-v2.1-backup-overlay.dtbo \ + enchilada-mp-v2.1-overlay.dtbo \ + fajita-evb-v2.1-overlay.dtbo \ + fajita-t0-v2.1-overlay.dtbo \ + fajita-evt1-v2.1-overlay.dtbo \ + fajita-dvt-v2.1-overlay.dtbo \ + fajita-dvt-v2.1-bu-overlay.dtbo \ + fajita-pvt-v2.1-overlay.dtbo \ + fajita-pvt-v2.1-bu-overlay.dtbo \ + fajita-pvt-v2.1-v1-overlay.dtbo \ + fajita-pvt-v2.1-spec-overlay.dtbo \ + fajita-mp-v2.1-spec-overlay.dtbo + +sdm845-mtp-overlay.dtbo-base := sdm845.dtb +sdm845-v2-mtp-overlay.dtbo-base := sdm845-v2.dtb +sdm845-v2.1-mtp-overlay.dtbo-base := sdm845-v2.1.dtb +enchilada-evb-v2.1-overlay.dtbo-base := sdm845-v2.1.dtb +enchilada-t0-v2.1-overlay.dtbo-base := sdm845-v2.1.dtb +enchilada-evt1-v2.1-overlay.dtbo-base := sdm845-v2.1.dtb +enchilada-evt2-v2.1-overlay.dtbo-base := sdm845-v2.1.dtb +enchilada-evt2-cxo-v2.1-overlay.dtbo-base := sdm845-v2.1.dtb +enchilada-dvt-v2.1-overlay.dtbo-base := sdm845-v2.1.dtb +enchilada-dvt-v2.1-backup-overlay.dtbo-base := sdm845-v2.1.dtb +enchilada-dvt-v2.1-usb30-overlay.dtbo-base := sdm845-v2.1.dtb +enchilada-pvt-v2.1-overlay.dtbo-base := sdm845-v2.1.dtb +enchilada-pvt-v2.1-backup-overlay.dtbo-base := sdm845-v2.1.dtb +enchilada-mp-v2.1-overlay.dtbo-base := sdm845-v2.1.dtb +fajita-evb-v2.1-overlay.dtbo-base := sdm845-v2.1.dtb +fajita-t0-v2.1-overlay.dtbo-base := sdm845-v2.1.dtb +fajita-evt1-v2.1-overlay.dtbo-base := sdm845-v2.1.dtb +fajita-dvt-v2.1-overlay.dtbo-base := sdm845-v2.1.dtb +fajita-dvt-v2.1-bu-overlay.dtbo-base := sdm845-v2.1.dtb +fajita-pvt-v2.1-overlay.dtbo-base := sdm845-v2.1.dtb +fajita-pvt-v2.1-bu-overlay.dtbo-base := sdm845-v2.1.dtb +fajita-pvt-v2.1-v1-overlay.dtbo-base := sdm845-v2.1.dtb +fajita-pvt-v2.1-spec-overlay.dtbo-base := sdm845-v2.1.dtb +fajita-mp-v2.1-spec-overlay.dtbo-base := sdm845-v2.1.dtb +else dtb-$(CONFIG_ARCH_QCOM) += sdm845-mtp.dtb +endif always := $(dtb-y) subdir-y := $(dts-dirs) diff --git a/arch/arm64/boot/dts/qcom/OP-batterydata-3300mah.dtsi b/arch/arm64/boot/dts/qcom/OP-batterydata-3300mah.dtsi new file mode 100644 index 000000000000..0ecee72799b3 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/OP-batterydata-3300mah.dtsi @@ -0,0 +1,80 @@ +/* Copyright (c) 2016, 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_3300mah { + qcom,max-voltage-uv = <4370000>; + qcom,fg-cc-cv-threshold-mv = <4360>; + qcom,fastchg-current-ma = <3000>; + qcom,batt-id-kohm = <200>; + qcom,battery-beta = <3450>; + qcom,battery-type = "OP_3300mah"; + qcom,checksum = <0xE06B>; + qcom,gui-version = "PMI8998GUI - 0.0.0.82"; + qcom,fg-profile-data = [ + A4 1F 6E 05 + 9C 0A 16 06 + 32 1D 24 E5 + 61 0B 1B 15 + AD 17 8C 22 + EB 3C 87 4A + 5B 00 00 00 + 12 00 00 00 + 00 00 62 C2 + 0C CD D8 C2 + 19 00 0C 00 + 7E 00 C7 EC + E3 05 5D FA + 97 F5 12 12 + C2 05 90 3B + 22 09 40 40 + 07 00 05 00 + 7D 1F DE 05 + 3F 0A 73 06 + 72 1D E2 F5 + 6F 12 BF 1D + 88 18 FB 22 + 8D 45 C6 52 + 54 00 00 00 + 0F 00 00 00 + 00 00 BD CD + 55 C2 5D C5 + 14 00 00 00 + 7E 00 C7 EC + 60 06 BB 00 + B3 FC 61 03 + 6A 06 78 1B + B3 33 08 33 + 07 10 00 00 + 3E 0B 99 45 + 14 00 19 00 + AE 01 0A FA + FF 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + ]; +}; diff --git a/arch/arm64/boot/dts/qcom/OP-batterydata-3700mah.dtsi b/arch/arm64/boot/dts/qcom/OP-batterydata-3700mah.dtsi new file mode 100644 index 000000000000..aef1d3f4f8d3 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/OP-batterydata-3700mah.dtsi @@ -0,0 +1,80 @@ +/* Copyright (c) 2016, 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_3700mAh { + qcom,max-voltage-uv = <4370000>; + qcom,fg-cc-cv-threshold-mv = <4360>; + qcom,fastchg-current-ma = <3000>; + qcom,batt-id-kohm = <200>; + qcom,battery-beta = <3450>; + qcom,battery-type = "OP_3700mAh"; + qcom,checksum = <0xE06B>; + qcom,gui-version = "PMI8998GUI - 0.0.0.82"; + qcom,fg-profile-data = [ + A4 1F 6E 05 + 9C 0A 16 06 + 32 1D 24 E5 + 61 0B 1B 15 + AD 17 8C 22 + EB 3C 87 4A + 5B 00 00 00 + 12 00 00 00 + 00 00 62 C2 + 0C CD D8 C2 + 19 00 0C 00 + 7E 00 C7 EC + E3 05 5D FA + 97 F5 12 12 + C2 05 90 3B + 22 09 40 40 + 07 00 05 00 + 7D 1F DE 05 + 3F 0A 73 06 + 72 1D E2 F5 + 6F 12 BF 1D + 88 18 FB 22 + 8D 45 C6 52 + 54 00 00 00 + 0F 00 00 00 + 00 00 BD CD + 55 C2 5D C5 + 14 00 00 00 + 7E 00 C7 EC + 60 06 BB 00 + B3 FC 61 03 + 6A 06 78 1B + B3 33 08 33 + 07 10 00 00 + 3E 0B 99 45 + 14 00 19 00 + AE 01 0A FA + FF 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + 00 00 00 00 + ]; +}; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-samsung_dsc.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-samsung_dsc.dtsi new file mode 100644 index 000000000000..59ecdfb593f5 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dsi-panel-samsung_dsc.dtsi @@ -0,0 +1,447 @@ +/* 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_dsc_cmd: qcom,mdss_dsi_samsung_dsc_cmd { + qcom,mdss-dsi-panel-name = "samsung dsc cmd mode 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 5>, <0 2>, <1 10>; + qcom,mdss-pan-physical-width-dimension = <68>; + qcom,mdss-pan-physical-height-dimension = <145>; + 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-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,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 08]; + qcom,mdss-dsi-panel-status-command-state = "dsi_hs_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 01 05 00 02 0A 08]; + qcom,mdss-dsi-panel-id1-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-id2-command = [06 01 00 01 05 00 02 0E 08]; + qcom,mdss-dsi-panel-id2-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-id3-command = [06 01 00 01 05 00 02 E0 08]; + qcom,mdss-dsi-panel-id3-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-id4-command = [06 01 00 01 05 00 02 0F 08]; + qcom,mdss-dsi-panel-id4-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-id5-command = [06 01 00 01 05 00 02 E3 08]; + qcom,mdss-dsi-panel-id5-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-id6-command = [06 01 00 01 05 00 02 E5 08]; + qcom,mdss-dsi-panel-id6-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-id7-command = [06 01 00 01 05 00 02 FB 08]; + qcom,mdss-dsi-panel-id7-command-state = "dsi_hs_mode"; + + qcom,mdss-dsi-panel-read-register-open-command = [ + 39 01 00 00 00 00 03 FC 5A 5A]; + qcom,mdss-dsi-panel-read-register-close-command = [ + 39 01 00 00 00 00 03 FC A5 A5]; + qcom,mdss-dsi-panel-read-register-open-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-read-register-close-command-state = "dsi_hs_mode"; + + 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-status-check-mode = "te_signal_check"; + 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,ulps-enabled; + 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 = <72>; + qcom,mdss-dsi-h-back-porch = <36>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <18>; + qcom,mdss-dsi-v-front-porch = <32>; + 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-panel-clockrate = <1037000000>;// 518.5MHZ + qcom,mdss-dsi-on-command = [ + + + 29 00 00 00 00 00 03 F0 5A 5A + 07 01 00 00 00 00 01 01 /* DSC enable : Compression Mode*/ + 29 01 00 00 00 00 5A 0A 11 00 00 89 30 80 09 24 04 38 00 3C 02 1C 02 1C + 02 00 02 0E 00 20 05 D2 + 00 07 00 0C 01 A1 01 B2 + 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 + 29 00 00 00 00 00 03 F0 A5 A5 + + + + 05 01 00 00 78 00 01 11 + + 39 01 00 00 00 00 03 FC 5A 5A /*OSC Speed */ + 39 01 00 00 00 00 02 B0 09 + 39 01 00 00 00 00 02 D7 2A + 39 01 00 00 00 00 02 FE B0 + 39 01 00 00 00 00 02 FE 30 + 39 01 00 00 00 00 03 FC A5 A5 + + 15 01 00 00 00 00 02 35 00 + + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 53 20 + 39 01 00 00 00 00 03 F0 A5 A5 + + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 9D 01 + 39 01 00 00 00 00 03 F0 A5 A5 + + 39 01 00 00 00 00 03 FC 5A 5A /*FFC Setting*/ + 39 01 00 00 00 00 06 C5 0D 10 B4 62 1A + 39 01 00 00 00 00 03 FC A5 A5 + + 05 01 00 00 00 00 02 29 00]; + + + qcom,mdss-dsi-off-command = [ + + /*Display off Delay 20ms*/ + 05 01 00 00 14 00 02 28 00 + /*Sleep in*/ + 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_lp_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + + qcom,compression-mode = "dsc"; + 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; + + + + + /**************************************************************/ + qcom,mdss-dsi-panel-hbm-on-command = [ + 39 01 00 00 00 00 03 51 00 26 + 39 01 00 00 00 00 02 53 E0 + ]; + qcom,mdss-dsi-panel-hbm-on-command-2 = [ + 39 01 00 00 00 00 03 51 00 78 + 39 01 00 00 00 00 02 53 E0 + ]; + qcom,mdss-dsi-panel-hbm-on-command-3 = [ + 39 01 00 00 00 00 03 51 00 CA + 39 01 00 00 00 00 02 53 E0 + ]; + qcom,mdss-dsi-panel-hbm-on-command-4 = [ + 39 01 00 00 00 00 03 51 01 2A + 39 01 00 00 00 00 02 53 E0 + ]; + qcom,mdss-dsi-panel-hbm-on-command-5 = [ + 39 01 00 00 00 00 03 51 03 FF + 39 01 00 00 00 00 02 53 E0 + ]; + qcom,mdss-dsi-panel-hbm-off-command = [ + 39 01 00 00 00 00 02 53 20 + ]; + + qcom,mdss-dsi-hbm-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-hbm-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-aod-on-command-1 = [ + 05 01 00 00 23 00 02 28 00 + 05 01 00 00 78 00 02 10 00 + 05 01 00 00 0A 00 02 11 00 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 01 + 15 01 00 00 00 00 02 CD 02 + 15 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 08 EB 17 41 92 0E 10 82 5A + 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 09 + 39 01 00 00 00 00 03 E8 10 30 + 15 01 00 00 00 00 02 53 23 /*AOD Low mode 10nit*/ + 15 01 00 00 00 00 02 B0 A5 + 15 01 00 00 00 00 02 C7 01 /*ALPM*/ + 39 01 00 00 00 00 03 F0 A5 A5 + 05 01 00 00 00 00 02 29 00 + ]; + qcom,mdss-dsi-panel-aod-on-command-2 = [ + 05 01 00 00 23 00 02 28 00 + 05 01 00 00 78 00 02 10 00 + 05 01 00 00 0A 00 02 11 00 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 01 + 15 01 00 00 00 00 02 CD 02 + 15 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 08 EB 17 41 92 0E 10 82 5A + 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 09 + 39 01 00 00 00 00 03 E8 10 30 + 15 01 00 00 00 00 02 53 22 /*AOD Low mode 50nit*/ + 15 01 00 00 00 00 02 B0 A5 + 15 01 00 00 00 00 02 C7 01 /*ALPM*/ + 39 01 00 00 00 00 03 F0 A5 A5 + 05 01 00 00 00 00 02 29 00 + ]; + qcom,mdss-dsi-panel-aod-on-command-3 = [ + + 05 01 00 00 23 00 02 28 00 + 05 01 00 00 78 00 02 10 00 + 05 01 00 00 0A 00 02 11 00 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 01 + 15 01 00 00 00 00 02 CD 02 + 15 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 08 EB 17 41 92 0E 10 82 5A + 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 09 + 39 01 00 00 00 00 03 E8 10 30 + 15 01 00 00 00 00 02 53 23/*AOD Low mode 10nit*/ + 15 01 00 00 00 00 02 B0 A5 + 15 01 00 00 00 00 02 C7 00 /*HLPM*/ + 39 01 00 00 00 00 03 F0 A5 A5 + 05 01 00 00 00 00 02 29 00 + ]; + qcom,mdss-dsi-panel-aod-on-command-4 = [ + 39 01 00 00 00 00 03 9F A5 A5 + 05 01 00 00 0A 00 01 28 + 05 01 00 00 78 00 01 10 + 05 01 00 00 0A 00 01 11 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 01 + 15 01 00 00 20 00 02 CD 01 + 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 01 + 15 01 00 00 14 00 02 CD 02 + 39 01 00 00 00 00 03 51 03 FF + 15 01 00 00 00 00 02 53 22 + 15 01 00 00 00 00 02 B0 A5 + 15 01 00 00 00 00 02 C7 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 05 01 00 00 00 00 01 29 + 39 01 00 00 00 00 03 9F 5A 5A + + ]; + qcom,mdss-dsi-panel-aod-off-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 01 + 15 01 00 00 00 00 02 CD 01 + 39 01 00 00 00 00 02 53 20 + 39 01 00 00 00 00 03 F0 A5 A5 + + ]; + qcom,mdss-dsi-panel-aod-mode-command-1 = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 53 23 + 15 01 00 00 00 00 02 B0 A5 + 15 01 00 00 00 00 02 C7 01 + 39 01 00 00 00 00 03 F0 A5 A5 + + ]; + qcom,mdss-dsi-panel-aod-mode-command-2 = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 53 22 + 15 01 00 00 00 00 02 B0 A5 + 15 01 00 00 00 00 02 C7 01 + 39 01 00 00 00 00 03 F0 A5 A5 + + ]; + qcom,mdss-dsi-panel-aod-mode-command-3 = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 53 23 + 15 01 00 00 00 00 02 B0 A5 + 15 01 00 00 00 00 02 C7 00 + 39 01 00 00 00 00 03 F0 A5 A5 + + ]; + qcom,mdss-dsi-panel-aod-mode-command-4 = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 53 22 + 15 01 00 00 00 00 02 B0 A5 + 15 01 00 00 00 00 02 C7 00 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + + qcom,mdss-dsi-aod-on-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-aod-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-aod-mode-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-serial-num-command = [ + 06 01 00 00 00 00 01 A1 + ]; + qcom,mdss-dsi-panel-serial-num-command-state = "dsi_lp_mode"; + + qcom,mdss-dsi-panel-srgb-on-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 02 + 39 01 00 00 00 00 16 B1 A3 05 04 46 cd 10 05 09 b0 57 ef cf bb 11 bf e1 da 17 ff f9 d8 + 39 01 00 00 00 00 03 B1 00 00 + 39 01 00 00 00 00 03 f0 A5 A5 + ]; + qcom,mdss-dsi-panel-srgb-off-command = [ + 39 01 00 00 00 00 02 81 00 + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 03 B1 00 01 /* SEED CRC OFF */ + 39 01 00 00 00 00 03 B3 00 C1 /* TCS OFF */ + 39 01 00 00 00 00 03 F0 A5 A5 + + ]; + qcom,mdss-dsi-srgb-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-srgb-off-command-state = "dsi_lp_mode"; + + qcom,mdss-dsi-panel-dci-p3-on-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 02 + 39 01 00 00 00 00 16 B1 C6 00 00 1e cf 00 06 0a c3 26 ef cd e0 04 ce e9 df 00 ff f9 d8 + 39 01 00 00 00 00 03 B1 00 00 + 39 01 00 00 00 00 03 f0 A5 A5 + ]; + qcom,mdss-dsi-panel-dci-p3-off-command = [ + 39 01 00 00 00 00 02 81 00 + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 03 B1 00 01 /* SEED CRC OFF */ + 39 01 00 00 00 00 03 B3 00 C1 /* TCS OFF */ + 39 01 00 00 00 00 03 F0 A5 A5 + + ]; + qcom,mdss-dsi-dci-p3-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dci-p3-off-command-state = "dsi_lp_mode"; + + qcom,mdss-dsi-panel-night-mode-on-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 02 + 39 01 00 00 00 00 16 B1 A0 02 04 3B C7 12 08 07 A8 4B E7 C9 BF 0A B9 E3 DA 18 FF FE FA + 39 01 00 00 00 00 03 B1 00 00 + 39 01 00 00 00 00 03 f0 A5 A5 + ]; + qcom,mdss-dsi-panel-night-mode-off-command = [ + 39 01 00 00 00 00 02 81 00 + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 03 B1 00 01 /* SEED CRC OFF */ + 39 01 00 00 00 00 03 B3 00 C1 /* TCS OFF */ + 39 01 00 00 00 00 03 F0 A5 A5 + + ]; + qcom,mdss-dsi-night-mode-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-night-mode-off-command-state = "dsi_lp_mode"; + + qcom,mdss-dsi-panel-oneplus-mode-on-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 02 + 39 01 00 00 00 00 16 B1 b4 02 04 05 ff 02 00 00 ff 00 ff ff f0 00 f0 e0 e1 18 ff fe fB + 39 01 00 00 00 00 03 B1 00 00 + 39 01 00 00 00 00 03 f0 A5 A5 + ]; + qcom,mdss-dsi-panel-oneplus-mode-off-command = [ + 39 01 00 00 00 00 02 81 00 + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 03 B1 00 01 /* SEED CRC OFF */ + 39 01 00 00 00 00 03 B3 00 C1 /* TCS OFF */ + 39 01 00 00 00 00 03 F0 A5 A5 + + ]; + qcom,mdss-dsi-panel-oneplus-mode-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-oneplus-mode-off-command-state = "dsi_lp_mode"; + + qcom,mdss-dsi-panel-adaption-mode-on-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 02 + 39 01 00 00 00 00 16 B1 B8 03 04 45 E2 10 04 07 C1 4B EB D7 B8 0A BF FF ED 14 FF FF FA + 39 01 00 00 00 00 03 B1 00 00 + 39 01 00 00 00 00 03 f0 A5 A5 + ]; + qcom,mdss-dsi-panel-adaption-mode-off-command = [ + 39 01 00 00 00 00 02 81 00 + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 03 B1 00 01 /* SEED CRC OFF */ + 39 01 00 00 00 00 03 B3 00 C1 /* TCS OFF */ + 39 01 00 00 00 00 03 F0 A5 A5 + + ]; + qcom,mdss-dsi-adaption-mode-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-adaption-mode-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 05 00 02 0A 08]; + qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-id-command = [06 01 00 01 05 00 02 DC 08]; + qcom,mdss-dsi-panel-id-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-id1-command = [06 01 00 01 05 00 02 0A 08]; + qcom,mdss-dsi-panel-id1-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-id2-command = [06 01 00 01 05 00 02 0E 08]; + qcom,mdss-dsi-panel-id2-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-id3-command = [06 01 00 01 05 00 02 E0 08]; + qcom,mdss-dsi-panel-id3-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-id4-command = [06 01 00 01 05 00 02 0F 08]; + qcom,mdss-dsi-panel-id4-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-id5-command = [06 01 00 01 05 00 02 E3 08]; + qcom,mdss-dsi-panel-id5-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-id6-command = [06 01 00 01 05 00 02 E5 08]; + qcom,mdss-dsi-panel-id6-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-id7-command = [06 01 00 01 05 00 02 FB 08]; + qcom,mdss-dsi-panel-id7-command-state = "dsi_hs_mode"; + + qcom,mdss-dsi-panel-read-register-open-command = [ + 39 01 00 00 00 00 03 FC 5A 5A]; + qcom,mdss-dsi-panel-read-register-close-command = [ + 39 01 00 00 00 00 03 FC A5 A5]; + qcom,mdss-dsi-panel-read-register-open-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-read-register-close-command-state = "dsi_hs_mode"; + + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-samsung_s6e3fc1_cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-samsung_s6e3fc1_cmd.dtsi new file mode 100644 index 000000000000..bc47af8ad4e2 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dsi-panel-samsung_s6e3fc1_cmd.dtsi @@ -0,0 +1,215 @@ +/* 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_s6e3fc1_cmd: qcom,mdss_dsi_samsung_s6e3fc1_cmd { + qcom,mdss-dsi-panel-name = "samsung s6e3fc1 cmd mode dsi panel"; + qcom,mdss-dsi-panel-manufacture = "SAMSUNG"; + qcom,mdss-dsi-panel-version = "S6E3FC1"; + 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 5>, <0 2>, <1 10>; + qcom,mdss-pan-physical-width-dimension = <68>; + qcom,mdss-pan-physical-height-dimension = <137>; + 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-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,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 08]; + 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-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-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,ulps-enabled; + 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 = <128>; + qcom,mdss-dsi-h-back-porch = <64>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <4>; + qcom,mdss-dsi-v-front-porch = <18>; + 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 = <0x8 0xa>; + qcom,mdss-dsi-on-command = [ + 05 01 00 00 14 00 02 11 00 + 15 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 03 FC 5A 5A + 39 01 00 00 00 00 04 E8 64 08 0C + 39 01 00 00 00 00 03 FC A5 A5 + 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 ED 04 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 53 20 + 15 01 00 00 00 00 02 55 00 + 05 01 00 00 00 00 02 29 00 + ]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 28 00 02 28 00 + 05 01 00 00 A0 00 02 10 00 + ]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + /**************************************************************/ + qcom,mdss-dsi-panel-acl-command = [15 01 00 00 00 00 02 55 00]; + qcom,mdss-dsi-acl-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-on-command = [15 01 00 00 00 00 02 53 E8]; + qcom,mdss-dsi-panel-hbm-off-command = [15 01 00 00 00 00 02 53 28]; + qcom,mdss-dsi-hbm-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-serial-num-command = [ + 06 01 00 00 00 00 01 A1 + ]; + qcom,mdss-dsi-panel-serial-num-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-srgb-on-command = [ + 39 01 00 00 00 00 03 f0 5A 5A + 39 01 00 00 00 00 02 BC 01 + 39 01 00 00 00 00 02 B0 01 + 39 01 00 00 00 00 02 BC 12 + 39 01 00 00 00 00 02 B0 2C + 39 01 00 00 00 00 16 bc A3 05 04 46 cd 10 05 09 b0 57 ef cf bb 11 bf e1 da 17 ff f9 d8 + 39 01 00 00 00 00 02 b0 42 + 39 01 00 00 00 00 02 bc 03 + 39 01 00 00 00 00 02 b0 4B + 39 01 00 00 00 00 02 bc A1 + 39 01 00 00 00 00 03 f0 A5 A5 + ]; + qcom,mdss-dsi-panel-srgb-off-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 03 BC 0E 00 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-srgb-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-srgb-off-command-state = "dsi_lp_mode"; + + qcom,mdss-dsi-panel-dci-p3-on-command = [ + 39 01 00 00 00 00 03 f0 5A 5A + 39 01 00 00 00 00 02 BC 01 + 39 01 00 00 00 00 02 B0 01 + 39 01 00 00 00 00 02 BC 12 + 39 01 00 00 00 00 02 B0 2C + 39 01 00 00 00 00 16 BC C6 00 00 1e cf 00 06 0a c3 26 ef cd e0 04 ce e9 df 00 ff f9 d8 + 39 01 00 00 00 00 02 b0 42 + 39 01 00 00 00 00 02 bc 03 + 39 01 00 00 00 00 02 b0 4B + 39 01 00 00 00 00 02 bc A1 + 39 01 00 00 00 00 03 f0 A5 A5 + ]; + qcom,mdss-dsi-panel-dci-p3-off-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 03 BC 0E 00 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-dci-p3-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dci-p3-off-command-state = "dsi_lp_mode"; + + qcom,mdss-dsi-panel-night-mode-on-command = [ + 39 01 00 00 00 00 03 f0 5A 5A + 39 01 00 00 00 00 03 BC 01 12 + 39 01 00 00 00 00 02 B0 2C + 39 01 00 00 00 00 16 BC A0 02 04 3B C7 12 08 07 A8 4B E7 C9 BF 0A B9 E3 DA 18 FF FE FA + 39 01 00 00 00 00 03 f0 A5 A5 + ]; + qcom,mdss-dsi-panel-night-mode-off-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 03 BC 0E 00 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-night-mode-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-night-mode-off-command-state = "dsi_lp_mode"; + + qcom,mdss-dsi-panel-oneplus-mode-on-command = [ + 39 01 00 00 00 00 03 f0 5a 5a + 39 01 00 00 00 00 03 bc 01 12 + 39 01 00 00 00 00 02 b0 2c + 39 01 00 00 00 00 16 bc b4 02 04 05 ff 02 00 00 ff 00 ff ff f0 00 f0 e0 e1 18 ff fe fB + 39 01 00 00 00 00 03 f0 a5 a5 + 39 01 00 00 00 00 03 f0 5a 5a + 39 01 00 00 00 00 02 bc 01 + 39 01 00 00 00 00 02 b0 42 + 39 01 00 00 00 00 02 bc 03 + 39 01 00 00 00 00 02 b0 4b + 39 01 00 00 00 00 02 bc 01 + 39 01 00 00 00 00 03 f0 a5 a5 + ]; + qcom,mdss-dsi-panel-oneplus-mode-off-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 03 BC 0E 00 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-oneplus-mode-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-oneplus-mode-off-command-state = "dsi_lp_mode"; + + qcom,mdss-dsi-panel-adaption-mode-on-command = [ + 39 01 00 00 00 00 03 f0 5a 5a + 39 01 00 00 00 00 03 bc 01 12 + 39 01 00 00 00 00 02 b0 2c + 39 01 00 00 00 00 16 bc B8 03 04 45 E2 10 04 07 C1 4B EB D7 B8 0A BF FF ED 14 FF FF FA + 39 01 00 00 00 00 03 f0 a5 a5 + 39 01 00 00 00 00 03 f0 5a 5a + 39 01 00 00 00 00 02 bc 01 + 39 01 00 00 00 00 02 b0 42 + 39 01 00 00 00 00 02 bc 03 + 39 01 00 00 00 00 02 b0 4b + 39 01 00 00 00 00 02 bc 01 + 39 01 00 00 00 00 03 f0 a5 a5 + ]; + qcom,mdss-dsi-panel-adaption-mode-off-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 03 BC 0E 00 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-adaption-mode-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-adaption-mode-off-command-state = "dsi_lp_mode"; + + qcom,mdss-dsi-panel-status-command = [06 01 00 01 05 00 02 0a 08]; + qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-samsung_s6e3fc2x01.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-samsung_s6e3fc2x01.dtsi new file mode 100644 index 000000000000..e950ed3c4984 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dsi-panel-samsung_s6e3fc2x01.dtsi @@ -0,0 +1,437 @@ +/* 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_s6e3fc2x01_cmd: qcom,mdss_dsi_samsung_s6e3fc2x01_cmd { + qcom,mdss-dsi-panel-name = "samsung s6e3fc2x01 cmd mode dsi panel"; + qcom,mdss-dsi-panel-manufacture = "SAMSUNG"; + qcom,mdss-dsi-panel-version = "S6E3FC2X01"; + 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 5>, <0 2>, <1 10>; + qcom,mdss-pan-physical-width-dimension = <68>; + qcom,mdss-pan-physical-height-dimension = <145>; + 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-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,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 08]; + 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-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-status-check-mode = "te_signal_check"; + 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,ulps-enabled; + /* 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-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 = <72>; + qcom,mdss-dsi-h-back-porch = <36>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <18>; + qcom,mdss-dsi-v-front-porch = <32>; + 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-panel-clockrate = <1037000000>;// 518.5MHZ + qcom,mdss-dsi-on-command = [ + 39 01 00 00 00 00 03 9F A5 A5 + 05 01 00 00 0A 00 02 11 00 + 39 01 00 00 00 00 03 9F 5A 5A + /*FD setting*/ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 01 + 15 01 00 00 00 00 02 CD 01 + 39 01 00 00 0F 00 03 F0 A5 A5 + /*TE ON*/ + 39 01 00 00 00 00 03 9F A5 A5 + 15 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 03 9F 5A 5A + /*MIC Setting*/ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 08 EB 17 41 92 0E 10 82 5A + 39 01 00 00 00 00 03 F0 A5 A5 + /*CASET/PASET*/ + 39 01 00 00 00 00 05 2A 00 00 04 37 + 39 01 00 00 00 00 05 2B 00 00 09 23 + /*TSP H_sync Setting*/ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 02 B0 09 + 39 01 00 00 00 00 03 E8 10 30 + 39 01 00 00 00 00 03 F0 A5 A5 + /*Dimming Setting*/ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 07 + 15 01 00 00 00 00 02 B7 01 + 15 01 00 00 00 00 02 B0 08 + 15 01 00 00 00 00 02 B7 12 + 39 01 00 00 00 00 03 F0 A5 A5 + /*ESD improvement 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 02 E3 88 + 39 01 00 00 00 00 02 B0 07 + 39 01 00 00 00 00 02 ED 67 + 39 01 00 00 00 00 03 FC A5 A5 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 53 20 + 39 01 00 00 00 00 03 F0 A5 A5 + /*ACL off*/ + 39 01 00 00 01 00 02 55 00 + /*SEED OFF*/ + // 39 01 00 00 00 00 03 F0 5A 5A + // 39 01 00 00 00 00 03 B1 00 01 + // 39 01 00 00 00 00 03 F0 A5 A5 + /*SEED TCS OFF*/ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 03 B3 00 C1 + 39 01 00 00 00 00 03 F0 A5 A5 + /*Display on*/ + // 39 01 00 00 00 00 03 9F A5 A5 + // 05 01 00 00 00 00 02 29 00 + // 39 01 00 00 00 00 03 9F 5A 5A + ]; + qcom,mdss-dsi-off-command = [ + 39 01 00 00 00 00 03 9F A5 A5 + 05 01 00 00 0A 00 01 28 + 39 01 00 00 10 00 03 F0 5A 5A + 39 01 00 00 00 00 02 B0 50 + 39 01 00 00 00 00 02 B9 82 + 39 01 00 00 10 00 03 F0 A5 A5 + 05 01 00 00 00 00 01 10 + 39 01 00 00 00 00 03 9F 5A 5A + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 05 + 15 01 00 00 00 00 02 F4 01 + 39 01 00 00 96 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-post-panel-on-command=[ + 39 01 00 00 00 00 03 9F A5 A5 + 05 01 00 00 00 00 01 29 + 39 01 00 00 00 00 03 9F 5A 5A + ]; + 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-panel-hbm-on-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 07 + 15 01 00 00 00 00 02 B7 7F + 15 01 00 00 00 00 02 B0 08 + 15 01 00 00 80 00 02 B7 92 + 39 01 00 00 00 00 02 53 E8 + 39 01 00 00 23 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 51 00 26 + ]; + qcom,mdss-dsi-panel-hbm-on-command-2 = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 07 + 15 01 00 00 00 00 02 B7 7F + 15 01 00 00 00 00 02 B0 08 + 15 01 00 00 80 00 02 B7 92 + 39 01 00 00 00 00 02 53 E8 + 39 01 00 00 23 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 51 00 78 + ]; + qcom,mdss-dsi-panel-hbm-on-command-3 = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 07 + 15 01 00 00 00 00 02 B7 7F + 15 01 00 00 00 00 02 B0 08 + 15 01 00 00 80 00 02 B7 92 + 39 01 00 00 00 00 02 53 E8 + 39 01 00 00 23 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 51 00 CA + ]; + qcom,mdss-dsi-panel-hbm-on-command-4 = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 07 + 15 01 00 00 00 00 02 B7 7F + 15 01 00 00 00 00 02 B0 08 + 15 01 00 00 80 00 02 B7 92 + 39 01 00 00 00 00 02 53 E8 + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 51 01 2A + + ]; + qcom,mdss-dsi-panel-hbm-on-command-5 = [ + /*ELVSS OFF*/ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 07 + 15 01 00 00 00 00 02 B7 01 + 15 01 00 00 00 00 02 B0 08 + 15 01 00 00 00 00 02 B7 12 + 39 01 00 00 00 00 03 F0 A5 A5 + /*DLY OFF*/ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 04 B7 00 01 5B + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 0A 00 02 53 E0 + 39 01 00 00 00 00 03 51 03 FF + /*DLY ON*/ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 04 B7 00 01 53 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-hbm-off-command = [ + /*DLY OFF*/ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 04 B7 00 01 5B + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 02 53 20 + /*DLY ON*/ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 04 B7 00 01 53 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-hbm-max-brightness-command-on = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 07 + 15 01 00 00 00 00 02 B7 7F + 15 01 00 00 00 00 02 B0 08 + 15 01 00 00 80 00 02 B7 92 + 39 01 00 00 40 00 02 53 E8 + 39 01 00 00 80 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 51 03 FF + ]; + qcom,mdss-dsi-panel-hbm-max-brightness-command-off = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 07 + 15 01 00 00 40 00 02 B7 7F + 15 01 00 00 00 00 02 B0 08 + 15 01 00 00 40 00 02 B7 92 + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 10 00 02 53 28 + ]; + qcom,mdss-dsi-seed-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 02 + 29 01 00 00 00 00 16 B1 B4 02 04 05 FF 02 00 00 FF 00 FF FF F0 00 F0 E0 E1 18 FF F3 F8 + 29 01 00 00 00 00 03 B1 00 00 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + + qcom,mdss-dsi-panel-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 02 + 29 01 00 00 00 00 16 B1 B4 02 04 05 FF 02 00 00 FF 00 FF FF F0 00 F0 E0 E1 18 FF F3 F8 + 29 01 00 00 00 00 03 B1 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-hbm-on-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-on-command-5-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-max-brightness-command-on-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-hbm-max-brightness-command-off-state = "dsi_lp_mode"; + qcom,mdss-dsi-hbm-off-command-state = "dsi_hs_mode"; + + 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-off-command = [ + ]; + qcom,mdss-dsi-panel-aod-off-samsung-command = [ + ]; + qcom,mdss-dsi-panel-aod-off-new-command = [ + ]; + 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 = [ + + /*ELVSS OFF*/ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 07 + 15 01 00 00 00 00 02 B7 01 + 15 01 00 00 00 00 02 B0 08 + 15 01 00 00 00 00 02 B7 12 + 39 01 00 00 00 00 03 F0 A5 A5 + /*DLY OFF*/ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 04 B7 00 01 5B + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 0A 00 02 53 E0 + 39 01 00 00 00 00 03 51 03 FF + /*DLY ON*/ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 04 B7 00 01 53 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-aod-off-hbm-on-command-state = "dsi_lp_mode"; + 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 04 B7 00 01 5B + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 02 53 20 + /*DLY ON*/ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 04 B7 00 01 53 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-hbm-off-aod-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-aod-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-aod-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-aod-mode-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-serial-num-command = [ + 06 01 00 00 00 00 01 A1 + ]; + qcom,mdss-dsi-panel-serial-num-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-display-srgb-color-mode-on-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 02 + 39 01 00 00 00 00 16 B1 DA 05 03 15 E3 18 03 03 E9 25 FC F0 FC 09 EE FE F8 16 FF F9 F3 + 39 01 00 00 00 00 03 B1 00 00 + 39 01 00 00 00 00 03 f0 A5 A5 + + ]; + qcom,mdss-dsi-panel-display-p3-mode-on-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 02 + 39 01 00 00 00 00 16 B1 CE 01 02 1D E3 00 07 0D E9 28 FD F0 D3 0A E2 EA EA 01 FF FF F2 + 39 01 00 00 00 00 03 B1 00 00 + 39 01 00 00 00 00 03 f0 A5 A5 + ]; + qcom,mdss-dsi-panel-display-wide-color-mode-on-command = [ + 39 01 00 00 02 00 02 81 90 + 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 16 B1 FF 00 00 00 FF 00 00 00 FF 00 FF FF FF 00 FF FF FF 00 FF FF FF + 39 01 00 00 00 00 03 B1 00 00 + 39 01 00 00 00 00 03 f0 A5 A5 + ]; + qcom,mdss-dsi-panel-dci-p3-off-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 03 B1 00 01 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-customer-srgb-enable-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 02 + 39 01 00 00 00 00 16 B1 CE 01 02 1D E3 00 07 0D E9 28 FD F0 D3 0A E2 EA EA 01 FF FF F2 + 39 01 00 00 00 00 03 B1 00 00 + 39 01 00 00 00 00 03 f0 A5 A5 + ]; + qcom,mdss-dsi-customer-p3-enable-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 02 + 39 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 F2 + 39 01 00 00 00 00 03 B1 00 00 + 39 01 00 00 00 00 03 f0 A5 A5 + ]; + qcom,mdss-dsi-customer-p3-enable-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-customer-srgb-enable-command-state = "dsi_lp_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-adaption-mode-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-adaption-mode-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 05 00 02 0E 08]; + qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-id-command = [06 01 00 01 05 00 02 DC 08]; + qcom,mdss-dsi-panel-id-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-id1-command = [06 01 00 01 05 00 02 0A 08]; + qcom,mdss-dsi-panel-id1-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-id2-command = [06 01 00 01 05 00 02 0E 08]; + qcom,mdss-dsi-panel-id2-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-id3-command = [06 01 00 01 05 00 02 E0 08]; + qcom,mdss-dsi-panel-id3-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-id4-command = [06 01 00 01 05 00 02 0F 08]; + qcom,mdss-dsi-panel-id4-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-id5-command = [06 01 00 01 05 00 02 E3 08]; + qcom,mdss-dsi-panel-id5-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-id6-command = [06 01 00 01 05 00 02 E5 08]; + qcom,mdss-dsi-panel-id6-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-id7-command = [06 01 00 01 05 00 02 FB 08]; + qcom,mdss-dsi-panel-id7-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-hbm-level1-command = [15 01 00 00 00 00 02 B0 08]; + qcom,mdss-dsi-panel-hbm-level1-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-hbm-read-command = [06 01 00 01 05 00 02 B7 08]; + qcom,mdss-dsi-panel-hbm-read-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-read-register-open-command = [ + 39 01 00 00 00 00 03 FC 5A 5A]; + qcom,mdss-dsi-panel-read-register-close-command = [ + 39 01 00 00 00 00 03 FC A5 A5]; + 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-hbm-elvss-open-command = [ + 39 01 00 00 00 00 03 F0 5A 5A]; + qcom,mdss-dsi-panel-read-hbm-elvss-close-command = [ + 39 01 00 00 00 00 03 F0 A5 A5]; + qcom,mdss-dsi-panel-read-hbm-elvss-open-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-read-hbm-elvss-close-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-hbm-diming-on-command = [39 01 00 00 00 00 02 B7 92]; + qcom,mdss-dsi-panel-hbm-diming-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-hbm-diming-off-command = [39 01 00 00 00 00 02 B7 12]; + qcom,mdss-dsi-panel-hbm-diming-off-command-state = "dsi_lp_mode"; + + + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-samsung_sefeg01_s_cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-samsung_sefeg01_s_cmd.dtsi new file mode 100644 index 000000000000..ad639e58aa63 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dsi-panel-samsung_sefeg01_s_cmd.dtsi @@ -0,0 +1,390 @@ +/* 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_sofeg01_s_cmd: qcom,mdss_dsi_samsung_sofeg01_s_cmd { + qcom,mdss-dsi-panel-name = "samsung sofeg01_s cmd mode dsi panel"; + qcom,mdss-dsi-panel-manufacture = "SAMSUNG"; + qcom,mdss-dsi-panel-version = "SOFEG01_S"; + 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 5>, <0 2>, <1 10>; + qcom,mdss-pan-physical-width-dimension = <68>; + qcom,mdss-pan-physical-height-dimension = <145>; + 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-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,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 08]; + //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-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-status-check-mode = "te_signal_check"; + 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,ulps-enabled; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <2280>; + qcom,mdss-dsi-h-front-porch = <112>; + qcom,mdss-dsi-h-back-porch = <36>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <12>; + qcom,mdss-dsi-v-front-porch = <36>; + 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 = <0x8 0xa>; + qcom,mdss-dsi-on-command = [ + 05 01 00 00 05 00 02 11 00 + 15 01 00 00 00 00 02 B0 1C + 15 01 00 00 0F 00 02 B5 24 + 15 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 03 FC 5A 5A + 39 01 00 00 00 00 04 E8 64 08 0C + 39 01 00 00 00 00 03 FC A5 A5 + 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 ED 04 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 53 20 + 15 01 00 00 00 00 02 55 00 + 05 01 00 00 00 00 02 29 00 + ]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 28 00 02 28 00 + 05 01 00 00 A0 00 02 10 00 + ]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + /**************************************************************/ + qcom,mdss-dsi-panel-acl-command = [15 01 00 00 00 00 02 55 00]; + qcom,mdss-dsi-acl-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-on-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 53 E8 + 39 01 00 00 00 00 04 B1 20 10 AC + 15 01 00 00 00 00 02 F7 03 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-hbm-on-command-2 = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 53 E8 + 39 01 00 00 00 00 04 B1 20 10 0C + 15 01 00 00 00 00 02 F7 03 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-hbm-on-command-3 = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 53 E8 + 39 01 00 00 00 00 04 B1 10 10 6C + 15 01 00 00 00 00 02 F7 03 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-hbm-on-command-4 = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 53 E8 + 39 01 00 00 00 00 04 B1 00 10 C0 + 15 01 00 00 00 00 02 F7 03 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-hbm-on-command-5 = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 53 E8 + 39 01 00 00 00 00 04 B1 00 10 10 + 15 01 00 00 00 00 02 F7 03 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-hbm-off-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 53 28 + 15 01 00 00 00 00 02 F7 03 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-hbm-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-hbm-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-aod-on-command-1 = [ + 05 01 00 00 0A 00 02 28 00 + 05 01 00 00 78 00 02 10 00 + 05 01 00 00 05 00 02 11 00 + 15 01 00 00 00 00 02 B0 1C + 15 01 00 00 0F 00 02 B5 28 + 15 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 03 FC 5A 5A + 39 01 00 00 00 00 04 E8 64 08 0C + 39 01 00 00 00 00 03 FC A5 A5 + 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 ED 04 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 64 00 02 55 00 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 53 03 + 15 01 00 00 00 00 02 BB 07 + 39 01 00 00 00 00 03 F0 A5 A5 + 05 01 00 00 00 00 02 29 00 + ]; + qcom,mdss-dsi-panel-aod-on-command-2 = [ + 05 01 00 00 0A 00 02 28 00 + 05 01 00 00 78 00 02 10 00 + 05 01 00 00 05 00 02 11 00 + 15 01 00 00 00 00 02 B0 1C + 15 01 00 00 0F 00 02 B5 28 + 15 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 03 FC 5A 5A + 39 01 00 00 00 00 04 E8 64 08 0C + 39 01 00 00 00 00 03 FC A5 A5 + 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 ED 04 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 64 00 02 55 00 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 53 02 + 15 01 00 00 00 00 02 BB 07 + 39 01 00 00 00 00 03 F0 A5 A5 + 05 01 00 00 00 00 02 29 00 + ]; + qcom,mdss-dsi-panel-aod-on-command-3 = [ + 05 01 00 00 0A 00 02 28 00 + 05 01 00 00 78 00 02 10 00 + 05 01 00 00 05 00 02 11 00 + 15 01 00 00 00 00 02 B0 1C + 15 01 00 00 0F 00 02 B5 28 + 15 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 03 FC 5A 5A + 39 01 00 00 00 00 04 E8 64 08 0C + 39 01 00 00 00 00 03 FC A5 A5 + 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 ED 04 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 64 00 02 55 00 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 53 03 + 15 01 00 00 00 00 02 BB 05 + 39 01 00 00 00 00 03 F0 A5 A5 + 05 01 00 00 00 00 02 29 00 + ]; + qcom,mdss-dsi-panel-aod-on-command-4 = [ + 05 01 00 00 0A 00 02 28 00 + 05 01 00 00 78 00 02 10 00 + 05 01 00 00 05 00 02 11 00 + 15 01 00 00 00 00 02 B0 1C + 15 01 00 00 0F 00 02 B5 28 + 15 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 03 FC 5A 5A + 39 01 00 00 00 00 04 E8 64 08 0C + 39 01 00 00 00 00 03 FC A5 A5 + 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 ED 04 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 64 00 02 55 00 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 53 02 + 15 01 00 00 00 00 02 BB 05 + 39 01 00 00 00 00 03 F0 A5 A5 + 05 01 00 00 00 00 02 29 00 + ]; + qcom,mdss-dsi-panel-aod-off-command = [ + 05 01 00 00 0A 00 02 28 00 + 05 01 00 00 78 00 02 10 00 + 05 01 00 00 05 00 02 11 00 + 15 01 00 00 00 00 02 B0 1C + 15 01 00 00 0F 00 02 B5 24 + 15 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 03 FC 5A 5A + 39 01 00 00 00 00 04 E8 64 08 0C + 39 01 00 00 00 00 03 FC A5 A5 + 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 ED 04 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 64 00 02 55 00 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 53 20 + 39 01 00 00 00 00 03 F0 A5 A5 + 05 01 00 00 00 00 02 29 00 + ]; + qcom,mdss-dsi-panel-aod-mode-command-1 = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 53 03 + 15 01 00 00 00 00 02 BB 07 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-aod-mode-command-2 = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 53 02 + 15 01 00 00 00 00 02 BB 07 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-aod-mode-command-3 = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 53 03 + 15 01 00 00 00 00 02 BB 05 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-aod-mode-command-4 = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 53 02 + 15 01 00 00 00 00 02 BB 05 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-aod-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-aod-off-command-state = "dsi_lp_mode"; + + qcom,mdss-dsi-panel-serial-num-command = [ + 06 01 00 00 00 00 01 A1 + ]; + qcom,mdss-dsi-panel-serial-num-command-state = "dsi_lp_mode"; + + qcom,mdss-dsi-panel-srgb-on-command = [ + 39 01 00 00 00 00 03 f0 5A 5A + 39 01 00 00 00 00 02 BC 01 + 39 01 00 00 00 00 02 B0 01 + 39 01 00 00 00 00 02 BC 12 + 39 01 00 00 00 00 02 B0 2C + 39 01 00 00 00 00 16 bc A3 05 04 46 cd 10 05 09 b0 57 ef cf bb 11 bf e1 da 17 ff f9 d8 + 39 01 00 00 00 00 02 b0 42 + 39 01 00 00 00 00 02 bc 03 + 39 01 00 00 00 00 02 b0 4B + 39 01 00 00 00 00 02 bc A1 + 39 01 00 00 00 00 03 f0 A5 A5 + ]; + qcom,mdss-dsi-panel-srgb-off-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 03 BC 0E 00 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-srgb-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-srgb-off-command-state = "dsi_lp_mode"; + + qcom,mdss-dsi-panel-dci-p3-on-command = [ + 39 01 00 00 00 00 03 f0 5A 5A + 39 01 00 00 00 00 02 BC 01 + 39 01 00 00 00 00 02 B0 01 + 39 01 00 00 00 00 02 BC 12 + 39 01 00 00 00 00 02 B0 2C + 39 01 00 00 00 00 16 BC C6 00 00 1e cf 00 06 0a c3 26 ef cd e0 04 ce e9 df 00 ff f9 d8 + 39 01 00 00 00 00 02 b0 42 + 39 01 00 00 00 00 02 bc 03 + 39 01 00 00 00 00 02 b0 4B + 39 01 00 00 00 00 02 bc A1 + 39 01 00 00 00 00 03 f0 A5 A5 + ]; + qcom,mdss-dsi-panel-dci-p3-off-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 03 BC 0E 00 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-dci-p3-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dci-p3-off-command-state = "dsi_lp_mode"; + + qcom,mdss-dsi-panel-night-mode-on-command = [ + 39 01 00 00 00 00 03 f0 5A 5A + 39 01 00 00 00 00 03 BC 01 12 + 39 01 00 00 00 00 02 B0 2C + 39 01 00 00 00 00 16 BC A0 02 04 3B C7 12 08 07 A8 4B E7 C9 BF 0A B9 E3 DA 18 FF FE FA + 39 01 00 00 00 00 03 f0 A5 A5 + ]; + qcom,mdss-dsi-panel-night-mode-off-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 03 BC 0E 00 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-night-mode-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-night-mode-off-command-state = "dsi_lp_mode"; + + qcom,mdss-dsi-panel-oneplus-mode-on-command = [ + 39 01 00 00 00 00 03 f0 5a 5a + 39 01 00 00 00 00 03 bc 01 12 + 39 01 00 00 00 00 02 b0 2c + 39 01 00 00 00 00 16 bc b4 02 04 05 ff 02 00 00 ff 00 ff ff f0 00 f0 e0 e1 18 ff fe fB + 39 01 00 00 00 00 03 f0 a5 a5 + 39 01 00 00 00 00 03 f0 5a 5a + 39 01 00 00 00 00 02 bc 01 + 39 01 00 00 00 00 02 b0 42 + 39 01 00 00 00 00 02 bc 03 + 39 01 00 00 00 00 02 b0 4b + 39 01 00 00 00 00 02 bc 01 + 39 01 00 00 00 00 03 f0 a5 a5 + ]; + qcom,mdss-dsi-panel-oneplus-mode-off-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 03 BC 0E 00 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-oneplus-mode-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-oneplus-mode-off-command-state = "dsi_lp_mode"; + + qcom,mdss-dsi-panel-adaption-mode-on-command = [ + 39 01 00 00 00 00 03 f0 5a 5a + 39 01 00 00 00 00 03 bc 01 12 + 39 01 00 00 00 00 02 b0 2c + 39 01 00 00 00 00 16 bc B8 03 04 45 E2 10 04 07 C1 4B EB D7 B8 0A BF FF ED 14 FF FF FA + 39 01 00 00 00 00 03 f0 a5 a5 + 39 01 00 00 00 00 03 f0 5a 5a + 39 01 00 00 00 00 02 bc 01 + 39 01 00 00 00 00 02 b0 42 + 39 01 00 00 00 00 02 bc 03 + 39 01 00 00 00 00 02 b0 4b + 39 01 00 00 00 00 02 bc 01 + 39 01 00 00 00 00 03 f0 a5 a5 + ]; + qcom,mdss-dsi-panel-adaption-mode-off-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 03 BC 0E 00 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-adaption-mode-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-adaption-mode-off-command-state = "dsi_lp_mode"; + + //qcom,mdss-dsi-panel-status-command = [06 01 00 01 05 00 02 0a 08]; + //qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-samsung_sofef00_m_cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-samsung_sofef00_m_cmd.dtsi new file mode 100644 index 000000000000..77680d0f38c5 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dsi-panel-samsung_sofef00_m_cmd.dtsi @@ -0,0 +1,336 @@ +/* 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_cmd: qcom,mdss_dsi_samsung_sofef00_m_cmd { + qcom,mdss-dsi-panel-name = "samsung sofef00_m cmd 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_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 5>, <0 2>, <1 12>; + qcom,mdss-pan-physical-width-dimension = <68>; + qcom,mdss-pan-physical-height-dimension = <145>; + 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-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,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 08]; + //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-status-value-2 = <0xdc>; + 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-status-check-mode = "te_signal_check"; + 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,ulps-enabled; + 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-display-timings { + timing@0{ + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <2280>; + qcom,mdss-dsi-h-front-porch = <112>; + qcom,mdss-dsi-h-back-porch = <36>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <12>; + qcom,mdss-dsi-v-front-porch = <36>; + 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 = <0x8 0xa>; + qcom,mdss-dsi-on-command = [ + 05 01 00 00 0A 00 02 11 00 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 35 00 + 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 07 + 15 01 00 00 00 00 02 B6 12 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 53 20 + 15 01 00 00 00 00 02 55 00 + 05 01 00 00 00 00 02 29 00 + ]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 28 00 02 28 00 + 05 01 00 00 A0 00 02 10 00 + ]; + qcom,mdss-dsi-seed-command = [ + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 03 E2 00 41 + 29 01 00 00 00 00 02 B0 2C + 29 01 00 00 00 00 14 E2 B4 02 04 05 FF 02 00 00 FF 00 FF FF F0 E0 E1 18 FF F3 F8 + 29 01 00 00 00 00 03 F0 A5 A5 + ]; + + qcom,mdss-dsi-panel-command = [ + 29 01 00 00 00 00 03 F0 5A 5A + 29 01 00 00 00 00 03 E2 00 41 + 29 01 00 00 00 00 02 B0 2C + 29 01 00 00 00 00 14 E2 B4 02 04 05 FF 02 00 00 FF 00 FF FF F0 E0 E1 18 FF F3 F8 + 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-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-panel-acl-command = [15 01 00 00 00 00 02 55 00]; + qcom,mdss-dsi-acl-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-panel-hbm-on-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 40 00 02 53 E8 + 39 01 00 00 10 00 03 B2 02 D4 + 15 01 00 00 00 00 02 F7 03 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-hbm-on-command-2 = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 40 00 02 53 E8 + 39 01 00 00 10 00 03 B2 02 3C + 15 01 00 00 00 00 02 F7 03 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-hbm-on-command-3 = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 40 00 02 53 E8 + 39 01 00 00 10 00 03 B2 01 9C + 15 01 00 00 00 00 02 F7 03 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-hbm-on-command-4 = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 40 00 02 53 E8 + 39 01 00 00 10 00 03 B2 00 F0 + 15 01 00 00 00 00 02 F7 03 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-hbm-on-command-5 = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 40 00 02 53 E8 + 39 01 00 00 10 00 03 B2 00 40 + 15 01 00 00 00 00 02 F7 03 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-hbm-off-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 53 28 + 15 01 00 00 00 00 02 F7 03 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-hbm-max-brightness-command-on = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 40 00 02 53 E8 + 39 01 00 00 10 00 03 B2 00 40 + 15 01 00 00 00 00 02 F7 03 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-hbm-max-brightness-command-off = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 53 28 + 15 01 00 00 00 00 02 F7 03 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-hbm-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-hbm-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-hbm-max-brightness-command-on-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-hbm-max-brightness-command-off-state = "dsi_lp_mode"; + 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-off-command = [ + ]; + qcom,mdss-dsi-panel-aod-mode-command-1 = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 53 23 + 05 01 00 00 01 00 02 39 00 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-aod-mode-command-2 = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 53 22 + 05 01 00 00 01 00 02 39 00 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-aod-mode-command-3 = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 53 23 + 05 01 00 00 01 00 02 38 00 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-aod-mode-command-4 = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 53 22 + 05 01 00 00 01 00 02 38 00 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-aod-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-aod-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-aod-mode-command-state = "dsi_lp_mode"; + + qcom,mdss-dsi-panel-serial-num-command = [ + 06 01 00 00 00 00 01 A1 + ]; + qcom,mdss-dsi-panel-serial-num-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-display-srgb-color-mode-on-command = [ + 39 01 00 00 00 00 03 f0 5A 5A + 39 01 00 00 00 00 03 E2 00 85 + 39 01 00 00 00 00 02 B0 2C + 39 01 00 00 00 00 16 E2 CE 01 02 1D E3 00 07 0D E9 28 FD F0 D3 0A E2 EA EA 01 FF FF F2 + 39 01 00 00 00 00 02 b0 49 + 39 01 00 00 00 00 02 E2 00 + 39 01 00 00 00 00 02 b0 4A + 39 01 00 00 00 00 02 E2 00 + 39 01 00 00 00 00 02 b0 4B + 39 01 00 00 00 00 02 E2 00 + 39 01 00 00 00 00 02 b0 4C + 39 01 00 00 00 00 02 E2 00 + 39 01 00 00 00 00 02 b0 4D + 39 01 00 00 00 00 02 E2 00 + 39 01 00 00 00 00 03 f0 A5 A5 + ]; + qcom,mdss-dsi-panel-display-p3-mode-on-command = [ + 39 01 00 00 00 00 03 f0 5A 5A + 39 01 00 00 00 00 03 E2 00 85 + 39 01 00 00 00 00 02 B0 2C + 39 01 00 00 00 00 16 E2 CE 01 02 1D E3 00 07 0D E9 28 FD F0 D3 0A E2 EA EA 01 FF FF F2 + 39 01 00 00 00 00 02 b0 49 + 39 01 00 00 00 00 02 E2 00 + 39 01 00 00 00 00 02 b0 4A + 39 01 00 00 00 00 02 E2 00 + 39 01 00 00 00 00 02 b0 4B + 39 01 00 00 00 00 02 E2 00 + 39 01 00 00 00 00 02 b0 4C + 39 01 00 00 00 00 02 E2 00 + 39 01 00 00 00 00 02 b0 4D + 39 01 00 00 00 00 02 E2 00 + 39 01 00 00 00 00 03 f0 A5 A5 + ]; + qcom,mdss-dsi-panel-display-wide-color-mode-on-command = [ + 39 01 00 00 00 00 03 f0 5A 5A + 39 01 00 00 00 00 03 E2 00 85 + 39 01 00 00 00 00 02 B0 2C + 39 01 00 00 00 00 16 E2 FF 00 00 00 FF 00 00 00 FF 00 FF FF FF 00 FF FF FF 00 FF FF FF + 39 01 00 00 00 00 02 b0 49 + 39 01 00 00 00 00 02 E2 00 + 39 01 00 00 00 00 02 b0 4A + 39 01 00 00 00 00 02 E2 00 + 39 01 00 00 00 00 02 b0 4B + 39 01 00 00 00 00 02 E2 00 + 39 01 00 00 00 00 02 b0 4C + 39 01 00 00 00 00 02 E2 00 + 39 01 00 00 00 00 02 b0 4D + 39 01 00 00 00 00 02 E2 00 + 39 01 00 00 00 00 03 f0 A5 A5 + ]; + qcom,mdss-dsi-panel-dci-p3-off-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 39 01 00 00 00 00 03 E2 00 40 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-customer-srgb-enable-command = [ + 39 01 00 00 00 00 03 f0 5A 5A + 39 01 00 00 00 00 03 E2 00 85 + 39 01 00 00 00 00 02 B0 2C + 39 01 00 00 00 00 16 E2 CE 01 02 1D E3 00 07 0D E9 28 FD F0 D3 0A E2 EA EA 01 FF FF F2 + 39 01 00 00 00 00 02 b0 49 + 39 01 00 00 00 00 02 E2 00 + 39 01 00 00 00 00 02 b0 4A + 39 01 00 00 00 00 02 E2 00 + 39 01 00 00 00 00 02 b0 4B + 39 01 00 00 00 00 02 E2 00 + 39 01 00 00 00 00 02 b0 4C + 39 01 00 00 00 00 02 E2 00 + 39 01 00 00 00 00 02 b0 4D + 39 01 00 00 00 00 02 E2 00 + 39 01 00 00 00 00 03 f0 A5 A5 + ]; + qcom,mdss-dsi-customer-p3-enable-command = [ + 39 01 00 00 00 00 03 f0 5A 5A + 39 01 00 00 00 00 03 E2 00 85 + 39 01 00 00 00 00 02 B0 2C + 39 01 00 00 00 00 16 E2 FF 00 00 00 FF 00 00 00 FF 00 FF FF FF 00 FF FF FF 00 FF FF F2 + 39 01 00 00 00 00 02 b0 49 + 39 01 00 00 00 00 02 E2 00 + 39 01 00 00 00 00 02 b0 4A + 39 01 00 00 00 00 02 E2 00 + 39 01 00 00 00 00 02 b0 4B + 39 01 00 00 00 00 02 E2 00 + 39 01 00 00 00 00 02 b0 4C + 39 01 00 00 00 00 02 E2 00 + 39 01 00 00 00 00 02 b0 4D + 39 01 00 00 00 00 02 E2 00 + 39 01 00 00 00 00 03 f0 A5 A5 + ]; + qcom,mdss-dsi-customer-p3-enable-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-customer-srgb-enable-command-state = "dsi_lp_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-status-command = + [06 01 00 01 05 00 02 0a 08]; + qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; + + qcom,mdss-dsi-panel-id-command = [06 01 00 01 05 00 02 dc 08]; + qcom,mdss-dsi-panel-id-command-state = "dsi_lp_mode"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-samsung_sofef00_m_video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-samsung_sofef00_m_video.dtsi new file mode 100644 index 000000000000..128043c1eed7 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dsi-panel-samsung_sofef00_m_video.dtsi @@ -0,0 +1,76 @@ +/* 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,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 5>, <0 2>, <1 12>; + qcom,mdss-pan-physical-width-dimension = <68>; + qcom,mdss-pan-physical-height-dimension = <145>; + 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-lp11-init; + qcom,mdss-dsi-high-brightness-panel; + qcom,mdss-bl-high2bit; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <2280>; + qcom,mdss-dsi-h-front-porch = <112>; + qcom,mdss-dsi-h-back-porch = <36>; + qcom,mdss-dsi-h-pulse-width = <16>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <12>; + qcom,mdss-dsi-v-front-porch = <36>; + 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-on-command = [ + 05 01 00 00 0A 00 02 11 00 + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 35 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 00 00 02 53 20 + 15 01 00 00 00 00 02 55 00 + ]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 28 00 02 28 00 + 05 01 00 00 A0 00 02 10 00 + ]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/enchilada-dvt-backup.dtsi b/arch/arm64/boot/dts/qcom/enchilada-dvt-backup.dtsi new file mode 100644 index 000000000000..56cfdde49805 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/enchilada-dvt-backup.dtsi @@ -0,0 +1,23 @@ +/* Copyright (c) 2016-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. + */ +/*don't suggest add to this file, this file is only for different hw*/ +#include "enchilada-dvt.dtsi" +&vendor { + +}; + +&soc { +}; + +&dsi_samsung_sofef00_m_cmd { + qcom,mdss-panel-mismatch-check; +}; diff --git a/arch/arm64/boot/dts/qcom/enchilada-dvt-usb30.dtsi b/arch/arm64/boot/dts/qcom/enchilada-dvt-usb30.dtsi new file mode 100644 index 000000000000..a733457224be --- /dev/null +++ b/arch/arm64/boot/dts/qcom/enchilada-dvt-usb30.dtsi @@ -0,0 +1,62 @@ +/* Copyright (c) 2016-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. + */ +/*don't suggest add to this file, this file is only for different hw*/ +#include "enchilada-dvt.dtsi" +&vendor { + +}; + +&soc { +}; + +&dsi_samsung_sofef00_m_cmd { + qcom,mdss-panel-mismatch-check; +}; + +&sde_dp{ + status = "okay"; +}; + +&sde_dp { + qcom,aux-en-gpio = <&tlmm 122 0>; + qcom,aux-sel-gpio = <&tlmm 123 0>; + qcom,usbplug-cc-gpio = <&tlmm 38 0>; +}; + +&mdss_mdp { + connectors = <&sde_rscc &sde_wb &sde_dp>; +}; + +&sde_dp_aux_active { + mux { + pins = "gpio122", "gpio123"; + function = "gpio"; + }; + + config { + pins = "gpio122", "gpio123"; + bias-disable = <0>; /* no pull */ + drive-strength = <8>; + }; +}; + +&usb0 { + dwc3@a600000 { + op,enable_super_speed; + }; +}; + +&usb1 { + dwc3@a800000 { + op,enable_super_speed; + }; +}; \ No newline at end of file diff --git a/arch/arm64/boot/dts/qcom/enchilada-dvt-v2.1-backup-overlay.dts b/arch/arm64/boot/dts/qcom/enchilada-dvt-v2.1-backup-overlay.dts new file mode 100644 index 000000000000..61dc5a429443 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/enchilada-dvt-v2.1-backup-overlay.dts @@ -0,0 +1,33 @@ +/* Copyright (c) 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. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-mtp.dtsi" +#include "sdm845-audio-overlay.dtsi" +#include "enchilada.dtsi" +#include "enchilada-dvt-backup.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM845 v2.1 MTP DVT-BACKUP"; + compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp"; + qcom,msm-id = <321 0x20001>; + qcom,board-id = <8 0 17819 25>; +}; diff --git a/arch/arm64/boot/dts/qcom/enchilada-dvt-v2.1-overlay.dts b/arch/arm64/boot/dts/qcom/enchilada-dvt-v2.1-overlay.dts new file mode 100644 index 000000000000..9ace8d33934d --- /dev/null +++ b/arch/arm64/boot/dts/qcom/enchilada-dvt-v2.1-overlay.dts @@ -0,0 +1,33 @@ +/* Copyright (c) 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. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-mtp.dtsi" +#include "sdm845-audio-overlay.dtsi" +#include "enchilada.dtsi" +#include "enchilada-dvt.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM845 v2.1 MTP DVT"; + compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp"; + qcom,msm-id = <321 0x20001>; + qcom,board-id = <8 0 17819 21>; +}; diff --git a/arch/arm64/boot/dts/qcom/enchilada-dvt-v2.1-usb30-overlay.dts b/arch/arm64/boot/dts/qcom/enchilada-dvt-v2.1-usb30-overlay.dts new file mode 100644 index 000000000000..d65ff283c422 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/enchilada-dvt-v2.1-usb30-overlay.dts @@ -0,0 +1,33 @@ +/* Copyright (c) 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. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-mtp.dtsi" +#include "sdm845-audio-overlay.dtsi" +#include "enchilada.dtsi" +#include "enchilada-dvt-usb30.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM845 v2.1 MTP DVTUSB30"; + compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp"; + qcom,msm-id = <321 0x20001>; + qcom,board-id = <8 0 17819 55>; +}; diff --git a/arch/arm64/boot/dts/qcom/enchilada-dvt.dtsi b/arch/arm64/boot/dts/qcom/enchilada-dvt.dtsi new file mode 100644 index 000000000000..282d9020ccf8 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/enchilada-dvt.dtsi @@ -0,0 +1,23 @@ +/* Copyright (c) 2016-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. + */ +/*don't suggest add to this file, this file is only for different hw*/ +#include "enchilada-evt2.dtsi" +&vendor { + +}; + +&soc { +}; + +&dsi_samsung_sofef00_m_cmd { + qcom,mdss-panel-mismatch-check; +}; diff --git a/arch/arm64/boot/dts/qcom/enchilada-evt2.dtsi b/arch/arm64/boot/dts/qcom/enchilada-evt2.dtsi new file mode 100644 index 000000000000..d024de261349 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/enchilada-evt2.dtsi @@ -0,0 +1,144 @@ +/* Copyright (c) 2016-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. + */ +/*don't suggest add to this file, this file is only for different hw*/ +&vendor { + +}; + +&soc { + +}; + + +&tlmm { + oem_rf_cable_mux { + oem_rf_cable_active: oem_rf_cable_active { + mux { + pins = "gpio32","gpio86"; + function = "gpio"; + }; + config { + pins = "gpio32","gpio86"; + drive-strength = <2>; + bias-disable; + }; + }; + oem_rf_cable_suspend: oem_rf_cable_suspend { + mux { + pins = "gpio32","gpio86"; + function = "gpio"; + }; + config { + pins = "gpio32","gpio86"; + drive-strength = <2>; + bias-disable; + }; + }; + }; +}; + +&soc { + oem_rf_cable { + compatible = "oem,rf_cable"; + interrupt-parent = <&tlmm>; + rf,cable-gpio-0 = <&tlmm 32 0>; + rf,cable-gpio-1 = <&tlmm 86 0>; + pinctrl-names = "oem_rf_cable_active", "oem_rf_cable_suspend"; + pinctrl-0 = <&oem_rf_cable_active >; + pinctrl-1 = <&oem_rf_cable_suspend >; + }; +}; + + +&qupv3_se3_i2c { + status = "ok"; + nq@28 { + qcom,nq-firm = <&tlmm 62 0x00>; + }; +}; + +&tlmm { + cam_sensor_rear_0_vaf_active: cam_sensor_rear_0_vaf_active { + /* ACTUATOR POWER */ + mux { + pins = "gpio31"; + function = "gpio"; + }; + + config { + pins = "gpio31"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_0_vaf_suspend: cam_sensor_rear_0_vaf_suspend { + /* ACTUATOR POWER */ + mux { + pins = "gpio31"; + function = "gpio"; + }; + + config { + pins = "gpio31"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; +}; + +&soc{ + rear_0_actuator_regulator: gpio-regulator@0 { + compatible = "regulator-fixed"; + reg = <0x00 0x00>; + regulator-name = "actuator_regulator"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-enable-ramp-delay = <100>; + enable-active-high; + gpio = <&tlmm 31 0>; + vin-supply = <&pmi8998_bob>; + }; +}; + +&actuator_rear_0{ + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,actuator"; + cci-master = <0>; + cam_vaf-supply = <&rear_0_actuator_regulator>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; +}; + +&ois_rear_0{ + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,ois"; + cam_vaf-supply = <&pm8998_l21>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2850000>; + rgltr-max-voltage = <2850000>; + rgltr-load-current = <500000>; + gpio-no-mux = <0>; + gpios = <&tlmm 40 0>; + gpio-vaf = <0>; + gpio-req-tbl-num = <0>; + gpio-req-tbl-flags = <0>; + gpio-req-tbl-label = "CAM_OIS_PWD_0"; + cci-master = <0>; + status = "ok"; +}; diff --git a/arch/arm64/boot/dts/qcom/enchilada-mp-v2.1-overlay.dts b/arch/arm64/boot/dts/qcom/enchilada-mp-v2.1-overlay.dts new file mode 100644 index 000000000000..a80230ad5a0f --- /dev/null +++ b/arch/arm64/boot/dts/qcom/enchilada-mp-v2.1-overlay.dts @@ -0,0 +1,33 @@ +/* Copyright (c) 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. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-mtp.dtsi" +#include "sdm845-audio-overlay.dtsi" +#include "enchilada.dtsi" +#include "enchilada-mp.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM845 v2.1 MTP MP"; + compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp"; + qcom,msm-id = <321 0x20001>; + qcom,board-id = <8 0 17819 23>; +}; diff --git a/arch/arm64/boot/dts/qcom/enchilada-mp.dtsi b/arch/arm64/boot/dts/qcom/enchilada-mp.dtsi new file mode 100644 index 000000000000..936081d968c6 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/enchilada-mp.dtsi @@ -0,0 +1,23 @@ +/* Copyright (c) 2016-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. + */ +/*don't suggest add to this file, this file is only for different hw*/ +&vendor { + +}; + +&soc { + +}; + +&dsi_samsung_sofef00_m_cmd { + qcom,mdss-panel-mismatch-check; +}; diff --git a/arch/arm64/boot/dts/qcom/enchilada-pvt-backup.dtsi b/arch/arm64/boot/dts/qcom/enchilada-pvt-backup.dtsi new file mode 100644 index 000000000000..b8c1573eb5f0 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/enchilada-pvt-backup.dtsi @@ -0,0 +1,55 @@ +/* Copyright (c) 2016-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. + */ +/*don't suggest add to this file, this file is only for different hw*/ +#include "enchilada-pvt.dtsi" +&vendor { + +}; + +&soc { + +}; + +&qupv3_se10_i2c { + oneplus_fastchg@26{ + status = "disable"; + }; + + oneplus_fastchg@52{ + status = "ok"; + compatible = "microchip,oneplus_fastchg"; + reg = <0x52>; + microchip,mcu-en-gpio = <&tlmm 102 0x00>; + microchip,usb-sw-1-gpio = <&tlmm 37 0x00>; + microchip,usb-sw-2-gpio = <&tlmm 51 0x00>; + microchip,ap-clk = <&tlmm 43 0x00>; + microchip,ap-data = <&tlmm 44 0x00>; + op,fw-erase-count = <959>; + op,fw-addr-low = <0>; + op,fw-addr-high = <0>; + op,n76e_support; + + pinctrl-names = "mux_fastchg_active", + "mux_fastchg_suspend", + "mcu_data_active", + "mcu_data_suspend"; + pinctrl-0 = <&fastchg_active + &usb_sw_active + &ap_clk_active >; + pinctrl-1 = <&usb_sw_suspend + &fastchg_suspend + &ap_clk_suspend>; + pinctrl-2 =<&ap_data_active>; + pinctrl-3 =<&ap_data_suspend>; + }; +}; + diff --git a/arch/arm64/boot/dts/qcom/enchilada-pvt-v2.1-backup-overlay.dts b/arch/arm64/boot/dts/qcom/enchilada-pvt-v2.1-backup-overlay.dts new file mode 100644 index 000000000000..65511f6c1f88 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/enchilada-pvt-v2.1-backup-overlay.dts @@ -0,0 +1,33 @@ +/* Copyright (c) 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. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-mtp.dtsi" +#include "sdm845-audio-overlay.dtsi" +#include "enchilada.dtsi" +#include "enchilada-pvt-backup.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM845 v2.1 MTP PVT-MCU-BACK"; + compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp"; + qcom,msm-id = <321 0x20001>; + qcom,board-id = <8 0 17819 24>; +}; diff --git a/arch/arm64/boot/dts/qcom/enchilada-pvt-v2.1-overlay.dts b/arch/arm64/boot/dts/qcom/enchilada-pvt-v2.1-overlay.dts new file mode 100644 index 000000000000..57673c63df73 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/enchilada-pvt-v2.1-overlay.dts @@ -0,0 +1,33 @@ +/* Copyright (c) 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. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-mtp.dtsi" +#include "sdm845-audio-overlay.dtsi" +#include "enchilada.dtsi" +#include "enchilada-pvt.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM845 v2.1 MTP PVT"; + compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp"; + qcom,msm-id = <321 0x20001>; + qcom,board-id = <8 0 17819 22>; +}; diff --git a/arch/arm64/boot/dts/qcom/enchilada-pvt.dtsi b/arch/arm64/boot/dts/qcom/enchilada-pvt.dtsi new file mode 100644 index 000000000000..1201436447fa --- /dev/null +++ b/arch/arm64/boot/dts/qcom/enchilada-pvt.dtsi @@ -0,0 +1,24 @@ +/* Copyright (c) 2016-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. + */ +/*don't suggest add to this file, this file is only for different hw*/ +#include "enchilada-dvt.dtsi" +&vendor { + +}; + +&soc { + +}; + +&dsi_samsung_sofef00_m_cmd { + qcom,mdss-panel-mismatch-check; +}; diff --git a/arch/arm64/boot/dts/qcom/enchilada-t0.dtsi b/arch/arm64/boot/dts/qcom/enchilada-t0.dtsi new file mode 100644 index 000000000000..6f1361236f0f --- /dev/null +++ b/arch/arm64/boot/dts/qcom/enchilada-t0.dtsi @@ -0,0 +1,122 @@ +/* Copyright (c) 2016-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. + */ +/*don't suggest add to this file, this file is only for different hw*/ +&vendor { + +}; + +&soc { + +}; + +&tlmm { + oem_rf_cable_mux { + oem_rf_cable_active: oem_rf_cable_active { + mux { + pins = "gpio32","gpio86"; + function = "gpio"; + }; + config { + pins = "gpio32","gpio86"; + drive-strength = <2>; + bias-disable; + }; + }; + oem_rf_cable_suspend: oem_rf_cable_suspend { + mux { + pins = "gpio32","gpio86"; + function = "gpio"; + }; + config { + pins = "gpio32","gpio86"; + drive-strength = <2>; + bias-disable; + }; + }; + }; +}; + +&soc { + oem_rf_cable { + compatible = "oem,rf_cable"; + interrupt-parent = <&tlmm>; + rf,cable-gpio-0 = <&tlmm 32 0>; + rf,cable-gpio-1 = <&tlmm 86 0>; + pinctrl-names = "oem_rf_cable_active", "oem_rf_cable_suspend"; + pinctrl-0 = <&oem_rf_cable_active>; + pinctrl-1 = <&oem_rf_cable_suspend>; + }; +}; + +&qupv3_se3_i2c { + status = "ok"; + nq@28 { + qcom,nq-firm = <&tlmm 62 0x00>; + }; +}; + +&tlmm { + cam_sensor_rear_0_vaf_active: cam_sensor_rear_0_vaf_active { + /* ACTUATOR POWER */ + mux { + pins = "gpio31"; + function = "gpio"; + }; + + config { + pins = "gpio31"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_0_vaf_suspend: cam_sensor_rear_0_vaf_suspend { + /* ACTUATOR POWER */ + mux { + pins = "gpio31"; + function = "gpio"; + }; + + config { + pins = "gpio31"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; +}; + +&soc{ + rear_0_actuator_regulator: gpio-regulator@0 { + compatible = "regulator-fixed"; + reg = <0x00 0x00>; + regulator-name = "actuator_regulator"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-enable-ramp-delay = <100>; + enable-active-high; + gpio = <&tlmm 31 0>; + vin-supply = <&pmi8998_bob>; + }; +}; + +&actuator_rear_0{ + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,actuator"; + cci-master = <0>; + cam_vaf-supply = <&rear_0_actuator_regulator>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; +}; diff --git a/arch/arm64/boot/dts/qcom/enchilada.dtsi b/arch/arm64/boot/dts/qcom/enchilada.dtsi new file mode 100644 index 000000000000..4593fbd0dc8a --- /dev/null +++ b/arch/arm64/boot/dts/qcom/enchilada.dtsi @@ -0,0 +1,2111 @@ +/* Copyright (c) 2016-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. + */ +/*recommand add our code to this dtsi*/ +#include "dsi-panel-samsung_s6e3fc1_cmd.dtsi" +#include "dsi-panel-samsung_sofef00_m_cmd.dtsi" +#include "dsi-panel-samsung_sofef00_m_video.dtsi" +#include "dsi-panel-samsung_sefeg01_s_cmd.dtsi" +#include "dsi-panel-samsung_s6e3fc2x01.dtsi" +#include "dsi-panel-samsung_dsc.dtsi" + +/{ +reserved-memory { + +}; +}; + +&vendor { + +}; + +&wdog{ + qcom,bark-time = <15000>; +}; + +&snd_934x { + qcom,audio-routing = + "AIF4 VI", "MCLK", + "RX_BIAS", "MCLK", + "MADINPUT", "MCLK", + "hifi amp", "LINEOUT1", + "hifi amp", "LINEOUT2", + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Headset Mic", + "AMIC3", "MIC BIAS4", + "MIC BIAS4", "ANCRight Headset Mic", + "AMIC4", "MIC BIAS1", + "MIC BIAS1", "ANCLeft Headset Mic", + "AMIC5", "MIC BIAS4", + "MIC BIAS4", "Handset Mic", + "DMIC0", "MIC BIAS1", + "MIC BIAS1", "Digital Mic0", + "DMIC1", "MIC BIAS1", + "MIC BIAS1", "Digital Mic1", + "DMIC2", "MIC BIAS3", + "MIC BIAS3", "Digital Mic2", + "DMIC3", "MIC BIAS3", + "MIC BIAS3", "Digital Mic3", + "DMIC4", "MIC BIAS4", + "MIC BIAS4", "Digital Mic4", + "DMIC5", "MIC BIAS4", + "MIC BIAS4", "Digital Mic5", + "SpkrLeft IN", "SPK1 OUT", + "SpkrRight IN", "SPK2 OUT"; +}; + +&wcd934x_cdc { + qcom,cdc-micbias2-mv = <2700>; +}; + +&soc { + + gpio_keys { + hallsensor_key { + label = "hallsensor_key"; + gpios = <&tlmm 124 1>; + interrupt-parent = <&tlmm>; + interrupts = <124 0x0>; + linux,input-type = <5>; + linux,code = <0>; + gpio-key,wakeup; + debounce-interval = <15>; + }; + }; + + + qcom,qbt1000 { + status = "disabled"; + }; + + fingerprint_detect { + compatible = "oneplus,fpdetect"; + fp-gpio-id0 = <&tlmm 91 0>; + fp-gpio-id1 = <&tlmm 92 0>; + fp-gpio-id2 = <&tlmm 95 0>; + pinctrl-names = "fp_id_init", "fp_id_up", "fp_id_down"; + pinctrl-0 = <&fp_id_init>; + pinctrl-1 = <&fp_id0_up &fp_id1_up &fp_id2_up>; + pinctrl-2 = <&fp_id0_down &fp_id1_down &fp_id2_down>; + oem,enchilada; + }; + + fpc_fpc1020 { + compatible = "fpc,fpc1020"; + interrupt-parent = <&tlmm>; + fpc,irq-gpio = <&tlmm 121 0>; + fpc,reset-gpio = <&tlmm 35 0>; + pinctrl-names = "fp_reset_high", "fp_reset_low"; + pinctrl-0 = <&fp_reset_high>; + pinctrl-1 = <&fp_reset_low>; + }; + + goodix_fp { + compatible = "goodix,fingerprint"; + interrupt-parent = <&tlmm>; + fp-gpio-irq = <&tlmm 121 0x00>; + fp-gpio-reset = <&tlmm 35 0x00>; + fp-gpio-enable = <&tlmm 80 0x00>; + pinctrl-names = "fp_en_init", "fp_dis_init"; + pinctrl-0 = <&goodixfp_enable_init &goodixfp_irq_init>; + pinctrl-1 = <&goodixfp_disable_init>; + oem,enchilada; + status = "okay"; + }; + + //add tri_state_key support + tri_state_key { + compatible = "oneplus,tri-state-key"; + status = "okay"; + interrupt-parent = <&tlmm>; + tristate,gpio_key1 = <&tlmm 24 0x00>; + tristate,gpio_key2 = <&tlmm 52 0x00>; + tristate,gpio_key3 = <&tlmm 126 0x00>; + pinctrl-names = + "pmx_tri_state_key_active", "pmx_tri_state_key_suspend"; + pinctrl-0 = <&tri_state_key_active>; + pinctrl-1 = <&tri_state_key_suspend>; + }; + + dsi_panel_pwr_supply_no_labibb_2: dsi_panel_pwr_supply_no_labibb_2 { + #address-cells = <1>; + #size-cells = <0>; + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1850000>; + qcom,supply-max-voltage = <1850000>; + qcom,supply-enable-load = <62000>; + qcom,supply-disable-load = <80>; + qcom,supply-post-on-sleep = <0>; + }; + }; + + dsi_samsung_s6e3fc1_cmd_display: qcom,dsi-display@17 { + compatible = "qcom,dsi-display"; + label = "dsi_samsung_s6e3fc1_cmd_display"; + qcom,display-type = "primary"; + qcom,dsi-ctrl = <&mdss_dsi0>; + qcom,dsi-phy = <&mdss_dsi_phy0>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "mux_byte_clk", "mux_pixel_clk"; + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active &esd_check_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend &esd_check_suspend>; + qcom,dsi-panel = <&dsi_samsung_s6e3fc1_cmd>; + vddio-supply = <&pm8998_l14>; + qcom,platform-te-gpio = <&tlmm 30 0>; + }; + + dsi_samsung_sofef00_m_cmd_display: qcom,dsi-display@18 { + compatible = "qcom,dsi-display"; + label = "dsi_samsung_sofef00_m_cmd_display"; + qcom,display-type = "primary"; + qcom,dsi-ctrl = <&mdss_dsi0>; + qcom,dsi-phy = <&mdss_dsi_phy0>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "mux_byte_clk", "mux_pixel_clk"; + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active &esd_check_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend &esd_check_suspend>; + qcom,dsi-panel = <&dsi_samsung_sofef00_m_cmd>; + vddio-supply = <&pm8998_l14>; + qcom,platform-te-gpio = <&tlmm 30 0>; + }; + + dsi_samsung_sofef00_m_video_display: qcom,dsi-display@19 { + compatible = "qcom,dsi-display"; + label = "dsi_samsung_sofef00_m_video_display"; + qcom,display-type = "primary"; + qcom,dsi-ctrl = <&mdss_dsi0>; + qcom,dsi-phy = <&mdss_dsi_phy0>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "mux_byte_clk", "mux_pixel_clk"; + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active &esd_check_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend &esd_check_suspend>; + qcom,dsi-panel = <&dsi_samsung_sofef00_m_video>; + vddio-supply = <&pm8998_l14>; + qcom,platform-te-gpio = <&tlmm 30 0>; + }; + +dsi_samsung_sofeg01_s_cmd_display: qcom,dsi-display@20 { + compatible = "qcom,dsi-display"; + label = "dsi_samsung_sofeg01_s_cmd_display"; + qcom,display-type = "primary"; + qcom,dsi-ctrl = <&mdss_dsi0>; + qcom,dsi-phy = <&mdss_dsi_phy0>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "mux_byte_clk", "mux_pixel_clk"; + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active &esd_check_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend &esd_check_suspend>; + qcom,dsi-panel = <&dsi_samsung_sofeg01_s_cmd>; + vddio-supply = <&pm8998_l14>; + qcom,platform-te-gpio = <&tlmm 30 0>; + }; +dsi_samsung_s6e3fc2x01_cmd_display: qcom,dsi-display@21 { + compatible = "qcom,dsi-display"; + label = "dsi_samsung_s6e3fc2x01_cmd_display"; + qcom,display-type = "primary"; + qcom,dsi-ctrl = <&mdss_dsi0>; + qcom,dsi-phy = <&mdss_dsi_phy0>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "mux_byte_clk", "mux_pixel_clk"; + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active &esd_check_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend &esd_check_suspend>; + qcom,dsi-panel = <&dsi_samsung_s6e3fc2x01_cmd>; + vddio-supply = <&pm8998_l14>; + qcom,platform-te-gpio = <&tlmm 30 0>; + }; + +dsi_samsung_dsc_cmd_display: qcom,dsi-display@22 { + compatible = "qcom,dsi-display"; + label = "dsi_samsung_dsc_cmd_display"; + qcom,display-type = "primary"; + qcom,dsi-ctrl = <&mdss_dsi0>; + qcom,dsi-phy = <&mdss_dsi_phy0>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "mux_byte_clk", "mux_pixel_clk"; + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active &esd_check_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend &esd_check_suspend>; + qcom,dsi-panel = <&dsi_samsung_dsc_cmd>; + vddio-supply = <&pm8998_l14>; + qcom,platform-te-gpio = <&tlmm 30 0>; + }; + + + oem_serial_pinctrl { + compatible = "oem,oem_serial_pinctrl"; + pinctrl-names = "uart_pinctrl_active","uart_pinctrl_deactive"; + pinctrl-0 = <&qupv3_se9_2uart_active>; + pinctrl-1 = <&qupv3_se9_2uart_oem_sleep>; + + }; + +}; + +&tlmm { + qupv3_se9_2uart_oem_sleep: qupv3_se9_2uart_oem_sleep { + mux { + pins = "gpio4", "gpio5"; + function = "gpio"; + }; + config { + pins = "gpio4", "gpio5"; + drive-strength = <2>; + bias-pull-down; + }; + }; + +}; + +&qupv3_se9_2uart { + compatible = "qcom,msm-geni-console-oem"; +}; + + +&tlmm{ + config { + pins = "gpio37"; + drive-strength = <2>; + bias-pull-up; + }; +}; +&soc { + gpio_keys { + vol_up { + /delete-property/ gpio-key,wakeup; + }; + vol_down { + label = "volume_down"; + gpios = <&pm8998_gpios 5 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = <114>; + debounce-interval = <15>; + linux,can-disable; + }; + //disable cam_snapshot,and cam_focus + cam_snapshot { + status = "disabled"; + }; + cam_focus { + status = "disabled"; + }; +}; + +}; + +&pm8998_gpios { + key_vol_down { + key_vol_down_default: key_vol_down_default { + pins = "gpio5"; + function = "normal"; + input-enable; + bias-pull-up; + power-source = <0>; + }; + }; +}; + +//add for volume down function ,and we do not use qbt1000 fingerprint sensor. +&soc{ + qcom,qbt1000 { + compatible = "qcom,qbt1000"; + clock-names = "core", "iface"; + clock-frequency = <25000000>; + qcom,ipc-gpio = <&tlmm 121 0>; + qcom,finger-detect-gpio = <&pm8998_gpios 5 0>; + status = "disabled"; + }; + +}; + + +&qupv3_se12_i2c { + status = "ok"; + synaptics-rmi-ts@20 { + compatible = "HWK,synaptics,s3320"; + reg = <0x20>; + interrupt-parent = <&tlmm>; + interrupts = <125 0x2008>; + //vcc_i2c_1v8-supply = <&pm8998_l6>; + vdd_2v8-supply = <&pm8998_l28>; + synaptics,tx-rx-num = <15 30>; + //synaptics,vdd-voltage = <1808000 1808000>; + synaptics,avdd-voltage = <3008000 3008000>; + //synaptics,vdd-current = <40000>; + synaptics,avdd-current = <20000>; + synaptics,display-coords = <1080 2160>; + synaptics,panel-coords = <1080 2160>; + synaptics,reset-gpio = <&tlmm 99 0x00>; + synaptics,irq-gpio = <&tlmm 125 0x2008>; + synaptics,1v8-gpio = <&tlmm 88 0x00>; + oem,support_1080x2160_tp; + oem,support_hw_poweroff; + pinctrl-names = "pmx_ts_active", "pmx_ts_suspend"; + pinctrl-0 = <&ts_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + }; +}; + + +&wsa881x_0211{ +status = "disabled"; +}; + +&wsa881x_0212{ +status = "disabled"; +}; + +&wsa881x_0213{ +status = "disabled"; +}; + +&wsa881x_0214{ +status = "disabled"; +}; + +&dai_mi2s3 { + qcom,msm-mi2s-rx-lines = <2>; + qcom,msm-mi2s-tx-lines = <1>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&quat_mi2s_active + &quat_mi2s_sd0_active &quat_mi2s_sd1_active >; + pinctrl-1 = <&quat_mi2s_sleep + &quat_mi2s_sd0_sleep &quat_mi2s_sd1_sleep >; +}; + +&dsi_nt35597_truly_dsc_cmd_display { + /delete-property/qcom,dsi-display-active; +}; + +&mdss_dsi1 { +status = "disabled"; +}; + +&mdss_dsi0_pll { + qcom,ssc-frequency-hz = <33000>; +}; + +&dsi_samsung_s6e3fc1_cmd { + qcom,dsi-display-active; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_no_labibb_2>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-brightness-max-level = <1023>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,platform-vci-gpio = <&tlmm 26 0>; + qcom,platform-poc-gpio = <&tlmm 25 0>; +}; + +&dsi_samsung_s6e3fc1_cmd { + qcom,mdss-dsi-t-clk-post = <0x0E>; + qcom,mdss-dsi-t-clk-pre = <0x34>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 21 09 09 25 23 09 + 09 06 03 04 00]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_samsung_sofef00_m_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_no_labibb_2>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-brightness-max-level = <1023>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,platform-vci-gpio = <&tlmm 26 0>; + qcom,platform-poc-gpio = <&tlmm 25 0>; +}; + +&dsi_samsung_sofef00_m_cmd { + qcom,mdss-dsi-t-clk-post = <0x0E>; + qcom,mdss-dsi-t-clk-pre = <0x36>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 23 09 09 26 24 09 + 09 06 03 04 00]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_samsung_sofef00_m_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_no_labibb_2>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-brightness-max-level = <1023>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,platform-vci-gpio = <&tlmm 26 0>; + qcom,platform-poc-gpio = <&tlmm 25 0>; +}; + +&dsi_samsung_sofef00_m_video { + qcom,mdss-dsi-t-clk-post = <0x0E>; + qcom,mdss-dsi-t-clk-pre = <0x36>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 23 09 09 26 24 09 + 09 06 03 04 00]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_samsung_sofeg01_s_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_no_labibb_2>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-brightness-max-level = <1023>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,platform-vci-gpio = <&tlmm 26 0>; + qcom,platform-poc-gpio = <&tlmm 25 0>; +}; + +&dsi_samsung_sofeg01_s_cmd { + qcom,mdss-dsi-t-clk-post = <0x0E>; + qcom,mdss-dsi-t-clk-pre = <0x36>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 23 09 09 26 24 09 + 09 06 03 04 00]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_samsung_s6e3fc2x01_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_no_labibb_2>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-brightness-max-level = <1023>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,platform-vci-gpio = <&tlmm 26 0>; + qcom,platform-poc-gpio = <&tlmm 25 0>; +}; + +&dsi_samsung_s6e3fc2x01_cmd { + qcom,mdss-dsi-t-clk-post = <0x0E>; + qcom,mdss-dsi-t-clk-pre = <0x35>; + qcom,mdss-dsi-panel-clockrate = <1037000000>;// 518.5MHZ + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 22 09 09 25 24 09 + 09 06 03 04 00]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; +}; +}; + + +&dsi_samsung_dsc_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_no_labibb_2>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-brightness-max-level = <1023>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,platform-vci-gpio = <&tlmm 26 0>; + qcom,platform-poc-gpio = <&tlmm 25 0>; +}; + +&dsi_samsung_dsc_cmd { + qcom,mdss-dsi-t-clk-post = <0x0E>; + qcom,mdss-dsi-t-clk-pre = <0x35>; + //qcom,mdss-dsi-panel-clockrate = <1037000000>;// 518.5MHZ + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 14 05 05 1F 0A 05 + 05 03 03 04 00]; + qcom,display-topology = <1 1 1>, + <2 2 1>, /* dsc merge */ + <2 1 1>; /* 3d mux */ + qcom,default-topology-index = <1>; + }; + }; +}; + +&qupv3_se4_i2c { + status = "ok"; + max98927@3a { + compatible = "maxim,max98927L"; + reg = <0x3a>; + mono_stereo_mode = <0>; + maxim,98927-reset-gpio = <&tlmm 69 0>; + status = "ok"; + }; +}; + +/* modify 0x240:0x45->0x46, 0x244:0x29->0x2b, 0x198:0x20->0x19*/ +/* add op host mode phy init parameters modify 0x198:0x20->0x20*/ +&qusb_phy0 { + qcom,overwrite-bias2-disable; + qcom,qusb-phy-init-seq = + /* */ + <0x23 0x210 /* PWR_CTRL1 */ + 0x03 0x04 /* PLL_ANALOG_CONTROLS_TWO */ + 0x7c 0x18c /* PLL_CLOCK_INVERTERS */ + 0x80 0x2c /* PLL_CMODE */ + 0x0a 0x184 /* PLL_LOCK_DELAY */ + 0x19 0xb4 /* PLL_DIGITAL_TIMERS_TWO */ + 0x40 0x194 /* PLL_BIAS_CONTROL_1 */ + 0x19 0x198 /* PLL_BIAS_CONTROL_2 */ + 0x21 0x214 /* PWR_CTRL2 */ + 0x07 0x220 /* IMP_CTRL1 */ + 0x58 0x224 /* IMP_CTRL2 */ + 0x46 0x240 /* TUNE1 */ + 0x2b 0x244 /* TUNE2 */ + 0xca 0x248 /* TUNE3 */ + 0x04 0x24c /* TUNE4 */ + 0x03 0x250 /* TUNE5 */ + 0x00 0x23c /* CHG_CTRL2 */ + 0x22 0x210>; /* PWR_CTRL1 */ + + qcom,qusb-phy-ophost-init-seq = + /* */ + <0x23 0x210 /* PWR_CTRL1 */ + 0x03 0x04 /* PLL_ANALOG_CONTROLS_TWO */ + 0x7c 0x18c /* PLL_CLOCK_INVERTERS */ + 0x80 0x2c /* PLL_CMODE */ + 0x0a 0x184 /* PLL_LOCK_DELAY */ + 0x19 0xb4 /* PLL_DIGITAL_TIMERS_TWO */ + 0x40 0x194 /* PLL_BIAS_CONTROL_1 */ + 0x20 0x198 /* PLL_BIAS_CONTROL_2 */ + 0x21 0x214 /* PWR_CTRL2 */ + 0x07 0x220 /* IMP_CTRL1 */ + 0x58 0x224 /* IMP_CTRL2 */ + 0x46 0x240 /* TUNE1 */ + 0x2b 0x244 /* TUNE2 */ + 0xca 0x248 /* TUNE3 */ + 0x04 0x24c /* TUNE4 */ + 0x03 0x250 /* TUNE5 */ + 0x00 0x23c /* CHG_CTRL2 */ + 0x22 0x210>; /* PWR_CTRL1 */ +}; + +&pmi8998_pdphy { + vbus-supply = <&smb2_vbus>; +}; + +&qupv3_se10_i2c { + qcom,clk-freq-out = <100000>; + bq27541-battery@55 { + status = "ok"; + compatible = "ti,bq27541-battery"; + reg = <0x55>; + qcom,modify-soc-smooth; + }; + + oneplus_fastchg@26{ + status = "ok"; + compatible = "microchip,oneplus_fastchg"; + reg = <0x26>; + microchip,mcu-en-gpio = <&tlmm 102 0x00>; + microchip,usb-sw-1-gpio = <&tlmm 37 0x00>; + microchip,usb-sw-2-gpio = <&tlmm 51 0x00>; + microchip,ap-clk = <&tlmm 43 0x00>; + microchip,ap-data = <&tlmm 44 0x00>; + + pinctrl-names = "mux_fastchg_active", + "mux_fastchg_suspend", + "mcu_data_active", + "mcu_data_suspend"; + pinctrl-0 = <&fastchg_active + &usb_sw_active + &ap_clk_active >; + pinctrl-1 = <&usb_sw_suspend + &fastchg_suspend + &ap_clk_suspend>; + pinctrl-2 =<&ap_data_active>; + pinctrl-3 =<&ap_data_suspend>; + op,fw-erase-count = <384>; + op,fw-addr-low = <0x88>; + op,fw-addr-high = <0>; + }; +}; + +&mtp_batterydata{ + #include "OP-batterydata-3300mah.dtsi" +}; + +&pmi8998_charger { + qcom,dc-icl-ua = <1200000>; + qcom,fcc-max-ua = <500000>; + qcom,usb-icl-ua = <1800000>; + qcom,fv-max-uv = <4365000>; + /* ibatmax setting for different temp regions */ + ibatmax-little-cold-ma = <275>; + ibatmax-cool-ma = <425>; + ibatmax-little-cool-ma = <725>; + ibatmax-pre-normal-ma = <1375>; + ibatmax-normal-ma = <1950>; + ibatmax-warm-ma = <750>; + /* vbatmax setting for different temp regions */ + vbatmax-little-cold-mv = <3975>; + vbatmax-cool-mv = <4400>; + vbatmax-little-cool-mv = <4400>; + vbatmax-pre-normal-mv = <4400>; + vbatmax-normal-mv = <4400>; + vbatmax-warm-mv = <4080>; + /* vbatdet setting for different temp regions */ + vbatdet-little-cold-mv = <3700>; + vbatdet-cool-mv = <4150>; + vbatdet-little-cool-mv = <4270>; + vbatdet-pre-normal-mv = <4270>; + vbatdet-normal-mv = <4270>; + vbatdet-warm-mv = <3980>; + /* temp region settings */ + cold-bat-decidegc = <30>; + 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 = <530>; + + op,sw-iterm-ma = <264>; + op,sw-check-full-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>; + /* other settings */ + qcom,cutoff-voltage-with-charger = <3250>; + disable-pd; + + 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>; +}; + +&pmi8998_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 = <150>; +}; + +&qusb_phy0 { + pinctrl-names = "atest_usb13_suspend", "atest_usb13_active"; + pinctrl-0 = <&atest_usb13_suspend>; + pinctrl-1 = <&atest_usb13_active>; +}; + +&tlmm { + atest_usb13_active: atest_usb13_active { + mux { + pins = "gpio7"; + function = "gpio"; + }; + + config { + pins = "gpio7"; + drive-strength = <12>; + bias-pull-up; + }; + }; + + atest_usb13_suspend: atest_usb13_suspend { + mux { + pins = "gpio7"; + function = "gpio"; + }; + + config { + pins = "gpio7"; + bias-pull-down; + drive-strength = <2>; + }; + }; + + oneplus_fastchg { + usb_sw_active: usb_sw_active { + mux { + pins = "gpio37", "gpio51"; + function = "gpio"; + }; + + config { + pins = "gpio37", "gpio51"; + drive-strength = <16>; + bias-pull-down; + }; + }; + + usb_sw_suspend: usb_sw_suspend { + mux { + pins = "gpio37", "gpio51"; + function = "gpio"; + }; + + config { + pins = "gpio37", "gpio51"; + drive-strength = <2>; + bias-disable; + }; + }; + + fastchg_active: fastchg_active { + mux { + pins = "gpio102"; + function = "gpio"; + }; + + config { + pins = "gpio102"; + drive-strength = <16>; + bias-pull-up; + }; + }; + + fastchg_suspend: fastchg_suspend { + mux { + pins = "gpio102"; + function = "gpio"; + }; + + config { + pins = "gpio102"; + drive-strength = <2>; + bias-disable; + }; + }; + + ap_clk_active: ap_clk_active { + mux { + pins = "gpio44"; + function = "gpio"; + }; + + config { + pins = "gpio44"; + drive-strength = <16>; + bias-pull-up; + }; + }; + + ap_clk_suspend: ap_clk_suspend { + mux { + pins = "gpio44"; + function = "gpio"; + }; + + config { + pins = "gpio44"; + drive-strength = <2>; + bias-disable; + }; + }; + + ap_data_active: ap_data_active { + mux { + pins = "gpio43"; + function = "gpio"; + }; + + config { + pins = "gpio43"; + drive-strength = <16>; + bias-pull-up; + }; + }; + + ap_data_suspend: ap_data_suspend { + mux { + pins = "gpio43"; + function = "gpio"; + }; + + config { + pins = "gpio43"; + drive-strength = <2>; + bias-disable; + }; + }; + }; +}; + +&pcie0 { + status = "disabled"; +}; + +&pcie1 { + status = "disabled"; +}; + +&spss_utils { + status = "disabled"; +}; + + +&qupv3_se3_i2c { + status = "ok"; + nq@28 { + qcom,nq-firm = <&tlmm 34 0x00>; + + }; +}; + +&pmi8998_wled { + status = "disabled"; +}; + +&dsi_nt35597_truly_dsc_cmd_display { + status = "disabled"; +}; +&mdss_mdp { + connectors = <&sde_rscc &sde_wb>; +}; +&sde_dp{ + status = "disabled"; +}; + +&labibb { + status = "disabled"; +}; +&sdhc_2 { + status = "disabled"; +}; + +&pm8998_rtc { + compatible = "qcom,qpnp-rtc"; + qcom,qpnp-rtc-alarm-pwrup = <1>; +}; + +&pmi8998_haptics { + status = "okay"; + qcom,wave-shape = "sine"; + qcom,play-mode = "buffer"; + qcom,brake-pattern = <0x3 0x3 0x3 0x3>; + qcom,drive-period-code-max-variation-pct = <5>; + qcom,drive-period-code-min-variation-pct = <5>; + qcom,wave-rep-cnt = <1>; + qcom,wave-samp-rep-cnt = <1>; + qcom,vmax-mv = <2088>; + qcom,wave-play-rate-us = <4255>; + qcom,lra-auto-res-mode = "zxd-eop"; + qcom,lra-res-cal-period = <32>; +}; + +&red_led { + qcom,use-blink; + qcom,duty-pcts = [00 05 0a 0f 14 1d 28 32 3c 4b 64]; + qcom,duty-ms = <20>; + qcom,start-idx = <1>; + qcom,idx-len = <11>; + qcom,lut-flags = <0x1f>; + qcom,ramp-step-ms = <100>; + qcom,pause-lo = <2000>; + qcom,pause-hi = <1000>; + /delete-property/ linux,default-trigger; +}; + +&green_led { + qcom,use-blink; + qcom,duty-pcts = [00 05 0a 0f 14 1d 28 32 3c 4b 64]; + qcom,duty-ms = <20>; + qcom,start-idx = <13>; + qcom,idx-len = <11>; + qcom,lut-flags = <0x1f>; + qcom,ramp-step-ms = <100>; + qcom,pause-lo = <2000>; + qcom,pause-hi = <1000>; + /delete-property/ linux,default-trigger; +}; + +&blue_led { + qcom,use-blink; + qcom,duty-pcts = [00 05 0a 0f 14 1d 28 32 3c 4b 64]; + qcom,duty-ms = <20>; + qcom,start-idx = <13>; + qcom,idx-len = <11>; + qcom,lut-flags = <0x1f>; + qcom,ramp-step-ms = <100>; + qcom,pause-lo = <2000>; + qcom,pause-hi = <1000>; + /delete-property/ linux,default-trigger; +}; + +&sde_dsi_active { + mux { + pins = "gpio6", "gpio25", "gpio26"; + function = "gpio"; + }; + + config { + pins = "gpio6", "gpio25", "gpio26"; + drive-strength = <8>; /* 8 mA */ + bias-disable = <0>; /* no pull */ + }; + }; +&sde_dsi_suspend { + mux { + pins = "gpio6", "gpio25", "gpio26"; + function = "gpio"; + }; + + config { + pins = "gpio6", "gpio25", "gpio26"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + }; + }; + + +&tlmm { + goodixfp_enable_init: goodixfp_enable_init { + mux { + pins = "gpio80"; + function = "gpio"; + }; + + config { + pins = "gpio80"; + drive-strength = <8>; + bias-pull-up; + output-high; + }; + }; + + goodixfp_irq_init: goodixfp_irq_init { + mux { + pins = "gpio121"; + function = "gpio"; + }; + + config { + pins = "gpio121"; + drive-strength = <2>; + bias-disable; + input-enable; + }; + }; + + goodixfp_disable_init: goodixfp_disable_init { + mux { + pins = "gpio80"; + function = "gpio"; + }; + + config { + pins = "gpio80"; + drive-strength = <8>; + bias-pull-up; + output-low; + }; + }; + + fp_id_init: fp_id_init { + mux { + pins = "gpio21"; + function = "gpio"; + }; + + config { + pins = "gpio21"; + drive-strength = <8>; + bias-pull-up; + output-high; + }; + }; + + fp_reset_high: fp_reset_high { + mux { + pins = "gpio35"; + function = "gpio"; + }; + + config { + pins = "gpio35"; + drive-strength = <8>; + bias-pull-up; + output-high; + }; + }; + + fp_reset_low: fp_reset_low { + mux { + pins = "gpio35"; + function = "gpio"; + }; + + config { + pins = "gpio35"; + drive-strength = <8>; + bias-pull-up; + output-low; + }; + }; + + fp_id0_up: fp_id0_up { + mux { + pins = "gpio91"; + function = "gpio"; + }; + + config { + pins = "gpio91"; + drive-strength = <2>; + bias-pull-up; + input-enable; + }; + }; + + fp_id0_down: fp_id0_down { + mux { + pins = "gpio91"; + function = "gpio"; + }; + + config { + pins = "gpio91"; + drive-strength = <2>; + bias-disable; + input-enable; + }; + }; + + fp_id1_up: fp_id1_up { + mux { + pins = "gpio92"; + function = "gpio"; + }; + + config { + pins = "gpio92"; + drive-strength = <2>; + bias-pull-up; + input-enable; + }; + }; + + fp_id1_down: fp_id1_down { + mux { + pins = "gpio92"; + function = "gpio"; + }; + + config { + pins = "gpio92"; + drive-strength = <2>; + bias-disable; + input-enable; + }; + }; + + fp_id2_up: fp_id2_up { + mux { + pins = "gpio95"; + function = "gpio"; + }; + + config { + pins = "gpio95"; + drive-strength = <2>; + bias-pull-up; + input-enable; + }; + }; + + fp_id2_down: fp_id2_down { + mux { + pins = "gpio95"; + function = "gpio"; + }; + + config { + pins = "gpio95"; + drive-strength = <2>; + bias-disable; + input-enable; + }; + }; + + tri_state_key_active: tri_state_key_active { + mux { + pins = "gpio24","gpio52","gpio126"; + function = "gpio"; + }; + + config { + pins = "gpio24","gpio52","gpio126"; + drive-strength = <2>; + bias-disable; + }; + }; + + tri_state_key_suspend: tri_state_key_suspend { + mux { + pins = "gpio24","gpio52","gpio126"; + function = "gpio"; + }; + + config { + pins = "gpio24","gpio52","gpio126"; + drive-strength = <2>; + bias-disable; + }; + }; + + esd_check_active: esd_check_active { + mux { + pins = "gpio30"; + function = "gpio"; + }; + config { + pins = "gpio30"; + drive-strength = <2>; + bias-pull-down; + input-enable; + }; + }; + esd_check_suspend: esd_check_suspend { + mux { + pins = "gpio30"; + function = "gpio"; + }; + config { + pins = "gpio30"; + drive-strength = <2>; + bias-pull-down; + input-enable; + }; + }; +}; + +//overlay for camera start +&tlmm { + cam_sensor_rear_0_mclk_active: cam_sensor_rear_0_mclk_active { + /* MCLK0 */ + mux { + /* CLK, DATA */ + pins = "gpio13"; + function = "cam_mclk"; + }; + + config { + pins = "gpio13"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_0_mclk_suspend: cam_sensor_rear_0_mclk_suspend { + /* MCLK0 */ + mux { + /* CLK, DATA */ + pins = "gpio13"; + function = "cam_mclk"; + }; + + config { + pins = "gpio13"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_0_rest_active: cam_sensor_rear_0_rest_active { + /* RESET, STANDBY */ + mux { + pins = "gpio28"; + function = "gpio"; + }; + + config { + pins = "gpio28"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_0_rest_suspend: cam_sensor_rear_0_rest_suspend { + /* RESET, STANDBY */ + mux { + pins = "gpio28"; + function = "gpio"; + }; + + config { + pins = "gpio28"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_0_ana_active: cam_sensor_rear_0_ana_active { + /* VANA */ + mux { + pins = "gpio27"; + function = "gpio"; + }; + + config { + pins = "gpio27"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_0_ana_suspend: cam_sensor_rear_0_ana_suspend { + /* VANA */ + mux { + pins = "gpio27"; + function = "gpio"; + }; + + config { + pins = "gpio27"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_0_dig_active: cam_sensor_rear_0_dig_active { + /* DIG */ + mux { + pins = "gpio8"; + function = "gpio"; + }; + + config { + pins = "gpio8"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_0_dig_suspend: cam_sensor_rear_0_dig_suspend { + /* DIG */ + mux { + pins = "gpio8"; + function = "gpio"; + }; + + config { + pins = "gpio8"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_1_mclk_active: cam_sensor_rear_1_mclk_active { + /* MCLK1 */ + mux { + /* CLK, DATA */ + pins = "gpio15"; + function = "cam_mclk"; + }; + + config { + pins = "gpio15"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_1_mclk_suspend: cam_sensor_rear_1_mclk_suspend { + /* MCLK1 */ + mux { + /* CLK, DATA */ + pins = "gpio15"; + function = "cam_mclk"; + }; + + config { + pins = "gpio15"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_1_rest_active: cam_sensor_rear_1_rest_active { + /* RESET, STANDBY */ + mux { + pins = "gpio23"; + function = "gpio"; + }; + + config { + pins = "gpio23"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_1_rest_suspend: cam_sensor_rear_1_rest_suspend { + /* RESET, STANDBY */ + mux { + pins = "gpio23"; + function = "gpio"; + }; + config { + pins = "gpio23"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_1_ana_active: cam_sensor_rear_1_ana_active { + /* VANA */ + mux { + pins = "gpio78"; + function = "gpio"; + }; + + config { + pins = "gpio78"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_1_ana_suspend: cam_sensor_rear_1_ana_suspend { + /* VANA */ + mux { + pins = "gpio78"; + function = "gpio"; + }; + + config { + pins = "gpio78"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_1_vaf_active: cam_sensor_rear_1_vaf_active { + /* ACTUATOR POWER */ + mux { + pins = "gpio77"; + function = "gpio"; + }; + + config { + pins = "gpio77"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_1_vaf_suspend: cam_sensor_rear_1_vaf_suspend { + /* ACTUATOR POWER */ + mux { + pins = "gpio77"; + function = "gpio"; + }; + + config { + pins = "gpio77"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_1_dig_active: cam_sensor_rear_1_dig_active { + /* DIG */ + mux { + pins = "gpio79"; + function = "gpio"; + }; + + config { + pins = "gpio79"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_1_dig_suspend: cam_sensor_rear_1_dig_suspend { + /* DIG */ + mux { + pins = "gpio79"; + function = "gpio"; + }; + + config { + pins = "gpio79"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_0_mclk_active: cam_sensor_front_0_mclk_active { + /* MCLK2 */ + mux { + /* CLK, DATA */ + pins = "gpio14"; + function = "cam_mclk"; + }; + + config { + pins = "gpio14"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_0_mclk_suspend: + cam_sensor_front_0_mclk_suspend { + /* MCLK2 */ + mux { + /* CLK, DATA */ + pins = "gpio14"; + function = "cam_mclk"; + }; + + config { + pins = "gpio14"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_0_rest_active: + cam_sensor_front_0_rest_active { + /* RESET, STANDBY */ + mux { + pins = "gpio9"; + function = "gpio"; + }; + + config { + pins = "gpio9"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_0_rest_suspend: + cam_sensor_front_0_rest_suspend { + /* RESET, STANDBY */ + mux { + pins = "gpio9"; + function = "gpio"; + }; + + config { + pins = "gpio9"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_0_ana_active: + cam_sensor_front_0_ana_active { + /* VANA */ + mux { + pins = "gpio104"; + function = "gpio"; + }; + + config { + pins = "gpio104"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_0_ana_suspend: + cam_sensor_front_0_ana_suspend { + /* VANA */ + mux { + pins = "gpio104"; + function = "gpio"; + }; + + config { + pins = "gpio104"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_0_dig_active: + cam_sensor_front_0_dig_active { + /* DIG */ + mux { + pins = "gpio117"; + function = "gpio"; + }; + + config { + pins = "gpio117"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_0_dig_suspend: + cam_sensor_front_0_dig_suspend { + /* DIG */ + mux { + pins = "gpio117"; + function = "gpio"; + }; + + config { + pins = "gpio117"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; +}; + +&soc { + led_flash_rear: qcom,camera-flash@0 { + cell-index = <0>; + reg = <0x00 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pmi8998_flash0 &pmi8998_flash1>; + torch-source = <&pmi8998_torch0 &pmi8998_torch1>; + switch-source = <&pmi8998_switch0>; + status = "ok"; + }; + + rear_1_actuator_regulator: gpio-regulator@1 { + compatible = "regulator-fixed"; + reg = <0x01 0x00>; + regulator-name = "actuator_regulator"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-enable-ramp-delay = <100>; + enable-active-high; + gpio = <&tlmm 77 0>; + vin-supply = <&pmi8998_bob>; + }; +}; + +&cam_cci { + qcom,cam-res-mgr { + compatible = "qcom,cam-res-mgr"; + status = "ok"; + }; + + actuator_rear_0: qcom,actuator@0 { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,actuator"; + cci-master = <0>; + cam_vaf-supply = <&pm8998_l22>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; + }; + + actuator_rear_1: qcom,actuator@1 { + cell-index = <1>; + reg = <0x1>; + compatible = "qcom,actuator"; + cci-master = <1>; + cam_vaf-supply = <&rear_1_actuator_regulator>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; + }; + + ois_rear_0: qcom,ois@0 { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,ois"; + cam_vaf-supply = <&pm8998_l22>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2864000>; + rgltr-max-voltage = <2864000>; + rgltr-load-current = <500000>; + gpio-no-mux = <0>; + gpios = <&tlmm 40 0>; + gpio-vaf = <0>; + gpio-req-tbl-num = <0>; + gpio-req-tbl-flags = <0>; + gpio-req-tbl-label = "CAM_OIS_PWD_0"; + cci-master = <0>; + status = "ok"; + }; + + eeprom_rear_0: qcom,eeprom@0 { + cell-index = <0>; + reg = <0>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pm8998_lvs1>; + cam_vana-supply = <&pmi8998_bob>; + cam_vdig-supply = <&pmi8998_bob>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 3312000 3312000 0>; + rgltr-max-voltage = <0 3600000 3600000 0>; + rgltr-load-current = <0 3600000 3600000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_rear_0_mclk_active + &cam_sensor_rear_0_rest_active + &cam_sensor_rear_0_ana_active + &cam_sensor_rear_0_dig_active>; + pinctrl-1 = <&cam_sensor_rear_0_mclk_suspend + &cam_sensor_rear_0_rest_suspend + &cam_sensor_rear_0_ana_suspend + &cam_sensor_rear_0_dig_suspend>; + gpios = <&tlmm 13 0>, + <&tlmm 28 0>, + <&tlmm 27 0>, + <&tlmm 8 0>; + 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_MCLK_0", + "CAM_RESET_0", + "CAM_VANA_0", + "CAM_DIG_0"; + 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_1: qcom,eeprom@1 { + cell-index = <1>; + reg = <0x1>; + compatible = "qcom,eeprom"; + cam_vdig-supply = <&pmi8998_bob>; + cam_vio-supply = <&pm8998_lvs1>; + cam_vana-supply = <&pmi8998_bob>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vdig", "cam_vio", "cam_vana", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <3312000 0 3312000 0>; + rgltr-max-voltage = <3600000 0 3600000 0>; + rgltr-load-current = <80000 0 80000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_rear_1_mclk_active + &cam_sensor_rear_1_rest_active + &cam_sensor_rear_1_ana_active + &cam_sensor_rear_1_dig_active>; + pinctrl-1 = <&cam_sensor_rear_1_mclk_suspend + &cam_sensor_rear_1_rest_suspend + &cam_sensor_rear_1_ana_suspend + &cam_sensor_rear_1_dig_suspend>; + gpios = <&tlmm 15 0>, + <&tlmm 23 0>, + <&tlmm 78 0>, + <&tlmm 79 0>; + 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_MCLK_1", + "CAM_RESET_1", + "CAM_VANA_1", + "CAM_DIG_1"; + + 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_front_0: qcom,eeprom@2 { + cell-index = <2>; + reg = <0x2>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pm8998_lvs1>; + cam_vana-supply = <&pmi8998_bob>; + cam_vdig-supply = <&pmi8998_bob>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 3312000 3312000 0>; + rgltr-max-voltage = <0 3600000 3600000 0>; + rgltr-load-current = <0 80000 80000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_front_0_mclk_active + &cam_sensor_front_0_rest_active + &cam_sensor_front_0_ana_active + &cam_sensor_front_0_dig_active>; + pinctrl-1 = <&cam_sensor_front_0_mclk_suspend + &cam_sensor_front_0_rest_suspend + &cam_sensor_front_0_ana_suspend + &cam_sensor_front_0_dig_suspend>; + gpios = <&tlmm 14 0>, + <&tlmm 9 0>, + <&tlmm 104 0>, + <&tlmm 117 0>; + 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_MCLK_2", + "CAM_RESET_2", + "CAM_VANA_2", + "CAM_DIG_2"; + sensor-position = <1>; + 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-sensor@0 { + cell-index = <0>; + compatible = "qcom,cam-sensor"; + reg = <0x0>; + csiphy-sd-index = <0>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + led-flash-src = <&led_flash_rear>; + actuator-src = <&actuator_rear_0>; + ois-src = <&ois_rear_0>; + eeprom-src = <&eeprom_rear_0>; + cam_vio-supply = <&pm8998_lvs1>; + cam_vana-supply = <&pmi8998_bob>; + cam_vdig-supply = <&pmi8998_bob>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 3312000 3312000 0>; + rgltr-max-voltage = <0 3600000 3600000 0>; + rgltr-load-current = <0 3600000 3600000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_rear_0_mclk_active + &cam_sensor_rear_0_rest_active + &cam_sensor_rear_0_ana_active + &cam_sensor_rear_0_dig_active>; + pinctrl-1 = <&cam_sensor_rear_0_mclk_suspend + &cam_sensor_rear_0_rest_suspend + &cam_sensor_rear_0_ana_suspend + &cam_sensor_rear_0_dig_suspend>; + gpios = <&tlmm 13 0>, + <&tlmm 28 0>, + <&tlmm 27 0>, + <&tlmm 8 0>; + 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_MCLK_0", + "CAM_RESET_0", + "CAM_VANA_0", + "CAM_DIG_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>; + }; + + qcom,cam-sensor@1 { + cell-index = <1>; + compatible = "qcom,cam-sensor"; + reg = <0x1>; + csiphy-sd-index = <1>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + led-flash-src = <&led_flash_rear>; + actuator-src = <&actuator_rear_1>; + eeprom-src = <&eeprom_rear_1>; + cam_vdig-supply = <&pmi8998_bob>; + cam_vio-supply = <&pm8998_lvs1>; + cam_vana-supply = <&pmi8998_bob>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vdig", "cam_vio", "cam_vana", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <3312000 0 3312000 0>; + rgltr-max-voltage = <3600000 0 3600000 0>; + rgltr-load-current = <80000 0 80000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_rear_1_mclk_active + &cam_sensor_rear_1_rest_active + &cam_sensor_rear_1_ana_active + &cam_sensor_rear_1_dig_active>; + pinctrl-1 = <&cam_sensor_rear_1_mclk_suspend + &cam_sensor_rear_1_rest_suspend + &cam_sensor_rear_1_ana_suspend + &cam_sensor_rear_1_dig_suspend>; + gpios = <&tlmm 15 0>, + <&tlmm 23 0>, + <&tlmm 78 0>, + <&tlmm 79 0>; + 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_MCLK_1", + "CAM_RESET_1", + "CAM_VANA_1", + "CAM_DIG_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-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 = <&pm8998_lvs1>; + cam_vana-supply = <&pmi8998_bob>; + cam_vdig-supply = <&pmi8998_bob>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 3312000 3312000 0>; + rgltr-max-voltage = <0 3600000 3600000 0>; + rgltr-load-current = <0 80000 80000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_front_0_mclk_active + &cam_sensor_front_0_rest_active + &cam_sensor_front_0_ana_active + &cam_sensor_front_0_dig_active>; + pinctrl-1 = <&cam_sensor_front_0_mclk_suspend + &cam_sensor_front_0_rest_suspend + &cam_sensor_front_0_ana_suspend + &cam_sensor_front_0_dig_suspend>; + gpios = <&tlmm 14 0>, + <&tlmm 9 0>, + <&tlmm 104 0>, + <&tlmm 117 0>; + 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_MCLK_2", + "CAM_RESET_2", + "CAM_VANA_2", + "CAM_DIG_2"; + 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>; + }; + +}; + + + +//overlay for camera end. + +&tlmm { + //add by gu qicai begin + ts_mux { + ts_active: ts_active { + mux { + pins = "gpio99", "gpio125"; + function = "gpio"; + }; + + config { + pins = "gpio99", "gpio125"; + drive-strength = <16>; + bias-pull-up; + }; + }; + + ts_reset_suspend: ts_reset_suspend { + mux { + pins = "gpio99"; + function = "gpio"; + }; + + config { + pins = "gpio99"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + ts_int_suspend: ts_int_suspend { + mux { + pins = "gpio125"; + function = "gpio"; + }; + + config { + pins = "gpio125"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + //add by gu qicai end +}; + +/* OnePlus add thermistor, by rio.zhao*/ +&pm8998_vadc { + chan@50 { + label = "pa1_therm"; + reg = <0x50>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + }; +}; + +&pm8998_adc_tm { + chan@50 { + label = "pa1_therm"; + reg = <0x50>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,btm-channel-number = <0x90>; + qcom,thermal-node; + }; +}; + +&thermal_zones { + pa1-therml-adc { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&pm8998_adc_tm 0x50>; + thermal-governor = "user_space"; + + trips { + active-config0 { + temperature = <65000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; +}; + +&spmi_bus { + qcom,pm8998@0 { + qcom,power-on@800 { + qcom,pon_1 { + qcom,support-reset = <0>; + }; + }; + }; +}; + + +&qupv3_se0_spi { + status = "ok"; + qcom,disable-autosuspend; + + ese@0 { + compatible = "nxp,p61"; + reg = <0>; + spi-max-frequency = <8000000>; + nxp,nfcc = "1-0028"; + }; +}; + +&qupv3_se3_i2c { + + nq@28 { + status = "disabled"; + }; + + pn5xx@28 { + compatible = "nxp,pn544"; + reg = <0x28>; + nxp,pn544-irq = <&tlmm 63 0x00>; + nxp,pn544-ven = <&tlmm 12 0x00>; + nxp,pn544-fw-dwnld = <&tlmm 62 0x00>; + nxp,pn544-clk-gpio = <&pm8998_gpios 21 0x00>; + nxp,pn544-ese-pwr = <&tlmm 116 0x00>; + nfc_voltage_s4-supply = <&pm8998_s4>; + nxp,pn544-wake-up = <&tlmm 129 0x00>; + interrupt-parent = <&tlmm>; + qcom,clk-src = "BBCLK3"; + interrupts = <63 0>; + interrupt-names = "nfc_irq"; + pinctrl-names = "nfc_active", "nfc_suspend"; + pinctrl-0 = <&nfc_int_active + &nfc_enable_active + &nfc_clk_default>; + pinctrl-1 = <&nfc_int_suspend &nfc_enable_suspend>; + clocks = <&clock_rpmh RPMH_LN_BB_CLK3>; + clock-names = "ref_clk"; + }; +}; + diff --git a/arch/arm64/boot/dts/qcom/fajita-dvt-bu.dtsi b/arch/arm64/boot/dts/qcom/fajita-dvt-bu.dtsi new file mode 100644 index 000000000000..d1ff91d17f1b --- /dev/null +++ b/arch/arm64/boot/dts/qcom/fajita-dvt-bu.dtsi @@ -0,0 +1,20 @@ +/* Copyright (c) 2016-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. + */ +/*don't suggest add to this file, this file is only for different hw*/ + +&vendor { + +}; + +&soc { + +}; diff --git a/arch/arm64/boot/dts/qcom/fajita-dvt-v2.1-bu-overlay.dts b/arch/arm64/boot/dts/qcom/fajita-dvt-v2.1-bu-overlay.dts new file mode 100644 index 000000000000..148cc5969b80 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/fajita-dvt-v2.1-bu-overlay.dts @@ -0,0 +1,33 @@ +/* Copyright (c) 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. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-mtp.dtsi" +#include "sdm845-audio-overlay.dtsi" +#include "fajita.dtsi" +#include "fajita-dvt-bu.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM845 v2.1 MTP DVT 2nd"; + compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp"; + qcom,msm-id = <321 0x20001>; + qcom,board-id = <8 0 18801 35>; +}; diff --git a/arch/arm64/boot/dts/qcom/fajita-dvt-v2.1-overlay.dts b/arch/arm64/boot/dts/qcom/fajita-dvt-v2.1-overlay.dts new file mode 100644 index 000000000000..914d27d58612 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/fajita-dvt-v2.1-overlay.dts @@ -0,0 +1,33 @@ +/* Copyright (c) 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. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-mtp.dtsi" +#include "sdm845-audio-overlay.dtsi" +#include "fajita.dtsi" +#include "fajita-dvt.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM845 v2.1 MTP DVT"; + compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp"; + qcom,msm-id = <321 0x20001>; + qcom,board-id = <8 0 18801 34>; +}; diff --git a/arch/arm64/boot/dts/qcom/fajita-dvt.dtsi b/arch/arm64/boot/dts/qcom/fajita-dvt.dtsi new file mode 100644 index 000000000000..d1ff91d17f1b --- /dev/null +++ b/arch/arm64/boot/dts/qcom/fajita-dvt.dtsi @@ -0,0 +1,20 @@ +/* Copyright (c) 2016-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. + */ +/*don't suggest add to this file, this file is only for different hw*/ + +&vendor { + +}; + +&soc { + +}; diff --git a/arch/arm64/boot/dts/qcom/fajita-mp-spec.dtsi b/arch/arm64/boot/dts/qcom/fajita-mp-spec.dtsi new file mode 100644 index 000000000000..00914208a77e --- /dev/null +++ b/arch/arm64/boot/dts/qcom/fajita-mp-spec.dtsi @@ -0,0 +1,36 @@ +/* Copyright (c) 2016-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. + */ +/*don't suggest add to this file, this file is only for different hw*/ + +&vendor { + +}; + +&soc { + +}; + +&oneplus_fastchg { + op,mcl_verion; +}; + +&pmi8998_charger { + warm-bat-decidegc = <480>; +}; + +&bq27541_battery { + op,mcl_verion; +}; + +&pmi8998_charger { + ibatmax-little-cool-low_ma = <480>; +}; diff --git a/arch/arm64/boot/dts/qcom/fajita-mp-v2.1-spec-overlay.dts b/arch/arm64/boot/dts/qcom/fajita-mp-v2.1-spec-overlay.dts new file mode 100644 index 000000000000..17386bf574bf --- /dev/null +++ b/arch/arm64/boot/dts/qcom/fajita-mp-v2.1-spec-overlay.dts @@ -0,0 +1,33 @@ +/* Copyright (c) 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. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-mtp.dtsi" +#include "sdm845-audio-overlay.dtsi" +#include "fajita.dtsi" +#include "fajita-mp-spec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM845 v2.1 MTP MP spec"; + compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp"; + qcom,msm-id = <321 0x20001>; + qcom,board-id = <8 0 18801 45>; +}; diff --git a/arch/arm64/boot/dts/qcom/fajita-pvt-bu.dtsi b/arch/arm64/boot/dts/qcom/fajita-pvt-bu.dtsi new file mode 100644 index 000000000000..d1ff91d17f1b --- /dev/null +++ b/arch/arm64/boot/dts/qcom/fajita-pvt-bu.dtsi @@ -0,0 +1,20 @@ +/* Copyright (c) 2016-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. + */ +/*don't suggest add to this file, this file is only for different hw*/ + +&vendor { + +}; + +&soc { + +}; diff --git a/arch/arm64/boot/dts/qcom/fajita-pvt-spec.dtsi b/arch/arm64/boot/dts/qcom/fajita-pvt-spec.dtsi new file mode 100644 index 000000000000..e7c9b8fd331a --- /dev/null +++ b/arch/arm64/boot/dts/qcom/fajita-pvt-spec.dtsi @@ -0,0 +1,32 @@ +/* Copyright (c) 2016-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. + */ +/*don't suggest add to this file, this file is only for different hw*/ + +&vendor { + +}; + +&soc { + +}; + +&oneplus_fastchg { + op,mcl_verion; +}; + +&pmi8998_charger { + warm-bat-decidegc = <480>; +}; + +&pmi8998_charger { + ibatmax-little-cool-low_ma = <480>; +}; diff --git a/arch/arm64/boot/dts/qcom/fajita-pvt-v1.dtsi b/arch/arm64/boot/dts/qcom/fajita-pvt-v1.dtsi new file mode 100644 index 000000000000..d1ff91d17f1b --- /dev/null +++ b/arch/arm64/boot/dts/qcom/fajita-pvt-v1.dtsi @@ -0,0 +1,20 @@ +/* Copyright (c) 2016-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. + */ +/*don't suggest add to this file, this file is only for different hw*/ + +&vendor { + +}; + +&soc { + +}; diff --git a/arch/arm64/boot/dts/qcom/fajita-pvt-v2.1-bu-overlay.dts b/arch/arm64/boot/dts/qcom/fajita-pvt-v2.1-bu-overlay.dts new file mode 100644 index 000000000000..4e18ae61e10b --- /dev/null +++ b/arch/arm64/boot/dts/qcom/fajita-pvt-v2.1-bu-overlay.dts @@ -0,0 +1,33 @@ +/* Copyright (c) 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. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-mtp.dtsi" +#include "sdm845-audio-overlay.dtsi" +#include "fajita.dtsi" +#include "fajita-pvt-bu.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM845 v2.1 MTP PVT/MP 2nd"; + compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp"; + qcom,msm-id = <321 0x20001>; + qcom,board-id = <8 0 18801 42>; +}; diff --git a/arch/arm64/boot/dts/qcom/fajita-pvt-v2.1-overlay.dts b/arch/arm64/boot/dts/qcom/fajita-pvt-v2.1-overlay.dts new file mode 100644 index 000000000000..76a31da29cb3 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/fajita-pvt-v2.1-overlay.dts @@ -0,0 +1,33 @@ +/* Copyright (c) 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. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-mtp.dtsi" +#include "sdm845-audio-overlay.dtsi" +#include "fajita.dtsi" +#include "fajita-pvt.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM845 v2.1 MTP PVT/MP"; + compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp"; + qcom,msm-id = <321 0x20001>; + qcom,board-id = <8 0 18801 41>; +}; diff --git a/arch/arm64/boot/dts/qcom/fajita-pvt-v2.1-spec-overlay.dts b/arch/arm64/boot/dts/qcom/fajita-pvt-v2.1-spec-overlay.dts new file mode 100644 index 000000000000..04dcbf331da1 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/fajita-pvt-v2.1-spec-overlay.dts @@ -0,0 +1,33 @@ +/* Copyright (c) 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. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-mtp.dtsi" +#include "sdm845-audio-overlay.dtsi" +#include "fajita.dtsi" +#include "fajita-pvt-spec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM845 v2.1 MTP PVT/MP spec"; + compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp"; + qcom,msm-id = <321 0x20001>; + qcom,board-id = <8 0 18801 44>; +}; diff --git a/arch/arm64/boot/dts/qcom/fajita-pvt-v2.1-v1-overlay.dts b/arch/arm64/boot/dts/qcom/fajita-pvt-v2.1-v1-overlay.dts new file mode 100644 index 000000000000..876235e7b1be --- /dev/null +++ b/arch/arm64/boot/dts/qcom/fajita-pvt-v2.1-v1-overlay.dts @@ -0,0 +1,33 @@ +/* Copyright (c) 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. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include +#include +#include + +#include "sdm845-sde-display.dtsi" +#include "sdm845-mtp.dtsi" +#include "sdm845-audio-overlay.dtsi" +#include "fajita.dtsi" +#include "fajita-pvt-v1.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM845 v2.1 MTP PVT/MP v1"; + compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp"; + qcom,msm-id = <321 0x20001>; + qcom,board-id = <8 0 18801 43>; +}; diff --git a/arch/arm64/boot/dts/qcom/fajita-pvt.dtsi b/arch/arm64/boot/dts/qcom/fajita-pvt.dtsi new file mode 100644 index 000000000000..d1ff91d17f1b --- /dev/null +++ b/arch/arm64/boot/dts/qcom/fajita-pvt.dtsi @@ -0,0 +1,20 @@ +/* Copyright (c) 2016-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. + */ +/*don't suggest add to this file, this file is only for different hw*/ + +&vendor { + +}; + +&soc { + +}; diff --git a/arch/arm64/boot/dts/qcom/fajita.dtsi b/arch/arm64/boot/dts/qcom/fajita.dtsi new file mode 100644 index 000000000000..927d14446d34 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/fajita.dtsi @@ -0,0 +1,2396 @@ +/* Copyright (c) 2016-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. + */ +/*recommand add our code to this dtsi*/ +#include "dsi-panel-samsung_s6e3fc1_cmd.dtsi" +#include "dsi-panel-samsung_sofef00_m_cmd.dtsi" +#include "dsi-panel-samsung_sofef00_m_video.dtsi" +#include "dsi-panel-samsung_sefeg01_s_cmd.dtsi" +#include "dsi-panel-samsung_s6e3fc2x01.dtsi" +#include "dsi-panel-samsung_dsc.dtsi" + + +/{ +reserved-memory { + +}; +}; + +&vendor { + +}; + +&wdog{ + qcom,bark-time = <15000>; +}; + +&snd_934x { + qcom,audio-routing = + "AIF4 VI", "MCLK", + "RX_BIAS", "MCLK", + "MADINPUT", "MCLK", + "hifi amp", "LINEOUT1", + "hifi amp", "LINEOUT2", + "AMIC1", "MIC BIAS3", + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Headset Mic", + "AMIC3", "MIC BIAS4", + "MIC BIAS4", "ANCRight Headset Mic", + "AMIC4", "MIC BIAS1", + "MIC BIAS1", "ANCLeft Headset Mic", + "AMIC5", "MIC BIAS3", + "MIC BIAS3", "Handset Mic", + "DMIC0", "MIC BIAS1", + "MIC BIAS1", "Digital Mic0", + "DMIC1", "MIC BIAS1", + "MIC BIAS1", "Digital Mic1", + "DMIC2", "MIC BIAS3", + "MIC BIAS3", "Digital Mic2", + "DMIC3", "MIC BIAS3", + "MIC BIAS3", "Digital Mic3", + "DMIC4", "MIC BIAS4", + "MIC BIAS4", "Digital Mic4", + "DMIC5", "MIC BIAS4", + "MIC BIAS4", "Digital Mic5", + "SpkrLeft IN", "SPK1 OUT", + "SpkrRight IN", "SPK2 OUT"; + op,smartpa ="tfa98xx"; +// qcom,us-euro-gpios = <&tlmm 103 0>; + op,usb_sw; + usb_sw = <&pmi8998_gpios 10 GPIO_ACTIVE_LOW>; + hp_sw = <&tlmm 103 0>; + mbhc_sw = <&tlmm 36 1>; + ldo_sw = <&pmi8998_gpios 6 GPIO_ACTIVE_LOW>; +}; + +&wcd934x_cdc { + qcom,cdc-micbias1-mv = <2700>; + qcom,cdc-micbias2-mv = <2700>; + qcom,cdc-micbias3-mv = <2700>; + qcom,cdc-micbias4-mv = <2700>; +}; + +&soc { + + gpio_keys { + hallsensor_key { + label = "hallsensor_key"; + gpios = <&tlmm 124 1>; + interrupt-parent = <&tlmm>; + interrupts = <124 0x0>; + linux,input-type = <5>; + linux,code = <0>; + gpio-key,wakeup; + debounce-interval = <15>; + }; + }; + + + qcom,qbt1000 { + status = "disabled"; + }; + + fingerprint_detect { + compatible = "oneplus,fpdetect"; + fp-gpio-id0 = <&tlmm 91 0>; + pinctrl-names = "fp_id_up", "fp_id_down"; + pinctrl-0 = <&fp_id0_up>; + pinctrl-1 = <&fp_id0_down>; + oem,fajta; + }; + + fpc_fpc1020 { + compatible = "fpc,fpc1020"; + interrupt-parent = <&tlmm>; + fpc,irq-gpio = <&tlmm 121 0>; + fpc,reset-gpio = <&tlmm 35 0>; + pinctrl-names = "fp_reset_high", "fp_reset_low"; + pinctrl-0 = <&fp_reset_high>; + pinctrl-1 = <&fp_reset_low>; + }; + + goodix_fp { + compatible = "goodix,fingerprint"; + interrupt-parent = <&tlmm>; + vdd-3v2-supply = <&pm8998_l22>; + vdd-voltage = <3200000 3200000>; + vdd-current = <50000>; + fp-gpio-irq = <&tlmm 121 0x00>; + fp-gpio-reset = <&tlmm 35 0x00>; + fp-gpio-enable = <&tlmm 80 0x00>; + pinctrl-names = "fp_en_init", "fp_dis_init"; + pinctrl-0 = <&fp_enable_init &fp_irq_init>; + pinctrl-1 = <&fp_disable_init>; + oem,fajta; + status = "okay"; + }; + + silead_fp { + compatible = "sil,fingerprint"; + interrupt-parent = <&tlmm>; + avdd-supply = <&pm8998_l22>; + irq-gpios = <&tlmm 121 0x00>; + rst-gpios = <&tlmm 35 0x00>; + pinctrl-names = "fp_en_init"; + pinctrl-0 = <&fp_reset_init &fp_irq_init>; + oem,fajta; + status = "okay"; + }; + + //add tri_state_key support + tri_state_key { + compatible = "oneplus,tri-state-key"; + status = "okay"; + interrupt-parent = <&tlmm>; + tristate,gpio_key1 = <&tlmm 24 0x00>; + tristate,gpio_key2 = <&tlmm 52 0x00>; + tristate,gpio_key3 = <&tlmm 126 0x00>; + pinctrl-names = + "pmx_tri_state_key_active", "pmx_tri_state_key_suspend"; + pinctrl-0 = <&tri_state_key_active>; + pinctrl-1 = <&tri_state_key_suspend>; + }; + + +/*#endif*/ + dsi_panel_pwr_supply_no_labibb_2: dsi_panel_pwr_supply_no_labibb_2 { + #address-cells = <1>; + #size-cells = <0>; + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1850000>; + qcom,supply-max-voltage = <1850000>; + qcom,supply-enable-load = <62000>; + qcom,supply-disable-load = <80>; + qcom,supply-post-on-sleep = <0>; + }; + }; + + dsi_samsung_s6e3fc1_cmd_display: qcom,dsi-display@17 { + compatible = "qcom,dsi-display"; + label = "dsi_samsung_s6e3fc1_cmd_display"; + qcom,display-type = "primary"; + qcom,dsi-ctrl = <&mdss_dsi0>; + qcom,dsi-phy = <&mdss_dsi_phy0>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "mux_byte_clk", "mux_pixel_clk"; + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active &esd_check_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend &esd_check_suspend>; + qcom,dsi-panel = <&dsi_samsung_s6e3fc1_cmd>; + vddio-supply = <&pm8998_l14>; + qcom,platform-te-gpio = <&tlmm 30 0>; + }; + + dsi_samsung_sofef00_m_cmd_display: qcom,dsi-display@18 { + compatible = "qcom,dsi-display"; + label = "dsi_samsung_sofef00_m_cmd_display"; + qcom,display-type = "primary"; + qcom,dsi-ctrl = <&mdss_dsi0>; + qcom,dsi-phy = <&mdss_dsi_phy0>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "mux_byte_clk", "mux_pixel_clk"; + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active &esd_check_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend &esd_check_suspend>; + qcom,dsi-panel = <&dsi_samsung_sofef00_m_cmd>; + vddio-supply = <&pm8998_l14>; + qcom,platform-te-gpio = <&tlmm 30 0>; + }; + + dsi_samsung_sofef00_m_video_display: qcom,dsi-display@19 { + compatible = "qcom,dsi-display"; + label = "dsi_samsung_sofef00_m_video_display"; + qcom,display-type = "primary"; + qcom,dsi-ctrl = <&mdss_dsi0>; + qcom,dsi-phy = <&mdss_dsi_phy0>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "mux_byte_clk", "mux_pixel_clk"; + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active &esd_check_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend &esd_check_suspend>; + qcom,dsi-panel = <&dsi_samsung_sofef00_m_video>; + vddio-supply = <&pm8998_l14>; + qcom,platform-te-gpio = <&tlmm 30 0>; + }; + +dsi_samsung_sofeg01_s_cmd_display: qcom,dsi-display@20 { + compatible = "qcom,dsi-display"; + label = "dsi_samsung_sofeg01_s_cmd_display"; + qcom,display-type = "primary"; + qcom,dsi-ctrl = <&mdss_dsi0>; + qcom,dsi-phy = <&mdss_dsi_phy0>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "mux_byte_clk", "mux_pixel_clk"; + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active &esd_check_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend &esd_check_suspend>; + qcom,dsi-panel = <&dsi_samsung_sofeg01_s_cmd>; + vddio-supply = <&pm8998_l14>; + qcom,platform-te-gpio = <&tlmm 30 0>; + }; + +dsi_samsung_s6e3fc2x01_cmd_display: qcom,dsi-display@21 { + compatible = "qcom,dsi-display"; + label = "dsi_samsung_s6e3fc2x01_cmd_display"; + qcom,display-type = "primary"; + qcom,dsi-ctrl = <&mdss_dsi0>; + qcom,dsi-phy = <&mdss_dsi_phy0>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "mux_byte_clk", "mux_pixel_clk"; + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active &esd_check_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend &esd_check_suspend>; + qcom,dsi-panel = <&dsi_samsung_s6e3fc2x01_cmd>; + vddio-supply = <&pm8998_l14>; + qcom,platform-te-gpio = <&tlmm 10 0>; + }; + +dsi_samsung_dsc_cmd_display: qcom,dsi-display@22 { + compatible = "qcom,dsi-display"; + label = "dsi_samsung_dsc_cmd_display"; + qcom,display-type = "primary"; + qcom,dsi-ctrl = <&mdss_dsi0>; + qcom,dsi-phy = <&mdss_dsi_phy0>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "mux_byte_clk", "mux_pixel_clk"; + pinctrl-names = "panel_active", "panel_suspend"; + pinctrl-0 = <&sde_dsi_active &sde_te_active &esd_check_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend &esd_check_suspend>; + qcom,dsi-panel = <&dsi_samsung_dsc_cmd>; + vddio-supply = <&pm8998_l14>; + qcom,platform-te-gpio = <&tlmm 10 0>; + }; + + oem_serial_pinctrl { + compatible = "oem,oem_serial_pinctrl"; + pinctrl-names = "uart_pinctrl_active","uart_pinctrl_deactive"; + pinctrl-0 = <&qupv3_se9_2uart_active>; + pinctrl-1 = <&qupv3_se9_2uart_oem_sleep>; + + }; + +}; + +&tlmm { + qupv3_se9_2uart_oem_sleep: qupv3_se9_2uart_oem_sleep { + mux { + pins = "gpio4", "gpio5"; + function = "gpio"; + }; + config { + pins = "gpio4", "gpio5"; + drive-strength = <2>; + bias-pull-down; + }; + }; + +}; + +&qupv3_se9_2uart { + compatible = "qcom,msm-geni-console-oem"; +}; + + +&tlmm{ + config { + pins = "gpio37"; + drive-strength = <2>; + bias-pull-up; + }; +}; +&soc { + gpio_keys { + vol_up { + /delete-property/ gpio-key,wakeup; + }; + //add volume down support , shankai @bsp . + vol_down { + label = "volume_down"; + gpios = <&pm8998_gpios 5 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = <114>; + debounce-interval = <15>; + linux,can-disable; + }; + //add end. + //disable cam_snapshot,and cam_focus + cam_snapshot { + status = "disabled"; + }; + cam_focus { + status = "disabled"; + }; +}; + +}; + +&pm8998_gpios { + //VENDOR_EIDT + key_vol_down { + key_vol_down_default: key_vol_down_default { + pins = "gpio5"; + function = "normal"; + input-enable; + bias-pull-up; + power-source = <0>; + }; + }; +}; + +//add for volume down function ,and we do not use qbt1000 fingerprint sensor. +&soc{ + qcom,qbt1000 { + compatible = "qcom,qbt1000"; + clock-names = "core", "iface"; + clock-frequency = <25000000>; + qcom,ipc-gpio = <&tlmm 121 0>; + qcom,finger-detect-gpio = <&pm8998_gpios 5 0>; + status = "disabled"; + }; + +}; + +&qupv3_se4_i2c { + status = "ok"; + tfa98xx@34 { + compatible = "nxp,tfa9894"; + reg = <0x34>; + reset-gpio = <&tlmm 69 0>; + status = "ok"; + }; +}; + +&pmi8998_gpios { + gpio10_dig_out { + gpio10_dig_out_default: gpio10_dig_out_default { + pins = "gpio10"; /* GPIO 14 */ + function = "normal"; /* normal output */ + power-source = <0>; /* VIN0 */ + output-low; /* digital output, no invert */ + input-disable; /* prevent GPIO from being set to DIO */ + }; + }; +}; + +&pmi8998_gpios { + gpio6_dig_out { + gpio6_dig_out_default: gpio6_dig_out_default { + pins = "gpio6"; /* GPIO 6 */ + function = "normal"; /* normal output */ + power-source = <1>; /* VIN0 */ + output-low; /* digital output, no invert */ + input-disable; /* prevent GPIO from being set to DIO */ + }; + }; +}; + +&pmi8998_gpios { + qnovo_fet_ctrl { + qnovo_fet_ctrl_default: qnovo_fet_ctrl_default { + pins = "gpio6"; + function = "normal"; + output-low; + input-disable; + bias-disable; + power-source = <1>; + qcom,drive-strength = <1>; + }; + }; +}; + + +//suzhiguang,add for fsa4480 +&qupv3_se7_i2c { + status = "ok"; + fsa4480@42 { + compatible = "fsa,fsa4480"; + reg = <0x42>; + mbhc_en = <&pmi8998_gpios 10 GPIO_ACTIVE_LOW>; + status = "ok"; + }; +}; +//suzhiguang,add for switch +&slim_aud { + tavil_codec { + op,usb_sw; + usb_sw = <&pmi8998_gpios 10 GPIO_ACTIVE_LOW>; + hp_sw = <&tlmm 103 0>; + mbhc_sw = <&tlmm 36 1>; + ldo_sw = <&pmi8998_gpios 6 GPIO_ACTIVE_LOW>; + }; +}; +&qupv3_se12_i2c { + status = "ok"; + synaptics-rmi-ts@20 { + compatible = "HWK,synaptics,s3320"; + reg = <0x20>; + interrupt-parent = <&tlmm>; + interrupts = <125 0x2008>; + //vcc_i2c_1v8-supply = <&pm8998_l6>; + vdd_2v8-supply = <&pm8998_l28>; + synaptics,tx-rx-num = <15 30>; + //synaptics,vdd-voltage = <1808000 1808000>; + synaptics,avdd-voltage = <3008000 3008000>; + //synaptics,vdd-current = <40000>; + synaptics,avdd-current = <20000>; + synaptics,display-coords = <1080 2160>; + synaptics,panel-coords = <1080 2160>; + synaptics,reset-gpio = <&tlmm 99 0x00>; + synaptics,irq-gpio = <&tlmm 125 0x2008>; + synaptics,1v8-gpio = <&tlmm 88 0x00>; + oem,support_1080x2160_tp; + oem,support_1080x2340_tp; + oem,support_hw_poweroff; + pinctrl-names = "pmx_ts_active", "pmx_ts_suspend"; + pinctrl-0 = <&ts_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + oem,fajta; + }; +}; + + +&wsa881x_0211{ +status = "disabled"; +}; + +&wsa881x_0212{ +status = "disabled"; +}; + +&wsa881x_0213{ +status = "disabled"; +}; + +&wsa881x_0214{ +status = "disabled"; +}; + +&dai_mi2s3 { + qcom,msm-mi2s-rx-lines = <2>; + qcom,msm-mi2s-tx-lines = <1>; + pinctrl-names = "default", "sleep"; + pinctrl-0 = <&quat_mi2s_active + &quat_mi2s_sd0_active &quat_mi2s_sd1_active >; + pinctrl-1 = <&quat_mi2s_sleep + &quat_mi2s_sd0_sleep &quat_mi2s_sd1_sleep >; +}; + +&dsi_nt35597_truly_dsc_cmd_display { + /delete-property/qcom,dsi-display-active; +}; + +&mdss_dsi1 { +status = "disabled"; +}; + +&mdss_dsi0_pll { + qcom,ssc-frequency-hz = <33000>; +}; + +&sde_dp { + qcom,aux-en-gpio = <&tlmm 122 0>; + qcom,aux-sel-gpio = <&tlmm 123 0>; + qcom,usbplug-cc-gpio = <&tlmm 38 0>; +}; + +&dsi_samsung_s6e3fc1_cmd { + qcom,dsi-display-active; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_no_labibb_2>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-brightness-max-level = <1023>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,platform-vci-gpio = <&tlmm 26 0>; + qcom,platform-poc-gpio = <&tlmm 25 0>; +}; + +&dsi_samsung_s6e3fc1_cmd { + qcom,mdss-dsi-t-clk-post = <0x0E>; + qcom,mdss-dsi-t-clk-pre = <0x34>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 21 09 09 25 23 09 + 09 06 03 04 00]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_samsung_sofef00_m_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_no_labibb_2>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-brightness-max-level = <1023>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,platform-vci-gpio = <&tlmm 26 0>; + qcom,platform-poc-gpio = <&tlmm 25 0>; +}; + +&dsi_samsung_sofef00_m_cmd { + qcom,mdss-dsi-t-clk-post = <0x0E>; + qcom,mdss-dsi-t-clk-pre = <0x36>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 23 09 09 26 24 09 + 09 06 03 04 00]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_samsung_sofef00_m_video { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_no_labibb_2>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-brightness-max-level = <1023>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,platform-vci-gpio = <&tlmm 26 0>; + qcom,platform-poc-gpio = <&tlmm 25 0>; +}; + +&dsi_samsung_sofef00_m_video { + qcom,mdss-dsi-t-clk-post = <0x0E>; + qcom,mdss-dsi-t-clk-pre = <0x36>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 23 09 09 26 24 09 + 09 06 03 04 00]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_samsung_sofeg01_s_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_no_labibb_2>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-brightness-max-level = <1023>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,platform-vci-gpio = <&tlmm 26 0>; + qcom,platform-poc-gpio = <&tlmm 25 0>; +}; + +&dsi_samsung_sofeg01_s_cmd { + qcom,mdss-dsi-t-clk-post = <0x0E>; + qcom,mdss-dsi-t-clk-pre = <0x36>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 23 09 09 26 24 09 + 09 06 03 04 00]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_samsung_s6e3fc2x01_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_no_labibb_2>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-brightness-max-level = <1023>; + qcom,mdss-brightness-default-val = <200>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,platform-vci-gpio = <&tlmm 26 0>; + qcom,platform-poc-gpio = <&tlmm 25 0>; +}; + +&dsi_samsung_s6e3fc2x01_cmd { + qcom,mdss-dsi-t-clk-post = <0x0E>; + qcom,mdss-dsi-t-clk-pre = <0x35>; + qcom,mdss-dsi-panel-clockrate = <1037000000>;// 518.5MHZ + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 22 09 09 25 24 09 + 09 06 03 04 00]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; +}; +}; + + +&dsi_samsung_dsc_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply_no_labibb_2>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-brightness-max-level = <1023>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <1023>; + qcom,platform-reset-gpio = <&tlmm 6 0>; + qcom,platform-vci-gpio = <&tlmm 26 0>; + qcom,platform-poc-gpio = <&tlmm 25 0>; +}; + +&dsi_samsung_dsc_cmd { + qcom,mdss-dsi-t-clk-post = <0x0E>; + qcom,mdss-dsi-t-clk-pre = <0x35>; + //qcom,mdss-dsi-panel-clockrate = <1037000000>;// 518.5MHZ + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 14 05 05 1F 0A 05 + 05 03 03 04 00]; + qcom,display-topology = <1 1 1>, + <2 2 1>, /* dsc merge */ + <2 1 1>; /* 3d mux */ + qcom,default-topology-index = <1>; + }; + }; +}; + +&qupv3_se4_i2c { + status = "ok"; + max98927@3a { + compatible = "maxim,max98927L"; + reg = <0x3a>; + mono_stereo_mode = <0>; + maxim,98927-reset-gpio = <&tlmm 69 0>; + status = "disabled"; + }; +}; + +/* Infi@bsp,20171130 usb-phy0 usb eye-diagram tunning */ +/* modify 0x240:0x45->0x47, 0x244:0x29->0x2b, 0x198:0x20->0x12*/ +/* add op host mode phy init parameters modify 0x198:0x20->0x21*/ +&qusb_phy0 { + qcom,usb-oe-exist; + qcom,overwrite-bias2-disable; + qcom,qusb-phy-init-seq = + /* */ + <0x23 0x210 /* PWR_CTRL1 */ + 0x03 0x04 /* PLL_ANALOG_CONTROLS_TWO */ + 0x7c 0x18c /* PLL_CLOCK_INVERTERS */ + 0x80 0x2c /* PLL_CMODE */ + 0x0a 0x184 /* PLL_LOCK_DELAY */ + 0x19 0xb4 /* PLL_DIGITAL_TIMERS_TWO */ + 0x40 0x194 /* PLL_BIAS_CONTROL_1 */ + 0x12 0x198 /* PLL_BIAS_CONTROL_2 */ + 0x21 0x214 /* PWR_CTRL2 */ + 0x07 0x220 /* IMP_CTRL1 */ + 0x58 0x224 /* IMP_CTRL2 */ + 0x47 0x240 /* TUNE1 */ + 0x2b 0x244 /* TUNE2 */ + 0xca 0x248 /* TUNE3 */ + 0x04 0x24c /* TUNE4 */ + 0x03 0x250 /* TUNE5 */ + 0x00 0x23c /* CHG_CTRL2 */ + 0x22 0x210>; /* PWR_CTRL1 */ + + qcom,qusb-phy-ophost-init-seq = + /* */ + <0x23 0x210 /* PWR_CTRL1 */ + 0x03 0x04 /* PLL_ANALOG_CONTROLS_TWO */ + 0x7c 0x18c /* PLL_CLOCK_INVERTERS */ + 0x80 0x2c /* PLL_CMODE */ + 0x0a 0x184 /* PLL_LOCK_DELAY */ + 0x19 0xb4 /* PLL_DIGITAL_TIMERS_TWO */ + 0x40 0x194 /* PLL_BIAS_CONTROL_1 */ + 0x21 0x198 /* PLL_BIAS_CONTROL_2 */ + 0x21 0x214 /* PWR_CTRL2 */ + 0x07 0x220 /* IMP_CTRL1 */ + 0x58 0x224 /* IMP_CTRL2 */ + 0x46 0x240 /* TUNE1 */ + 0x2b 0x244 /* TUNE2 */ + 0xca 0x248 /* TUNE3 */ + 0x04 0x24c /* TUNE4 */ + 0x03 0x250 /* TUNE5 */ + 0x00 0x23c /* CHG_CTRL2 */ + 0x22 0x210>; /* PWR_CTRL1 */ +}; + +&pmi8998_pdphy { + vbus-supply = <&smb2_vbus>; +}; + +/* david@bsp, 20171023 Battery & Charging porting STRAT */ +&qupv3_se10_i2c { + qcom,clk-freq-out = <100000>; + bq27541_battery:bq27541-battery@55 { + status = "ok"; + compatible = "ti,bq27541-battery"; + reg = <0x55>; + qcom,modify-soc-smooth; + }; + + oneplus_fastchg:oneplus_fastchg@26{ + status = "ok"; + compatible = "microchip,oneplus_fastchg"; + reg = <0x26>; + microchip,mcu-en-gpio = <&tlmm 102 0x00>; + microchip,usb-sw-1-gpio = <&tlmm 37 0x00>; + microchip,usb-sw-2-gpio = <&tlmm 51 0x00>; + microchip,ap-clk = <&tlmm 43 0x00>; + microchip,ap-data = <&tlmm 44 0x00>; + + pinctrl-names = "mux_fastchg_active", + "mux_fastchg_suspend", + "mcu_data_active", + "mcu_data_suspend"; + pinctrl-0 = <&fastchg_active + &usb_sw_active + &ap_clk_active>; + pinctrl-1 = <&usb_sw_suspend + &fastchg_suspend + &ap_clk_suspend>; + pinctrl-2 =<&ap_data_active>; + pinctrl-3 =<&ap_data_suspend>; + }; +}; + +&mtp_batterydata{ + #include "OP-batterydata-3700mah.dtsi" +}; + +&pm8998_gpios { + gpio12_adc { + gpio12_adc_default: gpio12_adc_default { + pins = "gpio12"; /* GPIO 12 */ + function = "normal"; /* normal */ + bias-pull-up; + bias-high-impedance; /* DISABLE GPIO12 for ADC*/ + }; + }; +}; + +&pm8998_vadc { + chan@36 { + label = "gpio12_adc"; + reg = <0x36>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "absolute"; + qcom,scale-function = <0>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + }; +}; + +&pmi8998_charger { + qcom,dc-icl-ua = <1200000>; + qcom,fcc-max-ua = <500000>; + qcom,usb-icl-ua = <1800000>; + qcom,fv-max-uv = <4365000>; + /* ibatmax setting for different temp regions */ + ibatmax-little-cold-ma = <325>; + ibatmax-cool-ma = <500>; + ibatmax-little-cool-ma = <875>; + ibatmax-little-cool-low_ma = <450>; + ibatmax-pre-normal-ma = <1625>; + ibatmax-normal-ma = <1950>; + ibatmax-warm-ma = <875>; + /* vbatmax setting for different temp regions */ + vbatmax-little-cold-mv = <3975>; + vbatmax-cool-mv = <4400>; + vbatmax-little-cool-mv = <4400>; + vbatmax-pre-normal-mv = <4400>; + vbatmax-normal-mv = <4400>; + vbatmax-warm-mv = <4080>; + little-cool-vbat-thr-mv = <4180>; + /* vbatdet setting for different temp regions */ + vbatdet-little-cold-mv = <3700>; + vbatdet-cool-mv = <4150>; + vbatdet-little-cool-mv = <4270>; + vbatdet-pre-normal-mv = <4270>; + vbatdet-normal-mv = <4270>; + vbatdet-warm-mv = <3980>; + + /*ffc temp region*/ + ffc-pre-normal-decidegc = <160>; + 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 = <4430>; + + /* temp region settings */ + cold-bat-decidegc = <30>; + 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 = <530>; + op,sw-iterm-ma = <296>; + op,sw-check-full-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>; + /* other settings */ + qcom,cutoff-voltage-with-charger = <3250>; + disable-pd; + op,usb-check = <&tlmm 95 0x00>; + 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>; + + qcom,usb-temp-vadc = <&pm8998_vadc>; + op,vbus-ctrl-gpio = <&pmi8998_gpios 3 GPIO_ACTIVE_LOW>; + +}; + +&pmi8998_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>; +}; + +&qusb_phy0 { + pinctrl-names = "atest_usb13_suspend", "atest_usb13_active", + "usb_oe_suspend", "usb_oe_active"; + pinctrl-0 = <&atest_usb13_suspend>; + pinctrl-1 = <&atest_usb13_active>; + pinctrl-2 = <&usb_oe_suspend>; + pinctrl-3 = <&usb_oe_active>; +}; + +&tlmm { + hp_sw_active: hp_sw_active { + mux { + pins = "gpio103"; + function = "gpio"; + }; + + config { + pins = "gpio103"; + drive-strength = <2>; + bias-pull-up; + }; + }; + + hp_sw_suspend: hp_sw_suspend { + mux { + pins = "gpio103"; + function = "gpio"; + }; + + config { + pins = "gpio103"; + bias-pull-down; + drive-strength = <2>; + }; + }; + + atest_usb13_active: atest_usb13_active { + mux { + pins = "gpio7"; + function = "gpio"; + }; + + config { + pins = "gpio7"; + drive-strength = <12>; + bias-pull-up; + }; + }; + + atest_usb13_suspend: atest_usb13_suspend { + mux { + pins = "gpio7"; + function = "gpio"; + }; + + config { + pins = "gpio7"; + bias-pull-down; + drive-strength = <2>; + }; + }; + + usb_oe_active: usb_oe_active { + mux { + pins = "gpio87"; + function = "gpio"; + }; + + config { + pins = "gpio87"; + drive-strength = <12>; + bias-pull-up; + }; + }; + + usb_oe_suspend: usb_oe_suspend { + mux { + pins = "gpio87"; + function = "gpio"; + }; + + config { + pins = "gpio87"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + oneplus_fastchg { + usb_sw_active: usb_sw_active { + mux { + pins = "gpio37", "gpio51"; + function = "gpio"; + }; + + config { + pins = "gpio37", "gpio51"; + drive-strength = <16>; + bias-pull-down; + }; + }; + + usb_sw_suspend: usb_sw_suspend { + mux { + pins = "gpio37", "gpio51"; + function = "gpio"; + }; + + config { + pins = "gpio37", "gpio51"; + drive-strength = <2>; + bias-disable; + }; + }; + + fastchg_active: fastchg_active { + mux { + pins = "gpio102"; + function = "gpio"; + }; + + config { + pins = "gpio102"; + drive-strength = <16>; + bias-pull-up; + }; + }; + + fastchg_suspend: fastchg_suspend { + mux { + pins = "gpio102"; + function = "gpio"; + }; + + config { + pins = "gpio102"; + drive-strength = <2>; + bias-disable; + }; + }; + + ap_clk_active: ap_clk_active { + mux { + pins = "gpio44"; + function = "gpio"; + }; + + config { + pins = "gpio44"; + drive-strength = <16>; + bias-pull-up; + }; + }; + + ap_clk_suspend: ap_clk_suspend { + mux { + pins = "gpio44"; + function = "gpio"; + }; + + config { + pins = "gpio44"; + drive-strength = <2>; + bias-disable; + }; + }; + + ap_data_active: ap_data_active { + mux { + pins = "gpio43"; + function = "gpio"; + }; + + config { + pins = "gpio43"; + drive-strength = <16>; + bias-pull-up; + }; + }; + + ap_data_suspend: ap_data_suspend { + mux { + pins = "gpio43"; + function = "gpio"; + }; + + config { + pins = "gpio43"; + drive-strength = <2>; + bias-disable; + }; + }; + }; +}; + +&pcie0 { + status = "disabled"; +}; + +&pcie1 { + status = "disabled"; +}; +/* david@bsp, 20171023 Battery & Charging porting END */ + +&qupv3_se3_i2c { + status = "ok"; + nq@28 { + qcom,nq-firm = <&tlmm 62 0x00>; + + }; +}; + +&pmi8998_wled { + status = "disabled"; +}; + +&dsi_nt35597_truly_dsc_cmd_display { + status = "disabled"; +}; +&mdss_mdp { + connectors = <&sde_rscc &sde_wb>; +}; +&sde_dp{ + status = "disabled"; +}; + +&labibb { + status = "disabled"; +}; +&sdhc_2 { + status = "disabled"; +}; + +&pm8998_rtc { + compatible = "qcom,qpnp-rtc"; + qcom,qpnp-rtc-alarm-pwrup = <1>; +}; + +&pmi8998_haptics { + status = "okay"; + qcom,wave-shape = "sine"; + qcom,play-mode = "buffer"; + qcom,brake-pattern = <0x3 0x3 0x3 0x3>; + qcom,drive-period-code-max-variation-pct = <5>; + qcom,drive-period-code-min-variation-pct = <5>; + qcom,wave-rep-cnt = <1>; + qcom,wave-samp-rep-cnt = <1>; + qcom,vmax-mv = <2088>; + qcom,wave-play-rate-us = <4255>; + qcom,lra-auto-res-mode = "zxd-eop"; + qcom,lra-res-cal-period = <32>; +}; + +&red_led { + qcom,use-blink; + qcom,duty-pcts = [00 05 0a 0f 14 1d 28 32 3c 4b 64]; + qcom,duty-ms = <20>; + qcom,start-idx = <1>; + qcom,idx-len = <11>; + qcom,lut-flags = <0x1f>; + qcom,ramp-step-ms = <100>; + qcom,pause-lo = <2000>; + qcom,pause-hi = <1000>; + /delete-property/ linux,default-trigger; +}; + +&green_led { + qcom,use-blink; + qcom,duty-pcts = [00 05 0a 0f 14 1d 28 32 3c 4b 64]; + qcom,duty-ms = <20>; + qcom,start-idx = <13>; + qcom,idx-len = <11>; + qcom,lut-flags = <0x1f>; + qcom,ramp-step-ms = <100>; + qcom,pause-lo = <2000>; + qcom,pause-hi = <1000>; + /delete-property/ linux,default-trigger; +}; + +&blue_led { + qcom,use-blink; + qcom,duty-pcts = [00 05 0a 0f 14 1d 28 32 3c 4b 64]; + qcom,duty-ms = <20>; + qcom,start-idx = <13>; + qcom,idx-len = <11>; + qcom,lut-flags = <0x1f>; + qcom,ramp-step-ms = <100>; + qcom,pause-lo = <2000>; + qcom,pause-hi = <1000>; + /delete-property/ linux,default-trigger; +}; + +&sde_dsi_active { + mux { + pins = "gpio6", "gpio25", "gpio26"; + function = "gpio"; + }; + + config { + pins = "gpio6", "gpio25", "gpio26"; + drive-strength = <8>; /* 8 mA */ + bias-disable = <0>; /* no pull */ + }; + }; +&sde_dsi_suspend { + mux { + pins = "gpio6", "gpio25", "gpio26"; + function = "gpio"; + }; + + config { + pins = "gpio6", "gpio25", "gpio26"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* PULL DOWN */ + }; + }; + +&sde_dp_aux_active { + mux { + pins = "gpio122", "gpio123"; + function = "gpio"; + }; + + config { + pins = "gpio122", "gpio123"; + bias-disable = <0>; /* no pull */ + drive-strength = <8>; + }; +}; + +&sde_dp_aux_suspend { + mux { + pins = "gpio122", "gpio123"; + function = "gpio"; + }; + + config { + pins = "gpio122", "gpio123"; + bias-pull-down; + drive-strength = <2>; + }; +}; + +&tlmm { + fp_enable_init: fp_enable_init { + mux { + pins = "gpio80"; + function = "gpio"; + }; + + config { + pins = "gpio80"; + drive-strength = <8>; + bias-pull-up; + output-high; + }; + }; + + fp_irq_init: fp_irq_init { + mux { + pins = "gpio121"; + function = "gpio"; + }; + + config { + pins = "gpio121"; + drive-strength = <2>; + bias-disable; + input-enable; + }; + }; + + fp_disable_init: fp_disable_init { + mux { + pins = "gpio80"; + function = "gpio"; + }; + + config { + pins = "gpio80"; + drive-strength = <8>; + bias-pull-up; + output-low; + }; + }; + + fp_reset_init: fp_reset_init { + mux { + pins = "gpio35"; + function = "gpio"; + }; + + config { + pins = "gpio35"; + drive-strength = <8>; + bias-pull-up; + }; + }; + + fp_reset_high: fp_reset_high { + mux { + pins = "gpio35"; + function = "gpio"; + }; + + config { + pins = "gpio35"; + drive-strength = <8>; + bias-pull-up; + output-high; + }; + }; + + fp_reset_low: fp_reset_low { + mux { + pins = "gpio35"; + function = "gpio"; + }; + + config { + pins = "gpio35"; + drive-strength = <8>; + bias-pull-up; + output-low; + }; + }; + + fp_id0_up: fp_id0_up { + mux { + pins = "gpio91"; + function = "gpio"; + }; + + config { + pins = "gpio91"; + drive-strength = <2>; + bias-pull-up; + input-enable; + }; + }; + + fp_id0_down: fp_id0_down { + mux { + pins = "gpio91"; + function = "gpio"; + }; + + config { + pins = "gpio91"; + drive-strength = <2>; + bias-disable; + input-enable; + }; + }; + tri_state_key_active: tri_state_key_active { + mux { + pins = "gpio24","gpio52","gpio126"; + function = "gpio"; + }; + + config { + pins = "gpio24","gpio52","gpio126"; + drive-strength = <2>; + bias-disable; + }; + }; + + tri_state_key_suspend: tri_state_key_suspend { + mux { + pins = "gpio24","gpio52","gpio126"; + function = "gpio"; + }; + + config { + pins = "gpio24","gpio52","gpio126"; + drive-strength = <2>; + bias-disable; + }; + }; + + esd_check_active: esd_check_active { + mux { + pins = "gpio30"; + function = "gpio"; + }; + config { + pins = "gpio30"; + drive-strength = <2>; + bias-pull-down; + input-enable; + }; + }; + esd_check_suspend: esd_check_suspend { + mux { + pins = "gpio30"; + function = "gpio"; + }; + config { + pins = "gpio30"; + drive-strength = <2>; + bias-pull-down; + input-enable; + }; + }; +}; +/*#endif*/ + + +//overlay for camera start +&tlmm { + cam_sensor_rear_0_mclk_active: cam_sensor_rear_0_mclk_active { + /* MCLK0 */ + mux { + /* CLK, DATA */ + pins = "gpio13"; + function = "cam_mclk"; + }; + + config { + pins = "gpio13"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_0_mclk_suspend: cam_sensor_rear_0_mclk_suspend { + /* MCLK0 */ + mux { + /* CLK, DATA */ + pins = "gpio13"; + function = "cam_mclk"; + }; + + config { + pins = "gpio13"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_0_rest_active: cam_sensor_rear_0_rest_active { + /* RESET, STANDBY */ + mux { + pins = "gpio28"; + function = "gpio"; + }; + + config { + pins = "gpio28"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_0_rest_suspend: cam_sensor_rear_0_rest_suspend { + /* RESET, STANDBY */ + mux { + pins = "gpio28"; + function = "gpio"; + }; + + config { + pins = "gpio28"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_0_ana_active: cam_sensor_rear_0_ana_active { + /* VANA */ + mux { + pins = "gpio27"; + function = "gpio"; + }; + + config { + pins = "gpio27"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_0_ana_suspend: cam_sensor_rear_0_ana_suspend { + /* VANA */ + mux { + pins = "gpio27"; + function = "gpio"; + }; + + config { + pins = "gpio27"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_0_dig_active: cam_sensor_rear_0_dig_active { + /* DIG */ + mux { + pins = "gpio8"; + function = "gpio"; + }; + + config { + pins = "gpio8"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_0_dig_suspend: cam_sensor_rear_0_dig_suspend { + /* DIG */ + mux { + pins = "gpio8"; + function = "gpio"; + }; + + config { + pins = "gpio8"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_0_vaf_active: cam_sensor_rear_0_vaf_active { + /* ACTUATOR POWER */ + mux { + pins = "gpio31"; + function = "gpio"; + }; + + config { + pins = "gpio31"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_0_vaf_suspend: cam_sensor_rear_0_vaf_suspend { + /* ACTUATOR POWER */ + mux { + pins = "gpio31"; + function = "gpio"; + }; + + config { + pins = "gpio31"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_1_mclk_active: cam_sensor_rear_1_mclk_active { + /* MCLK1 */ + mux { + /* CLK, DATA */ + pins = "gpio15"; + function = "cam_mclk"; + }; + + config { + pins = "gpio15"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_1_mclk_suspend: cam_sensor_rear_1_mclk_suspend { + /* MCLK1 */ + mux { + /* CLK, DATA */ + pins = "gpio15"; + function = "cam_mclk"; + }; + + config { + pins = "gpio15"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_1_rest_active: cam_sensor_rear_1_rest_active { + /* RESET, STANDBY */ + mux { + pins = "gpio23"; + function = "gpio"; + }; + + config { + pins = "gpio23"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_1_rest_suspend: cam_sensor_rear_1_rest_suspend { + /* RESET, STANDBY */ + mux { + pins = "gpio23"; + function = "gpio"; + }; + config { + pins = "gpio23"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_1_ana_active: cam_sensor_rear_1_ana_active { + /* VANA */ + mux { + pins = "gpio78"; + function = "gpio"; + }; + + config { + pins = "gpio78"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_1_ana_suspend: cam_sensor_rear_1_ana_suspend { + /* VANA */ + mux { + pins = "gpio78"; + function = "gpio"; + }; + + config { + pins = "gpio78"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_1_vaf_active: cam_sensor_rear_1_vaf_active { + /* ACTUATOR POWER */ + mux { + pins = "gpio77"; + function = "gpio"; + }; + + config { + pins = "gpio77"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_1_vaf_suspend: cam_sensor_rear_1_vaf_suspend { + /* ACTUATOR POWER */ + mux { + pins = "gpio77"; + function = "gpio"; + }; + + config { + pins = "gpio77"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_1_dig_active: cam_sensor_rear_1_dig_active { + /* DIG */ + mux { + pins = "gpio79"; + function = "gpio"; + }; + + config { + pins = "gpio79"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_rear_1_dig_suspend: cam_sensor_rear_1_dig_suspend { + /* DIG */ + mux { + pins = "gpio79"; + function = "gpio"; + }; + + config { + pins = "gpio79"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_0_mclk_active: cam_sensor_front_0_mclk_active { + /* MCLK2 */ + mux { + /* CLK, DATA */ + pins = "gpio14"; + function = "cam_mclk"; + }; + + config { + pins = "gpio14"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_0_mclk_suspend: + cam_sensor_front_0_mclk_suspend { + /* MCLK2 */ + mux { + /* CLK, DATA */ + pins = "gpio14"; + function = "cam_mclk"; + }; + + config { + pins = "gpio14"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_0_rest_active: + cam_sensor_front_0_rest_active { + /* RESET, STANDBY */ + mux { + pins = "gpio9"; + function = "gpio"; + }; + + config { + pins = "gpio9"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_0_rest_suspend: + cam_sensor_front_0_rest_suspend { + /* RESET, STANDBY */ + mux { + pins = "gpio9"; + function = "gpio"; + }; + + config { + pins = "gpio9"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_0_ana_active: + cam_sensor_front_0_ana_active { + /* VANA */ + mux { + pins = "gpio104"; + function = "gpio"; + }; + + config { + pins = "gpio104"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_0_ana_suspend: + cam_sensor_front_0_ana_suspend { + /* VANA */ + mux { + pins = "gpio104"; + function = "gpio"; + }; + + config { + pins = "gpio104"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_0_dig_active: + cam_sensor_front_0_dig_active { + /* DIG */ + mux { + pins = "gpio117"; + function = "gpio"; + }; + + config { + pins = "gpio117"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; + }; + + cam_sensor_front_0_dig_suspend: + cam_sensor_front_0_dig_suspend { + /* DIG */ + mux { + pins = "gpio117"; + function = "gpio"; + }; + + config { + pins = "gpio117"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + }; + }; +}; + +&soc { + led_flash_rear: qcom,camera-flash@0 { + cell-index = <0>; + reg = <0x00 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pmi8998_flash0 &pmi8998_flash1>; + torch-source = <&pmi8998_torch0 &pmi8998_torch1>; + switch-source = <&pmi8998_switch0>; + status = "ok"; + }; + + rear_1_actuator_regulator: gpio-regulator@1 { + compatible = "regulator-fixed"; + reg = <0x01 0x00>; + regulator-name = "actuator_regulator"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-enable-ramp-delay = <100>; + enable-active-high; + gpio = <&tlmm 77 0>; + vin-supply = <&pmi8998_bob>; + }; + + rear_0_actuator_regulator: gpio-regulator@0 { + compatible = "regulator-fixed"; + reg = <0x00 0x00>; + regulator-name = "actuator_regulator"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-enable-ramp-delay = <100>; + enable-active-high; + gpio = <&tlmm 31 0>; + vin-supply = <&pmi8998_bob>; + }; +}; + +&cam_cci { + qcom,cam-res-mgr { + compatible = "qcom,cam-res-mgr"; + status = "ok"; + }; + + actuator_rear_0: qcom,actuator@0 { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,actuator"; + cci-master = <0>; + cam_vaf-supply = <&rear_0_actuator_regulator>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; + }; + + actuator_rear_1: qcom,actuator@1 { + cell-index = <1>; + reg = <0x1>; + compatible = "qcom,actuator"; + cci-master = <1>; + cam_vaf-supply = <&rear_1_actuator_regulator>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; + }; + + ois_rear_0: qcom,ois@0 { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,ois"; + cam_vaf-supply = <&pm8998_l21>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2850000>; + rgltr-max-voltage = <2850000>; + rgltr-load-current = <500000>; + gpio-no-mux = <0>; + gpios = <&tlmm 40 0>; + gpio-vaf = <0>; + gpio-req-tbl-num = <0>; + gpio-req-tbl-flags = <0>; + gpio-req-tbl-label = "CAM_OIS_PWD_0"; + cci-master = <0>; + status = "ok"; + }; + + eeprom_rear_0: qcom,eeprom@0 { + cell-index = <0>; + reg = <0>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pm8998_lvs1>; + cam_vana-supply = <&pmi8998_bob>; + cam_vdig-supply = <&pmi8998_bob>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 3312000 3312000 0>; + rgltr-max-voltage = <0 3600000 3600000 0>; + rgltr-load-current = <0 3600000 3600000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_rear_0_mclk_active + &cam_sensor_rear_0_rest_active + &cam_sensor_rear_0_ana_active + &cam_sensor_rear_0_dig_active>; + pinctrl-1 = <&cam_sensor_rear_0_mclk_suspend + &cam_sensor_rear_0_rest_suspend + &cam_sensor_rear_0_ana_suspend + &cam_sensor_rear_0_dig_suspend>; + gpios = <&tlmm 13 0>, + <&tlmm 28 0>, + <&tlmm 27 0>, + <&tlmm 8 0>; + 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_MCLK_0", + "CAM_RESET_0", + "CAM_VANA_0", + "CAM_DIG_0"; + 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_1: qcom,eeprom@1 { + cell-index = <1>; + reg = <0x1>; + compatible = "qcom,eeprom"; + cam_vdig-supply = <&pmi8998_bob>; + cam_vio-supply = <&pm8998_lvs1>; + cam_vana-supply = <&pmi8998_bob>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vdig", "cam_vio", "cam_vana", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <3312000 0 3312000 0>; + rgltr-max-voltage = <3600000 0 3600000 0>; + rgltr-load-current = <80000 0 80000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_rear_1_mclk_active + &cam_sensor_rear_1_rest_active + &cam_sensor_rear_1_ana_active + &cam_sensor_rear_1_dig_active>; + pinctrl-1 = <&cam_sensor_rear_1_mclk_suspend + &cam_sensor_rear_1_rest_suspend + &cam_sensor_rear_1_ana_suspend + &cam_sensor_rear_1_dig_suspend>; + gpios = <&tlmm 15 0>, + <&tlmm 23 0>, + <&tlmm 78 0>, + <&tlmm 79 0>; + 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_MCLK_1", + "CAM_RESET_1", + "CAM_VANA_1", + "CAM_DIG_1"; + + 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_front_0: qcom,eeprom@2 { + cell-index = <2>; + reg = <0x2>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&pm8998_lvs1>; + cam_vana-supply = <&pmi8998_bob>; + cam_vdig-supply = <&pmi8998_bob>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 3312000 3312000 0>; + rgltr-max-voltage = <0 3600000 3600000 0>; + rgltr-load-current = <0 80000 80000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_front_0_mclk_active + &cam_sensor_front_0_rest_active + &cam_sensor_front_0_ana_active + &cam_sensor_front_0_dig_active>; + pinctrl-1 = <&cam_sensor_front_0_mclk_suspend + &cam_sensor_front_0_rest_suspend + &cam_sensor_front_0_ana_suspend + &cam_sensor_front_0_dig_suspend>; + gpios = <&tlmm 14 0>, + <&tlmm 9 0>, + <&tlmm 104 0>, + <&tlmm 117 0>; + 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_MCLK_2", + "CAM_RESET_2", + "CAM_VANA_2", + "CAM_DIG_2"; + sensor-position = <1>; + 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-sensor@0 { + cell-index = <0>; + compatible = "qcom,cam-sensor"; + reg = <0x0>; + csiphy-sd-index = <0>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + led-flash-src = <&led_flash_rear>; + actuator-src = <&actuator_rear_0>; + ois-src = <&ois_rear_0>; + eeprom-src = <&eeprom_rear_0>; + cam_vio-supply = <&pm8998_lvs1>; + cam_vana-supply = <&pmi8998_bob>; + cam_vdig-supply = <&pmi8998_bob>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 3312000 3312000 0>; + rgltr-max-voltage = <0 3600000 3600000 0>; + rgltr-load-current = <0 3600000 3600000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_rear_0_mclk_active + &cam_sensor_rear_0_rest_active + &cam_sensor_rear_0_ana_active + &cam_sensor_rear_0_dig_active>; + pinctrl-1 = <&cam_sensor_rear_0_mclk_suspend + &cam_sensor_rear_0_rest_suspend + &cam_sensor_rear_0_ana_suspend + &cam_sensor_rear_0_dig_suspend>; + gpios = <&tlmm 13 0>, + <&tlmm 28 0>, + <&tlmm 27 0>, + <&tlmm 8 0>; + 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_MCLK_0", + "CAM_RESET_0", + "CAM_VANA_0", + "CAM_DIG_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>; + }; + + qcom,cam-sensor@1 { + cell-index = <1>; + compatible = "qcom,cam-sensor"; + reg = <0x1>; + csiphy-sd-index = <1>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + led-flash-src = <&led_flash_rear>; + actuator-src = <&actuator_rear_1>; + eeprom-src = <&eeprom_rear_1>; + cam_vdig-supply = <&pmi8998_bob>; + cam_vio-supply = <&pm8998_lvs1>; + cam_vana-supply = <&pmi8998_bob>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vdig", "cam_vio", "cam_vana", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <3312000 0 3312000 0>; + rgltr-max-voltage = <3600000 0 3600000 0>; + rgltr-load-current = <80000 0 80000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_rear_1_mclk_active + &cam_sensor_rear_1_rest_active + &cam_sensor_rear_1_ana_active + &cam_sensor_rear_1_dig_active>; + pinctrl-1 = <&cam_sensor_rear_1_mclk_suspend + &cam_sensor_rear_1_rest_suspend + &cam_sensor_rear_1_ana_suspend + &cam_sensor_rear_1_dig_suspend>; + gpios = <&tlmm 15 0>, + <&tlmm 23 0>, + <&tlmm 78 0>, + <&tlmm 79 0>; + 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_MCLK_1", + "CAM_RESET_1", + "CAM_VANA_1", + "CAM_DIG_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-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 = <&pm8998_lvs1>; + cam_vana-supply = <&pmi8998_bob>; + cam_vdig-supply = <&pmi8998_bob>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + rgltr-min-voltage = <0 3312000 3312000 0>; + rgltr-max-voltage = <0 3600000 3600000 0>; + rgltr-load-current = <0 80000 80000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_front_0_mclk_active + &cam_sensor_front_0_rest_active + &cam_sensor_front_0_ana_active + &cam_sensor_front_0_dig_active>; + pinctrl-1 = <&cam_sensor_front_0_mclk_suspend + &cam_sensor_front_0_rest_suspend + &cam_sensor_front_0_ana_suspend + &cam_sensor_front_0_dig_suspend>; + gpios = <&tlmm 14 0>, + <&tlmm 9 0>, + <&tlmm 104 0>, + <&tlmm 117 0>; + 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_MCLK_2", + "CAM_RESET_2", + "CAM_VANA_2", + "CAM_DIG_2"; + 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>; + }; + +}; + + + +//overlay for camera end. + +&tlmm { + //add by gu qicai begin + ts_mux { + ts_active: ts_active { + mux { + pins = "gpio99", "gpio125"; + function = "gpio"; + }; + + config { + pins = "gpio99", "gpio125"; + drive-strength = <16>; + bias-pull-up; + }; + }; + + ts_reset_suspend: ts_reset_suspend { + mux { + pins = "gpio99"; + function = "gpio"; + }; + + config { + pins = "gpio99"; + drive-strength = <2>; + bias-pull-down; + }; + }; + + ts_int_suspend: ts_int_suspend { + mux { + pins = "gpio125"; + function = "gpio"; + }; + + config { + pins = "gpio125"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + //add by gu qicai end +}; + +/* OnePlus add thermistor, by rio.zhao*/ +&pm8998_vadc { + chan@50 { + label = "pa1_therm"; + reg = <0x50>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,fast-avg-setup = <0>; + }; +}; + +&pm8998_adc_tm { + chan@50 { + label = "pa1_therm"; + reg = <0x50>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <2>; + qcom,hw-settle-time = <2>; + qcom,btm-channel-number = <0x90>; + qcom,thermal-node; + }; +}; + +&thermal_zones { + pa1-therml-adc { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-sensors = <&pm8998_adc_tm 0x50>; + thermal-governor = "user_space"; + + trips { + active-config0 { + temperature = <65000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; +}; +&spmi_bus { + qcom,pm8998@0 { + qcom,power-on@800 { + qcom,pon_1 { + qcom,support-reset = <0>; + }; + }; + }; +}; + +/* add for rf cable support ,shankai@bsp*/ + +&tlmm { + oem_rf_cable_mux { + oem_rf_cable_active: oem_rf_cable_active { + mux { + pins = "gpio32","gpio128"; + function = "gpio"; + }; + config { + pins = "gpio32","gpio128"; + drive-strength = <2>; + bias-disable; + }; + }; + oem_rf_cable_suspend: oem_rf_cable_suspend { + mux { + pins = "gpio32","gpio128"; + function = "gpio"; + }; + config { + pins = "gpio32","gpio128"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + oem_aboard_mux { + oem_aboard_mux_active: oem_aboard_mux_active { + mux { + pins = "gpio33","gpio34"; + function = "gpio"; + }; + config { + pins = "gpio33","gpio34"; + drive-strength = <2>; + bias-disable; + }; + }; + oem_aboard_mux_suspend: oem_aboard_mux_suspend { + mux { + pins = "gpio33","gpio34"; + function = "gpio"; + }; + config { + pins = "gpio33","gpio34"; + drive-strength = <2>; + bias-disable; + }; + }; + }; + +}; + +&soc { + oem_rf_cable { + compatible = "oem,rf_cable"; + interrupt-parent = <&tlmm>; + rf,cable-gpio-0 = <&tlmm 32 0>; + rf,cable-gpio-1 = <&tlmm 128 0>; + pinctrl-names = "oem_rf_cable_active", "oem_rf_cable_suspend"; + pinctrl-0 = <&oem_rf_cable_active >; + pinctrl-1 = <&oem_rf_cable_suspend >; + }; + + oem_aboard_check { + compatible = "oem,aboard"; + interrupt-parent = <&tlmm>; + oem,aboard-gpio-0 = <&tlmm 33 0>; + oem,aboard-gpio-1 = <&tlmm 34 0>; + pinctrl-names = "oem_aboard_active", "oem_aboard_suspend"; + pinctrl-0 = <&oem_aboard_mux_active >; + pinctrl-1 = <&oem_aboard_mux_suspend >; + }; + +}; +/*shankai add for rf cable end shankai@bsp*/ + +&spss_utils { + status = "disabled"; +}; + +&qupv3_se0_spi { + status = "ok"; + qcom,disable-autosuspend; + + ese@0 { + compatible = "nxp,p61"; + reg = <0>; + spi-max-frequency = <8000000>; + nxp,nfcc = "1-0028"; + }; +}; + +&qupv3_se3_i2c { + + nq@28 { + status = "disabled"; + }; + + pn5xx@28 { + compatible = "nxp,pn544"; + reg = <0x28>; + nxp,pn544-irq = <&tlmm 63 0x00>; + nxp,pn544-ven = <&tlmm 12 0x00>; + nxp,pn544-fw-dwnld = <&tlmm 62 0x00>; + nxp,pn544-clk-gpio = <&pm8998_gpios 21 0x00>; + nxp,pn544-ese-pwr = <&tlmm 116 0x00>; + nfc_voltage_s4-supply = <&pm8998_s4>; + nxp,pn544-wake-up = <&tlmm 129 0x00>; + interrupt-parent = <&tlmm>; + qcom,clk-src = "BBCLK3"; + interrupts = <63 0>; + interrupt-names = "nfc_irq"; + pinctrl-names = "nfc_active", "nfc_suspend"; + pinctrl-0 = <&nfc_int_active + &nfc_enable_active + &nfc_clk_default>; + pinctrl-1 = <&nfc_int_suspend &nfc_enable_suspend>; + clocks = <&clock_rpmh RPMH_LN_BB_CLK3>; + clock-names = "ref_clk"; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi index c9a37b705577..9c9459b1e9d8 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi @@ -77,7 +77,7 @@ compatible = "snps,dwc3"; reg = <0x0a600000 0xcd00>; interrupts = ; - usb-phy = <&qusb_phy0>, <&usb_qmp_dp_phy>; + usb-phy = <&qusb_phy0>, <&usb_nop_phy>; tx-fifo-resize; linux,sysdev_is_parent; snps,disable-clk-gating; @@ -86,7 +86,7 @@ snps,usb3_lpm_capable; usb-core-id = <0>; dr_mode = "drd"; - maximum-speed = "super-speed"; + maximum-speed = "high-speed"; }; qcom,usbbam@a704000 { diff --git a/arch/arm64/boot/dts/qcom/sdm845-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/sdm845-audio-overlay.dtsi index 96b1e05600ab..4a746638523a 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-audio-overlay.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-audio-overlay.dtsi @@ -16,12 +16,12 @@ "hifi amp", "LINEOUT2", "AMIC2", "MIC BIAS2", "MIC BIAS2", "Headset Mic", - "AMIC3", "MIC BIAS2", - "MIC BIAS2", "ANCRight Headset Mic", - "AMIC4", "MIC BIAS2", - "MIC BIAS2", "ANCLeft Headset Mic", - "AMIC5", "MIC BIAS3", - "MIC BIAS3", "Handset Mic", + "AMIC3", "MIC BIAS3", + "MIC BIAS3", "ANCRight Headset Mic", + "AMIC4", "MIC BIAS1", + "MIC BIAS1", "ANCLeft Headset Mic", + "AMIC5", "MIC BIAS4", + "MIC BIAS4", "Handset Mic", "DMIC0", "MIC BIAS1", "MIC BIAS1", "Digital Mic0", "DMIC1", "MIC BIAS1", @@ -55,19 +55,19 @@ pinctrl-0 = <&wcd_usbc_analog_en2_active>; pinctrl-1 = <&wcd_usbc_analog_en2_idle>; - 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,wsa-max-devs = <0>; + //qcom,wsa-devs = <&wsa881x_0211>, <&wsa881x_0212>, + // <&wsa881x_0213>, <&wsa881x_0214>; + //qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight", + // "SpkrLeft", "SpkrRight"; }; &soc { wcd_usbc_analog_en1_gpio: msm_cdc_pinctrl@49 { compatible = "qcom,msm-cdc-pinctrl"; - pinctrl-names = "aud_active", "aud_sleep"; - pinctrl-0 = <&wcd_usbc_analog_en1_active>; - pinctrl-1 = <&wcd_usbc_analog_en1_idle>; + //pinctrl-names = "aud_active", "aud_sleep"; + //pinctrl-0 = <&wcd_usbc_analog_en1_active>; + //pinctrl-1 = <&wcd_usbc_analog_en1_idle>; }; wcd9xxx_intc: wcd9xxx-irq { diff --git a/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi b/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi index 08bb65b99dee..807e30ca7aab 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi @@ -31,6 +31,9 @@ snd_934x: sound-tavil { compatible = "qcom,sdm845-asoc-snd-tavil"; qcom,model = "sdm845-tavil-snd-card"; + /*MM.Audio, 2019/07/13, add for screen record headset mic path*/ + qcom,afe-rxtx-lb = <1>; + /*add end*/ qcom,ext-disp-audio-rx; qcom,wcn-btfm; qcom,mi2s-audio-intf; @@ -67,7 +70,10 @@ <&dai_tert_tdm_rx_0>, <&dai_tert_tdm_tx_0>, <&dai_quat_tdm_rx_0>, <&dai_quat_tdm_tx_0>, <&dai_quat_tdm_rx_1>, - <&proxy_rx>, <&proxy_tx>; + <&proxy_rx>, <&proxy_tx>, + /*MM.Audio, 2019/07/13, add for screen record headset mic path*/ + <&afe_loopback_tx>; + /*add end*/ asoc-cpu-names = "msm-dai-q6-hdmi.8", "msm-dai-q6-dp.0", "msm-dai-q6-mi2s.0", "msm-dai-q6-mi2s.1", "msm-dai-q6-mi2s.2", "msm-dai-q6-mi2s.3", @@ -91,7 +97,12 @@ "msm-dai-q6-tdm.36896", "msm-dai-q6-tdm.36897", "msm-dai-q6-tdm.36912", "msm-dai-q6-tdm.36913", "msm-dai-q6-tdm.36914", - "msm-dai-q6-dev.8194", "msm-dai-q6-dev.8195"; + "msm-dai-q6-dev.8194", "msm-dai-q6-dev.8195", + /*MM.Audio, 2019/07/13, add for screen record headset mic path*/ + "msm-dai-q6-dev.24577"; + /*add end*/ +/*suzhiguang, temp add here */ + op,smartpa ="max98927"; }; }; diff --git a/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-mtp.dtsi index 4afdf5600708..a3550ca9acde 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-mtp.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-camera-sensor-mtp.dtsi @@ -2,456 +2,3 @@ /* * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. */ - -&soc { - led_flash_rear: qcom,camera-flash@0 { - cell-index = <0>; - reg = <0x00 0x00>; - compatible = "qcom,camera-flash"; - flash-source = <&pmi8998_flash0 &pmi8998_flash1>; - torch-source = <&pmi8998_torch0 &pmi8998_torch1>; - switch-source = <&pmi8998_switch0>; - status = "ok"; - }; - - led_flash_rear_aux: qcom,camera-flash@1 { - cell-index = <1>; - reg = <0x01 0x00>; - compatible = "qcom,camera-flash"; - flash-source = <&pmi8998_flash0 &pmi8998_flash1>; - torch-source = <&pmi8998_torch0 &pmi8998_torch1>; - switch-source = <&pmi8998_switch0>; - status = "ok"; - }; - - led_flash_front: qcom,camera-flash@2 { - cell-index = <2>; - reg = <0x02 0x00>; - compatible = "qcom,camera-flash"; - flash-source = <&pmi8998_flash2>; - torch-source = <&pmi8998_torch2>; - switch-source = <&pmi8998_switch1>; - status = "ok"; - }; - - led_flash_iris: qcom,camera-flash@3 { - cell-index = <3>; - reg = <0x03 0x00>; - compatible = "qcom,camera-flash"; - flash-source = <&pmi8998_flash2>; - torch-source = <&pmi8998_torch2>; - switch-source = <&pmi8998_switch2>; - status = "ok"; - }; - - actuator_regulator: gpio-regulator@0 { - compatible = "regulator-fixed"; - reg = <0x00 0x00>; - regulator-name = "actuator_regulator"; - regulator-min-microvolt = <2800000>; - regulator-max-microvolt = <2800000>; - regulator-enable-ramp-delay = <100>; - enable-active-high; - gpio = <&tlmm 27 0>; - vin-supply = <&pmi8998_bob>; - }; - - camera_rear_ldo: gpio-regulator@1 { - compatible = "regulator-fixed"; - reg = <0x01 0x00>; - regulator-name = "camera_rear_ldo"; - regulator-min-microvolt = <1050000>; - regulator-max-microvolt = <1050000>; - regulator-enable-ramp-delay = <135>; - enable-active-high; - gpio = <&pm8998_gpios 12 0>; - pinctrl-names = "default"; - pinctrl-0 = <&camera_rear_dvdd_en_default>; - vin-supply = <&pm8998_s3>; - }; - - camera_ldo: gpio-regulator@2 { - compatible = "regulator-fixed"; - reg = <0x02 0x00>; - regulator-name = "camera_ldo"; - regulator-min-microvolt = <1050000>; - regulator-max-microvolt = <1050000>; - regulator-enable-ramp-delay = <233>; - enable-active-high; - gpio = <&pm8998_gpios 9 0>; - pinctrl-names = "default"; - pinctrl-0 = <&camera_dvdd_en_default>; - vin-supply = <&pm8998_s3>; - }; - - camera_vana_ldo: gpio-regulator@4 { - compatible = "regulator-fixed"; - reg = <0x04 0x00>; - regulator-name = "camera_vana_ldo"; - regulator-min-microvolt = <2850000>; - regulator-max-microvolt = <2850000>; - regulator-enable-ramp-delay = <233>; - enable-active-high; - gpio = <&tlmm 8 0>; - pinctrl-names = "default"; - pinctrl-0 = <&cam_sensor_rear_vana>; - vin-supply = <&pmi8998_bob>; - }; -}; - -&cam_cci { - qcom,cam-res-mgr { - compatible = "qcom,cam-res-mgr"; - status = "ok"; - }; - - actuator_rear: qcom,actuator@0 { - cell-index = <0>; - reg = <0x0>; - compatible = "qcom,actuator"; - cci-master = <0>; - cam_vaf-supply = <&actuator_regulator>; - regulator-names = "cam_vaf"; - rgltr-cntrl-support; - rgltr-min-voltage = <2800000>; - rgltr-max-voltage = <2800000>; - rgltr-load-current = <0>; - }; - - actuator_rear_aux: qcom,actuator@1 { - cell-index = <1>; - reg = <0x1>; - compatible = "qcom,actuator"; - cci-master = <1>; - cam_vaf-supply = <&actuator_regulator>; - regulator-names = "cam_vaf"; - rgltr-cntrl-support; - rgltr-min-voltage = <2800000>; - rgltr-max-voltage = <2800000>; - rgltr-load-current = <0>; - }; - - actuator_front: qcom,actuator@2 { - cell-index = <2>; - reg = <0x2>; - compatible = "qcom,actuator"; - cci-master = <1>; - cam_vaf-supply = <&actuator_regulator>; - regulator-names = "cam_vaf"; - rgltr-cntrl-support; - rgltr-min-voltage = <2800000>; - rgltr-max-voltage = <2800000>; - rgltr-load-current = <0>; - }; - - ois_rear: qcom,ois@0 { - cell-index = <0>; - reg = <0x0>; - compatible = "qcom,ois"; - cci-master = <0>; - cam_vaf-supply = <&actuator_regulator>; - regulator-names = "cam_vaf"; - rgltr-cntrl-support; - rgltr-min-voltage = <2800000>; - rgltr-max-voltage = <2800000>; - rgltr-load-current = <0>; - status = "ok"; - }; - - eeprom_rear: qcom,eeprom@0 { - cell-index = <0>; - reg = <0>; - compatible = "qcom,eeprom"; - cam_vio-supply = <&pm8998_lvs1>; - cam_vana-supply = <&pmi8998_bob>; - cam_vdig-supply = <&camera_rear_ldo>; - cam_clk-supply = <&titan_top_gdsc>; - cam_vaf-supply = <&actuator_regulator>; - regulator-names = "cam_vio", "cam_vana", "cam_vdig", - "cam_clk", "cam_vaf"; - rgltr-cntrl-support; - rgltr-min-voltage = <0 3312000 1050000 0 2800000>; - rgltr-max-voltage = <0 3600000 1050000 0 2800000>; - rgltr-load-current = <0 80000 105000 0 0>; - 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-vana = <2>; - gpio-req-tbl-num = <0 1 2>; - gpio-req-tbl-flags = <1 0 0>; - gpio-req-tbl-label = "CAMIF_MCLK0", - "CAM_RESET0", - "CAM_VANA0"; - 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,eeprom@1 { - cell-index = <1>; - reg = <0x1>; - compatible = "qcom,eeprom"; - cam_vdig-supply = <&camera_ldo>; - cam_vio-supply = <&pm8998_lvs1>; - cam_vana-supply = <&pmi8998_bob>; - cam_clk-supply = <&titan_top_gdsc>; - cam_vaf-supply = <&actuator_regulator>; - regulator-names = "cam_vdig", "cam_vio", "cam_vana", - "cam_clk", "cam_vaf"; - rgltr-cntrl-support; - rgltr-min-voltage = <1050000 0 3312000 0 2800000>; - rgltr-max-voltage = <1050000 0 3600000 0 2800000>; - rgltr-load-current = <105000 0 80000 0 0>; - gpio-no-mux = <0>; - pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cam_sensor_mclk2_active - &cam_sensor_rear2_active>; - pinctrl-1 = <&cam_sensor_mclk2_suspend - &cam_sensor_rear2_suspend>; - gpios = <&tlmm 15 0>, - <&tlmm 9 0>, - <&tlmm 8 0>; - gpio-reset = <1>; - gpio-vana = <2>; - gpio-req-tbl-num = <0 1 2>; - gpio-req-tbl-flags = <1 0 0>; - gpio-req-tbl-label = "CAMIF_MCLK1", - "CAM_RESET1", - "CAM_VANA1"; - 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_front: qcom,eeprom@2 { - cell-index = <2>; - reg = <0x2>; - compatible = "qcom,eeprom"; - cam_vio-supply = <&pm8998_lvs1>; - cam_vana-supply = <&pmi8998_bob>; - cam_vdig-supply = <&camera_ldo>; - cam_clk-supply = <&titan_top_gdsc>; - cam_vaf-supply = <&actuator_regulator>; - regulator-names = "cam_vio", "cam_vana", "cam_vdig", - "cam_clk", "cam_vaf"; - rgltr-cntrl-support; - rgltr-min-voltage = <0 3312000 1050000 0 2800000>; - rgltr-max-voltage = <0 3600000 1050000 0 2800000>; - rgltr-load-current = <0 80000 105000 0 0>; - gpio-no-mux = <0>; - pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cam_sensor_mclk1_active - &cam_sensor_front_active>; - pinctrl-1 = <&cam_sensor_mclk1_suspend - &cam_sensor_front_suspend>; - gpios = <&tlmm 14 0>, - <&tlmm 28 0>, - <&tlmm 8 0>; - gpio-reset = <1>; - gpio-vana = <2>; - gpio-req-tbl-num = <0 1 2>; - gpio-req-tbl-flags = <1 0 0>; - gpio-req-tbl-label = "CAMIF_MCLK2", - "CAM_RESET2", - "CAM_VANA2"; - sensor-position = <1>; - 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-sensor@0 { - cell-index = <0>; - compatible = "qcom,cam-sensor"; - reg = <0x0>; - csiphy-sd-index = <0>; - sensor-position-roll = <270>; - sensor-position-pitch = <0>; - sensor-position-yaw = <180>; - led-flash-src = <&led_flash_rear>; - actuator-src = <&actuator_rear>; - ois-src = <&ois_rear>; - eeprom-src = <&eeprom_rear>; - cam_vio-supply = <&pm8998_lvs1>; - cam_vana-supply = <&pmi8998_bob>; - cam_vdig-supply = <&camera_rear_ldo>; - cam_clk-supply = <&titan_top_gdsc>; - regulator-names = "cam_vio", "cam_vana", "cam_vdig", - "cam_clk"; - rgltr-cntrl-support; - rgltr-min-voltage = <0 3312000 1050000 0>; - rgltr-max-voltage = <0 3600000 1050000 0>; - rgltr-load-current = <0 80000 105000 0>; - gpio-no-mux = <0>; - pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cam_sensor_mclk0_active - &cam_sensor_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-vana = <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-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-sensor@1 { - cell-index = <1>; - compatible = "qcom,cam-sensor"; - reg = <0x1>; - 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_vdig-supply = <&camera_ldo>; - cam_vio-supply = <&pm8998_lvs1>; - cam_vana-supply = <&camera_vana_ldo>; - cam_clk-supply = <&titan_top_gdsc>; - regulator-names = "cam_vdig", "cam_vio", "cam_vana", - "cam_clk"; - rgltr-cntrl-support; - rgltr-min-voltage = <1050000 0 2850000 0>; - rgltr-max-voltage = <1050000 0 2850000 0>; - rgltr-load-current = <105000 0 80000 0>; - gpio-no-mux = <0>; - pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cam_sensor_mclk2_active - &cam_sensor_rear2_active>; - pinctrl-1 = <&cam_sensor_mclk2_suspend - &cam_sensor_rear2_suspend>; - gpios = <&tlmm 15 0>, - <&tlmm 9 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_MCLK2_CLK>; - clock-names = "cam_clk"; - clock-cntl-level = "turbo"; - clock-rates = <24000000>; - }; - - qcom,cam-sensor@2 { - cell-index = <2>; - compatible = "qcom,cam-sensor"; - reg = <0x02>; - csiphy-sd-index = <2>; - sensor-position-roll = <270>; - sensor-position-pitch = <0>; - sensor-position-yaw = <0>; - eeprom-src = <&eeprom_front>; - actuator-src = <&actuator_front>; - led-flash-src = <&led_flash_front>; - cam_vio-supply = <&pm8998_lvs1>; - cam_vana-supply = <&camera_vana_ldo>; - cam_vdig-supply = <&camera_ldo>; - cam_clk-supply = <&titan_top_gdsc>; - regulator-names = "cam_vio", "cam_vana", "cam_vdig", - "cam_clk"; - rgltr-cntrl-support; - rgltr-min-voltage = <0 2850000 1050000 0>; - rgltr-max-voltage = <0 2850000 1050000 0>; - rgltr-load-current = <0 80000 105000 0>; - gpio-no-mux = <0>; - pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cam_sensor_mclk1_active - &cam_sensor_front_active>; - pinctrl-1 = <&cam_sensor_mclk1_suspend - &cam_sensor_front_suspend>; - gpios = <&tlmm 14 0>, - <&tlmm 28 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_MCLK1_CLK>; - clock-names = "cam_clk"; - clock-cntl-level = "turbo"; - clock-rates = <24000000>; - }; - - qcom,cam-sensor@3 { - cell-index = <3>; - compatible = "qcom,cam-sensor"; - reg = <0x03>; - csiphy-sd-index = <3>; - sensor-position-roll = <270>; - sensor-position-pitch = <0>; - sensor-position-yaw = <0>; - led-flash-src = <&led_flash_iris>; - cam_vio-supply = <&pm8998_lvs1>; - cam_vana-supply = <&camera_vana_ldo>; - cam_vdig-supply = <&camera_ldo>; - cam_clk-supply = <&titan_top_gdsc>; - regulator-names = "cam_vio", "cam_vana", "cam_vdig", - "cam_clk"; - rgltr-cntrl-support; - rgltr-min-voltage = <0 2850000 1050000 0>; - rgltr-max-voltage = <0 2850000 1050000 0>; - rgltr-load-current = <0 80000 105000 0>; - gpio-no-mux = <0>; - pinctrl-names = "cam_default", "cam_suspend"; - pinctrl-0 = <&cam_sensor_mclk3_active - &cam_sensor_iris_active>; - pinctrl-1 = <&cam_sensor_mclk3_suspend - &cam_sensor_iris_suspend>; - gpios = <&tlmm 16 0>, - <&tlmm 9 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/qcom/sdm845-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-mtp-overlay.dts index 3ece5cd553fd..ec03a644588c 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-mtp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sdm845-mtp-overlay.dts @@ -15,10 +15,12 @@ #include "sdm845-sde-display.dtsi" #include "sdm845-mtp.dtsi" #include "sdm845-audio-overlay.dtsi" +#include "enchilada.dtsi" +#include "enchilada-t0.dtsi" / { model = "Qualcomm Technologies, Inc. SDM845 v1 MTP"; compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp"; qcom,msm-id = <321 0x10000>; - qcom,board-id = <8 0>; + qcom,board-id = <8 0 0 0>; }; diff --git a/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi index 8f0a40b37ac0..65d42feb436d 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-mtp.dtsi @@ -42,9 +42,7 @@ label = "gpio-keys"; pinctrl-names = "default"; - pinctrl-0 = <&key_vol_up_default - &key_cam_snapshot_default - &key_cam_focus_default>; + pinctrl-0 = <&key_vol_up_default>; vol_up { label = "volume_up"; @@ -55,7 +53,7 @@ debounce-interval = <15>; linux,can-disable; }; - + /* cam_snapshot { label = "cam_snapshot"; gpios = <&pm8998_gpios 7 GPIO_ACTIVE_LOW>; @@ -75,6 +73,7 @@ debounce-interval = <15>; linux,can-disable; }; + */ }; }; @@ -264,9 +263,6 @@ &vendor { mtp_batterydata: qcom,battery-data { qcom,batt-id-range-pct = <15>; - #include "fg-gen3-batterydata-itech-3000mah.dtsi" - #include "fg-gen3-batterydata-ascent-3450mah.dtsi" - #include "fg-gen3-batterydata-demo-6000mah.dtsi" }; extcon_usb1: extcon_usb1 { diff --git a/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi index 99e146c66569..0cfda27e63e6 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-pinctrl.dtsi @@ -444,7 +444,7 @@ pcie1_clkreq_default: pcie1_clkreq_default { mux { pins = "gpio103"; - function = "pci_e1"; + function = "gpio"; }; config { @@ -2683,8 +2683,19 @@ bias-pull-up; }; }; - }; + qupv3_se10_i2c_reset: qupv3_se10_i2c_reset { + mux { + pins = "gpio55", "gpio56"; + function = "gpio"; + }; + config { + pins = "gpio55", "gpio56"; + drive-strength = <2>; + bias-pull-down; + }; + }; + }; qupv3_se10_2uart_pins: qupv3_se10_2uart_pins { qupv3_se10_2uart_active: qupv3_se10_2uart_active { mux { diff --git a/arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi b/arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi index ec8a8f560300..e7af96176a29 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-qupv3.dtsi @@ -498,9 +498,10 @@ dmas = <&gpi_dma1 0 2 3 64 0>, <&gpi_dma1 1 2 3 64 0>; dma-names = "tx", "rx"; - pinctrl-names = "default", "sleep"; + pinctrl-names = "default", "sleep", "reset"; pinctrl-0 = <&qupv3_se10_i2c_active>; pinctrl-1 = <&qupv3_se10_i2c_sleep>; + pinctrl-2 = <&qupv3_se10_i2c_reset>; qcom,wrapper-core = <&qupv3_1>; status = "disabled"; }; diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi index 46ed48b27e87..71dd4cde966e 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-sde.dtsi @@ -434,7 +434,7 @@ label = "dsi-ctrl-0"; cell-index = <0>; reg = <0xae94000 0x400>, - <0xaf08000 0x4>; + <0xaf03000 0x5004>; reg-names = "dsi_ctrl", "disp_cc_base"; interrupt-parent = <&mdss_mdp>; interrupts = <4 IRQ_TYPE_LEVEL_HIGH>; @@ -469,7 +469,7 @@ label = "dsi-ctrl-1"; cell-index = <1>; reg = <0xae96000 0x400>, - <0xaf08000 0x4>; + <0xaf03000 0x5004>; reg-names = "dsi_ctrl", "disp_cc_base"; interrupt-parent = <&mdss_mdp>; interrupts = <5 IRQ_TYPE_LEVEL_HIGH>; diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-v2-mtp-overlay.dts index 7794bd578bdd..23f67a1aa6d3 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-v2-mtp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sdm845-v2-mtp-overlay.dts @@ -15,10 +15,12 @@ #include "sdm845-sde-display.dtsi" #include "sdm845-mtp.dtsi" #include "sdm845-audio-overlay.dtsi" +#include "enchilada.dtsi" +#include "enchilada-t0.dtsi" / { - model = "Qualcomm Technologies, Inc. SDM845 v2 MTP"; + model = "Qualcomm Technologies, Inc. SDM845 v2 MTP default"; compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp"; qcom,msm-id = <321 0x20000>; - qcom,board-id = <8 0>; + qcom,board-id = <8 0 0 0>; }; diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.1-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm845-v2.1-mtp-overlay.dts index 7a1101d2a5ef..d91ee93e4ed5 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-v2.1-mtp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sdm845-v2.1-mtp-overlay.dts @@ -15,10 +15,12 @@ #include "sdm845-sde-display.dtsi" #include "sdm845-mtp.dtsi" #include "sdm845-audio-overlay.dtsi" +#include "enchilada.dtsi" +#include "enchilada-t0.dtsi" / { model = "Qualcomm Technologies, Inc. SDM845 v2.1 MTP"; compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp"; qcom,msm-id = <321 0x20001>; - qcom,board-id = <8 0>; + qcom,board-id = <8 0 0 0>; }; diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.dts b/arch/arm64/boot/dts/qcom/sdm845-v2.dts index 62ec1afa9501..2ebff002a269 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-v2.dts +++ b/arch/arm64/boot/dts/qcom/sdm845-v2.dts @@ -10,5 +10,5 @@ / { model = "Qualcomm Technologies, Inc. SDM845 v2 SoC"; compatible = "qcom,sdm845"; - qcom,board-id = <0 0>; + qcom,board-id = <0 0 0 0>; }; diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi index b6710863ef5f..cbdc05d1b801 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi @@ -5,6 +5,7 @@ #include "sdm845.dtsi" #include "sdm845-v2-camera.dtsi" +#include "sdm845_enchilada_soc.dtsi" / { model = "Qualcomm Technologies, Inc. SDM845 V2"; diff --git a/arch/arm64/boot/dts/qcom/sdm845.dts b/arch/arm64/boot/dts/qcom/sdm845.dts index 286d69ec3e2e..1ec7247fcf4c 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dts +++ b/arch/arm64/boot/dts/qcom/sdm845.dts @@ -6,9 +6,10 @@ /dts-v1/; #include "sdm845.dtsi" +#include "sdm845_enchilada_soc.dtsi" / { model = "Qualcomm Technologies, Inc. SDM845 v1 SoC"; compatible = "qcom,sdm845"; - qcom,board-id = <0 0>; + qcom,board-id = <0 0 0 0>; }; diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index cfbe04cf1125..03b98b2e877f 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -422,7 +422,7 @@ removed_region1: removed_region@86200000 { no-map; - reg = <0 0x86200000 0 0x2d00000>; + reg = <0 0x86200000 0 0x4900000>; /* enlarge TA memory size from 34M to 62M on 2018/09/03 */ }; qseecom_mem: qseecom_region@0x8ab00000 { @@ -1647,7 +1647,7 @@ clock-names = "xo"; qcom,proxy-clock-names = "xo"; qcom,pil-generic-irq-handler; - status = "ok"; + status = "disabled"; qcom,pas-id = <14>; qcom,proxy-timeout-ms = <10000>; @@ -2540,7 +2540,7 @@ qcom_seecom: qseecom@86d00000 { compatible = "qcom,qseecom"; - reg = <0x86d00000 0x2200000>; + reg = <0x86d00000 0x03E00000>; /* enlarge TA memory size from 34M to 62M on 2018/09/03 */ reg-names = "secapp-region"; memory-region = <&qseecom_mem>; qcom,hlos-num-ce-hw-instances = <1>; @@ -3528,8 +3528,9 @@ gpu-virt-max-step { polling-delay-passive = <10>; - polling-delay = <100>; + polling-delay = <0>; thermal-governor = "step_wise"; + disable-thermal-zone; wake-capable-sensor; trips { gpu_trip0: gpu-trip0 { diff --git a/arch/arm64/boot/dts/qcom/sdm845_enchilada_soc.dtsi b/arch/arm64/boot/dts/qcom/sdm845_enchilada_soc.dtsi new file mode 100644 index 000000000000..7bccd60405c6 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm845_enchilada_soc.dtsi @@ -0,0 +1,47 @@ +/* Copyright (c) 2016-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. + */ + + +/{ + reserved-memory { + bootloader_log_mem: bootloader_log_mem@0x9FFF7000 { + reg = <0 0x9FFF7000 0 0x00100000>; + label = "bootloader_log_mem"; + }; + param_mem: param_mem@ac200000 { + reg = <0 0xAC200000 0 0x00100000>; + label = "param_mem"; + }; + ramoops: ramoops@0xAC300000 { + compatible = "ramoops"; + reg = <0 0xAC300000 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@ac700000 { + reg = <0 0xAC700000 0 0x00B00000>; + label = "mtp_mem"; + }; + }; +}; + +&soc { +bootloader_log { + compatible = "bootloader_log"; + linux,contiguous-region = <&bootloader_log_mem>; + }; +}; + From 2a546a459ad0ae7aa12f823e998ebd954a210a09 Mon Sep 17 00:00:00 2001 From: LuK1337 Date: Wed, 6 Nov 2019 14:34:01 +0100 Subject: [PATCH 222/356] msm: camera: Import OnePlus camera stack Change-Id: I7ec6f005df6bae2359b9bb8afb2fb5b2da7edb25 --- drivers/media/platform/msm/Kconfig | 9 + drivers/media/platform/msm/Makefile | 1 + .../platform/msm/camera_oneplus/Makefile | 13 + .../msm/camera_oneplus/cam_cdm/Makefile | 9 + .../msm/camera_oneplus/cam_cdm/cam_cdm.h | 261 + .../cam_cdm/cam_cdm_core_common.c | 569 +++ .../cam_cdm/cam_cdm_core_common.h | 50 + .../camera_oneplus/cam_cdm/cam_cdm_hw_core.c | 1144 +++++ .../msm/camera_oneplus/cam_cdm/cam_cdm_intf.c | 580 +++ .../camera_oneplus/cam_cdm/cam_cdm_intf_api.h | 209 + .../msm/camera_oneplus/cam_cdm/cam_cdm_soc.c | 208 + .../msm/camera_oneplus/cam_cdm/cam_cdm_soc.h | 28 + .../msm/camera_oneplus/cam_cdm/cam_cdm_util.c | 542 +++ .../msm/camera_oneplus/cam_cdm/cam_cdm_util.h | 161 + .../camera_oneplus/cam_cdm/cam_cdm_virtual.h | 25 + .../cam_cdm/cam_cdm_virtual_core.c | 384 ++ .../cam_cdm/cam_hw_cdm170_reg.h | 142 + .../msm/camera_oneplus/cam_core/Makefile | 6 + .../msm/camera_oneplus/cam_core/cam_context.c | 496 ++ .../msm/camera_oneplus/cam_core/cam_context.h | 420 ++ .../cam_core/cam_context_utils.c | 881 ++++ .../cam_core/cam_context_utils.h | 35 + .../camera_oneplus/cam_core/cam_core_defs.h | 45 + .../msm/camera_oneplus/cam_core/cam_hw.h | 53 + .../msm/camera_oneplus/cam_core/cam_hw_intf.h | 83 + .../camera_oneplus/cam_core/cam_hw_mgr_intf.h | 254 + .../msm/camera_oneplus/cam_core/cam_node.c | 576 +++ .../msm/camera_oneplus/cam_core/cam_node.h | 111 + .../msm/camera_oneplus/cam_core/cam_subdev.c | 161 + .../msm/camera_oneplus/cam_cpas/Makefile | 10 + .../msm/camera_oneplus/cam_cpas/cam_cpas_hw.c | 1692 +++++++ .../msm/camera_oneplus/cam_cpas/cam_cpas_hw.h | 202 + .../cam_cpas/cam_cpas_hw_intf.h | 135 + .../camera_oneplus/cam_cpas/cam_cpas_intf.c | 660 +++ .../camera_oneplus/cam_cpas/cam_cpas_soc.c | 275 ++ .../camera_oneplus/cam_cpas/cam_cpas_soc.h | 76 + .../cam_cpas/camss_top/Makefile | 6 + .../cam_cpas/camss_top/cam_camsstop_hw.c | 89 + .../camera_oneplus/cam_cpas/cpas_top/Makefile | 6 + .../cam_cpas/cpas_top/cam_cpastop_hw.c | 574 +++ .../cam_cpas/cpas_top/cam_cpastop_hw.h | 241 + .../cam_cpas/cpas_top/cpastop100.h | 538 +++ .../cam_cpas/cpas_top/cpastop_v170_110.h | 545 +++ .../cam_cpas/cpas_top/cpastop_v175_100.h | 545 +++ .../cam_cpas/cpas_top/cpastop_v175_101.h | 545 +++ .../cam_cpas/include/cam_cpas_api.h | 517 ++ .../msm/camera_oneplus/cam_fd/Makefile | 14 + .../camera_oneplus/cam_fd/cam_fd_context.c | 256 + .../camera_oneplus/cam_fd/cam_fd_context.h | 37 + .../msm/camera_oneplus/cam_fd/cam_fd_dev.c | 213 + .../camera_oneplus/cam_fd/fd_hw_mgr/Makefile | 14 + .../cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c | 1941 ++++++++ .../cam_fd/fd_hw_mgr/cam_fd_hw_mgr.h | 186 + .../cam_fd/fd_hw_mgr/cam_fd_hw_mgr_intf.h | 25 + .../cam_fd/fd_hw_mgr/fd_hw/Makefile | 13 + .../cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c | 1168 +++++ .../cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.h | 244 + .../cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c | 228 + .../cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_intf.h | 289 ++ .../cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.c | 290 ++ .../cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.h | 53 + .../cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v41.h | 70 + .../cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v501.h | 70 + .../msm/camera_oneplus/cam_icp/Makefile | 14 + .../camera_oneplus/cam_icp/cam_icp_context.c | 217 + .../camera_oneplus/cam_icp/cam_icp_context.h | 49 + .../camera_oneplus/cam_icp/cam_icp_subdev.c | 254 + .../camera_oneplus/cam_icp/fw_inc/hfi_intf.h | 150 + .../camera_oneplus/cam_icp/fw_inc/hfi_reg.h | 324 ++ .../cam_icp/fw_inc/hfi_session_defs.h | 530 ++ .../cam_icp/fw_inc/hfi_sys_defs.h | 522 ++ .../platform/msm/camera_oneplus/cam_icp/hfi.c | 808 ++++ .../camera_oneplus/cam_icp/icp_hw/Makefile | 9 + .../cam_icp/icp_hw/a5_hw/Makefile | 11 + .../cam_icp/icp_hw/a5_hw/a5_core.c | 478 ++ .../cam_icp/icp_hw/a5_hw/a5_core.h | 89 + .../cam_icp/icp_hw/a5_hw/a5_dev.c | 234 + .../cam_icp/icp_hw/a5_hw/a5_soc.c | 120 + .../cam_icp/icp_hw/a5_hw/a5_soc.h | 32 + .../cam_icp/icp_hw/bps_hw/Makefile | 11 + .../cam_icp/icp_hw/bps_hw/bps_core.c | 323 ++ .../cam_icp/icp_hw/bps_hw/bps_core.h | 47 + .../cam_icp/icp_hw/bps_hw/bps_dev.c | 206 + .../cam_icp/icp_hw/bps_hw/bps_soc.c | 171 + .../cam_icp/icp_hw/bps_hw/bps_soc.h | 33 + .../cam_icp/icp_hw/icp_hw_mgr/Makefile | 16 + .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 4297 +++++++++++++++++ .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h | 344 ++ .../icp_hw_mgr/include/cam_a5_hw_intf.h | 81 + .../icp_hw_mgr/include/cam_bps_hw_intf.h | 34 + .../icp_hw_mgr/include/cam_icp_hw_intf.h | 36 + .../icp_hw_mgr/include/cam_ipe_hw_intf.h | 34 + .../icp_hw/include/cam_icp_hw_mgr_intf.h | 47 + .../cam_icp/icp_hw/ipe_hw/Makefile | 11 + .../cam_icp/icp_hw/ipe_hw/ipe_core.c | 314 ++ .../cam_icp/icp_hw/ipe_hw/ipe_core.h | 47 + .../cam_icp/icp_hw/ipe_hw/ipe_dev.c | 198 + .../cam_icp/icp_hw/ipe_hw/ipe_soc.c | 174 + .../cam_icp/icp_hw/ipe_hw/ipe_soc.h | 33 + .../msm/camera_oneplus/cam_isp/Makefile | 9 + .../camera_oneplus/cam_isp/cam_isp_context.c | 2572 ++++++++++ .../camera_oneplus/cam_isp/cam_isp_context.h | 171 + .../msm/camera_oneplus/cam_isp/cam_isp_dev.c | 155 + .../msm/camera_oneplus/cam_isp/cam_isp_dev.h | 35 + .../msm/camera_oneplus/cam_isp/cam_isp_log.h | 26 + .../cam_isp/isp_hw_mgr/Makefile | 15 + .../cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 4223 ++++++++++++++++ .../cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h | 230 + .../cam_isp/isp_hw_mgr/cam_isp_hw_mgr.c | 36 + .../cam_isp/isp_hw_mgr/cam_isp_hw_mgr.h | 74 + .../cam_isp/isp_hw_mgr/hw_utils/Makefile | 12 + .../hw_utils/cam_isp_packet_parser.c | 745 +++ .../isp_hw_mgr/hw_utils/cam_tasklet_util.c | 329 ++ .../hw_utils/include/cam_isp_packet_parser.h | 162 + .../hw_utils/include/cam_tasklet_util.h | 99 + .../hw_utils/irq_controller/Makefile | 3 + .../irq_controller/cam_irq_controller.c | 727 +++ .../irq_controller/cam_irq_controller.h | 278 ++ .../isp_hw_mgr/include/cam_isp_hw_mgr_intf.h | 213 + .../cam_isp/isp_hw_mgr/isp_hw/Makefile | 2 + .../isp_hw_mgr/isp_hw/ife_csid_hw/Makefile | 12 + .../isp_hw/ife_csid_hw/cam_ife_csid170.c | 60 + .../isp_hw/ife_csid_hw/cam_ife_csid170.h | 304 ++ .../isp_hw/ife_csid_hw/cam_ife_csid_core.c | 2988 ++++++++++++ .../isp_hw/ife_csid_hw/cam_ife_csid_core.h | 466 ++ .../isp_hw/ife_csid_hw/cam_ife_csid_dev.c | 141 + .../isp_hw/ife_csid_hw/cam_ife_csid_dev.h | 23 + .../isp_hw/ife_csid_hw/cam_ife_csid_lite170.c | 58 + .../isp_hw/ife_csid_hw/cam_ife_csid_lite170.h | 319 ++ .../isp_hw/ife_csid_hw/cam_ife_csid_soc.c | 239 + .../isp_hw/ife_csid_hw/cam_ife_csid_soc.h | 114 + .../isp_hw/include/cam_ife_csid_hw_intf.h | 169 + .../isp_hw_mgr/isp_hw/include/cam_isp_hw.h | 222 + .../isp_hw/include/cam_vfe_hw_intf.h | 299 ++ .../cam_isp/isp_hw_mgr/isp_hw/vfe_hw/Makefile | 15 + .../isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c | 825 ++++ .../isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.h | 96 + .../isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_dev.c | 197 + .../isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_dev.h | 42 + .../isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c | 293 ++ .../isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h | 116 + .../isp_hw_mgr/isp_hw/vfe_hw/vfe170/Makefile | 14 + .../isp_hw/vfe_hw/vfe170/cam_vfe170.c | 51 + .../isp_hw/vfe_hw/vfe170/cam_vfe170.h | 837 ++++ .../isp_hw/vfe_hw/vfe170/cam_vfe_lite170.c | 51 + .../isp_hw/vfe_hw/vfe170/cam_vfe_lite170.h | 336 ++ .../isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/Makefile | 14 + .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus.c | 56 + .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver1.h | 120 + .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c | 3090 ++++++++++++ .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h | 210 + .../vfe_hw/vfe_bus/include/cam_vfe_bus.h | 85 + .../isp_hw_mgr/isp_hw/vfe_hw/vfe_top/Makefile | 13 + .../vfe_hw/vfe_top/cam_vfe_camif_ver2.c | 503 ++ .../vfe_hw/vfe_top/cam_vfe_camif_ver2.h | 87 + .../isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c | 301 ++ .../isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.h | 50 + .../isp_hw/vfe_hw/vfe_top/cam_vfe_top.c | 54 + .../isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c | 834 ++++ .../isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h | 66 + .../vfe_hw/vfe_top/include/cam_vfe_top.h | 41 + .../msm/camera_oneplus/cam_jpeg/Makefile | 11 + .../cam_jpeg/cam_jpeg_context.c | 169 + .../cam_jpeg/cam_jpeg_context.h | 74 + .../camera_oneplus/cam_jpeg/cam_jpeg_dev.c | 157 + .../camera_oneplus/cam_jpeg/cam_jpeg_dev.h | 37 + .../camera_oneplus/cam_jpeg/jpeg_hw/Makefile | 13 + .../cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c | 1477 ++++++ .../cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.h | 162 + .../jpeg_hw/include/cam_jpeg_hw_intf.h | 44 + .../jpeg_hw/include/cam_jpeg_hw_mgr_intf.h | 24 + .../cam_jpeg/jpeg_hw/jpeg_dma_hw/Makefile | 11 + .../jpeg_hw/jpeg_dma_hw/jpeg_dma_core.c | 198 + .../jpeg_hw/jpeg_dma_hw/jpeg_dma_core.h | 52 + .../jpeg_hw/jpeg_dma_hw/jpeg_dma_dev.c | 239 + .../jpeg_hw/jpeg_dma_hw/jpeg_dma_soc.c | 63 + .../jpeg_hw/jpeg_dma_hw/jpeg_dma_soc.h | 25 + .../cam_jpeg/jpeg_hw/jpeg_enc_hw/Makefile | 11 + .../cam_jpeg_enc_hw_info_ver_4_2_0.h | 79 + .../jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c | 432 ++ .../jpeg_hw/jpeg_enc_hw/jpeg_enc_core.h | 87 + .../jpeg_hw/jpeg_enc_hw/jpeg_enc_dev.c | 237 + .../jpeg_hw/jpeg_enc_hw/jpeg_enc_soc.c | 63 + .../jpeg_hw/jpeg_enc_hw/jpeg_enc_soc.h | 25 + .../msm/camera_oneplus/cam_lrme/Makefile | 14 + .../cam_lrme/cam_lrme_context.c | 255 + .../cam_lrme/cam_lrme_context.h | 41 + .../camera_oneplus/cam_lrme/cam_lrme_dev.c | 233 + .../cam_lrme/lrme_hw_mgr/Makefile | 14 + .../cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c | 1116 +++++ .../cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.h | 120 + .../lrme_hw_mgr/cam_lrme_hw_mgr_intf.h | 25 + .../cam_lrme/lrme_hw_mgr/lrme_hw/Makefile | 13 + .../lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c | 1243 +++++ .../lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.h | 457 ++ .../lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c | 321 ++ .../lrme_hw_mgr/lrme_hw/cam_lrme_hw_intf.h | 200 + .../lrme_hw_mgr/lrme_hw/cam_lrme_hw_reg.h | 193 + .../lrme_hw_mgr/lrme_hw/cam_lrme_hw_soc.c | 158 + .../lrme_hw_mgr/lrme_hw/cam_lrme_hw_soc.h | 28 + .../msm/camera_oneplus/cam_req_mgr/Makefile | 11 + .../camera_oneplus/cam_req_mgr/cam_mem_mgr.c | 1252 +++++ .../camera_oneplus/cam_req_mgr/cam_mem_mgr.h | 131 + .../cam_req_mgr/cam_mem_mgr_api.h | 125 + .../cam_req_mgr/cam_req_mgr_core.c | 2730 +++++++++++ .../cam_req_mgr/cam_req_mgr_core.h | 454 ++ .../cam_req_mgr/cam_req_mgr_core_defs.h | 25 + .../cam_req_mgr/cam_req_mgr_debug.c | 139 + .../cam_req_mgr/cam_req_mgr_debug.h | 21 + .../cam_req_mgr/cam_req_mgr_dev.c | 744 +++ .../cam_req_mgr/cam_req_mgr_dev.h | 50 + .../cam_req_mgr/cam_req_mgr_interface.h | 332 ++ .../cam_req_mgr/cam_req_mgr_timer.c | 100 + .../cam_req_mgr/cam_req_mgr_timer.h | 71 + .../cam_req_mgr/cam_req_mgr_util.c | 340 ++ .../cam_req_mgr/cam_req_mgr_util.h | 172 + .../cam_req_mgr/cam_req_mgr_util_priv.h | 49 + .../cam_req_mgr/cam_req_mgr_workq.c | 280 ++ .../cam_req_mgr/cam_req_mgr_workq.h | 138 + .../camera_oneplus/cam_req_mgr/cam_subdev.h | 115 + .../camera_oneplus/cam_sensor_module/Makefile | 10 + .../cam_sensor_module/cam_actuator/Makefile | 11 + .../cam_actuator/cam_actuator_core.c | 863 ++++ .../cam_actuator/cam_actuator_core.h | 73 + .../cam_actuator/cam_actuator_dev.c | 440 ++ .../cam_actuator/cam_actuator_dev.h | 129 + .../cam_actuator/cam_actuator_soc.c | 75 + .../cam_actuator/cam_actuator_soc.h | 26 + .../cam_sensor_module/cam_cci/Makefile | 8 + .../cam_sensor_module/cam_cci/cam_cci_core.c | 1383 ++++++ .../cam_sensor_module/cam_cci/cam_cci_core.h | 46 + .../cam_sensor_module/cam_cci/cam_cci_dev.c | 385 ++ .../cam_sensor_module/cam_cci/cam_cci_dev.h | 305 ++ .../cam_sensor_module/cam_cci/cam_cci_hwreg.h | 69 + .../cam_sensor_module/cam_cci/cam_cci_soc.c | 409 ++ .../cam_sensor_module/cam_cci/cam_cci_soc.h | 52 + .../cam_sensor_module/cam_csiphy/Makefile | 9 + .../cam_csiphy/cam_csiphy_core.c | 724 +++ .../cam_csiphy/cam_csiphy_core.h | 59 + .../cam_csiphy/cam_csiphy_dev.c | 252 + .../cam_csiphy/cam_csiphy_dev.h | 238 + .../cam_csiphy/cam_csiphy_soc.c | 237 + .../cam_csiphy/cam_csiphy_soc.h | 78 + .../cam_csiphy/include/cam_csiphy_1_0_hwreg.h | 355 ++ .../cam_sensor_module/cam_eeprom/Makefile | 8 + .../cam_eeprom/cam_eeprom_core.c | 983 ++++ .../cam_eeprom/cam_eeprom_core.h | 28 + .../cam_eeprom/cam_eeprom_dev.c | 573 +++ .../cam_eeprom/cam_eeprom_dev.h | 189 + .../cam_eeprom/cam_eeprom_soc.c | 382 ++ .../cam_eeprom/cam_eeprom_soc.h | 23 + .../cam_sensor_module/cam_flash/Makefile | 10 + .../cam_flash/cam_flash_core.c | 982 ++++ .../cam_flash/cam_flash_core.h | 35 + .../cam_flash/cam_flash_dev.c | 420 ++ .../cam_flash/cam_flash_dev.h | 181 + .../cam_flash/cam_flash_soc.c | 225 + .../cam_flash/cam_flash_soc.h | 21 + .../cam_sensor_module/cam_ir_led/Makefile | 10 + .../cam_ir_led/cam_ir_led_core.c | 233 + .../cam_ir_led/cam_ir_led_core.h | 29 + .../cam_ir_led/cam_ir_led_dev.c | 383 ++ .../cam_ir_led/cam_ir_led_dev.h | 140 + .../cam_ir_led/cam_ir_led_soc.c | 46 + .../cam_ir_led/cam_ir_led_soc.h | 21 + .../cam_sensor_module/cam_ois/Makefile | 10 + .../cam_ois/ROHM_BU24218GWL_OIS.h | 2216 +++++++++ .../cam_sensor_module/cam_ois/cam_ois_core.c | 893 ++++ .../cam_sensor_module/cam_ois/cam_ois_core.h | 40 + .../cam_sensor_module/cam_ois/cam_ois_dev.c | 419 ++ .../cam_sensor_module/cam_ois/cam_ois_dev.h | 133 + .../cam_sensor_module/cam_ois/cam_ois_soc.c | 118 + .../cam_sensor_module/cam_ois/cam_ois_soc.h | 19 + .../cam_sensor_module/cam_res_mgr/Makefile | 9 + .../cam_res_mgr/cam_res_mgr.c | 737 +++ .../cam_res_mgr/cam_res_mgr_api.h | 148 + .../cam_res_mgr/cam_res_mgr_private.h | 117 + .../cam_sensor/CAM_SENSOR_SETTINGS.h | 1024 ++++ .../cam_sensor_module/cam_sensor/Makefile | 10 + .../cam_sensor/cam_sensor_core.c | 1455 ++++++ .../cam_sensor/cam_sensor_core.h | 93 + .../cam_sensor/cam_sensor_dev.c | 445 ++ .../cam_sensor/cam_sensor_dev.h | 118 + .../cam_sensor/cam_sensor_soc.c | 252 + .../cam_sensor/cam_sensor_soc.h | 25 + .../cam_sensor_module/cam_sensor_io/Makefile | 9 + .../cam_sensor_io/cam_sensor_cci_i2c.c | 235 + .../cam_sensor_io/cam_sensor_i2c.h | 180 + .../cam_sensor_io/cam_sensor_io.c | 194 + .../cam_sensor_io/cam_sensor_io.h | 119 + .../cam_sensor_io/cam_sensor_qup_i2c.c | 526 ++ .../cam_sensor_io/cam_sensor_spi.c | 617 +++ .../cam_sensor_io/cam_sensor_spi.h | 112 + .../cam_sensor_utils/Makefile | 8 + .../cam_sensor_utils/cam_sensor_cmn_header.h | 394 ++ .../cam_sensor_utils/cam_sensor_util.c | 1754 +++++++ .../cam_sensor_utils/cam_sensor_util.h | 59 + .../msm/camera_oneplus/cam_smmu/Makefile | 3 + .../camera_oneplus/cam_smmu/cam_smmu_api.c | 3412 +++++++++++++ .../camera_oneplus/cam_smmu/cam_smmu_api.h | 371 ++ .../msm/camera_oneplus/cam_sync/Makefile | 3 + .../msm/camera_oneplus/cam_sync/cam_sync.c | 1077 +++++ .../camera_oneplus/cam_sync/cam_sync_api.h | 128 + .../cam_sync/cam_sync_private.h | 198 + .../camera_oneplus/cam_sync/cam_sync_util.c | 479 ++ .../camera_oneplus/cam_sync/cam_sync_util.h | 165 + .../msm/camera_oneplus/cam_utils/Makefile | 5 + .../cam_utils/cam_common_util.c | 35 + .../cam_utils/cam_common_util.h | 35 + .../camera_oneplus/cam_utils/cam_debug_util.c | 112 + .../camera_oneplus/cam_utils/cam_debug_util.h | 118 + .../camera_oneplus/cam_utils/cam_io_util.c | 288 ++ .../camera_oneplus/cam_utils/cam_io_util.h | 239 + .../cam_utils/cam_packet_util.c | 263 + .../cam_utils/cam_packet_util.h | 130 + .../camera_oneplus/cam_utils/cam_soc_util.c | 1403 ++++++ .../camera_oneplus/cam_utils/cam_soc_util.h | 619 +++ .../msm/camera_oneplus/cam_utils/cam_trace.c | 16 + .../msm/camera_oneplus/cam_utils/cam_trace.h | 307 ++ include/uapi/media/cam_cpas.h | 84 + include/uapi/media/cam_defs.h | 633 +++ include/uapi/media/cam_fd.h | 127 + include/uapi/media/cam_icp.h | 204 + include/uapi/media/cam_isp.h | 510 ++ include/uapi/media/cam_isp_ife.h | 44 + include/uapi/media/cam_isp_vfe.h | 44 + include/uapi/media/cam_jpeg.h | 117 + include/uapi/media/cam_lrme.h | 65 + include/uapi/media/cam_req_mgr.h | 456 ++ include/uapi/media/cam_sensor.h | 505 ++ include/uapi/media/cam_sync.h | 134 + 331 files changed, 104823 insertions(+) create mode 100644 drivers/media/platform/msm/camera_oneplus/Makefile create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_cdm/Makefile create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_core_common.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_core_common.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_hw_core.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_intf.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_intf_api.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_soc.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_soc.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_util.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_util.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_virtual.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_virtual_core.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_hw_cdm170_reg.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_core/Makefile create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_core/cam_context.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_core/cam_context.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_core/cam_context_utils.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_core/cam_context_utils.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_core/cam_core_defs.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_core/cam_hw.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_core/cam_hw_intf.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_core/cam_hw_mgr_intf.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_core/cam_node.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_core/cam_node.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_core/cam_subdev.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_cpas/Makefile create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_cpas/cam_cpas_hw.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_cpas/cam_cpas_hw.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_cpas/cam_cpas_hw_intf.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_cpas/cam_cpas_intf.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_cpas/cam_cpas_soc.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_cpas/cam_cpas_soc.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_cpas/camss_top/Makefile create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_cpas/camss_top/cam_camsstop_hw.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_cpas/cpas_top/Makefile create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_cpas/cpas_top/cam_cpastop_hw.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_cpas/cpas_top/cam_cpastop_hw.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_cpas/cpas_top/cpastop100.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_cpas/cpas_top/cpastop_v170_110.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_cpas/cpas_top/cpastop_v175_100.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_cpas/cpas_top/cpastop_v175_101.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_cpas/include/cam_cpas_api.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_fd/Makefile create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_fd/cam_fd_context.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_fd/cam_fd_context.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_fd/cam_fd_dev.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/Makefile create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/cam_fd_hw_mgr_intf.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/fd_hw/Makefile create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_intf.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v41.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v501.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_icp/Makefile create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_icp/cam_icp_context.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_icp/cam_icp_context.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_icp/cam_icp_subdev.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_icp/fw_inc/hfi_intf.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_icp/fw_inc/hfi_reg.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_icp/fw_inc/hfi_session_defs.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_icp/fw_inc/hfi_sys_defs.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_icp/hfi.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/Makefile create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/a5_hw/Makefile create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/a5_hw/a5_core.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/a5_hw/a5_core.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/a5_hw/a5_dev.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/a5_hw/a5_soc.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/a5_hw/a5_soc.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/bps_hw/Makefile create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/bps_hw/bps_core.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/bps_hw/bps_core.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/bps_hw/bps_dev.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/bps_hw/bps_soc.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/bps_hw/bps_soc.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/Makefile create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/include/cam_a5_hw_intf.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/include/cam_bps_hw_intf.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/include/cam_icp_hw_intf.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/include/cam_ipe_hw_intf.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/ipe_hw/Makefile create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/ipe_hw/ipe_core.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/ipe_hw/ipe_core.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/ipe_hw/ipe_dev.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/ipe_hw/ipe_soc.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/ipe_hw/ipe_soc.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/Makefile create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/cam_isp_context.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/cam_isp_context.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/cam_isp_dev.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/cam_isp_dev.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/cam_isp_log.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/Makefile create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/cam_isp_hw_mgr.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/cam_isp_hw_mgr.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/Makefile create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/include/cam_isp_packet_parser.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/include/cam_tasklet_util.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/irq_controller/Makefile create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/Makefile create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/Makefile create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_dev.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_dev.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite170.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite170.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/Makefile create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_dev.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_dev.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/Makefile create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe170.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe170.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe_lite170.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe_lite170.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/Makefile create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver1.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/include/cam_vfe_bus.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/Makefile create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/include/cam_vfe_top.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_jpeg/Makefile create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_jpeg/cam_jpeg_context.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_jpeg/cam_jpeg_context.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_jpeg/cam_jpeg_dev.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_jpeg/cam_jpeg_dev.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/Makefile create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_intf.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_mgr_intf.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_dma_hw/Makefile create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_dev.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_soc.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_soc.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_enc_hw/Makefile create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_enc_hw/cam_jpeg_enc_hw_info_ver_4_2_0.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_dev.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_soc.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_soc.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_lrme/Makefile create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_lrme/cam_lrme_context.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_lrme/cam_lrme_context.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_lrme/cam_lrme_dev.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/Makefile create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr_intf.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/lrme_hw/Makefile create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_intf.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_reg.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_soc.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_soc.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_req_mgr/Makefile create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_mem_mgr.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_mem_mgr.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_mem_mgr_api.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_core.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_core.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_core_defs.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_debug.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_debug.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_dev.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_dev.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_interface.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_timer.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_timer.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_util.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_util.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_util_priv.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_workq.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_workq.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_subdev.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/Makefile create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_actuator/Makefile create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_actuator/cam_actuator_core.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_actuator/cam_actuator_core.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_actuator/cam_actuator_dev.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_actuator/cam_actuator_dev.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_actuator/cam_actuator_soc.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_actuator/cam_actuator_soc.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci/Makefile create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci/cam_cci_core.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci/cam_cci_core.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci/cam_cci_dev.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci/cam_cci_dev.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci/cam_cci_hwreg.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci/cam_cci_soc.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci/cam_cci_soc.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_csiphy/Makefile create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_csiphy/cam_csiphy_core.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_csiphy/cam_csiphy_core.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_csiphy/cam_csiphy_soc.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_0_hwreg.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_eeprom/Makefile create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_eeprom/cam_eeprom_core.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_eeprom/cam_eeprom_core.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_eeprom/cam_eeprom_dev.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_eeprom/cam_eeprom_soc.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_eeprom/cam_eeprom_soc.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_flash/Makefile create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_flash/cam_flash_core.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_flash/cam_flash_core.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_flash/cam_flash_dev.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_flash/cam_flash_dev.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_flash/cam_flash_soc.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_flash/cam_flash_soc.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ir_led/Makefile create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ir_led/cam_ir_led_core.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ir_led/cam_ir_led_core.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ir_led/cam_ir_led_dev.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ir_led/cam_ir_led_dev.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ir_led/cam_ir_led_soc.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ir_led/cam_ir_led_soc.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ois/Makefile create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ois/ROHM_BU24218GWL_OIS.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ois/cam_ois_core.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ois/cam_ois_core.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ois/cam_ois_dev.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ois/cam_ois_dev.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ois/cam_ois_soc.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ois/cam_ois_soc.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_res_mgr/Makefile create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_res_mgr/cam_res_mgr.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_res_mgr/cam_res_mgr_api.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_res_mgr/cam_res_mgr_private.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/CAM_SENSOR_SETTINGS.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/Makefile create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/cam_sensor_core.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/cam_sensor_core.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/cam_sensor_dev.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/cam_sensor_dev.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/cam_sensor_soc.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/cam_sensor_soc.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io/Makefile create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io/cam_sensor_i2c.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io/cam_sensor_io.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io/cam_sensor_io.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io/cam_sensor_qup_i2c.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io/cam_sensor_spi.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io/cam_sensor_spi.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_utils/Makefile create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_utils/cam_sensor_util.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_smmu/Makefile create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_smmu/cam_smmu_api.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_smmu/cam_smmu_api.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sync/Makefile create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sync/cam_sync.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sync/cam_sync_api.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sync/cam_sync_private.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sync/cam_sync_util.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_sync/cam_sync_util.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_utils/Makefile create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_utils/cam_common_util.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_utils/cam_common_util.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_utils/cam_debug_util.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_utils/cam_debug_util.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_utils/cam_io_util.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_utils/cam_io_util.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_utils/cam_packet_util.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_utils/cam_packet_util.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_utils/cam_soc_util.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_utils/cam_soc_util.h create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_utils/cam_trace.c create mode 100644 drivers/media/platform/msm/camera_oneplus/cam_utils/cam_trace.h create mode 100644 include/uapi/media/cam_cpas.h create mode 100644 include/uapi/media/cam_defs.h create mode 100644 include/uapi/media/cam_fd.h create mode 100644 include/uapi/media/cam_icp.h create mode 100644 include/uapi/media/cam_isp.h create mode 100644 include/uapi/media/cam_isp_ife.h create mode 100644 include/uapi/media/cam_isp_vfe.h create mode 100644 include/uapi/media/cam_jpeg.h create mode 100644 include/uapi/media/cam_lrme.h create mode 100644 include/uapi/media/cam_req_mgr.h create mode 100644 include/uapi/media/cam_sensor.h create mode 100644 include/uapi/media/cam_sync.h diff --git a/drivers/media/platform/msm/Kconfig b/drivers/media/platform/msm/Kconfig index 8130c34d05e3..97c36197a9c5 100644 --- a/drivers/media/platform/msm/Kconfig +++ b/drivers/media/platform/msm/Kconfig @@ -54,6 +54,15 @@ if MSMB_CAMERA source "drivers/media/platform/msm/camera_v2/Kconfig" endif # MSMB_CAMERA +menuconfig SPECTRA_CAMERA + bool "Qualcomm Technologies, Inc. Spectra camera and video capture support" + depends on ARCH_QCOM && VIDEO_V4L2 && I2C + ---help--- + Say Y here to enable selecting the video adapters for + Qualcomm Technologies, Inc. Spectra camera and video capture. + Enabling this adds support for the camera driver stack including sensor, + IFE and postprocessing drivers. + source "drivers/media/platform/msm/cvp/Kconfig" source "drivers/media/platform/msm/npu/Kconfig" source "drivers/media/platform/msm/synx/Kconfig" diff --git a/drivers/media/platform/msm/Makefile b/drivers/media/platform/msm/Makefile index b86dd83e9292..4d031f377e09 100644 --- a/drivers/media/platform/msm/Makefile +++ b/drivers/media/platform/msm/Makefile @@ -13,3 +13,4 @@ obj-$(CONFIG_TSPP) += broadcast/ obj-$(CONFIG_DVB_MPQ) += dvb/ obj-$(CONFIG_MSMB_CAMERA) += camera_v2/ obj-$(CONFIG_MSM_VIDC_LEGACY_V4L2) += vidc/ +obj-$(CONFIG_SPECTRA_CAMERA) += camera_oneplus/ diff --git a/drivers/media/platform/msm/camera_oneplus/Makefile b/drivers/media/platform/msm/camera_oneplus/Makefile new file mode 100644 index 000000000000..9e0aee9f69e3 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/Makefile @@ -0,0 +1,13 @@ +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/ diff --git a/drivers/media/platform/msm/camera_oneplus/cam_cdm/Makefile b/drivers/media/platform/msm/camera_oneplus/cam_cdm/Makefile new file mode 100644 index 000000000000..a8dfde110e42 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_cdm/Makefile @@ -0,0 +1,9 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_smmu +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_utils +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_core +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_cpas/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/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/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm.h b/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm.h new file mode 100644 index 000000000000..03f6e0c4d5c8 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm.h @@ -0,0 +1,261 @@ +/* Copyright (c) 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. + */ + +#ifndef _CAM_CDM_H_ +#define _CAM_CDM_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#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; + uint64_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/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_core_common.c b/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_core_common.c new file mode 100644 index 000000000000..6d699cf965eb --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_core_common.c @@ -0,0 +1,569 @@ +/* Copyright (c) 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#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: + 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: + 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)) + 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; + + ahb_vote.type = CAM_VOTE_ABSOLUTE; + ahb_vote.vote.level = CAM_SVS_VOTE; + axi_vote.compressed_bw = CAM_CPAS_DEFAULT_AXI_BW; + axi_vote.uncompressed_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/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_core_common.h b/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_core_common.h new file mode 100644 index 000000000000..497832b4eeff --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_core_common.h @@ -0,0 +1,50 @@ +/* Copyright (c) 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. + */ + +#ifndef _CAM_CDM_CORE_COMMON_H_ +#define _CAM_CDM_CORE_COMMON_H_ + +#include "cam_mem_mgr.h" + +#define CAM_CDM170_VERSION 0x10000000 + +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/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_hw_core.c b/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_hw_core.c new file mode 100644 index 000000000000..29de3159e5a7 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_hw_core.c @@ -0,0 +1,1144 @@ +/* Copyright (c) 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#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++) { + uint64_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)) { + 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", + i, core->bl_tag); + + 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=%x", payload->irq_status); + if (payload->irq_status & + CAM_CDM_IRQ_STATUS_INFO_INLINE_IRQ_MASK) { + struct cam_cdm_bl_cb_request_entry *node; + + CAM_DBG(CAM_CDM, "inline IRQ 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, + "Inval node, inline_irq st=%x data=%x", + payload->irq_status, payload->irq_data); + } + 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) +{ + 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 (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); + 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"); + work_status = queue_work(cdm_core->work_queue, &payload->work); + if (work_status == false) { + CAM_ERR(CAM_CDM, "Failed to queue work for irq=%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; + + 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_reg_client_page_fault_handler(cdm_core->iommu_hdl.non_secure, + cam_hw_cdm_iommu_fault_handler, cdm_hw); + + rc = cam_smmu_ops(cdm_core->iommu_hdl.non_secure, CAM_SMMU_ATTACH); + if (rc < 0) { + CAM_ERR(CAM_CDM, "Attach iommu non secure handle failed"); + goto destroy_non_secure_hdl; + } + 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_SVS_VOTE; + axi_vote.compressed_bw = CAM_CPAS_DEFAULT_AXI_BW; + axi_vote.uncompressed_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_reg_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_reg_client_page_fault_handler(cdm_core->iommu_hdl.non_secure, + NULL, 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, + }, +}; + +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/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_intf.c b/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_intf.c new file mode 100644 index 000000000000..fa98be2285b7 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_intf.c @@ -0,0 +1,580 @@ +/* Copyright (c) 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#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->identifier) || (!data->base_array) || + (!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); + } + + 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, + }, +}; + +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/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_intf_api.h b/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_intf_api.h new file mode 100644 index 000000000000..2b00a87544fa --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_intf_api.h @@ -0,0 +1,209 @@ +/* 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_CDM_API_H_ +#define _CAM_CDM_API_H_ + +#include +#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; + void *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/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_soc.c b/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_soc.c new file mode 100644 index 000000000000..f8b0d3dffcae --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_soc.c @@ -0,0 +1,208 @@ +/* Copyright (c) 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#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/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_soc.h b/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_soc.h new file mode 100644 index 000000000000..765aba4d5bac --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_soc.h @@ -0,0 +1,28 @@ +/* Copyright (c) 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. + */ + +#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/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_util.c b/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_util.c new file mode 100644 index 000000000000..c8b830ff82ea --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_util.c @@ -0,0 +1,542 @@ +/* Copyright (c) 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. + */ + +#include +#include +#include +#include + +#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 + +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_CONTINUOUSROL*/ + 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 { + 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_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; +} diff --git a/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_util.h b/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_util.h new file mode 100644 index 000000000000..09d0d638c987 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_util.h @@ -0,0 +1,161 @@ +/* Copyright (c) 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. + */ + +#ifndef _CAM_CDM_UTIL_H_ +#define _CAM_CDM_UTIL_H_ + +#define CAM_CDM_SW_CMD_COUNT 2 +#define CAM_CMD_LENGTH_MASK 0xFFFF +#define CAM_CDM_COMMAND_OFFSET 24 + +#define CAM_CDM_DMI_DATA_HI_OFFSET 8 +#define CAM_CDM_DMI_DATA_LO_OFFSET 12 + +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); +}; + +#endif /* _CAM_CDM_UTIL_H_ */ diff --git a/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_virtual.h b/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_virtual.h new file mode 100644 index 000000000000..ed0721862a74 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_virtual.h @@ -0,0 +1,25 @@ +/* Copyright (c) 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. + */ + +#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/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_virtual_core.c b/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_virtual_core.c new file mode 100644 index 000000000000..d76f344c1efa --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_virtual_core.c @@ -0,0 +1,384 @@ +/* Copyright (c) 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#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++) { + uint64_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 = + (uint64_t)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)) { + 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/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_hw_cdm170_reg.h b/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_hw_cdm170_reg.h new file mode 100644 index 000000000000..183b657100d2 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_hw_cdm170_reg.h @@ -0,0 +1,142 @@ +/* Copyright (c) 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. + */ + +#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/drivers/media/platform/msm/camera_oneplus/cam_core/Makefile b/drivers/media/platform/msm/camera_oneplus/cam_core/Makefile new file mode 100644 index 000000000000..d08bc1a11ea6 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_core/Makefile @@ -0,0 +1,6 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_req_mgr +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_smmu/ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_sync +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_utils + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_context.o cam_context_utils.o cam_node.o cam_subdev.o diff --git a/drivers/media/platform/msm/camera_oneplus/cam_core/cam_context.c b/drivers/media/platform/msm/camera_oneplus/cam_core/cam_context.c new file mode 100644 index 000000000000..98fff4838050 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_core/cam_context.c @@ -0,0 +1,496 @@ +/* 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. + */ + +#include +#include +#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; + + if (ctx->state_machine[ctx->state].ioctl_ops.stop_dev) { + rc = ctx->state_machine[ctx->state].ioctl_ops.stop_dev( + ctx, NULL); + if (rc < 0) + CAM_ERR(CAM_CORE, "Error while dev stop %d", rc); + } + if (ctx->state_machine[ctx->state].ioctl_ops.release_dev) { + rc = ctx->state_machine[ctx->state].ioctl_ops.release_dev( + ctx, NULL); + if (rc < 0) + CAM_ERR(CAM_CORE, "Error while dev release %d", rc); + } + + 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_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_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_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->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->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); + mutex_unlock(&ctx->ctx_mutex); + + 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); + + ctx->dev_name = dev_name; + ctx->dev_id = dev_id; + ctx->ctx_id = ctx_id; + 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, atomic_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, "cam_context_getref fail\n"); + } + CAM_DBG(CAM_CORE, + "ctx device hdl %ld, ref count %d, dev_name %s", + ctx->dev_hdl, atomic_read(&(ctx->refcount.refcount)), + ctx->dev_name); +} diff --git a/drivers/media/platform/msm/camera_oneplus/cam_core/cam_context.h b/drivers/media/platform/msm/camera_oneplus/cam_core/cam_context.h new file mode 100644 index 000000000000..8324e78d9e0e --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_core/cam_context.h @@ -0,0 +1,420 @@ +/* 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_CONTEXT_H_ +#define _CAM_CONTEXT_H_ + +#include +#include +#include +#include "cam_req_mgr_interface.h" +#include "cam_hw_mgr_intf.h" + +/* Forward declarations */ +struct cam_context; + +/* 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_ACTIVATED = 4, + CAM_CTX_STATE_MAX = 5, +}; + +/** + * 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 + * + */ +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; + uint32_t num_in_acked; + uint32_t num_out_acked; + int flushed; + struct cam_context *ctx; +}; + +/** + * 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 + * + */ +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); +}; + +/** + * 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 *); + 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 + * + */ +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; +}; + +/** + * 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 + * + */ +struct cam_context { + const char *dev_name; + 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; +}; + +/** + * 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_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_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_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_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/drivers/media/platform/msm/camera_oneplus/cam_core/cam_context_utils.c b/drivers/media/platform/msm/camera_oneplus/cam_core/cam_context_utils.c new file mode 100644 index 000000000000..71561c0fddd1 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_core/cam_context_utils.c @@ -0,0 +1,881 @@ +/* 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. + */ + +#include +#include +#include +#include +#include +#include + +#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 + 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; + } + + req->num_in_acked++; + if (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_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; + uint64_t packet_addr; + struct cam_packet *packet; + size_t len = 0; + int32_t i = 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; + } + 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); + rc = -ENOMEM; + goto end; + } + + 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, + (uint64_t *) &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; + } + + packet = (struct cam_packet *) (packet_addr + cmd->offset); + + /* preprocess the configuration */ + memset(&cfg, 0, sizeof(cfg)); + cfg.packet = packet; + 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; + + 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; + req->request_id = packet->header.request_id; + req->status = 1; + req->req_priv = cfg.priv; + + 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 (i = 0; i < req->num_in_map_entries; i++) { + cam_context_getref(ctx); + rc = cam_sync_register_callback( + cam_context_sync_callback, + (void *)req, + req->in_map_entries[i].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[i].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); + + cam_context_putref(ctx); + + goto free_req; + } + CAM_DBG(CAM_CTXT, "register in fence cb: %d ret = %d", + req->in_map_entries[i].sync_id, rc); + } + goto end; + } + + return rc; + +free_req: + spin_lock(&ctx->lock); + list_add_tail(&req->list, &ctx->free_req_list); + req->ctx = NULL; + spin_unlock(&ctx->lock); +end: + 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; +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; + bool free_req = false; + uint32_t i; + int rc = 0; + + CAM_DBG(CAM_CTXT, "[%s] E: NRT flush ctx", ctx->dev_name); + + /* + * 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; + 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); + req->num_in_acked = req->num_in_acked + 1; + if (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); + + 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); + req->num_in_acked = req->num_in_acked + 1; + if (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) + 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; +} diff --git a/drivers/media/platform/msm/camera_oneplus/cam_core/cam_context_utils.h b/drivers/media/platform/msm/camera_oneplus/cam_core/cam_context_utils.h new file mode 100644 index 000000000000..9b95eaddb3c7 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_core/cam_context_utils.h @@ -0,0 +1,35 @@ +/* Copyright (c) 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. + */ + +#ifndef _CAM_CONTEXT_UTILS_H_ +#define _CAM_CONTEXT_UTILS_H_ + +#include + +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_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); + +#endif /* _CAM_CONTEXT_UTILS_H_ */ diff --git a/drivers/media/platform/msm/camera_oneplus/cam_core/cam_core_defs.h b/drivers/media/platform/msm/camera_oneplus/cam_core/cam_core_defs.h new file mode 100644 index 000000000000..45d989f9b6e4 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_core/cam_core_defs.h @@ -0,0 +1,45 @@ +/* Copyright (c) 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. + */ + +#ifndef _CAM_CORE_DEFS_H_ +#define _CAM_CORE_DEFS_H_ + +#define CAM_CORE_TRACE_ENABLE 0 + +#if (CAM_CORE_TRACE_ENABLE == 1) + #define CAM_CORE_DBG(fmt, args...) do { \ + trace_printk("%d: [cam_core_dbg] "fmt"\n", __LINE__, ##args); \ + pr_debug("%s:%d "fmt"\n", __func__, __LINE__, ##args); \ + } while (0) + + #define CAM_CORE_WARN(fmt, args...) do { \ + trace_printk("%d: [cam_core_warn] "fmt"\n", __LINE__, ##args); \ + pr_warn("%s:%d "fmt"\n", __func__, __LINE__, ##args); \ + } while (0) + + #define CAM_CORE_ERR(fmt, args...) do { \ + trace_printk("%d: [cam_core_err] "fmt"\n", __LINE__, ##args); \ + pr_err("%s:%d "fmt"\n", __func__, __LINE__, ##args);\ + } while (0) +#else + #define CAM_CORE_DBG(fmt, args...) pr_debug("%s:%d "fmt"\n", \ + __func__, __LINE__, ##args) + + #define CAM_CORE_WARN(fmt, args...) pr_warn("%s:%d "fmt"\n", \ + __func__, __LINE__, ##args) + + #define CAM_CORE_ERR(fmt, args...) pr_err("%s:%d "fmt"\n", \ + __func__, __LINE__, ##args) +#endif + +#endif /* _CAM_CORE_DEFS_H_ */ + diff --git a/drivers/media/platform/msm/camera_oneplus/cam_core/cam_hw.h b/drivers/media/platform/msm/camera_oneplus/cam_core/cam_hw.h new file mode 100644 index 000000000000..d01a84ae33e6 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_core/cam_hw.h @@ -0,0 +1,53 @@ +/* Copyright (c) 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. + */ + +#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/drivers/media/platform/msm/camera_oneplus/cam_core/cam_hw_intf.h b/drivers/media/platform/msm/camera_oneplus/cam_core/cam_hw_intf.h new file mode 100644 index 000000000000..bd2b789101bb --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_core/cam_hw_intf.h @@ -0,0 +1,83 @@ +/* Copyright (c) 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. + */ + +#ifndef _CAM_HW_INTF_H_ +#define _CAM_HW_INTF_H_ + +#include + +/* + * 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; +}; + +#endif /* _CAM_HW_INTF_H_ */ diff --git a/drivers/media/platform/msm/camera_oneplus/cam_core/cam_hw_mgr_intf.h b/drivers/media/platform/msm/camera_oneplus/cam_core/cam_hw_mgr_intf.h new file mode 100644 index 000000000000..f7990b6d5d4a --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_core/cam_hw_mgr_intf.h @@ -0,0 +1,254 @@ +/* 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_HW_MGR_INTF_H_ +#define _CAM_HW_MGR_INTF_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 + +/* hardware event callback function type */ +typedef int (*cam_hw_event_cb_func)(void *context, uint32_t evt_id, + void *evt_data); + +/** + * 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; + uint64_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) + * + */ +struct cam_hw_acquire_args { + void *context_data; + cam_hw_event_cb_func event_cb; + uint32_t num_acq; + uint64_t acquire_info; + void *ctxt_to_hw_map; +}; + +/** + * 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_prepare_update_args - Payload for prepare command + * + * @packet: CSL packet from user mode driver + * @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) + * @priv: Private pointer of hw update + * + */ +struct cam_hw_prepare_update_args { + struct cam_packet *packet; + 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; + 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 + * + */ +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; +}; + +/** + * 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 + * + */ +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; +}; + +/** + * 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: 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 + * + */ +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)(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); +}; + +#endif /* _CAM_HW_MGR_INTF_H_ */ diff --git a/drivers/media/platform/msm/camera_oneplus/cam_core/cam_node.c b/drivers/media/platform/msm/camera_oneplus/cam_core/cam_node.c new file mode 100644 index 000000000000..7e5b3ca2fd81 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_core/cam_node.c @@ -0,0 +1,576 @@ +/* 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. + */ + +#include +#include +#include + +#include "cam_node.h" +#include "cam_trace.h" +#include "cam_debug_util.h" + +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 uint64_t LrmeaRequreCount = 0; +static uint64_t LrmeaReleaseCount = 0; +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; + if (!strcmp(node->name, "cam-lrme")){ + CAM_ERR(CAM_CORE, "Acquire device for node %s session_handle =%d, %lld", + node->name,acquire->session_handle, ++LrmeaRequreCount); + } + ctx = cam_node_get_ctxt_from_free_list(node); + if (!ctx) { + rc = -ENOMEM; + if (!strcmp(node->name, "cam-lrme")) + CAM_ERR(CAM_CORE, "Can not get context for node %s", node->name); + goto err; + } + + 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; + } + + return 0; +free_ctx: + cam_context_putref(ctx); +err: + return rc; +} + +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; + } + + 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; + } + + 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; + } + + 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; + } + + 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; + } + if (!strcmp(node->name, "cam-lrme")){ + CAM_ERR(CAM_CORE, "cam_node_handle_release_dev %d,node %s, %lld", + release->dev_handle, node->name,++LrmeaReleaseCount); + } + 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; + } + + rc = cam_context_handle_release_dev(ctx, release); + if (rc) + CAM_ERR(CAM_CORE, "context release failed node %s", node->name); + + rc = cam_destroy_device_hdl(release->dev_handle); + if (rc) + CAM_ERR(CAM_CORE, "destroy device handle is failed node %s", + node->name); + + cam_context_putref(ctx); + 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; + + if (!node) + return -EINVAL; + + for (i = 0; i < node->ctx_size; i++) { + if (node->ctx_list[i].dev_hdl >= 0) { + cam_context_shutdown(&(node->ctx_list[i])); + cam_destroy_device_hdl(node->ctx_list[i].dev_hdl); + cam_context_putref(&(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, (void __user *)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((void __user *)cmd->handle, &query, + sizeof(query))) + rc = -EFAULT; + + break; + } + case CAM_ACQUIRE_DEV: { + struct cam_acquire_dev_cmd acquire; + + if (copy_from_user(&acquire, (void __user *)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((void __user *)cmd->handle, &acquire, + sizeof(acquire))) + rc = -EFAULT; + break; + } + case CAM_START_DEV: { + struct cam_start_stop_dev_cmd start; + + if (copy_from_user(&start, (void __user *)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, (void __user *)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, (void __user *)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, (void __user *)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_FLUSH_REQ: { + struct cam_flush_dev_cmd flush; + + if (copy_from_user(&flush, (void __user *)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/drivers/media/platform/msm/camera_oneplus/cam_core/cam_node.h b/drivers/media/platform/msm/camera_oneplus/cam_core/cam_node.h new file mode 100644 index 000000000000..4303ee38dd54 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_core/cam_node.h @@ -0,0 +1,111 @@ +/* Copyright (c) 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. + */ + +#ifndef _CAM_NODE_H_ +#define _CAM_NODE_H_ + +#include +#include "cam_context.h" +#include "cam_hw_mgr_intf.h" +#include "cam_req_mgr_interface.h" + +#define CAM_NODE_NAME_LENGTH_MAX 256 + +#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_NODE_NAME_LENGTH_MAX]; + 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/drivers/media/platform/msm/camera_oneplus/cam_core/cam_subdev.c b/drivers/media/platform/msm/camera_oneplus/cam_core/cam_subdev.c new file mode 100644 index 000000000000..d690508b85c0 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_core/cam_subdev.c @@ -0,0 +1,161 @@ +/* Copyright (c) 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. + */ + +#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/drivers/media/platform/msm/camera_oneplus/cam_cpas/Makefile b/drivers/media/platform/msm/camera_oneplus/cam_cpas/Makefile new file mode 100644 index 000000000000..68e4a1ceff9b --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_cpas/Makefile @@ -0,0 +1,10 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_utils +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_req_mgr +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_core +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_cpas/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_cpas/cpas_top +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_cpas/camss_top + +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/drivers/media/platform/msm/camera_oneplus/cam_cpas/cam_cpas_hw.c b/drivers/media/platform/msm/camera_oneplus/cam_cpas/cam_cpas_hw.c new file mode 100644 index 000000000000..5e4ff0d73f67 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_cpas/cam_cpas_hw.c @@ -0,0 +1,1692 @@ +/* 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "cam_cpas_hw.h" +#include "cam_cpas_hw_intf.h" +#include "cam_cpas_soc.h" + +#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 (3000000000L) + +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%8x] Value[0x%8x]", + 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] index[%d]", bus_client->client_id, + 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] :ab[%llu] ib[%llu], index[%d]", + bus_client->client_id, 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; + mutex_init(&bus_client->lock); + + CAM_DBG(CAM_CPAS, "Bus Client : src=%d, dst=%d, bus_client=%d", + bus_client->src, bus_client->dst, bus_client->client_id); + + 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) +{ + struct cam_cpas_private_soc *soc_private = + (struct cam_cpas_private_soc *)soc_info->soc_private; + struct cam_cpas_axi_port *curr_port; + struct cam_cpas_axi_port *temp_port; + + list_for_each_entry_safe(curr_port, temp_port, + &cpas_core->axi_ports_list_head, sibling_port) { + cam_cpas_util_unregister_bus_client(&curr_port->mnoc_bus); + of_node_put(curr_port->axi_port_mnoc_node); + if (soc_private->axi_camnoc_based) { + cam_cpas_util_unregister_bus_client( + &curr_port->camnoc_bus); + of_node_put(curr_port->axi_port_camnoc_node); + } + of_node_put(curr_port->axi_port_node); + list_del(&curr_port->sibling_port); + mutex_destroy(&curr_port->lock); + kfree(curr_port); + } + + of_node_put(soc_private->axi_port_list_node); + + return 0; +} + +static int cam_cpas_util_axi_setup(struct cam_cpas *cpas_core, + struct cam_hw_soc_info *soc_info) +{ + struct cam_cpas_private_soc *soc_private = + (struct cam_cpas_private_soc *)soc_info->soc_private; + struct cam_cpas_axi_port *axi_port; + int rc; + struct device_node *axi_port_list_node; + struct device_node *axi_port_node = NULL; + struct device_node *axi_port_mnoc_node = NULL; + struct device_node *axi_port_camnoc_node = NULL; + + INIT_LIST_HEAD(&cpas_core->axi_ports_list_head); + + axi_port_list_node = of_find_node_by_name(soc_info->pdev->dev.of_node, + "qcom,axi-port-list"); + if (!axi_port_list_node) { + CAM_ERR(CAM_CPAS, "Node qcom,axi-port-list not found."); + return -EINVAL; + } + + soc_private->axi_port_list_node = axi_port_list_node; + + for_each_available_child_of_node(axi_port_list_node, axi_port_node) { + axi_port = kzalloc(sizeof(*axi_port), GFP_KERNEL); + if (!axi_port) { + rc = -ENOMEM; + goto error_previous_axi_cleanup; + } + axi_port->axi_port_node = axi_port_node; + + rc = of_property_read_string_index(axi_port_node, + "qcom,axi-port-name", 0, + (const char **)&axi_port->axi_port_name); + if (rc) { + CAM_ERR(CAM_CPAS, + "failed to read qcom,axi-port-name rc=%d", rc); + goto port_name_fail; + } + + axi_port_mnoc_node = of_find_node_by_name(axi_port_node, + "qcom,axi-port-mnoc"); + if (!axi_port_mnoc_node) { + CAM_ERR(CAM_CPAS, "Node qcom,axi-port-mnoc not found."); + rc = -EINVAL; + goto mnoc_node_get_fail; + } + axi_port->axi_port_mnoc_node = axi_port_mnoc_node; + + rc = cam_cpas_util_register_bus_client(soc_info, + axi_port_mnoc_node, &axi_port->mnoc_bus); + if (rc) + goto mnoc_register_fail; + + if (soc_private->axi_camnoc_based) { + axi_port_camnoc_node = of_find_node_by_name( + axi_port_node, "qcom,axi-port-camnoc"); + if (!axi_port_camnoc_node) { + CAM_ERR(CAM_CPAS, + "Node qcom,axi-port-camnoc not found"); + rc = -EINVAL; + goto camnoc_node_get_fail; + } + axi_port->axi_port_camnoc_node = axi_port_camnoc_node; + + rc = cam_cpas_util_register_bus_client(soc_info, + axi_port_camnoc_node, &axi_port->camnoc_bus); + if (rc) + goto camnoc_register_fail; + } + + mutex_init(&axi_port->lock); + + INIT_LIST_HEAD(&axi_port->sibling_port); + list_add_tail(&axi_port->sibling_port, + &cpas_core->axi_ports_list_head); + INIT_LIST_HEAD(&axi_port->clients_list_head); + } + + return 0; +camnoc_register_fail: + of_node_put(axi_port->axi_port_camnoc_node); +camnoc_node_get_fail: + cam_cpas_util_unregister_bus_client(&axi_port->mnoc_bus); +mnoc_register_fail: + of_node_put(axi_port->axi_port_mnoc_node); +mnoc_node_get_fail: +port_name_fail: + of_node_put(axi_port->axi_port_node); + kfree(axi_port); +error_previous_axi_cleanup: + cam_cpas_util_axi_cleanup(cpas_core, soc_info); + return rc; +} + +static int cam_cpas_util_vote_default_ahb_axi(struct cam_hw_info *cpas_hw, + int enable) +{ + int rc; + struct cam_cpas *cpas_core = (struct cam_cpas *)cpas_hw->core_info; + struct cam_cpas_axi_port *curr_port; + struct cam_cpas_axi_port *temp_port; + uint64_t camnoc_bw, mnoc_bw; + struct cam_cpas_private_soc *soc_private = + (struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private; + + 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) { + mnoc_bw = CAM_CPAS_DEFAULT_AXI_BW; + camnoc_bw = CAM_CPAS_DEFAULT_AXI_BW; + } else { + mnoc_bw = 0; + camnoc_bw = 0; + } + + list_for_each_entry_safe(curr_port, temp_port, + &cpas_core->axi_ports_list_head, sibling_port) { + rc = cam_cpas_util_vote_bus_client_bw(&curr_port->mnoc_bus, + mnoc_bw, mnoc_bw, false); + if (rc) { + CAM_ERR(CAM_CPAS, + "Failed in mnoc vote, enable=%d, rc=%d", + enable, rc); + goto remove_ahb_vote; + } + + if (soc_private->axi_camnoc_based) { + cam_cpas_util_vote_bus_client_bw( + &curr_port->camnoc_bus, 0, camnoc_bw, true); + if (rc) { + CAM_ERR(CAM_CPAS, + "Failed in mnoc vote, enable=%d, %d", + enable, rc); + cam_cpas_util_vote_bus_client_bw( + &curr_port->mnoc_bus, 0, 0, false); + 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_util_insert_client_to_axi_port(struct cam_cpas *cpas_core, + struct cam_cpas_private_soc *soc_private, + struct cam_cpas_client *cpas_client, int32_t client_indx) +{ + struct cam_cpas_axi_port *curr_port; + struct cam_cpas_axi_port *temp_port; + + list_for_each_entry_safe(curr_port, temp_port, + &cpas_core->axi_ports_list_head, sibling_port) { + if (strnstr(curr_port->axi_port_name, + soc_private->client_axi_port_name[client_indx], + strlen(curr_port->axi_port_name))) { + + cpas_client->axi_port = curr_port; + INIT_LIST_HEAD(&cpas_client->axi_sibling_client); + + mutex_lock(&curr_port->lock); + list_add_tail(&cpas_client->axi_sibling_client, + &cpas_client->axi_port->clients_list_head); + mutex_unlock(&curr_port->lock); + break; + } + } + + return 0; +} + +static void cam_cpas_util_remove_client_from_axi_port( + struct cam_cpas_client *cpas_client) +{ + mutex_lock(&cpas_client->axi_port->lock); + list_del(&cpas_client->axi_sibling_client); + mutex_unlock(&cpas_client->axi_port->lock); +} + +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; + 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]); + + if (!CAM_CPAS_CLIENT_STARTED(cpas_core, client_indx)) { + CAM_ERR(CAM_CPAS, "client has not started%d", client_indx); + 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; + 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; + + mutex_lock(&cpas_core->client_mutex[client_indx]); + + if (!CAM_CPAS_CLIENT_STARTED(cpas_core, client_indx)) { + CAM_ERR(CAM_CPAS, "client has not started%d", client_indx); + rc = -EPERM; + goto unlock_client; + } + + 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; + +unlock_client: + mutex_unlock(&cpas_core->client_mutex[client_indx]); + return rc; +} + +static int cam_cpas_util_set_camnoc_axi_clk_rate( + struct cam_hw_info *cpas_hw) +{ + 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 rc = 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; + struct cam_cpas_axi_port *curr_axi_port = NULL; + struct cam_cpas_axi_port *temp_axi_port = NULL; + uint64_t required_camnoc_bw = 0; + int32_t clk_rate = 0; + + list_for_each_entry_safe(curr_axi_port, temp_axi_port, + &cpas_core->axi_ports_list_head, sibling_port) { + + if (curr_axi_port->consolidated_axi_vote.uncompressed_bw + > required_camnoc_bw) + required_camnoc_bw = curr_axi_port-> + consolidated_axi_vote.uncompressed_bw; + + CAM_DBG(CAM_CPAS, "[%s] : curr=%llu, overal=%llu", + curr_axi_port->axi_port_name, + curr_axi_port->consolidated_axi_vote. + uncompressed_bw, + required_camnoc_bw); + } + + required_camnoc_bw += (required_camnoc_bw * + soc_private->camnoc_axi_clk_bw_margin) / 100; + + if ((required_camnoc_bw > 0) && + (required_camnoc_bw < CAM_CPAS_AXI_MIN_CAMNOC_IB_BW)) + required_camnoc_bw = CAM_CPAS_AXI_MIN_CAMNOC_IB_BW; + + clk_rate = required_camnoc_bw / soc_private->camnoc_bus_width; + + CAM_DBG(CAM_CPAS, "Setting camnoc axi clk rate : %llu %d", + required_camnoc_bw, clk_rate); + + rc = cam_soc_util_set_clk_rate( + soc_info->clk[soc_info->src_clk_idx], + soc_info->clk_name[soc_info->src_clk_idx], + clk_rate); + if (!rc) + CAM_ERR(CAM_CPAS, + "Failed in setting camnoc axi clk %llu %d %d", + required_camnoc_bw, clk_rate, rc); + } + + 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_private_soc *soc_private = + (struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private; + struct cam_cpas_client *curr_client; + struct cam_cpas_client *temp_client; + struct cam_axi_vote req_axi_vote = *axi_vote; + struct cam_cpas_axi_port *axi_port = cpas_client->axi_port; + uint64_t camnoc_bw = 0, mnoc_bw = 0; + int rc = 0; + + if (!axi_port) { + CAM_ERR(CAM_CPAS, "axi port does not exists"); + return -EINVAL; + } + + /* + * Make sure we use same bw for both compressed, uncompressed + * in case client has requested either of one only + */ + if (req_axi_vote.compressed_bw == 0) + req_axi_vote.compressed_bw = req_axi_vote.uncompressed_bw; + + if (req_axi_vote.uncompressed_bw == 0) + req_axi_vote.uncompressed_bw = req_axi_vote.compressed_bw; + + if ((cpas_client->axi_vote.compressed_bw == + req_axi_vote.compressed_bw) && + (cpas_client->axi_vote.uncompressed_bw == + req_axi_vote.uncompressed_bw)) + return 0; + + mutex_lock(&axi_port->lock); + cpas_client->axi_vote = req_axi_vote; + + list_for_each_entry_safe(curr_client, temp_client, + &axi_port->clients_list_head, axi_sibling_client) { + camnoc_bw += curr_client->axi_vote.uncompressed_bw; + mnoc_bw += curr_client->axi_vote.compressed_bw; + } + + if ((!soc_private->axi_camnoc_based) && (mnoc_bw < camnoc_bw)) + mnoc_bw = camnoc_bw; + + axi_port->consolidated_axi_vote.compressed_bw = mnoc_bw; + axi_port->consolidated_axi_vote.uncompressed_bw = camnoc_bw; + + CAM_DBG(CAM_CPAS, + "axi[(%d, %d),(%d, %d)] : camnoc_bw[%llu], mnoc_bw[%llu]", + axi_port->mnoc_bus.src, axi_port->mnoc_bus.dst, + axi_port->camnoc_bus.src, axi_port->camnoc_bus.dst, + camnoc_bw, mnoc_bw); + + rc = cam_cpas_util_vote_bus_client_bw(&axi_port->mnoc_bus, + mnoc_bw, mnoc_bw, false); + if (rc) { + CAM_ERR(CAM_CPAS, + "Failed in mnoc vote ab[%llu] ib[%llu] rc=%d", + mnoc_bw, mnoc_bw, rc); + goto unlock_axi_port; + } + + if (soc_private->axi_camnoc_based) { + rc = cam_cpas_util_vote_bus_client_bw(&axi_port->camnoc_bus, + 0, camnoc_bw, true); + if (rc) { + CAM_ERR(CAM_CPAS, + "Failed camnoc vote ab[%llu] ib[%llu] rc=%d", + (uint64_t)0, camnoc_bw, rc); + goto unlock_axi_port; + } + } + + mutex_unlock(&axi_port->lock); + + 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; + +unlock_axi_port: + mutex_unlock(&axi_port->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_axi_vote axi_vote; + 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 (!client_axi_vote) { + CAM_ERR(CAM_CPAS, "Invalid arg client_handle=%d", + client_handle); + return -EINVAL; + } + + axi_vote = *client_axi_vote; + + if ((axi_vote.compressed_bw == 0) && + (axi_vote.uncompressed_bw == 0)) { + CAM_DBG(CAM_CPAS, "0 vote from client_handle=%d", + client_handle); + axi_vote.compressed_bw = CAM_CPAS_DEFAULT_AXI_BW; + axi_vote.uncompressed_bw = CAM_CPAS_DEFAULT_AXI_BW; + } + + 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_STARTED(cpas_core, client_indx)) { + CAM_ERR(CAM_CPAS, "client has not started %d", client_indx); + rc = -EPERM; + goto unlock_client; + } + + CAM_DBG(CAM_CPAS, + "Client[%d] Requested compressed[%llu], uncompressed[%llu]", + client_indx, axi_vote.compressed_bw, + axi_vote.uncompressed_bw); + + 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, "Clients required level[%d], curr_level[%d]", + 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); + + 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; + 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]); + + if (!CAM_CPAS_CLIENT_STARTED(cpas_core, client_indx)) { + CAM_ERR(CAM_CPAS, "client has not started %d", client_indx); + rc = -EPERM; + goto unlock_client; + } + + CAM_DBG(CAM_CPAS, + "client[%d] : type[%d], level[%d], freq[%ld], applied[%d]", + client_indx, 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_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; + enum cam_vote_level applied_level = CAM_SVS_VOTE; + int rc; + struct cam_cpas_private_soc *soc_private = NULL; + + 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 %ld %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; + axi_vote = cmd_hw_start->axi_vote; + + if (!ahb_vote || !axi_vote) + return -EINVAL; + + if ((ahb_vote->vote.level == 0) || ((axi_vote->compressed_bw == 0) && + (axi_vote->uncompressed_bw == 0))) { + CAM_ERR(CAM_CPAS, "Invalid vote ahb[%d], axi[%llu], [%llu]", + ahb_vote->vote.level, axi_vote->compressed_bw, + axi_vote->uncompressed_bw); + 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]); + + if (!CAM_CPAS_CLIENT_REGISTERED(cpas_core, client_indx)) { + CAM_ERR(CAM_CPAS, "client is not registered %d", client_indx); + rc = -EPERM; + goto done; + } + + if (CAM_CPAS_CLIENT_STARTED(cpas_core, client_indx)) { + CAM_ERR(CAM_CPAS, "Client %d is in start state", client_indx); + rc = -EPERM; + goto done; + } + + cpas_client = cpas_core->cpas_client[client_indx]; + + CAM_DBG(CAM_CPAS, "AHB :client[%d] type[%d], level[%d], applied[%d]", + client_indx, 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_DBG(CAM_CPAS, + "AXI client[%d] compressed_bw[%llu], uncompressed_bw[%llu]", + client_indx, axi_vote->compressed_bw, + axi_vote->uncompressed_bw); + rc = cam_cpas_util_apply_client_axi_vote(cpas_hw, + cpas_client, axi_vote); + if (rc) + goto done; + + if (cpas_core->streamon_clients == 0) { + 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=%s, streamon_clients=%d", + soc_private->client_name[client_indx], + 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; + 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 %ld %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]); + + CAM_DBG(CAM_CPAS, "client=%s, streamon_clients=%d", + soc_private->client_name[client_indx], + cpas_core->streamon_clients); + + if (!CAM_CPAS_CLIENT_STARTED(cpas_core, client_indx)) { + CAM_ERR(CAM_CPAS, "Client %d is not started", client_indx); + rc = -EPERM; + goto done; + } + + cpas_client = cpas_core->cpas_client[client_indx]; + 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; + + axi_vote.uncompressed_bw = 0; + axi_vote.compressed_bw = 0; + rc = cam_cpas_util_apply_client_axi_vote(cpas_hw, + cpas_client, &axi_vote); + +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 %ld %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; + struct cam_cpas_client *cpas_client; + 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; + + 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); + if (rc || !CAM_CPAS_CLIENT_VALID(client_indx) || + CAM_CPAS_CLIENT_REGISTERED(cpas_core, client_indx)) { + CAM_ERR(CAM_CPAS, "Invalid Client register : %s %d, %d", + register_params->identifier, + register_params->cell_index, client_indx); + mutex_unlock(&cpas_hw->hw_mutex); + return -EPERM; + } + + cpas_client = kzalloc(sizeof(struct cam_cpas_client), GFP_KERNEL); + if (!cpas_client) { + mutex_unlock(&cpas_hw->hw_mutex); + return -ENOMEM; + } + + rc = cam_cpas_util_insert_client_to_axi_port(cpas_core, soc_private, + cpas_client, client_indx); + if (rc) { + CAM_ERR(CAM_CPAS, + "axi_port_insert failed client_indx=%d, rc=%d", + client_indx, rc); + kfree(cpas_client); + mutex_unlock(&cpas_hw->hw_mutex); + return -EINVAL; + } + + register_params->client_handle = + CAM_CPAS_GET_CLIENT_HANDLE(client_indx); + memcpy(&cpas_client->data, register_params, + sizeof(struct cam_cpas_register_params)); + cpas_core->cpas_client[client_indx] = cpas_client; + cpas_core->registered_clients++; + + mutex_unlock(&cpas_hw->hw_mutex); + + CAM_DBG(CAM_CPAS, "client_indx=%d, registered_clients=%d", + client_indx, cpas_core->registered_clients); + + 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 not registered %d", client_indx); + rc = -EPERM; + goto done; + } + + if (CAM_CPAS_CLIENT_STARTED(cpas_core, client_indx)) { + CAM_ERR(CAM_CPAS, "Client %d is not stopped", client_indx); + rc = -EPERM; + goto done; + } + + cam_cpas_util_remove_client_from_axi_port( + cpas_core->cpas_client[client_indx]); + + CAM_DBG(CAM_CPAS, "client_indx=%d, registered_clients=%d", + client_indx, cpas_core->registered_clients); + + kfree(cpas_core->cpas_client[client_indx]); + cpas_core->cpas_client[client_indx] = NULL; + 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 %ld %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]); + cpas_core->cpas_client[i] = NULL; + } + + return 0; +} + +static 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]) { + cam_cpas_hw_unregister_client(cpas_hw, 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_get_hw_version(struct platform_device *pdev, + struct cam_hw_soc_info *soc_info) +{ + struct device_node *of_node = pdev->dev.of_node; + int rc; + + soc_info->hw_version = 0; + + rc = of_property_read_u32(of_node, + "qcom,cpas-hw-ver", &soc_info->hw_version); + + CAM_DBG(CAM_CPAS, "CPAS HW VERSION %x", soc_info->hw_version); + + if (rc) { + CAM_ERR(CAM_CPAS, "failed to get CPAS HW Version rc=%d", rc); + return -EINVAL; + } + + 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; + 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_get_hw_version(pdev, &cpas_hw->soc_info); + if (rc) + goto axi_cleanup; + + *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: + 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_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); + 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/drivers/media/platform/msm/camera_oneplus/cam_cpas/cam_cpas_hw.h b/drivers/media/platform/msm/camera_oneplus/cam_cpas/cam_cpas_hw.h new file mode 100644 index 000000000000..2e660b1adb95 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_cpas/cam_cpas_hw.h @@ -0,0 +1,202 @@ +/* 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_CPAS_HW_H_ +#define _CAM_CPAS_HW_H_ + +#include "cam_cpas_api.h" +#include "cam_cpas_hw_intf.h" +#include "cam_common_util.h" + +#define CAM_CPAS_MAX_CLIENTS 30 +#define CAM_CPAS_INFLIGHT_WORKS 5 + +#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])) +#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 + * @started: Whether client has streamed on + * @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 + * @axi_sibling_client: Client's sibllings sharing the same axi port + * + */ +struct cam_cpas_client { + struct cam_cpas_register_params data; + bool started; + enum cam_vote_level ahb_level; + struct cam_axi_vote axi_vote; + struct cam_cpas_axi_port *axi_port; + struct list_head axi_sibling_client; +}; + +/** + * 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 + * + */ +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; +}; + +/** + * struct cam_cpas_axi_port : AXI port information + * + * @sibling_port: Sibling AXI ports + * @clients_list_head: List head pointing to list of clients sharing this port + * @lock: Mutex lock for accessing this port + * @camnoc_bus: CAMNOC bus client info for this port + * @mnoc_bus: MNOC bus client info for this port + * @axi_port_name: Name of this AXI port + * @axi_port_node: Node representing this AXI Port + * @axi_port_mnoc_node: Node representing mnoc in this AXI Port + * @axi_port_camnoc_node: Node representing camnoc in this AXI Port + * @consolidated_axi_vote: Consolidated axi bw values for this AXI port + * + */ +struct cam_cpas_axi_port { + struct list_head sibling_port; + struct list_head clients_list_head; + struct mutex lock; + struct cam_cpas_bus_client camnoc_bus; + struct cam_cpas_bus_client mnoc_bus; + const char *axi_port_name; + struct device_node *axi_port_node; + struct device_node *axi_port_mnoc_node; + struct device_node *axi_port_camnoc_node; + struct cam_axi_vote consolidated_axi_vote; +}; + +/** + * 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 + * @num_clients: Total number of clients that CPAS supports + * @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_ports_list_head: Head pointing to list of AXI ports + * @internal_ops: CPAS HW internal ops + * @work_queue: Work queue handle + * + */ +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]; + uint32_t num_clients; + 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 list_head axi_ports_list_head; + struct cam_cpas_internal_ops internal_ops; + struct workqueue_struct *work_queue; + atomic_t irq_count; + wait_queue_head_t irq_count_wq; +}; + +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); + +#endif /* _CAM_CPAS_HW_H_ */ diff --git a/drivers/media/platform/msm/camera_oneplus/cam_cpas/cam_cpas_hw_intf.h b/drivers/media/platform/msm/camera_oneplus/cam_cpas/cam_cpas_hw_intf.h new file mode 100644 index 000000000000..fa4018e27c71 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_cpas/cam_cpas_hw_intf.h @@ -0,0 +1,135 @@ +/* Copyright (c) 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. + */ + +#ifndef _CAM_CPAS_HW_INTF_H_ +#define _CAM_CPAS_HW_INTF_H_ + +#include + +#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/drivers/media/platform/msm/camera_oneplus/cam_cpas/cam_cpas_intf.c b/drivers/media/platform/msm/camera_oneplus/cam_cpas/cam_cpas_intf.c new file mode 100644 index 000000000000..0187a6400275 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_cpas/cam_cpas_intf.c @@ -0,0 +1,660 @@ +/* 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cam_subdev.h" +#include "cam_cpas_hw_intf.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; + +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 (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 (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, (void __user *) 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((void __user *) 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); + 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, + }, +}; + +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/drivers/media/platform/msm/camera_oneplus/cam_cpas/cam_cpas_soc.c b/drivers/media/platform/msm/camera_oneplus/cam_cpas/cam_cpas_soc.c new file mode 100644 index 000000000000..46ee90c5f9c4 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_cpas/cam_cpas_soc.c @@ -0,0 +1,275 @@ +/* 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. + */ + +#include +#include +#include +#include +#include +#include + +#include "cam_cpas_api.h" +#include "cam_cpas_hw_intf.h" +#include "cam_cpas_hw.h" +#include "cam_cpas_soc.h" + +int cam_cpas_get_custom_dt_info(struct platform_device *pdev, + struct cam_cpas_private_soc *soc_private) +{ + struct device_node *of_node; + int count = 0, i = 0, rc = 0; + + if (!soc_private || !pdev) { + CAM_ERR(CAM_CPAS, "invalid input arg %pK %pK", + soc_private, pdev); + return -EINVAL; + } + + of_node = pdev->dev.of_node; + + rc = of_property_read_string_index(of_node, "arch-compat", 0, + (const char **)&soc_private->arch_compat); + if (rc) { + CAM_ERR(CAM_CPAS, "device %s failed to read arch-compat", + pdev->name); + return rc; + } + + + soc_private->hw_version = 0; + rc = of_property_read_u32(of_node, + "qcom,cpas-hw-ver", &soc_private->hw_version); + if (rc) { + CAM_ERR(CAM_CPAS, "device %s failed to read cpas-hw-ver", + pdev->name); + return rc; + } + + CAM_DBG(CAM_CPAS, "CPAS HW VERSION %x", soc_private->hw_version); + + 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; + } + 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 -ENODEV; + } + CAM_DBG(CAM_CPAS, "Client[%d] : %s", i, + soc_private->client_name[i]); + } + + count = of_property_count_strings(of_node, "client-axi-port-names"); + if ((count <= 0) || (count != soc_private->num_clients)) { + CAM_ERR(CAM_CPAS, "incorrect client-axi-port-names info %d %d", + count, soc_private->num_clients); + count = 0; + return -EINVAL; + } + + for (i = 0; i < soc_private->num_clients; i++) { + rc = of_property_read_string_index(of_node, + "client-axi-port-names", i, + &soc_private->client_axi_port_name[i]); + if (rc) { + CAM_ERR(CAM_CPAS, "no client-name at cnt=%d", i); + return -ENODEV; + } + CAM_DBG(CAM_CPAS, "Client AXI Port[%d] : %s", i, + soc_private->client_axi_port_name[i]); + } + + soc_private->axi_camnoc_based = of_property_read_bool(of_node, + "client-bus-camnoc-based"); + + 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); + return rc; + } + + 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); + return -ENODEV; + } + + 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); + return -ENODEV; + } + + 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); + return -EINVAL; + } + + 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; + } + + return 0; +} + +int cam_cpas_soc_init_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t irq_handler, void *irq_data) +{ + 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, + irq_data); + 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(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 disble_irq) +{ + int rc = 0; + + rc = cam_soc_util_disable_platform_resource(soc_info, + disable_clocks, disble_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/drivers/media/platform/msm/camera_oneplus/cam_cpas/cam_cpas_soc.h b/drivers/media/platform/msm/camera_oneplus/cam_cpas/cam_cpas_soc.h new file mode 100644 index 000000000000..70c49bdd28df --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_cpas/cam_cpas_soc.h @@ -0,0 +1,76 @@ +/* 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_CPAS_SOC_H_ +#define _CAM_CPAS_SOC_H_ + +#include "cam_soc_util.h" +#include "cam_cpas_hw.h" + +#define CAM_REGULATOR_LEVEL_MAX 16 + +/** + * 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 cam_cpas_private_soc : CPAS private DT info + * + * @arch_compat: ARCH compatible string + * @hw_version: Camera HW version + * @client_id_based: Whether clients are id based + * @num_clients: Number of clients supported + * @client_name: Client names + * @axi_camnoc_based: Whether AXi access is camnoc based + * @client_axi_port_name: AXI Port name for each client + * @axi_port_list_node : Node representing AXI Ports list + * @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 + * + */ +struct cam_cpas_private_soc { + const char *arch_compat; + uint32_t hw_version; + bool client_id_based; + uint32_t num_clients; + const char *client_name[CAM_CPAS_MAX_CLIENTS]; + bool axi_camnoc_based; + const char *client_axi_port_name[CAM_CPAS_MAX_CLIENTS]; + struct device_node *axi_port_list_node; + 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; +}; + +int cam_cpas_soc_init_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t vfe_irq_handler, void *irq_data); +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 disble_irq); +int cam_cpas_soc_disable_irq(struct cam_hw_soc_info *soc_info); +#endif /* _CAM_CPAS_SOC_H_ */ diff --git a/drivers/media/platform/msm/camera_oneplus/cam_cpas/camss_top/Makefile b/drivers/media/platform/msm/camera_oneplus/cam_cpas/camss_top/Makefile new file mode 100644 index 000000000000..a6cc9c2cb3f9 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_cpas/camss_top/Makefile @@ -0,0 +1,6 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_utils +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_core +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_cpas/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_cpas + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_camsstop_hw.o diff --git a/drivers/media/platform/msm/camera_oneplus/cam_cpas/camss_top/cam_camsstop_hw.c b/drivers/media/platform/msm/camera_oneplus/cam_cpas/camss_top/cam_camsstop_hw.c new file mode 100644 index 000000000000..0669070506bd --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_cpas/camss_top/cam_camsstop_hw.c @@ -0,0 +1,89 @@ +/* Copyright (c) 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. + */ + +#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/drivers/media/platform/msm/camera_oneplus/cam_cpas/cpas_top/Makefile b/drivers/media/platform/msm/camera_oneplus/cam_cpas/cpas_top/Makefile new file mode 100644 index 000000000000..d2ca9ff0cdcb --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_cpas/cpas_top/Makefile @@ -0,0 +1,6 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_utils +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_core +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_cpas/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_cpas + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_cpastop_hw.o diff --git a/drivers/media/platform/msm/camera_oneplus/cam_cpas/cpas_top/cam_cpastop_hw.c b/drivers/media/platform/msm/camera_oneplus/cam_cpas/cpas_top/cam_cpastop_hw.c new file mode 100644 index 000000000000..d6187ce210ce --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_cpas/cpas_top/cam_cpastop_hw.c @@ -0,0 +1,574 @@ +/* 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. + */ + +#include +#include +#include + +#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_v170_110.h" +#include "cpastop_v175_100.h" +#include "cpastop_v175_101.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); + + 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 timout 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; + + 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(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_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_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; + 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); + } + } + + 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_cpas_private_soc *soc_private = + (struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private; + + CAM_DBG(CAM_CPAS, + "hw_version=0x%x Camera Version %d.%d.%d, cpas version %d.%d.%d", + soc_private->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_private->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; + 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/drivers/media/platform/msm/camera_oneplus/cam_cpas/cpas_top/cam_cpastop_hw.h b/drivers/media/platform/msm/camera_oneplus/cam_cpas/cpas_top/cam_cpastop_hw.h new file mode 100644 index 000000000000..73f7e9be3eb7 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_cpas/cpas_top/cam_cpastop_hw.h @@ -0,0 +1,241 @@ +/* Copyright (c) 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. + */ + +#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_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_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_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_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_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_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_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_IPE_BPS_LRME_READ, + CAM_CAMNOC_IPE_BPS_LRME_WRITE, + 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 + * + */ +struct cam_cpas_hw_errata_wa_list { + struct cam_cpas_hw_errata_wa camnoc_flush_slave_pending_trans; +}; + +/** + * 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/drivers/media/platform/msm/camera_oneplus/cam_cpas/cpas_top/cpastop100.h b/drivers/media/platform/msm/camera_oneplus/cam_cpas/cpas_top/cpastop100.h new file mode 100644 index 000000000000..2654b4770b34 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_cpas/cpas_top/cpastop100.h @@ -0,0 +1,538 @@ +/* Copyright (c) 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. + */ + +#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/drivers/media/platform/msm/camera_oneplus/cam_cpas/cpas_top/cpastop_v170_110.h b/drivers/media/platform/msm/camera_oneplus/cam_cpas/cpas_top/cpastop_v170_110.h new file mode 100644 index 000000000000..e1af22b9f504 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_cpas/cpas_top/cpastop_v170_110.h @@ -0,0 +1,545 @@ +/* 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 _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/drivers/media/platform/msm/camera_oneplus/cam_cpas/cpas_top/cpastop_v175_100.h b/drivers/media/platform/msm/camera_oneplus/cam_cpas/cpas_top/cpastop_v175_100.h new file mode 100644 index 000000000000..e2aad09aa8e7 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_cpas/cpas_top/cpastop_v175_100.h @@ -0,0 +1,545 @@ +/* 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. + */ + +#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 = { + .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 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/drivers/media/platform/msm/camera_oneplus/cam_cpas/cpas_top/cpastop_v175_101.h b/drivers/media/platform/msm/camera_oneplus/cam_cpas/cpas_top/cpastop_v175_101.h new file mode 100644 index 000000000000..e5e967380c23 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_cpas/cpas_top/cpastop_v175_101.h @@ -0,0 +1,545 @@ +/* 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. + */ + +#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 = { + .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 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/drivers/media/platform/msm/camera_oneplus/cam_cpas/include/cam_cpas_api.h b/drivers/media/platform/msm/camera_oneplus/cam_cpas/include/cam_cpas_api.h new file mode 100644 index 000000000000..c844ef78a3c3 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_cpas/include/cam_cpas_api.h @@ -0,0 +1,517 @@ +/* Copyright (c) 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. + */ + +#ifndef _CAM_CPAS_API_H_ +#define _CAM_CPAS_API_H_ + +#include +#include + +#include +#include "cam_soc_util.h" + +#define CAM_HW_IDENTIFIER_LENGTH 128 + +/* Default AXI Bandwidth vote */ +#define CAM_CPAS_DEFAULT_AXI_BW 1024 + +/** + * 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_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_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_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_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_IFE02_UBWC_ENCODE_ERROR, + CAM_CAMNOC_IRQ_IFE13_UBWC_ENCODE_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 + * + * @uncompressed_bw : Bus bandwidth required in Bytes for uncompressed data + * This is the required bandwidth for uncompressed + * data traffic between hw core and camnoc. + * @compressed_bw : Bus bandwidth required in Bytes for compressed data. + * This is the required bandwidth for compressed + * data traffic between camnoc and mmnoc. + * + * If one of the above is not applicable to a hw client, it has to + * fill the same values in both. + * + */ +struct cam_axi_vote { + uint64_t uncompressed_bw; + uint64_t compressed_bw; +}; + +/** + * 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); + +#endif /* _CAM_CPAS_API_H_ */ diff --git a/drivers/media/platform/msm/camera_oneplus/cam_fd/Makefile b/drivers/media/platform/msm/camera_oneplus/cam_fd/Makefile new file mode 100644 index 000000000000..e5117b2cbe50 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_fd/Makefile @@ -0,0 +1,14 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_utils +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_req_mgr +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_core +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_sync +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_smmu +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_cdm +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_fd +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/fd_hw +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/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/drivers/media/platform/msm/camera_oneplus/cam_fd/cam_fd_context.c b/drivers/media/platform/msm/camera_oneplus/cam_fd/cam_fd_context.c new file mode 100644 index 000000000000..99c509c62809 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_fd/cam_fd_context.c @@ -0,0 +1,256 @@ +/* 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. + */ + +#include +#include + +#include "cam_debug_util.h" +#include "cam_fd_context.h" +#include "cam_trace.h" + +static const char fd_dev_name[] = "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, + }, + /* 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/drivers/media/platform/msm/camera_oneplus/cam_fd/cam_fd_context.h b/drivers/media/platform/msm/camera_oneplus/cam_fd/cam_fd_context.h new file mode 100644 index 000000000000..a8b5d159f265 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_fd/cam_fd_context.h @@ -0,0 +1,37 @@ +/* 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_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/drivers/media/platform/msm/camera_oneplus/cam_fd/cam_fd_dev.c b/drivers/media/platform/msm/camera_oneplus/cam_fd/cam_fd_dev.c new file mode 100644 index 000000000000..3f0124436b9e --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_fd/cam_fd_dev.c @@ -0,0 +1,213 @@ +/* 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. + */ + +#include +#include +#include +#include +#include + +#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; + + /* Initialze 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, + }, +}; + +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/drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/Makefile b/drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/Makefile new file mode 100644 index 000000000000..fa486052c9d8 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/Makefile @@ -0,0 +1,14 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_utils +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_req_mgr +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_core +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_sync +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_smmu +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_cdm +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_fd +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/fd_hw +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_cpas/include + +obj-$(CONFIG_SPECTRA_CAMERA) += fd_hw/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_fd_hw_mgr.o diff --git a/drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c b/drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c new file mode 100644 index 000000000000..a15ccdcf2dcc --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c @@ -0,0 +1,1941 @@ +/* Copyright (c) 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. + */ + +#include +#include +#include +#include + +#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) +{ + 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)) { + 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_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 %lu %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 %lu %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 i, j, plane, num_out_buf, num_in_buf; + struct cam_buf_io_cfg *io_cfg; + uint64_t io_addr[CAM_PACKET_MAX_PLANES]; + uint64_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) || (io_addr[plane] >> 32)) { + CAM_ERR(CAM_FD, + "Invalid io buf %d %d %d %d", + io_cfg[i].direction, + io_cfg[i].resource_type, plane, + rc); + return -ENOMEM; + } + + 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) { + CAM_ERR(CAM_FD, + "Invalid cpu buf %d %d %d %d", + io_cfg[i].direction, + io_cfg[i].resource_type, plane, + rc); + 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); + return -EINVAL; + } + } + + prepare->num_in_map_entries = num_in_buf; + prepare->num_out_map_entries = num_out_buf; + + return 0; +} + +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; + + if (copy_from_user(&query_fd, (void __user *)query->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((void __user *)query->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_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); + 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_ops(g_fd_hw_mgr.device_iommu.non_secure, CAM_SMMU_DETACH); + 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_smmu_ops(g_fd_hw_mgr.device_iommu.non_secure, CAM_SMMU_ATTACH); + if (rc) { + CAM_ERR(CAM_FD, "FD attach iommu handle failed, rc=%d", rc); + goto destroy_smmu; + } + + 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); + 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_ops(g_fd_hw_mgr.device_iommu.non_secure, CAM_SMMU_DETACH); +destroy_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/drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.h b/drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.h new file mode 100644 index 000000000000..db5d1002262a --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.h @@ -0,0 +1,186 @@ +/* Copyright (c) 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. + */ + +#ifndef _CAM_FD_HW_MGR_H_ +#define _CAM_FD_HW_MGR_H_ + +#include +#include + +#include +#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/drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/cam_fd_hw_mgr_intf.h b/drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/cam_fd_hw_mgr_intf.h new file mode 100644 index 000000000000..58cba4fad125 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/cam_fd_hw_mgr_intf.h @@ -0,0 +1,25 @@ +/* Copyright (c) 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. + */ + +#ifndef _CAM_FD_HW_MGR_INTF_H_ +#define _CAM_FD_HW_MGR_INTF_H_ + +#include + +#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/drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/fd_hw/Makefile b/drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/fd_hw/Makefile new file mode 100644 index 000000000000..1e89b80ea286 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/fd_hw/Makefile @@ -0,0 +1,13 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_utils +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_req_mgr +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_core +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_sync +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_smmu +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_cdm +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_fd +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/fd_hw +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/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/drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c b/drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c new file mode 100644 index 000000000000..a18afc6d7acc --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.c @@ -0,0 +1,1168 @@ +/* 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. + */ + +#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; + + 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); + 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); + + 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 -EINVAL; + } + + 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); + + 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 -EINVAL; + } + + trace_cam_irq_activated("FD", irq_type); + + cam_fd_soc_register_write(soc_info, CAM_FD_REG_WRAPPER, + hw_static_info->wrapper_regs.irq_clear, + hw_static_info->irq_mask); + + 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, %lu", 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, %lu", 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, %lu", 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, %lu", 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, %lu", 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/drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.h b/drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.h new file mode 100644 index 000000000000..3d9c5f0e90f8 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_core.h @@ -0,0 +1,244 @@ +/* Copyright (c) 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. + */ + +#ifndef _CAM_FD_HW_CORE_H_ +#define _CAM_FD_HW_CORE_H_ + +#include +#include +#include +#include +#include + +#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/drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c b/drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c new file mode 100644 index 000000000000..6d9d330f7838 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_dev.c @@ -0,0 +1,228 @@ +/* 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. + */ + +#include +#include +#include +#include +#include +#include + +#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" + +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; + 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; + } + + fd_hw_intf->hw_priv = fd_hw; + fd_hw->core_info = fd_core; + + 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 = pdev->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; + } + + fd_hw_intf->hw_idx = fd_hw->soc_info.index; + + 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, + }, + {} +}; +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, + }, +}; + +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/drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_intf.h b/drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_intf.h new file mode 100644 index 000000000000..aae7648ba1e2 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_intf.h @@ -0,0 +1,289 @@ +/* Copyright (c) 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. + */ + +#ifndef _CAM_FD_HW_INTF_H_ +#define _CAM_FD_HW_INTF_H_ + +#include +#include +#include +#include +#include +#include + +#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]; + uint64_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/drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.c b/drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.c new file mode 100644 index 000000000000..f27d016ae199 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.c @@ -0,0 +1,290 @@ +/* Copyright (c) 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. + */ + +#include +#include +#include +#include +#include +#include + +#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; +} + +static int cam_fd_soc_set_clk_flags(struct cam_hw_soc_info *soc_info) +{ + int i, rc = 0; + + if (soc_info->num_clk > CAM_SOC_MAX_CLK) { + CAM_ERR(CAM_FD, "Invalid num clk %d", soc_info->num_clk); + return -EINVAL; + } + + /* set memcore and mem periphery logic flags to 0 */ + for (i = 0; i < soc_info->num_clk; i++) { + if ((strcmp(soc_info->clk_name[i], "fd_core_clk") == 0) || + (strcmp(soc_info->clk_name[i], "fd_core_uar_clk") == + 0)) { + rc = cam_soc_util_set_clk_flags(soc_info, i, + CLKFLAG_NORETAIN_MEM); + if (rc) + CAM_ERR(CAM_FD, + "Failed in NORETAIN_MEM i=%d, rc=%d", + i, rc); + + cam_soc_util_set_clk_flags(soc_info, i, + CLKFLAG_NORETAIN_PERIPH); + if (rc) + CAM_ERR(CAM_FD, + "Failed in NORETAIN_PERIPH i=%d, rc=%d", + i, rc); + } + } + + return rc; +} + +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; + int rc; + + ahb_vote.type = CAM_VOTE_ABSOLUTE; + ahb_vote.vote.level = CAM_SVS_VOTE; + axi_vote.compressed_bw = 7200000; + axi_vote.uncompressed_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; + } + + rc = cam_fd_soc_set_clk_flags(soc_info); + if (rc) { + CAM_ERR(CAM_FD, "failed in set_clk_flags rc=%d", rc); + goto release_res; + } + + 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/drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.h b/drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.h new file mode 100644 index 000000000000..4a22293fab17 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_soc.h @@ -0,0 +1,53 @@ +/* Copyright (c) 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. + */ + +#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/drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v41.h b/drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v41.h new file mode 100644 index 000000000000..78257a591a31 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v41.h @@ -0,0 +1,70 @@ +/* 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_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, + .ro_mode_supported = true, +}; + +#endif /* _CAM_FD_HW_V41_H_ */ diff --git a/drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v501.h b/drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v501.h new file mode 100644 index 000000000000..44b9ab58e566 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/fd_hw/cam_fd_hw_v501.h @@ -0,0 +1,70 @@ +/* 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. + */ + +#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/drivers/media/platform/msm/camera_oneplus/cam_icp/Makefile b/drivers/media/platform/msm/camera_oneplus/cam_icp/Makefile new file mode 100644 index 000000000000..7f7d68debd05 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_icp/Makefile @@ -0,0 +1,14 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_utils +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_req_mgr +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_core +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_sync +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_icp +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_icp/fw_inc +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_cpas/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/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/drivers/media/platform/msm/camera_oneplus/cam_icp/cam_icp_context.c b/drivers/media/platform/msm/camera_oneplus/cam_icp/cam_icp_context.c new file mode 100644 index 000000000000..502c95d4c60e --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_icp/cam_icp_context.c @@ -0,0 +1,217 @@ +/* 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. + */ + +#include +#include +#include +#include +#include +#include +#include "cam_sync_api.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" + +static const char icp_dev_name[] = "icp"; + +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; + + 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, + }, + /* 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, + }, + /* Activated */ + { + .ioctl_ops = {}, + .crm_ops = {}, + .irq_ops = NULL, + }, +}; + +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/drivers/media/platform/msm/camera_oneplus/cam_icp/cam_icp_context.h b/drivers/media/platform/msm/camera_oneplus/cam_icp/cam_icp_context.h new file mode 100644 index 000000000000..0c3a360c7de5 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_icp/cam_icp_context.h @@ -0,0 +1,49 @@ +/* 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_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/drivers/media/platform/msm/camera_oneplus/cam_icp/cam_icp_subdev.c b/drivers/media/platform/msm/camera_oneplus/cam_icp/cam_icp_subdev.c new file mode 100644 index 000000000000..4f91f734e989 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_icp/cam_icp_subdev.c @@ -0,0 +1,254 @@ +/* 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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" + +#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 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_ERR(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; + + 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); + 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; + } + + g_icp_dev.open_cnt = 0; + mutex_init(&g_icp_dev.icp_lock); + + 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, + }, +}; + +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/drivers/media/platform/msm/camera_oneplus/cam_icp/fw_inc/hfi_intf.h b/drivers/media/platform/msm/camera_oneplus/cam_icp/fw_inc/hfi_intf.h new file mode 100644 index 000000000000..f5567801d95f --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_icp/fw_inc/hfi_intf.h @@ -0,0 +1,150 @@ +/* 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 _HFI_INTF_H_ +#define _HFI_INTF_H_ + +#include + +/** + * struct hfi_mem + * @len: length of memory + * @kva: kernel virtual address + * @iova: IO virtual address + * @reserved: reserved field + */ +struct hfi_mem { + uint64_t len; + uint64_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 + * @sec_heap: secondary heap hfi memory for firmware + * @qdss: qdss mapped memory for fw + * @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 sec_heap; + struct hfi_mem shmem; + struct hfi_mem qdss; + 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_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() - UBWC configuration to firmware + * @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); + +#endif /* _HFI_INTF_H_ */ diff --git a/drivers/media/platform/msm/camera_oneplus/cam_icp/fw_inc/hfi_reg.h b/drivers/media/platform/msm/camera_oneplus/cam_icp/fw_inc/hfi_reg.h new file mode 100644 index 000000000000..2153ceacbb83 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_icp/fw_inc/hfi_reg.h @@ -0,0 +1,324 @@ +/* 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. + */ + +#ifndef _CAM_HFI_REG_H_ +#define _CAM_HFI_REG_H_ + +#include +#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_QDSS_IOVA_SIZE 0x70 +/* 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_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 256 + +#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 + */ +enum intr_status { + INTR_DISABLE, + INTR_ENABLE +}; + +/** + * @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 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/drivers/media/platform/msm/camera_oneplus/cam_icp/fw_inc/hfi_session_defs.h b/drivers/media/platform/msm/camera_oneplus/cam_icp/fw_inc/hfi_session_defs.h new file mode 100644 index 000000000000..7b2cb8b1a412 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_icp/fw_inc/hfi_session_defs.h @@ -0,0 +1,530 @@ +/* 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_HFI_SESSION_DEFS_H +#define _CAM_HFI_SESSION_DEFS_H + +#include + +#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_HANDLE_TYPE_BPS 0x1 +#define HFI_IPEBPS_HANDLE_TYPE_IPE_RT 0x2 +#define HFI_IPEBPS_HANDLE_TYPE_IPE_NON_RT 0x3 + +/** + * 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_INPUT_IMAGE_FIRST = IPE_INPUT_IMAGE_FULL, + IPE_INPUT_IMAGE_LAST = IPE_INPUT_IMAGE_DS64_REF, + IPE_OUTPUT_IMAGE_FIRST = IPE_OUTPUT_IMAGE_DISPLAY, + IPE_OUTPUT_IMAGE_LAST = IPE_OUTPUT_IMAGE_DS64_REF, + 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 buffer_ptr[MAX_NUM_OF_IMAGE_PLANES]; + uint32_t meta_buffer_ptr[MAX_NUM_OF_IMAGE_PLANES]; +} __packed; + +struct bps_frame_process_data { + struct frame_buffer buffers[BPS_IO_IMAGES_MAX]; + 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; +}; + +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]; + struct ica_stab_params ica_params; + 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 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/drivers/media/platform/msm/camera_oneplus/cam_icp/fw_inc/hfi_sys_defs.h b/drivers/media/platform/msm/camera_oneplus/cam_icp/fw_inc/hfi_sys_defs.h new file mode 100644 index 000000000000..91190b6fa420 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_icp/fw_inc/hfi_sys_defs.h @@ -0,0 +1,522 @@ +/* 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 _HFI_DEFS_H_ +#define _HFI_DEFS_H_ + +#include + +/* + * 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) + +/* 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) + +/* 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 + +/* 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 + +/** + * 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; +}; + +/** + * 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 preperation 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/drivers/media/platform/msm/camera_oneplus/cam_icp/hfi.c b/drivers/media/platform/msm/camera_oneplus/cam_icp/hfi.c new file mode 100644 index 000000000000..b75719b78c82 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_icp/hfi.c @@ -0,0 +1,808 @@ +/* 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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" +#include "cam_soc_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 + +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); + +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"); + 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, "Inavlid 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); + + 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_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; +} + +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_POLL_TRY) { + data = cam_io_r(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. + */ + msleep(100); + 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); +} + +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, + 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->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); + + 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, soc_version, fw_version, status = 0; + uint32_t retry_cnt = 0; + + 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; + soc_version = socinfo_get_version(); + 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; + + 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->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); + + 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, + 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; + + 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, + g_hfi->csr_base + HFI_REG_A5_CSR_A2HOSTINTEN); + kzfree(g_hfi); + g_hfi = NULL; + +err: + mutex_unlock(&hfi_cmd_q_mutex); + mutex_unlock(&hfi_msg_q_mutex); +} diff --git a/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/Makefile b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/Makefile new file mode 100644 index 000000000000..f4fad8b012f7 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/Makefile @@ -0,0 +1,9 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_utils +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_req_mgr +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_core +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_icp +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_cpas/include + +obj-$(CONFIG_SPECTRA_CAMERA) += icp_hw_mgr/ a5_hw/ ipe_hw/ bps_hw/ diff --git a/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/a5_hw/Makefile b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/a5_hw/Makefile new file mode 100644 index 000000000000..5183c5172774 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/a5_hw/Makefile @@ -0,0 +1,11 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_utils +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_req_mgr +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_core +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_icp +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/a5_hw +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_icp/fw_inc +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_cpas/include + +obj-$(CONFIG_SPECTRA_CAMERA) += a5_dev.o a5_core.o a5_soc.o diff --git a/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/a5_hw/a5_core.c b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/a5_hw/a5_core.c new file mode 100644 index 000000000000..4b5f22eda762 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/a5_hw/a5_core.c @@ -0,0 +1,478 @@ +/* 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 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; + } + + cpas_vote.ahb_vote.type = CAM_VOTE_ABSOLUTE; + cpas_vote.ahb_vote.vote.level = CAM_SVS_VOTE; + cpas_vote.axi_vote.compressed_bw = CAM_ICP_A5_BW_BYTES_VOTE; + cpas_vote.axi_vote.uncompressed_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, "cpass start failed: %d", rc); + return rc; + } + 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; + } + + 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"); + } + + if (core_info->irq_cb.icp_hw_mgr_cb) + core_info->irq_cb.icp_hw_mgr_cb(irq_status, + core_info->irq_cb.data); + + 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; + int rc = 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; + } + + core_info->irq_cb.icp_hw_mgr_cb = irq_cb->icp_hw_mgr_cb; + core_info->irq_cb.data = irq_cb->data; + 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: + a5_soc = soc_info->soc_private; + if (!a5_soc) { + CAM_ERR(CAM_ICP, "A5 private soc info is NULL"); + return -EINVAL; + } + rc = hfi_cmd_ubwc_config(a5_soc->ubwc_cfg); + break; + default: + break; + } + + return rc; +} diff --git a/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/a5_hw/a5_core.h b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/a5_hw/a5_core.h new file mode 100644 index 000000000000..4aa6b4bd570e --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/a5_hw/a5_core.h @@ -0,0 +1,89 @@ +/* Copyright (c) 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. + */ + +#ifndef CAM_A5_CORE_H +#define CAM_A5_CORE_H + +#include +#include +#include +#include +#include +#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 0x10 +#define A5_WDT_1 0x100 + +#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; + uint64_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/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/a5_hw/a5_dev.c b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/a5_hw/a5_dev.c new file mode 100644 index 000000000000..14c3c9c5815b --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/a5_hw/a5_dev.c @@ -0,0 +1,234 @@ +/* Copyright (c) 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. + */ + +#include +#include +#include +#include +#include +#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, + }, +}; + +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/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/a5_hw/a5_soc.c b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/a5_hw/a5_soc.c new file mode 100644 index 000000000000..31775135d024 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/a5_hw/a5_soc.c @@ -0,0 +1,120 @@ +/* Copyright (c) 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. + */ + +#include +#include +#include +#include +#include +#include +#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 *camp_a5_soc_info; + struct device_node *of_node = NULL; + struct platform_device *pdev = 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; + } + + camp_a5_soc_info = soc_info->soc_private; + fw_name = camp_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; + } + + 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, &camp_a5_soc_info->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; +} diff --git a/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/a5_hw/a5_soc.h b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/a5_hw/a5_soc.h new file mode 100644 index 000000000000..3593cfb4a80a --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/a5_hw/a5_soc.h @@ -0,0 +1,32 @@ +/* Copyright (c) 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. + */ + +#ifndef CAM_A5_SOC_H +#define CAM_A5_SOC_H + +#include "cam_soc_util.h" + +#define ICP_UBWC_MAX 2 + +struct a5_soc_info { + char *fw_name; + uint32_t ubwc_cfg[ICP_UBWC_MAX]; +}; + +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); + +#endif diff --git a/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/bps_hw/Makefile b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/bps_hw/Makefile new file mode 100644 index 000000000000..62e453f03917 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/bps_hw/Makefile @@ -0,0 +1,11 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_utils +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_req_mgr +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_core +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_icp +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/bps_hw +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_icp/fw_inc +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_cpas/include + +obj-$(CONFIG_SPECTRA_CAMERA) += bps_dev.o bps_core.o bps_soc.o diff --git a/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/bps_hw/bps_core.c b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/bps_hw/bps_core.c new file mode 100644 index 000000000000..5bd7f1c91729 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/bps_hw/bps_core.c @@ -0,0 +1,323 @@ +/* Copyright (c) 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#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" + +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_ICP, "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_SVS_VOTE; + cpas_vote.axi_vote.compressed_bw = CAM_CPAS_DEFAULT_AXI_BW; + cpas_vote.axi_vote.uncompressed_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, "cpass start failed: %d", rc); + return rc; + } + 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; + } + + 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_ERR(CAM_ICP, "BPS: pwr_status(%x):pwr_ctrl(%x)", + pwr_status, pwr_ctrl); + return -EINVAL; + } + } + 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_ICP, "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_ERR(CAM_ICP, "BPS: pwr_ctrl(%x)", pwr_ctrl); + return -EINVAL; + } + + 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_ICP, "pwr_ctrl = %x pwr_status = %x", + pwr_ctrl, pwr_status); + + 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; + uint32_t clk_rate = clk_upd_cmd->curr_clk_rate; + + CAM_DBG(CAM_ICP, "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_ICP, "clock rate %d", clk_rate); + rc = cam_bps_update_clk_rate(soc_info, clk_rate); + if (rc) + CAM_ERR(CAM_ICP, "Failed to update clk"); + } + 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; + default: + break; + } + return rc; +} + +irqreturn_t cam_bps_irq(int irq_num, void *data) +{ + return IRQ_HANDLED; +} diff --git a/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/bps_hw/bps_core.h b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/bps_hw/bps_core.h new file mode 100644 index 000000000000..d97932141fb0 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/bps_hw/bps_core.h @@ -0,0 +1,47 @@ +/* Copyright (c) 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. + */ + +#ifndef CAM_BPS_CORE_H +#define CAM_BPS_CORE_H + +#include +#include +#include +#include +#include + +#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/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/bps_hw/bps_dev.c b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/bps_hw/bps_dev.c new file mode 100644 index 000000000000..feb0bd899d87 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/bps_hw/bps_dev.c @@ -0,0 +1,206 @@ +/* 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. + */ + +#include +#include +#include +#include +#include +#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 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; + } + bps_dev->soc_info.pdev = pdev; + bps_dev->soc_info.dev = &pdev->dev; + bps_dev->soc_info.dev_name = pdev->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, + }, +}; + +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/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/bps_hw/bps_soc.c b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/bps_hw/bps_soc.c new file mode 100644 index 000000000000..9d36cf44d76e --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/bps_hw/bps_soc.c @@ -0,0 +1,171 @@ +/* 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. + */ + +#include +#include +#include +#include +#include +#include +#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_WARN(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_clk_rate(soc_info->clk[soc_info->src_clk_idx], + soc_info->clk_name[soc_info->src_clk_idx], 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/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/bps_hw/bps_soc.h b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/bps_hw/bps_soc.h new file mode 100644 index 000000000000..18f3015855ac --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/bps_hw/bps_soc.h @@ -0,0 +1,33 @@ +/* Copyright (c) 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. + */ + +#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/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/Makefile b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/Makefile new file mode 100644 index 000000000000..fd9202eb13e7 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/Makefile @@ -0,0 +1,16 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/isp/isp_hw/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/isp/isp_hw/hw_utils/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/isp/isp_hw/isp_hw_mgr/ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_icp/fw_inc/ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_smmu/ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_core +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_utils +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_sync +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_req_mgr/ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/include/ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/a5_hw/ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_cpas/include + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_icp_hw_mgr.o diff --git a/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c new file mode 100644 index 000000000000..1d6a6dc8a708 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c @@ -0,0 +1,4297 @@ +/* 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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" + +#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) + +static struct cam_icp_hw_mgr icp_hw_mgr; + +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_ICP, "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_ICP, "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_ICP, "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->num_clk - 1]; + CAM_DBG(CAM_ICP, "clk_info = %d", + 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) +{ + 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; + 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_ICP, "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_ICP, "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_ICP, "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 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; + struct cam_icp_hw_mgr *hw_mgr = &icp_hw_mgr; + uint32_t id; + 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; + + if (!ctx_data) { + CAM_ERR(CAM_ICP, "ctx_data is NULL, failed to update clk"); + return -EINVAL; + } + + mutex_lock(&ctx_data->ctx_mutex); + if ((ctx_data->state != CAM_ICP_CTX_STATE_ACQUIRED) || + (ctx_data->watch_dog_reset_counter == 0)) { + CAM_DBG(CAM_ICP, "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_DBG(CAM_ICP, + "E :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); + + 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"); + mutex_unlock(&ctx_data->ctx_mutex); + return -EINVAL; + } + + if (!ctx_data->icp_dev_acquire_info) { + CAM_WARN(CAM_ICP, "NULL acquire info"); + mutex_unlock(&ctx_data->ctx_mutex); + 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; + } + + clk_info->compressed_bw -= ctx_data->clk_info.compressed_bw; + clk_info->uncompressed_bw -= ctx_data->clk_info.uncompressed_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.ahb_vote.type = CAM_VOTE_DYNAMIC; + clk_update.ahb_vote.vote.freq = clk_info->curr_clk; + clk_update.ahb_vote_valid = true; + clk_update.axi_vote.compressed_bw = clk_info->compressed_bw; + clk_update.axi_vote.uncompressed_bw = clk_info->uncompressed_bw; + clk_update.axi_vote_valid = true; + dev_intf->hw_ops.process_cmd(dev_intf->hw_priv, id, + &clk_update, sizeof(clk_update)); + + CAM_DBG(CAM_ICP, + "X :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); + + mutex_unlock(&ctx_data->ctx_mutex); + + return 0; +} + +static void cam_icp_ctx_timer_cb(unsigned long data) +{ + unsigned long flags; + struct crm_workq_task *task; + struct clk_work_data *task_data; + struct cam_req_mgr_timer *timer = (struct cam_req_mgr_timer *)data; + + 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(unsigned long data) +{ + unsigned long flags; + struct crm_workq_task *task; + struct clk_work_data *task_data; + struct cam_req_mgr_timer *timer = (struct cam_req_mgr_timer *)data; + + 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; + + 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; + 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_ICP, "stop 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, + 3000, &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_ICP, "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) / budget; + + CAM_DBG(CAM_ICP, "budget = %lld fc = %d ib = %lld base_clk = %lld", + budget, frame_cycles, + (long long int)(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_ICP, "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_ICP, "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_ICP, "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(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_ICP, "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)) + return false; + + if (busy && + 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_ICP, "ubw = %lld, cbw = %lld", + hw_mgr_clk_info->uncompressed_bw, + hw_mgr_clk_info->compressed_bw); + } + } + + 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_ICP, "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_ICP, "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_ICP, "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_ICP, "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, rc = false; + struct cam_icp_clk_bw_request *clk_info; + 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]; + + clk_info = &ctx_data->hfi_frame_process.clk_info[idx]; + frame_info = &ctx_data->hfi_frame_process; + req_id = frame_info->request_id[idx]; + busy = cam_icp_busy_prev_reqs(frame_info, req_id); + rc = cam_icp_update_bw(hw_mgr, ctx_data, hw_mgr_clk_info, + clk_info, busy); + + CAM_DBG(CAM_ICP, "ubw = %lld, cbw = %lld, update_bw = %d", + hw_mgr_clk_info->uncompressed_bw, + hw_mgr_clk_info->compressed_bw, rc); + + return rc; +} + +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 *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; + + + 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; + } + + clk_upd_cmd.curr_clk_rate = curr_clk_rate; + 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 (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)); + + return 0; +} + +static int cam_icp_update_cpas_vote(struct cam_icp_hw_mgr *hw_mgr, + struct cam_icp_hw_ctx_data *ctx_data) +{ + uint32_t id; + 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; + + 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; + } + + clk_update.ahb_vote.type = CAM_VOTE_DYNAMIC; + clk_update.ahb_vote.vote.freq = clk_info->curr_clk; + clk_update.ahb_vote_valid = true; + clk_update.axi_vote.compressed_bw = clk_info->compressed_bw; + clk_update.axi_vote.uncompressed_bw = clk_info->uncompressed_bw; + clk_update.axi_vote_valid = true; + dev_intf->hw_ops.process_cmd(dev_intf->hw_priv, id, + &clk_update, sizeof(clk_update)); + + /* + * Consolidated bw needs to be voted on only one IPE client. Otherwise + * total bw that we vote at bus client would be doubled. So either + * remove voting on IPE1 or divide the vote for each IPE client + * and vote to cpas - cpas will add up and vote full bw to sf client + * anyway. + */ + + return 0; +} + +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; + 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); + hw_mgr->core_info = hw_mgr->core_info | 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.ipe_bps_pc_flag) { + hw_mgr->core_info = hw_mgr->core_info | + (ICP_PWR_CLP_IPE0 | ICP_PWR_CLP_IPE1); + } + } + + CAM_DBG(CAM_ICP, "core_info %X", hw_mgr->core_info); + if (icp_hw_mgr.ipe_bps_pc_flag) + rc = hfi_enable_ipe_bps_pc(true, hw_mgr->core_info); + else if (icp_hw_mgr.icp_pc_flag) + rc = hfi_enable_ipe_bps_pc(false, hw_mgr->core_info); + else + rc = hfi_enable_ipe_bps_pc(false, hw_mgr->core_info); +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_ICP, "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) { + rc = bps_dev_intf->hw_ops.process_cmd( + bps_dev_intf->hw_priv, + CAM_ICP_BPS_CMD_POWER_COLLAPSE, + NULL, 0); + hw_mgr->core_info = + hw_mgr->core_info & (~ICP_PWR_CLP_BPS); + } + + 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_ICP, "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) { + 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) { + 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; + if (icp_hw_mgr.ipe_bps_pc_flag) { + hw_mgr->core_info = hw_mgr->core_info & + (~(ICP_PWR_CLP_IPE0 | ICP_PWR_CLP_IPE1)); + } + } + + CAM_DBG(CAM_ICP, "Exit: core_info = %x", hw_mgr->core_info); +end: + 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_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; + } + icp_hw_mgr.icp_pc_flag = false; + + 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; + } + + icp_hw_mgr.ipe_bps_pc_flag = false; + + 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\n"); + 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\n"); + rc = -ENOMEM; + goto err; + } + + return rc; +err: + debugfs_remove_recursive(icp_hw_mgr.dentry); + 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 *)ioconfig_ack->user_data1; + if (!ctx_data) { + CAM_ERR(CAM_ICP, "Invalid Context"); + return -EINVAL; + } + CAM_DBG(CAM_ICP, "ctx : %pK, request_id :%lld", + (void *)ctx_data->context_priv, request_id); + + 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); + + 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; + } + + 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; + + 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 != HFI_ERR_SYS_NONE) { + CAM_ERR(CAM_ICP, "failed with error : %u", + ioconfig_ack->err_type); + 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 *)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 *)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 *)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 *)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 *)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 *)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; + default: + CAM_ERR(CAM_ICP, "Invalid opcode : %u", + msg_ptr[ICP_PACKET_OPCODE]); + rc = -EINVAL; + break; + } + return rc; +} + +static void cam_icp_mgr_process_dbg_buf(void) +{ + uint32_t *msg_ptr = NULL, *pkt_ptr = NULL; + struct hfi_msg_debug *dbg_msg; + uint32_t read_len, size_processed = 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; + trace_cam_icp_fw_dbg(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; + 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"); + } 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; + } + } + + if (icp_hw_mgr.a5_debug_type == + HFI_DEBUG_MODE_QUEUE) + cam_icp_mgr_process_dbg_buf(); + + 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; + + 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); +} + +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_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; + uint64_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: %llX, 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_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_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; + } + + return rc; +sec_heap_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; + + 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; + + 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_ICP, "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) { + 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 { + 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_ICP, "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, "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, "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, "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, "kva = %llX IOVA = %X length = %lld\n", + hfi_mem.dbg_q.kva, hfi_mem.dbg_q.iova, hfi_mem.dbg_q.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; + 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_mgr_abort_handle( + struct cam_icp_hw_ctx_data *ctx_data) +{ + int rc = 0; + unsigned long rem_jiffies; + size_t packet_size; + int timeout = 100; + struct hfi_cmd_work_data *task_data; + struct hfi_cmd_ipebps_async *abort_cmd; + struct crm_workq_task *task; + + task = cam_req_mgr_workq_get_task(icp_hw_mgr.cmd_work); + if (!task) + return -ENOMEM; + + 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 = (uint64_t)ctx_data; + abort_cmd->user_data2 = (uint64_t)0x0; + + task_data = (struct hfi_cmd_work_data *)task->payload; + task_data->data = (void *)abort_cmd; + 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) { + 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 = -ETIMEDOUT; + CAM_ERR(CAM_ICP, "FW timeout/err in abort handle command"); + } + else{ + //workq won't do free,if no timeout means + //cmd execution finished,so just release it. + 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 = 100; + unsigned long rem_jiffies; + size_t packet_size; + struct hfi_cmd_work_data *task_data; + struct hfi_cmd_ipebps_async *destroy_cmd; + struct crm_workq_task *task; + + task = cam_req_mgr_workq_get_task(icp_hw_mgr.cmd_work); + if (!task) + return -ENOMEM; + + 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 = (uint64_t)ctx_data; + destroy_cmd->user_data2 = (uint64_t)0x0; + memcpy(destroy_cmd->payload.direct, &ctx_data->temp_payload, + sizeof(uint64_t)); + + task_data = (struct hfi_cmd_work_data *)task->payload; + task_data->data = (void *)destroy_cmd; + 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) { + 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); + if (icp_hw_mgr.a5_debug_type == + HFI_DEBUG_MODE_QUEUE) + cam_icp_mgr_process_dbg_buf(); + } + else{ + //workq won't do free,if no timeout means + //cmd execution finished,so just release it. + 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); + 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", ctx_id); + 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; + 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; + hw_mgr->secure_mode = CAM_SECURE_MODE_NON_SECURE; + + 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.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; + + 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_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; + + 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; + + request_id = *(uint64_t *)config_args->priv; + 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_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; + + 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; + } + + req_id = *(uint64_t *)config_args->priv; + idx = cam_icp_clk_idx_from_req_id(ctx_data, req_id); + ctx_data->hfi_frame_process.fw_process_flag[idx] = true; + cam_icp_mgr_ipe_bps_clk_update(hw_mgr, ctx_data, idx); + + rc = cam_icp_mgr_enqueue_config(hw_mgr, config_args); + if (rc) + goto config_err; + CAM_DBG(CAM_ICP, "req_id = %lld %u", + req_id, ctx_data->ctx_id); + 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 = (uint64_t)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 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; + } + + 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, j, k; + uint64_t addr; + size_t len; + struct cam_cmd_buf_desc *cmd_desc = NULL; + uint64_t cpu_addr = 0; + struct ipe_frame_process_data *frame_process_data = NULL; + struct bps_frame_process_data *bps_frame_process_data = NULL; + + cmd_desc = (struct cam_cmd_buf_desc *) + ((uint32_t *) &packet->payload + packet->cmd_buf_offset/4); + + *fw_cmd_buf_iova_addr = 0; + for (i = 0; i < packet->num_cmd_buf; i++) { + 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); + return rc; + } + *fw_cmd_buf_iova_addr = addr; + *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) { + CAM_ERR(CAM_ICP, "get cmd buf failed %x", + hw_mgr->iommu_hdl); + *fw_cmd_buf_iova_addr = 0; + return rc; + } + cpu_addr = cpu_addr + cmd_desc[i].offset; + } + } + + if (!cpu_addr) { + CAM_ERR(CAM_ICP, "Invalid cpu addr"); + return -EINVAL; + } + + if (ctx_data->icp_dev_acquire_info->dev_type != + CAM_ICP_RES_TYPE_BPS) { + CAM_DBG(CAM_ICP, "cpu addr = %llx", cpu_addr); + frame_process_data = (struct ipe_frame_process_data *)cpu_addr; + CAM_DBG(CAM_ICP, "%u %u %u", frame_process_data->max_num_cores, + frame_process_data->target_time, + frame_process_data->frames_in_batch); + frame_process_data->strip_lib_out_addr = 0; + frame_process_data->iq_settings_addr = 0; + frame_process_data->scratch_buffer_addr = 0; + frame_process_data->ubwc_stats_buffer_addr = 0; + frame_process_data->cdm_buffer_addr = 0; + frame_process_data->cdm_prog_base = 0; + for (i = 0; i < frame_process_data->frames_in_batch; i++) { + for (j = 0; j < IPE_IO_IMAGES_MAX; j++) { + for (k = 0; k < MAX_NUM_OF_IMAGE_PLANES; k++) { + frame_process_data-> + framesets[i].buffers[j]. + buffer_ptr[k] = 0; + frame_process_data-> + framesets[i].buffers[j]. + meta_buffer_ptr[k] = 0; + } + } + } + } else { + CAM_DBG(CAM_ICP, "cpu addr = %llx", cpu_addr); + bps_frame_process_data = + (struct bps_frame_process_data *)cpu_addr; + CAM_DBG(CAM_ICP, "%u %u", + bps_frame_process_data->max_num_cores, + bps_frame_process_data->target_time); + bps_frame_process_data->ubwc_stats_buffer_addr = 0; + bps_frame_process_data->cdm_buffer_addr = 0; + bps_frame_process_data->iq_settings_addr = 0; + bps_frame_process_data->strip_lib_out_addr = 0; + bps_frame_process_data->cdm_prog_addr = 0; + for (i = 0; i < BPS_IO_IMAGES_MAX; i++) { + for (j = 0; j < MAX_NUM_OF_IMAGE_PLANES; j++) { + bps_frame_process_data-> + buffers[i].buffer_ptr[j] = 0; + bps_frame_process_data-> + buffers[i].meta_buffer_ptr[j] = 0; + } + } + } + + 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_ICP, "dir[%d]: %u, fence: %u", + i, io_cfg_ptr[i].direction, io_cfg_ptr[i].fence); + } + + 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_ICP, "Merged Sync obj = %d", 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_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 icp_cmd_generic_blob *blob; + struct cam_icp_hw_ctx_data *ctx_data; + uint32_t index; + int rc = 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: + if (blob_size != sizeof(struct cam_icp_clk_bw_request)) { + rc = -EINVAL; + break; + } + clk_info = &ctx_data->hfi_frame_process.clk_info[index]; + memset(clk_info, 0, sizeof(struct cam_icp_clk_bw_request)); + + soc_req = (struct cam_icp_clk_bw_request *)blob_data; + *clk_info = *soc_req; + CAM_DBG(CAM_ICP, "%llu %llu %d %d %d", + clk_info->budget_ns, clk_info->frame_cycles, + clk_info->rt_flag, clk_info->uncompressed_bw, + clk_info->compressed_bw); + 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) +{ + 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_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_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; + + 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; + rc = cam_icp_process_generic_cmd_buffer(packet, ctx_data, index); + if (rc) { + clear_bit(index, ctx_data->hfi_frame_process.bitmap); + ctx_data->hfi_frame_process.request_id[index] = -1; + return rc; + } + *idx = index; + + return 0; +} + +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; + + 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; + } + + CAM_DBG(CAM_ICP, "E: req id = %lld", packet->header.request_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 = (uint64_t)hfi_cmd; + prepare_args->priv = &ctx_data->hfi_frame_process.request_id[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 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; + + 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; + } + + switch (flush_args->flush_type) { + case CAM_FLUSH_TYPE_ALL: + if (flush_args->num_req_active) + cam_icp_mgr_abort_handle(ctx_data); + 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"); + 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); + + if (release_hw->active_req) { + cam_icp_mgr_abort_handle(ctx_data); + cam_icp_mgr_send_abort_status(ctx_data); + } + + 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); + hw_mgr->secure_mode = CAM_SECURE_MODE_NON_SECURE; + 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, "Exit"); + 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; + + 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 = (uint64_t)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_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); + } + + 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 = (uint64_t)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); + } + + 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 = (uint64_t)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); + } + + 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) { + CAM_ERR(CAM_ICP, "num of out resources exceeding : %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; + } + + if (!hw_mgr->ctxt_cnt) { + hw_mgr->secure_mode = icp_dev_acquire_info.secure_mode; + } else { + if (hw_mgr->secure_mode != icp_dev_acquire_info.secure_mode) { + CAM_ERR(CAM_ICP, + "secure mode mismatch driver:%d, context:%d", + hw_mgr->secure_mode, + icp_dev_acquire_info.secure_mode); + return -EINVAL; + } + } + + 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) { + if (!hw_mgr->ctxt_cnt) + hw_mgr->secure_mode = CAM_SECURE_MODE_NON_SECURE; + 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); + if (!hw_mgr->ctxt_cnt) + hw_mgr->secure_mode = CAM_SECURE_MODE_NON_SECURE; + 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 %u", + 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, + hw_mgr->secure_mode); + + 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 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; + uint64_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; + + 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; + + 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); + + 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(icp_dev_acquire_info->dev_type, + ctx_data); + if (rc) { + CAM_ERR(CAM_ICP, "create handle failed"); + goto create_handle_failed; + } + + rc = cam_icp_mgr_send_config_io(ctx_data, io_buf_addr); + if (rc) { + CAM_ERR(CAM_ICP, "IO Config command failed"); + goto ioconfig_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"); + + return 0; + +copy_to_user_failed: + kfree(ctx_data->hfi_frame_process.bitmap); + ctx_data->hfi_frame_process.bitmap = NULL; +ioconfig_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); + 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, + (void __user *)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((void __user *)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] = kzalloc( + sizeof(struct cam_hw_intf *) * num_dev, 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] = kzalloc( + sizeof(struct cam_hw_intf *) * num_dev, GFP_KERNEL); + if (!icp_hw_mgr.devices[CAM_ICP_DEV_BPS]) { + rc = -ENOMEM; + goto num_bps_failed; + } + + 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); + 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); + 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); + if (rc) { + CAM_ERR(CAM_ICP, "unable to create a timer worker"); + goto timer_work_failed; + } + + icp_hw_mgr.cmd_work_data = (struct hfi_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 = (struct hfi_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 = (struct hfi_msg_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; +} + +int cam_icp_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl) +{ + int i, rc = 0; + struct cam_hw_mgr_intf *hw_mgr_intf; + struct cam_cpas_query_cap query; + uint32_t cam_caps; + + 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 = 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; + + 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); + 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_ops(icp_hw_mgr.iommu_hdl, CAM_SMMU_ATTACH); + if (rc) { + CAM_ERR(CAM_ICP, "icp attach failed: %d", rc); + goto icp_attach_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; + + 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_ops(icp_hw_mgr.iommu_hdl, CAM_SMMU_DETACH); +icp_attach_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/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h new file mode 100644 index 000000000000..c94550d770b1 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h @@ -0,0 +1,344 @@ +/* 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_ICP_HW_MGR_H +#define CAM_ICP_HW_MGR_H + +#include +#include +#include +#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 15 + +#define CPAS_IPE0_BIT 0x1000 +#define CPAS_IPE1_BIT 0x2000 +#define CPAS_BPS_BIT 0x400 + +#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 + +/** + * 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 + */ +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_smmu_region_info shmem; +}; + +/** + * 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 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 + */ +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_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 + */ +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]; +}; +/** + * 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 + * @clk_info: Current clock info of a context + * @watch_dog: watchdog timer handle + * @watch_dog_reset_counter: Counter for watch dog reset + */ +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; + struct cam_ctx_clk_info clk_info; + struct cam_req_mgr_timer *watch_dog; + uint32_t watch_dog_reset_counter; +}; + +/** + * struct icp_cmd_generic_blob + * @ctx: Current context info + * @frame_info_idx: Index used for frame process info + */ +struct icp_cmd_generic_blob { + struct cam_icp_hw_ctx_data *ctx; + uint32_t frame_info_idx; +}; + +/** + * 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 + * @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 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. + * @ipe0_enable: Flag for IPE0 + * @ipe1_enable: Flag for IPE1 + * @bps_enable: Flag for BPS + * @core_info: 32 bit value , tells IPE0/1 and 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 + */ +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; + bool ipe0_enable; + bool ipe1_enable; + bool bps_enable; + uint32_t core_info; + 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; +}; + +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/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/include/cam_a5_hw_intf.h b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/include/cam_a5_hw_intf.h new file mode 100644 index 000000000000..fd0482ce2b97 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/include/cam_a5_hw_intf.h @@ -0,0 +1,81 @@ +/* Copyright (c) 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. + */ + +#ifndef CAM_A5_HW_INTF_H +#define CAM_A5_HW_INTF_H + +#include +#include +#include +#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_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/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/include/cam_bps_hw_intf.h b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/include/cam_bps_hw_intf.h new file mode 100644 index 000000000000..4f0717290b06 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/include/cam_bps_hw_intf.h @@ -0,0 +1,34 @@ +/* Copyright (c) 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. + */ + +#ifndef CAM_BPS_HW_INTF_H +#define CAM_BPS_HW_INTF_H + +#include +#include +#include "cam_hw_mgr_intf.h" +#include "cam_icp_hw_intf.h" + +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_MAX, +}; + +#endif /* CAM_BPS_HW_INTF_H */ diff --git a/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/include/cam_icp_hw_intf.h b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/include/cam_icp_hw_intf.h new file mode 100644 index 000000000000..9e05f2bd6c9c --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/include/cam_icp_hw_intf.h @@ -0,0 +1,36 @@ +/* Copyright (c) 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. + */ + +#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 + +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 + */ +struct cam_a5_clk_update_cmd { + uint32_t curr_clk_rate; + bool ipe_bps_pc_enable; +}; +#endif diff --git a/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/include/cam_ipe_hw_intf.h b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/include/cam_ipe_hw_intf.h new file mode 100644 index 000000000000..0943bef0836d --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/include/cam_ipe_hw_intf.h @@ -0,0 +1,34 @@ +/* Copyright (c) 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. + */ + +#ifndef CAM_IPE_HW_INTF_H +#define CAM_IPE_HW_INTF_H + +#include +#include +#include "cam_hw_mgr_intf.h" +#include "cam_icp_hw_intf.h" + +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_MAX, +}; + +#endif /* CAM_IPE_HW_INTF_H */ diff --git a/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h new file mode 100644 index 000000000000..771c4ed7c55c --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h @@ -0,0 +1,47 @@ +/* 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_ICP_HW_MGR_INTF_H +#define CAM_ICP_HW_MGR_INTF_H + +#include +#include +#include +#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 36 + +#define CPAS_IPE1_BIT 0x2000 + +int cam_icp_hw_mgr_init(struct device_node *of_node, + uint64_t *hw_mgr_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/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/ipe_hw/Makefile b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/ipe_hw/Makefile new file mode 100644 index 000000000000..756eac3e64d4 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/ipe_hw/Makefile @@ -0,0 +1,11 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_utils +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_req_mgr +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_core +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_icp +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/ipe_hw +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_icp/fw_inc +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_cpas/include + +obj-$(CONFIG_SPECTRA_CAMERA) += ipe_dev.o ipe_core.o ipe_soc.o diff --git a/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/ipe_hw/ipe_core.c b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/ipe_hw/ipe_core.c new file mode 100644 index 000000000000..87478af551b7 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/ipe_hw/ipe_core.c @@ -0,0 +1,314 @@ +/* Copyright (c) 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#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" + +static int cam_ipe_caps_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_ICP, "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_SVS_VOTE; + cpas_vote.axi_vote.compressed_bw = CAM_CPAS_DEFAULT_AXI_BW; + cpas_vote.axi_vote.uncompressed_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, "cpass start failed: %d", rc); + return rc; + } + 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; + } + + 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) + return -EINVAL; + + } + 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_ICP, "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_ERR(CAM_ICP, "IPE: resume failed : %d", pwr_ctrl); + return -EINVAL; + } + 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_ICP, "pwr_ctrl = %x pwr_status = %x", + pwr_ctrl, pwr_status); + + 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_caps_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; + uint32_t clk_rate = clk_upd_cmd->curr_clk_rate; + + CAM_DBG(CAM_ICP, "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_ICP, "clock rate %d", clk_rate); + + rc = cam_ipe_update_clk_rate(soc_info, clk_rate); + if (rc) + CAM_ERR(CAM_ICP, "Failed to update clk"); + } + 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; + default: + break; + } + return rc; +} + +irqreturn_t cam_ipe_irq(int irq_num, void *data) +{ + return IRQ_HANDLED; +} diff --git a/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/ipe_hw/ipe_core.h b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/ipe_hw/ipe_core.h new file mode 100644 index 000000000000..65d349050f01 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/ipe_hw/ipe_core.h @@ -0,0 +1,47 @@ +/* Copyright (c) 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. + */ + +#ifndef CAM_IPE_CORE_H +#define CAM_IPE_CORE_H + +#include +#include +#include +#include +#include + +#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/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/ipe_hw/ipe_dev.c b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/ipe_hw/ipe_dev.c new file mode 100644 index 000000000000..cc2b1b1f88a5 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/ipe_hw/ipe_dev.c @@ -0,0 +1,198 @@ +/* Copyright (c) 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. + */ + +#include +#include +#include +#include +#include +#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); + +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; + } + ipe_dev->soc_info.pdev = pdev; + ipe_dev->soc_info.dev = &pdev->dev; + ipe_dev->soc_info.dev_name = pdev->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, + }, +}; + +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/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/ipe_hw/ipe_soc.c b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/ipe_hw/ipe_soc.c new file mode 100644 index 000000000000..838be2a58de1 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/ipe_hw/ipe_soc.c @@ -0,0 +1,174 @@ +/* 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. + */ + +#include +#include +#include +#include +#include +#include +#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_WARN(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_clk_rate(soc_info->clk[soc_info->src_clk_idx], + soc_info->clk_name[soc_info->src_clk_idx], 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/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/ipe_hw/ipe_soc.h b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/ipe_hw/ipe_soc.h new file mode 100644 index 000000000000..5385bde371e7 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/ipe_hw/ipe_soc.h @@ -0,0 +1,33 @@ +/* Copyright (c) 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. + */ + +#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/drivers/media/platform/msm/camera_oneplus/cam_isp/Makefile b/drivers/media/platform/msm/camera_oneplus/cam_isp/Makefile new file mode 100644 index 000000000000..69cbfac3106e --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/Makefile @@ -0,0 +1,9 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_core +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_req_mgr +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_smmu/ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_sync +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_utils + +obj-$(CONFIG_SPECTRA_CAMERA) += isp_hw_mgr/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_isp_dev.o cam_isp_context.o diff --git a/drivers/media/platform/msm/camera_oneplus/cam_isp/cam_isp_context.c b/drivers/media/platform/msm/camera_oneplus/cam_isp/cam_isp_context.c new file mode 100644 index 000000000000..e1157aa61501 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/cam_isp_context.c @@ -0,0 +1,2572 @@ +/* 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. + */ + +#include +#include +#include +#include +#include + +#include "cam_isp_context.h" +#include "cam_isp_log.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" + +static const char isp_dev_name[] = "isp"; + +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; + + 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 "CAM_ISP_IFE_OUT_RES_FULL"; + case CAM_ISP_IFE_OUT_RES_DS4: + return "CAM_ISP_IFE_OUT_RES_DS4"; + case CAM_ISP_IFE_OUT_RES_DS16: + return "CAM_ISP_IFE_OUT_RES_DS16"; + case CAM_ISP_IFE_OUT_RES_RAW_DUMP: + return "CAM_ISP_IFE_OUT_RES_RAW_DUMP"; + case CAM_ISP_IFE_OUT_RES_FD: + return "CAM_ISP_IFE_OUT_RES_FD"; + case CAM_ISP_IFE_OUT_RES_PDAF: + return "CAM_ISP_IFE_OUT_RES_PDAF"; + case CAM_ISP_IFE_OUT_RES_RDI_0: + return "CAM_ISP_IFE_OUT_RES_RDI_0"; + case CAM_ISP_IFE_OUT_RES_RDI_1: + return "CAM_ISP_IFE_OUT_RES_RDI_1"; + case CAM_ISP_IFE_OUT_RES_RDI_2: + return "CAM_ISP_IFE_OUT_RES_RDI_2"; + case CAM_ISP_IFE_OUT_RES_RDI_3: + return "CAM_ISP_IFE_OUT_RES_RDI_3"; + case CAM_ISP_IFE_OUT_RES_STATS_HDR_BE: + return "CAM_ISP_IFE_OUT_RES_STATS_HDR_BE"; + case CAM_ISP_IFE_OUT_RES_STATS_HDR_BHIST: + return "CAM_ISP_IFE_OUT_RES_STATS_HDR_BHIST"; + case CAM_ISP_IFE_OUT_RES_STATS_TL_BG: + return "CAM_ISP_IFE_OUT_RES_STATS_TL_BG"; + case CAM_ISP_IFE_OUT_RES_STATS_BF: + return "CAM_ISP_IFE_OUT_RES_STATS_BF"; + case CAM_ISP_IFE_OUT_RES_STATS_AWB_BG: + return "CAM_ISP_IFE_OUT_RES_STATS_AWB_BG"; + case CAM_ISP_IFE_OUT_RES_STATS_BHIST: + return "CAM_ISP_IFE_OUT_RES_STATS_BHIST"; + case CAM_ISP_IFE_OUT_RES_STATS_RS: + return "CAM_ISP_IFE_OUT_RES_STATS_RS"; + case CAM_ISP_IFE_OUT_RES_STATS_CS: + return "CAM_ISP_IFE_OUT_RES_STATS_CS"; + 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_handle_buf_done_fail_log( + struct cam_isp_ctx_req *req_isp) +{ + int i; + + if (req_isp->num_fence_map_out >= CAM_ISP_CTX_RES_MAX) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "Num Resources exceed mMAX %d >= %d ", + req_isp->num_fence_map_out, CAM_ISP_CTX_RES_MAX); + return; + } + + CAM_ERR_RATE_LIMIT(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_ERR_RATE_LIMIT(CAM_ISP, + "Resource_Handle: [%s] 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].sync_id); + } +} + +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; + int i, j; + struct cam_ctx_request *req; + struct cam_isp_ctx_req *req_isp; + struct cam_context *ctx = ctx_isp->base; + + if (list_empty(&ctx->active_req_list)) { + CAM_DBG(CAM_ISP, "Buf done with no active request!"); + goto end; + } + + CAM_DBG(CAM_ISP, "Enter with bubble_state %d", bubble_state); + + req = list_first_entry(&ctx->active_req_list, + struct cam_ctx_request, list); + + trace_cam_buf_done("ISP", ctx, req); + + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + 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_isp_ctx_handle_buf_done_fail_log(req_isp); + continue; + } + + if (!bubble_state) { + CAM_DBG(CAM_ISP, + "Sync with success: req %lld res 0x%x fd 0x%x", + req->request_id, + req_isp->fence_map_out[j].resource_handle, + req_isp->fence_map_out[j].sync_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_DBG(CAM_ISP, + "Sync with failure: req %lld res 0x%x fd 0x%x", + req->request_id, + req_isp->fence_map_out[j].resource_handle, + req_isp->fence_map_out[j].sync_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 + * In most case, active list should be empty when + * bubble detects. But for safety, we just move the + * current active request to the pending list here. + */ + CAM_DBG(CAM_ISP, + "buf done with bubble state %d recovery %d", + bubble_state, req_isp->bubble_report); + list_del_init(&req->list); + list_add(&req->list, &ctx->pending_req_list); + continue; + } + + CAM_DBG(CAM_ISP, "req %lld, reset sync id 0x%x", + req->request_id, + req_isp->fence_map_out[j].sync_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", + req->request_id, req_isp->num_acked, + req_isp->num_fence_map_out); + WARN_ON(req_isp->num_acked > req_isp->num_fence_map_out); + } + if (req_isp->num_acked == req_isp->num_fence_map_out) { + list_del_init(&req->list); + list_add_tail(&req->list, &ctx->free_req_list); + ctx_isp->active_req_cnt--; + CAM_DBG(CAM_ISP, + "Move active request %lld to free list(cnt = %d)", + req->request_id, ctx_isp->active_req_cnt); + } + +end: + return rc; +} + +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); + 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); +} + +static int __cam_isp_ctx_reg_upd_in_activated_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; + + if (list_empty(&ctx->pending_req_list)) { + CAM_ERR(CAM_ISP, "Reg upd ack with no pending request"); + goto end; + } + 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; + 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); + } 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)", + req->request_id, ctx_isp->active_req_cnt); + } + + /* + * 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 %d", ctx_isp->substate_activated); + +end: + return rc; +} + +static int __cam_isp_ctx_notify_sof_in_actived_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; + 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 (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; + + 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; + } + } + + 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); + } else { + CAM_ERR_RATE_LIMIT(CAM_ISP, "Can not notify SOF to CRM"); + rc = -EFAULT; + } + + return 0; +} + +static int __cam_isp_ctx_notify_eof_in_actived_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\n", + ctx_isp->frame_id); + } else { + CAM_ERR(CAM_ISP, "Can not notify EOF to CRM"); + 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; + + 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; + CAM_DBG(CAM_ISP, "frame id: %lld time stamp:0x%llx", + ctx_isp->frame_id, ctx_isp->sof_timestamp_val); + + 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; + struct cam_isp_ctx_req *req_isp; + struct cam_context *ctx = ctx_isp->base; + + if (ctx->state != CAM_CTX_ACTIVATED) { + 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->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; + if (req_isp->num_fence_map_out == req_isp->num_acked) { + list_add_tail(&req->list, &ctx->free_req_list); + } else { + /* need to handle the buf done */ + 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); + ctx_isp->substate_activated = + CAM_ISP_CTX_ACTIVATED_EPOCH; + } + } +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->pending_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, "No pending request"); + 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->pending_req_list, struct cam_ctx_request, + list); + req_isp = (struct cam_isp_ctx_req *)req->req_priv; + + CAM_DBG(CAM_ISP, "Report Bubble flag %d", req_isp->bubble_report); + 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; + ctx->ctx_crm_intf->notify_err(¬ify); + CAM_DBG(CAM_ISP, "Notify CRM about Bubble frame %lld", + ctx_isp->frame_id); + } else { + /* + * Since can not bubble report, always move the request to + * active list. + */ + 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); + req_isp->bubble_report = 0; + } + + 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 %d", + ctx_isp->substate_activated); +end: + 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; + + 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; + + 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 %d", + 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->pending_req_list)) { + /* + * If no pending req in epoch, this is an error case. + * Just go back to the bubble state. + */ + CAM_ERR(CAM_ISP, "No pending request."); + __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->pending_req_list, struct cam_ctx_request, + list); + req_isp = (struct cam_isp_ctx_req *)req->req_priv; + + 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; + ctx->ctx_crm_intf->notify_err(¬ify); + CAM_DBG(CAM_ISP, "Notify CRM about Bubble frame %lld", + ctx_isp->frame_id); + } else { + /* + * If we can not report bubble, then treat it as if no bubble + * report. Just move the req to active list. + */ + 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); + req_isp->bubble_report = 0; + } + + 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 %d", ctx_isp->substate_activated); +end: + 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_temp; + struct cam_isp_ctx_req *req_isp = NULL; + struct cam_req_mgr_error_notify notify; + uint64_t error_request_id; + + 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)) + notify.error = CRM_KMD_ERR_OVERFLOW; + + /* + * Need to check the active req + * move all of them to the pending request list + * Note this funciton need revisit! + */ + + if (list_empty(&ctx->active_req_list)) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "handling error with no active request"); + } else { + 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++) { + CAM_ERR(CAM_ISP, "req %llu, Sync fd %x", + req->request_id, + req_isp->fence_map_out[i]. + sync_id); + 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); + ctx_isp->active_req_cnt--; + } else { + found = 1; + break; + } + } + } + + 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--; + } + } + + do { + if (list_empty(&ctx->pending_req_list)) { + error_request_id = ctx_isp->last_applied_req_id + 1; + 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) + 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; + + if (req_isp && req_isp->bubble_report) + notify.error = CRM_KMD_ERR_BUBBLE; + + CAM_WARN(CAM_ISP, "Notify CRM: req %lld, frame %lld\n", + error_request_id, ctx_isp->frame_id); + + ctx->ctx_crm_intf->notify_err(¬ify); + ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_HW_ERROR; + } else { + CAM_ERR_RATE_LIMIT(CAM_ISP, "Can not notify ERRROR to CRM"); + rc = -EFAULT; + } + + CAM_DBG(CAM_ISP, "Exit"); + return rc; +} + +static int __cam_isp_ctx_sof_in_flush( + struct cam_isp_context *ctx_isp, void *evt_data) +{ + int rc = 0; + 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; + CAM_DBG(CAM_ISP, "frame id: %lld time stamp:0x%llx", + ctx_isp->frame_id, ctx_isp->sof_timestamp_val); + + if (--ctx_isp->frame_skip_count == 0) + ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF; + else + CAM_ERR(CAM_ISP, "Skip currect SOF"); + + 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_actived_state, + __cam_isp_ctx_notify_eof_in_actived_state, + NULL, + }, + }, + /* APPLIED */ + { + .irq_ops = { + __cam_isp_ctx_handle_error, + __cam_isp_ctx_sof_in_activated_state, + __cam_isp_ctx_reg_upd_in_activated_state, + __cam_isp_ctx_epoch_in_applied, + __cam_isp_ctx_notify_eof_in_actived_state, + __cam_isp_ctx_buf_done_in_applied, + }, + }, + /* EPOCH */ + { + .irq_ops = { + __cam_isp_ctx_handle_error, + __cam_isp_ctx_sof_in_epoch, + NULL, + __cam_isp_ctx_notify_sof_in_actived_state, + __cam_isp_ctx_notify_eof_in_actived_state, + __cam_isp_ctx_buf_done_in_epoch, + }, + }, + /* BUBBLE */ + { + .irq_ops = { + __cam_isp_ctx_handle_error, + __cam_isp_ctx_sof_in_activated_state, + NULL, + __cam_isp_ctx_notify_sof_in_actived_state, + __cam_isp_ctx_notify_eof_in_actived_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_activated_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 */ + { + }, + /* FLUSH */ + { + .irq_ops = { + NULL, + __cam_isp_ctx_sof_in_flush, + NULL, + NULL, + NULL, + __cam_isp_ctx_buf_done_in_applied, + }, + }, +}; + +static int __cam_isp_ctx_apply_req_in_activated_state( + struct cam_context *ctx, struct cam_req_mgr_apply_request *apply, + uint32_t next_state) +{ + int rc = 0; + struct cam_ctx_request *req; + struct cam_ctx_request *active_req; + struct cam_isp_ctx_req *req_isp; + struct cam_isp_ctx_req *active_req_isp; + struct cam_isp_context *ctx_isp; + 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; + req = list_first_entry(&ctx->pending_req_list, struct cam_ctx_request, + list); + + /* + * Check whehter 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_ISP, "Apply request %lld", req->request_id); + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + + if (ctx_isp->active_req_cnt >= 2) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "Reject apply request (id %lld) due to congestion(cnt = %d)", + req->request_id, + ctx_isp->active_req_cnt); + if (!list_empty(&ctx->active_req_list)) { + active_req = list_first_entry(&ctx->active_req_list, + struct cam_ctx_request, list); + active_req_isp = + (struct cam_isp_ctx_req *) active_req->req_priv; + __cam_isp_ctx_handle_buf_done_fail_log(active_req_isp); + } else { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "WARNING: should not happen (cnt = %d) but active_list empty", + ctx_isp->active_req_cnt); + } + 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; + + 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; + CAM_DBG(CAM_ISP, "new substate state %d, applied req %lld", + next_state, ctx_isp->last_applied_req_id); + spin_unlock_bh(&ctx->lock); + } +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 %d", + 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 %d", ctx_isp->substate_activated); + + 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 %d", + 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 %d", ctx_isp->substate_activated); + + 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 %d", + 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 %d", ctx_isp->substate_activated); + + 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; + 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; + + INIT_LIST_HEAD(&flush_list); + spin_lock_bh(&ctx->lock); + if (list_empty(req_list)) { + spin_unlock_bh(&ctx->lock); + CAM_DBG(CAM_ISP, "request list is empty"); + return 0; + } + + 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); + } + spin_unlock_bh(&ctx->lock); + + 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) + CAM_ERR_RATE_LIMIT(CAM_ISP, + "signal fence failed\n"); + req_isp->fence_map_out[i].sync_id = -1; + } + } + spin_lock_bh(&ctx->lock); + list_add_tail(&req->list, &ctx->free_req_list); + spin_unlock_bh(&ctx->lock); + } + + 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; + + CAM_DBG(CAM_ISP, "try to flush pending list"); + rc = __cam_isp_ctx_flush_req(ctx, &ctx->pending_req_list, flush_req); + CAM_DBG(CAM_ISP, "Flush request in top state %d", + ctx->state); + return rc; +} + +static int __cam_isp_ctx_flush_req_in_activated( + struct cam_context *ctx, + struct cam_req_mgr_flush_request *flush_req) +{ + int rc = 0; + struct cam_isp_context *ctx_isp; + + ctx_isp = (struct cam_isp_context *) ctx->ctx_priv; + spin_lock_bh(&ctx->lock); + ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_FLUSH; + ctx_isp->frame_skip_count = 2; + spin_unlock_bh(&ctx->lock); + + CAM_DBG(CAM_ISP, "Flush request in state %d", ctx->state); + rc = __cam_isp_ctx_flush_req(ctx, &ctx->pending_req_list, flush_req); + 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"); + rc = __cam_isp_ctx_flush_req(ctx, &ctx->pending_req_list, flush_req); + + /* if nothing is in pending req list, change state to acquire*/ + spin_lock_bh(&ctx->lock); + 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, + }, + /* FLUSH */ + { + .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; + 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; + + 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 %d", + 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; + 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 %d", 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; + CAM_DBG(CAM_ISP, "frame id: %lld time stamp:0x%llx", + ctx_isp->frame_id, ctx_isp->sof_timestamp_val); + + if (list_empty(&ctx->pending_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, "No pending request"); + 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->pending_req_list, struct cam_ctx_request, + list); + req_isp = (struct cam_isp_ctx_req *)req->req_priv; + + CAM_DBG(CAM_ISP, "Report Bubble flag %d", req_isp->bubble_report); + 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; + ctx->ctx_crm_intf->notify_err(¬ify); + CAM_DBG(CAM_ISP, "Notify CRM about Bubble frame %lld", + ctx_isp->frame_id); + } else { + /* + * Since can not bubble report, always move the request to + * active list. + */ + 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); + req_isp->bubble_report = 0; + } + + 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 %d", 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; + 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; + + 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 %d", + 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; + + /* notify reqmgr with sof signal*/ + if (ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_trigger) { + if (list_empty(&ctx->pending_req_list)) { + CAM_ERR(CAM_ISP, "Reg upd ack with no pending request"); + goto error; + } + 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; + request_id = 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); + } 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; + + 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"); + } + __cam_isp_ctx_send_sof_timestamp(ctx_isp, request_id, + CAM_REQ_MGR_SOF_EVENT_SUCCESS); + + ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_EPOCH; + CAM_DBG(CAM_ISP, "next substate %d", 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 */ + { + }, + /* FLUSH */ + { + .irq_ops = { + NULL, + __cam_isp_ctx_sof_in_flush, + NULL, + NULL, + NULL, + __cam_isp_ctx_buf_done_in_applied, + }, + }, +}; + +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 %d", + 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 %d", ctx_isp->substate_activated); + + 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, + }, + /* FLUSHED */ + { + .ioctl_ops = {}, + .crm_ops = {}, + .irq_ops = NULL, + }, +}; + +/* 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 (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_isp->frame_id = 0; + ctx_isp->active_req_cnt = 0; + ctx_isp->reported_req_id = 0; + + /* + * 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"); + rc = __cam_isp_ctx_flush_req(ctx, &ctx->pending_req_list, &flush_req); + + ctx->state = CAM_CTX_AVAILABLE; + + 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_top_state( + struct cam_context *ctx, struct cam_config_dev_cmd *cmd) +{ + int rc = 0; + struct cam_ctx_request *req = NULL; + struct cam_isp_ctx_req *req_isp; + uint64_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_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"); + rc = -ENOMEM; + goto end; + } + + 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, + (uint64_t *) &packet_addr, &len); + if (rc != 0) { + CAM_ERR(CAM_ISP, "Can not get packet address"); + rc = -EINVAL; + goto free_req; + } + + packet = (struct cam_packet *) (packet_addr + cmd->offset); + CAM_DBG(CAM_ISP, "pack_handle %llx", cmd->packet_handle); + CAM_DBG(CAM_ISP, "packet address is 0x%llx", 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); + + /* preprocess the configuration */ + memset(&cfg, 0, sizeof(cfg)); + cfg.packet = packet; + 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; + + 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; + + 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 0x%llx 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"); + } else { + rc = -EINVAL; + CAM_ERR(CAM_ISP, "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_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 in wrong state"); + } + } + if (rc) + goto free_req; + + CAM_DBG(CAM_ISP, "Preprocessing Config %lld successful", + req->request_id); + + return rc; + +free_req: + spin_lock_bh(&ctx->lock); + list_add_tail(&req->list, &ctx->free_req_list); + spin_unlock_bh(&ctx->lock); +end: + 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_isp_hw_cmd_args 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_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, (void __user *)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 = (uint64_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_ISP_HW_MGR_CMD_IS_RDI_ONLY_CONTEXT; + 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 (hw_cmd_args.u.is_rdi_only_context) { + /* + * 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; + } 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; + + 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."); + kfree(isp_res); + 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; +free_res: + kfree(isp_res); +end: + return rc; +} + +static int __cam_isp_ctx_config_dev_in_acquired(struct cam_context *ctx, + struct cam_config_dev_cmd *cmd) +{ + int rc = 0; + + 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_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 (!list_empty(&ctx->pending_req_list)) { + 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_hw_config_args arg; + 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; + } + + arg.ctxt_to_hw_map = ctx_isp->hw_ctx; + arg.request_id = req->request_id; + arg.hw_update_entries = req_isp->cfg; + arg.num_hw_update_entries = req_isp->num_cfg; + arg.priv = &req_isp->hw_update_data; + arg.init_packet = 1; + + ctx_isp->frame_id = 0; + ctx_isp->active_req_cnt = 0; + ctx_isp->reported_req_id = 0; + ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF; + + /* + * 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, &arg); + 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); + goto end; + } + CAM_DBG(CAM_ISP, "start device success"); +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; + + /* 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 %d", ctx_isp->substate_activated); + + /* stop hw first */ + if (ctx_isp->hw_ctx) { + stop.ctxt_to_hw_map = ctx_isp->hw_ctx; + stop.args = stop_cmd; + 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_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->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; + + CAM_DBG(CAM_ISP, "next state %d", ctx->state); + 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; + + __cam_isp_ctx_stop_dev_in_activated_unlock(ctx, cmd); + 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_link_pause(struct cam_context *ctx) +{ + int rc = 0; + struct cam_isp_hw_cmd_args 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_ISP_HW_MGR_CMD_PAUSE_HW; + 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_isp_hw_cmd_args 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_ISP_HW_MGR_CMD_RESUME_HW; + 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; + 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_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 %d request _id:%lld", + ctx_isp->substate_activated, apply->request_id); + if (ctx_isp->substate_machine[ctx_isp->substate_activated]. + crm_ops.apply_req) { + rc = ctx_isp->substate_machine[ctx_isp->substate_activated]. + crm_ops.apply_req(ctx, apply); + } else { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "No handle function in activated substate %d", + ctx_isp->substate_activated); + rc = -EFAULT; + } + + if (rc) + CAM_ERR_RATE_LIMIT(CAM_ISP, + "Apply failed in active substate %d", + ctx_isp->substate_activated); + 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_context *ctx = (struct cam_context *)context; + struct cam_isp_context *ctx_isp = + (struct cam_isp_context *)ctx->ctx_priv; + + spin_lock_bh(&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 %d, evt id %d", + ctx->state, ctx_isp->substate_activated, evt_id); + if (ctx_isp->substate_machine_irq[ctx_isp->substate_activated]. + irq_ops[evt_id]) { + rc = ctx_isp->substate_machine_irq[ctx_isp->substate_activated]. + irq_ops[evt_id](ctx_isp, evt_data); + } else { + CAM_DBG(CAM_ISP, "No handle function for substate %d", + ctx_isp->substate_activated); + } + CAM_DBG(CAM_ISP, "Exit: State %d Substate %d", + ctx->state, ctx_isp->substate_activated); + spin_unlock_bh(&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 = { + .release_dev = __cam_isp_ctx_release_dev_in_top_state, + .config_dev = __cam_isp_ctx_config_dev_in_acquired, + }, + .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, + }, + /* 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, + }, + .crm_ops = { + .unlink = __cam_isp_ctx_unlink_in_ready, + .flush_req = __cam_isp_ctx_flush_req_in_ready, + }, + .irq_ops = NULL, + }, + /* 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, + }, + .crm_ops = { + .unlink = __cam_isp_ctx_unlink_in_activated, + .apply_req = __cam_isp_ctx_apply_req, + .flush_req = __cam_isp_ctx_flush_req_in_activated, + .process_evt = __cam_isp_ctx_process_evt, + }, + .irq_ops = __cam_isp_ctx_handle_irq_in_activated, + }, +}; + + +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->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; + + 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; + +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 is invalid"); + + memset(ctx, 0, sizeof(*ctx)); + return rc; +} diff --git a/drivers/media/platform/msm/camera_oneplus/cam_isp/cam_isp_context.h b/drivers/media/platform/msm/camera_oneplus/cam_isp/cam_isp_context.h new file mode 100644 index 000000000000..38ea58de4a16 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/cam_isp_context.h @@ -0,0 +1,171 @@ +/* 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_ISP_CONTEXT_H_ +#define _CAM_ISP_CONTEXT_H_ + + +#include +#include + +#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 20. + */ +#define CAM_ISP_CTX_RES_MAX 20 + +/* + * Maxiimum configuration entry size - This is based on the + * worst case DUAL IFE use case plus some margin. + */ +#define CAM_ISP_CTX_CFG_MAX 22 + +/* 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_FLUSH, + CAM_ISP_CTX_ACTIVATED_MAX, +}; + + +/** + * 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 + * + */ +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; +}; + +/** + * 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. + * @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 + * @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 + * @frame_skip_count: Number of frame to skip before change state + * + */ +struct cam_isp_context { + struct cam_context *base; + + int64_t frame_id; + uint32_t substate_activated; + 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; + int32_t active_req_cnt; + int64_t reported_req_id; + uint32_t subscribe_event; + int64_t last_applied_req_id; + uint32_t frame_skip_count; +}; + +/** + * 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/drivers/media/platform/msm/camera_oneplus/cam_isp/cam_isp_dev.c b/drivers/media/platform/msm/camera_oneplus/cam_isp/cam_isp_dev.c new file mode 100644 index 000000000000..e775daac6fbe --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/cam_isp_dev.c @@ -0,0 +1,155 @@ +/* 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "cam_isp_dev.h" +#include "cam_isp_log.h" +#include "cam_hw_mgr_intf.h" +#include "cam_isp_hw_mgr_intf.h" +#include "cam_node.h" +#include "cam_debug_util.h" + +static struct cam_isp_dev g_isp_dev; + +static const struct of_device_id cam_isp_dt_match[] = { + { + .compatible = "qcom,cam-isp" + }, + {} +}; + +static int cam_isp_subdev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + struct cam_node *node = v4l2_get_subdevdata(sd); + + if (!node) { + CAM_ERR(CAM_ISP, "Node ptr is NULL"); + return -EINVAL; + } + + cam_node_shutdown(node); + + return 0; +} + +static const struct v4l2_subdev_internal_ops cam_isp_subdev_internal_ops = { + .close = cam_isp_subdev_close, +}; + +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; + + g_isp_dev.sd.internal_ops = &cam_isp_subdev_internal_ops; + /* Initialze 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); + 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_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, + }, +}; + +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/drivers/media/platform/msm/camera_oneplus/cam_isp/cam_isp_dev.h b/drivers/media/platform/msm/camera_oneplus/cam_isp/cam_isp_dev.h new file mode 100644 index 000000000000..95463ca37a13 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/cam_isp_dev.h @@ -0,0 +1,35 @@ +/* Copyright (c) 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. + */ + +#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 + * + */ +struct cam_isp_dev { + struct cam_subdev sd; + struct cam_context ctx[CAM_CTX_MAX]; + struct cam_isp_context ctx_isp[CAM_CTX_MAX]; +}; + +#endif /* __CAM_ISP_DEV_H__ */ diff --git a/drivers/media/platform/msm/camera_oneplus/cam_isp/cam_isp_log.h b/drivers/media/platform/msm/camera_oneplus/cam_isp/cam_isp_log.h new file mode 100644 index 000000000000..3d8d8aa194c8 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/cam_isp_log.h @@ -0,0 +1,26 @@ +/* Copyright (c) 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. + */ + +#ifndef _CAM_ISP_LOG_H_ +#define _CAM_ISP_LOG_H_ + +#include + +#define ISP_TRACE_ENABLE 0 + +#if (ISP_TRACE_ENABLE == 1) + #define ISP_TRACE(args...) trace_printk(args) +#else + #define ISP_TRACE(arg...) +#endif + +#endif /* __CAM_ISP_LOG_H__ */ diff --git a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/Makefile b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/Makefile new file mode 100644 index 000000000000..f66f64749e82 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/Makefile @@ -0,0 +1,15 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_req_mgr +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_utils +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_core +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_smmu +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_cdm +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/irq_controller +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_smmu/ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_cpas/include + +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/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c new file mode 100644 index 000000000000..f5cf1bac458e --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -0,0 +1,4223 @@ +/* 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. + */ + +#include +#include +#include +#include +#include +#include +#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" + +#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 + 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, +}; + +static struct cam_ife_hw_mgr g_ife_hw_mgr; + +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, (void __user *)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((void __user *)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; + + 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.start) { + isp_hw_res->hw_res[i]->rdi_only_ctx = + ctx->is_rdi_only_context; + 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; + } + } 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 (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 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 resrouce 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 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]) + continue; + + isp_res = hw_mgr_res->hw_res[i]; + if (isp_res->hw_intf->hw_idx != base_idx) + continue; + + 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 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 is alreay exist in the list */ + for (i = 0; i < CAM_IFE_HW_NUM_MAX; 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 == CAM_IFE_HW_NUM_MAX) { + 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_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_info *in_port) +{ + int rc = -EINVAL; + struct cam_vfe_acquire_args vfe_acquire; + struct cam_isp_out_port_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.vfe_out.ctx = 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; + 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 = CAM_ISP_RESOURCE_VFE_OUT; + ife_src_res->child[ife_src_res->num_children++] = ife_out_res; + + 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_info *in_port) +{ + int rc = -1; + uint32_t i, j, k; + struct cam_vfe_acquire_args vfe_acquire; + struct cam_isp_out_port_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; + + 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.vfe_out.ctx = 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; + + for (j = 0; j < CAM_ISP_HW_SPLIT_MAX; j++) { + if (!ife_src_res->hw_res[j]) + continue; + + 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 = + 1; + } 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 = 0; + } + + hw_intf = ife_src_res->hw_res[j]->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; + } + + 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 = 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; + } + + 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_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: + rc = cam_ife_hw_mgr_acquire_res_ife_out_pixel(ife_ctx, + ife_src_res, in_port); + 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_src( + struct cam_ife_hw_mgr_ctx *ife_ctx, + struct cam_isp_in_port_info *in_port) +{ + 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) + 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; + + switch (csid_res->res_id) { + case CAM_IFE_PIX_PATH_RES_IPP: + vfe_acquire.vfe_in.res_id = CAM_ISP_HW_VFE_IN_CAMIF; + vfe_acquire.vfe_in.in_port = in_port; + 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_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 = 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; + CAM_DBG(CAM_ISP, + "acquire success res type :0x%x res id:0x%x", + ife_src_res->hw_res[i]->res_type, + ife_src_res->hw_res[i]->res_id); + + } + + /* 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 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_info *in_port, + uint32_t *cid_res_id, + enum cam_ife_pix_path_res_id csid_path) +{ + int rc = -1; + int i, j; + struct cam_ife_hw_mgr *ife_hw_mgr; + struct cam_ife_hw_mgr_res *cid_res; + struct cam_hw_intf *hw_intf; + struct cam_csid_hw_reserve_resource_args csid_acquire; + + ife_hw_mgr = ife_ctx->hw_mgr; + + 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 err; + } + cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_cid, &cid_res); + + csid_acquire.res_type = CAM_ISP_RESOURCE_CID; + csid_acquire.in_port = in_port; + csid_acquire.res_id = csid_path; + + 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 + break; + } + + if (i == CAM_IFE_CSID_HW_NUM_MAX || !csid_acquire.node_res) { + CAM_ERR(CAM_ISP, "Can not acquire ife csid rdi resource"); + goto err; + } + + cid_res->res_type = CAM_IFE_HW_MGR_RES_CID; + cid_res->res_id = csid_acquire.node_res->res_id; + cid_res->is_dual_vfe = in_port->usage_type; + cid_res->hw_res[0] = csid_acquire.node_res; + cid_res->hw_res[1] = NULL; + /* CID(DT_ID) value of acquire device, require for path */ + *cid_res_id = csid_acquire.node_res->res_id; + + if (cid_res->is_dual_vfe) { + csid_acquire.node_res = NULL; + csid_acquire.res_type = CAM_ISP_RESOURCE_CID; + csid_acquire.in_port = in_port; + for (j = i + 1; j < CAM_IFE_CSID_HW_NUM_MAX; j++) { + if (!ife_hw_mgr->csid_devices[j]) + 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 err; + } + cid_res->hw_res[1] = csid_acquire.node_res; + } + cid_res->parent = &ife_ctx->res_list_ife_in; + ife_ctx->res_list_ife_in.child[ + ife_ctx->res_list_ife_in.num_children++] = cid_res; + + return 0; +err: + return rc; + +} + +static int cam_ife_hw_mgr_acquire_res_ife_csid_ipp( + struct cam_ife_hw_mgr_ctx *ife_ctx, + struct cam_isp_in_port_info *in_port) +{ + int rc = -1; + 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; + uint32_t cid_res_id; + struct cam_csid_hw_reserve_resource_args csid_acquire; + + /* get cid resource */ + rc = cam_ife_mgr_acquire_cid_res(ife_ctx, in_port, &cid_res_id, + CAM_IFE_PIX_PATH_RES_IPP); + if (rc) { + CAM_ERR(CAM_ISP, "Acquire IFE CID resource Failed"); + goto err; + } + + ife_hw_mgr = ife_ctx->hw_mgr; + + 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 err; + } + cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_csid, &csid_res); + + csid_acquire.res_type = CAM_ISP_RESOURCE_PIX_PATH; + csid_acquire.res_id = CAM_IFE_PIX_PATH_RES_IPP; + csid_acquire.cid = cid_res_id; + csid_acquire.in_port = in_port; + csid_acquire.out_port = in_port->data; + + csid_res->res_type = CAM_ISP_RESOURCE_PIX_PATH; + csid_res->res_id = CAM_IFE_PIX_PATH_RES_IPP; + csid_res->is_dual_vfe = in_port->usage_type; + + if (in_port->usage_type) + csid_res->is_dual_vfe = 1; + else { + csid_res->is_dual_vfe = 0; + csid_acquire.sync_mode = CAM_ISP_HW_SYNC_NONE; + } + + list_for_each_entry(cid_res, &ife_ctx->res_list_ife_cid, + list) { + if (cid_res->res_id != cid_res_id) + continue; + + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!cid_res->hw_res[i]) + continue; + + csid_acquire.node_res = NULL; + if (csid_res->is_dual_vfe) { + if (i == CAM_ISP_HW_SPLIT_LEFT) + csid_acquire.sync_mode = + CAM_ISP_HW_SYNC_MASTER; + else + csid_acquire.sync_mode = + CAM_ISP_HW_SYNC_SLAVE; + } + + hw_intf = ife_hw_mgr->csid_devices[ + cid_res->hw_res[i]->hw_intf->hw_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 ipp resource"); + goto err; + } + + csid_res->hw_res[i] = csid_acquire.node_res; + CAM_DBG(CAM_ISP, + "acquired csid(%s)=%d ipp rsrc successfully", + (i == 0) ? "left" : "right", + hw_intf->hw_idx); + + } + + if (i == CAM_IFE_CSID_HW_NUM_MAX) { + CAM_ERR(CAM_ISP, + "Can not acquire ife csid ipp resource"); + goto err; + } + + csid_res->parent = cid_res; + cid_res->child[cid_res->num_children++] = csid_res; + } + + CAM_DBG(CAM_ISP, "acquire res %d", csid_acquire.res_id); + + return 0; +err: + 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; + 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 %d 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_info *in_port) +{ + int rc = -1; + int i, j; + + 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_info *out_port; + uint32_t cid_res_id; + struct cam_csid_hw_reserve_resource_args csid_acquire; + + ife_hw_mgr = ife_ctx->hw_mgr; + + 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)) + continue; + + /* get cid resource */ + rc = cam_ife_mgr_acquire_cid_res(ife_ctx, + in_port, &cid_res_id, + cam_ife_hw_mgr_get_ife_csid_rdi_res_type( + out_port->res_type)); + if (rc) { + CAM_ERR(CAM_ISP, + "Acquire IFE CID resource Failed"); + goto err; + } + + 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 err; + } + cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_csid, &csid_res); + + /* + * no need to check since we are doing one to one mapping + * between the csid rdi type and out port rdi type + */ + + memset(&csid_acquire, 0, sizeof(csid_acquire)); + csid_acquire.res_id = + cam_ife_hw_mgr_get_ife_csid_rdi_res_type( + out_port->res_type); + + csid_acquire.res_type = CAM_ISP_RESOURCE_PIX_PATH; + csid_acquire.cid = cid_res_id; + csid_acquire.in_port = in_port; + csid_acquire.out_port = out_port; + csid_acquire.sync_mode = CAM_ISP_HW_SYNC_NONE; + + list_for_each_entry(cid_res, &ife_ctx->res_list_ife_cid, + list) { + if (cid_res->res_id != cid_res_id) + continue; + + for (j = 0; j < CAM_ISP_HW_SPLIT_MAX; j++) { + if (!cid_res->hw_res[j]) + continue; + + csid_acquire.node_res = NULL; + + hw_intf = ife_hw_mgr->csid_devices[ + cid_res->hw_res[j]->hw_intf->hw_idx]; + rc = hw_intf->hw_ops.reserve(hw_intf->hw_priv, + &csid_acquire, sizeof(csid_acquire)); + if (rc) { + CAM_DBG(CAM_ISP, + "CSID Path reserve failed hw=%d rc=%d", + hw_intf->hw_idx, rc); + continue; + } + + /* RDI does not need Dual ISP. Break */ + break; + } + + if (j == CAM_ISP_HW_SPLIT_MAX && + csid_acquire.node_res == NULL) { + CAM_ERR(CAM_ISP, + "acquire csid rdi rsrc failed, cid %d", + cid_res_id); + goto err; + } + + csid_res->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; + CAM_DBG(CAM_ISP, "acquire res %d", + csid_acquire.res_id); + csid_res->parent = cid_res; + cid_res->child[cid_res->num_children++] = + csid_res; + + /* Done with cid_res_id. Break */ + break; + } + } + + return 0; +err: + return rc; +} + +static int cam_ife_hw_mgr_acquire_res_root( + struct cam_ife_hw_mgr_ctx *ife_ctx, + struct cam_isp_in_port_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) { + 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_hw_mgr_preprocess_out_port( + struct cam_ife_hw_mgr_ctx *ife_ctx, + struct cam_isp_in_port_info *in_port, + int *pixel_count, + int *rdi_count) +{ + int pixel_num = 0; + int rdi_num = 0; + uint32_t i; + struct cam_isp_out_port_info *out_port; + struct cam_ife_hw_mgr *ife_hw_mgr; + + ife_hw_mgr = ife_ctx->hw_mgr; + + 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 + pixel_num++; + } + + *pixel_count = pixel_num; + *rdi_count = rdi_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_info *in_port, + uint32_t *num_pix_port, uint32_t *num_rdi_port) +{ + int rc = -1; + int is_dual_vfe = 0; + int pixel_count = 0; + int rdi_count = 0; + + 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_out_port(ife_ctx, in_port, + &pixel_count, &rdi_count); + + if (!pixel_count && !rdi_count) { + CAM_ERR(CAM_ISP, "No PIX or RDI resource"); + return -EINVAL; + } + + if (pixel_count) { + /* get ife csid IPP resrouce */ + rc = cam_ife_hw_mgr_acquire_res_ife_csid_ipp(ife_ctx, in_port); + if (rc) { + CAM_ERR(CAM_ISP, + "Acquire IFE CSID IPP 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; + } + } + + /* get ife src resource */ + rc = cam_ife_hw_mgr_acquire_res_ife_src(ife_ctx, in_port); + if (rc) { + CAM_ERR(CAM_ISP, "Acquire IFE SRC resource Failed"); + goto err; + } + + 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 += pixel_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_ife_hw_mgr_ctx *ctx = NULL; + + if (!userdata) { + CAM_ERR(CAM_ISP, "Invalid args"); + return; + } + + ctx = userdata; + + if (status == CAM_CDM_CB_STATUS_BL_SUCCESS) { + complete(&ctx->config_done_complete); + CAM_DBG(CAM_ISP, + "Called by CDM hdl=%x, udata=%pK, status=%d, cookie=%llu", + handle, userdata, status, cookie); + } else { + CAM_WARN(CAM_ISP, + "Called by CDM hdl=%x, udata=%pK, status=%d, cookie=%llu", + handle, userdata, status, cookie); + } +} + +/* 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_info *in_port = NULL; + struct cam_isp_resource *isp_resource = 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; + + 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; + + 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, + "start copy from user handle %lld with len = %d", + isp_resource[i].res_hdl, + isp_resource[i].length); + + in_port = memdup_user((void __user *)isp_resource[i].res_hdl, + isp_resource[i].length); + if (in_port > 0) { + rc = cam_ife_mgr_acquire_hw_for_ctx(ife_ctx, in_port, + &num_pix_port_per_in, &num_rdi_port_per_in); + total_pix_port += num_pix_port_per_in; + total_rdi_port += num_rdi_port_per_in; + + kfree(in_port); + 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_ife_hw_mgr_put_ctx(&ife_hw_mgr->used_ctx_list, &ife_ctx); + + CAM_DBG(CAM_ISP, "Exit...(success)"); + + 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; +} + +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; + + CAM_DBG(CAM_ISP, + "usage=%u left cam_bw_bps=%llu ext_bw_bps=%llu\n" + "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) + if (i == CAM_ISP_HW_SPLIT_LEFT) { + cam_bw_bps = + bw_config->left_pix_vote.cam_bw_bps; + ext_bw_bps = + bw_config->left_pix_vote.ext_bw_bps; + } else { + cam_bw_bps = + bw_config->right_pix_vote.cam_bw_bps; + ext_bw_bps = + bw_config->right_pix_vote.ext_bw_bps; + } + 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_ISP, "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; + 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; + + CAM_DBG(CAM_ISP, "Enter"); + if (!hw_mgr_priv || !config_hw_args) { + CAM_ERR(CAM_ISP, "Invalid arguments"); + 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 -EPERM; + } + + if (!ctx->ctx_in_use || !ctx->cdm_cmd) { + CAM_ERR(CAM_ISP, "Invalid context parameters"); + return -EPERM; + } + if (atomic_read(&ctx->overflow_pending)) + return -EINVAL; + + hw_update_data = (struct cam_isp_prepare_hw_update_data *) cfg->priv; + + for (i = 0; i < CAM_IFE_HW_NUM_MAX; i++) { + if (hw_update_data->bw_config_valid[i] == true) { + rc = cam_isp_blob_bw_update( + (struct cam_isp_bw_config *) + &hw_update_data->bw_config[i], ctx); + if (rc) + CAM_ERR(CAM_ISP, "Bandwidth Update Failed"); + } + } + + CAM_DBG(CAM_ISP, "Enter ctx id:%d num_hw_upd_entries %d", + ctx->ctx_index, cfg->num_hw_update_entries); + + if (cfg->num_hw_update_entries > 0) { + cdm_cmd = ctx->cdm_cmd; + cdm_cmd->cmd_arrary_count = cfg->num_hw_update_entries; + cdm_cmd->type = CAM_CDM_BL_CMD_TYPE_MEM_HANDLE; + cdm_cmd->flag = true; + cdm_cmd->userdata = ctx; + cdm_cmd->cookie = cfg->request_id; + + for (i = 0 ; i <= cfg->num_hw_update_entries; i++) { + cmd = (cfg->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; + } + + if (cfg->request_id == 1) + init_completion(&ctx->config_done_complete); + CAM_DBG(CAM_ISP, "Submit to CDM"); + rc = cam_cdm_submit_bls(ctx->cdm_handle, cdm_cmd); + if (rc) { + CAM_ERR(CAM_ISP, "Failed to apply the configs"); + return rc; + } + + if (cfg->init_packet) { + init_completion(&ctx->config_done_complete); + 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", + cfg->request_id, rc); + if (rc == 0) + rc = -ETIMEDOUT; + } else { + rc = 0; + CAM_DBG(CAM_ISP, + "config done Success for req_id=%llu", + cfg->request_id); + } + + rc = 0; + } + } else { + CAM_ERR(CAM_ISP, "No commands to config"); + } + CAM_DBG(CAM_ISP, "Exit"); + + 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 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_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); + + /* Set the csid halt command */ + if (!stop_args->args) + csid_halt_type = CAM_CSID_HALT_IMMEDIATELY; + else + csid_halt_type = CAM_CSID_HALT_AT_FRAME_BOUNDARY; + + /* 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"); + + if (cam_cdm_stream_off(ctx->cdm_handle)) + CAM_ERR(CAM_ISP, "CDM stream off failed %d", + ctx->cdm_handle); + + 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_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]); + /* 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; + } + } + + cam_tasklet_stop(ctx->common.tasklet_info); + /* + * 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; + + /* 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 (i == master_base_idx) + continue; + cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_cid, + ctx->base[i].idx, csid_halt_type); + } + + /* 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 (i == master_base_idx) + continue; + + cam_ife_mgr_csid_stop_hw(ctx, &ctx->res_list_ife_csid, + ctx->base[i].idx, csid_halt_type); + } + + + /* 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); + } + + /* 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]); + + CAM_DBG(CAM_ISP, "Exit...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); + + 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 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_hw_config_args *start_args = start_hw_args; + struct cam_hw_stop_args stop_args; + struct cam_isp_stop_hw_method stop_hw_method; + struct cam_ife_hw_mgr_ctx *ctx; + struct cam_ife_hw_mgr_res *hw_mgr_res; + uint32_t i; + + if (!hw_mgr_priv || !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, "Enter... ctx id:%d", + ctx->ctx_index); + + /* update Bandwidth should be done at the hw layer */ + + cam_tasklet_start(ctx->common.tasklet_info); + + /* 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)); + } + + /* INIT IFE Root: do nothing */ + + 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 err; + } + } + + + 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 err; + } + } + + /* 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 err; + } + } + + /* 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 err; + } + } + + 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 = -1; + } + } + 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 err; + } + + /* Apply initial configuration */ + CAM_DBG(CAM_ISP, "Config HW"); + rc = cam_ife_mgr_config_hw(hw_mgr_priv, start_hw_args); + if (rc) { + CAM_ERR(CAM_ISP, "Config HW failed"); + goto err; + } + + 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++) { + 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 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 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, "Exit...(success)"); + return 0; +err: + stop_hw_method.hw_stop_cmd = CAM_CSID_HALT_IMMEDIATELY; + stop_args.ctxt_to_hw_map = start_args->ctxt_to_hw_map; + stop_args.args = (void *)(&stop_hw_method); + cam_ife_mgr_stop_hw(hw_mgr_priv, &stop_args); + CAM_DBG(CAM_ISP, "Exit...(rc=%d)", rc); + 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_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); + + /* 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_DBG(CAM_ISP, "Exit...ctx id:%d", + ctx->ctx_index); + cam_ife_hw_mgr_put_ctx(&hw_mgr->free_ctx_list, &ctx); + 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_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; + + ctx = prepare->ctxt_to_hw_map; + + CAM_DBG(CAM_ISP, + "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) + clk_rate = + clock_config->left_pix_hz; + else + clk_rate = + clock_config->right_pix_hz; + 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 (j = 0; j < clock_config->num_rdi; j++) + clk_rate = max(clock_config->rdi_hz[j], + clk_rate); + 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) { + clock_upd_args.node_res = + hw_mgr_res->hw_res[i]; + CAM_DBG(CAM_ISP, + "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_ISP, "Clock Update failed"); + } else + CAM_WARN(CAM_ISP, "NULL hw_intf!"); + } + } + + 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; + + if (!blob_data || (blob_size == 0) || !blob_info) { + CAM_ERR(CAM_ISP, "Invalid info blob %pK %d prepare %pK", + blob_data, blob_size, prepare); + 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) { + CAM_ERR(CAM_ISP, "Failed. prepare is NULL, blob_type %d", + blob_type); + return -EINVAL; + } + + switch (blob_type) { + case CAM_ISP_GENERIC_BLOB_TYPE_HFR_CONFIG: { + struct cam_isp_resource_hfr_config *hfr_config = + (struct cam_isp_resource_hfr_config *)blob_data; + + 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 = + (struct cam_isp_clock_config *)blob_data; + + rc = cam_isp_blob_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_BW_CONFIG: { + struct cam_isp_bw_config *bw_config = + (struct cam_isp_bw_config *)blob_data; + struct cam_isp_prepare_hw_update_data *prepare_hw_data; + + if (!prepare || !prepare->priv || + (bw_config->usage_type >= CAM_IFE_HW_NUM_MAX)) { + CAM_ERR(CAM_ISP, "Invalid inputs"); + rc = -EINVAL; + break; + } + + 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_valid[bw_config->usage_type] = true; + + } + 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; + } + + CAM_DBG(CAM_ISP, "enter"); + + 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; + + rc = cam_packet_util_validate_packet(prepare->packet); + 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; + + 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, + 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; + goto end; + } else + prepare_hw_data->packet_opcode_type = CAM_ISP_PACKET_UPDATE_DEV; + + /* 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_cmd(void *hw_mgr_priv, void *cmd_args) +{ + int rc = 0; + struct cam_isp_hw_cmd_args *hw_cmd_args = cmd_args; + struct cam_ife_hw_mgr_ctx *ctx; + + if (!hw_mgr_priv || !cmd_args) { + CAM_ERR(CAM_ISP, "Invalid arguments"); + return -EINVAL; + } + + ctx = (struct cam_ife_hw_mgr_ctx *)hw_cmd_args->ctxt_to_hw_map; + 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_ISP_HW_MGR_CMD_IS_RDI_ONLY_CONTEXT: + if (ctx->is_rdi_only_context) + hw_cmd_args->u.is_rdi_only_context = 1; + else + hw_cmd_args->u.is_rdi_only_context = 0; + + break; + 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; + default: + CAM_ERR(CAM_ISP, "Invalid HW mgr command:0x%x", + hw_cmd_args->cmd_type); + rc = -EINVAL; + break; + } + + return rc; +} + +static int cam_ife_mgr_cmd_get_sof_timestamp( + struct cam_ife_hw_mgr_ctx *ife_ctx, + uint64_t *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; + + list_for_each_entry(hw_mgr_res, &ife_ctx->res_list_ife_csid, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + if (!hw_mgr_res->hw_res[i] || + (i == CAM_ISP_HW_SPLIT_RIGHT)) + 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) { + 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) + *time_stamp = + csid_get_time.time_stamp_val; + /* + * 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 + */ + goto end; + } + } + } +end: + if (rc) + CAM_ERR(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_VFE_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(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 0 i.e.SUCCESS + */ +static int cam_ife_hw_mgr_is_ctx_affected( + struct cam_ife_hw_mgr_ctx *ife_hwr_mgr_ctx, + uint32_t *affected_core, uint32_t size) +{ + + int32_t rc = -EPERM; + 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(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 = 0; + else { + ctx_affected_core_idx[j] = ife_hwr_mgr_ctx->base[i].idx; + j = j + 1; + } + } + + if (rc == 0) { + 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; +} + +/* + * Loop through each context + * a. match core_idx + * b. For each context from ctx_list Stop the acquired resources + * c. Notify CRM with fatal error for the affected isp context + * d. For any dual VFE context, if copanion VFE is also serving + * other context it should also notify the CRM with fatal error + */ +static int cam_ife_hw_mgr_process_overflow( + struct cam_ife_hw_mgr_ctx *curr_ife_hwr_mgr_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 ife_hwr_irq_err_cb; + struct cam_ife_hw_mgr *ife_hwr_mgr = NULL; + struct cam_hw_stop_args stop_args; + uint32_t i = 0; + + CAM_DBG(CAM_ISP, "Enter"); + + if (!recovery_data) { + CAM_ERR(CAM_ISP, "recovery_data parameter is NULL"); + return -EINVAL; + } + recovery_data->no_of_context = 0; + /* affected_core is indexed by core_idx*/ + affected_core[curr_core_idx] = 1; + + ife_hwr_mgr = curr_ife_hwr_mgr_ctx->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 + */ + CAM_DBG(CAM_ISP, "Calling match Hw idx"); + 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); + + ife_hwr_irq_err_cb = + ife_hwr_mgr_ctx->common.event_cb[CAM_ISP_HW_EVENT_ERROR]; + + stop_args.ctxt_to_hw_map = ife_hwr_mgr_ctx; + + /* Add affected_context in list of recovery data*/ + CAM_DBG(CAM_ISP, "Add new entry in affected_ctx_list"); + 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 + */ + + ife_hwr_irq_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]); + } + CAM_DBG(CAM_ISP, "Exit"); + return 0; +} + +static int cam_ife_hw_mgr_get_err_type( + void *handler_priv, + void *payload) +{ + struct cam_isp_resource_node *hw_res_l = NULL; + struct cam_isp_resource_node *hw_res_r = NULL; + struct cam_ife_hw_mgr_ctx *ife_hwr_mgr_ctx; + struct cam_vfe_top_irq_evt_payload *evt_payload; + struct cam_ife_hw_mgr_res *isp_ife_camif_res = NULL; + uint32_t status = 0; + uint32_t core_idx; + + ife_hwr_mgr_ctx = handler_priv; + evt_payload = payload; + + if (!evt_payload) { + CAM_ERR(CAM_ISP, "No payload"); + return IRQ_HANDLED; + } + + core_idx = evt_payload->core_index; + evt_payload->evt_id = CAM_ISP_HW_EVENT_ERROR; + + list_for_each_entry(isp_ife_camif_res, + &ife_hwr_mgr_ctx->res_list_ife_src, list) { + + if ((isp_ife_camif_res->res_type == + CAM_IFE_HW_MGR_RES_UNINIT) || + (isp_ife_camif_res->res_id != CAM_ISP_HW_VFE_IN_CAMIF)) + continue; + + hw_res_l = isp_ife_camif_res->hw_res[CAM_ISP_HW_SPLIT_LEFT]; + hw_res_r = isp_ife_camif_res->hw_res[CAM_ISP_HW_SPLIT_RIGHT]; + + CAM_DBG(CAM_ISP, "is_dual_vfe ? = %d\n", + isp_ife_camif_res->is_dual_vfe); + + /* ERROR check for Left VFE */ + if (!hw_res_l) { + CAM_DBG(CAM_ISP, "VFE(L) Device is NULL"); + break; + } + + CAM_DBG(CAM_ISP, "core id= %d, HW id %d", core_idx, + hw_res_l->hw_intf->hw_idx); + + if (core_idx == hw_res_l->hw_intf->hw_idx) { + status = hw_res_l->bottom_half_handler( + hw_res_l, evt_payload); + } + + if (status) + break; + + /* ERROR check for Right VFE */ + if (!hw_res_r) { + CAM_DBG(CAM_ISP, "VFE(R) Device is NULL"); + continue; + } + CAM_DBG(CAM_ISP, "core id= %d, HW id %d", core_idx, + hw_res_r->hw_intf->hw_idx); + + if (core_idx == hw_res_r->hw_intf->hw_idx) { + status = hw_res_r->bottom_half_handler( + hw_res_r, evt_payload); + } + + if (status) + break; + } + CAM_DBG(CAM_ISP, "Exit (status = %d)!", status); + return status; +} + +static int cam_ife_hw_mgr_handle_camif_error( + void *handler_priv, + void *payload) +{ + int32_t error_status; + uint32_t core_idx; + struct cam_ife_hw_mgr_ctx *ife_hwr_mgr_ctx; + struct cam_vfe_top_irq_evt_payload *evt_payload; + struct cam_isp_hw_error_event_data error_event_data = {0}; + struct cam_hw_event_recovery_data recovery_data = {0}; + + ife_hwr_mgr_ctx = handler_priv; + evt_payload = payload; + core_idx = evt_payload->core_index; + + error_status = cam_ife_hw_mgr_get_err_type(ife_hwr_mgr_ctx, + evt_payload); + + if (atomic_read(&ife_hwr_mgr_ctx->overflow_pending)) + return error_status; + + switch (error_status) { + case CAM_ISP_HW_ERROR_OVERFLOW: + case CAM_ISP_HW_ERROR_P2I_ERROR: + case CAM_ISP_HW_ERROR_VIOLATION: + CAM_ERR(CAM_ISP, "Enter: error_type (%d)", error_status); + + error_event_data.error_type = + CAM_ISP_HW_ERROR_OVERFLOW; + + cam_ife_hw_mgr_process_overflow(ife_hwr_mgr_ctx, + &error_event_data, + core_idx, + &recovery_data); + + /* Trigger for recovery */ + recovery_data.error_type = CAM_ISP_HW_ERROR_OVERFLOW; + cam_ife_hw_mgr_do_error_recovery(&recovery_data); + break; + default: + CAM_DBG(CAM_ISP, "None error (%d)", error_status); + } + + return 0; +} + +/* + * DUAL VFE is valid for PIX processing path + * This function assumes hw_res[0] is master in case + * of dual VFE. + * RDI path does not support DUAl VFE + */ +static int cam_ife_hw_mgr_handle_reg_update( + void *handler_priv, + void *payload) +{ + struct cam_isp_resource_node *hw_res; + struct cam_ife_hw_mgr_ctx *ife_hwr_mgr_ctx; + struct cam_vfe_top_irq_evt_payload *evt_payload; + struct cam_ife_hw_mgr_res *ife_src_res = NULL; + cam_hw_event_cb_func ife_hwr_irq_rup_cb; + struct cam_isp_hw_reg_update_event_data rup_event_data; + uint32_t core_idx; + uint32_t rup_status = -EINVAL; + + CAM_DBG(CAM_ISP, "Enter"); + + ife_hwr_mgr_ctx = handler_priv; + evt_payload = payload; + + if (!handler_priv || !payload) { + CAM_ERR(CAM_ISP, "Invalid Parameter"); + return -EPERM; + } + + core_idx = evt_payload->core_index; + ife_hwr_irq_rup_cb = + ife_hwr_mgr_ctx->common.event_cb[CAM_ISP_HW_EVENT_REG_UPDATE]; + + evt_payload->evt_id = CAM_ISP_HW_EVENT_REG_UPDATE; + list_for_each_entry(ife_src_res, + &ife_hwr_mgr_ctx->res_list_ife_src, list) { + + if (ife_src_res->res_type == CAM_IFE_HW_MGR_RES_UNINIT) + continue; + + CAM_DBG(CAM_ISP, "resource id = %d, curr_core_idx = %d", + ife_src_res->res_id, core_idx); + switch (ife_src_res->res_id) { + case CAM_ISP_HW_VFE_IN_CAMIF: + if (ife_src_res->is_dual_vfe) + /* It checks for slave core RUP ACK*/ + hw_res = ife_src_res->hw_res[1]; + else + hw_res = ife_src_res->hw_res[0]; + + if (!hw_res) { + CAM_ERR(CAM_ISP, "CAMIF device is NULL"); + break; + } + CAM_DBG(CAM_ISP, + "current_core_id = %d , core_idx res = %d", + core_idx, hw_res->hw_intf->hw_idx); + + if (core_idx == hw_res->hw_intf->hw_idx) { + rup_status = hw_res->bottom_half_handler( + hw_res, evt_payload); + } + + if (ife_src_res->is_dual_vfe) { + hw_res = ife_src_res->hw_res[0]; + if (core_idx == hw_res->hw_intf->hw_idx) { + hw_res->bottom_half_handler( + hw_res, evt_payload); + } + } + + if (atomic_read(&ife_hwr_mgr_ctx->overflow_pending)) + break; + + if (!rup_status) { + ife_hwr_irq_rup_cb( + ife_hwr_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: + hw_res = ife_src_res->hw_res[0]; + + if (!hw_res) { + CAM_ERR(CAM_ISP, "RDI Device is NULL"); + break; + } + + if (core_idx == hw_res->hw_intf->hw_idx) + rup_status = hw_res->bottom_half_handler( + hw_res, evt_payload); + + if (!ife_hwr_mgr_ctx->is_rdi_only_context) + continue; + + if (atomic_read(&ife_hwr_mgr_ctx->overflow_pending)) + break; + if (!rup_status) { + /* Send the Reg update hw event */ + ife_hwr_irq_rup_cb( + ife_hwr_mgr_ctx->common.cb_priv, + CAM_ISP_HW_EVENT_REG_UPDATE, + &rup_event_data); + } + break; + default: + CAM_ERR(CAM_ISP, "Invalid resource id (%d)", + ife_src_res->res_id); + } + + } + + if (!rup_status) + CAM_DBG(CAM_ISP, "Exit rup_status = %d", rup_status); + + 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 core_idx0, + uint32_t core_idx1, + uint32_t hw_event_type) +{ + int32_t rc = -1; + uint32_t *event_cnt = NULL; + + 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 cound not generate hw event %d", + hw_event_type); + 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_epoch_for_camif_hw_res( + void *handler_priv, + void *payload) +{ + int32_t rc = -EINVAL; + struct cam_isp_resource_node *hw_res_l; + struct cam_isp_resource_node *hw_res_r; + struct cam_ife_hw_mgr_ctx *ife_hwr_mgr_ctx; + struct cam_vfe_top_irq_evt_payload *evt_payload; + struct cam_ife_hw_mgr_res *isp_ife_camif_res = NULL; + cam_hw_event_cb_func ife_hwr_irq_epoch_cb; + struct cam_isp_hw_epoch_event_data epoch_done_event_data; + uint32_t core_idx; + uint32_t epoch_status = -EINVAL; + uint32_t core_index0; + uint32_t core_index1; + + CAM_DBG(CAM_ISP, "Enter"); + + ife_hwr_mgr_ctx = handler_priv; + evt_payload = payload; + ife_hwr_irq_epoch_cb = + ife_hwr_mgr_ctx->common.event_cb[CAM_ISP_HW_EVENT_EPOCH]; + core_idx = evt_payload->core_index; + + evt_payload->evt_id = CAM_ISP_HW_EVENT_EPOCH; + + list_for_each_entry(isp_ife_camif_res, + &ife_hwr_mgr_ctx->res_list_ife_src, list) { + if ((isp_ife_camif_res->res_type == CAM_IFE_HW_MGR_RES_UNINIT) + || (isp_ife_camif_res->res_id != + CAM_ISP_HW_VFE_IN_CAMIF)) + continue; + + hw_res_l = isp_ife_camif_res->hw_res[0]; + hw_res_r = isp_ife_camif_res->hw_res[1]; + + switch (isp_ife_camif_res->is_dual_vfe) { + /* Handling Single VFE Scenario */ + case 0: + /* EPOCH check for Left side VFE */ + if (!hw_res_l) { + CAM_ERR(CAM_ISP, "Left Device is NULL"); + break; + } + + if (core_idx == hw_res_l->hw_intf->hw_idx) { + epoch_status = hw_res_l->bottom_half_handler( + hw_res_l, evt_payload); + if (atomic_read( + &ife_hwr_mgr_ctx->overflow_pending)) + break; + if (!epoch_status) + ife_hwr_irq_epoch_cb( + ife_hwr_mgr_ctx->common.cb_priv, + CAM_ISP_HW_EVENT_EPOCH, + &epoch_done_event_data); + } + + break; + + /* Handling Dual VFE Scenario */ + case 1: + /* SOF check for Left side VFE (Master)*/ + + if ((!hw_res_l) || (!hw_res_r)) { + CAM_ERR(CAM_ISP, "Dual VFE Device is NULL"); + break; + } + if (core_idx == hw_res_l->hw_intf->hw_idx) { + epoch_status = hw_res_l->bottom_half_handler( + hw_res_l, evt_payload); + + if (!epoch_status) + ife_hwr_mgr_ctx->epoch_cnt[core_idx]++; + else + break; + } + + /* SOF check for Right side VFE */ + if (core_idx == hw_res_r->hw_intf->hw_idx) { + epoch_status = hw_res_r->bottom_half_handler( + hw_res_r, evt_payload); + + if (!epoch_status) + ife_hwr_mgr_ctx->epoch_cnt[core_idx]++; + else + break; + } + + core_index0 = hw_res_l->hw_intf->hw_idx; + core_index1 = hw_res_r->hw_intf->hw_idx; + + rc = cam_ife_hw_mgr_check_irq_for_dual_vfe( + ife_hwr_mgr_ctx, + core_index0, + core_index1, + evt_payload->evt_id); + + if (atomic_read(&ife_hwr_mgr_ctx->overflow_pending)) + break; + if (!rc) + ife_hwr_irq_epoch_cb( + ife_hwr_mgr_ctx->common.cb_priv, + CAM_ISP_HW_EVENT_EPOCH, + &epoch_done_event_data); + + break; + + /* Error */ + default: + CAM_ERR(CAM_ISP, "error with hw_res"); + + } + } + + if (!epoch_status) + CAM_DBG(CAM_ISP, "Exit epoch_status = %d", epoch_status); + + return 0; +} + +static int cam_ife_hw_mgr_process_camif_sof( + struct cam_ife_hw_mgr_res *isp_ife_camif_res, + struct cam_ife_hw_mgr_ctx *ife_hwr_mgr_ctx, + struct cam_vfe_top_irq_evt_payload *evt_payload) +{ + struct cam_isp_resource_node *hw_res_l = NULL; + struct cam_isp_resource_node *hw_res_r = NULL; + int32_t rc = -EINVAL; + uint32_t core_idx; + uint32_t sof_status = 0; + uint32_t core_index0; + uint32_t core_index1; + + CAM_DBG(CAM_ISP, "Enter"); + core_idx = evt_payload->core_index; + hw_res_l = isp_ife_camif_res->hw_res[0]; + hw_res_r = isp_ife_camif_res->hw_res[1]; + CAM_DBG(CAM_ISP, "is_dual_vfe ? = %d", + isp_ife_camif_res->is_dual_vfe); + + switch (isp_ife_camif_res->is_dual_vfe) { + /* Handling Single VFE Scenario */ + case 0: + /* SOF check for Left side VFE */ + if (!hw_res_l) { + CAM_ERR(CAM_ISP, "VFE Device is NULL"); + break; + } + CAM_DBG(CAM_ISP, "curr_core_idx = %d,core idx hw = %d", + core_idx, hw_res_l->hw_intf->hw_idx); + + if (core_idx == hw_res_l->hw_intf->hw_idx) { + sof_status = hw_res_l->bottom_half_handler(hw_res_l, + evt_payload); + if (atomic_read(&ife_hwr_mgr_ctx->overflow_pending)) + break; + if (!sof_status) + rc = 0; + } + + break; + + /* Handling Dual VFE Scenario */ + case 1: + /* SOF check for Left side VFE */ + + if (!hw_res_l) { + CAM_ERR(CAM_ISP, "VFE Device is NULL"); + break; + } + CAM_DBG(CAM_ISP, "curr_core_idx = %d, res hw idx= %d", + core_idx, + hw_res_l->hw_intf->hw_idx); + + if (core_idx == hw_res_l->hw_intf->hw_idx) { + sof_status = hw_res_l->bottom_half_handler( + hw_res_l, evt_payload); + if (!sof_status) + ife_hwr_mgr_ctx->sof_cnt[core_idx]++; + else + break; + } + + /* SOF check for Right side VFE */ + if (!hw_res_r) { + CAM_ERR(CAM_ISP, "VFE Device is NULL"); + break; + } + CAM_DBG(CAM_ISP, "curr_core_idx = %d, ews hw idx= %d", + core_idx, + hw_res_r->hw_intf->hw_idx); + if (core_idx == hw_res_r->hw_intf->hw_idx) { + sof_status = hw_res_r->bottom_half_handler(hw_res_r, + evt_payload); + if (!sof_status) + ife_hwr_mgr_ctx->sof_cnt[core_idx]++; + else + break; + } + + core_index0 = hw_res_l->hw_intf->hw_idx; + core_index1 = hw_res_r->hw_intf->hw_idx; + + if (atomic_read(&ife_hwr_mgr_ctx->overflow_pending)) + break; + + rc = cam_ife_hw_mgr_check_irq_for_dual_vfe(ife_hwr_mgr_ctx, + core_index0, core_index1, evt_payload->evt_id); + + break; + + default: + CAM_ERR(CAM_ISP, "error with hw_res"); + break; + } + + CAM_DBG(CAM_ISP, "Exit (sof_status = %d)", sof_status); + + return rc; +} + +static int cam_ife_hw_mgr_handle_sof( + void *handler_priv, + void *payload) +{ + struct cam_isp_resource_node *hw_res = NULL; + struct cam_ife_hw_mgr_ctx *ife_hw_mgr_ctx; + struct cam_vfe_top_irq_evt_payload *evt_payload; + struct cam_ife_hw_mgr_res *ife_src_res = NULL; + cam_hw_event_cb_func ife_hw_irq_sof_cb; + struct cam_isp_hw_sof_event_data sof_done_event_data; + uint32_t sof_status = 0; + bool sof_sent = false; + + CAM_DBG(CAM_ISP, "Enter"); + + ife_hw_mgr_ctx = handler_priv; + evt_payload = payload; + if (!evt_payload) { + CAM_ERR(CAM_ISP, "no payload"); + return IRQ_HANDLED; + } + ife_hw_irq_sof_cb = + ife_hw_mgr_ctx->common.event_cb[CAM_ISP_HW_EVENT_SOF]; + + evt_payload->evt_id = CAM_ISP_HW_EVENT_SOF; + + list_for_each_entry(ife_src_res, + &ife_hw_mgr_ctx->res_list_ife_src, list) { + + if (ife_src_res->res_type == CAM_IFE_HW_MGR_RES_UNINIT) + continue; + + switch (ife_src_res->res_id) { + 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: + hw_res = ife_src_res->hw_res[0]; + sof_status = hw_res->bottom_half_handler( + hw_res, evt_payload); + + /* check if it is rdi only context */ + if (ife_hw_mgr_ctx->is_rdi_only_context) { + if (!sof_status && !sof_sent) { + cam_ife_mgr_cmd_get_sof_timestamp( + ife_hw_mgr_ctx, + &sof_done_event_data.timestamp); + + ife_hw_irq_sof_cb( + ife_hw_mgr_ctx->common.cb_priv, + CAM_ISP_HW_EVENT_SOF, + &sof_done_event_data); + CAM_DBG(CAM_ISP, "sof_status = %d", + sof_status); + + sof_sent = true; + } + + } + break; + + case CAM_ISP_HW_VFE_IN_CAMIF: + sof_status = cam_ife_hw_mgr_process_camif_sof( + ife_src_res, ife_hw_mgr_ctx, evt_payload); + if (!sof_status && !sof_sent) { + cam_ife_mgr_cmd_get_sof_timestamp( + ife_hw_mgr_ctx, + &sof_done_event_data.timestamp); + + ife_hw_irq_sof_cb( + ife_hw_mgr_ctx->common.cb_priv, + CAM_ISP_HW_EVENT_SOF, + &sof_done_event_data); + CAM_DBG(CAM_ISP, "sof_status = %d", + sof_status); + + sof_sent = true; + } + break; + default: + CAM_ERR(CAM_ISP, "Invalid resource id :%d", + ife_src_res->res_id); + break; + } + } + + return 0; +} + +static int cam_ife_hw_mgr_handle_eof_for_camif_hw_res( + void *handler_priv, + void *payload) +{ + int32_t rc = -EINVAL; + struct cam_isp_resource_node *hw_res_l = NULL; + struct cam_isp_resource_node *hw_res_r = NULL; + struct cam_ife_hw_mgr_ctx *ife_hwr_mgr_ctx; + struct cam_vfe_top_irq_evt_payload *evt_payload; + struct cam_ife_hw_mgr_res *isp_ife_camif_res = NULL; + cam_hw_event_cb_func ife_hwr_irq_eof_cb; + struct cam_isp_hw_eof_event_data eof_done_event_data; + uint32_t core_idx; + uint32_t eof_status = 0; + uint32_t core_index0; + uint32_t core_index1; + + CAM_DBG(CAM_ISP, "Enter"); + + ife_hwr_mgr_ctx = handler_priv; + evt_payload = payload; + if (!evt_payload) { + pr_err("%s: no payload\n", __func__); + return IRQ_HANDLED; + } + core_idx = evt_payload->core_index; + ife_hwr_irq_eof_cb = + ife_hwr_mgr_ctx->common.event_cb[CAM_ISP_HW_EVENT_EOF]; + + evt_payload->evt_id = CAM_ISP_HW_EVENT_EOF; + + list_for_each_entry(isp_ife_camif_res, + &ife_hwr_mgr_ctx->res_list_ife_src, list) { + + if ((isp_ife_camif_res->res_type == + CAM_IFE_HW_MGR_RES_UNINIT) || + (isp_ife_camif_res->res_id != CAM_ISP_HW_VFE_IN_CAMIF)) + continue; + + hw_res_l = isp_ife_camif_res->hw_res[0]; + hw_res_r = isp_ife_camif_res->hw_res[1]; + + CAM_DBG(CAM_ISP, "is_dual_vfe ? = %d", + isp_ife_camif_res->is_dual_vfe); + switch (isp_ife_camif_res->is_dual_vfe) { + /* Handling Single VFE Scenario */ + case 0: + /* EOF check for Left side VFE */ + if (!hw_res_l) { + pr_err("%s: VFE Device is NULL\n", + __func__); + break; + } + CAM_DBG(CAM_ISP, "curr_core_idx = %d, core idx hw = %d", + core_idx, hw_res_l->hw_intf->hw_idx); + + if (core_idx == hw_res_l->hw_intf->hw_idx) { + eof_status = hw_res_l->bottom_half_handler( + hw_res_l, evt_payload); + if (atomic_read( + &ife_hwr_mgr_ctx->overflow_pending)) + break; + if (!eof_status) + ife_hwr_irq_eof_cb( + ife_hwr_mgr_ctx->common.cb_priv, + CAM_ISP_HW_EVENT_EOF, + &eof_done_event_data); + } + + break; + /* Handling dual VFE Scenario */ + case 1: + if ((!hw_res_l) || (!hw_res_r)) { + CAM_ERR(CAM_ISP, "Dual VFE Device is NULL"); + break; + } + if (core_idx == hw_res_l->hw_intf->hw_idx) { + eof_status = hw_res_l->bottom_half_handler( + hw_res_l, evt_payload); + + if (!eof_status) + ife_hwr_mgr_ctx->eof_cnt[core_idx]++; + else + break; + } + + /* EOF check for Right side VFE */ + if (core_idx == hw_res_r->hw_intf->hw_idx) { + eof_status = hw_res_r->bottom_half_handler( + hw_res_r, evt_payload); + + if (!eof_status) + ife_hwr_mgr_ctx->eof_cnt[core_idx]++; + else + break; + } + + core_index0 = hw_res_l->hw_intf->hw_idx; + core_index1 = hw_res_r->hw_intf->hw_idx; + + rc = cam_ife_hw_mgr_check_irq_for_dual_vfe( + ife_hwr_mgr_ctx, + core_index0, + core_index1, + evt_payload->evt_id); + + if (atomic_read(&ife_hwr_mgr_ctx->overflow_pending)) + break; + + if (!rc) + ife_hwr_irq_eof_cb( + ife_hwr_mgr_ctx->common.cb_priv, + CAM_ISP_HW_EVENT_EOF, + &eof_done_event_data); + + break; + + default: + CAM_ERR(CAM_ISP, "error with hw_res"); + } + } + + CAM_DBG(CAM_ISP, "Exit (eof_status = %d)", eof_status); + + return 0; +} + + +static int cam_ife_hw_mgr_handle_buf_done_for_hw_res( + void *handler_priv, + void *payload) + +{ + int32_t buf_done_status = 0; + int32_t i; + int32_t rc = 0; + cam_hw_event_cb_func ife_hwr_irq_wm_done_cb; + struct cam_isp_resource_node *hw_res_l = NULL; + struct cam_ife_hw_mgr_ctx *ife_hwr_mgr_ctx = NULL; + struct cam_vfe_bus_irq_evt_payload *evt_payload = payload; + struct cam_ife_hw_mgr_res *isp_ife_out_res = NULL; + struct cam_hw_event_recovery_data recovery_data; + struct cam_isp_hw_done_event_data buf_done_event_data = {0}; + struct cam_isp_hw_error_event_data error_event_data = {0}; + uint32_t error_resc_handle[CAM_IFE_HW_OUT_RES_MAX]; + uint32_t num_of_error_handles = 0; + + CAM_DBG(CAM_ISP, "Enter"); + + ife_hwr_mgr_ctx = evt_payload->ctx; + ife_hwr_irq_wm_done_cb = + ife_hwr_mgr_ctx->common.event_cb[CAM_ISP_HW_EVENT_DONE]; + + evt_payload->evt_id = CAM_ISP_HW_EVENT_DONE; + + for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) { + isp_ife_out_res = &ife_hwr_mgr_ctx->res_list_ife_out[i]; + + if (isp_ife_out_res->res_type == CAM_IFE_HW_MGR_RES_UNINIT) + continue; + + hw_res_l = isp_ife_out_res->hw_res[0]; + + /* + * DUAL VFE: Index 0 is always a master. In case of composite + * Error, if the error is not in master, it needs to be checked + * in slave (for debuging purpose only) For other cases: + * Index zero is valid + */ + + if (hw_res_l && (evt_payload->core_index == + hw_res_l->hw_intf->hw_idx)) + buf_done_status = hw_res_l->bottom_half_handler( + hw_res_l, evt_payload); + else + continue; + + switch (buf_done_status) { + case CAM_VFE_IRQ_STATUS_ERR_COMP: + /* + * Write interface can pipeline upto 2 buffer done + * strobes from each write client. If any of the client + * triggers a third buffer done strobe before a + * composite interrupt based on the first buffer doneis + * triggered an error irq is set. This scenario can + * only happen if a client is 3 frames ahead of the + * other clients enabled in the same composite mask. + */ + case CAM_VFE_IRQ_STATUS_COMP_OWRT: + /* + * It is an indication that bandwidth is not sufficient + * to generate composite done irq within the VBI time. + */ + + error_resc_handle[num_of_error_handles++] = + isp_ife_out_res->res_id; + + if (num_of_error_handles > 0) { + error_event_data.error_type = + CAM_ISP_HW_ERROR_BUSIF_OVERFLOW; + goto err; + } + + break; + case CAM_VFE_IRQ_STATUS_ERR: + break; + case CAM_VFE_IRQ_STATUS_SUCCESS: + buf_done_event_data.num_handles = 1; + buf_done_event_data.resource_handle[0] = + isp_ife_out_res->res_id; + + if (atomic_read(&ife_hwr_mgr_ctx->overflow_pending)) + break; + /* Report for Successful buf_done event if any */ + 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_hwr_mgr_ctx->common.cb_priv, + CAM_ISP_HW_EVENT_DONE, + &buf_done_event_data); + } + + break; + default: + /* Do NOTHING */ + error_resc_handle[num_of_error_handles++] = + isp_ife_out_res->res_id; + if (num_of_error_handles > 0) { + error_event_data.error_type = + CAM_ISP_HW_ERROR_BUSIF_OVERFLOW; + goto err; + } + break; + } + if (!buf_done_status) + CAM_DBG(CAM_ISP, + "buf_done status:(%d),out_res->res_id: 0x%x", + buf_done_status, isp_ife_out_res->res_id); + } + + return rc; + +err: + /* + * Report for error if any. + * For the first phase, Error is reported as overflow, for all + * the affected context and any successful buf_done event is not + * reported. + */ + rc = cam_ife_hw_mgr_process_overflow(ife_hwr_mgr_ctx, + &error_event_data, evt_payload->core_index, + &recovery_data); + + /* + * We can temporarily return from here as + * for the first phase, we are going to reset entire HW. + */ + + CAM_DBG(CAM_ISP, "Exit buf_done_status Error = %d", + buf_done_status); + return rc; +} + +int cam_ife_mgr_do_tasklet_buf_done(void *handler_priv, + void *evt_payload_priv) +{ + struct cam_ife_hw_mgr_ctx *ife_hwr_mgr_ctx = handler_priv; + struct cam_vfe_bus_irq_evt_payload *evt_payload; + int rc = -EINVAL; + + if (!handler_priv) + return rc; + + evt_payload = evt_payload_priv; + ife_hwr_mgr_ctx = (struct cam_ife_hw_mgr_ctx *)evt_payload->ctx; + + 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]); + /* WM Done */ + return cam_ife_hw_mgr_handle_buf_done_for_hw_res(ife_hwr_mgr_ctx, + evt_payload_priv); +} + +int cam_ife_mgr_do_tasklet(void *handler_priv, void *evt_payload_priv) +{ + struct cam_ife_hw_mgr_ctx *ife_hwr_mgr_ctx = handler_priv; + struct cam_vfe_top_irq_evt_payload *evt_payload; + int rc = -EINVAL; + + if (!evt_payload_priv) + return rc; + + evt_payload = evt_payload_priv; + if (!handler_priv) + return rc; + + ife_hwr_mgr_ctx = (struct cam_ife_hw_mgr_ctx *)handler_priv; + + CAM_DBG(CAM_ISP, "addr of evt_payload = %pK core_index:%d", + (void *)evt_payload, + evt_payload->core_index); + CAM_DBG(CAM_ISP, "irq_status_0: = %x", evt_payload->irq_reg_val[0]); + CAM_DBG(CAM_ISP, "irq_status_1: = %x", evt_payload->irq_reg_val[1]); + CAM_DBG(CAM_ISP, "Violation register: = %x", + evt_payload->irq_reg_val[2]); + + /* + * If overflow/overwrite/error/violation are pending + * for this context it needs to be handled remaining + * interrupts are ignored. + */ + if (g_ife_hw_mgr.debug_cfg.enable_recovery) { + CAM_DBG(CAM_ISP, "IFE Mgr recovery is enabled"); + rc = cam_ife_hw_mgr_handle_camif_error(ife_hwr_mgr_ctx, + evt_payload_priv); + } else { + CAM_DBG(CAM_ISP, "recovery is not enabled"); + rc = 0; + } + + if (rc) { + CAM_ERR(CAM_ISP, "Encountered Error (%d), ignoring other irqs", + rc); + goto put_payload; + } + + CAM_DBG(CAM_ISP, "Calling EOF"); + cam_ife_hw_mgr_handle_eof_for_camif_hw_res(ife_hwr_mgr_ctx, + evt_payload_priv); + + CAM_DBG(CAM_ISP, "Calling SOF"); + /* SOF IRQ */ + cam_ife_hw_mgr_handle_sof(ife_hwr_mgr_ctx, + evt_payload_priv); + + CAM_DBG(CAM_ISP, "Calling RUP"); + /* REG UPDATE */ + cam_ife_hw_mgr_handle_reg_update(ife_hwr_mgr_ctx, + evt_payload_priv); + + CAM_DBG(CAM_ISP, "Calling EPOCH"); + /* EPOCH IRQ */ + cam_ife_hw_mgr_handle_epoch_for_camif_hw_res(ife_hwr_mgr_ctx, + evt_payload_priv); + +put_payload: + cam_vfe_put_evt_payload(evt_payload->core_info, &evt_payload); + return IRQ_HANDLED; +} + +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_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; + } + 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 rc = -EFAULT; + int i, j; + struct cam_iommu_handle cdm_handles; + + 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_ops(g_ife_hw_mgr.mgr_common.img_iommu_hdl, + CAM_SMMU_ATTACH)) { + CAM_ERR(CAM_ISP, "Attach iommu handle failed."); + goto attach_fail; + } + + 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); + for (j = 0; j < CAM_IFE_HW_OUT_RES_MAX; j++) { + INIT_LIST_HEAD(&g_ife_hw_mgr.ctx_pool[i]. + res_list_ife_out[j].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); + 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; + 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; + + 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_ops(g_ife_hw_mgr.mgr_common.img_iommu_hdl, + CAM_SMMU_DETACH); +attach_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/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h new file mode 100644 index 000000000000..0e678b4584cd --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h @@ -0,0 +1,230 @@ +/* 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_IFE_HW_MGR_H_ +#define _CAM_IFE_HW_MGR_H_ + +#include +#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_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. + * + */ +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; +}; + + +/** + * 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 + * + */ +struct cam_ife_hw_mgr_debug { + struct dentry *dentry; + uint64_t csid_debug; + uint32_t enable_recovery; +}; + +/** + * 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_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 + * @is_rdi_only_context flag to specify the context has only rdi resource + * @config_done_complete indicator for configuration complete + */ +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 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; + uint32_t is_rdi_only_context; + struct completion config_done_complete; +}; + +/** + * 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 + * + */ +int cam_ife_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf); + +/** + * cam_ife_mgr_do_tasklet_buf_done() + * + * @brief: Main tasklet handle function for the buf done event + * + * @handler_priv: Tasklet information handle + * @evt_payload_priv: Event payload for the handler funciton + * + */ +int cam_ife_mgr_do_tasklet_buf_done(void *handler_priv, void *evt_payload_priv); + +/** + * cam_ife_mgr_do_tasklet() + * + * @brief: Main tasklet handle function for mux resource events + * + * @handler_priv: Tasklet information handle + * @evt_payload_priv: Event payload for the handler funciton + * + */ +int cam_ife_mgr_do_tasklet(void *handler_priv, void *evt_payload_priv); + +#endif /* _CAM_IFE_HW_MGR_H_ */ diff --git a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/cam_isp_hw_mgr.c b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/cam_isp_hw_mgr.c new file mode 100644 index 000000000000..2f18895c2402 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/cam_isp_hw_mgr.c @@ -0,0 +1,36 @@ +/* Copyright (c) 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. + */ + +#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 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); + else { + CAM_ERR(CAM_ISP, "Invalid ISP hw type"); + rc = -EINVAL; + } + + return rc; +} + diff --git a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/cam_isp_hw_mgr.h b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/cam_isp_hw_mgr.h new file mode 100644 index 000000000000..2810dbd54035 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/cam_isp_hw_mgr.h @@ -0,0 +1,74 @@ +/* Copyright (c) 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. + */ + +#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 4 + +/** + * 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/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/Makefile b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/Makefile new file mode 100644 index 000000000000..b88f793e0613 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/Makefile @@ -0,0 +1,12 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_utils +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_core +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_req_mgr +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/irq_controller +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_smmu/ + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_tasklet_util.o cam_isp_packet_parser.o +obj-$(CONFIG_SPECTRA_CAMERA) += irq_controller/ diff --git a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c new file mode 100644 index 000000000000..3606af9af117 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c @@ -0,0 +1,745 @@ +/* Copyright (c) 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. + */ + +#include +#include +#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; + + 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; + uint32_t *cpu_addr; + uint32_t i, j; + + CAM_DBG(CAM_UTIL, "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; + + cpu_addr += (cmd_desc->offset / 4); + dual_config = (struct cam_isp_dual_config *)cpu_addr; + + for (i = 0; i < dual_config->num_ports; i++) { + + if (i >= CAM_ISP_IFE_OUT_RES_MAX) { + CAM_ERR(CAM_UTIL, + "failed update for i:%d > size_isp_out:%d", + i, size_isp_out); + return -EINVAL; + } + + 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) + return rc; + } + } + + 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; + } + + 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; + 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.data = cmd_update_data; + + CAM_DBG(CAM_ISP, "cmd buffer 0x%pK, size %d", + cmd_update.cmd.cmd_buf_addr, + cmd_update.cmd.size); + 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; + + if (cmd_meta_data == + CAM_ISP_PACKET_META_DMI_LEFT) + hw_entry[num_ent].flags = 0x1; + + 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; + + if (cmd_meta_data == + CAM_ISP_PACKET_META_DMI_RIGHT) + hw_entry[num_ent].flags = 0x1; + 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; + + if (cmd_meta_data == CAM_ISP_PACKET_META_DMI_COMMON) + hw_entry[num_ent].flags = 0x1; + + 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; + } + 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; + } + 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; + } + num_ent = prepare->num_hw_update_entries; + } + 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, + uint32_t size_isp_out, + bool fill_fence) +{ + int rc = 0; + uint64_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; + 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; + + /* 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_ISP, "i %d resource_type:%d fence:%d", + i, io_cfg[i].resource_type, io_cfg[i].fence); + CAM_DBG(CAM_ISP, "format: %d", io_cfg[i].format); + CAM_DBG(CAM_ISP, "direction %d", + io_cfg[i].direction); + + 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); + if (fill_fence) { + if (num_out_buf < + prepare->max_out_map_entries) { + 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; + 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 (fill_fence) { + if (num_in_buf < prepare->max_in_map_entries) { + 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; + num_in_buf++; + } else { + CAM_ERR(CAM_ISP, "ln_in:%d imax_ln:%d", + num_in_buf, + prepare->max_in_map_entries); + return -EINVAL; + } + } + continue; + } 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; 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; + } + + if (io_addr[plane_id] >> 32) { + CAM_ERR(CAM_ISP, + "Invalid mapped address"); + rc = -EINVAL; + 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", + plane_id, io_addr[plane_id]); + } + 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; + } + } + + 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; + 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; + 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/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.c b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.c new file mode 100644 index 000000000000..949c08cb6d6d --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.c @@ -0,0 +1,329 @@ +/* Copyright (c) 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. + */ + +#include +#include +#include +#include +#include +#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 + * @bottom_half_handler: Function pointer for event handler in bottom + * half context + * + */ +struct cam_tasklet_queue_cmd { + struct list_head list; + void *payload; + 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; +}; + +/** + * cam_tasklet_get_cmd() + * + * @brief: Get free cmd from tasklet + * + * @tasklet: Tasklet Info structure to get cmd from + * @tasklet_cmd: Return tasklet_cmd pointer if successful + * + * @return: 0: Success + * Negative: Failure + */ +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; + + if (!atomic_read(&tasklet->tasklet_active)) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "Tasklet is not active!\n"); + 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!\n"); + 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; +} + +/** + * cam_tasklet_put_cmd() + * + * @brief: Put back cmd to free list + * + * @tasklet: Tasklet Info structure to put cmd into + * @tasklet_cmd: tasklet_cmd pointer that needs to be put back + * + * @return: Void + */ +int 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; + + spin_lock_irqsave(&tasklet->tasklet_lock, flags); + list_add_tail(&(tasklet_cmd)->list, + &tasklet->free_cmd_list); + spin_unlock_irqrestore(&tasklet->tasklet_lock, flags); + + return 0; +} + +/** + * 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."); + 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; +} + +int cam_tasklet_enqueue_cmd( + void *bottom_half, + void *bh_cmd, + void *evt_payload_priv, + CAM_IRQ_HANDLER_BOTTOM_HALF bottom_half_handler) +{ + unsigned long flags; + int rc = 0; + 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 -EINVAL; + } + + if (!bh_cmd) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "NULL bh cmd"); + return -EINVAL; + } + + CAM_DBG(CAM_ISP, "Enqueue tasklet cmd"); + tasklet_cmd->bottom_half_handler = bottom_half_handler; + tasklet_cmd->payload = evt_payload_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_schedule(&tasklet->tasklet); + + return rc; +} + +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; + + 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_info->ctx_priv, + tasklet_cmd->payload); + cam_tasklet_put_cmd(tasklet_info, (void**)(&tasklet_cmd)); + } +} + diff --git a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/include/cam_isp_packet_parser.h b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/include/cam_isp_packet_parser.h new file mode 100644 index 000000000000..e3f2ce26e1c5 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/include/cam_isp_packet_parser.h @@ -0,0 +1,162 @@ +/* Copyright (c) 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. + */ + +#ifndef _CAM_ISP_HW_PARSER_H_ +#define _CAM_ISP_HW_PARSER_H_ + +#include +#include +#include "cam_isp_hw_mgr_intf.h" +#include "cam_ife_hw_mgr.h" +#include "cam_hw_intf.h" +#include "cam_packet_util.h" + +/* + * 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 + * @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, + 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/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/include/cam_tasklet_util.h b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/include/cam_tasklet_util.h new file mode 100644 index 000000000000..0829d98377f5 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/include/cam_tasklet_util.h @@ -0,0 +1,99 @@ +/* Copyright (c) 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. + */ + +#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 + * @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: 0: Success + * Negative: Failure + */ +int cam_tasklet_enqueue_cmd( + void *bottom_half, + void *bh_cmd, + void *evt_payload_priv, + CAM_IRQ_HANDLER_BOTTOM_HALF bottom_half_handler); + +int cam_tasklet_get_cmd(void *bottom_half,void **bh_cmd); + +int cam_tasklet_put_cmd(void *bottom_half,void **bh_cmd); + +#endif /* _CAM_TASKLET_UTIL_H_ */ diff --git a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/irq_controller/Makefile b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/irq_controller/Makefile new file mode 100644 index 000000000000..1c2f3d0efacd --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/irq_controller/Makefile @@ -0,0 +1,3 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_utils + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_irq_controller.o \ No newline at end of file diff --git a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c new file mode 100644 index 000000000000..ee61c1584b2b --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c @@ -0,0 +1,727 @@ +/* Copyright (c) 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. + */ + +#include +#include +#include +#include +#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 + */ +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]; +}; + +/** + * 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 + */ +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; +}; + +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) +{ + 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_ISP, "Invalid parameters"); + rc = -EINVAL; + return rc; + } + + controller = kzalloc(sizeof(struct cam_irq_controller), GFP_KERNEL); + if (!controller) { + CAM_DBG(CAM_ISP, "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_ISP, "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_ISP, "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_ISP, "Failed to allocate BH payload bit mask Arr"); + rc = -ENOMEM; + goto evt_mask_alloc_error; + } + + controller->name = name; + + CAM_DBG(CAM_ISP, "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_ISP, "i %d mask_reg_offset: 0x%x", i, + controller->irq_register_arr[i].mask_reg_offset); + CAM_DBG(CAM_ISP, "i %d clear_reg_offset: 0x%x", i, + controller->irq_register_arr[i].clear_reg_offset); + CAM_DBG(CAM_ISP, "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; + + CAM_DBG(CAM_ISP, "global_clear_bitmask: 0x%x", + controller->global_clear_bitmask); + CAM_DBG(CAM_ISP, "global_clear_offset: 0x%x", + controller->global_clear_offset); + CAM_DBG(CAM_ISP, "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_ISP, + "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_ISP, "Missing top half handler"); + return -EINVAL; + } + + if (bottom_half_handler && + (!bottom_half || !irq_bh_api)) { + CAM_ERR(CAM_ISP, + "Invalid params: bh_handler=%pK bh=%pK bh_enq_f=%pK", + bottom_half_handler, + bottom_half, + irq_bh_api); + return -EINVAL; + } + + if (priority >= CAM_IRQ_PRIORITY_MAX) { + CAM_ERR(CAM_ISP, "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_ISP, "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_ISP, "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]; + + 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; + 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_ISP, "enable item %d", handle); + found = 1; + rc = 0; + break; + } + } + + if (!found) { + if (need_lock) + spin_unlock_irqrestore(&controller->lock, flags); + return rc; + } + + for (i = 0; i < controller->num_registers; i++) { + controller->irq_register_arr[i]. + top_half_enable_mask[evt_handler->priority] |= + evt_handler->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_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; + 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_ISP, "disable item %d", handle); + found = 1; + rc = 0; + break; + } + } + + if (!found) { + if (need_lock) + spin_unlock_irqrestore(&controller->lock, flags); + return rc; + } + + for (i = 0; i < controller->num_registers; i++) { + controller->irq_register_arr[i]. + top_half_enable_mask[evt_handler->priority] &= + ~(evt_handler->evt_bit_mask_arr[i]); + + irq_mask = cam_io_r_mb(controller->mem_base + + controller->irq_register_arr[i]. + mask_reg_offset); + CAM_INFO(CAM_ISP, "irq_mask 0x%x before disable 0x%x", + controller->irq_register_arr[i].mask_reg_offset, + irq_mask); + 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); + CAM_INFO(CAM_ISP, "irq_mask 0x%x after disable 0x%x", + controller->irq_register_arr[i].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 + + 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); + } + 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; + 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_ISP, "unsubscribe item %d", handle); + list_del_init(&evt_handler->list_node); + list_del_init(&evt_handler->th_list_node); + found = 1; + rc = 0; + break; + } + } + + if (found) { + for (i = 0; i < controller->num_registers; i++) { + controller->irq_register_arr[i]. + top_half_enable_mask[evt_handler->priority] &= + ~(evt_handler->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_handler->evt_bit_mask_arr[i]); + + cam_io_w_mb(irq_mask, controller->mem_base + + controller->irq_register_arr[i]. + mask_reg_offset); + + /* Clear the IRQ bits of this handler */ + cam_io_w_mb(evt_handler->evt_bit_mask_arr[i], + 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); + } + + 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_ISP, "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_ISP, "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 (irq_bh_api->get_bh_payload_func) { + if (irq_bh_api->get_bh_payload_func( + evt_handler->bottom_half, &bh_cmd)) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "Can't get bh payload"); + 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) { + CAM_ERR(CAM_ISP, + "Top half handler failed with %d", rc); + if (irq_bh_api->put_bh_payload_func && bh_cmd) { + if (irq_bh_api->put_bh_payload_func( + evt_handler->bottom_half, + &bh_cmd)) { + CAM_ERR(CAM_ISP, + "Can't put bh payload"); + } + } + continue; + } + } + + if (!rc && evt_handler->bottom_half_handler) { + CAM_DBG(CAM_ISP, "Enqueuing bottom half for %s", + controller->name); + if (irq_bh_api->bottom_half_enqueue_func) { + irq_bh_api->bottom_half_enqueue_func( + evt_handler->bottom_half, + bh_cmd, + th_payload->evt_payload_priv, + evt_handler->bottom_half_handler); + } + } + } + + CAM_DBG(CAM_ISP, "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; + bool need_th_processing[CAM_IRQ_PRIORITY_MAX] = {false}; + int i; + int j; + + if (!controller) + return IRQ_NONE; + + CAM_DBG(CAM_ISP, "locking controller %pK name %s lock %pK", + controller, controller->name, &controller->lock); + spin_lock(&controller->lock); + for (i = 0; i < controller->num_registers; i++) { + controller->irq_status_arr[i] = cam_io_r_mb( + controller->mem_base + + controller->irq_register_arr[i].status_reg_offset); + cam_io_w_mb(controller->irq_status_arr[i], + controller->mem_base + + controller->irq_register_arr[i].clear_reg_offset); + CAM_DBG(CAM_ISP, "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 (controller->irq_register_arr[i]. + top_half_enable_mask[j] & + controller->irq_status_arr[i]) + need_th_processing[j] = true; + CAM_DBG(CAM_ISP, + "i %d j %d need_th_processing = %d", + i, j, need_th_processing[j]); + } + } + + CAM_DBG(CAM_ISP, "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_ISP, "Status Clear done"); + + for (i = 0; i < CAM_IRQ_PRIORITY_MAX; i++) { + if (need_th_processing[i]) { + CAM_DBG(CAM_ISP, "Invoke TH processing"); + cam_irq_controller_th_processing(controller, + &controller->th_list_head[i]); + } + } + spin_unlock(&controller->lock); + CAM_DBG(CAM_ISP, "unlocked controller %pK name %s lock %pK", + controller, controller->name, &controller->lock); + + return IRQ_HANDLED; +} diff --git a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.h b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.h new file mode 100644 index 000000000000..93fe07ad4593 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.h @@ -0,0 +1,278 @@ +/* Copyright (c) 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. + */ + +#ifndef _CAM_IRQ_CONTROLLER_H_ +#define _CAM_IRQ_CONTROLLER_H_ + +#include + +#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 int (*CAM_IRQ_BOTTOM_HALF_ENQUEUE_FUNC)(void *bh_cmd, + void *handler_priv, void *evt_payload_priv, + CAM_IRQ_HANDLER_BOTTOM_HALF); +typedef int (*CAM_IRQ_GET_TASKLET_PAYLOAD_FUNC)(void *bh, + void **bh_cmd); + +typedef int (*CAM_IRQ_PUT_TASKLET_PAYLOAD_FUNC)(void *bh, + 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 + * + * @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); + +/* + * 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/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h new file mode 100644 index 000000000000..2601190d0f41 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h @@ -0,0 +1,213 @@ +/* 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 _CAM_ISP_HW_MGR_INTF_H_ +#define _CAM_ISP_HW_MGR_INTF_H_ + +#include +#include +#include +#include +#include "cam_hw_mgr_intf.h" + +/* MAX IFE instance */ +#define CAM_IFE_HW_NUM_MAX 4 +#define CAM_IFE_RDI_NUM_MAX 4 + +/** + * 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_hw_method - hardware stop method + * + * @hw_stop_cmd: Hardware stop command type information + * + */ +struct cam_isp_stop_hw_method { + enum cam_isp_hw_stop_cmd hw_stop_cmd; +}; + +/** + * 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 + * + * @packet_opcode_type: Packet header opcode in the packet header + * this opcode defines, packet is init packet or + * update packet + * @bw_config: BW config information + * @bw_config_valid: Flag indicating whether the bw_config at the index + * is valid or not + * + */ +struct cam_isp_prepare_hw_update_data { + uint32_t packet_opcode_type; + struct cam_isp_bw_config_internal bw_config[CAM_IFE_HW_NUM_MAX]; + bool bw_config_valid[CAM_IFE_HW_NUM_MAX]; +}; + + +/** + * struct cam_isp_hw_sof_event_data - Event payload for CAM_HW_EVENT_SOF + * + * @timestamp: Time stamp for the sof event + * + */ +struct cam_isp_hw_sof_event_data { + uint64_t timestamp; +}; + +/** + * 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 + * + */ +struct cam_isp_hw_error_event_data { + uint32_t error_type; + uint64_t timestamp; +}; + +/* 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_MAX, +}; + +/** + * struct cam_isp_hw_cmd_args - Payload for hw manager command + * + * @ctxt_to_hw_map: HW context from the acquire + * @cmd_type HW command type + * @get_context Get context type information + */ +struct cam_isp_hw_cmd_args { + void *ctxt_to_hw_map; + uint32_t cmd_type; + union { + uint32_t is_rdi_only_context; + } 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 + * + */ +int cam_isp_hw_mgr_init(struct device_node *of_node, + struct cam_hw_mgr_intf *hw_mgr); + +#endif /* __CAM_ISP_HW_MGR_INTF_H__ */ diff --git a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/Makefile b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/Makefile new file mode 100644 index 000000000000..4bf4a0e976e1 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_SPECTRA_CAMERA) += ife_csid_hw/ +obj-$(CONFIG_SPECTRA_CAMERA) += vfe_hw/ diff --git a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/Makefile b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/Makefile new file mode 100644 index 000000000000..9f20c3cbeb4b --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/Makefile @@ -0,0 +1,12 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_utils +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_core +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_cpas/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/irq_controller +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_smmu/ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/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_csid170.o cam_ife_csid_lite170.o diff --git a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170.c b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170.c new file mode 100644 index 000000000000..bdd59d232f70 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170.c @@ -0,0 +1,60 @@ +/* Copyright (c) 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. + */ + + +#include +#include "cam_ife_csid_core.h" +#include "cam_ife_csid170.h" +#include "cam_ife_csid_dev.h" + +#define CAM_CSID_DRV_NAME "csid_170" +#define CAM_CSID_VERSION_V170 0x10070000 + +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 const struct of_device_id cam_ife_csid170_dt_match[] = { + { + .compatible = "qcom,csid170", + .data = &cam_ife_csid170_hw_info, + }, + {} +}; + +MODULE_DEVICE_TABLE(of, cam_ife_csid170_dt_match); + +static struct platform_driver cam_ife_csid170_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_csid170_dt_match, + }, +}; + +static int __init cam_ife_csid170_init_module(void) +{ + return platform_driver_register(&cam_ife_csid170_driver); +} + +static void __exit cam_ife_csid170_exit_module(void) +{ + platform_driver_unregister(&cam_ife_csid170_driver); +} + +module_init(cam_ife_csid170_init_module); +module_exit(cam_ife_csid170_exit_module); +MODULE_DESCRIPTION("CAM IFE_CSID170 driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170.h b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170.h new file mode 100644 index 000000000000..c68ddf7343fc --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid170.h @@ -0,0 +1,304 @@ +/* Copyright (c) 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. + */ + +#ifndef _CAM_IFE_CSID_170_H_ +#define _CAM_IFE_CSID_170_H_ + +#include "cam_ife_csid_core.h" + +static struct cam_ife_csid_ipp_reg_offset cam_ife_csid_170_ipp_reg_offset = { + .csid_ipp_irq_status_addr = 0x30, + .csid_ipp_irq_mask_addr = 0x34, + .csid_ipp_irq_clear_addr = 0x38, + .csid_ipp_irq_set_addr = 0x3c, + + .csid_ipp_cfg0_addr = 0x200, + .csid_ipp_cfg1_addr = 0x204, + .csid_ipp_ctrl_addr = 0x208, + .csid_ipp_frm_drop_pattern_addr = 0x20c, + .csid_ipp_frm_drop_period_addr = 0x210, + .csid_ipp_irq_subsample_pattern_addr = 0x214, + .csid_ipp_irq_subsample_period_addr = 0x218, + .csid_ipp_hcrop_addr = 0x21c, + .csid_ipp_vcrop_addr = 0x220, + .csid_ipp_pix_drop_pattern_addr = 0x224, + .csid_ipp_pix_drop_period_addr = 0x228, + .csid_ipp_line_drop_pattern_addr = 0x22c, + .csid_ipp_line_drop_period_addr = 0x230, + .csid_ipp_rst_strobes_addr = 0x240, + .csid_ipp_status_addr = 0x254, + .csid_ipp_misr_val_addr = 0x258, + .csid_ipp_format_measure_cfg0_addr = 0x270, + .csid_ipp_format_measure_cfg1_addr = 0x274, + .csid_ipp_format_measure0_addr = 0x278, + .csid_ipp_format_measure1_addr = 0x27c, + .csid_ipp_format_measure2_addr = 0x280, + .csid_ipp_timestamp_curr0_sof_addr = 0x290, + .csid_ipp_timestamp_curr1_sof_addr = 0x294, + .csid_ipp_timestamp_perv0_sof_addr = 0x298, + .csid_ipp_timestamp_perv1_sof_addr = 0x29c, + .csid_ipp_timestamp_curr0_eof_addr = 0x2a0, + .csid_ipp_timestamp_curr1_eof_addr = 0x2a4, + .csid_ipp_timestamp_perv0_eof_addr = 0x2a8, + .csid_ipp_timestamp_perv1_eof_addr = 0x2ac, + /* configurations */ + .pix_store_en_shift_val = 7, +}; + +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, +}; + +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, + .no_rdis = 3, + .no_pix = 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, +}; + +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, + .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/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c new file mode 100644 index 000000000000..aba250dffa88 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -0,0 +1,2988 @@ +/* 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. + */ + +#include +#include +#include +#include + +#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" + +/* 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 100000 + +/* + * 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 + +static int cam_ife_csid_is_ipp_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: + 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) +{ + int rc = 0; + + switch (in_format) { + case CAM_FORMAT_MIPI_RAW_6: + switch (out_format) { + case CAM_FORMAT_MIPI_RAW_6: + *decode_fmt = 0xf; + 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; + 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; + 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; + 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; + 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; + 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; + 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; + 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( + 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; + 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_csid_cid_get(struct cam_ife_csid_hw *csid_hw, + struct cam_isp_resource_node **res, int32_t vc, uint32_t dt, + uint32_t res_type) +{ + int rc = 0; + struct cam_ife_csid_cid_data *cid_data; + uint32_t i = 0, j = 0; + + for (i = 0; i < CAM_IFE_CSID_CID_RES_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 (res_type == CAM_ISP_IFE_IN_RES_TPG) { + if (cid_data->tpg_set) { + cid_data->cnt++; + *res = &csid_hw->cid_res[i]; + break; + } + } else { + if (cid_data->vc == vc && cid_data->dt == dt) { + cid_data->cnt++; + *res = &csid_hw->cid_res[i]; + break; + } + } + } + } + + if (i == CAM_IFE_CSID_CID_RES_MAX) { + if (res_type == CAM_ISP_IFE_IN_RES_TPG) { + CAM_ERR(CAM_ISP, "CSID:%d TPG CID not available", + csid_hw->hw_intf->hw_idx); + rc = -EINVAL; + } + + for (j = 0; j < CAM_IFE_CSID_CID_RES_MAX; j++) { + if (csid_hw->cid_res[j].res_state == + CAM_ISP_RESOURCE_STATE_AVAILABLE) { + cid_data = (struct cam_ife_csid_cid_data *) + csid_hw->cid_res[j].res_priv; + cid_data->vc = vc; + cid_data->dt = dt; + cid_data->cnt = 1; + csid_hw->cid_res[j].res_state = + CAM_ISP_RESOURCE_STATE_RESERVED; + *res = &csid_hw->cid_res[j]; + CAM_DBG(CAM_ISP, "CSID:%d CID %d allocated", + csid_hw->hw_intf->hw_idx, + csid_hw->cid_res[j].res_id); + break; + } + } + + if (j == CAM_IFE_CSID_CID_RES_MAX) { + CAM_ERR(CAM_ISP, "CSID:%d Free cid is not available", + csid_hw->hw_intf->hw_idx); + rc = -EINVAL; + } + } + + return rc; +} + + +static int cam_ife_csid_global_reset(struct cam_ife_csid_hw *csid_hw) +{ + struct cam_hw_soc_info *soc_info; + struct cam_ife_csid_reg_offset *csid_reg; + int rc = 0; + uint32_t val = 0, i; + + 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); + + init_completion(&csid_hw->csid_top_complete); + + /* 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->no_pix) + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_ipp_irq_mask_addr); + + for (i = 0; i < csid_reg->cmn_reg->no_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->no_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_ipp_irq_clear_addr); + + for (i = 0 ; i < csid_reg->cmn_reg->no_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); + + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_irq_cmd_addr); + + 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->no_pix) + cam_io_w_mb(0x1, soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_ipp_cfg0_addr); + + for (i = 0; i < csid_reg->cmn_reg->no_rdis; i++) + cam_io_w_mb(0x2, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[i]->csid_rdi_cfg0_addr); + + /* perform the top CSID HW reset */ + cam_io_w_mb(csid_reg->cmn_reg->csid_rst_stb, + soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_rst_strobes_addr); + + CAM_DBG(CAM_ISP, " Waiting for reset complete from irq handler"); + rc = wait_for_completion_timeout(&csid_hw->csid_top_complete, + msecs_to_jiffies(IFE_CSID_TIMEOUT)); + if (rc <= 0) { + CAM_ERR(CAM_ISP, "CSID:%d reset completion in fail rc = %d", + csid_hw->hw_intf->hw_idx, rc); + if (rc == 0) + rc = -ETIMEDOUT; + } else { + rc = 0; + } + + 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); + + 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; + 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_ipp_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_ipp_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_ipp_irq_mask_addr); + + } else { + 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); + } + + init_completion(complete); + reset_strb_val = csid_reg->cmn_reg->path_rst_stb_all; + + /* Enable the Test gen before reset */ + cam_io_w_mb(1, csid_hw->hw_info->soc_info.reg_map[0].mem_base + + csid_reg->tpg_reg->csid_tpg_ctrl_addr); + + /* 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; + } + + /* Disable Test Gen after reset*/ + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->tpg_reg->csid_tpg_ctrl_addr); + +end: + return rc; + +} + +static 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; + struct cam_ife_csid_cid_data *cid_data; + + 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, + cid_reserv->in_port->vc); + + 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; + } + + /* CSID CSI2 v2.0 supports 31 vc */ + if (cid_reserv->in_port->dt > 0x3f || + cid_reserv->in_port->vc > 0x1f) { + CAM_ERR(CAM_ISP, "CSID:%d Invalid vc:%d dt %d", + csid_hw->hw_intf->hw_idx, + cid_reserv->in_port->vc, cid_reserv->in_port->dt); + 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 (cid_reserv->in_port->res_type == CAM_ISP_IFE_IN_RES_PHY_3 && + csid_hw->hw_intf->hw_idx != 2) { + rc = -EINVAL; + goto end; + } + + 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; + } + } + } + + if (!csid_hw->csi2_reserve_cnt) { + csid_hw->res_type = cid_reserv->in_port->res_type; + /* Take the first CID resource*/ + csid_hw->cid_res[0].res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + cid_data = (struct cam_ife_csid_cid_data *) + csid_hw->cid_res[0].res_priv; + + 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; + } + + cid_data->vc = cid_reserv->in_port->vc; + cid_data->dt = cid_reserv->in_port->dt; + cid_data->cnt = 1; + cid_reserv->node_res = &csid_hw->cid_res[0]; + csid_hw->csi2_reserve_cnt++; + + CAM_DBG(CAM_ISP, + "CSID:%d CID :%d resource acquired successfully", + csid_hw->hw_intf->hw_idx, + cid_reserv->node_res->res_id); + } else { + 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_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_DBG(CAM_ISP, + "CSID:%d RDI:%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->res_type); + /* if success then increment the reserve count */ + if (!rc) { + 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; + } else { + 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; +} + + +static int cam_ife_csid_path_reserve(struct cam_ife_csid_hw *csid_hw, + struct cam_csid_hw_reserve_resource_args *reserve) +{ + int rc = 0; + struct cam_ife_csid_path_cfg *path_data; + struct cam_isp_resource_node *res; + + /* CSID CSI2 v2.0 supports 31 vc */ + if (reserve->in_port->dt > 0x3f || reserve->in_port->vc > 0x1f || + (reserve->sync_mode >= CAM_ISP_HW_SYNC_MAX)) { + CAM_ERR(CAM_ISP, "CSID:%d Invalid vc:%d dt %d mode:%d", + csid_hw->hw_intf->hw_idx, + reserve->in_port->vc, reserve->in_port->dt, + reserve->sync_mode); + 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_DBG(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_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_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_DBG(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); + } + + 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->master_idx = reserve->master_idx; + 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; + 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; + path_data->vc = reserve->in_port->vc; + } + + if (reserve->sync_mode == CAM_ISP_HW_SYNC_MASTER) { + path_data->crop_enable = 1; + 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; + CAM_DBG(CAM_ISP, "CSID:%dmaster:startpixel 0x%x endpixel:0x%x", + csid_hw->hw_intf->hw_idx, path_data->start_pixel, + path_data->end_pixel); + CAM_DBG(CAM_ISP, "CSID:%dmaster:line start:0x%x line end:0x%x", + csid_hw->hw_intf->hw_idx, path_data->start_line, + path_data->end_line); + } else if (reserve->sync_mode == CAM_ISP_HW_SYNC_SLAVE) { + path_data->crop_enable = 1; + 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 slave:start:0x%x end:0x%x width 0x%x", + csid_hw->hw_intf->hw_idx, path_data->start_pixel, + path_data->end_pixel, path_data->width); + CAM_DBG(CAM_ISP, "CSID:%dmaster:line start:0x%x line end:0x%x", + csid_hw->hw_intf->hw_idx, path_data->start_line, + path_data->end_line); + } else { + path_data->crop_enable = 0; + path_data->width = reserve->in_port->left_width; + path_data->start_pixel = reserve->in_port->left_start; + } + + CAM_DBG(CAM_ISP, "Res %d width %d height %d", 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; + struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + uint32_t i, status, val; + + 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_ife_csid_enable_soc_resources(soc_info); + if (rc) { + CAM_ERR(CAM_ISP, "CSID:%d Enable SOC failed", + csid_hw->hw_intf->hw_idx); + goto err; + } + + + CAM_DBG(CAM_ISP, "CSID:%d enable top irq interrupt", + csid_hw->hw_intf->hw_idx); + + csid_hw->hw_info->hw_state = CAM_HW_STATE_POWER_UP; + /* Enable the top IRQ interrupt */ + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_mask_addr); + + rc = cam_ife_csid_global_reset(csid_hw); + if (rc) { + CAM_ERR(CAM_ISP, "CSID:%d csid_reset fail rc = %d", + csid_hw->hw_intf->hw_idx, rc); + rc = -ETIMEDOUT; + goto disable_soc; + } + + /* + * Reset the SW registers + * SW register reset also reset the mask irq, so poll the irq status + * to check the reset complete. + */ + CAM_DBG(CAM_ISP, "CSID:%d Reset Software registers", + csid_hw->hw_intf->hw_idx); + + cam_io_w_mb(csid_reg->cmn_reg->csid_rst_stb_sw_all, + soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_rst_strobes_addr); + + rc = readl_poll_timeout(soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_status_addr, + status, (status & 0x1) == 0x1, + CAM_IFE_CSID_TIMEOUT_SLEEP_US, CAM_IFE_CSID_TIMEOUT_ALL_US); + if (rc < 0) { + CAM_ERR(CAM_ISP, "software register reset timeout....."); + rc = -ETIMEDOUT; + goto disable_soc; + } + + /* 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->no_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_ipp_irq_clear_addr); + + for (i = 0; i < csid_reg->cmn_reg->no_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); + + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_irq_cmd_addr); + + /* Enable the top IRQ interrupt */ + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_mask_addr); + + 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); + + 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; + struct cam_ife_csid_reg_offset *csid_reg; + + /* 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); + + csid_hw->hw_info->hw_state = CAM_HW_STATE_POWER_DOWN; + 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; + + 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 */ + if (csid_hw->tpg_cfg.usage_type) { + rc = cam_ife_csid_enable_ife_force_clock_on(soc_info, + csid_hw->csid_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_hw->csid_info->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; + + 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; + + /* 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_hw->csid_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) +{ + 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; + 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 = (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 & 0x3) << 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) + 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 inerrupts */ + 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) +{ + 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); + 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 int cam_ife_csid_init_config_ipp_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; + struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + uint32_t decode_format = 0, plain_format = 0, 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 (!csid_reg->ipp_reg) { + CAM_ERR(CAM_ISP, "CSID:%d IPP:%d is not supported on HW", + csid_hw->hw_intf->hw_idx, + res->res_id); + return -EINVAL; + } + + CAM_DBG(CAM_ISP, "Config IPP Path"); + rc = cam_ife_csid_get_format_ipp(path_data->in_format, + &decode_format, &plain_format); + if (rc) + return rc; + + /* + * configure the IPP 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; + val |= (1 << csid_reg->ipp_reg->pix_store_en_shift_val); + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_ipp_cfg0_addr); + + /* 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->ipp_reg->csid_ipp_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->ipp_reg->csid_ipp_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->ipp_reg->csid_ipp_vcrop_addr); + CAM_DBG(CAM_ISP, "CSID:%d Vertical Crop config val: 0x%x", + csid_hw->hw_intf->hw_idx, val); + } + + /* set frame drop pattern to 0 and period to 1 */ + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_ipp_frm_drop_period_addr); + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_ipp_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 + + csid_reg->ipp_reg->csid_ipp_irq_subsample_period_addr); + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_ipp_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->ipp_reg->csid_ipp_pix_drop_pattern_addr); + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_ipp_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->ipp_reg->csid_ipp_line_drop_pattern_addr); + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_ipp_line_drop_period_addr); + + /*Set master or slave IPP */ + 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; + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_ipp_ctrl_addr); + + /* Enable the IPP path */ + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_ipp_cfg0_addr); + val |= (1 << csid_reg->cmn_reg->path_en_shift_val); + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_ipp_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_ipp_path( + struct cam_ife_csid_hw *csid_hw, + struct cam_isp_resource_node *res) +{ + int rc = 0; + 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 (res->res_state != CAM_ISP_RESOURCE_STATE_INIT_HW) { + CAM_ERR(CAM_ISP, + "CSID:%d Res type %d res_id:%d in wrong state %d", + csid_hw->hw_intf->hw_idx, + res->res_type, res->res_id, res->res_state); + rc = -EINVAL; + } + + if (!csid_reg->ipp_reg) { + CAM_ERR(CAM_ISP, "CSID:%d IPP %d is not supported on HW", + csid_hw->hw_intf->hw_idx, + res->res_id); + rc = -EINVAL; + } + + res->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + return rc; +} + +static int cam_ife_csid_enable_ipp_path( + struct cam_ife_csid_hw *csid_hw, + struct cam_isp_resource_node *res) +{ + struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + struct cam_ife_csid_path_cfg *path_data; + 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_state != CAM_ISP_RESOURCE_STATE_INIT_HW) { + CAM_ERR(CAM_ISP, + "CSID:%d res type:%d res_id:%d Invalid state%d", + csid_hw->hw_intf->hw_idx, + res->res_type, res->res_id, res->res_state); + return -EINVAL; + } + + if (!csid_reg->ipp_reg) { + CAM_ERR(CAM_ISP, "CSID:%d IPP %d not supported on HW", + csid_hw->hw_intf->hw_idx, + res->res_id); + return -EINVAL; + } + + CAM_DBG(CAM_ISP, "Enable IPP path"); + + /* Resume at frame boundary */ + if (path_data->sync_mode == CAM_ISP_HW_SYNC_MASTER) { + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_ipp_ctrl_addr); + val |= CAM_CSID_RESUME_AT_FRAME_BOUNDARY; + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_ipp_ctrl_addr); + } else if (path_data->sync_mode == CAM_ISP_HW_SYNC_NONE) { + cam_io_w_mb(CAM_CSID_RESUME_AT_FRAME_BOUNDARY, + soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_ipp_ctrl_addr); + } + /* for slave mode, not need to resume for slave device */ + + /* Enable the required ipp interrupts */ + val = CSID_PATH_INFO_RST_DONE | CSID_PATH_ERROR_FIFO_OVERFLOW; + + 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->ipp_reg->csid_ipp_irq_mask_addr); + + res->res_state = CAM_ISP_RESOURCE_STATE_STREAMING; + + return 0; +} + +static int cam_ife_csid_disable_ipp_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; + struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + struct cam_ife_csid_path_cfg *path_data; + + 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_state != CAM_ISP_RESOURCE_STATE_STREAMING) { + CAM_DBG(CAM_ISP, "CSID:%d Res:%d Invalid state%d", + csid_hw->hw_intf->hw_idx, res->res_id, + res->res_state); + return -EINVAL; + } + + if (!csid_reg->ipp_reg) { + CAM_ERR(CAM_ISP, "CSID:%d IPP%d is not supported on HW", + csid_hw->hw_intf->hw_idx, 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 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->ipp_reg->csid_ipp_irq_mask_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; + 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; + + 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); + 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; + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_cfg0_addr); + + /* 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); + } + /* 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); + 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); + + cam_io_w_mb(val, soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]->csid_rdi_cfg0_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_rdi_path( + struct cam_ife_csid_hw *csid_hw, + struct cam_isp_resource_node *res) +{ + int rc = 0; + uint32_t id; + 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; + } + + 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) +{ + 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_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_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; + 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_MAX || + !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); + + return rc; +} + +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; + struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + uint32_t time_32, id; + + 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_ipp_timestamp_curr1_sof_addr); + time_stamp->time_stamp_val = 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_ipp_timestamp_curr0_sof_addr); + time_stamp->time_stamp_val |= time_32; + } else { + id = res->res_id; + time_32 = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->rdi_reg[id]-> + csid_rdi_timestamp_curr1_sof_addr); + time_stamp->time_stamp_val = 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->rdi_reg[id]-> + csid_rdi_timestamp_curr0_sof_addr); + time_stamp->time_stamp_val |= 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); + + 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; +} + +static 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; + 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->no_rdis = csid_reg->cmn_reg->no_rdis; + hw_caps->no_pix = csid_reg->cmn_reg->no_pix; + 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->no_rdis, + hw_caps->no_pix, hw_caps->major_version, hw_caps->minor_version, + hw_caps->version_incr); + + return rc; +} + +static 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; + + 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; + } + + return rc; +} + +static 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; + + 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; +} + +static 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) { + CAM_DBG(CAM_ISP, + "CSID:%d res type:%d Res %d in released state", + csid_hw->hw_intf->hw_idx, + res->res_type, res->res_id); + goto end; + } + + if (res->res_type == CAM_ISP_RESOURCE_PIX_PATH && + res->res_state != CAM_ISP_RESOURCE_STATE_RESERVED) { + CAM_DBG(CAM_ISP, + "CSID:%d res type:%d Res id:%d invalid 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 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_retain_sw_reg( + struct cam_ife_csid_hw *csid_hw) +{ + int rc = 0; + struct cam_ife_csid_reg_offset *csid_reg = + csid_hw->csid_info->csid_reg; + + cam_io_w_mb(csid_reg->cmn_reg->csid_rst_stb, + csid_hw->hw_info->soc_info.reg_map[0].mem_base + + csid_reg->cmn_reg->csid_rst_strobes_addr); + + CAM_DBG(CAM_ISP, " Waiting for SW reset complete from irq handler"); + rc = wait_for_completion_timeout(&csid_hw->csid_top_complete, + msecs_to_jiffies(IFE_CSID_TIMEOUT)); + if (rc <= 0) { + CAM_ERR(CAM_ISP, "CSID:%d reset completion in fail rc = %d", + csid_hw->hw_intf->hw_idx, rc); + if (rc == 0) + rc = -ETIMEDOUT; + } else { + rc = 0; + } + + return rc; +} + +static 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; + 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) + rc = cam_ife_csid_init_config_ipp_path(csid_hw, res); + else + rc = cam_ife_csid_init_config_rdi_path(csid_hw, res); + + 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_retain_sw_reg(csid_hw); + if (rc < 0) { + CAM_ERR(CAM_ISP, "CSID: Failed in SW reset"); + } + + if (rc) + cam_ife_csid_disable_hw(csid_hw); +end: + mutex_unlock(&csid_hw->hw_info->hw_mutex); + return rc; +} + +static 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) + rc = cam_ife_csid_deinit_ipp_path(csid_hw, res); + else + rc = cam_ife_csid_deinit_rdi_path(csid_hw, res); + + 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; +} + +static 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; + 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; + } + + 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) + rc = cam_ife_csid_enable_ipp_path(csid_hw, res); + else + rc = cam_ife_csid_enable_rdi_path(csid_hw, res); + 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; +} + +static 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; + + 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; + csid_hw_info = (struct cam_hw_info *)hw_priv; + csid_hw = (struct cam_ife_csid_hw *)csid_hw_info->core_info; + + /* Stop the resource first */ + for (i = 0; i < csid_stop->num_res; i++) { + res = csid_stop->node_res[i]; + 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: + if (res->res_id == CAM_IFE_PIX_PATH_RES_IPP) + rc = cam_ife_csid_disable_ipp_path(csid_hw, + res, csid_stop->stop_cmd); + else + rc = cam_ife_csid_disable_rdi_path(csid_hw, + res, csid_stop->stop_cmd); + + break; + default: + CAM_ERR(CAM_ISP, "CSID:%d Invalid res type%d", + csid_hw->hw_intf->hw_idx, + res->res_type); + break; + } + } + + 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; + +} + +static int cam_ife_csid_read(void *hw_priv, + void *read_args, uint32_t arg_size) +{ + CAM_ERR(CAM_ISP, "CSID: un supported"); + + return -EINVAL; +} + +static 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_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; + + 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); + break; + case CAM_IFE_CSID_SET_CSID_DEBUG: + rc = cam_ife_csid_set_csid_debug(csid_hw, cmd_args); + break; + default: + CAM_ERR(CAM_ISP, "CSID:%d un supported cmd:%d", + csid_hw->hw_intf->hw_idx, cmd_type); + rc = -EINVAL; + break; + } + + return rc; + +} + +static int cam_ife_csid_halt_device( + struct cam_ife_csid_hw *csid_hw) +{ + uint32_t i; + int rc = 0; + struct cam_isp_resource_node *res_node; + struct cam_ife_csid_reg_offset *csid_reg; + struct cam_hw_soc_info *soc_info; + + res_node = &csid_hw->ipp_res; + csid_reg = csid_hw->csid_info->csid_reg; + soc_info = &csid_hw->hw_info->soc_info; + if (res_node->res_state == CAM_ISP_RESOURCE_STATE_STREAMING) { + rc = cam_ife_csid_disable_ipp_path(csid_hw, + res_node, CAM_CSID_HALT_IMMEDIATELY); + res_node->res_state = CAM_ISP_RESOURCE_STATE_INIT_HW; + } + + for (i = 0; i < CAM_IFE_CSID_RDI_MAX; i++) { + res_node = &csid_hw->rdi_res[i]; + if (res_node->res_state == CAM_ISP_RESOURCE_STATE_STREAMING) { + rc = cam_ife_csid_disable_rdi_path(csid_hw, + res_node, CAM_CSID_HALT_IMMEDIATELY); + res_node->res_state = CAM_ISP_RESOURCE_STATE_INIT_HW; + } + } + + cam_io_w_mb(0, soc_info->reg_map[0].mem_base + + csid_reg->csi2_reg->csid_csi2_rx_irq_mask_addr); + 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); + 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; + struct cam_ife_csid_reg_offset *csid_reg; + uint32_t i, irq_status_top, irq_status_rx, irq_status_ipp = 0; + uint32_t irq_status_rdi[4] = {0, 0, 0, 0}; + uint32_t val; + int rc; + + 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; + + /* 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->no_pix) + irq_status_ipp = cam_io_r_mb(soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_ipp_irq_status_addr); + + + for (i = 0; i < csid_reg->cmn_reg->no_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); + + /* 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->no_pix) + cam_io_w_mb(irq_status_ipp, soc_info->reg_map[0].mem_base + + csid_reg->ipp_reg->csid_ipp_irq_clear_addr); + + for (i = 0; i < csid_reg->cmn_reg->no_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); + } + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_irq_cmd_addr); + + CAM_DBG(CAM_ISP, "irq_status_top = 0x%x", irq_status_top); + CAM_INFO(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_rdi0= 0x%x", irq_status_rdi[0]); + CAM_DBG(CAM_ISP, "irq_status_rdi1= 0x%x", irq_status_rdi[1]); + CAM_DBG(CAM_ISP, "irq_status_rdi2= 0x%x", irq_status_rdi[2]); + + if (irq_status_top) { + CAM_DBG(CAM_ISP, "CSID global reset complete......Exit"); + complete(&csid_hw->csid_top_complete); + return IRQ_HANDLED; + } + + + 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); + } + + 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); + if (!(irq_status_rx & CSID_CSI2_RX_ERROR_CPHY_SOT_RECEPTION)) { + rc = cam_ife_csid_halt_device(csid_hw); + if (rc) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d csid halt device fail rc = %d", + csid_hw->hw_intf->hw_idx, rc); + } + } + } + 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); + if (!(irq_status_rx & CSID_CSI2_RX_ERROR_CPHY_SOT_RECEPTION)) { + rc = cam_ife_csid_halt_device(csid_hw); + if (rc) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d csid halt device fail rc = %d", + csid_hw->hw_intf->hw_idx, rc); + } + } + } + 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); + if (!(irq_status_rx & CSID_CSI2_RX_ERROR_CPHY_SOT_RECEPTION)) { + rc = cam_ife_csid_halt_device(csid_hw); + if (rc) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d csid halt device fail rc = %d", + csid_hw->hw_intf->hw_idx, rc); + } + } + } + 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); + if (!(irq_status_rx & CSID_CSI2_RX_ERROR_CPHY_SOT_RECEPTION)) { + rc = cam_ife_csid_halt_device(csid_hw); + if (rc) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d csid halt device fail rc = %d", + csid_hw->hw_intf->hw_idx, rc); + } + } + } + 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); + } + 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); + } + 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); + } + 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); + rc = cam_ife_csid_halt_device(csid_hw); + if (rc) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "CSID:%d csid halt device fail rc = %d", + csid_hw->hw_intf->hw_idx, rc); + } + } + 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); + } + + if (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOT_IRQ) { + if (irq_status_rx & CSID_CSI2_RX_INFO_PHY_DL0_EOT_CAPTURED) { + CAM_ERR(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_ERR(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_ERR(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_ERR(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_ERR(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_ERR(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_ERR(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_ERR(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_ERR(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 + + csid_reg->csi2_reg-> + csid_csi2_rx_captured_long_pkt_0_addr); + CAM_ERR(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 + + csid_reg->csi2_reg-> + csid_csi2_rx_captured_long_pkt_1_addr); + CAM_ERR(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 + + csid_reg->csi2_reg-> + csid_csi2_rx_captured_long_pkt_ftr_addr); + CAM_ERR(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_ERR(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 + + csid_reg->csi2_reg-> + csid_csi2_rx_captured_short_pkt_0_addr); + CAM_ERR(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 + + csid_reg->csi2_reg-> + csid_csi2_rx_captured_short_pkt_1_addr); + CAM_ERR(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_ERR(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 + + csid_reg->csi2_reg-> + csid_csi2_rx_captured_cphy_pkt_hdr_addr); + CAM_ERR(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->no_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_ERR(CAM_ISP, "CSID:%d IPP SOF received", + csid_hw->hw_intf->hw_idx); + + if ((irq_status_ipp & CSID_PATH_INFO_INPUT_EOF) && + (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ)) + CAM_ERR(CAM_ISP, "CSID:%d IPP EOF received", + csid_hw->hw_intf->hw_idx); + + if (irq_status_ipp & CSID_PATH_ERROR_FIFO_OVERFLOW) { + CAM_ERR(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_ipp_ctrl_addr); + } + } + + for (i = 0; i < csid_reg->cmn_reg->no_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_ERR(CAM_ISP, "CSID RDI:%d SOF received", i); + + if ((irq_status_rdi[i] & CSID_PATH_INFO_INPUT_EOF) && + (csid_hw->csid_debug & CSID_DEBUG_ENABLE_EOF_IRQ)) + CAM_ERR(CAM_ISP, "CSID RDI:%d EOF received", i); + + if (irq_status_rdi[i] & CSID_PATH_ERROR_FIFO_OVERFLOW) { + CAM_ERR(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); + } + } + + 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) +{ + int rc = -EINVAL; + uint32_t i; + 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_RES_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->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); + 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); + for (i = 0; i < CAM_IFE_CSID_RDI_MAX; i++) + init_completion(&ife_csid_hw->csid_rdin_complete[i]); + + + rc = cam_ife_csid_init_soc_resources(&ife_csid_hw->hw_info->soc_info, + cam_ife_csid_irq, ife_csid_hw); + if (rc < 0) { + CAM_ERR(CAM_ISP, "CSID:%d Failed to init_soc", csid_idx); + goto err; + } + + 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; + + /*Initialize the CID resoure */ + for (i = 0; i < CAM_IFE_CSID_CID_RES_MAX; 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->no_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(struct cam_ife_csid_path_cfg), + GFP_KERNEL); + if (!path_data) { + rc = -ENOMEM; + goto err; + } + ife_csid_hw->ipp_res.res_priv = path_data; + } + + /* Initialize the RDI resource */ + for (i = 0; i < ife_csid_hw->csid_info->csid_reg->cmn_reg->no_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(struct cam_ife_csid_path_cfg), + GFP_KERNEL); + if (!path_data) { + rc = -ENOMEM; + goto err; + } + ife_csid_hw->rdi_res[i].res_priv = path_data; + } + + ife_csid_hw->csid_debug = 0; + return 0; +err: + if (rc) { + kfree(ife_csid_hw->ipp_res.res_priv); + for (i = 0; i < + ife_csid_hw->csid_info->csid_reg->cmn_reg->no_rdis; i++) + kfree(ife_csid_hw->rdi_res[i].res_priv); + + for (i = 0; i < CAM_IFE_CSID_CID_RES_MAX; i++) + kfree(ife_csid_hw->cid_res[i].res_priv); + + } + + return rc; +} + + +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); + for (i = 0; i < + ife_csid_hw->csid_info->csid_reg->cmn_reg->no_rdis; + i++) { + kfree(ife_csid_hw->rdi_res[i].res_priv); + } + for (i = 0; i < CAM_IFE_CSID_CID_RES_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; +} diff --git a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h new file mode 100644 index 000000000000..681a47f031ba --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.h @@ -0,0 +1,466 @@ +/* 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_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" + +#define CAM_IFE_CSID_HW_RES_MAX 4 +#define CAM_IFE_CSID_CID_RES_MAX 4 +#define CAM_IFE_CSID_RDI_MAX 4 + +#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_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) + +/* + * 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) + +/* 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_ipp_reg_offset { + /*Image pixel path register offsets*/ + uint32_t csid_ipp_irq_status_addr; + uint32_t csid_ipp_irq_mask_addr; + uint32_t csid_ipp_irq_clear_addr; + uint32_t csid_ipp_irq_set_addr; + + uint32_t csid_ipp_cfg0_addr; + uint32_t csid_ipp_cfg1_addr; + uint32_t csid_ipp_ctrl_addr; + uint32_t csid_ipp_frm_drop_pattern_addr; + uint32_t csid_ipp_frm_drop_period_addr; + uint32_t csid_ipp_irq_subsample_pattern_addr; + uint32_t csid_ipp_irq_subsample_period_addr; + uint32_t csid_ipp_hcrop_addr; + uint32_t csid_ipp_vcrop_addr; + uint32_t csid_ipp_pix_drop_pattern_addr; + uint32_t csid_ipp_pix_drop_period_addr; + uint32_t csid_ipp_line_drop_pattern_addr; + uint32_t csid_ipp_line_drop_period_addr; + uint32_t csid_ipp_rst_strobes_addr; + uint32_t csid_ipp_status_addr; + uint32_t csid_ipp_misr_val_addr; + uint32_t csid_ipp_format_measure_cfg0_addr; + uint32_t csid_ipp_format_measure_cfg1_addr; + uint32_t csid_ipp_format_measure0_addr; + uint32_t csid_ipp_format_measure1_addr; + uint32_t csid_ipp_format_measure2_addr; + uint32_t csid_ipp_timestamp_curr0_sof_addr; + uint32_t csid_ipp_timestamp_curr1_sof_addr; + uint32_t csid_ipp_timestamp_perv0_sof_addr; + uint32_t csid_ipp_timestamp_perv1_sof_addr; + uint32_t csid_ipp_timestamp_curr0_eof_addr; + uint32_t csid_ipp_timestamp_curr1_eof_addr; + uint32_t csid_ipp_timestamp_perv0_eof_addr; + uint32_t csid_ipp_timestamp_perv1_eof_addr; + + /* configuration */ + uint32_t pix_store_en_shift_val; +}; + +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_byte_cntr_ping_addr; + uint32_t csid_rdi_byte_cntr_pong_addr; +}; + +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; + + /*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; +}; + +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 no_rdis; + uint32_t no_pix; + 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 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 crop_shift; + uint32_t ipp_irq_mask_all; + uint32_t rdi_irq_mask_all; +}; + +/** + * struct cam_ife_csid_reg_offset- CSID instance register info + * + * @cmn_reg: csid common registers info + * @ipp_reg: ipp register offset information + * @rdi_reg: rdi register offser information + * + */ +struct cam_ife_csid_reg_offset { + struct cam_ife_csid_common_reg_offset *cmn_reg; + struct cam_ife_csid_csi2_rx_reg_offset *csi2_reg; + struct cam_ife_csid_ipp_reg_offset *ipp_reg; + struct cam_ife_csid_rdi_reg_offset *rdi_reg[CAM_IFE_CSID_RDI_MAX]; + 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 { + 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 + * + */ +struct cam_ife_csid_cid_data { + uint32_t vc; + uint32_t dt; + uint32_t cnt; + uint32_t tpg_set; +}; + + +/** + * 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. + * @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 + * + */ +struct cam_ife_csid_path_cfg { + uint32_t vc; + uint32_t dt; + uint32_t cid; + uint32_t in_format; + uint32_t out_format; + bool crop_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; +}; + +/** + * 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 + * @rdi_res: raw dump image 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_rdin_reset_complete: rdi n completion + * @csid_debug: csid debug information to enable the SOT, EOT, + * SOF, EOF, measure etc in the csid hw + * @clk_rate Clock rate + * + */ +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 rdi_res[CAM_IFE_CSID_RDI_MAX]; + struct cam_isp_resource_node cid_res[CAM_IFE_CSID_CID_RES_MAX]; + struct completion csid_top_complete; + struct completion csid_csi2_complete; + struct completion csid_ipp_complete; + struct completion csid_rdin_complete[CAM_IFE_CSID_RDI_MAX]; + uint64_t csid_debug; + uint64_t clk_rate; +}; + +int cam_ife_csid_hw_probe_init(struct cam_hw_intf *csid_hw_intf, + uint32_t csid_idx); + +int cam_ife_csid_hw_deinit(struct cam_ife_csid_hw *ife_csid_hw); + +#endif /* _CAM_IFE_CSID_HW_H_ */ diff --git a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_dev.c b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_dev.c new file mode 100644 index 000000000000..128c050284d4 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_dev.c @@ -0,0 +1,141 @@ +/* Copyright (c) 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. + */ + +#include +#include +#include +#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_RES_MAX] = { + 0, 0, 0, 0}; + +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; + } + + 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 = pdev->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); + 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_RES_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/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_dev.h b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_dev.h new file mode 100644 index 000000000000..3b213e2394b5 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_dev.h @@ -0,0 +1,23 @@ +/* Copyright (c) 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. + */ + +#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/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite170.c b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite170.c new file mode 100644 index 000000000000..36c6df0ae194 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite170.c @@ -0,0 +1,58 @@ +/* Copyright (c) 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. + */ + +#include +#include "cam_ife_csid_lite170.h" +#include "cam_ife_csid_core.h" +#include "cam_ife_csid_dev.h" + +#define CAM_CSID_LITE_DRV_NAME "csid_lite_170" +#define CAM_CSID_LITE_VERSION_V170 0x10070000 + +static struct cam_ife_csid_hw_info cam_ife_csid_lite170_hw_info = { + .csid_reg = &cam_ife_csid_lite_170_reg_offset, + .hw_dts_version = CAM_CSID_LITE_VERSION_V170, +}; + +static const struct of_device_id cam_ife_csid_lite170_dt_match[] = { + { + .compatible = "qcom,csid-lite170", + .data = &cam_ife_csid_lite170_hw_info, + }, + {} +}; +MODULE_DEVICE_TABLE(of, cam_ife_csid_lite170_dt_match); + +static struct platform_driver cam_ife_csid_lite170_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_lite170_dt_match, + }, +}; + +static int __init cam_ife_csid_lite170_init_module(void) +{ + return platform_driver_register(&cam_ife_csid_lite170_driver); +} + +static void __exit cam_ife_csid_lite170_exit_module(void) +{ + platform_driver_unregister(&cam_ife_csid_lite170_driver); +} + +module_init(cam_ife_csid_lite170_init_module); +module_exit(cam_ife_csid_lite170_exit_module); +MODULE_DESCRIPTION("CAM IFE_CSID_LITE170 driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite170.h b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite170.h new file mode 100644 index 000000000000..952426da8f99 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_lite170.h @@ -0,0 +1,319 @@ +/* Copyright (c) 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. + */ + +#ifndef _CAM_IFE_CSID_LITE170_H_ +#define _CAM_IFE_CSID_LITE170_H_ +#include "cam_ife_csid_core.h" + +static struct cam_ife_csid_rdi_reg_offset + cam_ife_csid_lite_170_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 struct cam_ife_csid_rdi_reg_offset + cam_ife_csid_lite_170_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 struct cam_ife_csid_rdi_reg_offset + cam_ife_csid_lite_170_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 struct cam_ife_csid_rdi_reg_offset + cam_ife_csid_lite_170_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 struct cam_ife_csid_csi2_rx_reg_offset + cam_ife_csid_lite_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, +}; + + +static struct cam_ife_csid_csi2_tpg_reg_offset + cam_ife_csid_lite_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_csid_lite_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, + .no_rdis = 4, + .no_pix = 0, + .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, +}; + +struct cam_ife_csid_reg_offset cam_ife_csid_lite_170_reg_offset = { + .cmn_reg = &cam_csid_lite_170_cmn_reg_offset, + .csi2_reg = &cam_ife_csid_lite_170_csi2_reg_offset, + .ipp_reg = NULL, + .rdi_reg = { + &cam_ife_csid_lite_170_rdi_0_reg_offset, + &cam_ife_csid_lite_170_rdi_1_reg_offset, + &cam_ife_csid_lite_170_rdi_2_reg_offset, + &cam_ife_csid_lite_170_rdi_3_reg_offset, + }, + .tpg_reg = &cam_ife_csid_lite_170_tpg_reg_offset, +}; + +#endif /*_CAM_IFE_CSID_LITE170_H_ */ diff --git a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.c b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.c new file mode 100644 index 000000000000..e11ff6372ae0 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.c @@ -0,0 +1,239 @@ +/* Copyright (c) 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. + */ +#include +#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) +{ + 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)); + 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); + if (rc < 0) + return rc; + + return rc; +} + +int cam_ife_csid_enable_soc_resources(struct cam_hw_soc_info *soc_info) +{ + int rc = 0; + struct cam_csid_soc_private *soc_private; + struct cam_ahb_vote ahb_vote; + struct cam_axi_vote axi_vote; + + soc_private = soc_info->soc_private; + + ahb_vote.type = CAM_VOTE_ABSOLUTE; + ahb_vote.vote.level = CAM_SVS_VOTE; + axi_vote.compressed_bw = CAM_CPAS_DEFAULT_AXI_BW; + axi_vote.uncompressed_bw = CAM_CPAS_DEFAULT_AXI_BW; + + CAM_DBG(CAM_ISP, "csid vote compressed_bw:%lld uncompressed_bw:%lld", + axi_vote.compressed_bw, axi_vote.uncompressed_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, + CAM_SVS_VOTE, 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/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.h b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.h new file mode 100644 index 000000000000..8e963de18aec --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_soc.h @@ -0,0 +1,114 @@ +/* Copyright (c) 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. + */ + +#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 + * + */ +int cam_ife_csid_init_soc_resources(struct cam_hw_soc_info *soc_info, + irq_handler_t csid_irq_handler, void *irq_data); + + +/** + * 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 + * + */ +int cam_ife_csid_enable_soc_resources(struct cam_hw_soc_info *soc_info); + +/** + * 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); + + + +#endif diff --git a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h new file mode 100644 index 000000000000..ceeacbee247d --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/include/cam_ife_csid_hw_intf.h @@ -0,0 +1,169 @@ +/* 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_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 4 + +/** + * 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_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 + * @no_rdis : number of rdis supported by CSID HW device + * @no_pix: number of pixel path 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 no_rdis; + uint32_t no_pix; + uint32_t major_version; + uint32_t minor_version; + uint32_t version_incr; +}; + +/** + * 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 + * + */ +struct cam_csid_hw_reserve_resource_args { + enum cam_isp_resource_type res_type; + uint32_t res_id; + struct cam_isp_in_port_info *in_port; + struct cam_isp_out_port_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; +}; + +/** + * 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 + * + */ +struct cam_csid_get_time_stamp_args { + struct cam_isp_resource_node *node_res; + uint64_t time_stamp_val; +}; + +/** + * 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_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); + +#endif /* _CAM_CSID_HW_INTF_H_ */ diff --git a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h new file mode 100644 index 000000000000..c56c49fac5af --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h @@ -0,0 +1,222 @@ +/* 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_ISP_HW_H_ +#define _CAM_ISP_HW_H_ + +#include +#include "cam_hw.h" +#include +#include "cam_soc_util.h" +#include "cam_irq_controller.h" +#include + +/* + * 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_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_REG_UPDATE, + CAM_ISP_HW_CMD_GET_HFR_UPDATE, + 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_CONTROL, + CAM_ISP_HW_CMD_STOP_BUS_ERR_IRQ, + CAM_ISP_HW_CMD_GET_REG_DUMP, + 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: resouce 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_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 { + uint64_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_port_hfr_config *hfr_update; + struct cam_isp_clock_config *clock_update; + struct cam_isp_bw_config *bw_update; + }; +}; + +/* + * 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/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h new file mode 100644 index 000000000000..05c3c6120f4e --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/include/cam_vfe_hw_intf.h @@ -0,0 +1,299 @@ +/* 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_VFE_HW_INTF_H_ +#define _CAM_VFE_HW_INTF_H_ + +#include "cam_isp_hw.h" + +#define CAM_VFE_HW_NUM_MAX 4 + +#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 + +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_BUS_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_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_VIOLATION_STATUS = 2, + 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_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 + * @ctx: Context data + */ +struct cam_vfe_hw_vfe_out_acquire_args { + struct cam_isp_resource_node *rsrc_node; + struct cam_isp_out_port_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; + void *ctx; +}; + +/* + * 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_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. + * @vfe_out: Acquire args for VFE_OUT + * @vfe_in: Acquire args for VFE_IN + */ +struct cam_vfe_acquire_args { + enum cam_isp_resource_type rsrc_type; + void *tasklet; + union { + struct cam_vfe_hw_vfe_out_acquire_args vfe_out; + 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_bw_update_args: + * + * @node_res: Resource to get the time stamp + * @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; +}; + +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 + * @core_index: Index of VFE HW that generated this IRQ event + * @core_info: Private data of handler in bottom half context + * @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_top_irq_evt_payload { + struct list_head list; + uint32_t core_index; + void *core_info; + uint32_t evt_id; + uint32_t irq_reg_val[CAM_IFE_IRQ_REGISTERS_MAX]; + uint32_t error_type; + 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 + * @evt_id: IRQ event + * @irq_reg_val: IRQ and Error register values, read when IRQ was + * handled + * @error_type: Identify different errors + * @ts: Timestamp + * @ctx: Context data received during acquire + */ +struct cam_vfe_bus_irq_evt_payload { + struct list_head list; + uint32_t core_index; + uint32_t evt_id; + uint32_t irq_reg_val[CAM_IFE_BUS_IRQ_REGISTERS_MAX]; + uint32_t error_type; + struct cam_isp_timestamp ts; + void *ctx; +}; + +/* + * struct cam_vfe_irq_handler_priv: + * + * @Brief: This structure is used as private data to + * register with IRQ controller. It has information + * needed by top half and bottom half. + * + * @core_index: Index of VFE HW that generated this IRQ event + * @core_info: Private data of handler in bottom half context + * @mem_base: Mapped base address of the register space + * @reset_complete: Completion structure to be signaled if Reset IRQ + * is Set + */ +struct cam_vfe_irq_handler_priv { + uint32_t core_index; + void *core_info; + void __iomem *mem_base; + struct completion *reset_complete; +}; + +/* + * 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/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/Makefile b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/Makefile new file mode 100644 index 000000000000..0bdee6a7877c --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/Makefile @@ -0,0 +1,15 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_utils +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_core +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_cpas/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/irq_controller +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/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/ vfe170/ \ No newline at end of file diff --git a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c new file mode 100644 index 000000000000..688cd369af90 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c @@ -0,0 +1,825 @@ +/* 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. + */ + +#include +#include +#include +#include +#include +#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" + +static const char drv_name[] = "vfe"; +static uint32_t irq_reg_offset[CAM_IFE_IRQ_REGISTERS_MAX] = { + 0x0000006C, + 0x00000070, + 0x0000007C, +}; + +static uint32_t camif_irq_reg_mask[CAM_IFE_IRQ_REGISTERS_MAX] = { + 0x00000017, + 0x00000000, +}; + +static uint32_t camif_irq_err_reg_mask[CAM_IFE_IRQ_REGISTERS_MAX] = { + 0x0003FC00, + 0x0FFF7EBC, +}; + +static uint32_t rdi_irq_reg_mask[CAM_IFE_IRQ_REGISTERS_MAX] = { + 0x780001e0, + 0x00000000, +}; + +static uint32_t top_reset_irq_reg_mask[CAM_IFE_IRQ_REGISTERS_MAX] = { + 0x80000000, + 0x00000000, +}; + +static int cam_vfe_get_evt_payload(struct cam_vfe_hw_core_info *core_info, + struct cam_vfe_top_irq_evt_payload **evt_payload) +{ + spin_lock(&core_info->spin_lock); + if (list_empty(&core_info->free_payload_list)) { + *evt_payload = NULL; + spin_unlock(&core_info->spin_lock); + CAM_ERR_RATE_LIMIT(CAM_ISP, "No free payload, core info 0x%x\n", + core_info->cpas_handle); + return -ENODEV; + } + + *evt_payload = list_first_entry(&core_info->free_payload_list, + struct cam_vfe_top_irq_evt_payload, list); + list_del_init(&(*evt_payload)->list); + spin_unlock(&core_info->spin_lock); + + return 0; +} + +int cam_vfe_put_evt_payload(void *core_info, + struct cam_vfe_top_irq_evt_payload **evt_payload) +{ + struct cam_vfe_hw_core_info *vfe_core_info = core_info; + unsigned long flags; + + if (!core_info) { + 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(&vfe_core_info->spin_lock, flags); + (*evt_payload)->error_type = 0; + list_add_tail(&(*evt_payload)->list, &vfe_core_info->free_payload_list); + *evt_payload = NULL; + spin_unlock_irqrestore(&vfe_core_info->spin_lock, flags); + + + return 0; +} + +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_vfe_irq_handler_priv *handler_priv; + + handler_priv = th_payload->handler_priv; + + CAM_DBG(CAM_ISP, "Enter"); + CAM_DBG(CAM_ISP, "IRQ status_0 = 0x%x", th_payload->evt_status_arr[0]); + + if (th_payload->evt_status_arr[0] & (1<<31)) { + /* + * Clear All IRQs to avoid spurious IRQs immediately + * after Reset Done. + */ + cam_io_w(0xFFFFFFFF, handler_priv->mem_base + 0x64); + cam_io_w(0xFFFFFFFF, handler_priv->mem_base + 0x68); + cam_io_w(0x1, handler_priv->mem_base + 0x58); + CAM_DBG(CAM_ISP, "Calling Complete for RESET CMD"); + complete(handler_priv->reset_complete); + + + rc = 0; + } + + CAM_DBG(CAM_ISP, "Exit"); + return rc; +} + +static int cam_vfe_irq_err_top_half(uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + int32_t rc; + int i; + struct cam_vfe_irq_handler_priv *handler_priv; + struct cam_vfe_top_irq_evt_payload *evt_payload; + struct cam_vfe_hw_core_info *core_info; + 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]); + + handler_priv = th_payload->handler_priv; + core_info = handler_priv->core_info; + /* + * 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_irq_err_reg_mask[0])) { + CAM_ERR(CAM_ISP, + "Encountered Error: vfe:%d: Irq_status0=0x%x Status1=0x%x", + handler_priv->core_index, th_payload->evt_status_arr[0], + th_payload->evt_status_arr[1]); + CAM_ERR(CAM_ISP, + "Stopping further IRQ processing from this HW index=%d", + handler_priv->core_index); + cam_irq_controller_disable_irq(core_info->vfe_irq_controller, + core_info->irq_err_handle); + cam_irq_controller_clear_and_mask(evt_id, + core_info->vfe_irq_controller); + error_flag = true; + } + + rc = cam_vfe_get_evt_payload(handler_priv->core_info, &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); + + evt_payload->core_index = handler_priv->core_index; + evt_payload->core_info = handler_priv->core_info; + 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]; + + for (; i < CAM_IFE_IRQ_REGISTERS_MAX; i++) { + evt_payload->irq_reg_val[i] = cam_io_r(handler_priv->mem_base + + irq_reg_offset[i]); + } + + if (error_flag) + CAM_INFO(CAM_ISP, "Violation status = %x", + evt_payload->irq_reg_val[2]); + + th_payload->evt_payload_priv = evt_payload; + + 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; + } + + 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; + } + + 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); + + 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"); + } + + 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_hw_core_info *core_info = NULL; + 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; + core_info = (struct cam_vfe_hw_core_info *)vfe_hw->core_info; + + core_info->irq_payload.core_index = soc_info->index; + core_info->irq_payload.mem_base = + vfe_hw->soc_info.reg_map[VFE_CORE_BASE_IDX].mem_base; + core_info->irq_payload.core_info = core_info; + core_info->irq_payload.reset_complete = &vfe_hw->hw_complete; + + core_info->irq_handle = cam_irq_controller_subscribe_irq( + core_info->vfe_irq_controller, CAM_IRQ_PRIORITY_0, + top_reset_irq_reg_mask, &core_info->irq_payload, + cam_vfe_reset_irq_top_half, NULL, NULL, NULL); + if (core_info->irq_handle < 0) { + CAM_ERR(CAM_ISP, "subscribe irq controller failed"); + return -EFAULT; + } + + reinit_completion(&vfe_hw->hw_complete); + + CAM_INFO(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); + CAM_DBG(CAM_ISP, "waiting for vfe reset complete"); + /* Wait for Completion or Timeout of 500ms */ + rc = wait_for_completion_timeout(&vfe_hw->hw_complete, 500); + if (!rc) + CAM_ERR(CAM_ISP, "Error! Reset Timeout"); + + CAM_DBG(CAM_ISP, "reset complete done (%d)", rc); + + rc = cam_irq_controller_unsubscribe_irq( + core_info->vfe_irq_controller, core_info->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; +} + +static int cam_vfe_irq_top_half(uint32_t evt_id, + struct cam_irq_th_payload *th_payload) +{ + int32_t rc; + int i; + struct cam_vfe_irq_handler_priv *handler_priv; + struct cam_vfe_top_irq_evt_payload *evt_payload; + struct cam_vfe_hw_core_info *core_info; + + handler_priv = th_payload->handler_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_get_evt_payload(handler_priv->core_info, &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; + } + + core_info = handler_priv->core_info; + cam_isp_hw_get_timestamp(&evt_payload->ts); + + evt_payload->core_index = handler_priv->core_index; + evt_payload->core_info = handler_priv->core_info; + 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]; + + for (; i < CAM_IFE_IRQ_REGISTERS_MAX; i++) { + evt_payload->irq_reg_val[i] = cam_io_r(handler_priv->mem_base + + irq_reg_offset[i]); + } + CAM_DBG(CAM_ISP, "Violation status = %x", evt_payload->irq_reg_val[2]); + + th_payload->evt_payload_priv = evt_payload; + + CAM_DBG(CAM_ISP, "Exit"); + return rc; +} + +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; + + 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 + 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 + 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; + int rc = 0; + struct cam_irq_bh_api irq_bh_api; + + if (!hw_priv || !start_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 *)start_args; + core_info->tasklet_info = isp_res->tasklet_info; + irq_bh_api.bottom_half_enqueue_func = cam_tasklet_enqueue_cmd; + irq_bh_api.get_bh_payload_func = cam_tasklet_get_cmd; + irq_bh_api.put_bh_payload_func = cam_tasklet_put_cmd; + + mutex_lock(&vfe_hw->hw_mutex); + if (isp_res->res_type == CAM_ISP_RESOURCE_VFE_IN) { + if (isp_res->res_id == CAM_ISP_HW_VFE_IN_CAMIF) { + isp_res->irq_handle = + cam_irq_controller_subscribe_irq( + core_info->vfe_irq_controller, + CAM_IRQ_PRIORITY_1, + camif_irq_reg_mask, + &core_info->irq_payload, + cam_vfe_irq_top_half, + cam_ife_mgr_do_tasklet, + isp_res->tasklet_info, + &irq_bh_api); + if (isp_res->irq_handle < 1) + rc = -ENOMEM; + } else if (isp_res->rdi_only_ctx) { + isp_res->irq_handle = + cam_irq_controller_subscribe_irq( + core_info->vfe_irq_controller, + CAM_IRQ_PRIORITY_1, + rdi_irq_reg_mask, + &core_info->irq_payload, + cam_vfe_irq_top_half, + cam_ife_mgr_do_tasklet, + isp_res->tasklet_info, + &irq_bh_api); + if (isp_res->irq_handle < 1) + rc = -ENOMEM; + } + + if (rc == 0) { + 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, "Start failed. type:%d", + isp_res->res_type); + } else { + CAM_ERR(CAM_ISP, + "Error! subscribe irq controller failed"); + } + } else if (isp_res->res_type == CAM_ISP_RESOURCE_VFE_OUT) { + rc = core_info->vfe_bus->hw_ops.start(isp_res, NULL, 0); + } else { + CAM_ERR(CAM_ISP, "Invalid res type:%d", isp_res->res_type); + rc = -EFAULT; + } + + if (!core_info->irq_err_handle) { + core_info->irq_err_handle = + cam_irq_controller_subscribe_irq( + core_info->vfe_irq_controller, + CAM_IRQ_PRIORITY_0, + camif_irq_err_reg_mask, + &core_info->irq_payload, + cam_vfe_irq_err_top_half, + cam_ife_mgr_do_tasklet, + core_info->tasklet_info, + &irq_bh_api); + if (core_info->irq_err_handle < 1) { + CAM_ERR(CAM_ISP, "Error handle subscribe failure"); + rc = -ENOMEM; + core_info->irq_err_handle = 0; + } + } + + 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) { + cam_irq_controller_unsubscribe_irq( + core_info->vfe_irq_controller, isp_res->irq_handle); + isp_res->irq_handle = 0; + + 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 { + CAM_ERR(CAM_ISP, "Invalid res type:%d", isp_res->res_type); + } + + if (core_info->irq_err_handle) { + cam_irq_controller_unsubscribe_irq( + core_info->vfe_irq_controller, + core_info->irq_err_handle); + core_info->irq_err_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: + 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: + rc = core_info->vfe_bus->hw_ops.process_cmd( + core_info->vfe_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; + int i; + + CAM_DBG(CAM_ISP, "Enter"); + + 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); + if (rc) { + CAM_ERR(CAM_ISP, "Error! cam_irq_controller_init failed"); + 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_top); + if (rc) { + CAM_ERR(CAM_ISP, "Error! cam_vfe_top_init failed"); + goto deinit_controller; + } + + rc = cam_vfe_bus_init(vfe_hw_info->bus_version, 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"); + goto deinit_top; + } + + INIT_LIST_HEAD(&core_info->free_payload_list); + for (i = 0; i < CAM_VFE_EVT_MAX; i++) { + INIT_LIST_HEAD(&core_info->evt_payload[i].list); + list_add_tail(&core_info->evt_payload[i].list, + &core_info->free_payload_list); + } + + 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; + int i; + unsigned long flags; + + spin_lock_irqsave(&core_info->spin_lock, flags); + + INIT_LIST_HEAD(&core_info->free_payload_list); + for (i = 0; i < CAM_VFE_EVT_MAX; i++) + INIT_LIST_HEAD(&core_info->evt_payload[i].list); + + 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/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.h b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.h new file mode 100644 index 000000000000..0674a6addc7f --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.h @@ -0,0 +1,96 @@ +/* Copyright (c) 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. + */ + +#ifndef _CAM_VFE_CORE_H_ +#define _CAM_VFE_CORE_H_ + +#include +#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 top_version; + void *top_hw_info; + uint32_t camif_version; + void *camif_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; + void *tasklet_info; + struct cam_vfe_top_irq_evt_payload evt_payload[CAM_VFE_EVT_MAX]; + struct list_head free_payload_list; + struct cam_vfe_irq_handler_priv irq_payload; + uint32_t cpas_handle; + int irq_handle; + int irq_err_handle; + spinlock_t spin_lock; +}; + +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/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_dev.c b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_dev.c new file mode 100644 index 000000000000..74627b8d32ef --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_dev.c @@ -0,0 +1,197 @@ +/* Copyright (c) 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. + */ + + +#include +#include +#include +#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}; + +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; + } + vfe_hw->soc_info.pdev = pdev; + vfe_hw->soc_info.dev = &pdev->dev; + vfe_hw->soc_info.dev_name = pdev->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/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_dev.h b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_dev.h new file mode 100644 index 000000000000..9e7352834ad6 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_dev.h @@ -0,0 +1,42 @@ +/* Copyright (c) 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. + */ + +#ifndef _CAM_VFE_DEV_H_ +#define _CAM_VFE_DEV_H_ + +#include + +/* + * 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/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c new file mode 100644 index 000000000000..0f9366454568 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.c @@ -0,0 +1,293 @@ +/* Copyright (c) 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. + */ + +#include +#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: + 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; + + 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; + } + + 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_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"); + + 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; + + 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_SVS_VOTE; + + axi_vote.compressed_bw = 10640000000L; + axi_vote.uncompressed_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/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h new file mode 100644 index 000000000000..7a4dbeadb182 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_soc.h @@ -0,0 +1,116 @@ +/* Copyright (c) 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. + */ + +#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" + +/* + * 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. + */ +struct cam_vfe_soc_private { + uint32_t cpas_handle; + struct clk *dsp_clk; + int32_t dsp_clk_index; + int32_t dsp_clk_rate; +}; + +/* + * 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/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/Makefile b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/Makefile new file mode 100644 index 000000000000..e6509d621403 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/Makefile @@ -0,0 +1,14 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_utils +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_core +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/irq_controller +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_vfe170.o cam_vfe_lite170.o diff --git a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe170.c b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe170.c new file mode 100644 index 000000000000..0af32ad5d546 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe170.c @@ -0,0 +1,51 @@ +/* Copyright (c) 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. + */ + +#include +#include "cam_vfe170.h" +#include "cam_vfe_hw_intf.h" +#include "cam_vfe_core.h" +#include "cam_vfe_dev.h" + +static const struct of_device_id cam_vfe170_dt_match[] = { + { + .compatible = "qcom,vfe170", + .data = &cam_vfe170_hw_info, + }, + {} +}; +MODULE_DEVICE_TABLE(of, cam_vfe170_dt_match); + +static struct platform_driver cam_vfe170_driver = { + .probe = cam_vfe_probe, + .remove = cam_vfe_remove, + .driver = { + .name = "cam_vfe170", + .owner = THIS_MODULE, + .of_match_table = cam_vfe170_dt_match, + }, +}; + +static int __init cam_vfe170_init_module(void) +{ + return platform_driver_register(&cam_vfe170_driver); +} + +static void __exit cam_vfe170_exit_module(void) +{ + platform_driver_unregister(&cam_vfe170_driver); +} + +module_init(cam_vfe170_init_module); +module_exit(cam_vfe170_exit_module); +MODULE_DESCRIPTION("CAM VFE170 driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe170.h b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe170.h new file mode 100644 index 000000000000..a4ba2e12bca3 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe170.h @@ -0,0 +1,837 @@ +/* Copyright (c) 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. + */ + +#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, +}; + +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, +}; + +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, + }, + .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, + }, + }, + .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 = 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 = 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, + }, + .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, + +}; + +#endif /* _CAM_VFE170_H_ */ diff --git a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe_lite170.c b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe_lite170.c new file mode 100644 index 000000000000..3c8abbf065ab --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe_lite170.c @@ -0,0 +1,51 @@ +/* Copyright (c) 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. + */ + +#include +#include "cam_vfe_lite170.h" +#include "cam_vfe_hw_intf.h" +#include "cam_vfe_core.h" +#include "cam_vfe_dev.h" + +static const struct of_device_id cam_vfe170_dt_match[] = { + { + .compatible = "qcom,vfe-lite170", + .data = &cam_vfe_lite170_hw_info, + }, + {} +}; +MODULE_DEVICE_TABLE(of, cam_vfe170_dt_match); + +static struct platform_driver cam_vfe170_driver = { + .probe = cam_vfe_probe, + .remove = cam_vfe_remove, + .driver = { + .name = "cam_vfe_lite170", + .owner = THIS_MODULE, + .of_match_table = cam_vfe170_dt_match, + }, +}; + +static int __init cam_vfe170_init_module(void) +{ + return platform_driver_register(&cam_vfe170_driver); +} + +static void __exit cam_vfe170_exit_module(void) +{ + platform_driver_unregister(&cam_vfe170_driver); +} + +module_init(cam_vfe170_init_module); +module_exit(cam_vfe170_exit_module); +MODULE_DESCRIPTION("CAM VFE170 driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe_lite170.h b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe_lite170.h new file mode 100644 index 000000000000..2f95febee5f7 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe170/cam_vfe_lite170.h @@ -0,0 +1,336 @@ +/* Copyright (c) 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. + */ + +#ifndef _CAM_VFE_LITE170_H_ +#define _CAM_VFE_LITE170_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_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 = { + 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 vfe170_rdi_reg = { + .reg_update_cmd = 0x000004AC, +}; + +static struct cam_vfe_rdi_reg_data vfe170_rdi_0_data = { + .reg_update_cmd_data = 0x2, + .sof_irq_mask = 0x8000000, + .reg_update_irq_mask = 0x20, +}; + +static struct cam_vfe_rdi_reg_data vfe170_rdi_1_data = { + .reg_update_cmd_data = 0x4, + .sof_irq_mask = 0x10000000, + .reg_update_irq_mask = 0x40, +}; + +static struct cam_vfe_rdi_reg_data vfe170_rdi_2_data = { + .reg_update_cmd_data = 0x8, + .sof_irq_mask = 0x20000000, + .reg_update_irq_mask = 0x80, +}; + +static struct cam_vfe_rdi_reg_data vfe170_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 vfe170_top_hw_info = { + .common_reg = &vfe170_top_common_reg, + .camif_hw_info = { + .common_reg = NULL, + .camif_reg = NULL, + .reg_data = NULL, + }, + .rdi_hw_info = { + .common_reg = &vfe170_top_common_reg, + .rdi_reg = &vfe170_rdi_reg, + .reg_data = { + &vfe170_rdi_0_data, + &vfe170_rdi_1_data, + &vfe170_rdi_2_data, + &vfe170_rdi_3_data, + }, + }, + .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 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_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, + }, + .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_lite170_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, + +}; + +#endif /* _CAM_VFE_LITE170_H_ */ diff --git a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/Makefile b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/Makefile new file mode 100644 index 000000000000..bd776d948c6d --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/Makefile @@ -0,0 +1,14 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_utils/ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_cdm/ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_core/ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/irq_controller +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_cpas/include + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_vfe_bus.o cam_vfe_bus_ver2.o diff --git a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus.c b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus.c new file mode 100644 index 000000000000..c6c32723eb2f --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus.c @@ -0,0 +1,56 @@ +/* Copyright (c) 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. + */ + +#include "cam_vfe_bus.h" +#include "cam_vfe_bus_ver1.h" +#include "cam_vfe_bus_ver2.h" +#include "cam_debug_util.h" + +int cam_vfe_bus_init(uint32_t bus_version, + 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_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; + default: + CAM_ERR(CAM_ISP, "Unsupported Bus Version %x", bus_version); + 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; + default: + CAM_ERR(CAM_ISP, "Unsupported Bus Version %x", bus_version); + break; + } + + return rc; +} + diff --git a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver1.h b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver1.h new file mode 100644 index 000000000000..357245196e0b --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver1.h @@ -0,0 +1,120 @@ +/* Copyright (c) 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. + */ + +#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/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c new file mode 100644 index 000000000000..b057567c799c --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c @@ -0,0 +1,3090 @@ +/* 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. + */ + +#include +#include +#include +#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_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 0xFFFFF + +#define ALIGNUP(value, alignment) \ + ((value + alignment - 1) / alignment * alignment) + +#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) + +#define CAM_VFE_ADD_REG_VAL_PAIR(buf_array, index, offset, val) \ + do { \ + buf_array[index++] = offset; \ + buf_array[index++] = val; \ + } while (0) + +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; + struct mutex bus_mutex; + uint32_t secure_mode; + uint32_t num_sec_out; + uint32_t addr_no_sync; +}; + +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; + void *ctx; + + uint32_t irq_enabled; + 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; + 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; + 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; +}; + +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 irq_enabled; + 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; + uint32_t irq_trigger_cnt; + + void *ctx; +}; + +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; +}; + +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; + + uint32_t irq_handle; + uint32_t 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 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) +{ + if (list_empty(&common_data->free_payload_list)) { + *evt_payload = NULL; + CAM_ERR_RATE_LIMIT(CAM_ISP, "No free payload"); + return -ENODEV; + } + + *evt_payload = list_first_entry(&common_data->free_payload_list, + struct cam_vfe_bus_irq_evt_payload, list); + list_del_init(&(*evt_payload)->list); + return 0; +} + +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(void *core_info, + struct cam_vfe_bus_irq_evt_payload **evt_payload) +{ + struct cam_vfe_bus_ver2_common_data *common_data = NULL; + uint32_t *ife_irq_regs = NULL; + uint32_t status_reg0, status_reg1, status_reg2; + + if (!core_info) { + 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; + } + (*evt_payload)->error_type = 0; + ife_irq_regs = (*evt_payload)->irq_reg_val; + status_reg0 = ife_irq_regs[CAM_IFE_IRQ_BUS_REG_STATUS0]; + status_reg1 = ife_irq_regs[CAM_IFE_IRQ_BUS_REG_STATUS1]; + status_reg2 = ife_irq_regs[CAM_IFE_IRQ_BUS_REG_STATUS2]; + + if (status_reg0 || status_reg1 || status_reg2) { + CAM_DBG(CAM_ISP, "status0 0x%x status1 0x%x status2 0x%x", + status_reg0, status_reg1, status_reg2); + return 0; + } + + common_data = core_info; + list_add_tail(&(*evt_payload)->list, + &common_data->free_payload_list); + *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: + return true; + + case CAM_VFE_BUS_VER2_VFE_OUT_PDAF: + 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_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; + 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: + 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; + default: + break; + } + break; + case CAM_VFE_BUS_VER2_VFE_OUT_DS4: + case CAM_VFE_BUS_VER2_VFE_OUT_DS16: + 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_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: + 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; + default: + break; + } + + return wm_idx; +} + +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) + 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: + 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_info *out_port_info, + void *tasklet, + void *ctx, + enum cam_vfe_bus_ver2_vfe_out_type vfe_out_res_id, + enum cam_vfe_bus_plane_type plane, + uint32_t subscribe_irq, + 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]; + wm_res_local->tasklet_info = tasklet; + wm_res_local->res_state = CAM_ISP_RESOURCE_STATE_RESERVED; + + rsrc_data = wm_res_local->res_priv; + rsrc_data->irq_enabled = subscribe_irq; + rsrc_data->ctx = ctx; + 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: + 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_PLAIN16_12: + rsrc_data->en_cfg = 0x1; + rsrc_data->pack_fmt = 0x3; + rsrc_data->width = rsrc_data->width * 2; + rsrc_data->stride = rsrc_data->width; + break; + case CAM_FORMAT_PLAIN16_14: + rsrc_data->en_cfg = 0x1; + rsrc_data->pack_fmt = 0x4; + rsrc_data->width = rsrc_data->width * 2; + rsrc_data->stride = rsrc_data->width; + break; + case CAM_FORMAT_PLAIN16_16: + rsrc_data->en_cfg = 0x1; + rsrc_data->pack_fmt = 0x5; + rsrc_data->width = rsrc_data->width * 2; + rsrc_data->stride = rsrc_data->width; + break; + case CAM_FORMAT_PLAIN32_20: + rsrc_data->en_cfg = 0x1; + rsrc_data->pack_fmt = 0x9; + 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) { + /* Write master 3, 4 - for Full OUT , 7-8 FD OUT */ + 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: + 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) { + /* 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 == 9 || rsrc_data->index == 10) { + /* 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, 10 PDAF */ + 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->irq_enabled = 0; + 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; + 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; + + 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) +{ + 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; + uint32_t bus_irq_reg_mask[CAM_VFE_BUS_IRQ_MAX] = {0}; + struct cam_irq_bh_api irq_bh_api; + + 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)); + + /* Subscribe IRQ */ + if (rsrc_data->irq_enabled) { + CAM_DBG(CAM_ISP, "Subscribe WM%d IRQ", rsrc_data->index); + bus_irq_reg_mask[CAM_VFE_BUS_IRQ_REG1] = + (1 << rsrc_data->index); + irq_bh_api.bottom_half_enqueue_func = cam_tasklet_enqueue_cmd; + irq_bh_api.get_bh_payload_func = cam_tasklet_get_cmd; + irq_bh_api.put_bh_payload_func = cam_tasklet_put_cmd; + wm_res->irq_handle = cam_irq_controller_subscribe_irq( + common_data->bus_irq_controller, CAM_IRQ_PRIORITY_1, + bus_irq_reg_mask, wm_res, + wm_res->top_half_handler, + cam_ife_mgr_do_tasklet_buf_done, + wm_res->tasklet_info, &irq_bh_api); + if (wm_res->irq_handle < 0) { + CAM_ERR(CAM_ISP, "Subscribe IRQ failed for WM %d", + rsrc_data->index); + return -EFAULT; + } + } + + /* enable ubwc if needed*/ + if (rsrc_data->en_ubwc) { + int val = cam_io_r_mb(common_data->mem_base + + rsrc_data->hw_regs->ubwc_regs->mode_cfg); + CAM_DBG(CAM_ISP, "ubwc reg %d, res id %d", + val, rsrc_data->index); + val |= 0x1; + cam_io_w_mb(val, common_data->mem_base + + rsrc_data->hw_regs->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, "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; + + /* Disble WM */ + /* Disable all register access, reply on global reset */ + CAM_DBG(CAM_ISP, "irq_enabled %d", rsrc_data->irq_enabled); + /* Unsubscribe IRQ */ + if (rsrc_data->irq_enabled) + rc = cam_irq_controller_unsubscribe_irq( + common_data->bus_irq_controller, + wm_res->irq_handle); + + 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) +{ + int32_t rc; + int i; + struct cam_isp_resource_node *wm_res = NULL; + struct cam_vfe_bus_ver2_wm_resource_data *rsrc_data = NULL; + struct cam_vfe_bus_irq_evt_payload *evt_payload; + + wm_res = th_payload->handler_priv; + if (!wm_res) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "Error: No resource"); + return -ENODEV; + } + + rsrc_data = wm_res->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]); + + rc = cam_vfe_bus_get_evt_payload(rsrc_data->common_data, &evt_payload); + if (rc) { + 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->ctx = rsrc_data->ctx; + 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_wm_done_bottom_half(void *wm_node, + void *evt_payload_priv) +{ + int rc = CAM_VFE_IRQ_STATUS_ERR; + struct cam_isp_resource_node *wm_res = wm_node; + 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 || !rsrc_data) + return rc; + + 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; + } + CAM_DBG(CAM_ISP, "status_reg %x rc %d", status_reg, rc); + + if (rc == CAM_VFE_IRQ_STATUS_SUCCESS) + cam_vfe_bus_put_evt_payload(rsrc_data->common_data, + &evt_payload); + + return rc; +} + +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 = cam_vfe_bus_start_wm; + wm_res->stop = cam_vfe_bus_stop_wm; + 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_info *out_port_info, + void *tasklet, + void *ctx, + 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->ctx = ctx; + 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) +{ + 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; + uint32_t bus_irq_reg_mask[CAM_VFE_BUS_IRQ_MAX] = {0}; + struct cam_irq_bh_api irq_bh_api; + + 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)); + } + + /* + * For Dual composite subscribe IRQ only for master + * For regular composite, subscribe IRQ always + */ + CAM_DBG(CAM_ISP, "Subscribe COMP_GRP%d IRQ", rsrc_data->comp_grp_type); + 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) && + (rsrc_data->is_master)) || + (rsrc_data->comp_grp_type >= CAM_VFE_BUS_VER2_COMP_GRP_0 && + rsrc_data->comp_grp_type <= CAM_VFE_BUS_VER2_COMP_GRP_5)) { + irq_bh_api.bottom_half_enqueue_func = cam_tasklet_enqueue_cmd; + irq_bh_api.get_bh_payload_func = cam_tasklet_get_cmd; + irq_bh_api.put_bh_payload_func = cam_tasklet_put_cmd; + comp_grp->irq_handle = cam_irq_controller_subscribe_irq( + common_data->bus_irq_controller, CAM_IRQ_PRIORITY_1, + bus_irq_reg_mask, comp_grp, + comp_grp->top_half_handler, + cam_ife_mgr_do_tasklet_buf_done, + comp_grp->tasklet_info, &irq_bh_api); + if (comp_grp->irq_handle < 0) { + CAM_ERR(CAM_ISP, "Subscribe IRQ failed for comp_grp %d", + rsrc_data->comp_grp_type); + return -EFAULT; + } + } + 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; + 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; + + /* Unsubscribe IRQ */ + 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) && + (rsrc_data->is_master)) || + (rsrc_data->comp_grp_type >= CAM_VFE_BUS_VER2_COMP_GRP_0 && + rsrc_data->comp_grp_type <= CAM_VFE_BUS_VER2_COMP_GRP_5)) { + rc = cam_irq_controller_unsubscribe_irq( + common_data->bus_irq_controller, + comp_grp->irq_handle); + } + 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) +{ + int32_t rc; + int i; + struct cam_isp_resource_node *comp_grp = NULL; + struct cam_vfe_bus_ver2_comp_grp_data *rsrc_data = NULL; + struct cam_vfe_bus_irq_evt_payload *evt_payload; + + comp_grp = th_payload->handler_priv; + if (!comp_grp) { + CAM_ERR_RATE_LIMIT(CAM_ISP, "No resource"); + return -ENODEV; + } + + rsrc_data = comp_grp->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->ctx = rsrc_data->ctx; + 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_comp_done_bottom_half( + void *handler_priv, + void *evt_payload_priv) +{ + 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 */ + 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)) { + rc = CAM_VFE_IRQ_STATUS_COMP_OWRT; + break; + } + + /* Regular Composite SUCCESS */ + if (status_reg & BIT(comp_grp_id + 5)) { + rsrc_data->irq_trigger_cnt++; + if (rsrc_data->irq_trigger_cnt == + rsrc_data->acquire_dev_cnt) { + cam_ife_irq_regs[CAM_IFE_IRQ_BUS_REG_STATUS0] &= + ~BIT(comp_grp_id + 5); + rsrc_data->irq_trigger_cnt = 0; + } + 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 */ + 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)) { + rc = CAM_VFE_IRQ_STATUS_COMP_OWRT; + break; + } + + /* DUAL Composite SUCCESS */ + if (status_reg & BIT(comp_grp_id)) { + rsrc_data->irq_trigger_cnt++; + if (rsrc_data->irq_trigger_cnt == + rsrc_data->acquire_dev_cnt) { + cam_ife_irq_regs[CAM_IFE_IRQ_BUS_REG_STATUS2] &= + ~BIT(comp_grp_id); + rsrc_data->irq_trigger_cnt = 0; + } + 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; + } + + if (rc == CAM_VFE_IRQ_STATUS_SUCCESS) + cam_vfe_bus_put_evt_payload(rsrc_data->common_data, + &evt_payload); + + 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 = cam_vfe_bus_start_comp_grp; + comp_grp->stop = cam_vfe_bus_stop_comp_grp; + comp_grp->top_half_handler = cam_vfe_bus_handle_comp_done_top_half; + comp_grp->bottom_half_handler = + cam_vfe_bus_handle_comp_done_bottom_half; + 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 subscribe_irq; + 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; + 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); + + 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->ctx, + 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; + } + + subscribe_irq = 0; + } else { + subscribe_irq = 1; + } + + /* 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, + out_acquire_args->ctx, + vfe_out_res_id, + i, + subscribe_irq, + &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; + + 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; + } + + for (i = 0; i < rsrc_data->num_wm; i++) + rc = cam_vfe_bus_start_wm(rsrc_data->wm_res[i]); + + if (rsrc_data->comp_grp) + rc = cam_vfe_bus_start_comp_grp(rsrc_data->comp_grp); + + 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; + + if (!vfe_out) { + CAM_ERR(CAM_ISP, "Invalid input"); + return -EINVAL; + } + + rsrc_data = vfe_out->res_priv; + + 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]); + + 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) +{ + return -EPERM; +} + +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; + + CAM_DBG(CAM_ISP, "vfe_out %d", rsrc_data->out_type); + /* + * 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 = rsrc_data->comp_grp->bottom_half_handler( + rsrc_data->comp_grp, evt_payload_priv); + } else { + rc = rsrc_data->wm_res[0]->bottom_half_handler( + rsrc_data->wm_res[0], evt_payload_priv); + } + + 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; + + 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->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 (IRQ_HANDLED == rc) ? 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; + struct cam_vfe_bus_ver2_priv *bus_priv = + th_payload->handler_priv; + + 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); + + /* Returning error stops from enqueuing bottom half */ + return -EFAULT; +} + +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; + uint32_t *reg_val_pair; + uint32_t i, j, size = 0; + uint32_t frame_inc = 0, ubwc_bw_limit = 0, camera_hw_version, val; + int rc = 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 %lu", + j, MAX_REG_VAL_PAIR_SIZE); + return -ENOMEM; + } + + wm_data = vfe_out_data->wm_res[i]->res_priv; + + /* 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->packer_cfg != + io_cfg->planes[i].packer_config || + !wm_data->init_cfg_done) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->packer_cfg, + io_cfg->planes[i].packer_config); + wm_data->packer_cfg = + io_cfg->planes[i].packer_config; + 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, + wm_data->hw_regs->ubwc_regs->tile_cfg, + wm_data->tile_cfg); + } else if ((wm_data->tile_cfg != + io_cfg->planes[i].tile_config) + || !wm_data->init_cfg_done) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->ubwc_regs->tile_cfg, + io_cfg->planes[i].tile_config); + wm_data->tile_cfg = + io_cfg->planes[i].tile_config; + CAM_DBG(CAM_ISP, "WM %d tile cfg 0x%x", + wm_data->index, reg_val_pair[j-1]); + } + + if (wm_data->is_dual) { + if ((wm_data->h_init != wm_data->offset) || + !wm_data->init_cfg_done) { + /* + * For dual ife h init value need to + * take from offset. Striping config + * update offset value. + */ + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, + j, + wm_data->hw_regs->ubwc_regs-> + h_init, wm_data->offset); + wm_data->h_init = wm_data->offset; + } + } else if (wm_data->h_init != + io_cfg->planes[i].h_init || + !wm_data->init_cfg_done) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->ubwc_regs->h_init, + io_cfg->planes[i].h_init); + wm_data->h_init = io_cfg->planes[i].h_init; + CAM_DBG(CAM_ISP, "WM %d h_init 0x%x", + wm_data->index, reg_val_pair[j-1]); + } + + if (wm_data->v_init != io_cfg->planes[i].v_init || + !wm_data->init_cfg_done) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->ubwc_regs->v_init, + io_cfg->planes[i].v_init); + wm_data->v_init = io_cfg->planes[i].v_init; + CAM_DBG(CAM_ISP, "WM %d v_init 0x%x", + wm_data->index, reg_val_pair[j-1]); + } + + if (wm_data->ubwc_meta_stride != + io_cfg->planes[i].meta_stride || + !wm_data->init_cfg_done) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->ubwc_regs-> + meta_stride, + io_cfg->planes[i].meta_stride); + wm_data->ubwc_meta_stride = + io_cfg->planes[i].meta_stride; + CAM_DBG(CAM_ISP, "WM %d meta stride 0x%x", + wm_data->index, reg_val_pair[j-1]); + } + + if (wm_data->ubwc_mode_cfg != + io_cfg->planes[i].mode_config || + !wm_data->init_cfg_done) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->ubwc_regs->mode_cfg, + io_cfg->planes[i].mode_config); + wm_data->ubwc_mode_cfg = + io_cfg->planes[i].mode_config; + CAM_DBG(CAM_ISP, "WM %d ubwc mode cfg 0x%x", + wm_data->index, reg_val_pair[j-1]); + } + + if (wm_data->ubwc_meta_offset != + io_cfg->planes[i].meta_offset || + !wm_data->init_cfg_done) { + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->ubwc_regs-> + meta_offset, + io_cfg->planes[i].meta_offset); + wm_data->ubwc_meta_offset = + io_cfg->planes[i].meta_offset; + CAM_DBG(CAM_ISP, "WM %d ubwc meta offset 0x%x", + wm_data->index, reg_val_pair[j-1]); + } + + /* UBWC meta address */ + CAM_VFE_ADD_REG_VAL_PAIR(reg_val_pair, j, + wm_data->hw_regs->ubwc_regs->meta_addr, + 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]); + + /* Enable UBWC bandwidth limit if required */ + rc = cam_cpas_get_cpas_hw_version(&camera_hw_version); + if (camera_hw_version == CAM_CPAS_TITAN_170_V110 + && !rc) { + 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, + wm_data->hw_regs->ubwc_regs->bw_limit, + ubwc_bw_limit); + CAM_DBG(CAM_ISP, "WM %d ubwc bw limit 0x%x", + wm_data->index, ubwc_bw_limit); + } + } + + /* WM Image address */ + 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)); + 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); + CAM_DBG(CAM_ISP, "WM %d image address 0x%x", + wm_data->index, reg_val_pair[j-1]); + + 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; + } + + 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 %lu", + j, MAX_REG_VAL_PAIR_SIZE); + return -ENOMEM; + } + + wm_data = vfe_out_data->wm_res[i]->res_priv; + + 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_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; + } + + 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 <= 0) { + CAM_ERR(CAM_ISP, "Failed to subscribe BUS IRQ"); + return -EFAULT; + } + + 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, + NULL, + NULL, + NULL); + + if (bus_priv->irq_handle <= 0) { + CAM_ERR(CAM_ISP, "Failed to subscribe BUS IRQ"); + return -EFAULT; + } + + /* 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); + + 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; + + 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); + if (rc) + CAM_ERR(CAM_ISP, + "Failed to unsubscribe error irq rc=%d", rc); + + 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); + if (rc) + CAM_ERR(CAM_ISP, + "Failed to unsubscribe irq rc=%d", rc); + + 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; + 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_INFO(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); + if (rc) + CAM_ERR(CAM_ISP, + "Failed to unsubscribe error irq rc=%d", + rc); + + bus_priv->error_irq_handle = 0; + } + 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; + + 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); + 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; + } + } + + 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; + + 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; + } + + 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); + + 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/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h new file mode 100644 index 000000000000..5a12f745e328 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.h @@ -0,0 +1,210 @@ +/* Copyright (c) 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. + */ + +#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 20 + +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_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; +}; + +/* + * 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; + 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; + struct cam_vfe_bus_ver2_reg_offset_ubwc_client *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/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/include/cam_vfe_bus.h b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/include/cam_vfe_bus.h new file mode 100644 index 000000000000..0763bca8bd0d --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/include/cam_vfe_bus.h @@ -0,0 +1,85 @@ +/* Copyright (c) 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. + */ + +#ifndef _CAM_VFE_BUS_H_ +#define _CAM_VFE_BUS_H_ + +#include +#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 + +enum cam_vfe_bus_plane_type { + PLANE_Y, + PLANE_C, + PLANE_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 + * @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, + 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/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/Makefile b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/Makefile new file mode 100644 index 000000000000..7bb43577a594 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/Makefile @@ -0,0 +1,13 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_utils/ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_cdm/ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_core/ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_cpas/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/irq_controller +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_vfe_top.o cam_vfe_top_ver2.o cam_vfe_camif_ver2.o cam_vfe_rdi.o diff --git a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c new file mode 100644 index 000000000000..734cbdb3d4e5 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.c @@ -0,0 +1,503 @@ +/* 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. + */ + +#include +#include +#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_camif_ver2.h" +#include "cam_debug_util.h" +#include "cam_cdm_util.h" +#include "cam_cpas_api.h" + +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; + + 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; +}; + +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; + + 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; + + 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; + + /*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 with 20 line */ + cam_io_w_mb(rsrc_data->reg_data->epoch_line_cfg, + rsrc_data->mem_base + rsrc_data->camif_reg->epoch_irq); + + 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, "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; + int rc = 0, i; + 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; + soc_private = camif_priv->soc_info->soc_private; + for (i = 0xA3C; i <= 0xA90; i += 4) { + val = cam_io_r_mb(camif_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(camif_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(camif_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(camif_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(camif_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_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; + + return rc; +} + +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; + + 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_GET_REG_DUMP: + rc = cam_vfe_camif_reg_dump(rsrc_node); + 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) +{ + return -EPERM; +} + +static int cam_vfe_camif_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_data *camif_priv; + struct cam_vfe_top_irq_evt_payload *payload; + uint32_t irq_status0; + uint32_t irq_status1; + + 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]; + + CAM_DBG(CAM_ISP, "event ID:%d", payload->evt_id); + CAM_DBG(CAM_ISP, "irq_status_0 = %x", irq_status0); + + switch (payload->evt_id) { + case CAM_ISP_HW_EVENT_SOF: + if (irq_status0 & camif_priv->reg_data->sof_irq_mask) { + CAM_DBG(CAM_ISP, "Received SOF"); + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + } + break; + case CAM_ISP_HW_EVENT_EPOCH: + if (irq_status0 & camif_priv->reg_data->epoch0_irq_mask) { + CAM_DBG(CAM_ISP, "Received EPOCH"); + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + } + break; + case CAM_ISP_HW_EVENT_REG_UPDATE: + if (irq_status0 & camif_priv->reg_data->reg_update_irq_mask) { + CAM_DBG(CAM_ISP, "Received REG_UPDATE_ACK"); + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + } + break; + case CAM_ISP_HW_EVENT_EOF: + if (irq_status0 & camif_priv->reg_data->eof_irq_mask) { + CAM_DBG(CAM_ISP, "Received EOF\n"); + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + } + break; + case CAM_ISP_HW_EVENT_ERROR: + if (irq_status1 & camif_priv->reg_data->error_irq_mask1) { + CAM_DBG(CAM_ISP, "Received ERROR\n"); + ret = CAM_ISP_HW_ERROR_OVERFLOW; + cam_vfe_camif_reg_dump(camif_node); + } else { + ret = CAM_ISP_HW_ERROR_NONE; + } + break; + default: + break; + } + + CAM_DBG(CAM_ISP, "returing 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) +{ + struct cam_vfe_mux_camif_data *camif_priv = NULL; + struct cam_vfe_camif_ver2_hw_info *camif_info = camif_hw_info; + + 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_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; + + 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; + + 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/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.h b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.h new file mode 100644 index 000000000000..4a73bd74c097 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_camif_ver2.h @@ -0,0 +1,87 @@ +/* Copyright (c) 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. + */ + +#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; +}; + +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; +}; + +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); + +int cam_vfe_camif_ver2_deinit( + struct cam_isp_resource_node *camif_node); + +#endif /* _CAM_VFE_CAMIF_VER2_H_ */ diff --git a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c new file mode 100644 index 000000000000..0423e22cda4a --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.c @@ -0,0 +1,301 @@ +/* Copyright (c) 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. + */ + +#include +#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_io_util.h" +#include "cam_debug_util.h" +#include "cam_cdm_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_reg_data *reg_data; + + enum cam_isp_hw_sync_mode sync_mode; +}; + +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->sync_mode = acquire_data->vfe_in.sync_mode; + + 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; + + 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; + 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); + + CAM_DBG(CAM_ISP, "Start RDI %d", + rdi_res->res_id - CAM_ISP_HW_VFE_IN_RDI0); + + 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; + + + 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) +{ + return -EPERM; +} + +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; + 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]; + + CAM_DBG(CAM_ISP, "event ID:%d", payload->evt_id); + CAM_DBG(CAM_ISP, "irq_status_0 = %x", irq_status0); + + switch (payload->evt_id) { + case CAM_ISP_HW_EVENT_SOF: + if (irq_status0 & rdi_priv->reg_data->sof_irq_mask) { + CAM_DBG(CAM_ISP, "Received SOF"); + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + } + break; + case CAM_ISP_HW_EVENT_REG_UPDATE: + if (irq_status0 & rdi_priv->reg_data->reg_update_irq_mask) { + CAM_DBG(CAM_ISP, "Received REG UPDATE"); + ret = CAM_VFE_IRQ_STATUS_SUCCESS; + } + break; + default: + break; + } + + 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) +{ + struct cam_vfe_mux_rdi_data *rdi_priv = NULL; + struct cam_vfe_rdi_ver2_hw_info *rdi_info = rdi_hw_info; + + 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; + + 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; + + 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; + + 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/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.h b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.h new file mode 100644 index 000000000000..32a67c45ee28 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_rdi.h @@ -0,0 +1,50 @@ +/* Copyright (c) 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. + */ + +#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 + +struct cam_vfe_rdi_ver2_reg { + uint32_t reg_update_cmd; +}; + +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_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); + +int cam_vfe_rdi_ver2_deinit( + struct cam_isp_resource_node *rdi_node); + +#endif /* _CAM_VFE_RDI_H_ */ diff --git a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top.c b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top.c new file mode 100644 index 000000000000..8eb183568adb --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top.c @@ -0,0 +1,54 @@ +/* Copyright (c) 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. + */ + +#include "cam_vfe_top.h" +#include "cam_vfe_top_ver2.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, + 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_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; + default: + CAM_ERR(CAM_ISP, "Error! Unsupported Version %x", top_version); + break; + } + + return rc; +} + diff --git a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c new file mode 100644 index 000000000000..976e6d2dcbb6 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.c @@ -0,0 +1,834 @@ +/* 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. + */ + +#include +#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_cpas_api.h" +#include "cam_vfe_soc.h" + +#define CAM_VFE_HW_RESET_HW_AND_REG_VAL 0x00003F9F +#define CAM_VFE_HW_RESET_HW_VAL 0x00003F87 +#define CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES 3 + +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; + struct cam_isp_resource_node mux_rsrc[CAM_VFE_TOP_VER2_MUX_MAX]; + unsigned long hw_clk_rate; + struct cam_axi_vote to_be_applied_axi_vote; + struct cam_axi_vote applied_axi_vote; + uint32_t counter_to_update_axi_vote; + struct cam_axi_vote req_axi_vote[CAM_VFE_TOP_VER2_MUX_MAX]; + unsigned long req_clk_rate[CAM_VFE_TOP_VER2_MUX_MAX]; + enum cam_vfe_bw_control_action + axi_vote_control[CAM_VFE_TOP_VER2_MUX_MAX]; +}; + +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 < CAM_VFE_TOP_VER2_MUX_MAX; 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_ISP, "VFE: Clock name=%s idx=%d clk=%lld", + soc_info->clk_name[soc_info->src_clk_idx], + soc_info->src_clk_idx, max_clk_rate); + + rc = cam_soc_util_set_clk_rate( + soc_info->clk[soc_info->src_clk_idx], + soc_info->clk_name[soc_info->src_clk_idx], + max_clk_rate); + + if (!rc) + top_priv->hw_clk_rate = max_clk_rate; + else + CAM_ERR(CAM_ISP, "Set Clock rate failed, rc=%d", rc); + + return rc; +} + +static int cam_vfe_top_set_axi_bw_vote( + struct cam_vfe_top_ver2_priv *top_priv, + bool start_stop) +{ + struct cam_axi_vote sum = {0, 0}; + int i, rc = 0; + struct cam_hw_soc_info *soc_info = + top_priv->common_data.soc_info; + struct cam_vfe_soc_private *soc_private = + soc_info->soc_private; + bool apply_bw_update = false; + + if (!soc_private) { + CAM_ERR(CAM_ISP, "Error soc_private NULL"); + return -EINVAL; + } + + for (i = 0; i < CAM_VFE_TOP_VER2_MUX_MAX; i++) { + if (top_priv->axi_vote_control[i] == + CAM_VFE_BW_CONTROL_INCLUDE) { + sum.uncompressed_bw += + top_priv->req_axi_vote[i].uncompressed_bw; + sum.compressed_bw += + top_priv->req_axi_vote[i].compressed_bw; + } + } + + CAM_DBG(CAM_ISP, "Updating BW from (%llu %llu) to (%llu %llu)", + top_priv->applied_axi_vote.uncompressed_bw, + top_priv->applied_axi_vote.compressed_bw, + sum.uncompressed_bw, + sum.compressed_bw); + + if ((top_priv->applied_axi_vote.uncompressed_bw == + sum.uncompressed_bw) && + (top_priv->applied_axi_vote.compressed_bw == + sum.compressed_bw)) { + CAM_DBG(CAM_ISP, "BW config unchanged %llu %llu", + top_priv->applied_axi_vote.uncompressed_bw, + top_priv->applied_axi_vote.compressed_bw); + top_priv->counter_to_update_axi_vote = 0; + return 0; + } + + if ((top_priv->to_be_applied_axi_vote.uncompressed_bw != + sum.uncompressed_bw) || + (top_priv->to_be_applied_axi_vote.compressed_bw != + sum.compressed_bw)) { + // we got a new bw value to apply + top_priv->counter_to_update_axi_vote = 0; + + top_priv->to_be_applied_axi_vote.uncompressed_bw = + sum.uncompressed_bw; + top_priv->to_be_applied_axi_vote.compressed_bw = + sum.compressed_bw; + } + + if (start_stop == true) { + CAM_DBG(CAM_ISP, + "New bw in start/stop, applying bw now, counter=%d", + top_priv->counter_to_update_axi_vote); + top_priv->counter_to_update_axi_vote = 0; + apply_bw_update = true; + } else if ((top_priv->to_be_applied_axi_vote.uncompressed_bw < + top_priv->applied_axi_vote.uncompressed_bw) || + (top_priv->to_be_applied_axi_vote.compressed_bw < + top_priv->applied_axi_vote.compressed_bw)) { + if (top_priv->counter_to_update_axi_vote >= + (CAM_VFE_TOP_VER2_MUX_MAX * + CAM_VFE_DELAY_BW_REDUCTION_NUM_FRAMES)) { + CAM_DBG(CAM_ISP, + "New bw is less, applying bw now, counter=%d", + top_priv->counter_to_update_axi_vote); + top_priv->counter_to_update_axi_vote = 0; + apply_bw_update = true; + } else { + CAM_DBG(CAM_ISP, + "New bw is less, Defer applying bw, counter=%d", + top_priv->counter_to_update_axi_vote); + + top_priv->counter_to_update_axi_vote++; + apply_bw_update = false; + } + } else { + CAM_DBG(CAM_ISP, + "New bw is more, applying bw now, counter=%d", + top_priv->counter_to_update_axi_vote); + top_priv->counter_to_update_axi_vote = 0; + apply_bw_update = true; + } + + CAM_DBG(CAM_ISP, + "counter=%d, apply_bw_update=%d", + top_priv->counter_to_update_axi_vote, + apply_bw_update); + + if (apply_bw_update == true) { + rc = cam_cpas_update_axi_vote( + soc_private->cpas_handle, + &top_priv->to_be_applied_axi_vote); + if (!rc) { + top_priv->applied_axi_vote.uncompressed_bw = + top_priv-> + to_be_applied_axi_vote.uncompressed_bw; + top_priv->applied_axi_vote.compressed_bw = + top_priv-> + to_be_applied_axi_vote.compressed_bw; + } else { + CAM_ERR(CAM_ISP, "BW request failed, rc=%d", rc); + } + top_priv->counter_to_update_axi_vote = 0; + } + + return rc; +} + +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_ISP, "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_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 < CAM_VFE_TOP_VER2_MUX_MAX; i++) { + if (top_priv->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_ERR_RATE_LIMIT(CAM_ISP, + "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_bw_update( + struct cam_vfe_top_ver2_priv *top_priv, + 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; + + bw_update = (struct cam_vfe_bw_update_args *)cmd_args; + res = bw_update->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 < CAM_VFE_TOP_VER2_MUX_MAX; i++) { + if (top_priv->mux_rsrc[i].res_id == res->res_id) { + top_priv->req_axi_vote[i].uncompressed_bw = + bw_update->camnoc_bw_bytes; + top_priv->req_axi_vote[i].compressed_bw = + bw_update->external_bw_bytes; + top_priv->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_ISP, + "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(top_priv, false); + + return rc; +} + +static int cam_vfe_top_bw_control( + struct cam_vfe_top_ver2_priv *top_priv, + 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 < CAM_VFE_TOP_VER2_MUX_MAX; i++) { + if (top_priv->mux_rsrc[i].res_id == res->res_id) { + top_priv->axi_vote_control[i] = bw_ctrl->action; + break; + } + } + + if (hw_info->hw_state != CAM_HW_STATE_POWER_UP) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "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(top_priv, true); + } + + 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) +{ + return -EPERM; +} + +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 < CAM_VFE_TOP_VER2_MUX_MAX; i++) { + if (top_priv->mux_rsrc[i].res_id == acquire_args->res_id && + top_priv->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->mux_rsrc[i], + args); + if (rc) + break; + } + + top_priv->mux_rsrc[i].cdm_ops = acquire_args->cdm_ops; + top_priv->mux_rsrc[i].tasklet_info = args->tasklet; + top_priv->mux_rsrc[i].res_state = + CAM_ISP_RESOURCE_STATE_RESERVED; + acquire_args->rsrc_node = + &top_priv->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; + 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; + 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(top_priv, 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_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 < CAM_VFE_TOP_VER2_MUX_MAX; i++) { + if (top_priv->mux_rsrc[i].res_id == mux_res->res_id) { + top_priv->req_clk_rate[i] = 0; + top_priv->req_axi_vote[i].compressed_bw = 0; + top_priv->req_axi_vote[i].uncompressed_bw = 0; + top_priv->axi_vote_control[i] = + CAM_VFE_BW_CONTROL_EXCLUDE; + break; + } + } + + 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; + } + + top_priv->hw_clk_rate = 0; + + rc = cam_vfe_top_set_axi_bw_vote(top_priv, true); + if (rc) { + CAM_ERR(CAM_ISP, + "set_axi_bw_vote failed, rc=%d", rc); + return rc; + } + } else { + CAM_ERR(CAM_ISP, "VFE HW not powered up"); + rc = -EPERM; + } + } + + 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; + + if (!device_priv || !cmd_args) { + CAM_ERR(CAM_ISP, "Error! Invalid arguments"); + return -EINVAL; + } + top_priv = (struct cam_vfe_top_ver2_priv *)device_priv; + + 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_BW_UPDATE: + rc = cam_vfe_top_bw_update(top_priv, cmd_args, + arg_size); + break; + case CAM_ISP_HW_CMD_BW_CONTROL: + rc = cam_vfe_top_bw_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_ver2_init( + struct cam_hw_soc_info *soc_info, + struct cam_hw_intf *hw_intf, + void *top_hw_info, + 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; + top_priv->to_be_applied_axi_vote.compressed_bw = 0; + top_priv->to_be_applied_axi_vote.uncompressed_bw = 0; + top_priv->applied_axi_vote.compressed_bw = 0; + top_priv->applied_axi_vote.uncompressed_bw = 0; + top_priv->counter_to_update_axi_vote = 0; + + for (i = 0, j = 0; i < CAM_VFE_TOP_VER2_MUX_MAX; i++) { + top_priv->mux_rsrc[i].res_type = CAM_ISP_RESOURCE_VFE_IN; + top_priv->mux_rsrc[i].hw_intf = hw_intf; + top_priv->mux_rsrc[i].res_state = + CAM_ISP_RESOURCE_STATE_AVAILABLE; + top_priv->req_clk_rate[i] = 0; + top_priv->req_axi_vote[i].compressed_bw = 0; + top_priv->req_axi_vote[i].uncompressed_bw = 0; + top_priv->axi_vote_control[i] = CAM_VFE_BW_CONTROL_EXCLUDE; + + + if (ver2_hw_info->mux_type[i] == CAM_VFE_CAMIF_VER_2_0) { + top_priv->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->mux_rsrc[i]); + if (rc) + goto deinit_resources; + } else { + /* set the RDI resource id */ + top_priv->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->mux_rsrc[i]); + if (rc) + goto deinit_resources; + } + } + + 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->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->mux_rsrc[i])) + CAM_ERR(CAM_ISP, "Camif Deinit failed"); + } else { + if (cam_vfe_rdi_ver2_deinit(&top_priv->mux_rsrc[i])) + CAM_ERR(CAM_ISP, "RDI Deinit failed"); + } + top_priv->mux_rsrc[i].res_state = + CAM_ISP_RESOURCE_STATE_UNAVAILABLE; + } + + 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 < CAM_VFE_TOP_VER2_MUX_MAX; i++) { + top_priv->mux_rsrc[i].res_state = + CAM_ISP_RESOURCE_STATE_UNAVAILABLE; + if (top_priv->mux_rsrc[i].res_id == + CAM_ISP_HW_VFE_IN_CAMIF) { + rc = cam_vfe_camif_ver2_deinit(&top_priv->mux_rsrc[i]); + if (rc) + CAM_ERR(CAM_ISP, "Camif deinit failed rc=%d", + rc); + } else { + rc = cam_vfe_rdi_ver2_deinit(&top_priv->mux_rsrc[i]); + if (rc) + CAM_ERR(CAM_ISP, "RDI 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/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h new file mode 100644 index 000000000000..bafd7f2badac --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/cam_vfe_top_ver2.h @@ -0,0 +1,66 @@ +/* Copyright (c) 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. + */ + +#ifndef _CAM_VFE_TOP_VER2_H_ +#define _CAM_VFE_TOP_VER2_H_ + +#include "cam_vfe_camif_ver2.h" +#include "cam_vfe_rdi.h" + +#define CAM_VFE_TOP_VER2_MUX_MAX 4 + +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_rdi_ver2_hw_info rdi_hw_info; + uint32_t mux_type[CAM_VFE_TOP_VER2_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, + struct cam_vfe_top **vfe_top); + +int cam_vfe_top_ver2_deinit(struct cam_vfe_top **vfe_top); + +#endif /* _CAM_VFE_TOP_VER2_H_ */ diff --git a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/include/cam_vfe_top.h b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/include/cam_vfe_top.h new file mode 100644 index 000000000000..81e3b481ecfa --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_top/include/cam_vfe_top.h @@ -0,0 +1,41 @@ +/* Copyright (c) 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. + */ + +#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_CAMIF_VER_1_0 0x10 +#define CAM_VFE_CAMIF_VER_2_0 0x20 + +#define CAM_VFE_RDI_VER_1_0 0x1000 + +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, + 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/drivers/media/platform/msm/camera_oneplus/cam_jpeg/Makefile b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/Makefile new file mode 100644 index 000000000000..0d6ed7d3fdfe --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/Makefile @@ -0,0 +1,11 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_req_mgr +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_utils +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_sync +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_core +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_smmu +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_cpas/include/ + +obj-$(CONFIG_SPECTRA_CAMERA) += jpeg_hw/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_jpeg_dev.o cam_jpeg_context.o diff --git a/drivers/media/platform/msm/camera_oneplus/cam_jpeg/cam_jpeg_context.c b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/cam_jpeg_context.c new file mode 100644 index 000000000000..02334a4e8195 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/cam_jpeg_context.c @@ -0,0 +1,169 @@ +/* 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. + */ + +#include +#include +#include +#include + +#include "cam_mem_mgr.h" +#include "cam_sync_api.h" +#include "cam_jpeg_context.h" +#include "cam_context_utils.h" +#include "cam_debug_util.h" + +static const char jpeg_dev_name[] = "jpeg"; + +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, + }, +}; + +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/drivers/media/platform/msm/camera_oneplus/cam_jpeg/cam_jpeg_context.h b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/cam_jpeg_context.h new file mode 100644 index 000000000000..1a406793181b --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/cam_jpeg_context.h @@ -0,0 +1,74 @@ +/* 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_JPEG_CONTEXT_H_ +#define _CAM_JPEG_CONTEXT_H_ + +#include + +#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/drivers/media/platform/msm/camera_oneplus/cam_jpeg/cam_jpeg_dev.c b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/cam_jpeg_dev.c new file mode 100644 index 000000000000..60feeacde477 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/cam_jpeg_dev.c @@ -0,0 +1,157 @@ +/* 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. + */ + +#include +#include +#include +#include +#include +#include + +#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" + +#define CAM_JPEG_DEV_NAME "cam-jpeg" + +static struct cam_jpeg_dev g_jpeg_dev; + +static const struct of_device_id cam_jpeg_dt_match[] = { + { + .compatible = "qcom,cam-jpeg" + }, + { } +}; + +static int cam_jpeg_subdev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + struct cam_node *node = v4l2_get_subdevdata(sd); + + if (!node) { + CAM_ERR(CAM_JPEG, "Node ptr is NULL"); + return -EINVAL; + } + + cam_node_shutdown(node); + + return 0; +} + +static const struct v4l2_subdev_internal_ops cam_jpeg_subdev_internal_ops = { + .close = cam_jpeg_subdev_close, +}; + +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; + + 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); + 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; + } + + 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, + }, +}; + +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/drivers/media/platform/msm/camera_oneplus/cam_jpeg/cam_jpeg_dev.h b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/cam_jpeg_dev.h new file mode 100644 index 000000000000..deab2d5c0d02 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/cam_jpeg_dev.h @@ -0,0 +1,37 @@ +/* Copyright (c) 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. + */ + +#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 + */ +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; +}; +#endif /* __CAM_JPEG_DEV_H__ */ diff --git a/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/Makefile b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/Makefile new file mode 100644 index 000000000000..ee6adb8c853c --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/Makefile @@ -0,0 +1,13 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_smmu/ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_core/ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_utils/ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_sync/ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_req_mgr/ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_cdm/ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_cpas/include/ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/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/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c new file mode 100644 index 000000000000..32f11a7f7833 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c @@ -0,0 +1,1477 @@ +/* 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cam_sync_api.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" + +#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; + 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; + uint32_t dev_type = 0; + uint64_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 %d 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 *)(uint64_t)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; + } + + rc = cam_mem_get_cpu_buf( + p_cfg_req->hw_cfg_args. + hw_update_entries[CAM_JPEG_PARAM].handle, + (uint64_t *)&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; + + 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 = + (uint64_t)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; + uint32_t dev_type; + struct cam_cdm_bl_request *cdm_cmd; + uint32_t size; + uint32_t mem_cam_base; + uint64_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; + } + 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; + uint64_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; + + 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 != (uint64_t)config_args->priv) { + CAM_DBG(CAM_JPEG, "not a recent req %lld %lld", + request_id, (uint64_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) { + 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 = + (uint64_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; + uint64_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 = (uint64_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 %lld", + ctx_data, request_id, (uint64_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 *)(int64_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 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); + 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->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 *)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 int cam_jpeg_mgr_flush(void *hw_mgr_priv, + struct cam_jpeg_hw_ctx_data *ctx_data) +{ + int rc = 0; + 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; + struct cam_jpeg_set_irq_cb irq_cb; + + 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) { + /* 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, + "CMD_SET_IRQ_CB failed %d", rc); + + } else { + CAM_ERR(CAM_JPEG, "process_cmd null "); + } + 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); + + 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 "); + } + + 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", + dev_type); + } else { + CAM_ERR(CAM_JPEG, "op deinit null"); + } + } + + hw_mgr->device_in_use[dev_type][0] = false; + p_cfg_req = hw_mgr->dev_hw_cfg_args[dev_type][0]; + hw_mgr->dev_hw_cfg_args[dev_type][0] = NULL; + } + + list_for_each_entry_safe(cfg_req, req_temp, + &hw_mgr->hw_config_req_list, list) { + if ((cfg_req) && ((struct cam_jpeg_hw_ctx_data *)cfg_req-> + hw_cfg_args.ctxt_to_hw_map != ctx_data)) + continue; + + list_del_init(&cfg_req->list); + } + + CAM_DBG(CAM_JPEG, "X: JPEG flush ctx with rc: %d", rc); + + return rc; +} + + +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, *req_temp; + int64_t request_id; + + 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 = *(int64_t *)flush_args->flush_req_active[0]; + list_for_each_entry_safe(cfg_req, req_temp, + &hw_mgr->hw_config_req_list, list) { + if ((cfg_req) && (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); + } + + 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); + CAM_ERR(CAM_JPEG, "Flush per request is not supported"); + 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"); + kfree(ctx_data->cdm_cmd); + 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); + return -EINVAL; + } + + kfree(ctx_data->cdm_cmd); + 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; + 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((void __user *)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, "cam_jpeg_mgr_get_hw_caps 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); + 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); + 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 = + (struct cam_jpeg_process_frame_work_data_t *) + 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 = + (struct cam_jpeg_process_irq_work_data_t *) + 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; +} + +int cam_jpeg_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_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; + + 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_smmu_ops(g_jpeg_hw_mgr.iommu_hdl, CAM_SMMU_ATTACH); + if (rc) { + CAM_ERR(CAM_JPEG, "jpeg attach failed: %d", rc); + goto jpeg_attach_failed; + } + + 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; + } + + return rc; + +cdm_iommu_failed: + cam_smmu_ops(g_jpeg_hw_mgr.iommu_hdl, CAM_SMMU_DETACH); + cam_smmu_destroy_handle(g_jpeg_hw_mgr.iommu_hdl); +jpeg_attach_failed: + 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/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.h b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.h new file mode 100644 index 000000000000..35e2fc1421ae --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.h @@ -0,0 +1,162 @@ +/* Copyright (c) 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. + */ + +#ifndef CAM_JPEG_HW_MGR_H +#define CAM_JPEG_HW_MGR_H + +#include +#include +#include + +#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; + uint64_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; + int64_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/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_intf.h b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_intf.h new file mode 100644 index 000000000000..44b134ae0340 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_intf.h @@ -0,0 +1,44 @@ +/* Copyright (c) 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. + */ + +#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/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_mgr_intf.h b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_mgr_intf.h new file mode 100644 index 000000000000..5fb4e3ad3399 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_mgr_intf.h @@ -0,0 +1,24 @@ +/* Copyright (c) 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. + */ + +#ifndef CAM_JPEG_HW_MGR_INTF_H +#define CAM_JPEG_HW_MGR_INTF_H + +#include +#include +#include + + +int cam_jpeg_hw_mgr_init(struct device_node *of_node, + uint64_t *hw_mgr_hdl); + +#endif /* CAM_JPEG_HW_MGR_INTF_H */ diff --git a/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_dma_hw/Makefile b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_dma_hw/Makefile new file mode 100644 index 000000000000..8d26d6ada557 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_dma_hw/Makefile @@ -0,0 +1,11 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_utils +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_req_mgr +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_core +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_cpas/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_jpeg +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_hw_mgr/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/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/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.c b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.c new file mode 100644 index 000000000000..2d343dd521c5 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.c @@ -0,0 +1,198 @@ +/* Copyright (c) 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#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; + 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_SVS_VOTE; + axi_vote.compressed_bw = JPEG_VOTE; + axi_vote.uncompressed_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/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.h b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.h new file mode 100644 index 000000000000..a4d5d89e705e --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.h @@ -0,0 +1,52 @@ +/* Copyright (c) 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. + */ + +#ifndef CAM_JPEG_DMA_CORE_H +#define CAM_JPEG_DMA_CORE_H + +#include +#include +#include +#include +#include + +#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/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_dev.c b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_dev.c new file mode 100644 index 000000000000..05ae7cc95ddf --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_dev.c @@ -0,0 +1,239 @@ +/* Copyright (c) 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. + */ + +#include +#include +#include +#include +#include + +#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, + }, +}; + +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/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_soc.c b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_soc.c new file mode 100644 index 000000000000..63d54fdf7d80 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_soc.c @@ -0,0 +1,63 @@ +/* Copyright (c) 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. + */ + +#include +#include +#include +#include +#include +#include + +#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/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_soc.h b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_soc.h new file mode 100644 index 000000000000..bc9bed868d59 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_soc.h @@ -0,0 +1,25 @@ +/* Copyright (c) 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. + */ + +#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/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_enc_hw/Makefile b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_enc_hw/Makefile new file mode 100644 index 000000000000..5c6619a4ee99 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_enc_hw/Makefile @@ -0,0 +1,11 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_utils +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_req_mgr +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_core +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_cpas/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_jpeg +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_hw_mgr/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/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/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_enc_hw/cam_jpeg_enc_hw_info_ver_4_2_0.h b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_enc_hw/cam_jpeg_enc_hw_info_ver_4_2_0.h new file mode 100644 index 000000000000..2ac4db6c0a46 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_enc_hw/cam_jpeg_enc_hw_info_ver_4_2_0.h @@ -0,0 +1,79 @@ +/* Copyright (c) 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. + */ + +#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 = 0x00032093, + .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/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c new file mode 100644 index 000000000000..934b911ad7c1 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c @@ -0,0 +1,432 @@ +/* Copyright (c) 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#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; + 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_SVS_VOTE; + axi_vote.compressed_bw = JPEG_VOTE; + axi_vote.uncompressed_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_unlock(&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/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.h b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.h new file mode 100644 index 000000000000..5fa8f21f6b23 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.h @@ -0,0 +1,87 @@ +/* Copyright (c) 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. + */ + +#ifndef CAM_JPEG_ENC_CORE_H +#define CAM_JPEG_ENC_CORE_H + +#include +#include +#include +#include +#include + +#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/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_dev.c b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_dev.c new file mode 100644 index 000000000000..21804486a338 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_dev.c @@ -0,0 +1,237 @@ +/* Copyright (c) 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. + */ + +#include +#include +#include +#include +#include + +#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, + }, +}; + +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/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_soc.c b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_soc.c new file mode 100644 index 000000000000..ddf246560534 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_soc.c @@ -0,0 +1,63 @@ +/* Copyright (c) 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. + */ + +#include +#include +#include +#include +#include +#include + +#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/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_soc.h b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_soc.h new file mode 100644 index 000000000000..a0485a2b9f0c --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_soc.h @@ -0,0 +1,25 @@ +/* Copyright (c) 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. + */ + +#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/drivers/media/platform/msm/camera_oneplus/cam_lrme/Makefile b/drivers/media/platform/msm/camera_oneplus/cam_lrme/Makefile new file mode 100644 index 000000000000..0caffc466834 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_lrme/Makefile @@ -0,0 +1,14 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_req_mgr +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_utils +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_sync +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_core +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_smmu +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_cdm +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_lrme +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/lrme_hw +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/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/drivers/media/platform/msm/camera_oneplus/cam_lrme/cam_lrme_context.c b/drivers/media/platform/msm/camera_oneplus/cam_lrme/cam_lrme_context.c new file mode 100644 index 000000000000..3d0266d6fb13 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_lrme/cam_lrme_context.c @@ -0,0 +1,255 @@ +/* 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. + */ + +#include +#include + +#include "cam_debug_util.h" +#include "cam_lrme_context.h" + +static const char lrme_dev_name[] = "lrme"; + +static int __cam_lrme_ctx_acquire_dev_in_available(struct cam_context *ctx, + struct cam_acquire_dev_cmd *cmd) +{ + int rc = 0; + uint64_t ctxt_to_hw_map = (uint64_t)ctx->ctxt_to_hw_map; + struct cam_lrme_context *lrme_ctx = ctx->ctx_priv; + + CAM_DBG(CAM_LRME, "Enter"); + + 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"); + + 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"); + + 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"); + + 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; + + 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"); + + 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"); + + 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 = { + .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, + }, + /* 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/drivers/media/platform/msm/camera_oneplus/cam_lrme/cam_lrme_context.h b/drivers/media/platform/msm/camera_oneplus/cam_lrme/cam_lrme_context.h new file mode 100644 index 000000000000..4c705c139405 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_lrme/cam_lrme_context.h @@ -0,0 +1,41 @@ +/* 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_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" +#include "cam_sync_api.h" + +#define CAM_LRME_CTX_INDEX_SHIFT 32 + +/** + * 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/drivers/media/platform/msm/camera_oneplus/cam_lrme/cam_lrme_dev.c b/drivers/media/platform/msm/camera_oneplus/cam_lrme/cam_lrme_dev.c new file mode 100644 index 000000000000..5be16ef6a174 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_lrme/cam_lrme_dev.c @@ -0,0 +1,233 @@ +/* Copyright (c) 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. + */ + +#include +#include +#include +#include +#include + +#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) +{ + 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); + lrme_dev->open_cnt--; + mutex_unlock(&lrme_dev->lock); + + if (!node) { + CAM_ERR(CAM_LRME, "Node is NULL"); + return -EINVAL; + } + + if (lrme_dev->open_cnt == 0) + cam_node_shutdown(node); + + return 0; +} + +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, + }, +}; + +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/drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/Makefile b/drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/Makefile new file mode 100644 index 000000000000..d11e2036d43a --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/Makefile @@ -0,0 +1,14 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_utils +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_req_mgr +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_core +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_sync +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_smmu +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_cdm +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_lrme +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/lrme_hw +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_cpas/include + +obj-$(CONFIG_SPECTRA_CAMERA) += lrme_hw/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_lrme_hw_mgr.o diff --git a/drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c b/drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c new file mode 100644 index 000000000000..4c93968b599c --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c @@ -0,0 +1,1116 @@ +/* Copyright (c) 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. + */ + +#include +#include +#include +#include + +#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) +{ + 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)) { + 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; + uint64_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); + + if ((num_in_buf > io_buf_size) || + (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; + } + + 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; + } + + io_addr[plane] += io_cfg[i].offsets[plane]; + + if (io_addr[plane] >> 32) { + CAM_ERR(CAM_LRME, "Invalid io addr for %d %d", + plane, rc); + return -ENOMEM; + } + + 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: { + 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: { + 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) = %lu, args->size = %d", + sizeof(struct cam_query_cap_cmd), args->size); + return -EFAULT; + } + + if (copy_to_user((void __user *)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; + uint64_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 %llu", 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 = ((uint64_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, "Invald 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, "Invald start function"); + return -EINVAL; + } + + 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); + 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; +} + +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); + 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_DBG(CAM_LRME, "Hw mgr init done"); + return rc; +} diff --git a/drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.h b/drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.h new file mode 100644 index 000000000000..f7ce4d23cb63 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.h @@ -0,0 +1,120 @@ +/* Copyright (c) 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. + */ + +#ifndef _CAM_LRME_HW_MGR_H_ +#define _CAM_LRME_HW_MGR_H_ + +#include +#include + +#include +#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) \ + ((uint64_t)ctxt_to_hw_map & 0xF) + +#define CAM_LRME_DECODE_PRIORITY(ctxt_to_hw_map) \ + (((uint64_t)ctxt_to_hw_map & 0xF0) >> 4) + +#define CAM_LRME_DECODE_CTX_INDEX(ctxt_to_hw_map) \ + ((uint64_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_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 + */ +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; +}; + +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/drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr_intf.h b/drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr_intf.h new file mode 100644 index 000000000000..8bb609cdb01b --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr_intf.h @@ -0,0 +1,25 @@ +/* Copyright (c) 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. + */ + +#ifndef _CAM_LRME_HW_MGR_INTF_H_ +#define _CAM_LRME_HW_MGR_INTF_H_ + +#include + +#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/drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/lrme_hw/Makefile b/drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/lrme_hw/Makefile new file mode 100644 index 000000000000..a40eb5d005d8 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/lrme_hw/Makefile @@ -0,0 +1,13 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_utils +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_req_mgr +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_core +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_sync +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_smmu +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_cdm +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_lrme +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/lrme_hw +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus0 +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/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/drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c b/drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c new file mode 100644 index 000000000000..21e66a2dbd39 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.c @@ -0,0 +1,1243 @@ +/* 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. + */ + +#include "cam_lrme_hw_core.h" +#include "cam_lrme_hw_soc.h" +#include "cam_smmu_api.h" + +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 */ + 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) + 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].meta_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_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; + + 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(0xFFFF, + soc_info->reg_map[0].mem_base + + hw_info->bus_wr_reg.common_reg.irq_mask_0); + cam_io_w_mb(0xFFFF, + soc_info->reg_map[0].mem_base + + hw_info->bus_wr_reg.common_reg.irq_mask_1); + cam_io_w_mb(0xFFFF, + 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 (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) { + 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); + goto unlock; + } + + 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); + return -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 %lu, 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, "Stop 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 -EINVAL; + } + + 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 -ENOMEM; + } + 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; + } + + default: + break; + } + + return rc; +} diff --git a/drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.h b/drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.h new file mode 100644 index 000000000000..bf2f37084cd1 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_core.h @@ -0,0 +1,457 @@ +/* Copyright (c) 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. + */ + +#ifndef _CAM_LRME_HW_CORE_H_ +#define _CAM_LRME_HW_CORE_H_ + +#include +#include +#include +#include +#include + +#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; +}; + +/** + * 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/drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c b/drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c new file mode 100644 index 000000000000..da42c84f3835 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c @@ -0,0 +1,321 @@ +/* Copyright (c) 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#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" + +#define CAM_LRME_HW_WORKQ_NUM_TASK 30 + +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); + 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_smmu_ops(lrme_core->device_iommu.non_secure, CAM_SMMU_ATTACH); + if (rc) { + CAM_ERR(CAM_LRME, "LRME attach iommu handle failed, rc=%d", rc); + goto destroy_smmu; + } + + 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_ops(lrme_core->device_iommu.non_secure, CAM_SMMU_DETACH); +destroy_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"); + rc = -ENODEV; + goto deinit_platform_res; + } + + 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_ops(lrme_core->device_iommu.non_secure, CAM_SMMU_DETACH); + 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, + }, +}; + +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/drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_intf.h b/drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_intf.h new file mode 100644 index 000000000000..d16b174767cc --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_intf.h @@ -0,0 +1,200 @@ +/* Copyright (c) 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. + */ + +#ifndef _CAM_LRME_HW_INTF_H_ +#define _CAM_LRME_HW_INTF_H_ + +#include +#include +#include +#include +#include +#include + +#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 + */ +enum cam_lrme_hw_cmd_type { + CAM_LRME_HW_CMD_PREPARE_HW_UPDATE, + CAM_LRME_HW_CMD_REGISTER_CB, + CAM_LRME_HW_CMD_SUBMIT, +}; + +/** + * 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/drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_reg.h b/drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_reg.h new file mode 100644 index 000000000000..39cfde724953 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_reg.h @@ -0,0 +1,193 @@ +/* Copyright (c) 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. + */ + +#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/drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_soc.c b/drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_soc.c new file mode 100644 index 000000000000..75de0ddbfd79 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_soc.c @@ -0,0 +1,158 @@ +/* Copyright (c) 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. + */ + +#include +#include +#include +#include +#include +#include + +#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; + int rc = 0; + + ahb_vote.type = CAM_VOTE_ABSOLUTE; + ahb_vote.vote.level = CAM_SVS_VOTE; + axi_vote.compressed_bw = 7200000; + axi_vote.uncompressed_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/drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_soc.h b/drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_soc.h new file mode 100644 index 000000000000..44e8486ecbe4 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_soc.h @@ -0,0 +1,28 @@ +/* Copyright (c) 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. + */ + +#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/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/Makefile b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/Makefile new file mode 100644 index 000000000000..1220a9b427c0 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/Makefile @@ -0,0 +1,11 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_core/ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_smmu/ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_utils + +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/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_mem_mgr.c b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_mem_mgr.c new file mode 100644 index 000000000000..643b0afce740 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_mem_mgr.c @@ -0,0 +1,1252 @@ +/* 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. + */ + +#include +#include +#include +#include +#include +#include + +#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 int cam_mem_util_map_cpu_va(struct ion_handle *hdl, + uint64_t *vaddr, + size_t *len) +{ + *vaddr = (uintptr_t)ion_map_kernel(tbl.client, hdl); + if (IS_ERR_OR_NULL((void *)*vaddr)) { + CAM_ERR(CAM_CRM, "kernel map fail"); + return -ENOSPC; + } + + if (ion_handle_get_size(tbl.client, hdl, len)) { + CAM_ERR(CAM_CRM, "kernel get len failed"); + ion_unmap_kernel(tbl.client, hdl); + return -ENOSPC; + } + + return 0; +} + +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_client_create(void) +{ + int rc = 0; + + tbl.client = msm_ion_client_create("camera_global_pool"); + if (IS_ERR_OR_NULL(tbl.client)) { + CAM_ERR(CAM_CRM, "fail to create client"); + rc = -EINVAL; + } + + return rc; +} + +static void cam_mem_util_client_destroy(void) +{ + ion_client_destroy(tbl.client); + tbl.client = NULL; +} + +int cam_mem_mgr_init(void) +{ + int rc; + int i; + int bitmap_size; + + memset(tbl.bufq, 0, sizeof(tbl.bufq)); + + rc = cam_mem_util_client_create(); + if (rc < 0) { + CAM_ERR(CAM_CRM, "fail to create ion client"); + goto client_fail; + } + + bitmap_size = BITS_TO_LONGS(CAM_MEM_BUFQ_MAX) * sizeof(long); + tbl.bitmap = kzalloc(bitmap_size, GFP_KERNEL); + if (!tbl.bitmap) { + rc = -ENOMEM; + goto bitmap_fail; + } + 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); + return rc; + +bitmap_fail: + cam_mem_util_client_destroy(); +client_fail: + return rc; +} + +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, + uint64_t *iova_ptr, size_t *len_ptr) +{ + int rc = 0, idx; + + 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 -EINVAL; + + 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 < 0) + CAM_ERR(CAM_CRM, "fail to get buf hdl :%d", buf_handle); + +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, uint64_t *vaddr_ptr, size_t *len) +{ + int rc = 0; + int idx; + struct ion_handle *ion_hdl = NULL; + uint64_t kvaddr = 0; + size_t klen = 0; + + 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; + + mutex_lock(&tbl.bufq[idx].q_lock); + if (buf_handle != tbl.bufq[idx].buf_handle) { + rc = -EINVAL; + goto exit_func; + } + + ion_hdl = tbl.bufq[idx].i_hdl; + if (!ion_hdl) { + CAM_ERR(CAM_CRM, "Invalid ION handle"); + rc = -EINVAL; + goto exit_func; + } + + if (tbl.bufq[idx].flags & CAM_MEM_FLAG_KMD_ACCESS) { + if (!tbl.bufq[idx].kmdvaddr) { + rc = cam_mem_util_map_cpu_va(ion_hdl, + &kvaddr, &klen); + if (rc) + goto exit_func; + tbl.bufq[idx].kmdvaddr = kvaddr; + } + } else { + rc = -EINVAL; + goto exit_func; + } + + *vaddr_ptr = tbl.bufq[idx].kmdvaddr; + *len = tbl.bufq[idx].len; + +exit_func: + mutex_unlock(&tbl.bufq[idx].q_lock); + return rc; +} +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 ion_cache_ops; + unsigned long ion_flag = 0; + + 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 fail; + } + + if (cmd->buf_handle != tbl.bufq[idx].buf_handle) { + rc = -EINVAL; + goto fail; + } + + rc = ion_handle_get_flags(tbl.client, tbl.bufq[idx].i_hdl, + &ion_flag); + if (rc) { + CAM_ERR(CAM_CRM, "cache get flags failed %d", rc); + goto fail; + } + + if (ION_IS_CACHED(ion_flag)) { + switch (cmd->mem_cache_ops) { + case CAM_MEM_CLEAN_CACHE: + ion_cache_ops = ION_IOC_CLEAN_CACHES; + break; + case CAM_MEM_INV_CACHE: + ion_cache_ops = ION_IOC_INV_CACHES; + break; + case CAM_MEM_CLEAN_INV_CACHE: + ion_cache_ops = ION_IOC_CLEAN_INV_CACHES; + break; + default: + CAM_ERR(CAM_CRM, + "invalid cache ops :%d", cmd->mem_cache_ops); + rc = -EINVAL; + goto fail; + } + + rc = msm_ion_do_cache_op(tbl.client, + tbl.bufq[idx].i_hdl, + (void *)tbl.bufq[idx].vaddr, + tbl.bufq[idx].len, + ion_cache_ops); + if (rc) + CAM_ERR(CAM_CRM, "cache operation failed %d", rc); + } +fail: + 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, + size_t align, + unsigned int heap_id_mask, + unsigned int flags, + struct ion_handle **hdl, + struct dma_buf **buf) +{ + int rc = 0; + + if (!hdl || !buf) { + CAM_ERR(CAM_CRM, "Invalid params"); + return -EINVAL; + } + + *hdl = ion_alloc(tbl.client, len, align, heap_id_mask, flags); + if (IS_ERR_OR_NULL(*hdl)) + return -ENOMEM; + + *buf = ion_share_dma_buf(tbl.client, *hdl); + if (IS_ERR_OR_NULL(*buf)) { + CAM_ERR(CAM_CRM, "get dma buf fail"); + rc = -EINVAL; + goto get_buf_fail; + } + + return rc; + +get_buf_fail: + ion_free(tbl.client, *hdl); + 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 ion_handle **hdl, + int *fd) +{ + int rc = 0; + + if (!hdl || !fd) { + CAM_ERR(CAM_CRM, "Invalid params"); + return -EINVAL; + } + + *hdl = ion_alloc(tbl.client, len, align, heap_id_mask, flags); + if (IS_ERR_OR_NULL(*hdl)) + return -ENOMEM; + + *fd = ion_share_dma_buf_fd(tbl.client, *hdl); + if (*fd < 0) { + CAM_ERR(CAM_CRM, "get fd fail"); + rc = -EINVAL; + goto get_fd_fail; + } + + return rc; + +get_fd_fail: + ion_free(tbl.client, *hdl); + return rc; +} + +static int cam_mem_util_ion_alloc(struct cam_mem_mgr_alloc_cmd *cmd, + struct ion_handle **hdl, + int *fd) +{ + uint32_t heap_id; + uint32_t ion_flag = 0; + int rc; + + 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, + hdl, + fd); + + return rc; +} + + +static int cam_mem_util_check_flags(struct cam_mem_mgr_alloc_cmd *cmd) +{ + if (!cmd->flags) { + CAM_ERR(CAM_CRM, "Invalid flags"); + return -EINVAL; + } + + if (cmd->num_hdl > CAM_MEM_MMU_MAX_HANDLE) { + CAM_ERR(CAM_CRM, "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_CRM, "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_CRM, "Invalid flags"); + return -EINVAL; + } + + if (cmd->num_hdl > CAM_MEM_MMU_MAX_HANDLE) { + CAM_ERR(CAM_CRM, "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_CRM, "Kernel mapping in secure mode not allowed"); + return -EINVAL; + } + + if (cmd->flags & CAM_MEM_FLAG_HW_SHARED_ACCESS) { + CAM_ERR(CAM_CRM, + "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); + + if (dir < 0) { + CAM_ERR(CAM_CRM, "fail to map DMA direction"); + return dir; + } + + 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, + tbl.client, + (ion_phys_addr_t *)hw_vaddr, + len); + + if (rc < 0) { + CAM_ERR(CAM_CRM, + "Failed to securely map to smmu"); + goto multi_map_fail; + } + } + } else { + for (i = 0; i < num_hdls; i++) { + rc = cam_smmu_map_user_iova(mmu_hdls[i], + fd, + dir, + (dma_addr_t *)hw_vaddr, + len, + region); + + if (rc < 0) { + CAM_ERR(CAM_CRM, "Failed to map to smmu"); + 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 ion_handle *ion_hdl; + int ion_fd; + dma_addr_t hw_vaddr = 0; + size_t len; + + if (!cmd) { + CAM_ERR(CAM_CRM, " Invalid argument"); + return -EINVAL; + } + len = cmd->len; + + rc = cam_mem_util_check_flags(cmd); + if (rc) { + CAM_ERR(CAM_CRM, "Invalid flags: flags = %X", cmd->flags); + return rc; + } + + rc = cam_mem_util_ion_alloc(cmd, + &ion_hdl, + &ion_fd); + if (rc) { + CAM_ERR(CAM_CRM, "Ion allocation failed"); + return rc; + } + + idx = cam_mem_get_slot(); + if (idx < 0) { + 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; + + rc = cam_mem_util_map_hw_va(cmd->flags, + cmd->mmu_hdls, + cmd->num_hdl, + ion_fd, + &hw_vaddr, + &len, + region); + if (rc) + goto map_hw_fail; + } + + mutex_lock(&tbl.bufq[idx].q_lock); + tbl.bufq[idx].fd = ion_fd; + tbl.bufq[idx].dma_buf = NULL; + tbl.bufq[idx].flags = cmd->flags; + tbl.bufq[idx].buf_handle = GET_MEM_HANDLE(idx, ion_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].i_hdl = ion_hdl; + 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_CRM, "buf handle: %x, fd: %d, len: %zu", + cmd->out.buf_handle, cmd->out.fd, + tbl.bufq[idx].len); + + return rc; + +map_hw_fail: + cam_mem_put_slot(idx); +slot_fail: + ion_free(tbl.client, ion_hdl); + return rc; +} + +int cam_mem_mgr_map(struct cam_mem_mgr_map_cmd *cmd) +{ + int32_t idx; + int rc; + struct ion_handle *ion_hdl; + dma_addr_t hw_vaddr = 0; + size_t len = 0; + + if (!cmd || (cmd->fd < 0)) { + CAM_ERR(CAM_CRM, "Invalid argument"); + return -EINVAL; + } + + if (cmd->num_hdl > CAM_MEM_MMU_MAX_HANDLE) + return -EINVAL; + + rc = cam_mem_util_check_map_flags(cmd); + if (rc) { + CAM_ERR(CAM_CRM, "Invalid flags: flags = %X", cmd->flags); + return rc; + } + + ion_hdl = ion_import_dma_buf_fd(tbl.client, cmd->fd); + if (IS_ERR_OR_NULL((void *)(ion_hdl))) { + CAM_ERR(CAM_CRM, "Failed to import ion 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) + 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].i_hdl = ion_hdl; + 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; + + return rc; + +map_fail: + ion_free(tbl.client, ion_hdl); + 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 = -EINVAL; + + if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) { + CAM_ERR(CAM_CRM, "Incorrect index"); + return rc; + } + + flags = tbl.bufq[idx].flags; + mmu_hdls = tbl.bufq[idx].hdls; + num_hdls = tbl.bufq[idx].num_hdl; + fd = tbl.bufq[idx].fd; + + 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) + 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_CRM, + "invalid caller for unmapping : %d", + client); + rc = -EINVAL; + } + if (rc < 0) + goto unmap_end; + } + } + + return rc; + +unmap_end: + CAM_ERR(CAM_CRM, "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_CRM, + "Buffer inactive at idx=%d, continuing", i); + continue; + } else { + CAM_DBG(CAM_CRM, + "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].i_hdl) { + ion_free(tbl.client, tbl.bufq[i].i_hdl); + tbl.bufq[i].i_hdl = 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].i_hdl = 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) +{ + cam_mem_mgr_cleanup_table(); + mutex_lock(&tbl.m_lock); + bitmap_zero(tbl.bitmap, tbl.bits); + kfree(tbl.bitmap); + tbl.bitmap = NULL; + cam_mem_util_client_destroy(); + 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_CRM, "Incorrect index"); + return -EINVAL; + } + + CAM_DBG(CAM_CRM, "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_CRM, "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].i_hdl && tbl.bufq[idx].kmdvaddr) + ion_unmap_kernel(tbl.client, tbl.bufq[idx].i_hdl); + + /* 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)) + rc = cam_mem_util_unmap_hw_va(idx, region, client); + + + 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_CRM, + "Ion handle at idx = %d freeing = %pK, fd = %d, imported %d dma_buf %pK", + idx, tbl.bufq[idx].i_hdl, tbl.bufq[idx].fd, + tbl.bufq[idx].is_imported, + tbl.bufq[idx].dma_buf); + + if (tbl.bufq[idx].i_hdl) { + ion_free(tbl.client, tbl.bufq[idx].i_hdl); + tbl.bufq[idx].i_hdl = NULL; + } + + 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 (!cmd) { + CAM_ERR(CAM_CRM, "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_CRM, "Incorrect index extracted from mem handle"); + return -EINVAL; + } + + if (!tbl.bufq[idx].active) { + CAM_ERR(CAM_CRM, "Released buffer state should be active"); + return -EINVAL; + } + + if (tbl.bufq[idx].buf_handle != cmd->buf_handle) { + CAM_ERR(CAM_CRM, + "Released buf handle not matching within table"); + return -EINVAL; + } + + CAM_DBG(CAM_CRM, "Releasing hdl = %u", cmd->buf_handle); + 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 ion_handle *hdl; + struct dma_buf *buf = NULL; + int ion_fd = -1; + int rc = 0; + uint32_t heap_id; + int32_t ion_flag = 0; + uint64_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 (!inp || !out) { + CAM_ERR(CAM_CRM, "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_CRM, "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, + inp->align, + heap_id, + ion_flag, + &hdl, + &buf); + + if (rc) { + CAM_ERR(CAM_CRM, "ION alloc failed for shared buffer"); + goto ion_fail; + } else { + CAM_DBG(CAM_CRM, "Got dma_buf = %pK, hdl = %pK", buf, hdl); + } + + rc = cam_mem_util_map_cpu_va(hdl, &kvaddr, &request_len); + if (rc) { + CAM_ERR(CAM_CRM, "Failed to get kernel vaddr"); + goto map_fail; + } + + if (!inp->smmu_hdl) { + CAM_ERR(CAM_CRM, "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_CRM, "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].i_hdl = hdl; + 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: + ion_unmap_kernel(tbl.client, hdl); +map_fail: + ion_free(tbl.client, hdl); +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 (!inp) { + CAM_ERR(CAM_CRM, "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_CRM, "Incorrect index extracted from mem handle"); + return -EINVAL; + } + + if (!tbl.bufq[idx].active) { + if (tbl.bufq[idx].vaddr == 0) { + CAM_ERR(CAM_CRM, "buffer is released already"); + return 0; + } + CAM_ERR(CAM_CRM, "Released buffer state should be active"); + return -EINVAL; + } + + if (tbl.bufq[idx].buf_handle != inp->mem_handle) { + CAM_ERR(CAM_CRM, + "Released buf handle not matching within table"); + return -EINVAL; + } + + CAM_DBG(CAM_CRM, "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 ion_handle *hdl; + 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 (!inp || !out) { + CAM_ERR(CAM_CRM, "Invalid param(s)"); + return -EINVAL; + } + + if (!inp->smmu_hdl) { + CAM_ERR(CAM_CRM, "Invalid SMMU handle"); + return -EINVAL; + } + + if (region != CAM_SMMU_REGION_SECHEAP) { + CAM_ERR(CAM_CRM, "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, + inp->align, + heap_id, + 0, + &hdl, + &buf); + + if (rc) { + CAM_ERR(CAM_CRM, "ION alloc failed for sec heap buffer"); + goto ion_fail; + } else { + CAM_DBG(CAM_CRM, "Got dma_buf = %pK, hdl = %pK", buf, hdl); + } + + rc = cam_smmu_reserve_sec_heap(inp->smmu_hdl, + buf, + &iova, + &request_len); + + if (rc) { + CAM_ERR(CAM_CRM, "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].i_hdl = hdl; + 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: + ion_free(tbl.client, hdl); +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 (!inp) { + CAM_ERR(CAM_CRM, "Invalid argument"); + return -EINVAL; + } + + if (inp->region != CAM_SMMU_REGION_SECHEAP) { + CAM_ERR(CAM_CRM, "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_CRM, "Incorrect index extracted from mem handle"); + return -EINVAL; + } + + if (!tbl.bufq[idx].active) { + if (tbl.bufq[idx].vaddr == 0) { + CAM_ERR(CAM_CRM, "buffer is released already"); + return 0; + } + CAM_ERR(CAM_CRM, "Released buffer state should be active"); + return -EINVAL; + } + + if (tbl.bufq[idx].buf_handle != inp->mem_handle) { + CAM_ERR(CAM_CRM, + "Released buf handle not matching within table"); + return -EINVAL; + } + + if (tbl.bufq[idx].num_hdl != 1) { + CAM_ERR(CAM_CRM, + "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_CRM, + "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_CRM, + "Sec heap region release failed"); + return -ENODEV; + } + + CAM_DBG(CAM_CRM, "Releasing hdl = %X", inp->mem_handle); + rc = cam_mem_util_unmap(idx, CAM_SMMU_MAPPING_KERNEL); + if (rc) + CAM_ERR(CAM_CRM, "unmapping secondary heap failed"); + + return rc; +} +EXPORT_SYMBOL(cam_mem_mgr_free_memory_region); diff --git a/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_mem_mgr.h b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_mem_mgr.h new file mode 100644 index 000000000000..83727d20e685 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_mem_mgr.h @@ -0,0 +1,131 @@ +/* Copyright (c) 2016-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. + */ + +#ifndef _CAM_MEM_MGR_H_ +#define _CAM_MEM_MGR_H_ + +#include +#include +#include +#include "cam_mem_mgr_api.h" + +#define CAM_MEM_BUFQ_MAX 1024 + +/*Enum for possible SMMU operations */ +enum cam_smmu_mapping_client { + CAM_SMMU_MAPPING_USER, + CAM_SMMU_MAPPING_KERNEL, +}; + +/** + * struct cam_mem_buf_queue + * + * @i_hdl: ion handle for the buffer + * @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 ion_handle *i_hdl; + 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; + uint64_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 + * @client: ion client pointer + * @bufq: array of buffers + */ +struct cam_mem_table { + struct mutex m_lock; + void *bitmap; + size_t bits; + struct ion_client *client; + 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/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_mem_mgr_api.h b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_mem_mgr_api.h new file mode 100644 index 000000000000..7588c179f4a5 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_mem_mgr_api.h @@ -0,0 +1,125 @@ +/* Copyright (c) 2016-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. + */ + +#ifndef _CAM_MEM_MGR_API_H_ +#define _CAM_MEM_MGR_API_H_ + +#include +#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 { + uint64_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, + uint64_t *iova_ptr, size_t *len_ptr); +/** + * @brief: Returns CPU address information about 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, uint64_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/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_core.c b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_core.c new file mode 100644 index 000000000000..98117ea7c259 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_core.c @@ -0,0 +1,2730 @@ +/* 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. + */ + +#include +#include +#include +#include +#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; + +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); + } + } +} + +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_reset_req_tbl() + * + * @brief : Initialize req table data + * @in_q : request queue pointer + * + * @return: 0 for success, negative for failure + * + */ +static int __cam_req_mgr_print_req_tbl(struct cam_req_mgr_req_data *req) +{ + int rc = 0; + int32_t i = 0; + struct cam_req_mgr_req_queue *in_q = req->in_q; + struct cam_req_mgr_req_tbl *req_tbl = req->l_tbl; + + if (!in_q || !req_tbl) { + CAM_WARN(CAM_CRM, "NULL pointer %pK %pK", in_q, req_tbl); + return -EINVAL; + } + CAM_DBG(CAM_CRM, "in_q %pK %pK %d", in_q, req_tbl, req_tbl->num_slots); + mutex_lock(&req->lock); + for (i = 0; i < in_q->num_slots; i++) { + CAM_DBG(CAM_CRM, "IN_Q %d: idx %d, red_id %lld", i, + in_q->slot[i].idx, CRM_GET_REQ_ID(in_q, i)); + } + + while (req_tbl != NULL) { + for (i = 0; i < req_tbl->num_slots; i++) { + CAM_DBG(CAM_CRM, "idx= %d, map= %x, state= %d", + req_tbl->slot[i].idx, + req_tbl->slot[i].req_ready_map, + req_tbl->slot[i].state); + } + CAM_DBG(CAM_CRM, + "TBL:id= %d, pd=%d cnt=%d mask=%x skip=%d num_slt= %d", + req_tbl->id, req_tbl->pd, req_tbl->dev_count, + req_tbl->dev_mask, req_tbl->skip_traverse, + req_tbl->num_slots); + req_tbl = req_tbl->next; + } + mutex_unlock(&req->lock); + + 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_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); + + if ((slot->inject_delay > 0) && + (traverse_data->self_link == true)) { + CAM_DBG(CAM_CRM, "Injecting Delay of one frame"); + apply_data[tbl->pd].req_id = -1; + slot->inject_delay--; + /* This pd table is not ready to proceed with asked idx */ + SET_FAILURE_BIT(traverse_data->result, tbl->pd); + return -EAGAIN; + } + + /* 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: %d 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 */ + 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_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) + return; + + /* Reset input queue slot */ + slot->req_id = -1; + slot->skip_idx = 0; + slot->recover = 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_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 + * + */ +static void __cam_req_mgr_check_next_req_slot( + struct cam_req_mgr_req_queue *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) { + __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); + } +} + +/** + * __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) +{ + 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; + + 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) { + 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; + apply_req.report_if_bubble = + in_q->slot[idx].recover; + + trace_cam_req_mgr_apply_request(link, &apply_req, dev); + + apply_req.trigger_point = trigger; + CAM_DBG(CAM_CRM, "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) + break; + } + } + } + if (rc < 0) { + CAM_ERR_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.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 + * @self_link : To indicate whether the validation is for the given link or + * other sync link + * + * @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, bool self_link) +{ + 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.validate_only = validate_only; + traverse_data.self_link = self_link; + /* + * 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 self_link %d validate %d result %x pd_mask %x rc %d", + idx, traverse_data.self_link, traverse_data.validate_only, + traverse_data.result, link->pd_mask, rc); + + if (!rc && traverse_data.result == link->pd_mask) { + CAM_DBG(CAM_CRM, + "APPLY: 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; + + return rc; +} + +/** + * __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_sof_cnt() + * + * @brief : the sof_count for both the links are reset + * @link : pointer to link whose input queue and req tbl are + * traversed through + * + */ +static void __cam_req_mgr_reset_sof_cnt( + struct cam_req_mgr_core_link *link) +{ + link->sof_counter = -1; + link->sync_link->sof_counter = -1; + link->frame_skip_flag = false; + + CAM_DBG(CAM_CRM, + "link_hdl %x self_counter %lld other_counter %lld frame_skip_lag %d", + link->link_hdl, link->sof_counter, + link->sync_link->sof_counter, link->frame_skip_flag); +} + +/** + * __cam_req_mgr_sof_cnt_initialize() + * + * @brief : when the sof count is intially -1 it increments count + * and computes the sync_self_ref for this link + * the count needs to be wrapped back starting from 0 + * @link : pointer to link whose input queue and req tbl are + * traversed through + * + */ +static void __cam_req_mgr_sof_cnt_initialize( + struct cam_req_mgr_core_link *link) +{ + link->sof_counter++; + link->sync_self_ref = link->sof_counter - + link->sync_link->sof_counter; + + CAM_DBG(CAM_CRM, + "link_hdl %x self_counter %lld other_counter %lld", + link->link_hdl, link->sof_counter, + link->sync_link->sof_counter); +} + +/** + * __cam_req_mgr_wrap_sof_cnt() + * + * @brief : once the sof count reaches a predefined maximum + * the count needs to be wrapped back starting from 0 + * @link : pointer to link whose input queue and req tbl are + * traversed through + * + */ +static void __cam_req_mgr_wrap_sof_cnt( + struct cam_req_mgr_core_link *link) +{ + link->sof_counter = (MAX_SYNC_COUNT - + (link->sync_link->sof_counter)); + link->sync_link->sof_counter = 0; + + CAM_DBG(CAM_CRM, + "link_hdl %x self_counter %lld sync_link_hdl %x other_counter %lld", + link->link_hdl, link->sof_counter, + link->sync_link->link_hdl, link->sync_link->sof_counter); +} + +/** + * __cam_req_mgr_validate_sof_cnt() + * + * @brief : validates sof count difference for a given link + * @link : pointer to link whose input queue and req tbl are + * traversed through + * @sync_link : pointer to the sync link + * @return : 0 for success, negative for failure + * + */ +static int __cam_req_mgr_validate_sof_cnt( + struct cam_req_mgr_core_link *link, + struct cam_req_mgr_core_link *sync_link) +{ + int64_t sync_diff = 0; + int rc = 0; + + if (link->sof_counter == MAX_SYNC_COUNT) + __cam_req_mgr_wrap_sof_cnt(link); + + sync_diff = link->sof_counter - sync_link->sof_counter; + + CAM_DBG(CAM_CRM, + "link[%x] self_counter=%lld other_counter=%lld diff=%lld sync_self_ref=%lld", + link->link_hdl, link->sof_counter, + sync_link->sof_counter, sync_diff, link->sync_self_ref); + + if (sync_diff > SYNC_LINK_SOF_CNT_MAX_LMT) { + link->sync_link->frame_skip_flag = true; + CAM_WARN(CAM_CRM, + "Detected anomaly, skip link_hdl %x self_counter=%lld other_counter=%lld sync_self_ref=%lld", + link->link_hdl, link->sof_counter, + sync_link->sof_counter, link->sync_self_ref); + rc = -EPERM; + } + + return rc; +} + + +/** + * __cam_req_mgr_process_sync_req() + * + * @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_process_sync_req( + struct cam_req_mgr_core_link *link, + struct cam_req_mgr_slot *slot) +{ + struct cam_req_mgr_core_link *sync_link = NULL; + int64_t req_id = 0; + int sync_slot_idx = 0, rc = 0; + + if (!link->sync_link) { + CAM_ERR(CAM_CRM, "Sync link null"); + return -EINVAL; + } + + sync_link = link->sync_link; + req_id = slot->req_id; + + CAM_DBG(CAM_CRM, + "link_hdl %x req %lld sync_self_ref %lld sof_counter %lld frame_skip_flag %d sync_link_self_ref %lld", + link->link_hdl, req_id, link->sync_self_ref, link->sof_counter, + link->frame_skip_flag, link->sync_link->sync_self_ref); + + 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; + return -EINVAL; + } + + if (link->sof_counter == -1) { + __cam_req_mgr_sof_cnt_initialize(link); + } else if ((link->frame_skip_flag) && + (sync_link->sync_self_ref != -1)) { + CAM_DBG(CAM_CRM, "Link[%x] Req[%lld] Resetting values ", + link->link_hdl, req_id); + __cam_req_mgr_reset_sof_cnt(link); + __cam_req_mgr_sof_cnt_initialize(link); + } else { + link->sof_counter++; + } + + rc = __cam_req_mgr_check_link_is_ready(link, slot->idx, true, true); + if (rc) { + CAM_DBG(CAM_CRM, + "Req: %lld [My link]not available link: %x, rc=%d", + req_id, link->link_hdl, rc); + link->sync_link_sof_skip = true; + goto failure; + } + + sync_slot_idx = __cam_req_mgr_find_slot_for_req( + sync_link->req.in_q, req_id); + + if (sync_slot_idx != -1) { + rc = __cam_req_mgr_check_link_is_ready( + sync_link, sync_slot_idx, true, false); + CAM_DBG(CAM_CRM, "sync_slot_idx=%d, status=%d, rc=%d", + sync_slot_idx, + sync_link->req.in_q->slot[sync_slot_idx].status, + rc); + } else { + CAM_DBG(CAM_CRM, "sync_slot_idx=%d, rc=%d", + sync_slot_idx, rc); + } + + if ((sync_slot_idx != -1) && + ((sync_link->req.in_q->slot[sync_slot_idx].status == + CRM_SLOT_STATUS_REQ_APPLIED) || (rc == 0))) { + rc = __cam_req_mgr_validate_sof_cnt(link, sync_link); + if (rc) { + CAM_DBG(CAM_CRM, + "Req: %lld validate failed: %x", + req_id, sync_link->link_hdl); + goto failure; + } + + CAM_DBG(CAM_CRM, + "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, true); + + if (rc) { + CAM_WARN(CAM_CRM, "Unexpected return value rc: %d", rc); + } + } else { + CAM_DBG(CAM_CRM, + "Req: %lld [Other link] not ready to apply on link: %x", + req_id, sync_link->link_hdl); + rc = -EPERM; + link->sync_link_sof_skip = true; + goto failure; + } + + return rc; + +failure: + link->sof_counter--; + return rc; +} + +/** + * __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, + uint32_t trigger) +{ + int rc = 0, idx; + struct cam_req_mgr_slot *slot = NULL; + struct cam_req_mgr_req_queue *in_q; + struct cam_req_mgr_core_session *session; + + 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_CRM, "SOF Req[%lld] idx %d req_status %d link_hdl %x", + in_q->slot[in_q->rd_idx].req_id, in_q->rd_idx, + in_q->slot[in_q->rd_idx].status, link->link_hdl); + + 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) { + 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) + rc = __cam_req_mgr_process_sync_req(link, slot); + else + rc = __cam_req_mgr_check_link_is_ready(link, + slot->idx, false, true); + + 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); + if (rc < 0) { + /* Apply req failed retry at next sof */ + slot->status = CRM_SLOT_STATUS_REQ_PENDING; + } else { + link->trigger_mask |= trigger; + + 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; + __cam_req_mgr_dec_idx( + &idx, link->max_delay + 1, + in_q->num_slots); + __cam_req_mgr_reset_req_slot(link, idx); + } + } + + 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_sof_freeze() + * + * @brief : Apoptosis - Handles case when connected devices are not responding + * @data : timer pointer + * + */ +static void __cam_req_mgr_sof_freeze(unsigned long data) +{ + struct cam_req_mgr_timer *timer = (struct cam_req_mgr_timer *)data; + struct cam_req_mgr_core_link *link = NULL; + struct cam_req_mgr_core_session *session = NULL; + struct cam_req_mgr_message msg; + + if (!timer) { + CAM_ERR(CAM_CRM, "NULL timer"); + return; + } + link = (struct cam_req_mgr_core_link *)timer->parent; + session = (struct cam_req_mgr_core_session *)link->parent; + + CAM_ERR(CAM_CRM, "SOF freeze for session %d link 0x%x", + session->session_hdl, link->link_hdl); + + memset(&msg, 0, sizeof(msg)); + + msg.session_hdl = session->session_hdl; + msg.u.err_msg.error_type = CAM_REQ_MGR_ERROR_TYPE_DEVICE; + msg.u.err_msg.request_id = 0; + msg.u.err_msg.link_hdl = link->link_hdl; + + + if (cam_req_mgr_notify_message(&msg, + V4L_EVENT_CAM_REQ_MGR_ERROR, V4L_EVENT_CAM_REQ_MGR_EVENT)) + CAM_ERR(CAM_CRM, + "Error notifying SOF freeze for session %d link 0x%x", + session->session_hdl, link->link_hdl); +} + +/** + * __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 = (struct cam_req_mgr_connected_device *) + 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 : Cleans up the mem allocated while linking + * @link : pointer to link, mem associated with this link is freed + * + * @return : returns if unlink for any device was success or failure + */ +static int __cam_req_mgr_destroy_link_info(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) { + 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_hdl %d", + dev->dev_hdl); + } + dev->dev_hdl = 0; + dev->parent = NULL; + dev->ops = NULL; + } + } + __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; + + return rc; +} + +/** + * __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 >= MAX_LINKS_PER_SESSION) { + CAM_ERR(CAM_CRM, "Reached max links %d per session limit %d", + session->num_links, MAX_LINKS_PER_SESSION); + return NULL; + } + + link = (struct cam_req_mgr_core_link *) + kzalloc(sizeof(struct cam_req_mgr_core_link), GFP_KERNEL); + if (!link) { + CAM_ERR(CAM_CRM, "failed to create link, no mem"); + return NULL; + } + in_q = (struct cam_req_mgr_req_queue *) + kzalloc(sizeof(struct cam_req_mgr_req_queue), GFP_KERNEL); + if (!in_q) { + CAM_ERR(CAM_CRM, "failed to create input queue, no mem"); + kfree(link); + return NULL; + } + mutex_init(&link->lock); + spin_lock_init(&link->link_state_spin_lock); + + mutex_lock(&link->lock); + link->state = CAM_CRM_LINK_STATE_AVAILABLE; + 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 < MAX_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 == MAX_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(link); + 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) +{ + kfree(link->req.in_q); + link->req.in_q = NULL; + kfree(link); +} + +/** + * __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 < MAX_LINKS_PER_SESSION; i++) { + if (session->links[i] == link) + session->links[i] = NULL; + } + + if ((session->sync_mode != CAM_REQ_MGR_SYNC_MODE_NO_SYNC) && + (link->sync_link)) { + /* + * make sure to unlink sync setup under the assumption + * of only having 2 links in a given session + */ + session->sync_mode = CAM_REQ_MGR_SYNC_MODE_NO_SYNC; + for (i = 0; i < MAX_LINKS_PER_SESSION; i++) { + if (session->links[i]) + session->links[i]->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; + + 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); +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; + + 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; + flush_info = (struct cam_req_mgr_flush_info *)&task_data->u; + CAM_DBG(CAM_CRM, "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) { + for (i = 0; i < in_q->num_slots; i++) { + slot = &in_q->slot[i]; + slot->req_id = -1; + slot->sync_mode = CAM_REQ_MGR_SYNC_MODE_NO_SYNC; + slot->skip_idx = 1; + slot->status = CRM_SLOT_STATUS_NO_REQ; + } + in_q->wr_idx = 0; + in_q->rd_idx = 0; + } 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; + } + __cam_req_mgr_in_q_skip_idx(in_q, idx); + } + } + + 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", + sched_req->link_hdl, sched_req->req_id, + in_q->wr_idx, sched_req->sync_mode); + + 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; + __cam_req_mgr_inc_idx(&in_q->wr_idx, 1, in_q->num_slots); + 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", add_req->req_id); + rc = -EBADSLT; + mutex_unlock(&link->req.lock); + goto end; + } + + slot = &tbl->slot[idx]; + if (add_req->skip_before_applying > slot->inject_delay) { + slot->inject_delay = add_req->skip_before_applying; + CAM_DBG(CAM_CRM, "Req_id %llu injecting delay %u", + add_req->req_id, add_req->skip_before_applying); + } + + 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", + slot->state, idx, slot->req_ready_map); + } + + 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_CRM, "idx %d req_id %lld pd %d SLOT READY", + 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; + spin_lock_bh(&link->link_state_spin_lock); + link->state = CAM_CRM_LINK_STATE_ERR; + spin_unlock_bh(&link->link_state_spin_lock); + } + } + mutex_unlock(&link->req.lock); + +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; + 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_CRM, "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); + /* + * 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); + __cam_req_mgr_check_next_req_slot(in_q); + __cam_req_mgr_inc_idx(&in_q->rd_idx, 1, in_q->num_slots); + } + rc = __cam_req_mgr_process_req(link, trigger_data->trigger); + mutex_unlock(&link->req.lock); + +end: + return rc; +} + + +/* 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; + } + + CAM_DBG(CAM_CRM, "E: dev %x dev req %lld", + add_req->dev_hdl, add_req->req_id); + 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; + } + + 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_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; + } + 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; + 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, +}; + +/** + * __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_link_info *link_info) +{ + int rc = 0, i = 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->num_devices > CAM_REQ_MGR_MAX_HANDLES) + 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; + for (i = 0; i < link_info->num_devices; i++) { + dev = &link->l_dev[i]; + /* Using dev hdl, get ops ptr to communicate with device */ + dev->ops = (struct cam_req_mgr_kmd_ops *) + cam_get_device_ops(link_info->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; + } + dev->dev_hdl = link_info->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); + + CAM_DBG(CAM_CRM, + "%x: connected: %s, id %d, delay %d, trigger %x", + link_info->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 { + CAM_DBG(CAM_CRM, "%x: connected: %s, delay %d", + link_info->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 < link_info->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); + + /* 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 = link_info->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 = (struct cam_req_mgr_core_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; + + mutex_lock(&link->lock); + spin_lock_bh(&link->link_state_spin_lock); + link->state = CAM_CRM_LINK_STATE_IDLE; + + /* Destroy timer of link */ + crm_timer_exit(&link->watchdog); + spin_unlock_bh(&link->link_state_spin_lock); + __cam_req_mgr_print_req_tbl(&link->req); + + /* Destroy workq payload data */ + kfree(link->workq->task.pool[0].payload); + link->workq->task.pool[0].payload = NULL; + + /* Destroy workq of link */ + cam_req_mgr_workq_destroy(&link->workq); + + /* Cleanup request tables and unlink devices */ + rc = __cam_req_mgr_destroy_link_info(link); + if (rc) + CAM_ERR(CAM_CORE, + "Unlink for all devices was not successful"); + + /* 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 while destroying dev handle %d %x", + rc, link->link_hdl); + } + + mutex_unlock(&link->lock); + return rc; +} + +int cam_req_mgr_destroy_session( + struct cam_req_mgr_session_info *ses_info) +{ + 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; + + } + mutex_lock(&cam_session->lock); + 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 < MAX_LINKS_PER_SESSION; i++) { + link = cam_session->links[i]; + + if (!link) + continue; + + /* Ignore return value since session is going away */ + __cam_req_mgr_unlink(link); + __cam_req_mgr_free_link(link); + } + } + list_del(&cam_session->entry); + mutex_unlock(&cam_session->lock); + 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_link_info *link_info) +{ + int rc = 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->num_devices > CAM_REQ_MGR_MAX_HANDLES) { + CAM_ERR(CAM_CRM, "Invalid num devices %d", + link_info->num_devices); + return -EINVAL; + } + + /* session hdl's priv data is cam session struct */ + cam_session = (struct cam_req_mgr_core_session *) + cam_get_device_priv(link_info->session_hdl); + if (!cam_session) { + CAM_DBG(CAM_CRM, "NULL pointer"); + return -EINVAL; + } + + mutex_lock(&g_crm_core_dev->crm_lock); + + /* 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->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->link_hdl = link->link_hdl; + + /* Allocate memory to hold data of all linked devs */ + rc = __cam_req_mgr_create_subdevs(&link->l_dev, + link_info->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->session_hdl, link->link_hdl); + rc = cam_req_mgr_workq_create(buf, CRM_WORKQ_NUM_TASKS, + &link->workq, CRM_WORKQ_USAGE_NON_IRQ); + 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->link_hdl = 0; +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 */ + if (!rc) + __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; + } + + CAM_DBG(CAM_CRM, "link %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; + 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_CRM, "DONE dev %x req %lld sync_mode %d", + sched_req->link_hdl, sched_req->req_id, sched_req->sync_mode); +end: + mutex_unlock(&g_crm_core_dev->crm_lock); + return rc; +} + +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->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->sof_counter = -1; + link1->sync_self_ref = -1; + link1->frame_skip_flag = false; + link1->sync_link_sof_skip = false; + link1->sync_link = link2; + + link2->sof_counter = -1; + link2->sync_self_ref = -1; + link2->frame_skip_flag = false; + link2->sync_link_sof_skip = false; + link2->sync_link = link1; + + cam_session->sync_mode = sync_info->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"); + rc = -EFAULT; + goto end; + } + if (flush_info->flush_type >= CAM_REQ_MGR_FLUSH_TYPE_MAX) { + CAM_ERR(CAM_CRM, "incorrect flush type %x", + flush_info->flush_type); + rc = -EINVAL; + goto end; + } + + 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; + } + + 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_RATE_LIMIT(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) { + /* 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) { + /* Destroy SOF watchdog timer */ + spin_lock_bh(&link->link_state_spin_lock); + crm_timer_exit(&link->watchdog); + spin_unlock_bh(&link->link_state_spin_lock); + /* 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); + } + } 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) +{ + 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 = (struct cam_req_mgr_core_device *) + 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); + + 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/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_core.h b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_core.h new file mode 100644 index 000000000000..0083d1fd6310 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_core.h @@ -0,0 +1,454 @@ +/* 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 _CAM_REQ_MGR_CORE_H_ +#define _CAM_REQ_MGR_CORE_H_ + +#include +#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_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 + +#define SYNC_LINK_SOF_CNT_MAX_LMT 1 + +/** + * 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_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 + * @idx : slot index + * @result : contains which all tables were able to apply successfully + * @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 + * @self_link : To indicate whether the check is for the given link or the + * other sync link + */ +struct cam_req_mgr_traverse { + int32_t idx; + uint32_t result; + 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; + bool self_link; +}; + +/** + * 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 + */ +struct cam_req_mgr_tbl_slot { + int32_t idx; + uint32_t req_ready_map; + enum crm_req_state state; + uint32_t inject_delay; +}; + +/** + * 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 + */ +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; +}; + +/** + * 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. + */ +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; +}; + +/** + * 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 + * @sof_counter : sof counter during sync_mode + * @sync_self_ref : reference sync count against which the difference + * between sync_counts for a given link is checked + * @frame_skip_flag : flag that determines if a frame needs to be skipped + * @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. + * + */ +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; + int64_t sof_counter; + int64_t sync_self_ref; + bool frame_skip_flag; + bool sync_link_sof_skip; +}; + +/** + * 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[MAX_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 + * + * Called as part of session destroy + * return success/failure + */ +int cam_req_mgr_destroy_session(struct cam_req_mgr_session_info *ses_info); + +/** + * 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_link_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/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_core_defs.h b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_core_defs.h new file mode 100644 index 000000000000..475b64099d52 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_core_defs.h @@ -0,0 +1,25 @@ +/* Copyright (c) 2016-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. + */ +#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/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_debug.c b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_debug.c new file mode 100644 index 000000000000..19833d85a23a --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_debug.c @@ -0,0 +1,139 @@ +/* Copyright (c) 2016-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. + */ + +#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/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_debug.h b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_debug.h new file mode 100644 index 000000000000..82ac7644ff8e --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_debug.h @@ -0,0 +1,21 @@ +/* Copyright (c) 2016-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. + */ + +#ifndef _CAM_REQ_MGR_DEBUG_H_ +#define _CAM_REQ_MGR_DEBUG_H_ + +#include +#include "cam_req_mgr_core.h" + +int cam_req_mgr_debug_register(struct cam_req_mgr_core_device *core_dev); + +#endif diff --git a/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_dev.c b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_dev.c new file mode 100644 index 000000000000..9a93feba1ac5 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_dev.c @@ -0,0 +1,744 @@ +/* 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 + +#define CAM_REQ_MGR_EVENT_MAX 30 + +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) +{ + 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(); + 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 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, NULL); +} + +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, + (void *)k_ioctl->handle, + k_ioctl->size)) { + return -EFAULT; + } + + rc = cam_req_mgr_create_session(&ses_info); + if (!rc) + if (copy_to_user((void *)k_ioctl->handle, + &ses_info, k_ioctl->size)) + 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, + (void *)k_ioctl->handle, + k_ioctl->size)) { + return -EFAULT; + } + + rc = cam_req_mgr_destroy_session(&ses_info); + } + break; + + case CAM_REQ_MGR_LINK: { + struct cam_req_mgr_link_info link_info; + + if (k_ioctl->size != sizeof(link_info)) + return -EINVAL; + + if (copy_from_user(&link_info, + (void *)k_ioctl->handle, + k_ioctl->size)) { + return -EFAULT; + } + + rc = cam_req_mgr_link(&link_info); + if (!rc) + if (copy_to_user((void *)k_ioctl->handle, + &link_info, k_ioctl->size)) + 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, + (void *)k_ioctl->handle, + k_ioctl->size)) { + 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, + (void *)k_ioctl->handle, + k_ioctl->size)) { + 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, + (void *)k_ioctl->handle, + k_ioctl->size)) { + 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, + (void *)k_ioctl->handle, + k_ioctl->size)) { + 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, + (void *)k_ioctl->handle, + k_ioctl->size)) { + rc = -EFAULT; + break; + } + + rc = cam_mem_mgr_alloc_and_map(&cmd); + if (!rc) + if (copy_to_user((void *)k_ioctl->handle, + &cmd, k_ioctl->size)) { + 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, + (void *)k_ioctl->handle, + k_ioctl->size)) { + rc = -EFAULT; + break; + } + + rc = cam_mem_mgr_map(&cmd); + if (!rc) + if (copy_to_user((void *)k_ioctl->handle, + &cmd, k_ioctl->size)) { + 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, + (void *)k_ioctl->handle, + k_ioctl->size)) { + 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, + (void *)k_ioctl->handle, + k_ioctl->size)) { + 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, + (void __user *)k_ioctl->handle, + k_ioctl->size)) { + 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_mem_mgr_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; + + 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_mem_mgr_init(); + if (rc) { + CAM_ERR(CAM_CRM, "mem mgr init failed"); + goto mem_mgr_init_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_mem_mgr_deinit(); +mem_mgr_init_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, + }, +}; + +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/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_dev.h b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_dev.h new file mode 100644 index 000000000000..93278b8e8b0c --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_dev.h @@ -0,0 +1,50 @@ +/* Copyright (c) 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. + */ + +#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/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_interface.h b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_interface.h new file mode 100644 index 000000000000..1ca6cc598ec8 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_interface.h @@ -0,0 +1,332 @@ +/* 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 _CAM_REQ_MGR_INTERFACE_H +#define _CAM_REQ_MGR_INTERFACE_H + +#include +#include +#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_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; + +/* 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 *); + +/** + * @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 cancle 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 + */ +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; +}; + +/** + * @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_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 + * @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_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: + * @CAM_REQ_MGR_LINK_EVT_MAX: + */ +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_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. + */ +struct cam_req_mgr_trigger_notify { + int32_t link_hdl; + int32_t dev_hdl; + int64_t frame_id; + uint32_t trigger; +}; + +/** + * 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; +}; + + +/* 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/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_timer.c b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_timer.c new file mode 100644 index 000000000000..124b336dd265 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_timer.c @@ -0,0 +1,100 @@ +/* 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. + */ + +#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(unsigned long data) +{ + struct cam_req_mgr_timer *timer = (struct cam_req_mgr_timer *)data; + + 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)(unsigned long)) +{ + 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 = (struct cam_req_mgr_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; + setup_timer(&crm_timer->sys_timer, + crm_timer->timer_cb, (unsigned long)crm_timer); + 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/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_timer.h b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_timer.h new file mode 100644 index 000000000000..b3e473a56daa --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_timer.h @@ -0,0 +1,71 @@ +/* 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 _CAM_REQ_MGR_TIMER_H_ +#define _CAM_REQ_MGR_TIMER_H_ + +#include +#include + +#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 + */ +struct cam_req_mgr_timer { + int32_t expires; + struct timer_list sys_timer; + void *parent; + void (*timer_cb)(unsigned long data); +}; + +/** + * 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)(unsigned long)); + +/** + * 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/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_util.c b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_util.c new file mode 100644 index 000000000000..dda04f8e5164 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_util.c @@ -0,0 +1,340 @@ +/* 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. + */ + +#define pr_fmt(fmt) "CAM-REQ-MGR_UTIL %s:%d " fmt, __func__, __LINE__ + +#include +#include +#include +#include +#include +#include +#include +#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) * 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; i++) { + if (hdl_tbl->hdl[i].state == HDL_ACTIVE) { + CAM_ERR(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); + 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 || 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) { + 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) { + 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) { + 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/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_util.h b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_util.h new file mode 100644 index 000000000000..21cd6dd66117 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_util.h @@ -0,0 +1,172 @@ +/* Copyright (c) 2016-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. + */ + +#ifndef _CAM_REQ_MGR_UTIL_API_H_ +#define _CAM_REQ_MGR_UTIL_API_H_ + +#include +#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]; + 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/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_util_priv.h b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_util_priv.h new file mode 100644 index 000000000000..8624442f643b --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_util_priv.h @@ -0,0 +1,49 @@ +/* Copyright (c) 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. + */ + +#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/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_workq.c b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_workq.c new file mode 100644 index 000000000000..2e0187ce7075 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_workq.c @@ -0,0 +1,280 @@ +/* Copyright (c) 2016-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. + */ + +#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; + + WORKQ_ACQUIRE_LOCK(workq, flags); + list_del_init(&task->entry); + task->cancel = 0; + task->process_cb = NULL; + task->priv = NULL; + 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++; + } +} + +void crm_workq_clear_q(struct cam_req_mgr_core_workq *workq) +{ + int32_t i = CRM_TASK_PRIORITY_0; + struct crm_workq_task *task, *task_save; + + CAM_DBG(CAM_CRM, "pending_cnt %d", + atomic_read(&workq->task.pending_cnt)); + + while (i < CRM_TASK_PRIORITY_MAX) { + if (!list_empty(&workq->task.process_head[i])) { + list_for_each_entry_safe(task, task_save, + &workq->task.process_head[i], entry) { + cam_req_mgr_workq_put_task(task); + CAM_WARN(CAM_CRM, "flush task %pK, %d, cnt %d", + task, i, atomic_read( + &workq->task.free_cnt)); + } + } + 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 (!workq->job) { + 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); + list_add_tail(&task->entry, + &workq->task.process_head[task->priority]); + WORKQ_RELEASE_LOCK(workq, flags); + + 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); + +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) +{ + int32_t i; + struct crm_workq_task *task; + struct cam_req_mgr_core_workq *crm_workq = NULL; + char buf[128] = "crm_workq-"; + + if (!*workq) { + crm_workq = (struct cam_req_mgr_core_workq *) + kzalloc(sizeof(struct cam_req_mgr_core_workq), + GFP_KERNEL); + if (crm_workq == NULL) + return -ENOMEM; + + strlcat(buf, name, sizeof(buf)); + CAM_DBG(CAM_CRM, "create workque crm_workq-%s", name); + crm_workq->job = alloc_workqueue(buf, + WQ_HIGHPRI | WQ_UNBOUND, 0, 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 = (struct crm_workq_task *) + kzalloc(sizeof(struct crm_workq_task) * + crm_workq->task.num_task, + GFP_KERNEL); + if (!crm_workq->task.pool) { + CAM_WARN(CAM_CRM, "Insufficient memory %lu", + 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 */ + list_add_tail(&task->entry, + &crm_workq->task.process_head[CRM_TASK_PRIORITY_0]); + 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) +{ + CAM_DBG(CAM_CRM, "destroy workque %pK", crm_workq); + if (*crm_workq) { + crm_workq_clear_q(*crm_workq); + if ((*crm_workq)->job) { + destroy_workqueue((*crm_workq)->job); + (*crm_workq)->job = NULL; + } + kfree((*crm_workq)->task.pool); + kfree(*crm_workq); + *crm_workq = NULL; + } +} diff --git a/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_workq.h b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_workq.h new file mode 100644 index 000000000000..eb3b804f97a9 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_workq.h @@ -0,0 +1,138 @@ +/* Copyright (c) 2016-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. + */ + +#ifndef _CAM_REQ_MGR_WORKQ_H_ +#define _CAM_REQ_MGR_WORKQ_H_ + +#include +#include +#include +#include +#include +#include +#include + +#include "cam_req_mgr_core.h" + +/* 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 *, void *); + 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 + * 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); + +/** + * 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/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_subdev.h b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_subdev.h new file mode 100644 index 000000000000..8cd3214674d5 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_subdev.h @@ -0,0 +1,115 @@ +/* Copyright (c) 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. + */ + +#ifndef _CAM_SUBDEV_H_ +#define _CAM_SUBDEV_H_ + +#include +#include +#include +#include +#include +#include +#include + +#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/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/Makefile b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/Makefile new file mode 100644 index 000000000000..65c23274e5ae --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/Makefile @@ -0,0 +1,10 @@ +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_flash/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_eeprom/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_ois/ diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_actuator/Makefile b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_actuator/Makefile new file mode 100644 index 000000000000..3f9157cf3001 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_actuator/Makefile @@ -0,0 +1,11 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_cpas/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_core +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_req_mgr +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_res_mgr +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_utils +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_smmu/ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_utils + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_actuator_dev.o cam_actuator_core.o cam_actuator_soc.o diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_actuator/cam_actuator_core.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_actuator/cam_actuator_core.c new file mode 100644 index 000000000000..89ce797c3e6f --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_actuator/cam_actuator_core.c @@ -0,0 +1,863 @@ +/* Copyright (c) 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. + */ + +#include +#include +#include "cam_actuator_core.h" +#include "cam_sensor_util.h" +#include "cam_trace.h" +#include "cam_res_mgr_api.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 = + (struct cam_sensor_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 = + (struct cam_sensor_power_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); + 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_INFO(CAM_ACTUATOR, + "Using default power settings"); + rc = cam_actuator_construct_default_power_setting(power_info); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, + "Construct default actuator power setting failed."); + return rc; + } + } + + /* 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 = msm_camera_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) +{ + int32_t rc = 0; + struct cam_cmd_i2c_info *i2c_info; + + if (!a_ctrl || !cmd_buf) { + 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) { + CAM_ERR(CAM_ACTUATOR, + "Failed to apply settings: %d", + rc); + return rc; + } + } + + 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); + + 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); + return rc; + } + } + 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); + return rc; + } + } else { + CAM_DBG(CAM_ACTUATOR, "No Valid Req to clean Up"); + } + + 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; + } + 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; + } + + return 0; +} + +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 = 0; + 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; + uint32_t *offset = NULL; + uint32_t *cmd_buf = NULL; + uint64_t generic_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_req_mgr_add_request add_req; + struct cam_actuator_soc_private *soc_private = NULL; + struct cam_sensor_power_ctrl_t *power_info = NULL; + + 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, (void __user *) ioctl_ctrl->handle, + sizeof(config))) + return -EFAULT; + + rc = cam_mem_get_cpu_buf(config.packet_handle, + (uint64_t *)&generic_ptr, &len_of_buff); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, "Error in converting command Handle %d", + rc); + return rc; + } + + if (config.offset > len_of_buff) { + CAM_ERR(CAM_ACTUATOR, + "offset is out of bounds: offset: %lld len: %zu", + config.offset, len_of_buff); + return -EINVAL; + } + + csl_packet = (struct cam_packet *)(generic_ptr + config.offset); + CAM_DBG(CAM_ACTUATOR, "Pkt opcode: %d", csl_packet->header.op_code); + + 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, + (uint64_t *)&generic_ptr, &len_of_buff); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, "Failed to get cpu buf"); + return rc; + } + cmd_buf = (uint32_t *)generic_ptr; + if (!cmd_buf) { + CAM_ERR(CAM_ACTUATOR, "invalid cmd buf"); + return -EINVAL; + } + 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); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, + "Failed to parse slave info: %d", rc); + return rc; + } + 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); + if (rc) { + CAM_ERR(CAM_ACTUATOR, + "Failed:parse power settings: %d", + rc); + return rc; + } + 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( + i2c_reg_settings, + &cmd_desc[i], 1); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, + "Failed:parse init settings: %d", + rc); + return rc; + } + break; + } + } + + if (a_ctrl->cam_act_state == CAM_ACTUATOR_ACQUIRE) { + rc = cam_actuator_power_up(a_ctrl); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, + " Actuator Power up failed"); + return rc; + } + a_ctrl->cam_act_state = CAM_ACTUATOR_CONFIG; + } + + rc = cam_actuator_apply_settings(a_ctrl, + &a_ctrl->i2c_data.init_settings); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, "Cannot apply Init settings"); + return rc; + } + + /* 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); + return rc; + } + 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(i2c_reg_settings, + cmd_desc, 1); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, + "Auto move lens parsing failed: %d", rc); + return rc; + } + 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); + return rc; + } + i2c_data = &(a_ctrl->i2c_data); + i2c_reg_settings = &i2c_data->per_frame[ + csl_packet->header.request_id % MAX_PER_FRAME_ARRAY]; + + 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(i2c_reg_settings, + cmd_desc, 1); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, + "Manual move lens parsing failed: %d", rc); + return rc; + } + break; + } + + if ((csl_packet->header.op_code & 0xFFFFFF) != + CAM_ACTUATOR_PACKET_OPCODE_INIT) { + 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, "Req Id: %lld added to Bridge", + add_req.req_id); + } + + return rc; +} + +void cam_actuator_shutdown(struct cam_actuator_ctrl_t *a_ctrl) +{ + int rc; + + 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"); + } + + 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; + } + 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; + + if (!a_ctrl || !cmd) { + CAM_ERR(CAM_ACTUATOR, " Invalid Args"); + return -EINVAL; + } + + 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, + (void __user *) 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((void __user *) 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; + } + 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; + } + 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((void __user *) 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; + } + 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->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 < 0) + CAM_ERR(CAM_ACTUATOR, + "Cannot apply Update settings"); + + /* 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; + } + + /* PATCH, add by xcb */ + if (a_ctrl->i2c_data.per_frame == NULL) { + CAM_ERR(CAM_ACTUATOR, "i2c frame data is NULL"); + return -EINVAL; + } + + 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); + return rc; +} diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_actuator/cam_actuator_core.h b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_actuator/cam_actuator_core.h new file mode 100644 index 000000000000..c28d79d0554d --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_actuator/cam_actuator_core.h @@ -0,0 +1,73 @@ +/* Copyright (c) 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. + */ + +#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/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_actuator/cam_actuator_dev.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_actuator/cam_actuator_dev.c new file mode 100644 index 000000000000..96fdfeb1b4ba --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_actuator/cam_actuator_dev.c @@ -0,0 +1,440 @@ +/* Copyright (c) 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. + */ + +#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 = + (struct i2c_settings_array *) + 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.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; + + v4l2_set_subdevdata(&(a_ctrl->v4l2_dev_str.sd), a_ctrl); + + 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; + } + + 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(power_info->power_setting); + kfree(power_info->power_down_setting); + kfree(a_ctrl->soc_info.soc_private); + kfree(a_ctrl->i2c_data.per_frame); + a_ctrl->i2c_data.per_frame = NULL; + devm_kfree(&pdev->dev, a_ctrl); + + return rc; +} + +static int32_t cam_actuator_driver_i2c_remove(struct i2c_client *client) +{ + int32_t rc = 0; + 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; + } + + 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; + kfree(power_info->power_setting); + kfree(power_info->power_down_setting); + kfree(a_ctrl->soc_info.soc_private); + a_ctrl->soc_info.soc_private = NULL; + kfree(a_ctrl); + return rc; +} + +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 = + (struct i2c_settings_array *) + 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.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; + + platform_set_drvdata(pdev, a_ctrl); + v4l2_set_subdevdata(&a_ctrl->v4l2_dev_str.sd, 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, + }, + .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/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_actuator/cam_actuator_dev.h b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_actuator/cam_actuator_dev.h new file mode 100644 index 000000000000..c4333a023607 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_actuator/cam_actuator_dev.h @@ -0,0 +1,129 @@ +/* Copyright (c) 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. + */ + +#ifndef _CAM_ACTUATOR_DEV_H_ +#define _CAM_ACTUATOR_DEV_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cam_sensor_util.h" +#include "cam_soc_util.h" +#include "cam_debug_util.h" + +#define NUM_MASTERS 2 +#define NUM_QUEUES 2 + +#define TRUE 1 +#define FALSE 0 + +#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 + * @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 + * @device_name: Device name + */ +struct cam_actuator_ctrl_t { + struct i2c_driver *i2c_driver; + enum cci_i2c_master_t cci_i2c_master; + 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; + char device_name[20]; +}; + +#endif /* _CAM_ACTUATOR_DEV_H_ */ diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_actuator/cam_actuator_soc.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_actuator/cam_actuator_soc.c new file mode 100644 index 000000000000..96dc2840b0dd --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_actuator/cam_actuator_soc.c @@ -0,0 +1,75 @@ +/* Copyright (c) 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. + */ + +#include +#include +#include +#include +#include +#include +#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; + + /* 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; + } + } + + 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/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_actuator/cam_actuator_soc.h b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_actuator/cam_actuator_soc.h new file mode 100644 index 000000000000..05d51f41a24b --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_actuator/cam_actuator_soc.h @@ -0,0 +1,26 @@ +/* Copyright (c) 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. + */ + +#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/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci/Makefile b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci/Makefile new file mode 100644 index 000000000000..2ebe8bde8f4a --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci/Makefile @@ -0,0 +1,8 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_utils +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_cpas/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_utils +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_req_mgr +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_smmu/ + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_cci_dev.o cam_cci_core.o cam_cci_soc.o diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci/cam_cci_core.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci/cam_cci_core.c new file mode 100644 index 000000000000..b975418df86a --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci/cam_cci_core.c @@ -0,0 +1,1383 @@ +/* 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. + */ + +#include +#include "cam_cci_core.h" +#include "cam_cci_dev.h" + +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); + 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; + + /* 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); + } +} + +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); + } + + 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; + 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); + for (i = 0; i < DEBUG_MASTER_REG_COUNT; i++) { + if (i == 6) + continue; + reg_offset = DEBUG_MASTER_REG_START + master*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 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); + 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) +{ + 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); + 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) { + 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; + } + } + 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, "failed rc %d", rc); + return rc; + } + + 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_q[queue]); + + /* + * Todo: If there is a change in frequency of operation + * Wait for previos transaction to complete + */ + + /* 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); + goto rel_mutex; + } + + /* + * 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; + } + + if (c_ctrl->cci_info->retries > CCI_I2C_READ_MAX_RETRIES) { + CAM_ERR(CAM_CCI, "More than max retries"); + goto rel_mutex; + } + + if (read_cfg->data == NULL) { + CAM_ERR(CAM_CCI, "Data ptr is NULL"); + goto rel_mutex; + } + + 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; + } + + 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; + } + + 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; + } + + 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; + } + + 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; + } + + 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; + } + + 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, "wait_for_completion_timeout"); + + rc = wait_for_completion_timeout(&cci_dev-> + cci_master_info[master].reset_complete, CCI_TIMEOUT); + if (rc <= 0) { +#ifdef DUMP_CCI_REGISTERS + cam_cci_dump_registers(cci_dev, master, queue); +#endif + if (rc == 0) + rc = -ETIMEDOUT; + CAM_ERR(CAM_CCI, "wait_for_completion_timeout rc = %d", rc); + cam_cci_flush_queue(cci_dev, master); + goto rel_mutex; + } else { + rc = 0; + } + + 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; + } + index = 0; + CAM_DBG(CAM_CCI, "index %d num_type %d", index, read_cfg->num_byte); + first_byte = 0; + do { + 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++; + } + } + } while (--read_words > 0); +rel_mutex: + mutex_unlock(&cci_dev->cci_master_info[master].mutex_q[queue]); + + 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); + + /* 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); + return rc; + } + /* + * 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); + return rc; + } + if (c_ctrl->cci_info->retries > CCI_I2C_READ_MAX_RETRIES) { + CAM_ERR(CAM_CCI, "More than max retries"); + return rc; + } + rc = cam_cci_data_queue(cci_dev, c_ctrl, queue, sync_en); + if (rc < 0) { + CAM_ERR(CAM_CCI, "failed rc: %d", rc); + return rc; + } + + 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; + do { + if (read_bytes > CCI_READ_MAX) + read_cfg->num_byte = CCI_READ_MAX; + else + read_cfg->num_byte = read_bytes; + rc = cam_cci_read(sd, c_ctrl); + if (rc < 0) { + CAM_ERR(CAM_CCI, "failed rc %d", rc); + goto ERROR; + } + if (read_bytes > CCI_READ_MAX) { + read_cfg->addr += CCI_READ_MAX; + read_cfg->data += CCI_READ_MAX; + read_bytes -= CCI_READ_MAX; + } else { + read_bytes = 0; + } + } while (read_bytes); + +ERROR: + 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; + + CAM_DBG(CAM_CCI, "cmd %d", cci_ctrl->cmd); + switch (cci_ctrl->cmd) { + case MSM_CCI_INIT: + rc = cam_cci_init(sd, cci_ctrl); + break; + case MSM_CCI_RELEASE: + rc = cam_cci_release(sd); + break; + case MSM_CCI_I2C_READ: + rc = cam_cci_read_bytes(sd, cci_ctrl); + 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: + rc = cam_cci_write(sd, cci_ctrl); + 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; + + return rc; +} diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci/cam_cci_core.h b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci/cam_cci_core.h new file mode 100644 index 000000000000..a28d5d8ed303 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci/cam_cci_core.h @@ -0,0 +1,46 @@ +/* Copyright (c) 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. + */ +#ifndef _CAM_CCI_CORE_H_ +#define _CAM_CCI_CORE_H_ + +#include +#include +#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/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci/cam_cci_dev.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci/cam_cci_dev.c new file mode 100644 index 000000000000..ed7fd3435e46 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci/cam_cci_dev.c @@ -0,0 +1,385 @@ +/* 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. + */ + +#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 +#define CCI_TIMEOUT msecs_to_jiffies(500) + +static struct v4l2_subdev *g_cci_subdev; + +struct v4l2_subdev *cam_cci_get_subdev(void) +{ + return g_cci_subdev; +} + +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; + 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; + + irq = cam_io_r_mb(base + CCI_IRQ_STATUS_0_ADDR); + cam_io_w_mb(irq, base + CCI_IRQ_CLEAR_0_ADDR); + cam_io_w_mb(0x1, base + CCI_IRQ_GLOBAL_CLEAR_CMD_ADDR); + + if (irq & CCI_IRQ_STATUS_0_RST_DONE_ACK_BMSK) { + if (cci_dev->cci_master_info[MASTER_0].reset_pending == TRUE) { + cci_dev->cci_master_info[MASTER_0].reset_pending = + FALSE; + complete(&cci_dev->cci_master_info[MASTER_0]. + reset_complete); + } + if (cci_dev->cci_master_info[MASTER_1].reset_pending == TRUE) { + cci_dev->cci_master_info[MASTER_1].reset_pending = + FALSE; + complete(&cci_dev->cci_master_info[MASTER_1]. + reset_complete); + } + } + if (irq & CCI_IRQ_STATUS_0_I2C_M0_RD_DONE_BMSK) { + cci_dev->cci_master_info[MASTER_0].status = 0; + complete(&cci_dev->cci_master_info[MASTER_0].reset_complete); + } + if (irq & 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 & 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); + } + if (irq & CCI_IRQ_STATUS_0_I2C_M1_RD_DONE_BMSK) { + cci_dev->cci_master_info[MASTER_1].status = 0; + complete(&cci_dev->cci_master_info[MASTER_1].reset_complete); + } + if (irq & 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 & 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 & 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 & 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 & CCI_IRQ_STATUS_0_I2C_M0_ERROR_BMSK) { + cci_dev->cci_master_info[MASTER_0].status = -EINVAL; + cam_io_w_mb(CCI_M0_HALT_REQ_RMSK, + base + CCI_HALT_REQ_ADDR); + CAM_DBG(CAM_CCI, "MASTER_0 error 0x%x", irq); + } + if (irq & CCI_IRQ_STATUS_0_I2C_M1_ERROR_BMSK) { + cci_dev->cci_master_info[MASTER_1].status = -EINVAL; + cam_io_w_mb(CCI_M1_HALT_REQ_RMSK, + base + CCI_HALT_REQ_ADDR); + CAM_DBG(CAM_CCI, "MASTER_1 error 0x%x", irq); + } + 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); + g_cci_subdev = &new_cci_dev->v4l2_dev_str.sd; + + 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 = 0; + 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; + + mutex_init(&new_cci_dev->ref_count_mutex); + 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, + }, +}; + +static int cam_cci_assign_fops(void) +{ + struct v4l2_subdev *sd; + + sd = g_cci_subdev; + if (!sd || !(sd->devnode)) { + CAM_ERR(CAM_CRM, + "Invalid args sd node: %pK", sd); + 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/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci/cam_cci_dev.h b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci/cam_cci_dev.h new file mode 100644 index 000000000000..e8ba8b1b1c34 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci/cam_cci_dev.h @@ -0,0 +1,305 @@ +/* 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_DEV_H_ +#define _CAM_CCI_DEV_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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(500) + +#define NUM_MASTERS 2 +#define NUM_QUEUES 2 + +#define TRUE 1 +#define FALSE 0 + +#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 12 +#define CCI_I2C_READ_MAX_RETRIES 3 +#define CCI_I2C_MAX_READ 8192 +#define CCI_I2C_MAX_WRITE 8192 + +#define CAMX_CCI_DEV_NAME "cam-cci-driver" + +/* Max bytes that can be read per CCI read transaction */ +#define CCI_READ_MAX 12 +#define CCI_I2C_READ_MAX_RETRIES 3 +#define CCI_I2C_MAX_READ 8192 +#define CCI_I2C_MAX_WRITE 8192 + +#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; +}; + +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 mutex mutex_q[NUM_QUEUES]; + struct completion report_q[NUM_QUEUES]; + atomic_t done_pending[NUM_QUEUES]; + spinlock_t lock_q[NUM_QUEUES]; +}; + +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 + */ +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; + struct mutex ref_count_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; +}; + +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); + +#ifdef CONFIG_SPECTRA_CAMERA +extern struct v4l2_subdev *cam_cci_get_subdev(void); +#else +static inline struct v4l2_subdev *cam_cci_get_subdev(void) +{ + return NULL; +} +#endif + +#define VIDIOC_MSM_CCI_CFG \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 23, struct cam_cci_ctrl *) + +#endif /* _CAM_CCI_DEV_H_ */ diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci/cam_cci_hwreg.h b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci/cam_cci_hwreg.h new file mode 100644 index 000000000000..c18593eb5e78 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci/cam_cci_hwreg.h @@ -0,0 +1,69 @@ +/* Copyright (c) 2012-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. + */ + +#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_CLEAR_0_ADDR 0x00000c08 +#define CCI_IRQ_STATUS_0_ADDR 0x00000c0c +#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_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_RD_DONE_BMSK 0x1 +#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 8 +#define DEBUG_MASTER_QUEUE_REG_START 0x300 +#define DEBUG_MASTER_QUEUE_REG_COUNT 6 +#define DEBUG_INTR_REG_START 0xC00 +#define DEBUG_INTR_REG_COUNT 7 +#endif /* _CAM_CCI_HWREG_ */ diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci/cam_cci_soc.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci/cam_cci_soc.c new file mode 100644 index 000000000000..d104e206c2c3 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci/cam_cci_soc.c @@ -0,0 +1,409 @@ +/* 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. + */ + +#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 = MASTER_0; + struct cam_ahb_vote ahb_vote; + struct cam_axi_vote axi_vote; + 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); + + mutex_lock(&cci_dev->ref_count_mutex); + if (cci_dev->ref_count++) { + CAM_DBG(CAM_CCI, "ref_count %d", cci_dev->ref_count); + master = c_ctrl->cci_info->cci_i2c_master; + 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); + 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; + /* 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); + mutex_unlock(&cci_dev->cci_master_info[master].mutex); + } + mutex_unlock(&cci_dev->ref_count_mutex); + return 0; + } + + mutex_unlock(&cci_dev->ref_count_mutex); + ahb_vote.type = CAM_VOTE_ABSOLUTE; + ahb_vote.vote.level = CAM_SVS_VOTE; + axi_vote.compressed_bw = CAM_CPAS_DEFAULT_AXI_BW; + axi_vote.uncompressed_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); + 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_0].reset_pending = TRUE; + 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_0].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(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]); + } + } + 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: + mutex_lock(&cci_dev->ref_count_mutex); + cci_dev->ref_count--; + mutex_unlock(&cci_dev->ref_count_mutex); + 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; + mutex_init(&new_cci_dev->cci_master_info[i].mutex); + init_completion(&new_cci_dev-> + cci_master_info[i].reset_complete); + + 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]); + } + } +} + +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; + + mutex_lock(&cci_dev->ref_count_mutex); + 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); + mutex_unlock(&cci_dev->ref_count_mutex); + return -EINVAL; + } + if (--cci_dev->ref_count) { + CAM_DBG(CAM_CCI, "ref_count Exit %d", cci_dev->ref_count); + mutex_unlock(&cci_dev->ref_count_mutex); + return 0; + } + mutex_unlock(&cci_dev->ref_count_mutex); + + 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/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci/cam_cci_soc.h b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci/cam_cci_soc.h new file mode 100644 index 000000000000..331227bbee3b --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci/cam_cci_soc.h @@ -0,0 +1,52 @@ +/* Copyright (c) 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. + */ + +#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/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_csiphy/Makefile b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_csiphy/Makefile new file mode 100644 index 000000000000..110171480119 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_csiphy/Makefile @@ -0,0 +1,9 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_utils +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_cpas/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_utils +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_req_mgr +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_smmu/ + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_csiphy_soc.o cam_csiphy_dev.o cam_csiphy_core.o diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_csiphy/cam_csiphy_core.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_csiphy/cam_csiphy_core.c new file mode 100644 index 000000000000..8b092b664f2c --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_csiphy/cam_csiphy_core.c @@ -0,0 +1,724 @@ +/* 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. + */ + +#include +#include "cam_csiphy_core.h" +#include "cam_csiphy_dev.h" +#include "cam_csiphy_soc.h" + +#include +#include + +#define SCM_SVC_CAMERASS 0x18 +#define SECURE_SYSCALL_ID 0x6 + +static int csiphy_dump; +module_param(csiphy_dump, int, 0644); + +static int cam_csiphy_notify_secure_mode(int phy, bool protect) +{ + struct scm_desc desc = {0}; + + desc.arginfo = SCM_ARGS(2, SCM_VAL, SCM_VAL); + desc.args[0] = protect; + desc.args[1] = phy; + + CAM_DBG(CAM_CSIPHY, "phy : %d, protect : %d", phy, protect); + if (scm_call2(SCM_SIP_FNID(SCM_SVC_CAMERASS, SECURE_SYSCALL_ID), + &desc)) { + CAM_ERR(CAM_CSIPHY, "scm call to hypervisor failed"); + return -EINVAL; + } + + return 0; +} + +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_cmd_buf_parser(struct csiphy_device *csiphy_dev, + struct cam_config_dev_cmd *cfg_dev) +{ + int32_t rc = 0; + uint64_t generic_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; + + 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, + (uint64_t *)&generic_ptr, &len); + if (rc < 0) { + CAM_ERR(CAM_CSIPHY, "Failed to get packet Mem address: %d", rc); + return rc; + } + + if (cfg_dev->offset > len) { + CAM_ERR(CAM_CSIPHY, + "offset is out of bounds: offset: %lld len: %zu", + cfg_dev->offset, len); + return -EINVAL; + } + + csl_packet = (struct cam_packet *)(generic_ptr + cfg_dev->offset); + + 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, + (uint64_t *)&generic_ptr, &len); + if (rc < 0) { + CAM_ERR(CAM_CSIPHY, + "Failed to get cmd buf Mem address : %d", rc); + 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; + 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; + csiphy_dev->csiphy_info.secure_mode = cam_cmd_csiphy_info->secure_mode; + + 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_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; + void __iomem *base = NULL; + + if (!csiphy_dev) { + CAM_ERR(CAM_CSIPHY, "Invalid Args"); + return -EINVAL; + } + + soc_info = &csiphy_dev->soc_info; + base = csiphy_dev->soc_info.reg_map[0].mem_base; + + for (i = 0; i < csiphy_dev->num_irq_registers; i++) { + irq = cam_io_r( + base + + csiphy_dev->ctrl_reg->csiphy_reg. + mipi_csiphy_interrupt_status0_addr + 0x4*i); + cam_io_w_mb(irq, + base + + csiphy_dev->ctrl_reg->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_dev->ctrl_reg->csiphy_reg. + mipi_csiphy_interrupt_clear0_addr + 0x4*i); + } + cam_io_w_mb(0x1, base + + csiphy_dev->ctrl_reg-> + csiphy_reg.mipi_csiphy_glbl_irq_cmd_addr); + cam_io_w_mb(0x0, base + + csiphy_dev->ctrl_reg-> + 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; + void __iomem *csiphybase; + 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 & 0x1f; + 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) + reg_array = + csiphy_dev->ctrl_reg->csiphy_2ph_3ph_mode_reg; + 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 & 0x7; + 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++) { + switch (csiphy_dev->ctrl_reg-> + csiphy_common_reg[i].csiphy_param_type) { + case CSIPHY_LANE_ENABLE: + cam_io_w_mb(lane_enable, + csiphybase + + csiphy_dev->ctrl_reg-> + csiphy_common_reg[i].reg_addr); + usleep_range(csiphy_dev->ctrl_reg-> + csiphy_common_reg[i].delay*1000, + csiphy_dev->ctrl_reg-> + csiphy_common_reg[i].delay*1000 + 10); + break; + case CSIPHY_DEFAULT_PARAMS: + cam_io_w_mb(csiphy_dev->ctrl_reg-> + csiphy_common_reg[i].reg_data, + csiphybase + + csiphy_dev->ctrl_reg-> + csiphy_common_reg[i].reg_addr); + usleep_range(csiphy_dev->ctrl_reg-> + csiphy_common_reg[i].delay*1000, + csiphy_dev->ctrl_reg-> + csiphy_common_reg[i].delay*1000 + 10); + break; + default: + break; + } + } + + while (lane_mask) { + if (!(lane_mask & 0x1)) { + lane_pos++; + lane_mask >>= 1; + continue; + } + + settle_cnt = (csiphy_dev->csiphy_info.settle_time / 200000000); + if (csiphy_dev->csiphy_info.combo_mode == 1 && + (lane_pos >= 3)) + settle_cnt = + (csiphy_dev->csiphy_info. + settle_time_combo_sensor / 200000000); + 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; + } + usleep_range(reg_array[lane_pos][i].delay*1000, + reg_array[lane_pos][i].delay*1000 + 1000); + } + lane_mask >>= 1; + lane_pos++; + } + + 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; + + if (csiphy_dev->csiphy_state == CAM_CSIPHY_INIT) + return; + + if (csiphy_dev->csiphy_state == CAM_CSIPHY_START) { + soc_info = &csiphy_dev->soc_info; + + if (csiphy_dev->csiphy_info.secure_mode) + cam_csiphy_notify_secure_mode( + csiphy_dev->soc_info.index, + CAM_SECURE_MODE_NON_SECURE); + + csiphy_dev->csiphy_info.secure_mode = + CAM_SECURE_MODE_NON_SECURE; + + 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, + (void __user *)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 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; + + rc = copy_from_user(&csiphy_acq_dev, + (void __user *)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, + (void __user *)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); + csiphy_dev->bridge_intf. + device_hdl[csiphy_acq_params.combo_mode] = + csiphy_acq_dev.device_handle; + csiphy_dev->bridge_intf. + session_hdl[csiphy_acq_params.combo_mode] = + csiphy_acq_dev.session_handle; + + if (copy_to_user((void __user *)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((void __user *)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: { + 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); + goto release_mutex; + } + + if (--csiphy_dev->start_dev_count) { + CAM_DBG(CAM_CSIPHY, "Stop Dev ref Cnt: %d", + csiphy_dev->start_dev_count); + goto release_mutex; + } + + if (csiphy_dev->csiphy_info.secure_mode) + cam_csiphy_notify_secure_mode( + csiphy_dev->soc_info.index, + CAM_SECURE_MODE_NON_SECURE); + + csiphy_dev->csiphy_info.secure_mode = + CAM_SECURE_MODE_NON_SECURE; + + 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->acquire_count) { + CAM_ERR(CAM_CSIPHY, "No valid devices to release"); + rc = -EINVAL; + goto release_mutex; + } + + if (copy_from_user(&release, (void __user *) 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; + } + break; + case CAM_CONFIG_DEV: { + struct cam_config_dev_cmd config; + + if (copy_from_user(&config, (void __user *)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; + + if (csiphy_dev->csiphy_state == CAM_CSIPHY_START) { + csiphy_dev->start_dev_count++; + goto release_mutex; + } + + ahb_vote.type = CAM_VOTE_ABSOLUTE; + ahb_vote.vote.level = CAM_SVS_VOTE; + axi_vote.compressed_bw = CAM_CPAS_DEFAULT_AXI_BW; + axi_vote.uncompressed_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); + goto release_mutex; + } + + if (csiphy_dev->csiphy_info.secure_mode) { + rc = cam_csiphy_notify_secure_mode( + csiphy_dev->soc_info.index, + CAM_SECURE_MODE_SECURE); + if (rc < 0) + csiphy_dev->csiphy_info.secure_mode = + CAM_SECURE_MODE_NON_SECURE; + } + + 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, + (void __user *)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/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_csiphy/cam_csiphy_core.h b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_csiphy/cam_csiphy_core.h new file mode 100644 index 000000000000..361004beb3cd --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_csiphy/cam_csiphy_core.h @@ -0,0 +1,59 @@ +/* Copyright (c) 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. + */ + +#ifndef _CAM_CSIPHY_CORE_H_ +#define _CAM_CSIPHY_CORE_H_ + +#include +#include "cam_csiphy_dev.h" +#include +#include +#include + +/** + * @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/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c new file mode 100644 index 000000000000..e2f061f49a31 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_csiphy/cam_csiphy_dev.c @@ -0,0 +1,252 @@ +/* Copyright (c) 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. + */ + +#include "cam_csiphy_dev.h" +#include "cam_req_mgr_dev.h" +#include "cam_csiphy_soc.h" +#include "cam_csiphy_core.h" +#include + +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)); + v4l2_set_subdevdata(&(new_csiphy_dev->v4l2_dev_str.sd), new_csiphy_dev); + + 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_cpas_unregister_client(csiphy_dev->cpas_handle); + cam_csiphy_soc_release(csiphy_dev); + kfree(csiphy_dev->ctrl_reg); + 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, + }, +}; + +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/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h new file mode 100644 index 000000000000..afe4239b2d71 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h @@ -0,0 +1,238 @@ +/* Copyright (c) 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. + */ + +#ifndef _CAM_CSIPHY_DEV_H_ +#define _CAM_CSIPHY_DEV_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cam_soc_util.h" +#include "cam_debug_util.h" + +#define MAX_CSIPHY 3 +#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 20 + +#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 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 + */ +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; +}; + +/** + * 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[2]; + int32_t session_hdl[2]; + int32_t link_hdl[2]; + 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_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 + */ +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]; +}; + +/** + * 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 + * + */ +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; + uint64_t settle_time; + uint64_t settle_time_combo_sensor; + uint64_t data_rate; +}; + +/** + * struct csiphy_device + * @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 + * @csiphy_clk_index: Timer Src clk index + * @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 + */ +struct csiphy_device { + 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]; + uint32_t csiphy_clk_index; + unsigned char csi_3phase; + int32_t ref_count; + uint16_t lane_mask[MAX_CSIPHY]; + uint8_t is_csiphy_3phase_hw; + 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; + char device_name[20]; + uint32_t is_acquired_dev_combo_mode; + struct cam_hw_soc_info soc_info; + uint32_t cpas_handle; + uint32_t config_count; +}; + +#endif /* _CAM_CSIPHY_DEV_H_ */ diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c new file mode 100644 index 000000000000..6db5a9796606 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_csiphy/cam_csiphy_soc.c @@ -0,0 +1,237 @@ +/* Copyright (c) 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. + */ + +#include "cam_csiphy_soc.h" +#include "cam_csiphy_core.h" +#include "include/cam_csiphy_1_0_hwreg.h" + +#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; +} + +int32_t cam_csiphy_enable_hw(struct csiphy_device *csiphy_dev) +{ + int32_t rc = 0; + struct cam_hw_soc_info *soc_info; + + soc_info = &csiphy_dev->soc_info; + + if (csiphy_dev->ref_count++) { + CAM_ERR(CAM_CSIPHY, "csiphy refcount = %d", + csiphy_dev->ref_count); + return rc; + } + + rc = cam_soc_util_enable_platform_resource(soc_info, true, + CAM_SVS_VOTE, ENABLE_IRQ); + if (rc < 0) { + CAM_ERR(CAM_CSIPHY, "failed to enable platform resources %d", + rc); + return rc; + } + + rc = cam_soc_util_set_clk_rate( + soc_info->clk[csiphy_dev->csiphy_clk_index], + soc_info->clk_name[csiphy_dev->csiphy_clk_index], + soc_info->clk_rate[0][csiphy_dev->csiphy_clk_index]); + + 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(csiphy_dev->v4l2_dev_str.pdev->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->hw_version = CSIPHY_VERSION_V10; + csiphy_dev->is_csiphy_3phase_hw = CSI_3PHASE_HW; + csiphy_dev->clk_lane = 0; + } 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; + } + + if (!strcmp(soc_info->clk_name[i], + "csiphy_timer_src_clk")) { + csiphy_dev->csiphy_max_clk = + soc_info->clk_rate[0][clk_cnt]; + csiphy_dev->csiphy_clk_index = clk_cnt; + } + CAM_DBG(CAM_CSIPHY, "clk_rate[%d] = %d", clk_cnt, + soc_info->clk_rate[0][clk_cnt]); + clk_cnt++; + } + 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/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_csiphy/cam_csiphy_soc.h b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_csiphy/cam_csiphy_soc.h new file mode 100644 index 000000000000..443048979d67 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_csiphy/cam_csiphy_soc.h @@ -0,0 +1,78 @@ +/* Copyright (c) 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. + */ + +#ifndef _CAM_CSIPHY_SOC_H_ +#define _CAM_CSIPHY_SOC_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 + +/** + * @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/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_0_hwreg.h b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_0_hwreg.h new file mode 100644 index 000000000000..d37f09a30dfe --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_csiphy/include/cam_csiphy_1_0_hwreg.h @@ -0,0 +1,355 @@ +/* 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_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, 0x01, 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, 0x01, 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, 0x01, 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, 0x01, 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, 0x01, 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, 0x43, 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}, + {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, 0x43, 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}, + {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, 0x43, 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}, + {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/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_eeprom/Makefile b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_eeprom/Makefile new file mode 100644 index 000000000000..f7e1be6ff233 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_eeprom/Makefile @@ -0,0 +1,8 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_utils +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_cpas/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_utils +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_req_mgr +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_smmu/ +obj-$(CONFIG_SPECTRA_CAMERA) += cam_eeprom_dev.o cam_eeprom_core.o cam_eeprom_soc.o diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_eeprom/cam_eeprom_core.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_eeprom/cam_eeprom_core.c new file mode 100644 index 000000000000..2158ff686229 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_eeprom/cam_eeprom_core.c @@ -0,0 +1,983 @@ +/* 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. + */ + +#include +#include +#include + +#include "cam_eeprom_core.h" +#include "cam_eeprom_soc.h" +#include "cam_debug_util.h" + +#include +struct ois_vendor_match_tbl { + uint16_t ois_id; + char ois_name[32]; + char vendor_name[32]; +}; +static struct ois_vendor_match_tbl match_tbl[] = { + {0x24, "BU24218GWL", "Rohm"}, + {0x28, "BU24228GWL", "Rohm"}, +}; + +/** + * 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; + struct cam_sensor_i2c_reg_array i2c_reg_array; + struct cam_eeprom_memory_map_t *emap = block->map; + struct cam_eeprom_soc_private *eb_info; + uint8_t *memptr = block->mapdata; + + int ret = 0; + uint32_t reg_data; + uint32_t ois_driver_id; + uint16_t eeprom_slave_addr = 0xA0>>1; // 0xA0>>1 is the slave address of main camera Eeprom + uint16_t ois_driver_id_reg_addr = 0x0110; // 0x0110 and 0x0111 are the registers of OIS driver ID + + 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 (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.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; + } + } + } + + if (e_ctrl->io_master_info.cci_client->sid == eeprom_slave_addr) { + ret = camera_io_dev_read(&(e_ctrl->io_master_info), ois_driver_id_reg_addr, ®_data, + CAMERA_SENSOR_I2C_TYPE_WORD, CAMERA_SENSOR_I2C_TYPE_BYTE); + if (ret) { + CAM_ERR(CAM_EEPROM, "failed: to read 0x%x rc %d", ois_driver_id_reg_addr, ret); + } else { + ois_driver_id = reg_data & 0xFF; + ret = camera_io_dev_read(&(e_ctrl->io_master_info), ois_driver_id_reg_addr+1, ®_data, + CAMERA_SENSOR_I2C_TYPE_WORD, CAMERA_SENSOR_I2C_TYPE_BYTE); + if (ret) { + CAM_ERR(CAM_EEPROM, "failed: to read 0x%x rc %d", ois_driver_id_reg_addr+1, ret); + } else { + ois_driver_id = ((reg_data & 0xFF) << 8) | ois_driver_id; + if (ois_driver_id == match_tbl[0].ois_id) { + push_component_info(OIS, match_tbl[0].ois_name, + match_tbl[0].vendor_name); + } else if (ois_driver_id == match_tbl[1].ois_id) { + push_component_info(OIS, match_tbl[1].ois_name, + match_tbl[1].vendor_name); + } + CAM_ERR(CAM_EEPROM, "OIS module 0x%x", ois_driver_id); + } + } + } + + 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 = msm_camera_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: + kvfree(e_ctrl->cal_data.mapdata); + kfree(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, (void __user *) 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((void __user *) 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, uint16_t *cmd_length_bytes, + int *num_map) +{ + 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; + + generic_op_code = cmm_hdr->third_byte; + switch (cmm_hdr->cmd_type) { + case CAMERA_SENSOR_CMD_TYPE_I2C_RNDM_WR: + i2c_random_wr = (struct cam_cmd_i2c_random_wr *)cmd_buf; + cmd_length_in_bytes = sizeof(struct cam_cmd_i2c_random_wr) + + ((i2c_random_wr->header.count - 1) * + sizeof(struct i2c_random_wr_payload)); + + 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); + + 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; +} + +/** + * 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; + uint64_t generic_pkt_addr; + size_t pkt_len = 0; + uint32_t total_cmd_buf_in_bytes = 0; + uint32_t processed_cmd_buf_in_bytes = 0; + struct common_header *cmm_hdr = NULL; + uint16_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 = kcalloc((MSM_EEPROM_MEMORY_MAP_MAX_SIZE * + MSM_EEPROM_MAX_MEM_MAP_CNT), + (sizeof(struct cam_eeprom_memory_map_t)), GFP_KERNEL); + 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, + (uint64_t *)&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"); + return -EINVAL; + } + cmd_buf += cmd_desc[i].offset / sizeof(uint32_t); + /* Loop through multiple cmd formats in one cmd buffer */ + while (processed_cmd_buf_in_bytes < total_cmd_buf_in_bytes) { + 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; + /* 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); + 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"); + return rc; + } + 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); + processed_cmd_buf_in_bytes += + cmd_length_in_bytes; + cmd_buf += cmd_length_in_bytes/sizeof(uint32_t); + break; + default: + break; + } + } + e_ctrl->cal_data.num_map = num_map + 1; + } + 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; + uint64_t buf_addr; + size_t buf_size; + uint8_t *read_buffer; + + 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], + (uint64_t *)&buf_addr, &buf_size); + 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"); + return -EINVAL; + } + read_buffer += io_cfg->offsets[0]; + + if (buf_size < e_ctrl->cal_data.num_data) { + CAM_ERR(CAM_EEPROM, + "failed to copy, Invalid size"); + return -EINVAL; + } + + 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; +} + +/** + * 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; + uint64_t generic_pkt_addr; + size_t pkt_len; + 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, (void __user *) ioctl_ctrl->handle, + sizeof(dev_config))) + return -EFAULT; + rc = cam_mem_get_cpu_buf(dev_config.packet_handle, + (uint64_t *)&generic_pkt_addr, &pkt_len); + if (rc) { + CAM_ERR(CAM_EEPROM, + "error in converting command Handle Error: %d", rc); + return rc; + } + + if (dev_config.offset > pkt_len) { + CAM_ERR(CAM_EEPROM, + "Offset is out of bound: off: %lld, %zu", + dev_config.offset, pkt_len); + return -EINVAL; + } + + csl_packet = (struct cam_packet *) + (generic_pkt_addr + dev_config.offset); + 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); + kvfree(e_ctrl->cal_data.mapdata); + kfree(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; + } + + if ((e_ctrl->cal_data.num_data) < PAGE_SIZE) { + e_ctrl->cal_data.mapdata = + kzalloc(e_ctrl->cal_data.num_data, GFP_KERNEL); + if (!e_ctrl->cal_data.mapdata) { + rc = -ENOMEM; + CAM_ERR(CAM_EEPROM, "failed"); + goto error; + } + } else { + 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; + } + } + + 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; + kvfree(e_ctrl->cal_data.mapdata); + kfree(e_ctrl->cal_data.map); + e_ctrl->cal_data.num_data = 0; + e_ctrl->cal_data.num_map = 0; + break; + default: + break; + } + return rc; +power_down: + cam_eeprom_power_down(e_ctrl); +memdata_free: + kvfree(e_ctrl->cal_data.mapdata); +error: + kfree(power_info->power_setting); + kfree(power_info->power_down_setting); + kfree(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_INIT; + 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); + } + + 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, "e_ctrl is NULL"); + return -EINVAL; + } + + if (cmd->handle_type != CAM_HANDLE_USER_POINTER) { + CAM_ERR(CAM_EEPROM, "Invalid 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; + + if (copy_to_user((void __user *) cmd->handle, + &eeprom_cap, + sizeof(struct cam_eeprom_query_cap_t))) { + CAM_ERR(CAM_EEPROM, "Failed Copy to User"); + return -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/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_eeprom/cam_eeprom_core.h b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_eeprom/cam_eeprom_core.h new file mode 100644 index 000000000000..c9fccbb173e7 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_eeprom/cam_eeprom_core.h @@ -0,0 +1,28 @@ +/* Copyright (c) 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. + */ +#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/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c new file mode 100644 index 000000000000..68c5eea0b175 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_eeprom/cam_eeprom_dev.c @@ -0,0 +1,573 @@ +/* Copyright (c) 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. + */ + +#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; + } + 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)); + + 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; + + 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; + + e_ctrl->cal_data.mapdata = NULL; + e_ctrl->cal_data.map = NULL; + e_ctrl->userspace_probe = false; + + 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; + v4l2_set_subdevdata(&e_ctrl->v4l2_dev_str.sd, e_ctrl); + 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; + } + + 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]); + + if (soc_private) + kfree(soc_private); + + 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; + + 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)); + + 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.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; + + 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]); + + kfree(e_ctrl->io_master_info.spi_client); + soc_private = + (struct cam_eeprom_soc_private *)e_ctrl->soc_info.soc_private; + if (soc_private) { + kfree(soc_private->power_info.gpio_num_info); + kfree(soc_private); + } + 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; + } + + 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); + v4l2_set_subdevdata(&e_ctrl->v4l2_dev_str.sd, 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; + } + + 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]); + + kfree(soc_info->soc_private); + kfree(e_ctrl->io_master_info.cci_client); + 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, + }, + .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/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_eeprom/cam_eeprom_dev.h b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_eeprom/cam_eeprom_dev.h new file mode 100644 index 000000000000..4a2190da7c70 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_eeprom/cam_eeprom_dev.h @@ -0,0 +1,189 @@ +/* Copyright (c) 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. + */ +#ifndef _CAM_EEPROM_DEV_H_ +#define _CAM_EEPROM_DEV_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cam_soc_util.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 8 +#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 cam_cmd_conditional_wait - Conditional wait command + * @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 + * + */ +struct cam_eeprom_ctrl_t { + 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; + 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; + char device_name[20]; +}; + +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/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_eeprom/cam_eeprom_soc.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_eeprom/cam_eeprom_soc.c new file mode 100644 index 000000000000..3280899bb3e2 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_eeprom/cam_eeprom_soc.c @@ -0,0 +1,382 @@ +/* Copyright (c) 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. + */ + +#include +#include +#include +#include +#include +#include + +#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 = kzalloc((sizeof(*map) * data->num_map), GFP_KERNEL); + 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; + } + + if (data->num_data < PAGE_SIZE) { + data->mapdata = kzalloc(data->num_data, GFP_KERNEL); + if (!data->mapdata) { + rc = -ENOMEM; + goto ERROR; + } + } else { + data->mapdata = vzalloc(data->num_data); + if (!data->mapdata) { + rc = -ENOMEM; + goto ERROR; + } + } + return rc; + +ERROR: + kfree(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 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; + } + + 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; + + 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; + } + } + + 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/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_eeprom/cam_eeprom_soc.h b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_eeprom/cam_eeprom_soc.h new file mode 100644 index 000000000000..d3115499173c --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_eeprom/cam_eeprom_soc.h @@ -0,0 +1,23 @@ +/* Copyright (c) 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. + */ +#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/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_flash/Makefile b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_flash/Makefile new file mode 100644 index 000000000000..aa8032fdca5e --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_flash/Makefile @@ -0,0 +1,10 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_utils +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_sync +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_res_mgr +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_utils +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_req_mgr +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_smmu/ + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_flash_dev.o cam_flash_core.o cam_flash_soc.o diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_flash/cam_flash_core.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_flash/cam_flash_core.c new file mode 100644 index 000000000000..3452a8e1b698 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_flash/cam_flash_core.c @@ -0,0 +1,982 @@ +/* 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. + */ + +#include + +#include "cam_sensor_cmn_header.h" +#include "cam_flash_core.h" +#include "cam_res_mgr_api.h" + +int cam_flash_prepare(struct cam_flash_ctrl *flash_ctrl, + bool regulator_enable) +{ + int rc = 0; + + if (!(flash_ctrl->switch_trigger)) { + CAM_ERR(CAM_FLASH, "Invalid argument"); + return -EINVAL; + } + + 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_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; +} + +int cam_flash_flush_request(struct cam_req_mgr_flush_request *flush) +{ + int rc = 0; + int i = 0, j = 0; + struct cam_flash_ctrl *fctrl = NULL; + int frame_offset = 0; + + fctrl = (struct cam_flash_ctrl *) cam_get_device_priv(flush->dev_hdl); + if (!fctrl) { + CAM_ERR(CAM_FLASH, "Device data is NULL"); + return -EINVAL; + } + + if (flush->type == CAM_REQ_MGR_FLUSH_TYPE_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; + } + + rc = cam_flash_flush_nrt(fctrl); + if (rc) + CAM_ERR(CAM_FLASH, "NonRealTime flush error"); + } else if (flush->type == CAM_REQ_MGR_FLUSH_TYPE_CANCEL_REQ) { + /* flush request with req_id*/ + frame_offset = flush->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; + } + 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_data->led_current_ma[i]) { + if (i) + flash_data->led_current_ma[i-1] = + flash_data->led_current_ma[i]; + else + flash_data->led_current_ma[i+1] = + flash_data->led_current_ma[i]; + break; + } + } + } else if (op == CAMERA_SENSOR_FLASH_OP_FIREHIGH) { + for (i = 0; i < flash_ctrl->flash_num_sources; i++) { + if (flash_data->led_current_ma[i]) { + if (i) + flash_data->led_current_ma[i-1] = + flash_data->led_current_ma[i]; + else + flash_data->led_current_ma[i+1] = + flash_data->led_current_ma[i]; + break; + } + } + } else { + CAM_ERR(CAM_FLASH, "Wrong Operation: %d", op); + } + + 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 = soc_private->torch_op_current[i]; + + CAM_DBG(CAM_FLASH, + "Led_Current[%d] = %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 = soc_private->flash_op_current[i]; + + CAM_DBG(CAM_FLASH, "LED flash_current[%d]: %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, + LED_SWITCH_ON); + + return 0; +} + +int cam_flash_off(struct cam_flash_ctrl *flash_ctrl) +{ + int i = 0; + + if (!flash_ctrl) { + CAM_ERR(CAM_FLASH, "Flash control 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); + + 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); + + if (flash_ctrl->switch_trigger) + cam_res_mgr_led_trigger_event(flash_ctrl->switch_trigger, + 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 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) { + flash_data = &fctrl->nrt_info; + if ((fctrl->nrt_info.cmn_attr.cmd_type == + CAMERA_SENSOR_FLASH_CMD_TYPE_WIDGET) || + (fctrl->nrt_info.cmn_attr.cmd_type == + CAMERA_SENSOR_FLASH_CMD_TYPE_RER)) { + 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; + } else { + fctrl->flash_init_setting.cmn_attr. + is_settings_valid = false; + } + } else { + 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); + + for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) { + flash_data = &fctrl->per_frame[i]; + if ((del_req_id == + flash_data->cmn_attr.request_id) && + (flash_data->cmn_attr. + is_settings_valid == 1)) { + CAM_DBG(CAM_FLASH, "Deleting request[%d] %llu", + i, flash_data->cmn_attr.request_id); + flash_data->cmn_attr.request_id = 0; + flash_data->cmn_attr.is_settings_valid = false; + flash_data->opcode = 0; + for (i = 0; i < flash_data->cmn_attr.count; i++) + flash_data->led_current_ma[i] = 0; + } + } + } + + return 0; +} + +int cam_flash_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; + if (flash_data->opcode == + CAMERA_SENSOR_FLASH_OP_FIREHIGH) { + if (fctrl->flash_state != + CAM_FLASH_STATE_CONFIG) { + CAM_WARN(CAM_FLASH, + "Cannot apply Start Dev:Prev state: %d", + fctrl->flash_state); + return rc; + } + rc = cam_flash_prepare(fctrl, true); + if (rc) { + CAM_ERR(CAM_FLASH, + "Enable Regulator Failed rc = %d", rc); + return rc; + } + 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_OFF) { + rc = cam_flash_off(fctrl); + if (rc) { + CAM_ERR(CAM_FLASH, + "LED OFF FAILED: %d", + rc); + return rc; + } + 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: %d", + rc); + } + } + } else if (fctrl->nrt_info.cmn_attr.cmd_type == + CAMERA_SENSOR_FLASH_CMD_TYPE_WIDGET) { + flash_data = &fctrl->nrt_info; + 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; + } + } + 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]; + + 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 { + CAM_DBG(CAM_FLASH, "NOP opcode: req_id: %u", req_id); + } + } + +nrt_del_req: + delete_req(fctrl, req_id); +apply_setting_err: + return rc; +} + +int cam_flash_parser(struct cam_flash_ctrl *fctrl, void *arg) +{ + int rc = 0, i = 0; + uint64_t generic_ptr; + uint32_t *cmd_buf = NULL; + uint32_t *offset = NULL; + uint32_t frame_offset = 0; + size_t len_of_buffer; + 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; + 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; + + 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"); + rc = -EFAULT; + return rc; + } + + rc = cam_mem_get_cpu_buf(config.packet_handle, + (uint64_t *)&generic_ptr, &len_of_buffer); + if (rc) { + CAM_ERR(CAM_FLASH, "Failed in getting the buffer : %d", rc); + return rc; + } + + if (config.offset > len_of_buffer) { + CAM_ERR(CAM_FLASH, + "offset is out of bounds: offset: %lld len: %zu", + config.offset, len_of_buffer); + return -EINVAL; + } + + /* Add offset to the flash csl header */ + csl_packet = (struct cam_packet *)(generic_ptr + config.offset); + + 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); + fctrl->flash_init_setting.cmn_attr.request_id = 0; + fctrl->flash_init_setting.cmn_attr.is_settings_valid = true; + cmd_desc = (struct cam_cmd_buf_desc *)(offset); + rc = cam_mem_get_cpu_buf(cmd_desc->mem_handle, + (uint64_t *)&generic_ptr, &len_of_buffer); + cmd_buf = (uint32_t *)((uint8_t *)generic_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: + 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; + fctrl->flash_state = + CAM_FLASH_STATE_CONFIG; + break; + case CAMERA_SENSOR_FLASH_CMD_TYPE_INIT_FIRE: + CAM_DBG(CAM_FLASH, "Widget Flash Operation"); + flash_operation_info = + (struct cam_flash_set_on_off *) cmd_buf; + 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]; + + mutex_lock(&fctrl->flash_wq_mutex); + rc = cam_flash_apply_setting(fctrl, 0); + if (rc) + CAM_ERR(CAM_FLASH, + "Apply setting failed: %d", + rc); + mutex_unlock(&fctrl->flash_wq_mutex); + fctrl->flash_state = + CAM_FLASH_STATE_CONFIG; + break; + default: + CAM_ERR(CAM_FLASH, "Wrong cmd_type = %d", + cam_flash_info->cmd_type); + return -EINVAL; + } + break; + } + case CAM_FLASH_PACKET_OPCODE_SET_OPS: { + offset = (uint32_t *)((uint8_t *)&csl_packet->payload + + csl_packet->cmd_buf_offset); + frame_offset = csl_packet->header.request_id % + MAX_PER_FRAME_ARRAY; + if (fctrl->per_frame[frame_offset].cmn_attr.is_settings_valid + == true) { + fctrl->per_frame[frame_offset].cmn_attr.request_id = 0; + fctrl->per_frame[frame_offset]. + cmn_attr.is_settings_valid = false; + for (i = 0; + i < fctrl->per_frame[frame_offset].cmn_attr.count; + i++) { + fctrl->per_frame[frame_offset]. + led_current_ma[i] = 0; + } + } + + fctrl->per_frame[frame_offset].cmn_attr.request_id = + csl_packet->header.request_id; + fctrl->per_frame[frame_offset].cmn_attr.is_settings_valid = + true; + cmd_desc = (struct cam_cmd_buf_desc *)(offset); + rc = cam_mem_get_cpu_buf(cmd_desc->mem_handle, + (uint64_t *)&generic_ptr, &len_of_buffer); + cmd_buf = (uint32_t *)((uint8_t *)generic_ptr + + cmd_desc->offset); + + if (!cmd_buf) + return -EINVAL; + + cmn_hdr = (struct common_header *)cmd_buf; + + switch (cmn_hdr->cmd_type) { + case CAMERA_SENSOR_FLASH_CMD_TYPE_FIRE: { + CAM_DBG(CAM_FLASH, + "CAMERA_FLASH_CMD_TYPE_OPS case 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"); + fctrl->per_frame[frame_offset]. + cmn_attr.is_settings_valid = false; + return 0; + } + + flash_operation_info = + (struct cam_flash_set_on_off *) cmd_buf; + if (!flash_operation_info) { + CAM_ERR(CAM_FLASH, + "flash_operation_info Null"); + return -EINVAL; + } + + fctrl->per_frame[frame_offset].opcode = + flash_operation_info->opcode; + fctrl->per_frame[frame_offset].cmn_attr.count = + flash_operation_info->count; + for (i = 0; + i < flash_operation_info->count; i++) + fctrl->per_frame[frame_offset]. + led_current_ma[i] + = flash_operation_info-> + led_current_ma[i]; + } + break; + default: + CAM_ERR(CAM_FLASH, "Wrong cmd_type = %d", + cmn_hdr->cmd_type); + return -EINVAL; + } + 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, + (uint64_t *)&generic_ptr, &len_of_buffer); + cmd_buf = (uint32_t *)((uint8_t *)generic_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"); + flash_operation_info = + (struct cam_flash_set_on_off *) cmd_buf; + 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]; + + mutex_lock(&fctrl->flash_wq_mutex); + rc = cam_flash_apply_setting(fctrl, 0); + if (rc) + CAM_ERR(CAM_FLASH, "Apply setting failed: %d", + rc); + mutex_unlock(&fctrl->flash_wq_mutex); + return rc; + } + case CAMERA_SENSOR_FLASH_CMD_TYPE_QUERYCURR: { + int query_curr_ma = 0; + + flash_query_info = + (struct cam_flash_query_curr *)cmd_buf; + + rc = qpnp_flash_led_prepare(fctrl->switch_trigger, + QUERY_MAX_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; + flash_rer_info = (struct cam_flash_set_rer *)cmd_buf; + 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]; + + + mutex_lock(&fctrl->flash_wq_mutex); + rc = cam_flash_apply_setting(fctrl, 0); + if (rc) + CAM_ERR(CAM_FLASH, "apply_setting failed: %d", + rc); + mutex_unlock(&fctrl->flash_wq_mutex); + return rc; + } + default: + CAM_ERR(CAM_FLASH, "Wrong cmd_type : %d", + cmn_hdr->cmd_type); + return -EINVAL; + } + + break; + } + 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"); + fctrl->per_frame[frame_offset]. + cmn_attr.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_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; + } + + 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; + } + + return 0; +} + + +int cam_flash_stop_dev(struct cam_flash_ctrl *fctrl) +{ + int rc = 0, i, j; + + cam_flash_off(fctrl); + + 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; + } + + rc = cam_flash_flush_nrt(fctrl); + if (rc) { + CAM_ERR(CAM_FLASH, + "NonRealTime Dev flush failed rc: %d", rc); + return rc; + } + + 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_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; + } + + 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)) { + rc = cam_flash_stop_dev(fctrl); + if (rc) + CAM_ERR(CAM_FLASH, "Stop 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"); + rc = -EINVAL; + goto free_resource; + } + + if (!(apply->report_if_bubble)) { + mutex_lock(&fctrl->flash_wq_mutex); + rc = cam_flash_apply_setting(fctrl, apply->request_id); + if (rc) + CAM_ERR(CAM_FLASH, "apply_setting failed with rc=%d", + rc); + mutex_unlock(&fctrl->flash_wq_mutex); + } + +free_resource: + return rc; +} diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_flash/cam_flash_core.h b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_flash/cam_flash_core.h new file mode 100644 index 000000000000..f73409a0a935 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_flash/cam_flash_core.h @@ -0,0 +1,35 @@ +/* Copyright (c) 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. + */ + +#ifndef _CAM_FLASH_CORE_H_ +#define _CAM_FLASH_CORE_H_ + +#include +#include +#include "cam_flash_dev.h" +#include "cam_sync_api.h" +#include "cam_mem_mgr_api.h" + +int cam_flash_parser(struct cam_flash_ctrl *fctrl, void *arg); +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_setting(struct cam_flash_ctrl *fctrl, uint64_t req_id); +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); +int cam_flash_off(struct cam_flash_ctrl *fctrl); +int cam_flash_prepare(struct cam_flash_ctrl *flash_ctrl, + bool regulator_enable); +void cam_flash_shutdown(struct cam_flash_ctrl *flash_ctrl); +int cam_flash_stop_dev(struct cam_flash_ctrl *flash_ctrl); +int cam_flash_release_dev(struct cam_flash_ctrl *fctrl); +#endif /*_CAM_FLASH_CORE_H_*/ diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_flash/cam_flash_dev.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_flash/cam_flash_dev.c new file mode 100644 index 000000000000..c69c70b8440a --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_flash/cam_flash_dev.c @@ -0,0 +1,420 @@ +/* Copyright (c) 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. + * + */ + +#include +#include "cam_flash_dev.h" +#include "cam_flash_soc.h" +#include "cam_flash_core.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); + rc = -EINVAL; + goto release_mutex; + } + + 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, (void __user *)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((void __user *) 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, + "Cannot apply 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; + } + rc = cam_flash_release_dev(fctrl); + if (rc) + CAM_ERR(CAM_FLASH, + "Failed in destroying the device Handle rc= %d", + rc); + 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((void __user *) 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; + } + + rc = cam_flash_prepare(fctrl, true); + if (rc) { + CAM_ERR(CAM_FLASH, + "Enable Regulator Failed rc = %d", rc); + goto release_mutex; + } + rc = cam_flash_apply_setting(fctrl, 0); + if (rc) { + CAM_ERR(CAM_FLASH, "cannot apply settings rc = %d", rc); + 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; + } + + rc = cam_flash_stop_dev(fctrl); + if (rc) { + CAM_ERR(CAM_FLASH, "Stop Dev Failed rc = %d", + rc); + goto release_mutex; + } + fctrl->flash_state = CAM_FLASH_STATE_ACQUIRE; + break; + } + case CAM_CONFIG_DEV: { + CAM_DBG(CAM_FLASH, "CAM_CONFIG_DEV"); + rc = cam_flash_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 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; + } + + devm_kfree(&pdev->dev, fctrl); + + return 0; +} + +static int cam_flash_subdev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + struct cam_flash_ctrl *flash_ctrl = + v4l2_get_subdevdata(sd); + + if (!flash_ctrl) { + CAM_ERR(CAM_FLASH, "Flash ctrl ptr is NULL"); + return -EINVAL; + } + + mutex_lock(&flash_ctrl->flash_mutex); + cam_flash_shutdown(flash_ctrl); + mutex_unlock(&flash_ctrl->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 int32_t cam_flash_platform_probe(struct platform_device *pdev) +{ + int32_t rc = 0; + struct cam_flash_ctrl *flash_ctrl = NULL; + + CAM_DBG(CAM_FLASH, "Enter"); + if (!pdev->dev.of_node) { + CAM_ERR(CAM_FLASH, "of_node NULL"); + return -EINVAL; + } + + flash_ctrl = kzalloc(sizeof(struct cam_flash_ctrl), GFP_KERNEL); + if (!flash_ctrl) + return -ENOMEM; + + flash_ctrl->pdev = pdev; + flash_ctrl->soc_info.pdev = pdev; + flash_ctrl->soc_info.dev = &pdev->dev; + flash_ctrl->soc_info.dev_name = pdev->name; + + rc = cam_flash_get_dt_data(flash_ctrl, &flash_ctrl->soc_info); + if (rc) { + CAM_ERR(CAM_FLASH, "cam_flash_get_dt_data failed with %d", rc); + kfree(flash_ctrl); + return -EINVAL; + } + + flash_ctrl->v4l2_dev_str.internal_ops = + &cam_flash_internal_ops; + flash_ctrl->v4l2_dev_str.ops = &cam_flash_subdev_ops; + flash_ctrl->v4l2_dev_str.name = CAMX_FLASH_DEV_NAME; + flash_ctrl->v4l2_dev_str.sd_flags = + V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; + flash_ctrl->v4l2_dev_str.ent_function = CAM_FLASH_DEVICE_TYPE; + flash_ctrl->v4l2_dev_str.token = flash_ctrl; + + rc = cam_register_subdev(&(flash_ctrl->v4l2_dev_str)); + if (rc) { + CAM_ERR(CAM_FLASH, "Fail to create subdev with %d", rc); + goto free_resource; + } + flash_ctrl->bridge_intf.device_hdl = -1; + flash_ctrl->bridge_intf.ops.get_dev_info = cam_flash_publish_dev_info; + flash_ctrl->bridge_intf.ops.link_setup = cam_flash_establish_link; + flash_ctrl->bridge_intf.ops.apply_req = cam_flash_apply_request; + flash_ctrl->bridge_intf.ops.flush_req = cam_flash_flush_request; + + platform_set_drvdata(pdev, flash_ctrl); + v4l2_set_subdevdata(&flash_ctrl->v4l2_dev_str.sd, flash_ctrl); + + mutex_init(&(flash_ctrl->flash_mutex)); + mutex_init(&(flash_ctrl->flash_wq_mutex)); + + flash_ctrl->flash_state = CAM_FLASH_STATE_INIT; + CAM_DBG(CAM_FLASH, "Probe success"); + return rc; +free_resource: + kfree(flash_ctrl); + 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, + }, +}; + +static int __init cam_flash_init_module(void) +{ + int32_t rc = 0; + + rc = platform_driver_register(&cam_flash_platform_driver); + if (rc) + CAM_ERR(CAM_FLASH, "platform probe for flash failed"); + + return rc; +} + +static void __exit cam_flash_exit_module(void) +{ + platform_driver_unregister(&cam_flash_platform_driver); +} + +module_init(cam_flash_init_module); +module_exit(cam_flash_exit_module); +MODULE_DESCRIPTION("CAM FLASH"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_flash/cam_flash_dev.h b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_flash/cam_flash_dev.h new file mode 100644 index 000000000000..92726a9a125c --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_flash/cam_flash_dev.h @@ -0,0 +1,181 @@ +/* Copyright (c) 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. + * + */ + +#ifndef _CAM_FLASH_DEV_H_ +#define _CAM_FLASH_DEV_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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" + +#define CAMX_FLASH_DEV_NAME "cam-flash-dev" + +#define CAM_FLASH_PIPELINE_DELAY 1 + +#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 + +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, +}; + +/** + * 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; + int32_t request_id; + uint16_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; + uint8_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 + */ + +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]; +}; + +/** + * struct cam_flash_ctrl + * @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_wq_mutex : Mutex for flash apply setting + * @flash_state : Current flash state (LOW/OFF/ON/INIT) + * @flash_type : Flash types (PMIC/I2C/GPIO) + * @is_regulator_enable : Regulator disable/enable notifier + * @flash_trigger : Flash trigger ptr + * @torch_trigger : Torch trigger ptr + */ +struct cam_flash_ctrl { + struct cam_hw_soc_info soc_info; + struct platform_device *pdev; + 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; + struct mutex flash_wq_mutex; + enum cam_flash_state flash_state; + uint8_t flash_type; + bool is_regulator_enabled; + struct led_trigger *flash_trigger[CAM_FLASH_MAX_LED_TRIGGERS]; + struct led_trigger *torch_trigger[CAM_FLASH_MAX_LED_TRIGGERS]; +}; + +#endif /*_CAM_FLASH_DEV_H_*/ diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_flash/cam_flash_soc.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_flash/cam_flash_soc.c new file mode 100644 index 000000000000..a195762c249f --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_flash/cam_flash_soc.c @@ -0,0 +1,225 @@ +/* Copyright (c) 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. + */ + +#include +#include +#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; + + switch_src_node = of_parse_phandle(of_node, "switch-source", 0); + if (!switch_src_node) { + CAM_DBG(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, "default trigger %s", + soc_private->flash_trigger_name[i]); + + /* Read operational-current */ + rc = of_property_read_u32(flash_src_node, + "qcom,current-ma", + &soc_private->flash_op_current[i]); + if (rc) { + CAM_WARN(CAM_FLASH, "op-current: read failed"); + of_node_put(flash_src_node); + continue; + } + + /* Read max-current */ + rc = of_property_read_u32(flash_src_node, + "qcom,max-current", + &soc_private->flash_max_current[i]); + if (rc) { + CAM_WARN(CAM_FLASH, + "max-current: read failed"); + of_node_put(flash_src_node); + continue; + } + + /* Read max-duration */ + rc = of_property_read_u32(flash_src_node, + "qcom,duration-ms", + &soc_private->flash_max_duration[i]); + if (rc) + CAM_WARN(CAM_FLASH, + "max-duration: read failed"); + + of_node_put(flash_src_node); + + CAM_DBG(CAM_FLASH, "max_current[%d]: %d", + i, soc_private->flash_max_current[i]); + + cam_res_mgr_led_trigger_register( + soc_private->flash_trigger_name[i], + &fctrl->flash_trigger[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; + } + + /* 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, "current: read failed"); + of_node_put(torch_src_node); + continue; + } + + /* Read max-current */ + rc = of_property_read_u32(torch_src_node, + "qcom,max-current", + &soc_private->torch_max_current[i]); + if (rc < 0) { + CAM_WARN(CAM_FLASH, + "max-current: read failed"); + of_node_put(torch_src_node); + continue; + } + + of_node_put(torch_src_node); + + CAM_DBG(CAM_FLASH, "max_current[%d]: %d", + i, soc_private->torch_max_current[i]); + + cam_res_mgr_led_trigger_register( + soc_private->torch_trigger_name[i], + &fctrl->torch_trigger[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; + } + + of_node = fctrl->pdev->dev.of_node; + + rc = cam_soc_util_get_dt_properties(soc_info); + if (rc < 0) { + CAM_ERR(CAM_FLASH, "Get_dt_properties failed rc %d", rc); + return rc; + } + + soc_info->soc_private = + kzalloc(sizeof(struct cam_flash_private_soc), GFP_KERNEL); + if (!soc_info->soc_private) { + rc = -ENOMEM; + goto release_soc_res; + } + + rc = cam_get_source_node_info(of_node, fctrl, soc_info->soc_private); + if (rc < 0) { + 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); +release_soc_res: + cam_soc_util_release_platform_resource(soc_info); + return rc; +} diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_flash/cam_flash_soc.h b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_flash/cam_flash_soc.h new file mode 100644 index 000000000000..2e1da69dd317 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_flash/cam_flash_soc.h @@ -0,0 +1,21 @@ +/* Copyright (c) 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. + */ + +#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/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ir_led/Makefile b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ir_led/Makefile new file mode 100644 index 000000000000..f10b36a8efa8 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ir_led/Makefile @@ -0,0 +1,10 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_utils +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_sync +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_res_mgr +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_utils +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_req_mgr +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_smmu/ + +#obj-$(CONFIG_SPECTRA_CAMERA) += cam_ir_led_dev.o cam_ir_led_soc.o cam_ir_led_core.o diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ir_led/cam_ir_led_core.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ir_led/cam_ir_led_core.c new file mode 100644 index 000000000000..7cac1628107a --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ir_led/cam_ir_led_core.c @@ -0,0 +1,233 @@ +/* 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. + */ + +#include "cam_ir_led_core.h" + +static int cam_ir_cut_on(struct cam_ir_led_ctrl *ictrl) +{ + if (!ictrl) { + CAM_ERR(CAM_IR_LED, "Ir_led control Null"); + return -EINVAL; + } + + gpio_direction_output( + ictrl->soc_info.gpio_data->cam_gpio_common_tbl[4].gpio, 0); + gpio_direction_input( + ictrl->soc_info.gpio_data->cam_gpio_common_tbl[3].gpio); + + return 0; +} + +static int cam_ir_cut_off(struct cam_ir_led_ctrl *ictrl) +{ + if (!ictrl) { + CAM_ERR(CAM_IR_LED, "Ir_led control Null"); + return -EINVAL; + } + + gpio_direction_output( + ictrl->soc_info.gpio_data->cam_gpio_common_tbl[0].gpio, 0); + gpio_direction_output( + ictrl->soc_info.gpio_data->cam_gpio_common_tbl[3].gpio, 0); + gpio_direction_input( + ictrl->soc_info.gpio_data->cam_gpio_common_tbl[4].gpio); + + return 0; +} + +static int cam_ir_led_set_intensity(struct cam_ir_led_ctrl *ictrl, + uint32_t ir_led_intensity) +{ + CAM_DBG(CAM_IR_LED, "ir_led_intensity=%d", ir_led_intensity); + switch (ir_led_intensity) { + case IRLED_INTENSITY_OFF: + gpio_direction_output( + ictrl->soc_info.gpio_data->cam_gpio_common_tbl[0].gpio, + 0); + break; + + case IRLED_INTENSITY_LEVEL1: + gpio_direction_output( + ictrl->soc_info.gpio_data->cam_gpio_common_tbl[0].gpio, + 1); + gpio_direction_output( + ictrl->soc_info.gpio_data->cam_gpio_common_tbl[1].gpio, + 1); + gpio_direction_output( + ictrl->soc_info.gpio_data->cam_gpio_common_tbl[2].gpio, + 1); + break; + + case IRLED_INTENSITY_LEVEL2: + gpio_direction_output( + ictrl->soc_info.gpio_data->cam_gpio_common_tbl[0].gpio, + 1); + gpio_direction_output( + ictrl->soc_info.gpio_data->cam_gpio_common_tbl[1].gpio, + 0); + gpio_direction_output( + ictrl->soc_info.gpio_data->cam_gpio_common_tbl[2].gpio, + 1); + break; + case IRLED_INTENSITY_LEVEL3: + gpio_direction_output( + ictrl->soc_info.gpio_data->cam_gpio_common_tbl[0].gpio, + 1); + gpio_direction_output( + ictrl->soc_info.gpio_data->cam_gpio_common_tbl[1].gpio, + 1); + gpio_direction_output( + ictrl->soc_info.gpio_data->cam_gpio_common_tbl[2].gpio, + 0); + break; + case IRLED_INTENSITY_LEVEL4: + gpio_direction_output( + ictrl->soc_info.gpio_data->cam_gpio_common_tbl[0].gpio, + 1); + gpio_direction_output( + ictrl->soc_info.gpio_data->cam_gpio_common_tbl[1].gpio, + 0); + gpio_direction_output( + ictrl->soc_info.gpio_data->cam_gpio_common_tbl[2].gpio, + 0); + break; + } + return 0; +} + +int cam_ir_led_parser(struct cam_ir_led_ctrl *ictrl, void *arg) +{ + int rc = 0; + uint32_t *cmd_buf = NULL; + uintptr_t generic_ptr; + uint32_t *offset = NULL; + size_t len_of_buffer; + struct cam_control *ioctl_ctrl = NULL; + struct cam_packet *csl_packet = NULL; + struct cam_config_dev_cmd config; + struct cam_cmd_buf_desc *cmd_desc = NULL; + struct cam_ir_led_set_on_off *cam_ir_led_info = NULL; + + if (!ictrl || !arg) { + CAM_ERR(CAM_IR_LED, "ictrl/arg is NULL"); + return -EINVAL; + } + /* 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_IR_LED, "Copy cmd handle from user failed"); + rc = -EFAULT; + return rc; + } + + rc = cam_mem_get_cpu_buf(config.packet_handle, + (uintptr_t *)&generic_ptr, &len_of_buffer); + if (rc) { + CAM_ERR(CAM_IR_LED, "Failed in getting the buffer : %d", rc); + return rc; + } + + if (config.offset > len_of_buffer) { + CAM_ERR(CAM_IR_LED, + "offset is out of bounds: offset: %lld len: %zu", + config.offset, len_of_buffer); + return -EINVAL; + } + + /* Add offset to the ir_led csl header */ + csl_packet = (struct cam_packet *)(uintptr_t)(generic_ptr + + config.offset); + + 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, + (uintptr_t *)&generic_ptr, &len_of_buffer); + if (rc < 0) { + CAM_ERR(CAM_IR_LED, "Failed to get the command Buffer"); + return -EINVAL; + } + + cmd_buf = (uint32_t *)((uint8_t *)generic_ptr + + cmd_desc->offset); + cam_ir_led_info = (struct cam_ir_led_set_on_off *)cmd_buf; + + switch (csl_packet->header.op_code & 0xFFFFFF) { + case CAM_IR_LED_PACKET_OPCODE_ON: + CAM_DBG(CAM_IR_LED, ":CAM_IR_LED_PACKET_OPCODE_ON"); + cam_ir_cut_on(ictrl); + cam_ir_led_set_intensity(ictrl, + cam_ir_led_info->ir_led_intensity); + break; + case CAM_IR_LED_PACKET_OPCODE_OFF: + CAM_DBG(CAM_IR_LED, "CAM_IR_LED_PACKET_OPCODE_OFF"); + cam_ir_cut_off(ictrl); + break; + case CAM_PKT_NOP_OPCODE: + CAM_DBG(CAM_IR_LED, "CAM_IR_LED: CAM_PKT_NOP_OPCODE"); + break; + default: + CAM_ERR(CAM_IR_LED, "Wrong Opcode : %d", + (csl_packet->header.op_code & 0xFFFFFF)); + return -EINVAL; + } + + return 0; +} + +int cam_ir_led_stop_dev(struct cam_ir_led_ctrl *ictrl) +{ + int rc = 0; + + rc = cam_ir_cut_off(ictrl); + + return rc; +} + +int cam_ir_led_release_dev(struct cam_ir_led_ctrl *ictrl) +{ + int rc = 0; + + if (ictrl->device_hdl != -1) { + rc = cam_destroy_device_hdl(ictrl->device_hdl); + if (rc) + CAM_ERR(CAM_IR_LED, + "Failed in destroying device handle rc = %d", + rc); + ictrl->device_hdl = -1; + } + + return rc; +} + +void cam_ir_led_shutdown(struct cam_ir_led_ctrl *ictrl) +{ + int rc; + + if (ictrl->ir_led_state == CAM_IR_LED_STATE_INIT) + return; + + if ((ictrl->ir_led_state == CAM_IR_LED_STATE_CONFIG) || + (ictrl->ir_led_state == CAM_IR_LED_STATE_START)) { + rc = cam_ir_led_stop_dev(ictrl); + if (rc) + CAM_ERR(CAM_IR_LED, "Stop Failed rc: %d", rc); + } + + rc = cam_ir_led_release_dev(ictrl); + if (rc) + CAM_ERR(CAM_IR_LED, "Release failed rc: %d", rc); + + ictrl->ir_led_state = CAM_IR_LED_STATE_INIT; +} diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ir_led/cam_ir_led_core.h b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ir_led/cam_ir_led_core.h new file mode 100644 index 000000000000..6d50a4068d97 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ir_led/cam_ir_led_core.h @@ -0,0 +1,29 @@ +/* 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. + */ + +#ifndef _CAM_IR_LED_CORE_H_ +#define _CAM_IR_LED_CORE_H_ +#include "cam_ir_led_dev.h" + +#define IRLED_INTENSITY_OFF 0 +#define IRLED_INTENSITY_LEVEL1 1 +#define IRLED_INTENSITY_LEVEL2 2 +#define IRLED_INTENSITY_LEVEL3 3 +#define IRLED_INTENSITY_LEVEL4 4 +#define IRLED_INTENSITY_MAX 5 + + +int cam_ir_led_parser(struct cam_ir_led_ctrl *fctrl, void *arg); +void cam_ir_led_shutdown(struct cam_ir_led_ctrl *ir_led_ctrl); +int cam_ir_led_stop_dev(struct cam_ir_led_ctrl *ir_led_ctrl); +int cam_ir_led_release_dev(struct cam_ir_led_ctrl *fctrl); +#endif /*_CAM_IR_LED_CORE_H_*/ diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ir_led/cam_ir_led_dev.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ir_led/cam_ir_led_dev.c new file mode 100644 index 000000000000..d3b28eaf92e9 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ir_led/cam_ir_led_dev.c @@ -0,0 +1,383 @@ +/* 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. + * + */ + +#include +#include "cam_ir_led_dev.h" +#include "cam_ir_led_soc.h" +#include "cam_ir_led_core.h" + +static int32_t cam_ir_led_driver_cmd(struct cam_ir_led_ctrl *ictrl, + void *arg, struct cam_ir_led_private_soc *soc_private) +{ + int rc = 0; + struct cam_control *cmd = (struct cam_control *)arg; + + if (!ictrl || !arg) { + CAM_ERR(CAM_IR_LED, "ictrl/arg is NULL with arg:%pK ictrl%pK", + ictrl, arg); + return -EINVAL; + } + + if (cmd->handle_type != CAM_HANDLE_USER_POINTER) { + CAM_ERR(CAM_IR_LED, "Invalid handle type: %d", + cmd->handle_type); + return -EINVAL; + } + + mutex_lock(&(ictrl->ir_led_mutex)); + switch (cmd->op_code) { + case CAM_ACQUIRE_DEV: { + struct cam_sensor_acquire_dev ir_led_acq_dev; + struct cam_create_dev_hdl dev_hdl; + + CAM_DBG(CAM_IR_LED, "CAM_ACQUIRE_DEV"); + + if (ictrl->ir_led_state != CAM_IR_LED_STATE_INIT) { + CAM_ERR(CAM_IR_LED, + " Cannot apply Acquire dev: Prev state: %d", + ictrl->ir_led_state); + rc = -EINVAL; + goto release_mutex; + } + + rc = copy_from_user(&ir_led_acq_dev, + u64_to_user_ptr(cmd->handle), + sizeof(ir_led_acq_dev)); + if (rc) { + CAM_ERR(CAM_IR_LED, "Failed Copy from User rc=%d", rc); + goto release_mutex; + } + + dev_hdl.priv = ictrl; + + ir_led_acq_dev.device_handle = + cam_create_device_hdl(&dev_hdl); + ictrl->device_hdl = + ir_led_acq_dev.device_handle; + + rc = copy_to_user(u64_to_user_ptr(cmd->handle), &ir_led_acq_dev, + sizeof(struct cam_sensor_acquire_dev)); + if (rc) { + CAM_ERR(CAM_IR_LED, "Failed Copy to User rc=%d", rc); + rc = -EFAULT; + goto release_mutex; + } + ictrl->ir_led_state = CAM_IR_LED_STATE_ACQUIRE; + break; + } + case CAM_RELEASE_DEV: { + CAM_DBG(CAM_IR_LED, "CAM_RELEASE_DEV"); + if ((ictrl->ir_led_state == CAM_IR_LED_STATE_INIT) || + (ictrl->ir_led_state == CAM_IR_LED_STATE_START)) { + CAM_WARN(CAM_IR_LED, + " Cannot apply Release dev: Prev state:%d", + ictrl->ir_led_state); + } + + if (ictrl->device_hdl == -1 && + ictrl->ir_led_state == CAM_IR_LED_STATE_ACQUIRE) { + CAM_ERR(CAM_IR_LED, + " Invalid Handle: device hdl: %d", + ictrl->device_hdl); + rc = -EINVAL; + goto release_mutex; + } + rc = cam_ir_led_release_dev(ictrl); + if (rc) + CAM_ERR(CAM_IR_LED, + " Failed in destroying the device Handle rc= %d", + rc); + ictrl->ir_led_state = CAM_IR_LED_STATE_INIT; + break; + } + case CAM_QUERY_CAP: { + struct cam_ir_led_query_cap_info ir_led_cap = {0}; + + CAM_DBG(CAM_IR_LED, "CAM_QUERY_CAP"); + ir_led_cap.slot_info = ictrl->soc_info.index; + + if (copy_to_user(u64_to_user_ptr(cmd->handle), &ir_led_cap, + sizeof(struct cam_ir_led_query_cap_info))) { + CAM_ERR(CAM_IR_LED, " Failed Copy to User"); + rc = -EFAULT; + goto release_mutex; + } + break; + } + case CAM_START_DEV: { + CAM_DBG(CAM_IR_LED, "CAM_START_DEV"); + if ((ictrl->ir_led_state == CAM_IR_LED_STATE_INIT) || + (ictrl->ir_led_state == CAM_IR_LED_STATE_START)) { + CAM_ERR(CAM_IR_LED, + "Cannot apply Start Dev: Prev state: %d", + ictrl->ir_led_state); + rc = -EINVAL; + goto release_mutex; + } + ictrl->ir_led_state = CAM_IR_LED_STATE_START; + + break; + } + case CAM_STOP_DEV: { + CAM_DBG(CAM_IR_LED, "CAM_STOP_DEV ENTER"); + if (ictrl->ir_led_state != CAM_IR_LED_STATE_START) { + CAM_WARN(CAM_IR_LED, + " Cannot apply Stop dev: Prev state is: %d", + ictrl->ir_led_state); + rc = -EINVAL; + goto release_mutex; + } + rc = cam_ir_led_stop_dev(ictrl); + if (rc) { + CAM_ERR(CAM_IR_LED, "Failed STOP_DEV: rc=%d\n", rc); + goto release_mutex; + } + ictrl->ir_led_state = CAM_IR_LED_STATE_ACQUIRE; + break; + } + case CAM_CONFIG_DEV: { + CAM_DBG(CAM_IR_LED, "CAM_CONFIG_DEV"); + rc = cam_ir_led_parser(ictrl, arg); + if (rc) { + CAM_ERR(CAM_IR_LED, "Failed CONFIG_DEV: rc=%d\n", rc); + goto release_mutex; + } + break; + } + default: + CAM_ERR(CAM_IR_LED, "Invalid Opcode: %d", cmd->op_code); + rc = -EINVAL; + } + +release_mutex: + mutex_unlock(&(ictrl->ir_led_mutex)); + return rc; +} + +static const struct of_device_id cam_ir_led_dt_match[] = { + {.compatible = "qcom,camera-ir-led", .data = NULL}, + {} +}; + +static long cam_ir_led_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + int rc = 0; + struct cam_ir_led_ctrl *ictrl = NULL; + struct cam_ir_led_private_soc *soc_private = NULL; + + CAM_DBG(CAM_IR_LED, "Enter"); + + ictrl = v4l2_get_subdevdata(sd); + soc_private = ictrl->soc_info.soc_private; + + switch (cmd) { + case VIDIOC_CAM_CONTROL: { + rc = cam_ir_led_driver_cmd(ictrl, arg, + soc_private); + break; + } + default: + CAM_ERR(CAM_IR_LED, " Invalid ioctl cmd type"); + rc = -EINVAL; + break; + } + + CAM_DBG(CAM_IR_LED, "Exit"); + return rc; +} + +#ifdef CONFIG_COMPAT +static long cam_ir_led_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_IR_LED, + " 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_ir_led_subdev_ioctl(sd, cmd, &cmd_data); + if (rc) + CAM_ERR(CAM_IR_LED, "cam_ir_led_ioctl failed"); + break; + } + default: + CAM_ERR(CAM_IR_LED, " 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_IR_LED, + " Failed to copy to user_ptr=%pK size=%zu", + (void __user *)arg, sizeof(cmd_data)); + rc = -EFAULT; + } + } + + return rc; +} +#endif + +static int cam_ir_led_platform_remove(struct platform_device *pdev) +{ + struct cam_ir_led_ctrl *ictrl; + + ictrl = platform_get_drvdata(pdev); + if (!ictrl) { + CAM_ERR(CAM_IR_LED, " Ir_led device is NULL"); + return 0; + } + + devm_kfree(&pdev->dev, ictrl); + + return 0; +} + +static int cam_ir_led_subdev_close(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh) +{ + struct cam_ir_led_ctrl *ir_led_ctrl = + v4l2_get_subdevdata(sd); + + if (!ir_led_ctrl) { + CAM_ERR(CAM_IR_LED, " Ir_led ctrl ptr is NULL"); + return -EINVAL; + } + + mutex_lock(&ir_led_ctrl->ir_led_mutex); + cam_ir_led_shutdown(ir_led_ctrl); + mutex_unlock(&ir_led_ctrl->ir_led_mutex); + + return 0; +} + +static struct v4l2_subdev_core_ops cam_ir_led_subdev_core_ops = { + .ioctl = cam_ir_led_subdev_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl32 = cam_ir_led_subdev_do_ioctl +#endif +}; + +static struct v4l2_subdev_ops cam_ir_led_subdev_ops = { + .core = &cam_ir_led_subdev_core_ops, +}; + +static const struct v4l2_subdev_internal_ops cam_ir_led_internal_ops = { + .close = cam_ir_led_subdev_close, +}; + +static int32_t cam_ir_led_platform_probe(struct platform_device *pdev) +{ + int32_t rc = 0; + struct cam_ir_led_ctrl *ir_led_ctrl = NULL; + + CAM_ERR(CAM_IR_LED, "DBG:Enter"); + if (!pdev->dev.of_node) { + CAM_ERR(CAM_IR_LED, "of_node NULL"); + return -EINVAL; + } + + ir_led_ctrl = kzalloc(sizeof(struct cam_ir_led_ctrl), GFP_KERNEL); + if (!ir_led_ctrl) + return -ENOMEM; + + ir_led_ctrl->pdev = pdev; + ir_led_ctrl->soc_info.pdev = pdev; + ir_led_ctrl->soc_info.dev = &pdev->dev; + ir_led_ctrl->soc_info.dev_name = pdev->name; + + rc = cam_ir_led_get_dt_data(ir_led_ctrl, &ir_led_ctrl->soc_info); + if (rc) { + CAM_ERR(CAM_IR_LED, "cam_ir_led_get_dt_data failed rc=%d", rc); + if (ir_led_ctrl->soc_info.soc_private != NULL) { + kfree(ir_led_ctrl->soc_info.soc_private); + ir_led_ctrl->soc_info.soc_private = NULL; + } + kfree(ir_led_ctrl); + ir_led_ctrl = NULL; + return -EINVAL; + } + + ir_led_ctrl->v4l2_dev_str.internal_ops = + &cam_ir_led_internal_ops; + ir_led_ctrl->v4l2_dev_str.ops = &cam_ir_led_subdev_ops; + ir_led_ctrl->v4l2_dev_str.name = CAMX_IR_LED_DEV_NAME; + ir_led_ctrl->v4l2_dev_str.sd_flags = + V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; + ir_led_ctrl->v4l2_dev_str.ent_function = CAM_IRLED_DEVICE_TYPE; + ir_led_ctrl->v4l2_dev_str.token = ir_led_ctrl; + + rc = cam_register_subdev(&(ir_led_ctrl->v4l2_dev_str)); + if (rc) { + CAM_ERR(CAM_IR_LED, "Fail to create subdev with %d", rc); + goto free_resource; + } + ir_led_ctrl->device_hdl = -1; + + platform_set_drvdata(pdev, ir_led_ctrl); + v4l2_set_subdevdata(&ir_led_ctrl->v4l2_dev_str.sd, ir_led_ctrl); + + mutex_init(&(ir_led_ctrl->ir_led_mutex)); + + ir_led_ctrl->ir_led_state = CAM_IR_LED_STATE_INIT; + CAM_ERR(CAM_IR_LED, "DBG:Probe success"); + return rc; +free_resource: + kfree(ir_led_ctrl); + return rc; +} + +MODULE_DEVICE_TABLE(of, cam_ir_led_dt_match); + +static struct platform_driver cam_ir_led_platform_driver = { + .probe = cam_ir_led_platform_probe, + .remove = cam_ir_led_platform_remove, + .driver = { + .name = "CAM-IR-LED-DRIVER", + .owner = THIS_MODULE, + .of_match_table = cam_ir_led_dt_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init cam_ir_led_init_module(void) +{ + int32_t rc = 0; + + rc = platform_driver_register(&cam_ir_led_platform_driver); + if (rc) + CAM_ERR(CAM_IR_LED, "platform probe for ir_led failed"); + + return rc; +} + +static void __exit cam_ir_led_exit_module(void) +{ + platform_driver_unregister(&cam_ir_led_platform_driver); +} + +module_init(cam_ir_led_init_module); +module_exit(cam_ir_led_exit_module); +MODULE_DESCRIPTION("CAM IR_LED"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ir_led/cam_ir_led_dev.h b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ir_led/cam_ir_led_dev.h new file mode 100644 index 000000000000..b462adbd4d43 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ir_led/cam_ir_led_dev.h @@ -0,0 +1,140 @@ +/* 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. + * + */ + +#ifndef _CAM_IR_LED_DEV_H_ +#define _CAM_IR_LED_DEV_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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" + +#define CAMX_IR_LED_DEV_NAME "cam-ir-led-dev" + +#define CAM_IR_LED_PIPELINE_DELAY 1 + +#define CAM_IR_LED_PACKET_OPCODE_OFF 0 +#define CAM_IR_LED_PACKET_OPCODE_ON 1 + +enum cam_ir_led_switch_trigger_ops { + LED_SWITCH_OFF = 0, + LED_SWITCH_ON, +}; + +enum cam_ir_led_state { + CAM_IR_LED_STATE_INIT = 0, + CAM_IR_LED_STATE_ACQUIRE, + CAM_IR_LED_STATE_CONFIG, + CAM_IR_LED_STATE_START, +}; + +/** + * struct cam_ir_led_intf_params + * @device_hdl : Device Handle + * @session_hdl : Session Handle + * @link_hdl : Link Handle + * @ops : KMD operations + * @crm_cb : Callback API pointers + */ +struct cam_ir_led_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_ir_led_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_ir_led_common_attr { + bool is_settings_valid; + uint64_t request_id; + uint16_t count; + uint8_t cmd_type; +}; + +/** + * struct ir_led_init_packet + * @cmn_attr : Provides common attributes + * @ir_led_type : Ir_led type(PMIC/I2C/GPIO) + */ +struct cam_ir_led_init_packet { + struct cam_ir_led_common_attr cmn_attr; + uint8_t ir_led_type; +}; + +/** + * struct cam_ir_led_private_soc + * @switch_trigger_name : Switch trigger name + * @ir_led_trigger_name : Ir_led trigger name array + * @ir_led_op_current : Ir_led operational current + * @ir_led_max_current : Max supported current for LED in ir_led mode + * @ir_led_max_duration : Max turn on duration for LED in Ir_led 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 + */ + +struct cam_ir_led_private_soc { + const char *switch_trigger_name; + const char *ir_led_trigger_name; + uint32_t ir_led_op_current; + uint32_t ir_led_max_current; + uint32_t ir_led_max_duration; + const char *torch_trigger_name; + uint32_t torch_op_current; + uint32_t torch_max_current; +}; + +/** + * struct cam_ir_led_ctrl + * @soc_info : Soc related information + * @pdev : Platform device + * @of_node : Of Node ptr + * @v4l2_dev_str : V4L2 device structure + * @ir_led_mutex : Mutex for ir_led operations + * @ir_led_state : Current ir_led state (LOW/OFF/ON/INIT) + * @device_hdl : Device Handle + */ +struct cam_ir_led_ctrl { + struct cam_hw_soc_info soc_info; + struct platform_device *pdev; + struct device_node *of_node; + struct cam_subdev v4l2_dev_str; + struct mutex ir_led_mutex; + enum cam_ir_led_state ir_led_state; + int32_t device_hdl; +}; + +#endif /*_CAM_IR_LED_DEV_H_*/ diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ir_led/cam_ir_led_soc.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ir_led/cam_ir_led_soc.c new file mode 100644 index 000000000000..65b53614cc90 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ir_led/cam_ir_led_soc.c @@ -0,0 +1,46 @@ +/* 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. + */ + +#include +#include +#include "cam_ir_led_soc.h" +#include "cam_res_mgr_api.h" + +int cam_ir_led_get_dt_data(struct cam_ir_led_ctrl *ictrl, + struct cam_hw_soc_info *soc_info) +{ + int32_t rc = 0; + + if (!ictrl) { + CAM_ERR(CAM_IR_LED, "NULL ir_led control structure"); + return -EINVAL; + } + + rc = cam_soc_util_get_dt_properties(soc_info); + if (rc < 0) { + CAM_ERR(CAM_IR_LED, "get_dt_properties failed rc %d", rc); + return rc; + } + + soc_info->soc_private = + kzalloc(sizeof(struct cam_ir_led_private_soc), GFP_KERNEL); + if (!soc_info->soc_private) { + rc = -ENOMEM; + goto release_soc_res; + } + + return rc; + +release_soc_res: + cam_soc_util_release_platform_resource(soc_info); + return rc; +} diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ir_led/cam_ir_led_soc.h b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ir_led/cam_ir_led_soc.h new file mode 100644 index 000000000000..3a9139ae2cc1 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ir_led/cam_ir_led_soc.h @@ -0,0 +1,21 @@ +/* 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. + */ + +#ifndef _CAM_IR_LED_SOC_H_ +#define _CAM_IR_LED_SOC_H_ + +#include "cam_ir_led_dev.h" + +int cam_ir_led_get_dt_data(struct cam_ir_led_ctrl *fctrl, + struct cam_hw_soc_info *soc_info); + +#endif /*_CAM_IR_LED_SOC_H_*/ diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ois/Makefile b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ois/Makefile new file mode 100644 index 000000000000..436836a4c67f --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ois/Makefile @@ -0,0 +1,10 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_utils +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_cpas/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_res_mgr +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_utils +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_req_mgr +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_smmu/ + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_ois_dev.o cam_ois_core.o cam_ois_soc.o diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ois/ROHM_BU24218GWL_OIS.h b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ois/ROHM_BU24218GWL_OIS.h new file mode 100644 index 000000000000..e9488c8d7574 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ois/ROHM_BU24218GWL_OIS.h @@ -0,0 +1,2216 @@ +.start_download = +{ + .reg_settings = + { + {.reg_addr = 0xF010, .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, +}, +.firmware = +{ + .reg_settings = + { + {.reg_addr = 0x0000, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0001, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0002, .reg_data = 0xB5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0003, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0004, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0005, .reg_data = 0x85, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0006, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0007, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0008, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0009, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x000A, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x000B, .reg_data = 0x24, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x000C, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x000D, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x000E, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x000F, .reg_data = 0x67, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0010, .reg_data = 0x4F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0011, .reg_data = 0x67, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0012, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0013, .reg_data = 0x67, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0014, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0015, .reg_data = 0x67, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0016, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0017, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0018, .reg_data = 0x37, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0019, .reg_data = 0xB4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x001A, .reg_data = 0x4D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x001B, .reg_data = 0x63, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x001C, .reg_data = 0x42, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x001D, .reg_data = 0x84, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x001E, .reg_data = 0x26, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x001F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0020, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0021, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0022, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0023, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0024, .reg_data = 0xF9, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0025, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0026, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0027, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0028, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0029, .reg_data = 0x62, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x002A, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x002B, .reg_data = 0x24, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x002C, .reg_data = 0x42, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x002D, .reg_data = 0x84, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x002E, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x002F, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0030, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0031, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0032, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0033, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0034, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0035, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0036, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0037, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0038, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0039, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x003A, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x003B, .reg_data = 0x5E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x003C, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x003D, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x003E, .reg_data = 0x42, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x003F, .reg_data = 0x84, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0040, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0041, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0042, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0043, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0044, .reg_data = 0xF9, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0045, .reg_data = 0x1F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0046, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0047, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0048, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0049, .reg_data = 0x5A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x004A, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x004B, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x004C, .reg_data = 0x42, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x004D, .reg_data = 0x84, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x004E, .reg_data = 0x1D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x004F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0050, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0051, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0052, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0053, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0054, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0055, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0056, .reg_data = 0x42, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0057, .reg_data = 0x84, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0058, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0059, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x005A, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x005B, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x005C, .reg_data = 0x49, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x005D, .reg_data = 0x56, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x005E, .reg_data = 0x1A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x005F, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0060, .reg_data = 0x13, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0061, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0062, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0063, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0064, .reg_data = 0xDD, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0065, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0066, .reg_data = 0x2E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0067, .reg_data = 0x7F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0068, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0069, .reg_data = 0x99, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x006A, .reg_data = 0x26, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x006B, .reg_data = 0x7F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x006C, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x006D, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x006E, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x006F, .reg_data = 0x7F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0070, .reg_data = 0xDA, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0071, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0072, .reg_data = 0x42, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0073, .reg_data = 0x86, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0074, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0075, .reg_data = 0x93, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0076, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0077, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0078, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0079, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x007A, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x007B, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x007C, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x007D, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x007E, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x007F, .reg_data = 0x2D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0080, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0081, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0082, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0083, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0084, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0085, .reg_data = 0x8B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0086, .reg_data = 0xFA, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0087, .reg_data = 0xAF, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0088, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0089, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x008A, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x008B, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x008C, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x008D, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x008E, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x008F, .reg_data = 0x3B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0090, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0091, .reg_data = 0x4A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0092, .reg_data = 0xD8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0093, .reg_data = 0x17, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0094, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0095, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0096, .reg_data = 0x55, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0097, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0098, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0099, .reg_data = 0x3C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x009A, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x009B, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x009C, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x009D, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x009E, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x009F, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00A0, .reg_data = 0x31, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00A1, .reg_data = 0x3B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00A2, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00A3, .reg_data = 0x8C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00A4, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00A5, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00A6, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00A7, .reg_data = 0x83, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00A8, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00A9, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00AA, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00AB, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00AC, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00AD, .reg_data = 0x3E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00AE, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00AF, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00B0, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00B1, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00B2, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00B3, .reg_data = 0x76, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00B4, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00B5, .reg_data = 0x92, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00B6, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00B7, .reg_data = 0xA3, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00B8, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00B9, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00BA, .reg_data = 0x31, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00BB, .reg_data = 0x3D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00BC, .reg_data = 0xFA, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00BD, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00BE, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00BF, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00C0, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00C1, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00C2, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00C3, .reg_data = 0x6E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00C4, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00C5, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00C6, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00C7, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00C8, .reg_data = 0xB2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00C9, .reg_data = 0xCD, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00CA, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00CB, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00CC, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00CD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00CE, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00CF, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00D0, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00D1, .reg_data = 0x3A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00D2, .reg_data = 0xFA, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00D3, .reg_data = 0xBB, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00D4, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00D5, .reg_data = 0x63, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00D6, .reg_data = 0x55, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00D7, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00D8, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00D9, .reg_data = 0x1D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00DA, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00DB, .reg_data = 0x36, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00DC, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00DD, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00DE, .reg_data = 0x42, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00DF, .reg_data = 0x84, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00E0, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00E1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00E2, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00E3, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00E4, .reg_data = 0xE7, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00E5, .reg_data = 0xC5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00E6, .reg_data = 0xF8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00E7, .reg_data = 0x73, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00E8, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00E9, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00EA, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00EB, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00EC, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00ED, .reg_data = 0x57, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00EE, .reg_data = 0x42, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00EF, .reg_data = 0x84, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00F0, .reg_data = 0xFA, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00F1, .reg_data = 0x70, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00F2, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00F3, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00F4, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00F5, .reg_data = 0xA1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00F6, .reg_data = 0x24, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00F7, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00F8, .reg_data = 0x91, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00F9, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00FA, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00FB, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00FC, .reg_data = 0x4A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00FD, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00FE, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x00FF, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0100, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0101, .reg_data = 0x89, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0102, .reg_data = 0x99, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0103, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0104, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0105, .reg_data = 0x64, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0106, .reg_data = 0x62, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0107, .reg_data = 0xC8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0108, .reg_data = 0xDB, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0109, .reg_data = 0xF4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x010A, .reg_data = 0x2C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x010B, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x010C, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x010D, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x010E, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x010F, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0110, .reg_data = 0x4C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0111, .reg_data = 0x2B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0112, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0113, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0114, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0115, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0116, .reg_data = 0x34, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0117, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0118, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0119, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x011A, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x011B, .reg_data = 0x2C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x011C, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x011D, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x011E, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x011F, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0120, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0121, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0122, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0123, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0124, .reg_data = 0x4C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0125, .reg_data = 0x26, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0126, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0127, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0128, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0129, .reg_data = 0x34, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x012A, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x012B, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x012C, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x012D, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x012E, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x012F, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0130, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0131, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0132, .reg_data = 0x62, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0133, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0134, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0135, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0136, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0137, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0138, .reg_data = 0x34, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0139, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x013A, .reg_data = 0x4C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x013B, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x013C, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x013D, .reg_data = 0x4C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x013E, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x013F, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0140, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0141, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0142, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0143, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0144, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0145, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0146, .reg_data = 0x63, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0147, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0148, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0149, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x014A, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x014B, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x014C, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x014D, .reg_data = 0x1B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x014E, .reg_data = 0x63, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x014F, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0150, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0151, .reg_data = 0x42, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0152, .reg_data = 0x78, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0153, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0154, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0155, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0156, .reg_data = 0x9A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0157, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0158, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0159, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x015A, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x015B, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x015C, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x015D, .reg_data = 0x2D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x015E, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x015F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0160, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0161, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0162, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0163, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0164, .reg_data = 0x2C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0165, .reg_data = 0x13, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0166, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0167, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0168, .reg_data = 0x4F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0169, .reg_data = 0x16, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x016A, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x016B, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x016C, .reg_data = 0x37, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x016D, .reg_data = 0xB4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x016E, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x016F, .reg_data = 0x15, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0170, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0171, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0172, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0173, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0174, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0175, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0176, .reg_data = 0x9A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0177, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0178, .reg_data = 0x99, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0179, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x017A, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x017B, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x017C, .reg_data = 0x99, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x017D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x017E, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x017F, .reg_data = 0x88, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0180, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0181, .reg_data = 0x88, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0182, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0183, .reg_data = 0x0B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0184, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0185, .reg_data = 0xB8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0186, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0187, .reg_data = 0x13, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0188, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0189, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x018A, .reg_data = 0x99, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x018B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x018C, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x018D, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x018E, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x018F, .reg_data = 0x88, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0190, .reg_data = 0x2D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0191, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0192, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0193, .reg_data = 0xB8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0194, .reg_data = 0x99, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0195, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0196, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0197, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0198, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0199, .reg_data = 0x88, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x019A, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x019B, .reg_data = 0x1F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x019C, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x019D, .reg_data = 0xB8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x019E, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x019F, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01A0, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01A1, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01A2, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01A3, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01A4, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01A5, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01A6, .reg_data = 0xBD, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01A7, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01A8, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01A9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01AA, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01AB, .reg_data = 0x15, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01AC, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01AD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01AE, .reg_data = 0x54, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01AF, .reg_data = 0xBD, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01B0, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01B1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01B2, .reg_data = 0x29, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01B3, .reg_data = 0xD9, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01B4, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01B5, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01B6, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01B7, .reg_data = 0x2D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01B8, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01B9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01BA, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01BB, .reg_data = 0xAA, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01BC, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01BD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01BE, .reg_data = 0x19, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01BF, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01C0, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01C1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01C2, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01C3, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01C4, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01C5, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01C6, .reg_data = 0x2B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01C7, .reg_data = 0x25, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01C8, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01C9, .reg_data = 0x70, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01CA, .reg_data = 0xBA, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01CB, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01CC, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01CD, .reg_data = 0x86, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01CE, .reg_data = 0xB5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01CF, .reg_data = 0xF1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01D0, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01D1, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01D2, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01D3, .reg_data = 0x5F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01D4, .reg_data = 0x4C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01D5, .reg_data = 0x5F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01D6, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01D7, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01D8, .reg_data = 0x27, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01D9, .reg_data = 0x7D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01DA, .reg_data = 0x78, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01DB, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01DC, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01DD, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01DE, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01DF, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01E0, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01E1, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01E2, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01E3, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01E4, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01E5, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01E6, .reg_data = 0x26, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01E7, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01E8, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01E9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01EA, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01EB, .reg_data = 0x8C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01EC, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01ED, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01EE, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01EF, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01F0, .reg_data = 0x15, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01F1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01F2, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01F3, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01F4, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01F5, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01F6, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01F7, .reg_data = 0x92, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01F8, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01F9, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01FA, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01FB, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01FC, .reg_data = 0x15, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01FD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01FE, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x01FF, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0200, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0201, .reg_data = 0x55, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0202, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0203, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0204, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0205, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0206, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0207, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0208, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0209, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x020A, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x020B, .reg_data = 0x54, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x020C, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x020D, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x020E, .reg_data = 0x99, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x020F, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0210, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0211, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0212, .reg_data = 0x99, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0213, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0214, .reg_data = 0xD5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0215, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0216, .reg_data = 0x1A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0217, .reg_data = 0x44, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0218, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0219, .reg_data = 0x51, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x021A, .reg_data = 0x42, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x021B, .reg_data = 0x64, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x021C, .reg_data = 0x99, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x021D, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x021E, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x021F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0220, .reg_data = 0x99, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0221, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0222, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0223, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0224, .reg_data = 0x1A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0225, .reg_data = 0x45, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0226, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0227, .reg_data = 0x49, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0228, .reg_data = 0x42, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0229, .reg_data = 0x6D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x022A, .reg_data = 0xD5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x022B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x022C, .reg_data = 0xDC, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x022D, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x022E, .reg_data = 0x2C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x022F, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0230, .reg_data = 0xDD, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0231, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0232, .reg_data = 0x2D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0233, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0234, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0235, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0236, .reg_data = 0x26, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0237, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0238, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0239, .reg_data = 0x19, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x023A, .reg_data = 0x1E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x023B, .reg_data = 0x76, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x023C, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x023D, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x023E, .reg_data = 0x99, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x023F, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0240, .reg_data = 0x1E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0241, .reg_data = 0x7F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0242, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0243, .reg_data = 0x88, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0244, .reg_data = 0x98, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0245, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0246, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0247, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0248, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0249, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x024A, .reg_data = 0x7F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x024B, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x024C, .reg_data = 0x99, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x024D, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x024E, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x024F, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0250, .reg_data = 0x98, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0251, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0252, .reg_data = 0x77, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0253, .reg_data = 0xC8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0254, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0255, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0256, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0257, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0258, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0259, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x025A, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x025B, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x025C, .reg_data = 0xDD, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x025D, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x025E, .reg_data = 0x2C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x025F, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0260, .reg_data = 0xDD, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0261, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0262, .reg_data = 0x2D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0263, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0264, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0265, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0266, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0267, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0268, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0269, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x026A, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x026B, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x026C, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x026D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x026E, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x026F, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0270, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0271, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0272, .reg_data = 0x98, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0273, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0274, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0275, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0276, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0277, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0278, .reg_data = 0x99, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0279, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x027A, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x027B, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x027C, .reg_data = 0x76, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x027D, .reg_data = 0xC8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x027E, .reg_data = 0x98, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x027F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0280, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0281, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0282, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0283, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0284, .reg_data = 0xB5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0285, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0286, .reg_data = 0xBD, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0287, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0288, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0289, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x028A, .reg_data = 0x4A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x028B, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x028C, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x028D, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x028E, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x028F, .reg_data = 0x24, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0290, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0291, .reg_data = 0x44, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0292, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0293, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0294, .reg_data = 0xBD, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0295, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0296, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0297, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0298, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0299, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x029A, .reg_data = 0xB5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x029B, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x029C, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x029D, .reg_data = 0x89, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x029E, .reg_data = 0x4E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x029F, .reg_data = 0x2D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02A0, .reg_data = 0x36, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02A1, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02A2, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02A3, .reg_data = 0x31, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02A4, .reg_data = 0x1D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02A5, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02A6, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02A7, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02A8, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02A9, .reg_data = 0xF8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02AA, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02AB, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02AC, .reg_data = 0x4D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02AD, .reg_data = 0x2D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02AE, .reg_data = 0x4C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02AF, .reg_data = 0x29, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02B0, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02B1, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02B2, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02B3, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02B4, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02B5, .reg_data = 0x54, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02B6, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02B7, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02B8, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02B9, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02BA, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02BB, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02BC, .reg_data = 0x98, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02BD, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02BE, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02BF, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02C0, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02C1, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02C2, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02C3, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02C4, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02C5, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02C6, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02C7, .reg_data = 0x58, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02C8, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02C9, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02CA, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02CB, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02CC, .reg_data = 0xA9, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02CD, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02CE, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02CF, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02D0, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02D1, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02D2, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02D3, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02D4, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02D5, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02D6, .reg_data = 0x2F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02D7, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02D8, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02D9, .reg_data = 0x4C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02DA, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02DB, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02DC, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02DD, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02DE, .reg_data = 0xE7, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02DF, .reg_data = 0xEC, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02E0, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02E1, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02E2, .reg_data = 0xE7, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02E3, .reg_data = 0xF1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02E4, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02E5, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02E6, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02E7, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02E8, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02E9, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02EA, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02EB, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02EC, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02ED, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02EE, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02EF, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02F0, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02F1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02F2, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02F3, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02F4, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02F5, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02F6, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02F7, .reg_data = 0x44, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02F8, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02F9, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02FA, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02FB, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02FC, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02FD, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02FE, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x02FF, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0300, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0301, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0302, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0303, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0304, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0305, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0306, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0307, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0308, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0309, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x030A, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x030B, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x030C, .reg_data = 0x91, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x030D, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x030E, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x030F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0310, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0311, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0312, .reg_data = 0x1D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0313, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0314, .reg_data = 0x24, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0315, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0316, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0317, .reg_data = 0x15, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0318, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0319, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x031A, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x031B, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x031C, .reg_data = 0x27, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x031D, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x031E, .reg_data = 0x1D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x031F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0320, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0321, .reg_data = 0x3F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0322, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0323, .reg_data = 0x6E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0324, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0325, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0326, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0327, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0328, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0329, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x032A, .reg_data = 0x2C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x032B, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x032C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x032D, .reg_data = 0x81, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x032E, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x032F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0330, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0331, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0332, .reg_data = 0x58, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0333, .reg_data = 0x72, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0334, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0335, .reg_data = 0x72, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0336, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0337, .reg_data = 0x3A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0338, .reg_data = 0xDB, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0339, .reg_data = 0xF8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x033A, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x033B, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x033C, .reg_data = 0xA9, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x033D, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x033E, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x033F, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0340, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0341, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0342, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0343, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0344, .reg_data = 0x2C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0345, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0346, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0347, .reg_data = 0x64, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0348, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0349, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x034A, .reg_data = 0xDB, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x034B, .reg_data = 0xEE, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x034C, .reg_data = 0xBD, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x034D, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x034E, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x034F, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0350, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0351, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0352, .reg_data = 0x54, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0353, .reg_data = 0xBD, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0354, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0355, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0356, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0357, .reg_data = 0xCD, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0358, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0359, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x035A, .reg_data = 0x19, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x035B, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x035C, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x035D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x035E, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x035F, .reg_data = 0xBC, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0360, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0361, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0362, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0363, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0364, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0365, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0366, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0367, .reg_data = 0xB5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0368, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0369, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x036A, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x036B, .reg_data = 0x78, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x036C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x036D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x036E, .reg_data = 0x42, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x036F, .reg_data = 0x88, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0370, .reg_data = 0x24, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0371, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0372, .reg_data = 0xB5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0373, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0374, .reg_data = 0x2A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0375, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0376, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0377, .reg_data = 0xE4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0378, .reg_data = 0x23, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0379, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x037A, .reg_data = 0xDC, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x037B, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x037C, .reg_data = 0x6A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x037D, .reg_data = 0x5B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x037E, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x037F, .reg_data = 0x9B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0380, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0381, .reg_data = 0x9B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0382, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0383, .reg_data = 0x9B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0384, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0385, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0386, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0387, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0388, .reg_data = 0x23, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0389, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x038A, .reg_data = 0xBD, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x038B, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x038C, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x038D, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x038E, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x038F, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0390, .reg_data = 0x4E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0391, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0392, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0393, .reg_data = 0x9D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0394, .reg_data = 0x19, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0395, .reg_data = 0xAE, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0396, .reg_data = 0x59, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0397, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0398, .reg_data = 0x59, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0399, .reg_data = 0x4D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x039A, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x039B, .reg_data = 0x37, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x039C, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x039D, .reg_data = 0x1E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x039E, .reg_data = 0x63, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x039F, .reg_data = 0xB5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03A0, .reg_data = 0x25, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03A1, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03A2, .reg_data = 0x36, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03A3, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03A4, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03A5, .reg_data = 0x2C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03A6, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03A7, .reg_data = 0xB5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03A8, .reg_data = 0x42, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03A9, .reg_data = 0x93, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03AA, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03AB, .reg_data = 0x5B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03AC, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03AD, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03AE, .reg_data = 0xDB, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03AF, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03B0, .reg_data = 0x6A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03B1, .reg_data = 0x41, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03B2, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03B3, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03B4, .reg_data = 0x62, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03B5, .reg_data = 0x41, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03B6, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03B7, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03B8, .reg_data = 0xBD, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03B9, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03BA, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03BB, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03BC, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03BD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03BE, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03BF, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03C0, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03C1, .reg_data = 0x79, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03C2, .reg_data = 0xB5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03C3, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03C4, .reg_data = 0x69, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03C5, .reg_data = 0xC2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03C6, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03C7, .reg_data = 0x85, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03C8, .reg_data = 0x4B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03C9, .reg_data = 0x77, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03CA, .reg_data = 0x4C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03CB, .reg_data = 0x77, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03CC, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03CD, .reg_data = 0xA4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03CE, .reg_data = 0x34, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03CF, .reg_data = 0x78, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03D0, .reg_data = 0x49, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03D1, .reg_data = 0x75, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03D2, .reg_data = 0x1D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03D3, .reg_data = 0x24, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03D4, .reg_data = 0x4C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03D5, .reg_data = 0x75, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03D6, .reg_data = 0x94, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03D7, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03D8, .reg_data = 0x31, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03D9, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03DA, .reg_data = 0x33, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03DB, .reg_data = 0x98, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03DC, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03DD, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03DE, .reg_data = 0x4F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03DF, .reg_data = 0x73, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03E0, .reg_data = 0x34, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03E1, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03E2, .reg_data = 0x4E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03E3, .reg_data = 0x72, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03E4, .reg_data = 0x37, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03E5, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03E6, .reg_data = 0x78, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03E7, .reg_data = 0x1B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03E8, .reg_data = 0x2B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03E9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03EA, .reg_data = 0x4D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03EB, .reg_data = 0x71, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03EC, .reg_data = 0x78, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03ED, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03EE, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03EF, .reg_data = 0x74, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03F0, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03F1, .reg_data = 0x71, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03F2, .reg_data = 0x29, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03F3, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03F4, .reg_data = 0x78, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03F5, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03F6, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03F7, .reg_data = 0x91, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03F8, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03F9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03FA, .reg_data = 0x0E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03FB, .reg_data = 0x89, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03FC, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03FD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03FE, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x03FF, .reg_data = 0x6C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0400, .reg_data = 0x29, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0401, .reg_data = 0x39, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0402, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0403, .reg_data = 0x6C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0404, .reg_data = 0x29, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0405, .reg_data = 0x3D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0406, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0407, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0408, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0409, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x040A, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x040B, .reg_data = 0x49, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x040C, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x040D, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x040E, .reg_data = 0x78, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x040F, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0410, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0411, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0412, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0413, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0414, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0415, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0416, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0417, .reg_data = 0x2A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0418, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0419, .reg_data = 0xEA, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x041A, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x041B, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x041C, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x041D, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x041E, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x041F, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0420, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0421, .reg_data = 0x59, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0422, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0423, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0424, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0425, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0426, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0427, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0428, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0429, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x042A, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x042B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x042C, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x042D, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x042E, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x042F, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0430, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0431, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0432, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0433, .reg_data = 0xE8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0434, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0435, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0436, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0437, .reg_data = 0xE8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0438, .reg_data = 0x1E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0439, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x043A, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x043B, .reg_data = 0x15, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x043C, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x043D, .reg_data = 0x4A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x043E, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x043F, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0440, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0441, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0442, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0443, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0444, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0445, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0446, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0447, .reg_data = 0xE8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0448, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0449, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x044A, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x044B, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x044C, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x044D, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x044E, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x044F, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0450, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0451, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0452, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0453, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0454, .reg_data = 0x98, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0455, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0456, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0457, .reg_data = 0x69, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0458, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0459, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x045A, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x045B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x045C, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x045D, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x045E, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x045F, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0460, .reg_data = 0x69, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0461, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0462, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0463, .reg_data = 0x0B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0464, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0465, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0466, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0467, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0468, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0469, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x046A, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x046B, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x046C, .reg_data = 0xE7, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x046D, .reg_data = 0xF2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x046E, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x046F, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0470, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0471, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0472, .reg_data = 0x69, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0473, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0474, .reg_data = 0x1E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0475, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0476, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0477, .reg_data = 0x0E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0478, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0479, .reg_data = 0x4A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x047A, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x047B, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x047C, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x047D, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x047E, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x047F, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0480, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0481, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0482, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0483, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0484, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0485, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0486, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0487, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0488, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0489, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x048A, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x048B, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x048C, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x048D, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x048E, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x048F, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0490, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0491, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0492, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0493, .reg_data = 0xA9, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0494, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0495, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0496, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0497, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0498, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0499, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x049A, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x049B, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x049C, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x049D, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x049E, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x049F, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04A0, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04A1, .reg_data = 0x89, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04A2, .reg_data = 0x4B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04A3, .reg_data = 0x45, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04A4, .reg_data = 0x1D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04A5, .reg_data = 0x1B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04A6, .reg_data = 0x63, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04A7, .reg_data = 0x0B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04A8, .reg_data = 0x1D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04A9, .reg_data = 0x1B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04AA, .reg_data = 0x63, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04AB, .reg_data = 0x4B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04AC, .reg_data = 0x4B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04AD, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04AE, .reg_data = 0x63, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04AF, .reg_data = 0x8B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04B0, .reg_data = 0x4E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04B1, .reg_data = 0x44, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04B2, .reg_data = 0x63, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04B3, .reg_data = 0xCB, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04B4, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04B5, .reg_data = 0x31, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04B6, .reg_data = 0x49, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04B7, .reg_data = 0x42, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04B8, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04B9, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04BA, .reg_data = 0x78, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04BB, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04BC, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04BD, .reg_data = 0x64, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04BE, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04BF, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04C0, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04C1, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04C2, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04C3, .reg_data = 0x41, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04C4, .reg_data = 0x62, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04C5, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04C6, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04C7, .reg_data = 0xF2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04C8, .reg_data = 0x62, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04C9, .reg_data = 0xB2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04CA, .reg_data = 0x62, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04CB, .reg_data = 0x72, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04CC, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04CD, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04CE, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04CF, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04D0, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04D1, .reg_data = 0x1F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04D2, .reg_data = 0x6A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04D3, .reg_data = 0x41, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04D4, .reg_data = 0x62, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04D5, .reg_data = 0x41, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04D6, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04D7, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04D8, .reg_data = 0x7B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04D9, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04DA, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04DB, .reg_data = 0x3C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04DC, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04DD, .reg_data = 0x52, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04DE, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04DF, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04E0, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04E1, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04E2, .reg_data = 0x49, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04E3, .reg_data = 0x33, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04E4, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04E5, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04E6, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04E7, .reg_data = 0xC2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04E8, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04E9, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04EA, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04EB, .reg_data = 0xD2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04EC, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04ED, .reg_data = 0x4A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04EE, .reg_data = 0x2A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04EF, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04F0, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04F1, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04F2, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04F3, .reg_data = 0x94, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04F4, .reg_data = 0x4D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04F5, .reg_data = 0x2E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04F6, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04F7, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04F8, .reg_data = 0x35, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04F9, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04FA, .reg_data = 0xB2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04FB, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04FC, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04FD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04FE, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x04FF, .reg_data = 0x29, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0500, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0501, .reg_data = 0x5C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0502, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0503, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0504, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0505, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0506, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0507, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0508, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0509, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x050A, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x050B, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x050C, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x050D, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x050E, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x050F, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0510, .reg_data = 0x92, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0511, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0512, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0513, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0514, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0515, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0516, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0517, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0518, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0519, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x051A, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x051B, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x051C, .reg_data = 0x6A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x051D, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x051E, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x051F, .reg_data = 0x2C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0520, .reg_data = 0x6A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0521, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0522, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0523, .reg_data = 0x41, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0524, .reg_data = 0x1A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0525, .reg_data = 0x44, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0526, .reg_data = 0x1A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0527, .reg_data = 0x67, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0528, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0529, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x052A, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x052B, .reg_data = 0x29, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x052C, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x052D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x052E, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x052F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0530, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0531, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0532, .reg_data = 0x15, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0533, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0534, .reg_data = 0x49, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0535, .reg_data = 0x26, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0536, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0537, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0538, .reg_data = 0x31, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0539, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x053A, .reg_data = 0x13, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x053B, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x053C, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x053D, .reg_data = 0x6D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x053E, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x053F, .reg_data = 0x49, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0540, .reg_data = 0x15, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0541, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0542, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0543, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0544, .reg_data = 0x13, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0545, .reg_data = 0x69, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0546, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0547, .reg_data = 0x4D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0548, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0549, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x054A, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x054B, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x054C, .reg_data = 0x9A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x054D, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x054E, .reg_data = 0x1A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x054F, .reg_data = 0x84, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0550, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0551, .reg_data = 0x54, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0552, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0553, .reg_data = 0x64, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0554, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0555, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0556, .reg_data = 0x13, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0557, .reg_data = 0xE2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0558, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0559, .reg_data = 0x52, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x055A, .reg_data = 0x1A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x055B, .reg_data = 0xCA, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x055C, .reg_data = 0x13, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x055D, .reg_data = 0xD2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x055E, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x055F, .reg_data = 0x72, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0560, .reg_data = 0x4A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0561, .reg_data = 0x13, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0562, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0563, .reg_data = 0x51, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0564, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0565, .reg_data = 0x91, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0566, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0567, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0568, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0569, .reg_data = 0xD2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x056A, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x056B, .reg_data = 0x83, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x056C, .reg_data = 0x92, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x056D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x056E, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x056F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0570, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0571, .reg_data = 0xA3, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0572, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0573, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0574, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0575, .reg_data = 0xD2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0576, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0577, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0578, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0579, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x057A, .reg_data = 0x92, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x057B, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x057C, .reg_data = 0xA9, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x057D, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x057E, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x057F, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0580, .reg_data = 0xF7, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0581, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0582, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0583, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0584, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0585, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0586, .reg_data = 0xFE, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0587, .reg_data = 0xF5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0588, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0589, .reg_data = 0x3E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x058A, .reg_data = 0xBD, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x058B, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x058C, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x058D, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x058E, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x058F, .reg_data = 0xB8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0590, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0591, .reg_data = 0xB8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0592, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0593, .reg_data = 0x3C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0594, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0595, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0596, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0597, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0598, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0599, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x059A, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x059B, .reg_data = 0x69, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x059C, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x059D, .reg_data = 0x1A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x059E, .reg_data = 0xB2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x059F, .reg_data = 0x8B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05A0, .reg_data = 0x62, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05A1, .reg_data = 0x71, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05A2, .reg_data = 0x62, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05A3, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05A4, .reg_data = 0xE7, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05A5, .reg_data = 0x91, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05A6, .reg_data = 0x62, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05A7, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05A8, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05A9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05AA, .reg_data = 0x17, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05AB, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05AC, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05AD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05AE, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05AF, .reg_data = 0xCD, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05B0, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05B1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05B2, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05B3, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05B4, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05B5, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05B6, .reg_data = 0x19, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05B7, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05B8, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05B9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05BA, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05BB, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05BC, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05BD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05BE, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05BF, .reg_data = 0x2C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05C0, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05C1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05C2, .reg_data = 0x53, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05C3, .reg_data = 0x2C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05C4, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05C5, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05C6, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05C7, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05C8, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05C9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05CA, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05CB, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05CC, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05CD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05CE, .reg_data = 0x1A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05CF, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05D0, .reg_data = 0xC8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05D1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05D2, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05D3, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05D4, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05D5, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05D6, .reg_data = 0x49, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05D7, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05D8, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05D9, .reg_data = 0x70, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05DA, .reg_data = 0x62, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05DB, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05DC, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05DD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05DE, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05DF, .reg_data = 0xC1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05E0, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05E1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05E2, .reg_data = 0x1B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05E3, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05E4, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05E5, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05E6, .reg_data = 0xB5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05E7, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05E8, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05E9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05EA, .reg_data = 0x4B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05EB, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05EC, .reg_data = 0xA9, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05ED, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05EE, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05EF, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05F0, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05F1, .reg_data = 0x98, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05F2, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05F3, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05F4, .reg_data = 0x49, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05F5, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05F6, .reg_data = 0x98, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05F7, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05F8, .reg_data = 0x72, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05F9, .reg_data = 0x8A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05FA, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05FB, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05FC, .reg_data = 0x72, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05FD, .reg_data = 0xC8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05FE, .reg_data = 0x0B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x05FF, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0600, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0601, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0602, .reg_data = 0xBD, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0603, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0604, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0605, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0606, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0607, .reg_data = 0x24, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0608, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0609, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x060A, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x060B, .reg_data = 0x49, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x060C, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x060D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x060E, .reg_data = 0x1A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x060F, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0610, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0611, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0612, .reg_data = 0xB5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0613, .reg_data = 0xFE, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0614, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0615, .reg_data = 0x16, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0616, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0617, .reg_data = 0x0B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0618, .reg_data = 0x4D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0619, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x061A, .reg_data = 0x4C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x061B, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x061C, .reg_data = 0xF7, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x061D, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x061E, .reg_data = 0x5A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x061F, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0620, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0621, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0622, .reg_data = 0xFD, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0623, .reg_data = 0xD3, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0624, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0625, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0626, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0627, .reg_data = 0x31, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0628, .reg_data = 0x19, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0629, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x062A, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x062B, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x062C, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x062D, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x062E, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x062F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0630, .reg_data = 0xA9, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0631, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0632, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0633, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0634, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0635, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0636, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0637, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0638, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0639, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x063A, .reg_data = 0xBD, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x063B, .reg_data = 0xFE, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x063C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x063D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x063E, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x063F, .reg_data = 0xCD, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0640, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0641, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0642, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0643, .reg_data = 0xB5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0644, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0645, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0646, .reg_data = 0x19, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0647, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0648, .reg_data = 0x49, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0649, .reg_data = 0x15, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x064A, .reg_data = 0xB5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x064B, .reg_data = 0x7C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x064C, .reg_data = 0x4E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x064D, .reg_data = 0x13, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x064E, .reg_data = 0x4A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x064F, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0650, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0651, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0652, .reg_data = 0x4D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0653, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0654, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0655, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0656, .reg_data = 0x91, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0657, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0658, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0659, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x065A, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x065B, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x065C, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x065D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x065E, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x065F, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0660, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0661, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0662, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0663, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0664, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0665, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0666, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0667, .reg_data = 0x69, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0668, .reg_data = 0x6A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0669, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x066A, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x066B, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x066C, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x066D, .reg_data = 0xFC, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x066E, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x066F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0670, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0671, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0672, .reg_data = 0x78, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0673, .reg_data = 0xE8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0674, .reg_data = 0x70, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0675, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0676, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0677, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0678, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0679, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x067A, .reg_data = 0xBD, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x067B, .reg_data = 0x7C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x067C, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x067D, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x067E, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x067F, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0680, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0681, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0682, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0683, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0684, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0685, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0686, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0687, .reg_data = 0x69, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0688, .reg_data = 0x6A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0689, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x068A, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x068B, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x068C, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x068D, .reg_data = 0xFC, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x068E, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x068F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0690, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0691, .reg_data = 0xEF, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0692, .reg_data = 0x78, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0693, .reg_data = 0xE8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0694, .reg_data = 0xE7, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0695, .reg_data = 0xEE, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0696, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0697, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0698, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0699, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x069A, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x069B, .reg_data = 0x15, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x069C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x069D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x069E, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x069F, .reg_data = 0xB5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x06A0, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x06A1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x06A2, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x06A3, .reg_data = 0xF4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x06A4, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x06A5, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x06A6, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x06A7, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x06A8, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x06A9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x06AA, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x06AB, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x06AC, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x06AD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x06AE, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x06AF, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x06B0, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x06B1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x06B2, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x06B3, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x06B4, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x06B5, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x06B6, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x06B7, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x06B8, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x06B9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x06BA, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x06BB, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x06BC, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x06BD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x06BE, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x06BF, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x06C0, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x06C1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x06C2, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x06C3, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x06C4, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x06C5, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x06C6, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x06C7, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x06C8, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x06C9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x06CA, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x06CB, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + }, + .size = 1740, //1096//1097//1483 + .addr_type = CAMERA_SENSOR_I2C_TYPE_WORD, + .data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .delay = 0, +}, +.init_setting = +{ + .reg_settings = + { + {.reg_addr = 0x1C00, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C01, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C02, .reg_data = 0x77, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C03, .reg_data = 0x7E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C04, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C05, .reg_data = 0x15, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C06, .reg_data = 0x24, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C07, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C08, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C09, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C0A, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C0B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C0C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C0D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C0E, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C0F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C10, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C11, .reg_data = 0x45, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C12, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C13, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C14, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C15, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C16, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C17, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C18, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C19, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C1A, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C1B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C1C, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C1D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C1E, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C1F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C20, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C21, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C22, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C23, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C24, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C25, .reg_data = 0xEC, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C26, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C27, .reg_data = 0xEC, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C28, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C29, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C2A, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C2B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C2C, .reg_data = 0x0B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C2D, .reg_data = 0x3F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C2E, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C2F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C30, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C31, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C32, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C33, .reg_data = 0x71, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C34, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C35, .reg_data = 0x27, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C36, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C37, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C38, .reg_data = 0x83, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C39, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C3A, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C3B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C3C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C3D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C3E, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C3F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C40, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C41, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C42, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C43, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C44, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C45, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C46, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C47, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C48, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C49, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C4A, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C4B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C4C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C4D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C4E, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C4F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C50, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C51, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C52, .reg_data = 0x70, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C53, .reg_data = 0x70, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C54, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C55, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C56, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C57, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C58, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C59, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C5A, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C5B, .reg_data = 0x66, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C5C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C5D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C5E, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C5F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C60, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C61, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C62, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C63, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C64, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C65, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C66, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C67, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C68, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C69, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C6A, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C6B, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C6C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C6D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C6E, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C6F, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C70, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C71, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C72, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C73, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C74, .reg_data = 0x82, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C75, .reg_data = 0xCE, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C76, .reg_data = 0x3D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C77, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C78, .reg_data = 0x82, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C79, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C7A, .reg_data = 0x3D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C7B, .reg_data = 0x2F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C7C, .reg_data = 0x3F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C7D, .reg_data = 0xFE, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C7E, .reg_data = 0x3F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C7F, .reg_data = 0xFC, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C80, .reg_data = 0x3F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C81, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C82, .reg_data = 0x3F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C83, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C84, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C85, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C86, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C87, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C88, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C89, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C8A, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C8B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C8C, .reg_data = 0x3E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C8D, .reg_data = 0xFC, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C8E, .reg_data = 0xC1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C8F, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C90, .reg_data = 0x7F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C91, .reg_data = 0xF8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C92, .reg_data = 0x7F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C93, .reg_data = 0xF8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C94, .reg_data = 0x1A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C95, .reg_data = 0x5E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C96, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C97, .reg_data = 0xA5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C98, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C99, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C9A, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C9B, .reg_data = 0x1B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C9C, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C9D, .reg_data = 0xCE, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C9E, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1C9F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CA0, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CA1, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CA2, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CA3, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CA4, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CA5, .reg_data = 0x51, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CA6, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CA7, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CA8, .reg_data = 0x3F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CA9, .reg_data = 0xF2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CAA, .reg_data = 0x3F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CAB, .reg_data = 0xF2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CAC, .reg_data = 0x3F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CAD, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CAE, .reg_data = 0x7F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CAF, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CB0, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CB1, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CB2, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CB3, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CB4, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CB5, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CB6, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CB7, .reg_data = 0x9A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CB8, .reg_data = 0x6F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CB9, .reg_data = 0xF9, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CBA, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CBB, .reg_data = 0x6D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CBC, .reg_data = 0x7F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CBD, .reg_data = 0xA6, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CBE, .reg_data = 0x16, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CBF, .reg_data = 0xC1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CC0, .reg_data = 0xDD, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CC1, .reg_data = 0x31, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CC2, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CC3, .reg_data = 0xD5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CC4, .reg_data = 0x7A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CC5, .reg_data = 0xF7, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CC6, .reg_data = 0x89, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CC7, .reg_data = 0x99, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CC8, .reg_data = 0x3C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CC9, .reg_data = 0xAE, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CCA, .reg_data = 0x87, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CCB, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CCC, .reg_data = 0x3C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CCD, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CCE, .reg_data = 0x7F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CCF, .reg_data = 0x3A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CD0, .reg_data = 0x81, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CD1, .reg_data = 0x82, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CD2, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CD3, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CD4, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CD5, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CD6, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CD7, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CD8, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CD9, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CDA, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CDB, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CDC, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CDD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CDE, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CDF, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CE0, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CE1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CE2, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CE3, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CE4, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CE5, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CE6, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CE7, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CE8, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CE9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CEA, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CEB, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CEC, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CED, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CEE, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CEF, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CF0, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CF1, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CF2, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CF3, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CF4, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CF5, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CF6, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CF7, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CF8, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CF9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CFA, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CFB, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CFC, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CFD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CFE, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1CFF, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D00, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D01, .reg_data = 0x9D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D02, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D03, .reg_data = 0x9D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D04, .reg_data = 0xC6, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D05, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D06, .reg_data = 0xC6, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D07, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D08, .reg_data = 0x19, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D09, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D0A, .reg_data = 0x19, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D0B, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D0C, .reg_data = 0x7C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D0D, .reg_data = 0x5E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D0E, .reg_data = 0x7C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D0F, .reg_data = 0x5E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D10, .reg_data = 0x87, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D11, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D12, .reg_data = 0x87, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D13, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D14, .reg_data = 0x3C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D15, .reg_data = 0xAE, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D16, .reg_data = 0x3C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D17, .reg_data = 0xAE, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D18, .reg_data = 0x87, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D19, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D1A, .reg_data = 0x87, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D1B, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D1C, .reg_data = 0x3C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D1D, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D1E, .reg_data = 0x3C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D1F, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D20, .reg_data = 0x7F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D21, .reg_data = 0x3A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D22, .reg_data = 0x7F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D23, .reg_data = 0x3A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D24, .reg_data = 0x81, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D25, .reg_data = 0x82, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D26, .reg_data = 0x81, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D27, .reg_data = 0x82, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D28, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D29, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D2A, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D2B, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D2C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D2D, .reg_data = 0x1F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D2E, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D2F, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D30, .reg_data = 0x3C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D31, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D32, .reg_data = 0x3C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D33, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D34, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D35, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D36, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D37, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D38, .reg_data = 0x75, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D39, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D3A, .reg_data = 0x74, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D3B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D3C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D3D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D3E, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D3F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D40, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D41, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D42, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D43, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D44, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D45, .reg_data = 0x0E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D46, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D47, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D48, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D49, .reg_data = 0x6D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D4A, .reg_data = 0x7F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D4B, .reg_data = 0xF4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D4C, .reg_data = 0x82, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D4D, .reg_data = 0x83, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D4E, .reg_data = 0x81, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D4F, .reg_data = 0xA5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D50, .reg_data = 0x3D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D51, .reg_data = 0x7D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D52, .reg_data = 0x3E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D53, .reg_data = 0x5B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D54, .reg_data = 0x82, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D55, .reg_data = 0x86, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D56, .reg_data = 0x81, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D57, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D58, .reg_data = 0x3D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D59, .reg_data = 0x7A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D5A, .reg_data = 0x3E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D5B, .reg_data = 0x58, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D5C, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D5D, .reg_data = 0xFB, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D5E, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D5F, .reg_data = 0xFB, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D60, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D61, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D62, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D63, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D64, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D65, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D66, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1D67, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, + }, + .size = 360, + .addr_type = CAMERA_SENSOR_I2C_TYPE_WORD, + .data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .delay = 0, +}, +.calib_data = +{ + .reg_settings = + { + {.reg_addr = 0x1DC0, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1DC1, .reg_data = 0x24, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1DC2, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1DC3, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1DC4, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1DC5, .reg_data = 0xea, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1DC6, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1DC7, .reg_data = 0xec, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1DC8, .reg_data = 0xff, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1DC9, .reg_data = 0x5f, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1DCA, .reg_data = 0xff, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1DCB, .reg_data = 0xc3, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1DCC, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1DCD, .reg_data = 0x35, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1DCE, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1DCF, .reg_data = 0x23, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1DD0, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1DD1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1DD2, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1DD3, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1DD4, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1DD5, .reg_data = 0x6a, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1DD6, .reg_data = 0x0d, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1DD7, .reg_data = 0x70, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1DD8, .reg_data = 0x0e, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1DD9, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1DDA, .reg_data = 0xc9, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1DDB, .reg_data = 0x0a, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1DDC, .reg_data = 0xc9, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1DDD, .reg_data = 0x0a, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1DDE, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1DDF, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1DE0, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1DE1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1DE2, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1DE3, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1DE4, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x1DE5, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xF006, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + }, + .size = 39, + .addr_type = CAMERA_SENSOR_I2C_TYPE_WORD, + .data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .delay = 0, +}, +.control_data_0 = +{ + .reg_settings = + { + {.reg_addr = 0x6020, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00},// servo on + }, + .size = 1, + .addr_type = CAMERA_SENSOR_I2C_TYPE_WORD, + .data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .delay = 100, +}, +.control_data_1 = +{ + .reg_settings = + { + {.reg_addr = 0x614F, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00},// LC on + {.reg_addr = 0x6023, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00},// gyro on + {.reg_addr = 0x6021, .reg_data = 0x7B, .delay = 0x00, .data_mask = 0x00},// zero shutter mode + }, + .size = 3, + .addr_type = CAMERA_SENSOR_I2C_TYPE_WORD, + .data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .delay = 10, +}, +.control_data_2 = +{ + .reg_settings = + { + {.reg_addr = 0x6020, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00},// ois on + }, + .size = 1, + .addr_type = CAMERA_SENSOR_I2C_TYPE_WORD, + .data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .delay = 0, +}, + diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ois/cam_ois_core.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ois/cam_ois_core.c new file mode 100644 index 000000000000..612305598ca5 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ois/cam_ois_core.c @@ -0,0 +1,893 @@ +/* Copyright (c) 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. + */ + +#include +#include +#include +#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" + +int32_t cam_ois_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 = + (struct cam_sensor_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 = + (struct cam_sensor_power_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); + 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, (void __user *) 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((void __user *) 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; +} + +static 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); + + 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; + } + + rc = msm_camera_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) +{ + int32_t rc = 0; + struct cam_cmd_ois_info *ois_info; + + if (!o_ctrl || !cmd_buf) { + 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, 32); + 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); + 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); + 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; + uint64_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; + uint64_t generic_pkt_addr; + size_t pkt_len; + 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; + struct cam_sensor_i2c_reg_setting hhk_add_setting;//add by hhk + struct cam_sensor_i2c_reg_array hhk_add_reg[3];//add by hhk + int32_t j = 0; + uint32_t red_reg_data=0; + ioctl_ctrl = (struct cam_control *)arg; + + if (copy_from_user(&dev_config, (void __user *) ioctl_ctrl->handle, + sizeof(dev_config))) + return -EFAULT; + + rc = cam_mem_get_cpu_buf(dev_config.packet_handle, + (uint64_t *)&generic_pkt_addr, &pkt_len); + if (rc) { + CAM_ERR(CAM_OIS, + "error in converting command Handle Error: %d", rc); + return rc; + } + + if (dev_config.offset > pkt_len) { + CAM_ERR(CAM_OIS, + "offset is out of bound: off: %lld len: %zu", + dev_config.offset, pkt_len); + return -EINVAL; + } + + csl_packet = (struct cam_packet *) + (generic_pkt_addr + dev_config.offset); + 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, + (uint64_t *)&generic_ptr, &len_of_buff); + if (rc < 0) { + CAM_ERR(CAM_OIS, "Failed to get cpu buf"); + return rc; + } + cmd_buf = (uint32_t *)generic_ptr; + if (!cmd_buf) { + CAM_ERR(CAM_OIS, "invalid cmd buf"); + return -EINVAL; + } + 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); + 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"); + rc = cam_sensor_update_power_settings( + cmd_buf, + total_cmd_buf_in_bytes, + power_info); + 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( + 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( + 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) { + rc = cam_ois_power_up(o_ctrl); + 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) { + rc = cam_ois_fw_download(o_ctrl); + if (rc) { + CAM_ERR(CAM_OIS, "Failed OIS FW Download"); + goto pwr_dwn; + } + } + + rc = cam_ois_apply_settings(o_ctrl, &o_ctrl->i2c_init_data); + if (rc < 0) { + CAM_ERR(CAM_OIS, "Cannot apply Init settings"); + goto pwr_dwn; + } + + if (o_ctrl->is_ois_calib) { + //modify by huanghongkun begin + //for debug + rc = camera_io_dev_read(&(o_ctrl->io_master_info), + 0xF008, + &red_reg_data, + CAMERA_SENSOR_I2C_TYPE_WORD, + CAMERA_SENSOR_I2C_TYPE_DWORD); + if (rc < 0) { + CAM_ERR(CAM_OIS, "Failed to read 0xF008"); + } else + CAM_DBG(CAM_OIS, "read 0xF008 = 0x%x", + red_reg_data); + + if (o_ctrl->i2c_calib_data.is_settings_valid == 1) { + 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; + } + } else{ + CAM_ERR(CAM_OIS, + "WA ois calib data invalid,ignore it."); + } + } + + rc = delete_request(&o_ctrl->i2c_init_data); + if (rc < 0) { + CAM_WARN(CAM_OIS, + "Fail deleting Init data: rc: %d", rc); + rc = 0; + } + if (o_ctrl->is_ois_calib + && o_ctrl->i2c_calib_data.is_settings_valid == 1){ + o_ctrl->isPollNeeded = true; + CAM_ERR(CAM_OIS, + "WA calib data invalid,ignore poll."); + } + 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; + } + + if(o_ctrl->isPollNeeded == true) + { + red_reg_data=0; + for(j = 0; j < 50; j++) + { + rc = camera_io_dev_read(&(o_ctrl->io_master_info), 0x6024, &red_reg_data, + CAMERA_SENSOR_I2C_TYPE_WORD, CAMERA_SENSOR_I2C_TYPE_BYTE); + if (rc < 0) { + CAM_ERR(CAM_OIS, "Failed to read 0x6024"); + } else + CAM_DBG(CAM_OIS, "calib_data end read 0x6024 = 0x%x", red_reg_data); + if(red_reg_data == 1) + break; + else + msleep(10); + }//control data 0 + hhk_add_reg[0].data_mask = 0x00; + hhk_add_reg[0].delay = 0x00; + hhk_add_reg[0].reg_addr = 0x6020; + hhk_add_reg[0].reg_data = 0x01; + hhk_add_setting.reg_setting = &hhk_add_reg[0]; + hhk_add_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD; + hhk_add_setting.data_type = CAMERA_SENSOR_I2C_TYPE_BYTE; + hhk_add_setting.size = 1; + hhk_add_setting.delay =10; + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &hhk_add_setting); + if (rc < 0) { + CAM_ERR(CAM_OIS, "Failed to write control_data_0"); + goto pwr_dwn; + } + red_reg_data=0; + for(j = 0; j < 50; j++) + { + rc = camera_io_dev_read(&(o_ctrl->io_master_info), 0x6024, &red_reg_data, + CAMERA_SENSOR_I2C_TYPE_WORD, CAMERA_SENSOR_I2C_TYPE_BYTE); + if (rc < 0) { + CAM_ERR(CAM_OIS, "Failed to read 0x6024"); + } else + CAM_DBG(CAM_OIS, "control_data_0 end read 0x6024 = 0x%x", red_reg_data); + if(red_reg_data == 1) + break; + else + msleep(10); + }//control data 1 + hhk_add_reg[0].data_mask = 0x00; + hhk_add_reg[0].delay = 0x00; + hhk_add_reg[0].reg_addr = 0x614F; + hhk_add_reg[0].reg_data = 0x01; + hhk_add_reg[1].data_mask = 0x00; + hhk_add_reg[1].delay = 0x00; + hhk_add_reg[1].reg_addr = 0x6023; + hhk_add_reg[1].reg_data = 0x00; + hhk_add_reg[2].data_mask = 0x00; + hhk_add_reg[2].delay = 0x00; + hhk_add_reg[2].reg_addr = 0x6021; + hhk_add_reg[2].reg_data = 0x7B; + hhk_add_setting.reg_setting = &hhk_add_reg[0]; + hhk_add_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD; + hhk_add_setting.data_type = CAMERA_SENSOR_I2C_TYPE_BYTE; + hhk_add_setting.size = 3; + hhk_add_setting.delay = 0; + rc = camera_io_dev_write(&(o_ctrl->io_master_info), &hhk_add_setting); + if (rc < 0) { + CAM_ERR(CAM_OIS, "Failed to write control_data_1"); + goto pwr_dwn; + } + red_reg_data=0; + for(j = 0; j < 50; j++) + { + rc = camera_io_dev_read(&(o_ctrl->io_master_info), 0x6024, &red_reg_data, + CAMERA_SENSOR_I2C_TYPE_WORD, CAMERA_SENSOR_I2C_TYPE_BYTE); + if (rc < 0) { + CAM_ERR(CAM_OIS, "Failed to read 0x6024"); + } else + CAM_DBG(CAM_OIS, "control_data_1 end read 0x6024 = 0x%x", red_reg_data); + if(red_reg_data == 1) + break; + else + msleep(10); + } + //modify by huanghongkun end + o_ctrl->isPollNeeded = false; + } + + 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(i2c_reg_settings, + cmd_desc, 1); + if (rc < 0) { + CAM_ERR(CAM_OIS, "OIS pkt parsing failed: %d", rc); + return rc; + } + + 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); + break; + default: + break; + } + return rc; +pwr_dwn: + CAM_ERR(CAM_OIS, "cam_ois_power_down."); + cam_ois_power_down(o_ctrl); + return rc; +} + +void cam_ois_shutdown(struct cam_ois_ctrl_t *o_ctrl) +{ + int rc; + + if (o_ctrl->cam_ois_state == CAM_OIS_INIT) + return; + + if (o_ctrl->cam_ois_state >= CAM_OIS_CONFIG) { + CAM_ERR(CAM_OIS, "cam_ois_power_down."); + rc = cam_ois_power_down(o_ctrl); + if (rc < 0) + CAM_ERR(CAM_OIS, "OIS Power down failed"); + } + + 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; + } + + 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; + + if (!o_ctrl) { + CAM_ERR(CAM_OIS, "e_ctrl is NULL"); + return -EINVAL; + } + + if (cmd->handle_type != CAM_HANDLE_USER_POINTER) { + CAM_ERR(CAM_OIS, "Invalid handle type: %d", + cmd->handle_type); + return -EINVAL; + } + + 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((void __user *) 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: + 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: + 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_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) { + CAM_ERR(CAM_OIS, "cam_ois_power_down."); + rc = cam_ois_power_down(o_ctrl); + 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; + break; + case CAM_STOP_DEV: + 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; + default: + CAM_ERR(CAM_OIS, "invalid opcode"); + goto release_mutex; + } +release_mutex: + mutex_unlock(&(o_ctrl->ois_mutex)); + return rc; +} diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ois/cam_ois_core.h b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ois/cam_ois_core.h new file mode 100644 index 000000000000..908f9d27963b --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ois/cam_ois_core.h @@ -0,0 +1,40 @@ +/* Copyright (c) 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. + */ +#ifndef _CAM_OIS_CORE_H_ +#define _CAM_OIS_CORE_H_ + +#include +#include +#include "cam_ois_dev.h" + +/** + * @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); + +/** + * @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/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ois/cam_ois_dev.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ois/cam_ois_dev.c new file mode 100644 index 000000000000..d742acf7813d --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ois/cam_ois_dev.c @@ -0,0 +1,419 @@ +/* Copyright (c) 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. + */ + +#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" + +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; + 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)); + 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; + } + + 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]); + + soc_private = + (struct cam_ois_soc_private *)soc_info->soc_private; + power_info = &soc_private->power_info; + + kfree(power_info->power_setting); + kfree(power_info->power_down_setting); + kfree(o_ctrl->soc_info.soc_private); + 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)); + 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); + v4l2_set_subdevdata(&o_ctrl->v4l2_dev_str.sd, o_ctrl); + + o_ctrl->cam_ois_state = CAM_OIS_INIT; + + 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; + } + + 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]); + + soc_private = + (struct cam_ois_soc_private *)o_ctrl->soc_info.soc_private; + power_info = &soc_private->power_info; + + kfree(power_info->power_setting); + kfree(power_info->power_down_setting); + kfree(o_ctrl->soc_info.soc_private); + kfree(o_ctrl->io_master_info.cci_client); + 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/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ois/cam_ois_dev.h b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ois/cam_ois_dev.h new file mode 100644 index 000000000000..3a30b250f6bd --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ois/cam_ois_dev.h @@ -0,0 +1,133 @@ +/* Copyright (c) 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. + */ +#ifndef _CAM_OIS_DEV_H_ +#define _CAM_OIS_DEV_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cam_soc_util.h" + +#define DEFINE_MSM_MUTEX(mutexname) \ + static struct mutex mutexname = __MUTEX_INITIALIZER(mutexname) + +enum cam_ois_state { + CAM_OIS_INIT, + CAM_OIS_ACQUIRE, + CAM_OIS_CONFIG, + CAM_OIS_START, +}; + +/** + * 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 + * @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_name : ois name + * @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 { + 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; + 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 device_name[20]; + char ois_name[32]; + uint8_t ois_fw_flag; + uint8_t is_ois_calib; + struct cam_ois_opcode opcode; + bool isPollNeeded; +}; + +#endif /*_CAM_OIS_DEV_H_ */ diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ois/cam_ois_soc.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ois/cam_ois_soc.c new file mode 100644 index 000000000000..c8b34487a1fa --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ois/cam_ois_soc.c @@ -0,0 +1,118 @@ +/* Copyright (c) 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. + */ + +#include +#include +#include +#include +#include +#include + +#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; + struct cam_hw_soc_info *soc_info = &o_ctrl->soc_info; + struct device_node *of_node = NULL; + + 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; + } + } + + rc = cam_ois_get_dt_data(o_ctrl); + if (rc < 0) + CAM_DBG(CAM_OIS, "failed: ois get dt data rc %d", rc); + + return rc; +} diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ois/cam_ois_soc.h b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ois/cam_ois_soc.h new file mode 100644 index 000000000000..af0413436a0b --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ois/cam_ois_soc.h @@ -0,0 +1,19 @@ +/* Copyright (c) 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. + */ +#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/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_res_mgr/Makefile b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_res_mgr/Makefile new file mode 100644 index 000000000000..ed911ac1e5a0 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_res_mgr/Makefile @@ -0,0 +1,9 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_core +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_cpas/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_req_mgr +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_utils +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_utils + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_res_mgr.o diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_res_mgr/cam_res_mgr.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_res_mgr/cam_res_mgr.c new file mode 100644 index 000000000000..bb3789b12dcc --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_res_mgr/cam_res_mgr.c @@ -0,0 +1,737 @@ +/* Copyright (c) 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. + */ + +#include +#include +#include +#include +#include +#include +#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; + } + + if (cam_res->pstatus != PINCTRL_STATUS_PUT) { + CAM_DBG(CAM_RES, "The shared pinctrl already been got."); + 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; + 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; + 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; + return -EINVAL; + } + + mutex_lock(&cam_res->gpio_res_lock); + 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; + + for (; index < dt->num_shared_gpio; index++) { + if (gpio == dt->shared_gpio[index]) { + found = true; + break; + } + } + + 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); + + rc = cam_res_mgr_add_device(dev, gpio_res); + if (rc) { + kfree(gpio_res); + return rc; + } + + mutex_lock(&cam_res->gpio_res_lock); + 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, + }, +}; + +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/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_res_mgr/cam_res_mgr_api.h b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_res_mgr/cam_res_mgr_api.h new file mode 100644 index 000000000000..7fb13ba4b9e9 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_res_mgr/cam_res_mgr_api.h @@ -0,0 +1,148 @@ +/* Copyright (c) 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. + */ + +#ifndef __CAM_RES_MGR_API_H__ +#define __CAM_RES_MGR_API_H__ + +#include + +/** + * @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/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_res_mgr/cam_res_mgr_private.h b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_res_mgr/cam_res_mgr_private.h new file mode 100644 index 000000000000..53a877808d55 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_res_mgr/cam_res_mgr_private.h @@ -0,0 +1,117 @@ +/* Copyright (c) 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. + */ + +#ifndef __CAM_RES_MGR_PRIVATE_H__ +#define __CAM_RES_MGR_PRIVATE_H__ + +#include +#include +#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/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/CAM_SENSOR_SETTINGS.h b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/CAM_SENSOR_SETTINGS.h new file mode 100644 index 000000000000..aacaf00ae87b --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/CAM_SENSOR_SETTINGS.h @@ -0,0 +1,1024 @@ +.imx519_setting = +{ + .reg_setting = + { + {.reg_addr = 0x0136, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0137, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C7E, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C7F, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3020, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3E35, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F7F, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5609, .reg_data = 0x57, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5613, .reg_data = 0x51, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x561F, .reg_data = 0x5E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5623, .reg_data = 0xD2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5637, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5657, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5659, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5733, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5905, .reg_data = 0x57, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x590F, .reg_data = 0x51, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x591B, .reg_data = 0x5E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x591F, .reg_data = 0xD2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5933, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5953, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5955, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5A2F, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5A85, .reg_data = 0x57, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5A8F, .reg_data = 0x51, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5A9B, .reg_data = 0x5E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5A9F, .reg_data = 0xD2, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5AB3, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5AD3, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5AD5, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5BAF, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5C15, .reg_data = 0x2A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5C17, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5C19, .reg_data = 0x31, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5C1B, .reg_data = 0x87, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5C25, .reg_data = 0x25, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5C27, .reg_data = 0x7B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5C29, .reg_data = 0x2A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5C2B, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5C2D, .reg_data = 0x31, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5C2F, .reg_data = 0x87, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5C35, .reg_data = 0x2B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5C37, .reg_data = 0x81, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5C39, .reg_data = 0x31, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5C3B, .reg_data = 0x87, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5C45, .reg_data = 0x25, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5C47, .reg_data = 0x7B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5C49, .reg_data = 0x2A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5C4B, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5C4D, .reg_data = 0x31, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5C4F, .reg_data = 0x87, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5C55, .reg_data = 0x2D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5C57, .reg_data = 0x83, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5C59, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5C5B, .reg_data = 0x88, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5C65, .reg_data = 0x29, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5C67, .reg_data = 0x7F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5C69, .reg_data = 0x2E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5C6B, .reg_data = 0x84, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5C6D, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5C6F, .reg_data = 0x88, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5E69, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5E9D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F18, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F1A, .reg_data = 0x0E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F20, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F22, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F24, .reg_data = 0x0E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F28, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F2A, .reg_data = 0x0E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F30, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F32, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F34, .reg_data = 0x0E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F38, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F39, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F3C, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F3D, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F3E, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F61, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F64, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F67, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F6A, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F6D, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F70, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F73, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F76, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F79, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F7C, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F7F, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F82, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F85, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F88, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F8B, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F8E, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F91, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F94, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F97, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5F9D, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5FA0, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5FA3, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5FA6, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5FA9, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5FAC, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5FAF, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5FB5, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5FB8, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5FBB, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5FC1, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5FC4, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5FC7, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5FD1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6302, .reg_data = 0x79, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6305, .reg_data = 0x78, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6306, .reg_data = 0xA5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6308, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6309, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x630B, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x630D, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x630F, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6311, .reg_data = 0xA4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6313, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6314, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6316, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6317, .reg_data = 0x31, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6318, .reg_data = 0x4A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x631A, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x631B, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x631C, .reg_data = 0xA4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x631E, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x631F, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6321, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6323, .reg_data = 0x4A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6328, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6329, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x632A, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x632B, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x632C, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x632D, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x632E, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6330, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6332, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6333, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6334, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6335, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6336, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6338, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x633A, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x633B, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x633C, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x633D, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x633E, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x633F, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6340, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6341, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6342, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6343, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6344, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6345, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6346, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6348, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6349, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x634A, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x634B, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x634C, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x634D, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x634E, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6350, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6351, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6352, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6353, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6354, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6355, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6356, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6357, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6358, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6359, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x635A, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x635B, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x635C, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x635F, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6360, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6361, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6362, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6363, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6364, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6368, .reg_data = 0x70, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x636A, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x636B, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x636C, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x637D, .reg_data = 0xE4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x637E, .reg_data = 0xB4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x638C, .reg_data = 0x8E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x638D, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x638E, .reg_data = 0xE3, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x638F, .reg_data = 0x4C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6390, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6391, .reg_data = 0xC3, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6392, .reg_data = 0xAE, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6393, .reg_data = 0xBA, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6394, .reg_data = 0xEB, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6395, .reg_data = 0x6E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6396, .reg_data = 0x34, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6397, .reg_data = 0xE3, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6398, .reg_data = 0xCF, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6399, .reg_data = 0x3C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x639A, .reg_data = 0xF3, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x639B, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x639C, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x639D, .reg_data = 0xC1, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x63B9, .reg_data = 0xA3, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x63BA, .reg_data = 0xFE, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7600, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x79A0, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x79A1, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x79A2, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x79A3, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x79A4, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x79A5, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x79A9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x79AA, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x79AD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x79AF, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x8173, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x835C, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x8A74, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x8C1F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x8C27, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x8C3B, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9004, .reg_data = 0x0B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x920C, .reg_data = 0x6A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x920D, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x920E, .reg_data = 0x6A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x920F, .reg_data = 0x23, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9214, .reg_data = 0x6A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9215, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9216, .reg_data = 0x6A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9217, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9385, .reg_data = 0x3E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9387, .reg_data = 0x1B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x938D, .reg_data = 0x4D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x938F, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9391, .reg_data = 0x1B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9395, .reg_data = 0x4D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9397, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9399, .reg_data = 0x1B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x939D, .reg_data = 0x3E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x939F, .reg_data = 0x2F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93A5, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93A7, .reg_data = 0x2F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93A9, .reg_data = 0x2F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93AD, .reg_data = 0x34, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93AF, .reg_data = 0x2F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93B5, .reg_data = 0x3E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93B7, .reg_data = 0x2F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93BD, .reg_data = 0x4D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93BF, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93C1, .reg_data = 0x2F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93C5, .reg_data = 0x4D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93C7, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93C9, .reg_data = 0x2F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x974B, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x995C, .reg_data = 0x8C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x995D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x995E, .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 = 0xAA0A, .reg_data = 0x26, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAE03, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAE04, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAE05, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xBC1C, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAA06, .reg_data = 0x3F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAA07, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAA08, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAA12, .reg_data = 0x3F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAA13, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAA14, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAA1E, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAA1F, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAA20, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAA2A, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAA2B, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAA2C, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAC19, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAC1B, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAC1D, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAC3C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAC3D, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAC3E, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAC3F, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAC40, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAC41, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAC61, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAC63, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAC65, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAC84, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAC85, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAC86, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAC87, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAC88, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAC89, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0111, .reg_data = 0x03, .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 = 0x17, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0343, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0340, .reg_data = 0x0E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0341, .reg_data = 0x13, .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 = 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 = 0x3F4C, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F4D, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4254, .reg_data = 0x7F, .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 = 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 = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0305, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0306, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0307, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0309, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x030B, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x030D, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x030E, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x030F, .reg_data = 0x13, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0310, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0820, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0821, .reg_data = 0xE4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0822, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0823, .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 = 0x3E3B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0106, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0B00, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3230, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F14, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F3C, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F0D, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3FBC, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C06, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C07, .reg_data = 0x06, .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 = 0x3F78, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F79, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F7C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F7D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0202, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0203, .reg_data = 0xE8, .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 = 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 = 0x020E, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x020F, .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 = 0x0100, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + }, + .size = 387, + .addr_type = CAMERA_SENSOR_I2C_TYPE_WORD, + .data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .delay = 1, +}, +.imx376k_setting = +{ + .reg_setting = + { + {.reg_addr = 0x0136, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0137, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C7D, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C7E, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C7F, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0B06, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F02, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F22, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F7F, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4421, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4430, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4431, .reg_data = 0xDC, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5222, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x56B7, .reg_data = 0x74, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6204, .reg_data = 0xC6, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x620E, .reg_data = 0x27, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6210, .reg_data = 0x69, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6211, .reg_data = 0xD6, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6213, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6215, .reg_data = 0x5A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6216, .reg_data = 0x75, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6218, .reg_data = 0x5A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6219, .reg_data = 0x75, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6220, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6222, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6225, .reg_data = 0x19, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6228, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6229, .reg_data = 0x70, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x622B, .reg_data = 0x64, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x622E, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6231, .reg_data = 0x71, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6234, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6236, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6237, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6239, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x623C, .reg_data = 0x19, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x623F, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6240, .reg_data = 0x71, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6242, .reg_data = 0x64, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6243, .reg_data = 0x44, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6245, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6246, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6248, .reg_data = 0x71, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x624B, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x624D, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x625C, .reg_data = 0xC9, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x625F, .reg_data = 0x92, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6262, .reg_data = 0x26, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6264, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6265, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6267, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x626A, .reg_data = 0x19, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x626D, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x626E, .reg_data = 0x72, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6270, .reg_data = 0x64, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6271, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6273, .reg_data = 0xC8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6276, .reg_data = 0x91, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6279, .reg_data = 0x27, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x627B, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x627C, .reg_data = 0x55, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x627F, .reg_data = 0x95, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6282, .reg_data = 0x84, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6283, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6284, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6285, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6286, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6287, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6288, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6289, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x628A, .reg_data = 0x1B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x628B, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x628C, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x628E, .reg_data = 0x35, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x628F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6290, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6291, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6292, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6293, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6294, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6296, .reg_data = 0x54, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6297, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6298, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6299, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x629A, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x629B, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x629C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x629D, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x629E, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x629F, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62A0, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62B1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62B2, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62B3, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62B5, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62B6, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62B7, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62B8, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62B9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62BA, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62BB, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62BC, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62BD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62BE, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62BF, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62D0, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62D1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62D2, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62D4, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62D5, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62D6, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62D7, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62D8, .reg_data = 0xD8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62D9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62DA, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62DB, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62DC, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62DD, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62DE, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62EF, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62F0, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62F1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62F3, .reg_data = 0x58, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62F4, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62F5, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62F6, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62F7, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62F8, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62F9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62FA, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62FB, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62FC, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62FD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62FE, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62FF, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6300, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6301, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6302, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6303, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6304, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6305, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6306, .reg_data = 0x1B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6307, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6308, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x630A, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x630B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x630C, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x630E, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x630F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6310, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6312, .reg_data = 0x58, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6313, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6314, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6315, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6316, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6317, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6318, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6319, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x631A, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x631B, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x631C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x632D, .reg_data = 0x0E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x632E, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x632F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6331, .reg_data = 0x44, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6332, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6333, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6334, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6335, .reg_data = 0xE8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6336, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6337, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6338, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6339, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x633A, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x633B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x634C, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x634D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x634E, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6350, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6351, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6352, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6353, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6354, .reg_data = 0xD8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6355, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6356, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6357, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6358, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6359, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x635A, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x636B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x636C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x636D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x636F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6370, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6371, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6372, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6373, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6374, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6375, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6376, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6377, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6378, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6379, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x637A, .reg_data = 0x13, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x637B, .reg_data = 0xD4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6388, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6389, .reg_data = 0x82, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x638A, .reg_data = 0xC8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x639D, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7BA0, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7BA9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7BAA, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7BAD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9002, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9003, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9004, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9006, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9200, .reg_data = 0x93, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9201, .reg_data = 0x85, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9202, .reg_data = 0x93, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9203, .reg_data = 0x87, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9204, .reg_data = 0x93, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9205, .reg_data = 0x8D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9206, .reg_data = 0x93, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9207, .reg_data = 0x8F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9208, .reg_data = 0x62, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9209, .reg_data = 0x2C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x920A, .reg_data = 0x62, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x920B, .reg_data = 0x2F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x920C, .reg_data = 0x6A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x920D, .reg_data = 0x23, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x920E, .reg_data = 0x71, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x920F, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9210, .reg_data = 0x71, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9211, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9212, .reg_data = 0x71, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9213, .reg_data = 0x0B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9214, .reg_data = 0x6A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9215, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9216, .reg_data = 0x71, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9217, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9218, .reg_data = 0x71, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9219, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x935D, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9389, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x938B, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9391, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9393, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9395, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9397, .reg_data = 0x5A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9399, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x939B, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x939D, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x939F, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93A1, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x93A3, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xB3F1, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xB3F2, .reg_data = 0x0E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xBC40, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xBC82, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xBC83, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xBC84, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xBC85, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xE0A6, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAA3F, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAA41, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAA43, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAA5D, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAA5F, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAA61, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAACF, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAAD1, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAAD3, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAAED, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAAEF, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAAF1, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xB6D9, .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 = 0x15, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0343, .reg_data = 0xF8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0340, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0341, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F39, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F3A, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F3B, .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 = 0x14, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0349, .reg_data = 0x3F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x034A, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x034B, .reg_data = 0x27, .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 = 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 = 0x3F4D, .reg_data = 0x81, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F4C, .reg_data = 0x81, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4254, .reg_data = 0x7F, .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 = 0x0A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x040D, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x040E, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x040F, .reg_data = 0x94, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x034C, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x034D, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x034E, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x034F, .reg_data = 0x94, .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 = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0306, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0307, .reg_data = 0xFA, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x030B, .reg_data = 0x02, .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 = 0x5E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0310, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0820, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0821, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0822, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0823, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xBC41, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0106, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0B00, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0B05, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3230, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3602, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3607, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C00, .reg_data = 0x74, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C01, .reg_data = 0x5F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C02, .reg_data = 0x73, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C03, .reg_data = 0x64, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C04, .reg_data = 0x54, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C05, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C06, .reg_data = 0xBE, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C07, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C08, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C09, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C0A, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C0B, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C0C, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3E20, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3E3D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F14, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F17, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F3C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F78, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F79, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F7A, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F7B, .reg_data = 0xBC, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x562B, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x562D, .reg_data = 0x34, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5617, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7849, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9104, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0202, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0203, .reg_data = 0x70, .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 = 375, + .addr_type = CAMERA_SENSOR_I2C_TYPE_WORD, + .data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .delay = 1, +}, +.imx371_setting = +{ + .reg_setting = + { + {.reg_addr = 0x0136, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0137, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C7D, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C7E, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C7F, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F02, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F7F, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4421, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4430, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x4431, .reg_data = 0xDC, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5222, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x562B, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x562D, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x56B7, .reg_data = 0x74, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6200, .reg_data = 0x95, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6201, .reg_data = 0xB9, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6202, .reg_data = 0x58, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6220, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6222, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6225, .reg_data = 0x19, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6228, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6229, .reg_data = 0x70, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x622A, .reg_data = 0xC3, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x622B, .reg_data = 0x64, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x622C, .reg_data = 0x54, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x622E, .reg_data = 0xB8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x622F, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6231, .reg_data = 0x73, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6233, .reg_data = 0x42, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6234, .reg_data = 0xEA, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6235, .reg_data = 0x8C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6236, .reg_data = 0x35, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6237, .reg_data = 0xC5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6239, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x623A, .reg_data = 0x96, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x623C, .reg_data = 0x19, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x623F, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6240, .reg_data = 0x59, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6241, .reg_data = 0x83, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6242, .reg_data = 0x64, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6243, .reg_data = 0x54, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6245, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6246, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6248, .reg_data = 0x53, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x624A, .reg_data = 0x42, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x624B, .reg_data = 0xA5, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x624C, .reg_data = 0x98, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x624D, .reg_data = 0x35, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6265, .reg_data = 0x45, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6267, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x626A, .reg_data = 0x19, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x626D, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x626E, .reg_data = 0x72, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x626F, .reg_data = 0xC3, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6270, .reg_data = 0x64, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6271, .reg_data = 0x58, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6273, .reg_data = 0xC8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6276, .reg_data = 0x91, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6279, .reg_data = 0x27, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x627B, .reg_data = 0x36, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6282, .reg_data = 0x82, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6283, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6286, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6287, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6288, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x628A, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x628B, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x628C, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x628E, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6290, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6292, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6296, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x629A, .reg_data = 0xF8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x629B, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x629D, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x629F, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62B1, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62B5, .reg_data = 0x3C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62B9, .reg_data = 0xC8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62BC, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62BD, .reg_data = 0x70, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62D0, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62D4, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62D8, .reg_data = 0xB8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62DB, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62DC, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x62DD, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x637A, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x637B, .reg_data = 0xD4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6388, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x6389, .reg_data = 0x82, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x638A, .reg_data = 0xC8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x639D, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7BA0, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7BA9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7BAA, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x7BAD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9002, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9003, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9004, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9006, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9200, .reg_data = 0x93, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9201, .reg_data = 0x85, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9202, .reg_data = 0x93, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9203, .reg_data = 0x87, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9204, .reg_data = 0x93, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9205, .reg_data = 0x8D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9206, .reg_data = 0x93, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9207, .reg_data = 0x8F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9208, .reg_data = 0x6A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9209, .reg_data = 0x23, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x920A, .reg_data = 0x6A, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x920B, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x920C, .reg_data = 0x71, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x920D, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x920E, .reg_data = 0x71, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x920F, .reg_data = 0x0B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x935D, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9389, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x938B, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9391, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9393, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9395, .reg_data = 0x82, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9397, .reg_data = 0x78, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x9399, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x939B, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAA3F, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAA41, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAA43, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAA5D, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAA5F, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAA61, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAACF, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAAD1, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAAD3, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAAED, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAAEF, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xAAF1, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xB388, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xBC40, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xE0A5, .reg_data = 0x0B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xE0A6, .reg_data = 0x0B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x5617, .reg_data = 0x0A, .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 = 0x17, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0343, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0340, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0341, .reg_data = 0xE0, .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 = 0x4254, .reg_data = 0x7F, .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 = 0x14, .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 = 0x80, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0xBC41, .reg_data = 0x01, .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 = 0x80, .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 = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0306, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0307, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x030B, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x030D, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x030E, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x030F, .reg_data = 0xDA, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0310, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0820, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0821, .reg_data = 0x70, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0822, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0823, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3E20, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3E37, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3E3B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3614, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3616, .reg_data = 0x0E, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3617, .reg_data = 0x66, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0106, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0B00, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0B05, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0B06, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3230, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3602, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C00, .reg_data = 0x5B, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C01, .reg_data = 0x54, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C02, .reg_data = 0x77, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C03, .reg_data = 0x66, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C04, .reg_data = 0xC8, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C05, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C06, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3C07, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F14, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F17, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F3C, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F78, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F79, .reg_data = 0xB4, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F7C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x3F7D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0202, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, + {.reg_addr = 0x0203, .reg_data = 0xE8, .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 = 232, + .addr_type = CAMERA_SENSOR_I2C_TYPE_WORD, + .data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .delay = 1, +}, \ No newline at end of file diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/Makefile b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/Makefile new file mode 100644 index 000000000000..37cc8068b202 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/Makefile @@ -0,0 +1,10 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_core +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_cpas/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_req_mgr +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_utils +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_smmu/ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_utils + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_sensor_dev.o cam_sensor_core.o cam_sensor_soc.o diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/cam_sensor_core.c new file mode 100644 index 000000000000..a0aef5b9a6fa --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/cam_sensor_core.c @@ -0,0 +1,1455 @@ +/* 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. + */ + +#include +#include +#include "cam_sensor_core.h" +#include "cam_sensor_util.h" +#include "cam_soc_util.h" +#include "cam_trace.h" + +#include + +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[] = { + {0x519, "imx519", "Sony"}, + {0x376, "imx376k", "Sony"}, + {0x371, "imx371", "Sony"}, +}; + +static struct cam_sensor_i2c_reg_array lotid_on_setting[2] = { + { + .reg_addr = 0x0A02, + .reg_data = 0x27, + .delay = 0x01, + .data_mask = 0x00 + }, + { + .reg_addr = 0x0A00, + .reg_data = 0x01, + .delay = 0x01, + .data_mask = 0x00 + }, +}; + +static struct cam_sensor_i2c_reg_array lotid_off_setting = { + .reg_addr = 0x0A00, + .reg_data = 0x00, + .delay = 0x01, + .data_mask = 0x00 +}; + +static struct cam_sensor_i2c_reg_setting lotid_on = { + .reg_setting = lotid_on_setting, + .size = 2, + .addr_type = CAMERA_SENSOR_I2C_TYPE_WORD, + .data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .delay = 5, +}; + +static struct cam_sensor_i2c_reg_setting lotid_off = { + .reg_setting = &lotid_off_setting, + .size = 1, + .addr_type = CAMERA_SENSOR_I2C_TYPE_WORD, + .data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, + .delay = 5, +}; + +#define LOTID_START_ADDR 0x0A20 +#define LOTID_LENGTH 8 + +static char fuse_id[64] = {'\0'}; + +static int sensor_get_fuseid(struct cam_sensor_ctrl_t *s_ctrl) +{ + int rc = 0; + uint16_t lotid_addr = LOTID_START_ADDR; + struct cam_camera_slave_info *slave_info; + + int i = 0; + uint32_t check_reg_val = 0; + int retry_cnt = 5; + char str_tmp[6] = {'\0'}; + + slave_info = &(s_ctrl->sensordata->slave_info); + if (!slave_info) { + CAM_ERR(CAM_SENSOR, "slave_info is NULL: %pK", + slave_info); + return -EINVAL; + } + + rc = camera_io_dev_read( + &(s_ctrl->io_master_info), + 0x0A01, + &check_reg_val, CAMERA_SENSOR_I2C_TYPE_WORD, + CAMERA_SENSOR_I2C_TYPE_BYTE); + + //enable read lot id + rc = camera_io_dev_write( + &(s_ctrl->io_master_info), + &lotid_on); + + //verify lot id availability + for (i = 0; i < retry_cnt; i++) { + rc = camera_io_dev_read( + &(s_ctrl->io_master_info), + 0x0A01, + &check_reg_val, CAMERA_SENSOR_I2C_TYPE_WORD, + CAMERA_SENSOR_I2C_TYPE_BYTE); + if (check_reg_val & (0x1)) + break; + } + + if (i == retry_cnt) { + CAM_ERR(CAM_SENSOR, "lot id not available"); + return -EINVAL; + } + + //read lot id + for (i = 0; i < LOTID_LENGTH; i++) { + rc = camera_io_dev_read( + &(s_ctrl->io_master_info), + lotid_addr+i, + &check_reg_val, CAMERA_SENSOR_I2C_TYPE_WORD, + CAMERA_SENSOR_I2C_TYPE_BYTE); + snprintf(str_tmp, sizeof(str_tmp), "%02x", + (check_reg_val&0x00FF)); + strlcat(fuse_id, str_tmp, sizeof(fuse_id)); + } + + //disable read lot id + rc = camera_io_dev_write( + &(s_ctrl->io_master_info), + &lotid_off); + + return 0; +} + +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_resource( + struct cam_sensor_ctrl_t *s_ctrl) +{ + struct i2c_settings_array *i2c_set = NULL; + int i, rc; + + i2c_set = &(s_ctrl->i2c_data.init_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 Init settings"); + } + + i2c_set = &(s_ctrl->i2c_data.config_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 Res settings"); + } + + 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; + uint64_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; + 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, (void __user *) ioctl_ctrl->handle, + sizeof(config))) + return -EFAULT; + + rc = cam_mem_get_cpu_buf( + config.packet_handle, + (uint64_t *)&generic_ptr, + &len_of_buff); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "Failed in getting the buffer: %d", rc); + return rc; + } + + csl_packet = (struct cam_packet *)(generic_ptr + + config.offset); + if (config.offset > len_of_buff) { + CAM_ERR(CAM_SENSOR, + "offset is out of bounds: off: %lld len: %zu", + config.offset, len_of_buff); + return -EINVAL; + } + + 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) + return 0; + + 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) + return 0; + + 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"); + return 0; + } + + 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); + return 0; + } + 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"); + return 0; + } + + cam_sensor_update_req_mgr(s_ctrl, csl_packet); + return 0; + } + default: + CAM_ERR(CAM_SENSOR, "Invalid Packet Header"); + return -EINVAL; + } + + 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(i2c_reg_settings, cmd_desc, 1); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "Fail parsing I2C Pkt: %d", rc); + return rc; + } + + 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); + } + + 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; + + 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_id: 0x%x sensor_mask: 0x%x", + s_ctrl->sensordata->slave_info.sensor_id_reg_addr, + s_ctrl->sensordata->slave_info.sensor_id, + s_ctrl->sensordata->slave_info.sensor_id_mask); + 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, + "Sensor Addr: 0x%x sensor_id: 0x%x sensor_mask: 0x%x", + 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, int cmd_buf_length) +{ + int32_t rc = 0; + + switch (cmd_buf_num) { + case 0: { + struct cam_cmd_i2c_info *i2c_info = NULL; + struct cam_cmd_probe *probe_info; + + 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); + 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; + void *packet = NULL, *cmd_buf1 = NULL; + uint32_t *cmd_buf; + void *ptr; + size_t len; + struct cam_packet *pkt; + struct cam_cmd_buf_desc *cmd_desc; + + rc = cam_mem_get_cpu_buf(handle, + (uint64_t *)&packet, &len); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "Failed to get the command Buffer"); + return -EINVAL; + } + pkt = (struct cam_packet *)packet; + 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"); + return -EINVAL; + } + if (pkt->num_cmd_buf != 2) { + CAM_ERR(CAM_SENSOR, "Expected More Command Buffers : %d", + pkt->num_cmd_buf); + return -EINVAL; + } + 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, + (uint64_t *)&cmd_buf1, &len); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Failed to parse the command Buffer Header"); + return -EINVAL; + } + 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); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Failed to parse the command Buffer Header"); + return -EINVAL; + } + } + 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; + + s_ctrl->is_probe_succeed = 0; + if (s_ctrl->sensor_state == CAM_SENSOR_INIT) + return; + + CAM_INFO(CAM_SENSOR, "streamoff Sensor"); + rc = cam_sensor_apply_settings(s_ctrl, 0, + CAM_SENSOR_PACKET_OPCODE_SENSOR_STREAMOFF); + if (rc < 0) { + CAM_INFO(CAM_SENSOR, "non-fatal cannot apply streamoff settings"); + } + + cam_sensor_release_resource(s_ctrl); + cam_sensor_release_stream_rsc(s_ctrl); + if (s_ctrl->sensor_state >= CAM_SENSOR_ACQUIRE) + cam_sensor_power_down(s_ctrl); + + rc = cam_destroy_device_hdl(s_ctrl->bridge_intf.device_hdl); + if (rc < 0) + CAM_ERR(CAM_SENSOR, " failed destroying dhdl"); + 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); + + s_ctrl->streamon_count = 0; + s_ctrl->streamoff_count = 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 sensor_version = 0; + uint16_t sensor_version_reg = 0x0018; + uint16_t sensor_slave_addr = 0; + uint32_t id = 0; + uint32_t id_l = 0; + uint32_t id_h = 0; + struct cam_camera_slave_info *slave_info; + + slave_info = &(s_ctrl->sensordata->slave_info); + + if (!slave_info) { + CAM_ERR(CAM_SENSOR, " failed: %pK", + slave_info); + return -EINVAL; + } + + if (((s_ctrl->sensordata->id_info.sensor_id_reg_addr & 0xFFFF) != 0) && ((s_ctrl->sensordata->id_info.sensor_id_reg_addr >> 16) != 0)) { + sensor_slave_addr = 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; + rc = camera_io_dev_read( + &(s_ctrl->io_master_info), + s_ctrl->sensordata->id_info.sensor_id_reg_addr & 0xFFFF, + &id_l, s_ctrl->sensordata->id_info.sensor_addr_type, + s_ctrl->sensordata->id_info.sensor_data_type); + rc = camera_io_dev_read( + &(s_ctrl->io_master_info), + s_ctrl->sensordata->id_info.sensor_id_reg_addr >> 16, + &id_h, s_ctrl->sensordata->id_info.sensor_addr_type, + s_ctrl->sensordata->id_info.sensor_data_type); + s_ctrl->io_master_info.cci_client->sid = sensor_slave_addr; + id = (id_h << 8) | id_l; + if (s_ctrl->sensordata->id_info.sensor_id != id) { + CAM_ERR(CAM_SENSOR, "sensor id 0x%x does not match 0x%x", id, s_ctrl->sensordata->id_info.sensor_id); + return -ENODEV; + } else { + CAM_ERR(CAM_SENSOR, "sensor id 0x%x matched", id); + } + } else { + CAM_ERR(CAM_SENSOR, "sensor id register is 0x%x", s_ctrl->sensordata->id_info.sensor_id_reg_addr); + } + + rc = camera_io_dev_read( + &(s_ctrl->io_master_info), + slave_info->sensor_id_reg_addr, + &chipid, CAMERA_SENSOR_I2C_TYPE_WORD, + CAMERA_SENSOR_I2C_TYPE_WORD); + + CAM_DBG(CAM_SENSOR, "read id: 0x%x expected id 0x%x:", + chipid, slave_info->sensor_id); + + if (chipid == 0x519) { + rc = camera_io_dev_read( + &(s_ctrl->io_master_info), + sensor_version_reg, + &sensor_version, CAMERA_SENSOR_I2C_TYPE_WORD, + CAMERA_SENSOR_I2C_TYPE_WORD); + + CAM_INFO(CAM_SENSOR, "imx519 sensor_version: 0x%x", + sensor_version >> 8); + } + + if (cam_sensor_id_by_mask(s_ctrl, chipid) != slave_info->sensor_id) { + CAM_ERR(CAM_SENSOR, "chip id %x does not match %x", + chipid, slave_info->sensor_id); + return -ENODEV; + } + if (slave_info->sensor_id == 0x519 && fuse_id[0] == '\0') { + sensor_get_fuseid(s_ctrl); + CAM_ERR(CAM_SENSOR, + "sensor_id: 0x%x, fuse_id:%s", + slave_info->sensor_id, fuse_id); + } + 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_setting *pu = NULL; + struct cam_sensor_power_setting *pd = NULL; + struct cam_sensor_power_ctrl_t *power_info = + &s_ctrl->sensordata->power_info; + uint32_t count = 0, i; + enum COMPONENT_TYPE CameraID; + + 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; + } + /* Allocate memory for power up setting */ + pu = kzalloc(sizeof(struct cam_sensor_power_setting) * + MAX_POWER_CONFIG, GFP_KERNEL); + if (!pu) { + rc = -ENOMEM; + goto release_mutex; + } + + pd = kzalloc(sizeof(struct cam_sensor_power_setting) * + MAX_POWER_CONFIG, GFP_KERNEL); + if (!pd) { + kfree(pu); + rc = -ENOMEM; + goto release_mutex; + } + + power_info->power_setting = pu; + power_info->power_down_setting = pd; + + 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"); + kfree(pu); + kfree(pd); + goto release_mutex; + } + } else { + CAM_ERR(CAM_SENSOR, "Invalid Command Type: %d", + cmd->handle_type); + return -EINVAL; + } + + /* 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); + kfree(pu); + kfree(pd); + goto release_mutex; + } + + /* 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); + kfree(pu); + kfree(pd); + goto release_mutex; + } + + /* Power up and probe sensor */ + rc = cam_sensor_power_up(s_ctrl); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "power up failed"); + kfree(pu); + kfree(pd); + goto release_mutex; + } + + /* Match sensor ID */ + rc = cam_sensor_match_id(s_ctrl); + if (rc < 0) { + cam_sensor_power_down(s_ctrl); + msleep(20); + kfree(pu); + kfree(pd); + goto release_mutex; + } + + CAM_INFO(CAM_SENSOR, + "Probe Succees,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"); + kfree(pu); + kfree(pd); + goto release_mutex; + } + /* + * 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; + + 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 + CameraID = -1; + + 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); + else + push_component_info(CameraID, match_tbl[i].sensor_name, + match_tbl[i].vendor_name); + + } + break; + case CAM_ACQUIRE_DEV: { + struct cam_sensor_acquire_dev sensor_acq_dev; + struct cam_create_dev_hdl bridge_params; + + 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, + (void __user *) 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((void __user *) 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; + CAM_INFO(CAM_SENSOR, + "CAM_ACQUIRE_DEV Success, sensor_id:0x%x", + s_ctrl->sensordata->slave_info.sensor_id); + } + break; + case CAM_RELEASE_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 release : %d", + s_ctrl->sensor_state); + 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_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", + s_ctrl->sensordata->slave_info.sensor_id); + s_ctrl->streamon_count = 0; + s_ctrl->streamoff_count = 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((void __user *) 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", + s_ctrl->sensordata->slave_info.sensor_id); + } + 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_resource(s_ctrl); + s_ctrl->sensor_state = CAM_SENSOR_ACQUIRE; + CAM_INFO(CAM_SENSOR, + "CAM_STOP_DEV Success, sensor_id:0x%x", + s_ctrl->sensordata->slave_info.sensor_id); + } + break; + case CAM_CONFIG_DEV: { + rc = cam_sensor_i2c_pkt_parse(s_ctrl, arg); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "Failed CCI Config: %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 < 0) { + CAM_ERR(CAM_SENSOR, + "cannot apply 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; + } + s_ctrl->i2c_data.init_settings.request_id = -1; + } + + 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); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "cannot apply 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; + s_ctrl->i2c_data.config_settings.request_id = -1; + } + } + break; + case CAM_GET_FUSE_ID: { + CAM_ERR(CAM_SENSOR, "fuse_id:%s", fuse_id); + if (fuse_id[0] == '\0') { + CAM_ERR(CAM_SENSOR, "fuse_id is empty"); + rc = -EFAULT; + goto release_mutex; + } else if (copy_to_user((void __user *) cmd->handle, &fuse_id, + sizeof(fuse_id))) { + CAM_ERR(CAM_SENSOR, "Failed Copy to User"); + rc = -EFAULT; + goto release_mutex; + } + 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; +} + +int cam_sensor_publish_dev_info(struct cam_req_mgr_device_info *info) +{ + int rc = 0; + + if (!info) + return -EINVAL; + + info->dev_id = CAM_REQ_MGR_DEVICE_SENSOR; + strlcpy(info->name, CAM_SENSOR_NAME, sizeof(info->name)); + 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; + } + 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; + } + + 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; + } + + 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 = msm_camera_power_down(power_info, soc_info); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "power down the core is failed:%d", rc); + return rc; + } + + camera_io_release(&(s_ctrl->io_master_info)); + + return rc; +} + +int cam_sensor_apply_settings(struct cam_sensor_ctrl_t *s_ctrl, + int64_t req_id, enum cam_sensor_packet_opcodes opcode) +{ + int rc = 0, offset, i; + uint64_t top = 0, del_req_id = 0; + struct i2c_settings_array *i2c_set = NULL; + struct i2c_settings_list *i2c_list; + + if (req_id == 0) { + switch (opcode) { + case CAM_SENSOR_PACKET_OPCODE_SENSOR_STREAMON: { + i2c_set = &s_ctrl->i2c_data.streamon_settings; + break; + } + case CAM_SENSOR_PACKET_OPCODE_SENSOR_INITIAL_CONFIG: { + i2c_set = &s_ctrl->i2c_data.init_settings; + break; + } + case CAM_SENSOR_PACKET_OPCODE_SENSOR_CONFIG: { + i2c_set = &s_ctrl->i2c_data.config_settings; + break; + } + case CAM_SENSOR_PACKET_OPCODE_SENSOR_STREAMOFF: { + i2c_set = &s_ctrl->i2c_data.streamoff_settings; + break; + } + case CAM_SENSOR_PACKET_OPCODE_SENSOR_UPDATE: + case CAM_SENSOR_PACKET_OPCODE_SENSOR_PROBE: + default: + return 0; + } + if (i2c_set->is_settings_valid == 1) { + list_for_each_entry(i2c_list, + &(i2c_set->list_head), list) { + rc = cam_sensor_i2c_modes_util( + &(s_ctrl->io_master_info), + i2c_list); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Failed to apply settings: %d", + rc); + return rc; + } + } + } + } else { + offset = req_id % MAX_PER_FRAME_ARRAY; + i2c_set = &(s_ctrl->i2c_data.per_frame[offset]); + if (i2c_set->is_settings_valid == 1 && + i2c_set->request_id == req_id) { + list_for_each_entry(i2c_list, + &(i2c_set->list_head), list) { + rc = cam_sensor_i2c_modes_util( + &(s_ctrl->io_master_info), + i2c_list); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "Failed to apply settings: %d", + rc); + return rc; + } + } + } else { + CAM_DBG(CAM_SENSOR, + "Invalid/NOP request to apply: %lld", req_id); + } + + /* Change the logic dynamically */ + for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) { + if ((req_id >= + s_ctrl->i2c_data.per_frame[i].request_id) && + (top < + s_ctrl->i2c_data.per_frame[i].request_id) && + (s_ctrl->i2c_data.per_frame[i]. + is_settings_valid == 1)) { + del_req_id = top; + top = s_ctrl->i2c_data.per_frame[i].request_id; + } + } + + if (top < req_id) { + if ((((top % MAX_PER_FRAME_ARRAY) - (req_id % + MAX_PER_FRAME_ARRAY)) >= BATCH_SIZE_MAX) || + (((top % MAX_PER_FRAME_ARRAY) - (req_id % + MAX_PER_FRAME_ARRAY)) <= -BATCH_SIZE_MAX)) + del_req_id = req_id; + } + + if (!del_req_id) + return rc; + + CAM_DBG(CAM_SENSOR, "top: %llu, del_req_id:%llu", + top, del_req_id); + + for (i = 0; i < MAX_PER_FRAME_ARRAY; i++) { + if ((del_req_id > + s_ctrl->i2c_data.per_frame[i].request_id) && + (s_ctrl->i2c_data.per_frame[i]. + is_settings_valid == 1)) { + s_ctrl->i2c_data.per_frame[i].request_id = 0; + rc = delete_request( + &(s_ctrl->i2c_data.per_frame[i])); + if (rc < 0) + CAM_ERR(CAM_SENSOR, + "Delete request Fail:%lld rc:%d", + del_req_id, rc); + } + } + } + + return rc; +} + +int32_t cam_sensor_apply_request(struct cam_req_mgr_apply_request *apply) +{ + int32_t rc = 0; + struct cam_sensor_ctrl_t *s_ctrl = NULL; + + if (!apply) + return -EINVAL; + + s_ctrl = (struct cam_sensor_ctrl_t *) + cam_get_device_priv(apply->dev_hdl); + if (!s_ctrl) { + CAM_ERR(CAM_SENSOR, "Device data is NULL"); + return -EINVAL; + } + CAM_DBG(CAM_SENSOR, " Req Id: %lld", apply->request_id); + trace_cam_apply_req("Sensor", apply->request_id); + rc = cam_sensor_apply_settings(s_ctrl, apply->request_id, + CAM_SENSOR_PACKET_OPCODE_SENSOR_UPDATE); + 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; + } + + /* PATCH, add by xcb */ + if (s_ctrl->i2c_data.per_frame == NULL) { + CAM_ERR(CAM_SENSOR, "i2c frame data is NULL"); + return -EINVAL; + } + + + 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); + return rc; +} diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/cam_sensor_core.h b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/cam_sensor_core.h new file mode 100644 index 000000000000..45701794be4a --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/cam_sensor_core.h @@ -0,0 +1,93 @@ +/* Copyright (c) 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. + */ + +#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/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/cam_sensor_dev.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/cam_sensor_dev.c new file mode 100644 index 000000000000..7e79d1a597f4 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/cam_sensor_dev.c @@ -0,0 +1,445 @@ +/* Copyright (c) 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. + */ + +#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[512]; + 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 imx519_setting; + struct cam_sensor_i2c_reg_setting_array imx376k_setting; + struct cam_sensor_i2c_reg_setting_array imx371_setting; +}; + +struct cam_sensor_settings sensor_settings = { +#include "CAM_SENSOR_SETTINGS.h" +}; + +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); + struct cam_sensor_i2c_reg_setting sensor_setting; + + switch (cmd) { + case VIDIOC_CAM_CONTROL: + rc = cam_sensor_driver_cmd(s_ctrl, arg); + break; + case VIDIOC_CAM_FTM_POWNER_DOWN: + CAM_INFO(CAM_SENSOR, "FTM power down"); + return cam_sensor_power_down(s_ctrl); + break; + case VIDIOC_CAM_FTM_POWNER_UP: + CAM_INFO(CAM_SENSOR, "FTM power up, sensor id 0x%x", s_ctrl->sensordata->slave_info.sensor_id); + rc = cam_sensor_power_up(s_ctrl); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "ftm power up failed!"); + break; + } + + if (s_ctrl->sensordata->slave_info.sensor_id == 0x519) { + sensor_setting.reg_setting = sensor_settings.imx519_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.imx519_setting.size; + sensor_setting.delay = sensor_settings.imx519_setting.delay; + } else if(s_ctrl->sensordata->slave_info.sensor_id == 0x376) { + sensor_setting.reg_setting = sensor_settings.imx376k_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.imx376k_setting.size; + sensor_setting.delay = sensor_settings.imx376k_setting.delay; + } else if(s_ctrl->sensordata->slave_info.sensor_id == 0x371) { + sensor_setting.reg_setting = sensor_settings.imx371_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.imx371_setting.size; + sensor_setting.delay = sensor_settings.imx371_setting.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"); + } 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; +} + +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)); + 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; + + 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 = + (struct i2c_settings_array *) + 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.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; + v4l2_set_subdevdata(&(s_ctrl->v4l2_dev_str.sd), s_ctrl); + 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; + } + + 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); + 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; + } + + 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); + 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; + + /*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 = + (struct i2c_settings_array *) + 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.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); + v4l2_set_subdevdata(&(s_ctrl->v4l2_dev_str.sd), 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, + }, + .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/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/cam_sensor_dev.h b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/cam_sensor_dev.h new file mode 100644 index 000000000000..cc6070cdc1b6 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/cam_sensor_dev.h @@ -0,0 +1,118 @@ +/* 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_SENSOR_DEV_H_ +#define _CAM_SENSOR_DEV_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cam_debug_util.h" + +#define NUM_MASTERS 2 +#define NUM_QUEUES 2 + +#define TRUE 1 +#define FALSE 0 + +#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 + * @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 + * @device_name: Sensor device 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 + */ +struct cam_sensor_ctrl_t { + 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; + 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; + char device_name[20]; + uint32_t streamon_count; + uint32_t streamoff_count; +}; + +#endif /* _CAM_SENSOR_DEV_H_ */ diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/cam_sensor_soc.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/cam_sensor_soc.c new file mode 100644 index 000000000000..1c3ead0c25bf --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/cam_sensor_soc.c @@ -0,0 +1,252 @@ +/* Copyright (c) 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. + */ + +#include +#include +#include +#include +#include +#include +#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; + struct cam_sensor_board_info *sensordata = NULL; + struct device_node *of_node = s_ctrl->of_node; + 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; + } + + /* 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; + } + } + + 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; + + } 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/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/cam_sensor_soc.h b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/cam_sensor_soc.h new file mode 100644 index 000000000000..7f4a551d997f --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/cam_sensor_soc.h @@ -0,0 +1,25 @@ +/* Copyright (c) 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. + */ + +#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/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io/Makefile b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io/Makefile new file mode 100644 index 000000000000..9726654c4db2 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io/Makefile @@ -0,0 +1,9 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_utils +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_cpas/include +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_utils +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_req_mgr +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/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/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c new file mode 100644 index 000000000000..2c1f5204f4cc --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c @@ -0,0 +1,235 @@ +/* Copyright (c) 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. + */ + +#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[data_type]; + 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 = 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, + 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) + || (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 = 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/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io/cam_sensor_i2c.h b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io/cam_sensor_i2c.h new file mode 100644 index 000000000000..7cddcf9338b0 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io/cam_sensor_i2c.h @@ -0,0 +1,180 @@ +/* Copyright (c) 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. + */ + +#ifndef _CAM_SENSOR_I2C_H_ +#define _CAM_SENSOR_I2C_H_ + +#include +#include +#include +#include +#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 + * @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, + 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/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io/cam_sensor_io.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io/cam_sensor_io.c new file mode 100644 index 000000000000..89aad4e7aa15 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io/cam_sensor_io.c @@ -0,0 +1,194 @@ +/* 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. + */ + +#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_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, 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, 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 { + 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(); + 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; + } else { + CAM_ERR(CAM_SENSOR, "Invalid Comm. Master:%d", + io_master_info->master_type); + 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; + } else { + CAM_ERR(CAM_SENSOR, "Invalid Comm. Master:%d", + io_master_info->master_type); + return -EINVAL; + } +} diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io/cam_sensor_io.h b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io/cam_sensor_io.h new file mode 100644 index 000000000000..ec5ed25c0785 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io/cam_sensor_io.h @@ -0,0 +1,119 @@ +/* Copyright (c) 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. + */ + +#ifndef _CAM_SENSOR_IO_H_ +#define _CAM_SENSOR_IO_H_ + +#include + +#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 + * @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, + 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); + +/** + * @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/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io/cam_sensor_qup_i2c.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io/cam_sensor_qup_i2c.c new file mode 100644 index 000000000000..1c6ab0b1d94b --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io/cam_sensor_qup_i2c.c @@ -0,0 +1,526 @@ +/* Copyright (c) 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. + */ + +#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[I2C_REG_MAX_BUF_SIZE]; + uint8_t len = 0; + + 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"); + return -EINVAL; + } + + 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"); + return -EINVAL; + } + + rc = cam_qup_i2c_txdata(client, buf, len); + if (rc < 0) + CAM_ERR(CAM_SENSOR, "failed rc: %d", rc); + 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/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io/cam_sensor_spi.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io/cam_sensor_spi.c new file mode 100644 index 000000000000..626b2630a3e5 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io/cam_sensor_spi.c @@ -0,0 +1,617 @@ +/* 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. + */ + +#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 , 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); + 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); + 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; + } + + 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) +{ + 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/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io/cam_sensor_spi.h b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io/cam_sensor_spi.h new file mode 100644 index 000000000000..8ce45d8e9a4e --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io/cam_sensor_spi.h @@ -0,0 +1,112 @@ +/* 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_SENSOR_SPI_H_ +#define _CAM_SENSOR_SPI_H_ + +#include +#include +#include +#include +#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); + +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); + +#endif diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_utils/Makefile b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_utils/Makefile new file mode 100644 index 000000000000..def8d6944cc5 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_utils/Makefile @@ -0,0 +1,8 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_req_mgr +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_utils +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_res_mgr +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_smmu/ + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_sensor_util.o diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h new file mode 100644 index 000000000000..1047a170ab68 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_utils/cam_sensor_cmn_header.h @@ -0,0 +1,394 @@ +/* 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_SENSOR_CMN_HEADER_ +#define _CAM_SENSOR_CMN_HEADER_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +}; + +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 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 { + uint16_t first_word; + uint8_t third_byte; + uint8_t cmd_type; +}; + +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; + unsigned short size; + enum camera_sensor_i2c_type addr_type; + enum camera_sensor_i2c_type data_type; + unsigned short delay; +}; + +struct i2c_settings_list { + struct cam_sensor_i2c_reg_setting i2c_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; +}; + +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, + 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/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c new file mode 100644 index 000000000000..a0128ab0d141 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c @@ -0,0 +1,1754 @@ +/* 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. + */ + +#include +#include +#include "cam_sensor_util.h" +#include +#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 = (struct i2c_settings_list *) + kzalloc(sizeof(struct i2c_settings_list), GFP_KERNEL); + + if (tmp != NULL) + list_add_tail(&(tmp->list), + &(i2c_reg_settings->list_head)); + else + return NULL; + + if ((sizeof(struct cam_sensor_i2c_reg_array) * size) < PAGE_SIZE) { + tmp->i2c_settings.reg_setting = + (struct cam_sensor_i2c_reg_array *) + kzalloc(sizeof(struct cam_sensor_i2c_reg_array) * + size, GFP_KERNEL); + if (tmp->i2c_settings.reg_setting == NULL) { + list_del(&(tmp->list)); + kfree(tmp); + return NULL; + } + } else { + tmp->i2c_settings.reg_setting = + (struct cam_sensor_i2c_reg_array *) + vzalloc(sizeof(struct cam_sensor_i2c_reg_array) * + size); + 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) { + + if ((sizeof(struct cam_sensor_i2c_reg_array) * + i2c_list->i2c_settings.size) < PAGE_SIZE) { + kfree(i2c_list->i2c_settings.reg_setting); + } else { + 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; + } + (*offset) = 0;//add by HHK fox fix delayus invalid + 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, + uint16_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; + (*offset) = 0;//add by HHK fox fix delayus invalid + 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, + uint16_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; + (*offset) = 0;//add by HHK fox fix delayus invalid + 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; +} + +/** + * 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 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; + uint64_t generic_ptr; + + 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, + (uint64_t *)&generic_ptr, &len_of_buff); + cmd_buf = (uint32_t *)generic_ptr; + if (rc < 0) { + CAM_ERR(CAM_SENSOR, + "cmd hdl failed:%d, Err: %d, Buffer_len: %ld", + cmd_desc[i].mem_handle, rc, len_of_buff); + return rc; + } + cmd_buf += cmd_desc[i].offset / sizeof(uint32_t); + + while (byte_cnt < cmd_desc[i].length) { + cmm_hdr = (struct common_header *)cmd_buf; + generic_op_code = cmm_hdr->third_byte; + switch (cmm_hdr->cmd_type) { + case CAMERA_SENSOR_CMD_TYPE_I2C_RNDM_WR: { + uint16_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; + + 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); + return rc; + } + + cmd_buf += cmd_length_in_bytes / + sizeof(uint32_t); + byte_cnt += cmd_length_in_bytes; + break; + } + case CAMERA_SENSOR_CMD_TYPE_I2C_CONT_WR: { + uint16_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; + + 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); + return rc; + } + + cmd_buf += cmd_length_in_bytes / + sizeof(uint32_t); + byte_cnt += cmd_length_in_bytes; + 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) { + + 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); + return rc; + } + + } 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); + return rc; + } + } else { + CAM_ERR(CAM_SENSOR, + "Wrong Wait Command: %d", + generic_op_code); + return -EINVAL; + } + break; + } + default: + CAM_ERR(CAM_SENSOR, "Invalid Command Type:%d", + cmm_hdr->cmd_type); + return -EINVAL; + } + } + i2c_reg_settings->is_settings_valid = 1; + } + + 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; +} + +int32_t cam_sensor_update_power_settings(void *cmd_buf, + int cmd_length, struct cam_sensor_power_ctrl_t *power_info) +{ + int32_t rc = 0, tot_size = 0, last_cmd_type = 0; + int32_t i = 0, pwr_up = 0, pwr_down = 0; + 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) { + 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 = + (struct cam_sensor_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 = + (struct cam_sensor_power_setting *) + kzalloc(sizeof(struct cam_sensor_power_setting) * + MAX_POWER_CONFIG, GFP_KERNEL); + if (!power_info->power_down_setting) { + rc = -ENOMEM; + goto free_power_settings; + } + + while (tot_size < cmd_length) { + if (cmm_hdr->cmd_type == + CAMERA_SENSOR_CMD_TYPE_PWR_UP) { + struct cam_cmd_power *pwr_cmd = + (struct cam_cmd_power *)ptr; + + power_info->power_setting_size += pwr_cmd->count; + 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, "Un expected Command"); + + 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_down_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) { + if (last_cmd_type == + CAMERA_SENSOR_CMD_TYPE_PWR_UP) { + if (pwr_up > 0) + power_info-> + power_setting + [pwr_up - 1].delay += + wait_cmd->delay; + else + CAM_ERR(CAM_SENSOR, + "Delay is expected only after valid power up setting"); + } else if (last_cmd_type == + CAMERA_SENSOR_CMD_TYPE_PWR_DOWN) { + if (pwr_down > 0) + power_info-> + power_down_setting + [pwr_down - 1].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"); + rc = -EINVAL; + goto free_power_down_settings; + } + 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); + power_info->power_down_setting_size += pwr_cmd->count; + + if (pwr_cmd->count == 0) + CAM_ERR(CAM_SENSOR, "Invalid Command"); + + for (i = 0; i < pwr_cmd->count; i++, pwr_down++) { + power_info-> + power_down_setting[pwr_down]. + seq_type = + pwr_cmd->power_settings[i]. + power_seq_type; + power_info-> + power_down_setting[pwr_down]. + 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_down_settings; + } + CAM_DBG(CAM_SENSOR, + "Seq Type[%d]: %d Config_val: %ld", + pwr_down, + power_info-> + power_down_setting[pwr_down]. + seq_type, + power_info-> + power_down_setting[pwr_down]. + 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); + } + } + + return rc; +free_power_down_settings: + kfree(power_info->power_down_setting); +free_power_settings: + kfree(power_info->power_setting); + 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 = + kzalloc(sizeof(*ps) * count, 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 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; +} + +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; + 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]; + 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; + } + + 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]); + + 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"); + return no_gpio; + } + 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; + } + + 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]); + + 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_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]); + + 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"); + cam_res_mgr_shared_pinctrl_select_state(false); + pinctrl_put(ctrl->pinctrl_info.pinctrl); + cam_res_mgr_shared_pinctrl_put(); + } + + if (soc_info->use_shared_clk) + cam_res_mgr_shared_clk_config(false); + + 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; +} + +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 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]); + + ps->data[0] = + soc_info->rgltr[j]; + + regulator_put( + soc_info->rgltr[j]); + soc_info->rgltr[j] = NULL; + } + } + } + + return rc; +} + +int msm_camera_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; + 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; + } + + for (index = 0; index < ctrl->power_down_setting_size; index++) { + CAM_DBG(CAM_SENSOR, "index %d", index); + pd = &ctrl->power_down_setting[index]; + ps = NULL; + CAM_DBG(CAM_SENSOR, "type %d", pd->seq_type); + switch (pd->seq_type) { + case SENSOR_MCLK: + ret = cam_config_mclk_reg(ctrl, soc_info, index); + if (ret < 0) { + CAM_ERR(CAM_SENSOR, + "config clk reg failed rc: %d", ret); + return ret; + } + //cam_soc_util_clk_disable_default(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]); + } + + 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]); + + 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"); + + cam_res_mgr_shared_pinctrl_select_state(false); + pinctrl_put(ctrl->pinctrl_info.pinctrl); + cam_res_mgr_shared_pinctrl_put(); + } + + if (soc_info->use_shared_clk) + cam_res_mgr_shared_clk_config(false); + + ctrl->cam_pinctrl_status = 0; + + cam_sensor_util_request_gpio_table(soc_info, 0); + + return 0; +} + diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_utils/cam_sensor_util.h b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_utils/cam_sensor_util.h new file mode 100644 index 000000000000..d2079b0a7bd5 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_utils/cam_sensor_util.h @@ -0,0 +1,59 @@ +/* Copyright (c) 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. + */ + +#ifndef _CAM_SENSOR_UTIL_H_ +#define _CAM_SENSOR_UTIL_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cam_soc_util.h" +#include "cam_debug_util.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 i2c_settings_array *i2c_reg_settings, + struct cam_cmd_buf_desc *cmd_desc, int32_t num_cmd_buffers); + +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 msm_camera_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, + int cmd_length, struct cam_sensor_power_ctrl_t *power_info); +#endif /* _CAM_SENSOR_UTIL_H_ */ diff --git a/drivers/media/platform/msm/camera_oneplus/cam_smmu/Makefile b/drivers/media/platform/msm/camera_oneplus/cam_smmu/Makefile new file mode 100644 index 000000000000..cc0d20d44e1f --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_smmu/Makefile @@ -0,0 +1,3 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_utils + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_smmu_api.o diff --git a/drivers/media/platform/msm/camera_oneplus/cam_smmu/cam_smmu_api.c b/drivers/media/platform/msm/camera_oneplus/cam_smmu/cam_smmu_api.c new file mode 100644 index 000000000000..ecfc5665085b --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_smmu/cam_smmu_api.c @@ -0,0 +1,3412 @@ +/* Copyright (c) 2014-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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cam_smmu_api.h" +#include "cam_debug_util.h" + +#define SHARED_MEM_POOL_GRANULARITY 12 + +#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) & COOKIE_MASK) + +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 dma_iommu_mapping *mapping; + 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; + + void (*handler[CAM_SMMU_CB_MAX])(struct iommu_domain *, + struct device *, unsigned long, + int, void*); + void *token[CAM_SMMU_CB_MAX]; + int cb_count; + int secure_count; +}; + +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; + u32 enable_iova_guard; +}; + +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 ion_handle *i_hdl; + struct ion_client *i_client; + 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, + 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_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 void cam_smmu_check_vaddr_in_range(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; + + 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; + mutex_lock(&iommu_cb_set.cb_info[idx].lock); + cam_smmu_check_vaddr_in_range(idx, (void *)payload->iova); + 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]); + } + } + mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + kfree(payload); +} + +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 void cam_smmu_check_vaddr_in_range(int idx, void *vaddr) +{ + struct cam_dma_buff_info *mapping; + unsigned long start_addr, end_addr, current_addr; + + 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) { + CAM_ERR(CAM_SMMU, + "va %pK valid: range:%pK-%pK, fd = %d cb: %s", + vaddr, (void *)start_addr, (void *)end_addr, + mapping->ion_fd, + iommu_cb_set.cb_info[idx].name); + goto end; + } else { + CAM_DBG(CAM_SMMU, + "va %pK is not in this range: %pK-%pK, fd = %d", + vaddr, (void *)start_addr, (void *)end_addr, + mapping->ion_fd); + } + } + CAM_ERR(CAM_SMMU, + "Cannot find vaddr:%pK in SMMU %s uses invalid virt address", + vaddr, iommu_cb_set.cb_info[idx].name); +end: + return; +} + +void cam_smmu_reg_client_page_fault_handler(int handle, + void (*client_page_fault_handler)(struct iommu_domain *, + struct device *, unsigned long, + int, void*), 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 (client_page_fault_handler) { + 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] = + client_page_fault_handler; + 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); +} + +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; + } + + 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); + + schedule_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; + 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 = arm_iommu_attach_device(cb->dev, cb->mapping); + 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) { + CAM_ERR(CAM_SMMU, + "Error: %s already got handle 0x%x", + name, + iommu_cb_set.cb_info[i].handle); + + 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; + } + 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) { + arm_iommu_detach_device(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, + uint64_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].mapping->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 = (uint64_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].mapping->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].mapping->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].mapping->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_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].mapping->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].mapping->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, + 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; + } + + table = dma_buf_map_attachment(attach, dma_dir); + if (IS_ERR_OR_NULL(table)) { + rc = PTR_ERR(table); + CAM_ERR(CAM_SMMU, "Error: dma buf map attachment failed"); + goto err_detach; + } + + if (region_id == CAM_SMMU_REGION_SHARED) { + domain = iommu_cb_set.cb_info[idx].mapping->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"); + 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 %zu", size); + *paddr_ptr = iova; + *len_ptr = size; + } + } else if (region_id == CAM_SMMU_REGION_IO) { + rc = msm_dma_map_sg_lazy(iommu_cb_set.cb_info[idx].dev, + table->sgl, table->nents, dma_dir, buf); + + if (rc != table->nents) { + CAM_ERR(CAM_SMMU, "Error: msm_dma_map_sg_lazy failed"); + rc = -ENOMEM; + goto err_unmap_sg; + } else { + *paddr_ptr = sg_dma_address(table->sgl); + *len_ptr = (size_t)sg_dma_len(table->sgl); + } + } else { + CAM_ERR(CAM_SMMU, "Error: Wrong region id passed"); + rc = -EINVAL; + goto err_unmap_sg; + } + + 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); + rc = -ENOSPC; + goto err_alloc; + } + CAM_DBG(CAM_SMMU, "dma_buf = %pK, dev = %pK, paddr= %pK, len = %u", + 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].mapping->domain, + *paddr_ptr, + *len_ptr); + } else if (region_id == CAM_SMMU_REGION_IO) { + msm_dma_unmap_sg(iommu_cb_set.cb_info[idx].dev, + table->sgl, + table->nents, + dma_dir, + buf); + } +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, + 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, &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, &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; + } + + 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].mapping->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"); + + } else if (mapping_info->region_id == CAM_SMMU_REGION_IO) { + msm_dma_unmap_sg(iommu_cb_set.cb_info[idx].dev, + mapping_info->table->sgl, mapping_info->table->nents, + mapping_info->dir, mapping_info->buf); + } + + 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; + 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].mapping->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].mapping->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, struct ion_client *client, + dma_addr_t *paddr_ptr, + size_t *len_ptr) +{ + int rc = 0; + struct ion_handle *i_handle = NULL; + struct cam_sec_buff_info *mapping_info; + + /* clean the content from clients */ + *paddr_ptr = (dma_addr_t)NULL; + *len_ptr = (size_t)0; + + i_handle = ion_import_dma_buf_fd(client, ion_fd); + if (IS_ERR_OR_NULL((void *)(i_handle))) { + CAM_ERR(CAM_SMMU, "ion import dma buffer failed"); + return -EINVAL; + } + + /* return addr and len to client */ + rc = ion_phys(client, i_handle, paddr_ptr, len_ptr); + if (rc) { + CAM_ERR(CAM_SMMU, "ION Get Physical failed, rc: %d", + rc); + return rc; + } + + /* fill up mapping_info */ + mapping_info = kzalloc(sizeof(struct cam_sec_buff_info), GFP_KERNEL); + if (!mapping_info) + return -ENOMEM; + + 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->i_hdl = i_handle; + mapping_info->i_client = client; + + CAM_DBG(CAM_SMMU, "ion_fd = %d, dev = %pK, paddr= %pK, len = %u", + 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 rc; +} + +int cam_smmu_map_stage2_iova(int handle, + int ion_fd, enum cam_smmu_map_dir dir, + struct ion_client *client, ion_phys_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"); + 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_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, give same addr back", + ion_fd); + rc = 0; + goto get_addr_end; + } + rc = cam_smmu_map_stage2_buffer_and_add_to_list(idx, ion_fd, dma_dir, + client, paddr_ptr, len_ptr); + if (rc < 0) { + CAM_ERR(CAM_SMMU, "Error: mapping or add list fail"); + 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; + } + ion_free(mapping_info->i_client, mapping_info->i_hdl); + 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; + } + + /* 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, + 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_fd_in_list(idx, ion_fd, paddr_ptr, len_ptr); + if (buf_state == CAM_SMMU_BUFF_EXIST) { + CAM_ERR(CAM_SMMU, + "ion_fd: %d already in the list", ion_fd); + rc = -EALREADY; + goto get_addr_end; + } + + rc = cam_smmu_map_buffer_and_add_to_list(idx, ion_fd, 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_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_check_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) +{ + arm_iommu_detach_device(cb->dev); + + if (cb->io_support && cb->mapping) { + arm_iommu_release_mapping(cb->mapping); + cb->mapping = 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 4K 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->mapping = arm_iommu_create_mapping(&platform_bus_type, + cb->io_info.iova_start, cb->io_info.iova_len); + if (IS_ERR(cb->mapping)) { + CAM_ERR(CAM_SMMU, "Error: create mapping Failed"); + rc = -ENODEV; + goto end; + } + + iommu_cb_set.non_fatal_fault = 1; + if (iommu_domain_set_attr(cb->mapping->domain, + DOMAIN_ATTR_NON_FATAL_FAULTS, + &iommu_cb_set.non_fatal_fault) < 0) { + CAM_ERR(CAM_SMMU, + "Error: failed to set non fatal fault attribute"); + } + + if (!strcmp(cb->name, "icp")) { + iommu_cb_set.enable_iova_guard = 1; + if (iommu_domain_set_attr(cb->mapping->domain, + DOMAIN_ATTR_FORCE_IOVA_GUARD_PAGE, + &iommu_cb_set.enable_iova_guard) < 0) { + CAM_ERR(CAM_SMMU, + "Failed to set iova guard pagei attr"); + } + } + } 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_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; + 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); + } + 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 */ + 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->mapping) + iommu_set_fault_handler(cb->mapping->domain, + cam_smmu_iommu_fault_handler, + (void *)cb->name); + /* 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_probe(struct platform_device *pdev) +{ + int rc = 0; + struct device *dev = &pdev->dev; + + 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"); + 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); + } + + return rc; +} + +static int cam_smmu_remove(struct platform_device *pdev) +{ + /* release all the context banks and memory allocated */ + cam_smmu_reset_iommu_table(CAM_SMMU_TABLE_DEINIT); + if (of_device_is_compatible(pdev->dev.of_node, "qcom,msm-cam-smmu")) + cam_smmu_release_cb(pdev); + 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, + }, +}; + +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/drivers/media/platform/msm/camera_oneplus/cam_smmu/cam_smmu_api.h b/drivers/media/platform/msm/camera_oneplus/cam_smmu/cam_smmu_api.h new file mode 100644 index 000000000000..254e382a99ad --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_smmu/cam_smmu_api.h @@ -0,0 +1,371 @@ +/* Copyright (c) 2014-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. + */ + +#ifndef _CAM_SMMU_API_H_ +#define _CAM_SMMU_API_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/*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 : Structure to store region information + * + * @param iova_start : Start address of region + * @param iova_len : length of region + */ +struct cam_smmu_region_info { + dma_addr_t iova_start; + size_t 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. + * @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, 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 client_page_fault_handler: It is triggered in IOMMU page fault + * @param token: It is input param when trigger page fault handler + */ +void cam_smmu_reg_client_page_fault_handler(int handle, + void (*client_page_fault_handler)(struct iommu_domain *, + struct device *, unsigned long, + int, void*), 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 client: Ion client passed by caller + * @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, struct ion_client *client, + ion_phys_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, + uint64_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); + +#endif /* _CAM_SMMU_API_H_ */ diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sync/Makefile b/drivers/media/platform/msm/camera_oneplus/cam_sync/Makefile new file mode 100644 index 000000000000..f3813fd63d5a --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sync/Makefile @@ -0,0 +1,3 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_utils + +obj-$(CONFIG_SPECTRA_CAMERA) += cam_sync.o cam_sync_util.o diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sync/cam_sync.c b/drivers/media/platform/msm/camera_oneplus/cam_sync/cam_sync.c new file mode 100644 index 000000000000..d625a20d6ad5 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sync/cam_sync.c @@ -0,0 +1,1077 @@ +/* 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. + */ + +#include +#include +#include +#include +#include +#include +#include "cam_sync_util.h" +#include "cam_debug_util.h" + +struct sync_device *sync_dev; + +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) + 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_object(sync_dev->sync_table, idx, name); + 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; + 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_callback_info *cb_info; + struct sync_table_row *row = NULL; + + 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; + } + + /* Don't register if callback was registered earlier */ + list_for_each_entry(cb_info, &row->callback_list, list) { + if (cb_info->callback_func == cb_func && + cb_info->cb_data == userdata) { + CAM_ERR(CAM_SYNC, "Duplicate register for sync_obj %d", + sync_obj); + spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); + return -EALREADY; + } + } + + 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)) { + 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, "Callback trigger 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; + + 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); + } + } + + spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); + return 0; +} + +int cam_sync_signal(int32_t sync_obj, uint32_t status) +{ + int rc; + struct sync_table_row *row = NULL; + struct sync_table_row *parent_row = NULL; + struct sync_callback_info *sync_cb; + struct sync_user_payload *payload_info; + struct sync_parent_info *parent_info; + struct list_head sync_list; + struct cam_signalable_info *list_info = NULL; + struct cam_signalable_info *temp_list_info = NULL; + + /* Objects to be signaled will be added into this list */ + INIT_LIST_HEAD(&sync_list); + + if (sync_obj >= CAM_SYNC_MAX_OBJS || sync_obj <= 0) { + CAM_ERR(CAM_SYNC, "Error: Out of range sync obj"); + 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; + } + + spin_lock_bh(&sync_dev->row_spinlocks[sync_obj]); + 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; + } + + row->state = status; + rc = cam_sync_util_add_to_signalable_list(sync_obj, status, &sync_list); + if (rc < 0) { + spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); + CAM_ERR(CAM_SYNC, + "Error: Unable to add sync object :%d to signalable list", + sync_obj); + return rc; + } + + /* + * Now iterate over all parents of this object and if they too need to + * be signaled add them to the list + */ + list_for_each_entry(parent_info, + &row->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--; + + parent_row->state = cam_sync_util_get_state( + parent_row->state, + status); + + if (!parent_row->remaining) { + rc = cam_sync_util_add_to_signalable_list + (parent_info->sync_id, + parent_row->state, + &sync_list); + if (rc < 0) { + spin_unlock_bh( + &sync_dev->row_spinlocks[ + parent_info->sync_id]); + spin_unlock_bh( + &sync_dev->row_spinlocks[sync_obj]); + return rc; + } + } + spin_unlock_bh(&sync_dev->row_spinlocks[parent_info->sync_id]); + } + + spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj]); + + /* + * Now dispatch the various sync objects collected so far, in our + * list + */ + list_for_each_entry_safe(list_info, + temp_list_info, + &sync_list, + list) { + struct sync_table_row *signalable_row = NULL; + struct sync_callback_info *temp_sync_cb; + struct sync_user_payload *temp_payload_info; + + signalable_row = sync_dev->sync_table + list_info->sync_obj; + + spin_lock_bh(&sync_dev->row_spinlocks[list_info->sync_obj]); + if (signalable_row->state == CAM_SYNC_STATE_INVALID) { + spin_unlock_bh( + &sync_dev->row_spinlocks[list_info->sync_obj]); + continue; + } + + /* 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 = list_info->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, + list_info->sync_obj, + list_info->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); + + spin_unlock_bh(&sync_dev->row_spinlocks[list_info->sync_obj]); + + list_del_init(&list_info->list); + kfree(list_info); + } + + return rc; +} + +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; + } + + rc = cam_sync_util_validate_merge(sync_obj, + num_objs); + if (rc < 0) { + CAM_ERR(CAM_SYNC, "Validation failed, Merge not allowed"); + 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_destroy(int32_t 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, + (void *)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((void *)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) +{ + 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, + (void *)k_ioctl->ioctl_ptr, + k_ioctl->size)) + return -EFAULT; + + 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, + (void *)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, + (void *)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((void *)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, + (void *)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, + (void *)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, + (void *)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, + (void *)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; +} + +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, NULL); +} + +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_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; + } + + 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); + 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, + }, +}; + +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/drivers/media/platform/msm/camera_oneplus/cam_sync/cam_sync_api.h b/drivers/media/platform/msm/camera_oneplus/cam_sync/cam_sync_api.h new file mode 100644 index 000000000000..9646887e9184 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sync/cam_sync_api.h @@ -0,0 +1,128 @@ +/* Copyright (c) 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. + */ + +#ifndef __CAM_SYNC_API_H__ +#define __CAM_SYNC_API_H__ + +#include +#include +#include +#include +#include + +#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: 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/drivers/media/platform/msm/camera_oneplus/cam_sync/cam_sync_private.h b/drivers/media/platform/msm/camera_oneplus/cam_sync/cam_sync_private.h new file mode 100644 index 000000000000..5ae707a2b6e7 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sync/cam_sync_private.h @@ -0,0 +1,198 @@ +/* Copyright (c) 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. + */ + +#ifndef __CAM_SYNC_PRIVATE_H__ +#define __CAM_SYNC_PRIVATE_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 50 +#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 + */ +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; +}; + +/** + * 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 + * @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 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/drivers/media/platform/msm/camera_oneplus/cam_sync/cam_sync_util.c b/drivers/media/platform/msm/camera_oneplus/cam_sync/cam_sync_util.c new file mode 100644 index 000000000000..ed69829575bb --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sync/cam_sync_util.c @@ -0,0 +1,479 @@ +/* Copyright (c) 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. + */ + +#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_object(struct sync_table_row *table, + uint32_t idx, + const char *name) +{ + struct sync_table_row *row = table + idx; + + if (!table || idx <= 0 || idx >= CAM_SYNC_MAX_OBJS) + return -EINVAL; + + if (name) + strlcpy(row->name, name, SYNC_DEBUG_NAME_LEN); + INIT_LIST_HEAD(&row->parents_list); + INIT_LIST_HEAD(&row->children_list); + row->type = CAM_SYNC_TYPE_INDV; + row->sync_id = idx; + row->state = CAM_SYNC_STATE_ACTIVE; + row->remaining = 0; + init_completion(&row->signaled); + INIT_LIST_HEAD(&row->callback_list); + INIT_LIST_HEAD(&row->user_payload_list); + CAM_DBG(CAM_SYNC, "Sync object Initialised: sync_id:%u row_state:%u ", + row->sync_id, row->state); + + return 0; +} + +uint32_t cam_sync_util_get_group_object_state(struct sync_table_row *table, + uint32_t *sync_objs, + uint32_t num_objs) +{ + int i; + struct sync_table_row *child_row = NULL; + int success_count = 0; + int active_count = 0; + + if (!table || !sync_objs) + return CAM_SYNC_STATE_SIGNALED_ERROR; + + /* + * We need to arrive at the state of the merged object based on + * counts of error, active and success states of all children objects + */ + for (i = 0; i < num_objs; i++) { + child_row = table + sync_objs[i]; + switch (child_row->state) { + case CAM_SYNC_STATE_SIGNALED_ERROR: + return CAM_SYNC_STATE_SIGNALED_ERROR; + case CAM_SYNC_STATE_SIGNALED_SUCCESS: + success_count++; + break; + case CAM_SYNC_STATE_ACTIVE: + active_count++; + break; + default: + CAM_ERR(CAM_SYNC, + "Invalid state of child object during merge"); + return CAM_SYNC_STATE_SIGNALED_ERROR; + } + } + + if (active_count) + return CAM_SYNC_STATE_ACTIVE; + + if (success_count == num_objs) + return CAM_SYNC_STATE_SIGNALED_SUCCESS; + + return CAM_SYNC_STATE_SIGNALED_ERROR; +} + +static int cam_sync_util_get_group_object_remaining_count( + struct sync_table_row *table, + uint32_t *sync_objs, + uint32_t num_objs) +{ + int i; + struct sync_table_row *child_row = NULL; + int remaining_count = 0; + + if (!table || !sync_objs) + return -EINVAL; + + for (i = 0; i < num_objs; i++) { + child_row = table + sync_objs[i]; + if (child_row->state == CAM_SYNC_STATE_ACTIVE) + remaining_count++; + } + + return remaining_count; +} + +int cam_sync_init_group_object(struct sync_table_row *table, + uint32_t idx, + uint32_t *sync_objs, + uint32_t num_objs) +{ + int i; + int remaining; + 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; + + INIT_LIST_HEAD(&row->parents_list); + + INIT_LIST_HEAD(&row->children_list); + + /* + * While traversing parents and children, we allocate in a loop and in + * case allocation fails, we call the clean up function which frees up + * all memory allocation thus far + */ + for (i = 0; i < num_objs; i++) { + child_info = kzalloc(sizeof(*child_info), GFP_ATOMIC); + + if (!child_info) { + cam_sync_util_cleanup_children_list(row, + SYNC_LIST_CLEAN_ALL, 0); + return -ENOMEM; + } + + child_info->sync_id = sync_objs[i]; + list_add_tail(&child_info->list, &row->children_list); + } + + for (i = 0; i < num_objs; i++) { + /* This gets us the row corresponding to the sync object */ + child_row = table + sync_objs[i]; + spin_lock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); + parent_info = kzalloc(sizeof(*parent_info), GFP_ATOMIC); + if (!parent_info) { + cam_sync_util_cleanup_parents_list(child_row, + SYNC_LIST_CLEAN_ALL, 0); + cam_sync_util_cleanup_children_list(row, + SYNC_LIST_CLEAN_ALL, 0); + spin_unlock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); + return -ENOMEM; + } + 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]]); + } + + row->type = CAM_SYNC_TYPE_GROUP; + row->sync_id = idx; + row->state = cam_sync_util_get_group_object_state(table, + sync_objs, num_objs); + remaining = cam_sync_util_get_group_object_remaining_count(table, + sync_objs, num_objs); + if (remaining < 0) { + CAM_ERR(CAM_SYNC, "Failed getting remaining count"); + return -ENODEV; + } + + row->remaining = remaining; + + init_completion(&row->signaled); + INIT_LIST_HEAD(&row->callback_list); + INIT_LIST_HEAD(&row->user_payload_list); + + if (row->state != CAM_SYNC_STATE_ACTIVE) + complete_all(&row->signaled); + + return 0; +} + +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; + + spin_lock_bh(&sync_dev->row_spinlocks[idx]); + if (row->state == CAM_SYNC_STATE_INVALID) { + CAM_ERR(CAM_SYNC, + "Error: accessing an uninitialized sync obj: idx = %d", + idx); + spin_unlock_bh(&sync_dev->row_spinlocks[idx]); + return -EINVAL; + } + 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) { + spin_unlock_bh(&sync_dev->row_spinlocks[ + child_info->sync_id]); + list_del_init(&child_info->list); + kfree(child_info); + continue; + } + + cam_sync_util_cleanup_parents_list(child_row, + SYNC_LIST_CLEAN_ONE, idx); + + spin_unlock_bh(&sync_dev->row_spinlocks[child_info->sync_id]); + + list_del_init(&child_info->list); + 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) { + spin_unlock_bh(&sync_dev->row_spinlocks[ + parent_info->sync_id]); + list_del_init(&parent_info->list); + kfree(parent_info); + continue; + } + + cam_sync_util_cleanup_children_list(parent_row, + SYNC_LIST_CLEAN_ONE, idx); + + spin_unlock_bh(&sync_dev->row_spinlocks[parent_info->sync_id]); + + list_del_init(&parent_info->list); + 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_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_validate_merge(uint32_t *sync_obj, uint32_t num_objs) +{ + int i; + struct sync_table_row *row = NULL; + + if (num_objs <= 1) { + CAM_ERR(CAM_SYNC, "Single object merge is not allowed"); + return -EINVAL; + } + + for (i = 0; i < num_objs; i++) { + row = sync_dev->sync_table + sync_obj[i]; + spin_lock_bh(&sync_dev->row_spinlocks[sync_obj[i]]); + if (row->type == CAM_SYNC_TYPE_GROUP || + row->state == CAM_SYNC_STATE_INVALID) { + CAM_ERR(CAM_SYNC, + "Group obj %d can't be merged or obj UNINIT", + sync_obj[i]); + spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj[i]]); + return -EINVAL; + } + spin_unlock_bh(&sync_dev->row_spinlocks[sync_obj[i]]); + } + return 0; +} + +int cam_sync_util_add_to_signalable_list(int32_t sync_obj, + uint32_t status, + struct list_head *sync_list) +{ + struct cam_signalable_info *signalable_info = NULL; + + signalable_info = kzalloc(sizeof(*signalable_info), GFP_ATOMIC); + if (!signalable_info) + return -ENOMEM; + + signalable_info->sync_obj = sync_obj; + signalable_info->status = status; + + list_add_tail(&signalable_info->list, sync_list); + CAM_DBG(CAM_SYNC, "Add sync_obj :%d with status :%d to signalable list", + sync_obj, status); + + return 0; +} + +int cam_sync_util_get_state(int current_state, + int new_state) +{ + int result = CAM_SYNC_STATE_SIGNALED_ERROR; + + if (new_state != CAM_SYNC_STATE_SIGNALED_SUCCESS && + new_state != CAM_SYNC_STATE_SIGNALED_ERROR) + return CAM_SYNC_STATE_SIGNALED_ERROR; + + switch (current_state) { + case CAM_SYNC_STATE_INVALID: + result = CAM_SYNC_STATE_SIGNALED_ERROR; + break; + + case CAM_SYNC_STATE_ACTIVE: + case CAM_SYNC_STATE_SIGNALED_SUCCESS: + if (new_state == CAM_SYNC_STATE_SIGNALED_ERROR) + result = CAM_SYNC_STATE_SIGNALED_ERROR; + else if (new_state == CAM_SYNC_STATE_SIGNALED_SUCCESS) + result = CAM_SYNC_STATE_SIGNALED_SUCCESS; + break; + + case CAM_SYNC_STATE_SIGNALED_ERROR: + result = CAM_SYNC_STATE_SIGNALED_ERROR; + break; + } + + return result; +} + +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/drivers/media/platform/msm/camera_oneplus/cam_sync/cam_sync_util.h b/drivers/media/platform/msm/camera_oneplus/cam_sync/cam_sync_util.h new file mode 100644 index 000000000000..ae7d5421e6b7 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_sync/cam_sync_util.h @@ -0,0 +1,165 @@ +/* Copyright (c) 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. + */ + +#ifndef __CAM_SYNC_UTIL_H__ +#define __CAM_SYNC_UTIL_H__ + + +#include +#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 + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_sync_init_object(struct sync_table_row *table, + uint32_t idx, + const char *name); + +/** + * @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 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 to validate sync merge arguments + * + * @param sync_obj : Array of sync objects to merge + * @param num_objs : Number of sync objects in the array + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_sync_util_validate_merge(uint32_t *sync_obj, uint32_t num_objs); + +/** + * @brief: Function which adds sync object information to the signalable list + * + * @param sync_obj : Sync object to add + * @param status : Status of above sync object + * @param list : Linked list where the information should be added to + * + * @return Status of operation. Negative in case of error. Zero otherwise. + */ +int cam_sync_util_add_to_signalable_list(int32_t sync_obj, + uint32_t status, + struct list_head *sync_list); + +/** + * @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_get_state(int current_state, + 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/drivers/media/platform/msm/camera_oneplus/cam_utils/Makefile b/drivers/media/platform/msm/camera_oneplus/cam_utils/Makefile new file mode 100644 index 000000000000..06f606caf4c3 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_utils/Makefile @@ -0,0 +1,5 @@ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_core/ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_req_mgr/ +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/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 diff --git a/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_common_util.c b/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_common_util.c new file mode 100644 index 000000000000..199d3ea072fd --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_common_util.c @@ -0,0 +1,35 @@ +/* Copyright (c) 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. + */ + +#include +#include +#include + +#include "cam_common_util.h" +#include "cam_debug_util.h" + +int cam_common_util_get_string_index(const char **strings, + uint32_t num_strings, 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; +} diff --git a/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_common_util.h b/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_common_util.h new file mode 100644 index 000000000000..d6a11b75b993 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_common_util.h @@ -0,0 +1,35 @@ +/* Copyright (c) 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. + */ + +#ifndef _CAM_COMMON_UTIL_H_ +#define _CAM_COMMON_UTIL_H_ + +#define CAM_BITS_MASK_SHIFT(x, mask, shift) (((x) & (mask)) >> shift) + +/** + * 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, char *matching_string, uint32_t *index); + +#endif /* _CAM_COMMON_UTIL_H_ */ diff --git a/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_debug_util.c b/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_debug_util.c new file mode 100644 index 000000000000..26f2ba12be9f --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_debug_util.c @@ -0,0 +1,112 @@ +/* Copyright (c) 2017, The Linux Foundataion. 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 "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; + 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("CAM_DBG: %s: %s: %d: %s\n", + cam_get_module_name(module_id), + func, line, str_buffer); + va_end(args); + } +} diff --git a/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_debug_util.h b/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_debug_util.h new file mode 100644 index 000000000000..4e97100bfb6a --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_debug_util.h @@ -0,0 +1,118 @@ +/* Copyright (c) 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. + */ + +#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 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); + +/* + * 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("CAM_ERR: %s: %s: %d " fmt "\n", \ + 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("CAM_WARN: %s: %s: %d " fmt "\n", \ + 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("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 prevent error print logs with ratelimit + */ +#define CAM_ERR_RATE_LIMIT(__module, fmt, args...) \ + pr_err_ratelimited("CAM_ERR: %s: %s: %d " fmt "\n", \ + cam_get_module_name(__module), __func__, __LINE__, ##args) + +#endif /* _CAM_DEBUG_UTIL_H_ */ diff --git a/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_io_util.c b/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_io_util.c new file mode 100644 index 000000000000..8d5f96ac816f --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_io_util.c @@ -0,0 +1,288 @@ +/* Copyright (c) 2011-2014, 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. + */ + +#include +#include +#include +#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/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_io_util.h b/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_io_util.h new file mode 100644 index 000000000000..e4f73cae85b8 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_io_util.h @@ -0,0 +1,239 @@ +/* Copyright (c) 2011-2014, 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. + */ + +#ifndef _CAM_IO_UTIL_H_ +#define _CAM_IO_UTIL_H_ + +#include + +/** + * 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/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_packet_util.c b/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_packet_util.c new file mode 100644 index 000000000000..30ab0754c47f --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_packet_util.c @@ -0,0 +1,263 @@ +/* Copyright (c) 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. + */ + +#include +#include + +#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; + uint64_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 :%ld", *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) +{ + if (!packet) + 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); + + if ((packet->kmd_cmd_buf_index >= packet->num_cmd_buf) || + (!packet->header.size) || + (packet->cmd_buf_offset > packet->header.size) || + (packet->io_configs_offset > packet->header.size)) { + CAM_ERR(CAM_UTIL, "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; + } + + 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; + 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; + } + + /* 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; + + if (len < cmd_desc->size) { + CAM_ERR(CAM_UTIL, "invalid memory len:%ld and cmd desc size:%d", + len, cmd_desc->size); + 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; +} + +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; + uint64_t iova_addr; + uint64_t cpu_addr; + 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) { + 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); + + 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; + uint64_t cpu_addr; + size_t buf_size; + 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; + } + + 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); + return -EINVAL; + } + + 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); + return rc; + } + + blob_ptr += (blob_block_size / sizeof(uint32_t)); + } + + return 0; +} diff --git a/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_packet_util.h b/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_packet_util.h new file mode 100644 index 000000000000..94d269313c7d --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_packet_util.h @@ -0,0 +1,130 @@ +/* Copyright (c) 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. + */ + +#ifndef _CAM_PACKET_UTIL_H_ +#define _CAM_PACKET_UTIL_H_ + +#include + +/** + * @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 + * + * @return: 0 for success + * -EINVAL for Fail + */ +int cam_packet_util_validate_packet(struct cam_packet *packet); + +/** + * 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_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/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_soc_util.c b/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_soc_util.c new file mode 100644 index 000000000000..0b1896fc9ed6 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_soc_util.c @@ -0,0 +1,1403 @@ +/* Copyright (c) 2015-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. + */ + +#include +#include +#include +#include +#include +#include "cam_soc_util.h" +#include "cam_debug_util.h" + +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, "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); +} + +int cam_soc_util_set_clk_flags(struct cam_hw_soc_info *soc_info, + uint32_t clk_index, unsigned long flags) +{ + if (!soc_info || (clk_index >= soc_info->num_clk)) { + CAM_ERR(CAM_UTIL, "Invalid input params %pK, %d", + soc_info, clk_index); + return -EINVAL; + } + + return clk_set_flags(soc_info->clk[clk_index], flags); +} + +int cam_soc_util_set_clk_rate(struct clk *clk, const char *clk_name, + int32_t clk_rate) +{ + int rc = 0; + long clk_rate_round; + + if (!clk || !clk_name) + return -EINVAL; + + CAM_DBG(CAM_UTIL, "set %s, rate %d", 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_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); + + *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; + + 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; + } + + return rc; + +clk_disable: + 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; + + 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 *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, "count = %d", 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; + /* Bottom loop is dependent on src_clk_str. So return here */ + return rc; + } + + 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; + } + } + + 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; + + 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) + 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 = 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; + + 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; + } + + 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); + + 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 disble_irq) +{ + int rc = 0; + + if (!soc_info) + return -EINVAL; + + if (disble_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; +} + diff --git a/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_soc_util.h b/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_soc_util.h new file mode 100644 index 000000000000..4b57d54466c3 --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_soc_util.h @@ -0,0 +1,619 @@ +/* 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. + */ + +#ifndef _CAM_SOC_UTIL_H_ +#define _CAM_SOC_UTIL_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cam_io_util.h" + +#define NO_SET_RATE -1 +#define INIT_RATE -2 + +/* maximum number of device block */ +#define CAM_SOC_MAX_BLOCK 4 + +/* maximum number of device base */ +#define CAM_SOC_MAX_BASE CAM_SOC_MAX_BLOCK + +/* maximum number of device regulator */ +#define CAM_SOC_MAX_REGULATOR 5 + +/* maximum number of device clock */ +#define CAM_SOC_MAX_CLK 32 + +/** + * 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_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_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 + * @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 + * @src_clk_idx: Source clock index that is rate-controllable + * @clk_level_valid: Indicates whether corresponding level is valid + * @gpio_data: Pointer to gpio info + * @pinctrl_info: Pointer to pinctrl info + * @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; + + 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 src_clk_idx; + bool clk_level_valid[CAM_MAX_VOTE]; + + struct cam_soc_gpio_data *gpio_data; + struct cam_soc_pinctrl_info pinctrl_info; + + 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 disble 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_clk_flags() + * + * @brief: Camera SOC util to set the flags for a specified clock + * + * @soc_info: Device soc information + * @clk_index: Clock index in soc_info for which flags are to be set + * @flags: Flags to set + * + * @return: Success or Failure + */ +int cam_soc_util_set_clk_flags(struct cam_hw_soc_info *soc_info, + uint32_t clk_index, unsigned long flags); + +/** + * cam_soc_util_set_clk_rate() + * + * @brief: Set the rate on a given clock. + * + * @clk: Clock that needs to be set + * @clk_name: Clocks name associated with clk + * @clk_rate: Clocks rate associated with clk + * + * @return: success or failure + */ +int cam_soc_util_set_clk_rate(struct clk *clk, const char *clk_name, + int32_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); + +#endif /* _CAM_SOC_UTIL_H_ */ diff --git a/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_trace.c b/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_trace.c new file mode 100644 index 000000000000..08129f3c8c8a --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_trace.c @@ -0,0 +1,16 @@ +/* Copyright (c) 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. + * + */ + +/* Instantiate tracepoints */ +#define CREATE_TRACE_POINTS +#include "cam_trace.h" diff --git a/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_trace.h b/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_trace.h new file mode 100644 index 000000000000..90ec5666941e --- /dev/null +++ b/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_trace.h @@ -0,0 +1,307 @@ +/* Copyright (c) 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. + * + */ + +#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 cam_trace + +#include +#include +#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), + TP_ARGS(dbg_message), + TP_STRUCT__entry( + __string(dbg_message, dbg_message) + ), + TP_fast_assign( + __assign_str(dbg_message, dbg_message); + ), + TP_printk( + "%s: ", + __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 diff --git a/include/uapi/media/cam_cpas.h b/include/uapi/media/cam_cpas.h new file mode 100644 index 000000000000..371b74c74500 --- /dev/null +++ b/include/uapi/media/cam_cpas.h @@ -0,0 +1,84 @@ +#ifndef __UAPI_CAM_CPAS_H__ +#define __UAPI_CAM_CPAS_H__ + +#include "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/include/uapi/media/cam_defs.h b/include/uapi/media/cam_defs.h new file mode 100644 index 000000000000..6ec286c33834 --- /dev/null +++ b/include/uapi/media/cam_defs.h @@ -0,0 +1,633 @@ +#ifndef __UAPI_CAM_DEFS_H__ +#define __UAPI_CAM_DEFS_H__ + +#include +#include +#include + + +/* 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_COMMON_OPCODE_MAX (CAM_COMMON_OPCODE_BASE + 0xA) + +#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) + +#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 + +/** + * 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 +}; + +/** + * 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_MAX 47 + +/* 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 + + +/* 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_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 + +/** + * 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; +}; + +#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_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]; +}; + +#endif /* __UAPI_CAM_DEFS_H__ */ diff --git a/include/uapi/media/cam_fd.h b/include/uapi/media/cam_fd.h new file mode 100644 index 000000000000..8feb6e4da89a --- /dev/null +++ b/include/uapi/media/cam_fd.h @@ -0,0 +1,127 @@ +#ifndef __UAPI_CAM_FD_H__ +#define __UAPI_CAM_FD_H__ + +#include "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/include/uapi/media/cam_icp.h b/include/uapi/media/cam_icp.h new file mode 100644 index 000000000000..5b4a6045d9ce --- /dev/null +++ b/include/uapi/media/cam_icp.h @@ -0,0 +1,204 @@ +#ifndef __UAPI_CAM_ICP_H__ +#define __UAPI_CAM_ICP_H__ + +#include "cam_defs.h" +#include "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_MAX 4 + +/* 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/include/uapi/media/cam_isp.h b/include/uapi/media/cam_isp.h new file mode 100644 index 000000000000..7489b72031b7 --- /dev/null +++ b/include/uapi/media/cam_isp.h @@ -0,0 +1,510 @@ +#ifndef __UAPI_CAM_ISP_H__ +#define __UAPI_CAM_ISP_H__ + +#include "cam_defs.h" +#include "cam_isp_vfe.h" +#include "cam_isp_ife.h" +#include "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 + +/* 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_BW_CONFIG_V2 6 +#define CAM_ISP_GENERIC_BLOB_TYPE_INIT_FRAME_DROP 10 + +/* 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 + +/* 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_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_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_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_ab - Bandwidth configuration + * + * @usage_type: Usage type (Single/Dual) + * @num_rdi: Number of RDI votes + * @left_pix_vote_ab: AB Bandwidth vote for left ISP + * @right_pix_vote_ab: AB Bandwidth vote for right ISP + * @rdi_vote_ab: AB RDI bandwidth requirements + */ + +struct cam_isp_bw_config_ab { + uint32_t usage_type; + uint32_t num_rdi; + uint64_t left_pix_vote_ab; + uint64_t right_pix_vote_ab; + uint64_t rdi_vote_ab[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)); + +/* Acquire Device/HW v2 */ + +/** + * 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; +}; + +#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_OUT_VER0 0x3000 + +/** + * struct cam_isp_init_frame_drop_config - init frame drop configuration + * + * @init_frame_drop: Initial number of frames needs to drop + */ + +struct cam_isp_init_frame_drop_config { + uint32_t init_frame_drop; +} __attribute__((packed)); + +#endif /* __UAPI_CAM_ISP_H__ */ diff --git a/include/uapi/media/cam_isp_ife.h b/include/uapi/media/cam_isp_ife.h new file mode 100644 index 000000000000..7e9ba62c507f --- /dev/null +++ b/include/uapi/media/cam_isp_ife.h @@ -0,0 +1,44 @@ +#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_MAX (CAM_ISP_IFE_OUT_RES_BASE + 24) + +/*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_RD (CAM_ISP_IFE_IN_RES_BASE + 5) +#define CAM_ISP_IFE_IN_RES_MAX (CAM_ISP_IFE_IN_RES_BASE + 6) + +#endif /* __UAPI_CAM_ISP_IFE_H__ */ diff --git a/include/uapi/media/cam_isp_vfe.h b/include/uapi/media/cam_isp_vfe.h new file mode 100644 index 000000000000..e48db2f98d91 --- /dev/null +++ b/include/uapi/media/cam_isp_vfe.h @@ -0,0 +1,44 @@ +#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_FE (CAM_ISP_VFE_IN_RES_BASE + 5) +#define CAM_ISP_VFE_IN_RES_MAX (CAM_ISP_VFE_IN_RES_BASE + 6) + +#endif /* __UAPI_CAM_ISP_VFE_H__ */ diff --git a/include/uapi/media/cam_jpeg.h b/include/uapi/media/cam_jpeg.h new file mode 100644 index 000000000000..f3082f3bfe29 --- /dev/null +++ b/include/uapi/media/cam_jpeg.h @@ -0,0 +1,117 @@ +#ifndef __UAPI_CAM_JPEG_H__ +#define __UAPI_CAM_JPEG_H__ + +#include "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/include/uapi/media/cam_lrme.h b/include/uapi/media/cam_lrme.h new file mode 100644 index 000000000000..97d957835ee3 --- /dev/null +++ b/include/uapi/media/cam_lrme.h @@ -0,0 +1,65 @@ +#ifndef __UAPI_CAM_LRME_H__ +#define __UAPI_CAM_LRME_H__ + +#include "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/include/uapi/media/cam_req_mgr.h b/include/uapi/media/cam_req_mgr.h new file mode 100644 index 000000000000..defed877b52d --- /dev/null +++ b/include/uapi/media/cam_req_mgr.h @@ -0,0 +1,456 @@ +#ifndef __UAPI_LINUX_CAM_REQ_MGR_H +#define __UAPI_LINUX_CAM_REQ_MGR_H + +#include +#include +#include +#include +#include + +#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_IRLED_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 + * @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; + 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_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) + +/** + * 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 + */ +#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 + +/** + * 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 + */ +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; +}; + +/** + * 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/include/uapi/media/cam_sensor.h b/include/uapi/media/cam_sensor.h new file mode 100644 index 000000000000..e5c7605616c5 --- /dev/null +++ b/include/uapi/media/cam_sensor.h @@ -0,0 +1,505 @@ +#ifndef __UAPI_CAM_SENSOR_H__ +#define __UAPI_CAM_SENSOR_H__ + +#include +#include +#include + +#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 +#define CAM_IR_LED_SUPPORTED +/** + * 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 + * @irled_slot_id : IRLED 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; + uint32_t ir_led_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 reserved; +} __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 { + uint16_t slave_addr; + uint8_t i2c_freq_mode; + uint8_t cmd_type; +} __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 { + uint16_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 { + uint16_t count; + uint8_t reserved; + uint8_t cmd_type; + 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 { + uint16_t count; + uint8_t op_code; + uint8_t cmd_type; + uint8_t data_type; + uint8_t addr_type; + uint16_t reserved; +} __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; + uint8_t op_code; + uint8_t cmd_type; + uint16_t timeout; + uint16_t reserved; + 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; + uint8_t op_code; + uint8_t cmd_type; +} __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 { + uint8_t flash_type; + uint16_t reserved; + uint8_t cmd_type; +} __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 { + uint16_t count; + uint8_t opcode; + uint8_t cmd_type; + uint16_t num_iteration; + uint16_t reserved; + 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 { + uint16_t count; + uint8_t opcode; + uint8_t cmd_type; + 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)); + +/** + * struct cam_ir_led_query_cap : capabilities info for ir_led + * + * @slot_info : Indicates about the slotId or cell Index + * + */ +struct cam_ir_led_query_cap_info { + uint32_t slot_info; +} __attribute__ ((packed)); + +/** + * struct cam_ir_ledset_on_off : led turn on/off command buffer + * + * @opcode : command buffer opcodes + * @cmd_type : command buffer operation type + * @ir_led_intensity : ir led intensity level + * + */ +struct cam_ir_led_set_on_off { + uint16_t reserved; + uint8_t opcode; + uint8_t cmd_type; + uint32_t ir_led_intensity; +} __attribute__((packed)); + +#endif diff --git a/include/uapi/media/cam_sync.h b/include/uapi/media/cam_sync.h new file mode 100644 index 000000000000..4a8781fc823d --- /dev/null +++ b/include/uapi/media/cam_sync.h @@ -0,0 +1,134 @@ +#ifndef __UAPI_CAM_SYNC_H__ +#define __UAPI_CAM_SYNC_H__ + +#include +#include +#include +#include + +#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__ */ From 8a953a4f76f472d08ec077f2b70f199af7d3435f Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Sun, 8 Oct 2023 12:33:10 +0000 Subject: [PATCH 223/356] techpack: display: Import DRM notifier from 4.9 --- include/linux/msm_drm_notify.h | 45 +++++++++++++++++++ techpack/display/msm/msm_atomic.c | 74 ++++++++++++++++++++++++++++++- 2 files changed, 117 insertions(+), 2 deletions(-) create mode 100644 include/linux/msm_drm_notify.h diff --git a/include/linux/msm_drm_notify.h b/include/linux/msm_drm_notify.h new file mode 100644 index 000000000000..924ba852c99c --- /dev/null +++ b/include/linux/msm_drm_notify.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 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. + */ +#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, +}; + +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 msm_drm_register_client(struct notifier_block *nb); +int msm_drm_unregister_client(struct notifier_block *nb); +#endif diff --git a/techpack/display/msm/msm_atomic.c b/techpack/display/msm/msm_atomic.c index ddd966d7cd41..733d8e57d518 100644 --- a/techpack/display/msm/msm_atomic.c +++ b/techpack/display/msm/msm_atomic.c @@ -16,6 +16,8 @@ * this program. If not, see . */ #include +#include +#include #include "msm_drv.h" #include "msm_gem.h" @@ -33,6 +35,49 @@ struct msm_commit { struct kthread_work commit_work; }; +static BLOCKING_NOTIFIER_HEAD(msm_drm_notifier_list); + +/** + * msm_drm_register_client - register a client notifier + * @nb: notifier block to callback on events + * + * This function registers a notifier callback function + * to msm_drm_notifier_list, which would be called when + * received unblank/power down event. + */ +int msm_drm_register_client(struct notifier_block *nb) +{ + return blocking_notifier_chain_register(&msm_drm_notifier_list, + nb); +} +EXPORT_SYMBOL(msm_drm_register_client); + +/** + * msm_drm_unregister_client - unregister a client notifier + * @nb: notifier block to callback on events + * + * This function unregisters the callback function from + * msm_drm_notifier_list. + */ +int msm_drm_unregister_client(struct notifier_block *nb) +{ + return blocking_notifier_chain_unregister(&msm_drm_notifier_list, + nb); +} +EXPORT_SYMBOL(msm_drm_unregister_client); + +/** + * msm_drm_notifier_call_chain - notify clients of drm_events + * @val: event MSM_DRM_EARLY_EVENT_BLANK or MSM_DRM_EVENT_BLANK + * @v: notifier data, inculde display id and display blank + * event(unblank or power down). + */ +static int msm_drm_notifier_call_chain(unsigned long val, void *v) +{ + return blocking_notifier_call_chain(&msm_drm_notifier_list, val, + v); +} + static inline bool _msm_seamless_for_crtc(struct drm_device *dev, struct drm_atomic_state *state, struct drm_crtc_state *crtc_state, bool enable) @@ -156,7 +201,8 @@ msm_disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) struct drm_connector_state *old_conn_state; struct drm_crtc *crtc; struct drm_crtc_state *old_crtc_state; - int i; + struct msm_drm_notifier notifier_data; + int i, blank; SDE_ATRACE_BEGIN("msm_disable"); for_each_old_connector_in_state(old_state, connector, @@ -164,6 +210,7 @@ msm_disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) const struct drm_encoder_helper_funcs *funcs; struct drm_encoder *encoder; struct drm_crtc_state *old_crtc_state; + unsigned int crtc_idx; /* * Shut down everything that's in the changeset and currently @@ -172,6 +219,7 @@ msm_disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) if (!old_conn_state->crtc) continue; + crtc_idx = drm_crtc_index(old_conn_state->crtc); old_crtc_state = drm_atomic_get_old_crtc_state(old_state, old_conn_state->crtc); @@ -195,6 +243,11 @@ msm_disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) DRM_DEBUG_ATOMIC("disabling [ENCODER:%d:%s]\n", encoder->base.id, encoder->name); + blank = MSM_DRM_BLANK_POWERDOWN; + notifier_data.data = ␣ + notifier_data.id = crtc_idx; + msm_drm_notifier_call_chain(MSM_DRM_EARLY_EVENT_BLANK, + ¬ifier_data); /* * Each encoder has at most one connector (since we always steal * it away), so we won't call disable hooks twice. @@ -210,6 +263,8 @@ msm_disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) funcs->dpms(encoder, DRM_MODE_DPMS_OFF); drm_bridge_post_disable(encoder->bridge); + msm_drm_notifier_call_chain(MSM_DRM_EVENT_BLANK, + ¬ifier_data); } for_each_old_crtc_in_state(old_state, crtc, old_crtc_state, i) { @@ -353,10 +408,11 @@ static void msm_atomic_helper_commit_modeset_enables(struct drm_device *dev, struct drm_crtc_state *new_crtc_state; struct drm_connector *connector; struct drm_connector_state *new_conn_state; + struct msm_drm_notifier notifier_data; struct msm_drm_private *priv = dev->dev_private; struct msm_kms *kms = priv->kms; int bridge_enable_count = 0; - int i; + int i, blank; SDE_ATRACE_BEGIN("msm_enable"); for_each_oldnew_crtc_in_state(old_state, crtc, old_crtc_state, @@ -416,6 +472,15 @@ static void msm_atomic_helper_commit_modeset_enables(struct drm_device *dev, DRM_DEBUG_ATOMIC("enabling [ENCODER:%d:%s]\n", encoder->base.id, encoder->name); + if (connector->state->crtc->state->active_changed) { + blank = MSM_DRM_BLANK_UNBLANK; + notifier_data.data = ␣ + notifier_data.id = + connector->state->crtc->index; + DRM_DEBUG_ATOMIC("Notify early unblank\n"); + msm_drm_notifier_call_chain(MSM_DRM_EARLY_EVENT_BLANK, + ¬ifier_data); + } /* * Each encoder has at most one connector (since we always steal * it away), so we won't call enable hooks twice. @@ -464,6 +529,11 @@ static void msm_atomic_helper_commit_modeset_enables(struct drm_device *dev, encoder->base.id, encoder->name); drm_bridge_enable(encoder->bridge); + if (connector->state->crtc->state->active_changed) { + DRM_DEBUG_ATOMIC("Notify unblank\n"); + msm_drm_notifier_call_chain(MSM_DRM_EVENT_BLANK, + ¬ifier_data); + } } SDE_ATRACE_END("msm_enable"); } From be78afebcafe46ffabaf4b052847a4b4270a1529 Mon Sep 17 00:00:00 2001 From: Luca Stefani Date: Sat, 28 Jul 2018 10:37:53 +0200 Subject: [PATCH 224/356] techpack: display: Import OnePlus changes Change-Id: Ifbec17f55d317d716b15cd789e76bebdead11f33 --- drivers/gpu/drm/drm_mipi_dsi.c | 23 ++++++++++++++++ include/drm/drm_mipi_dsi.h | 2 ++ include/linux/msm_drm_notify.h | 12 ++++++-- techpack/display/msm/dsi/dsi_display.c | 38 ++++++++++++++++---------- techpack/display/msm/dsi/dsi_display.h | 3 ++ techpack/display/msm/dsi/dsi_panel.c | 29 ++++++++++++++++++-- techpack/display/msm/dsi/dsi_panel.h | 1 + techpack/display/msm/msm_atomic.c | 7 ++++- techpack/display/msm/msm_drv.h | 1 + techpack/display/msm/sde/sde_plane.c | 6 +++- 10 files changed, 102 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index b15d5e4320d6..6cd4053e9b25 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -1162,6 +1162,29 @@ int mipi_dsi_dcs_get_display_brightness_large(struct mipi_dsi_device *dsi, } EXPORT_SYMBOL(mipi_dsi_dcs_get_display_brightness_large); +/** + * 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); + static int mipi_dsi_drv_probe(struct device *dev) { struct mipi_dsi_driver *drv = to_mipi_dsi_driver(dev->driver); diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index d80635d66bef..102061d6edec 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -292,6 +292,8 @@ int mipi_dsi_dcs_set_display_brightness_large(struct mipi_dsi_device *dsi, u16 brightness); int mipi_dsi_dcs_get_display_brightness_large(struct mipi_dsi_device *dsi, u16 *brightness); +int mipi_dsi_dcs_set_display_brightness_samsung(struct mipi_dsi_device *dsi, + u16 brightness); /** * struct mipi_dsi_driver - DSI driver diff --git a/include/linux/msm_drm_notify.h b/include/linux/msm_drm_notify.h index 924ba852c99c..866327be492a 100644 --- a/include/linux/msm_drm_notify.h +++ b/include/linux/msm_drm_notify.h @@ -25,6 +25,14 @@ enum { 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: fingerprit on display */ + MSM_DRM_ONSCREENFINGERPRINT_EVENT, }; enum msm_drm_display_id { @@ -40,6 +48,6 @@ struct msm_drm_notifier { void *data; }; -int msm_drm_register_client(struct notifier_block *nb); -int msm_drm_unregister_client(struct notifier_block *nb); +extern int msm_drm_register_client(struct notifier_block *nb); +extern int msm_drm_unregister_client(struct notifier_block *nb); #endif diff --git a/techpack/display/msm/dsi/dsi_display.c b/techpack/display/msm/dsi/dsi_display.c index 148777e7b148..dd6f68695033 100644 --- a/techpack/display/msm/dsi/dsi_display.c +++ b/techpack/display/msm/dsi/dsi_display.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "msm_drv.h" #include "sde_connector.h" @@ -1045,7 +1046,9 @@ int dsi_display_set_power(struct drm_connector *connector, int power_mode, void *disp) { struct dsi_display *display = disp; + struct msm_drm_notifier notifier_data; int rc = 0; + int blank; if (!display || !display->panel) { DSI_ERR("invalid display/panel\n"); @@ -1059,23 +1062,30 @@ int dsi_display_set_power(struct drm_connector *connector, case SDE_MODE_DPMS_LP2: rc = dsi_panel_set_lp2(display->panel); break; - case SDE_MODE_DPMS_ON: - if ((display->panel->power_mode == SDE_MODE_DPMS_LP1) || - (display->panel->power_mode == SDE_MODE_DPMS_LP2)) - rc = dsi_panel_set_nolp(display->panel); - break; - case SDE_MODE_DPMS_OFF: default: - return rc; + rc = dsi_panel_set_nolp(display->panel); + break; } - SDE_EVT32(display->panel->power_mode, power_mode, rc); - DSI_DEBUG("Power mode transition from %d to %d %s", - display->panel->power_mode, power_mode, - rc ? "failed" : "successful"); - if (!rc) - display->panel->power_mode = power_mode; - + if (power_mode == SDE_MODE_DPMS_ON) { + blank = MSM_DRM_BLANK_UNBLANK_CUST; + notifier_data.data = ␣ + notifier_data.id = connector_state_crtc_index; + msm_drm_notifier_call_chain(MSM_DRM_EARLY_EVENT_BLANK, + ¬ifier_data); + } else if (power_mode == SDE_MODE_DPMS_LP1) { + blank = MSM_DRM_BLANK_NORMAL; + notifier_data.data = ␣ + notifier_data.id = connector_state_crtc_index; + msm_drm_notifier_call_chain(MSM_DRM_EARLY_EVENT_BLANK, + ¬ifier_data); + } else if (power_mode == SDE_MODE_DPMS_OFF) { + blank = MSM_DRM_BLANK_POWERDOWN_CUST; + notifier_data.data = ␣ + notifier_data.id = connector_state_crtc_index; + msm_drm_notifier_call_chain(MSM_DRM_EARLY_EVENT_BLANK, + ¬ifier_data); + } return rc; } diff --git a/techpack/display/msm/dsi/dsi_display.h b/techpack/display/msm/dsi/dsi_display.h index d254dfe739bd..88bca968605e 100644 --- a/techpack/display/msm/dsi/dsi_display.h +++ b/techpack/display/msm/dsi/dsi_display.h @@ -735,4 +735,7 @@ int dsi_display_cont_splash_config(void *display); int dsi_display_get_panel_vfp(void *display, int h_active, int v_active); +extern int connector_state_crtc_index; +extern int msm_drm_notifier_call_chain(unsigned long val, void *v); + #endif /* _DSI_DISPLAY_H_ */ diff --git a/techpack/display/msm/dsi/dsi_panel.c b/techpack/display/msm/dsi/dsi_panel.c index e1f231f13c00..78cf87fb67be 100644 --- a/techpack/display/msm/dsi/dsi_panel.c +++ b/techpack/display/msm/dsi/dsi_panel.c @@ -674,8 +674,13 @@ static int dsi_panel_update_backlight(struct dsi_panel *panel, if (panel->bl_config.bl_dcs_subtype == 0xc2) rc = dsi_panel_dcs_set_display_brightness_c2(dsi, bl_lvl); - else - rc = mipi_dsi_dcs_set_display_brightness(dsi, bl_lvl); + else { + if (panel->bl_config.bl_high2bit) { + rc = mipi_dsi_dcs_set_display_brightness_samsung(dsi, bl_lvl); + } else { + rc = mipi_dsi_dcs_set_display_brightness(dsi, bl_lvl); + } + } if (rc < 0) DSI_ERR("failed to update dcs backlight:%d\n", bl_lvl); @@ -3363,6 +3368,22 @@ static void dsi_panel_update_util(struct dsi_panel *panel, utils->node = panel->panel_of_node; } +static int dsi_panel_parse_oem_config(struct dsi_panel *panel, + struct device_node *of_node) +{ + panel->lp11_init = of_property_read_bool(of_node, + "qcom,mdss-dsi-lp11-init"); + if (panel->lp11_init) + pr_debug("lp11_init: %d\n", panel->lp11_init); + + panel->bl_config.bl_high2bit = of_property_read_bool(of_node, + "qcom,mdss-bl-high2bit"); + if (panel->bl_config.bl_high2bit) + pr_debug("bl_high2bit: %d\n", panel->bl_config.bl_high2bit); + + return 0; +} + struct dsi_panel *dsi_panel_get(struct device *parent, struct device_node *of_node, struct device_node *parser_node, @@ -3378,6 +3399,10 @@ struct dsi_panel *dsi_panel_get(struct device *parent, if (!panel) return ERR_PTR(-ENOMEM); + rc = dsi_panel_parse_oem_config(panel, of_node); + if (rc) + pr_debug("failed to get oem config, rc=%d\n", rc); + panel->panel_of_node = of_node; panel->parent = parent; panel->type = type; diff --git a/techpack/display/msm/dsi/dsi_panel.h b/techpack/display/msm/dsi/dsi_panel.h index ee30cd5375b4..53a2f275c069 100644 --- a/techpack/display/msm/dsi/dsi_panel.h +++ b/techpack/display/msm/dsi/dsi_panel.h @@ -123,6 +123,7 @@ struct dsi_backlight_config { u32 bl_scale_sv; bool bl_inverted_dbv; u32 bl_dcs_subtype; + bool bl_high2bit; int en_gpio; /* PWM params */ diff --git a/techpack/display/msm/msm_atomic.c b/techpack/display/msm/msm_atomic.c index 733d8e57d518..c6c85fe215cf 100644 --- a/techpack/display/msm/msm_atomic.c +++ b/techpack/display/msm/msm_atomic.c @@ -37,6 +37,8 @@ struct msm_commit { static BLOCKING_NOTIFIER_HEAD(msm_drm_notifier_list); +int connector_state_crtc_index; + /** * msm_drm_register_client - register a client notifier * @nb: notifier block to callback on events @@ -72,11 +74,12 @@ EXPORT_SYMBOL(msm_drm_unregister_client); * @v: notifier data, inculde display id and display blank * event(unblank or power down). */ -static int msm_drm_notifier_call_chain(unsigned long val, void *v) +int msm_drm_notifier_call_chain(unsigned long val, void *v) { return blocking_notifier_call_chain(&msm_drm_notifier_list, val, v); } +EXPORT_SYMBOL(msm_drm_notifier_call_chain); static inline bool _msm_seamless_for_crtc(struct drm_device *dev, struct drm_atomic_state *state, @@ -246,6 +249,7 @@ msm_disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state) blank = MSM_DRM_BLANK_POWERDOWN; notifier_data.data = ␣ notifier_data.id = crtc_idx; + connector_state_crtc_index = crtc_idx; msm_drm_notifier_call_chain(MSM_DRM_EARLY_EVENT_BLANK, ¬ifier_data); /* @@ -477,6 +481,7 @@ static void msm_atomic_helper_commit_modeset_enables(struct drm_device *dev, notifier_data.data = ␣ notifier_data.id = connector->state->crtc->index; + connector_state_crtc_index = connector->state->crtc->index; DRM_DEBUG_ATOMIC("Notify early unblank\n"); msm_drm_notifier_call_chain(MSM_DRM_EARLY_EVENT_BLANK, ¬ifier_data); diff --git a/techpack/display/msm/msm_drv.h b/techpack/display/msm/msm_drv.h index 084aaab34e3d..c9902e33fb6b 100644 --- a/techpack/display/msm/msm_drv.h +++ b/techpack/display/msm/msm_drv.h @@ -107,6 +107,7 @@ enum msm_mdp_plane_property { /* range properties */ PLANE_PROP_ZPOS = PLANE_PROP_BLOBCOUNT, + PLANE_PROP_CUSTOM, PLANE_PROP_ALPHA, PLANE_PROP_COLOR_FILL, PLANE_PROP_H_DECIMATE, diff --git a/techpack/display/msm/sde/sde_plane.c b/techpack/display/msm/sde/sde_plane.c index 0264cefe1ddd..3e83fb961cd5 100644 --- a/techpack/display/msm/sde/sde_plane.c +++ b/techpack/display/msm/sde/sde_plane.c @@ -2857,7 +2857,8 @@ static void _sde_plane_map_prop_to_dirty_bits(void) 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] = 0; + 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; @@ -3577,6 +3578,9 @@ static void _sde_plane_install_properties(struct drm_plane *plane, msm_property_install_range(&psde->property_info, "zpos", 0x0, 0, zpos_max, zpos_def, PLANE_PROP_ZPOS); + 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); From 693251d6ffe53a85a3b2ce83426ddedc7134065c Mon Sep 17 00:00:00 2001 From: Danny Baumann Date: Wed, 25 Jul 2018 10:28:02 +0200 Subject: [PATCH 225/356] techpack: display: Restore previous display brightness when enabling display. Change-Id: I3b2ae8963813a436d04bb6b5eafef4b2b65628f5 --- techpack/display/msm/dsi/dsi_display.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/techpack/display/msm/dsi/dsi_display.c b/techpack/display/msm/dsi/dsi_display.c index dd6f68695033..1c55043c2156 100644 --- a/techpack/display/msm/dsi/dsi_display.c +++ b/techpack/display/msm/dsi/dsi_display.c @@ -7584,6 +7584,7 @@ int dsi_display_enable(struct dsi_display *display) { int rc = 0; struct dsi_display_mode *mode; + struct drm_connector *connector = NULL; if (!display || !display->panel) { DSI_ERR("Invalid params\n"); @@ -7679,6 +7680,12 @@ int dsi_display_enable(struct dsi_display *display) goto error_disable_panel; } + rc = dsi_display_set_backlight(connector, display, + display->panel->bl_config.bl_level); + if (rc) + pr_warn("[%s]failed to restore previous brightness, rc=%d\n", + display->name, rc); + goto error; error_disable_panel: From 18286c9a22948164ef19d6d03886b00358d34c7f Mon Sep 17 00:00:00 2001 From: Cosmin Tanislav Date: Thu, 10 Feb 2022 10:35:42 +0200 Subject: [PATCH 226/356] teckpack: display: dsi_display: create empty ettributes group Change-Id: Ia1e747272240d380c82843d9faeeedac7bc58d9b --- techpack/display/msm/dsi/dsi_display.c | 32 ++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/techpack/display/msm/dsi/dsi_display.c b/techpack/display/msm/dsi/dsi_display.c index 1c55043c2156..4e4cb5bef9ce 100644 --- a/techpack/display/msm/dsi/dsi_display.c +++ b/techpack/display/msm/dsi/dsi_display.c @@ -5014,6 +5014,33 @@ static int dsi_display_validate_split_link(struct dsi_display *display) return rc; } +static struct attribute *display_attrs[] = { + NULL, +}; + +static struct attribute_group display_attrs_group = { + .attrs = display_attrs, +}; + +static int dsi_display_sysfs_init(struct dsi_display *display) +{ + int rc = 0; + struct device *dev = &display->pdev->dev; + + rc = sysfs_create_group(&dev->kobj, &display_attrs_group); + if (rc) + DSI_ERR("failed to create display sysfs attributes\n"); + + return rc; +} + +static void dsi_display_sysfs_deinit(struct dsi_display *display) +{ + struct device *dev = &display->pdev->dev; + + sysfs_remove_group(&dev->kobj, &display_attrs_group); +} + /** * dsi_display_bind - bind dsi device with controlling device * @dev: Pointer to base of platform device @@ -5082,6 +5109,10 @@ static int dsi_display_bind(struct device *dev, goto error; } + rc = dsi_display_sysfs_init(display); + if (rc) + goto error; + atomic_set(&display->clkrate_change_pending, 0); display->cached_clk_rate = 0; @@ -5235,6 +5266,7 @@ static int dsi_display_bind(struct device *dev, (void)dsi_ctrl_drv_deinit(display_ctrl->ctrl); } (void)dsi_display_debugfs_deinit(display); + dsi_display_sysfs_deinit(display); error: mutex_unlock(&display->display_lock); return rc; From 3961e76712cbef6c6d15b48ba18a4bfbd8911643 Mon Sep 17 00:00:00 2001 From: Danny Baumann Date: Thu, 19 Jul 2018 09:41:23 +0200 Subject: [PATCH 227/356] techpack: display: Add support for high brightness mode (HBM) Change-Id: Id133e30c7bf645386053c42d4d121a053b03bac7 --- techpack/display/msm/dsi/dsi_defs.h | 6 +++ techpack/display/msm/dsi/dsi_display.c | 59 ++++++++++++++++++++++++++ techpack/display/msm/dsi/dsi_panel.c | 42 ++++++++++++++++++ techpack/display/msm/dsi/dsi_panel.h | 4 ++ 4 files changed, 111 insertions(+) diff --git a/techpack/display/msm/dsi/dsi_defs.h b/techpack/display/msm/dsi/dsi_defs.h index 5179edfebd02..454ea05d20b7 100644 --- a/techpack/display/msm/dsi/dsi_defs.h +++ b/techpack/display/msm/dsi/dsi_defs.h @@ -307,6 +307,12 @@ enum dsi_cmd_set_type { DSI_CMD_SET_POST_TIMING_SWITCH, DSI_CMD_SET_QSYNC_ON, DSI_CMD_SET_QSYNC_OFF, + DSI_CMD_SET_HBM_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_MAX }; diff --git a/techpack/display/msm/dsi/dsi_display.c b/techpack/display/msm/dsi/dsi_display.c index 4e4cb5bef9ce..cc8302977a56 100644 --- a/techpack/display/msm/dsi/dsi_display.c +++ b/techpack/display/msm/dsi/dsi_display.c @@ -5014,7 +5014,66 @@ static int dsi_display_validate_split_link(struct dsi_display *display) return rc; } +static ssize_t sysfs_hbm_read(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct dsi_display *display = dev_get_drvdata(dev); + if (!display->panel) + return 0; + + return scnprintf(buf, PAGE_SIZE, "%d\n", display->panel->hbm_mode); +} + +static ssize_t sysfs_hbm_write(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct dsi_display *display = dev_get_drvdata(dev); + int ret, hbm_mode; + + if (!display->panel) + return -EINVAL; + + ret = kstrtoint(buf, 10, &hbm_mode); + if (ret) { + pr_err("kstrtoint failed. ret=%d\n", ret); + return ret; + } + + mutex_lock(&display->display_lock); + + display->panel->hbm_mode = hbm_mode; + if (!dsi_panel_initialized(display->panel)) { + goto error; + } + + ret = dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_ON); + if (ret) { + pr_err("[%s] failed to enable DSI core clocks, rc=%d\n", + display->name, ret); + goto error; + } + + ret = dsi_panel_apply_hbm_mode(display->panel); + if (ret) + pr_err("unable to set hbm mode\n"); + + ret = dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_OFF); + if (ret) { + pr_err("[%s] failed to disable DSI core clocks, rc=%d\n", + display->name, ret); + goto error; + } +error: + mutex_unlock(&display->display_lock); + return ret == 0 ? count : ret; +} + +static DEVICE_ATTR(hbm, 0644, sysfs_hbm_read, sysfs_hbm_write); + static struct attribute *display_attrs[] = { + &dev_attr_hbm.attr, NULL, }; diff --git a/techpack/display/msm/dsi/dsi_panel.c b/techpack/display/msm/dsi/dsi_panel.c index 78cf87fb67be..f9ab8ed5cdfd 100644 --- a/techpack/display/msm/dsi/dsi_panel.c +++ b/techpack/display/msm/dsi/dsi_panel.c @@ -1835,6 +1835,12 @@ const char *cmd_set_prop_map[DSI_CMD_SET_MAX] = { "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-off-command", + "qcom,mdss-dsi-panel-hbm-on-command", + "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", }; const char *cmd_set_state_map[DSI_CMD_SET_MAX] = { @@ -1861,6 +1867,12 @@ const char *cmd_set_state_map[DSI_CMD_SET_MAX] = { "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-hbm-off-command-state", + "qcom,mdss-dsi-hbm-on-command-state", + "qcom,mdss-dsi-hbm-on-command-state", + "qcom,mdss-dsi-hbm-on-command-state", + "qcom,mdss-dsi-hbm-on-command-state", + "qcom,mdss-dsi-hbm-on-command-state", }; static int dsi_panel_get_cmd_pkt_count(const char *data, u32 length, u32 *cnt) @@ -4496,6 +4508,10 @@ int dsi_panel_enable(struct dsi_panel *panel) else panel->panel_initialized = true; mutex_unlock(&panel->panel_lock); + + if (panel->hbm_mode) + dsi_panel_apply_hbm_mode(panel); + return rc; } @@ -4630,3 +4646,29 @@ int dsi_panel_post_unprepare(struct dsi_panel *panel) mutex_unlock(&panel->panel_lock); return rc; } + +int dsi_panel_apply_hbm_mode(struct dsi_panel *panel) +{ + static const enum dsi_cmd_set_type type_map[] = { + DSI_CMD_SET_HBM_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 + }; + + enum dsi_cmd_set_type type; + int rc; + + if (panel->hbm_mode >= 0 && panel->hbm_mode < ARRAY_SIZE(type_map)) + type = type_map[panel->hbm_mode]; + else + type = DSI_CMD_SET_HBM_OFF; + + mutex_lock(&panel->panel_lock); + rc = dsi_panel_tx_cmd_set(panel, type); + mutex_unlock(&panel->panel_lock); + + return rc; +} diff --git a/techpack/display/msm/dsi/dsi_panel.h b/techpack/display/msm/dsi/dsi_panel.h index 53a2f275c069..803022c08480 100644 --- a/techpack/display/msm/dsi/dsi_panel.h +++ b/techpack/display/msm/dsi/dsi_panel.h @@ -205,6 +205,8 @@ struct dsi_panel { struct drm_panel_hdr_properties hdr_props; struct drm_panel_esd_config esd_config; + int hbm_mode; + struct dsi_parser_utils utils; bool lp11_init; @@ -310,6 +312,8 @@ int dsi_panel_unprepare(struct dsi_panel *panel); int dsi_panel_post_unprepare(struct dsi_panel *panel); +int dsi_panel_apply_hbm_mode(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); From 2ca2134486fca342bda45ca6bc079c163ef65460 Mon Sep 17 00:00:00 2001 From: Danny Baumann Date: Thu, 19 Jul 2018 09:59:55 +0200 Subject: [PATCH 228/356] techpack: display: Add support for display modes. Change-Id: I0e1f2bfa2348e5c94d67147c9fec4b042b0cabf4 --- techpack/display/msm/dsi/dsi_defs.h | 4 ++ techpack/display/msm/dsi/dsi_display.c | 71 ++++++++++++++++++++++++++ techpack/display/msm/dsi/dsi_panel.c | 31 ++++++++++- techpack/display/msm/dsi/dsi_panel.h | 10 ++++ 4 files changed, 115 insertions(+), 1 deletion(-) diff --git a/techpack/display/msm/dsi/dsi_defs.h b/techpack/display/msm/dsi/dsi_defs.h index 454ea05d20b7..3af6926a2ac5 100644 --- a/techpack/display/msm/dsi/dsi_defs.h +++ b/techpack/display/msm/dsi/dsi_defs.h @@ -313,6 +313,10 @@ enum dsi_cmd_set_type { DSI_CMD_SET_HBM_ON_3, DSI_CMD_SET_HBM_ON_4, DSI_CMD_SET_HBM_ON_5, + DSI_CMD_SET_MODE_SRGB, + DSI_CMD_SET_MODE_DCI_P3, + DSI_CMD_SET_MODE_WIDE_COLOR, + DSI_CMD_SET_MODE_DEFAULT, DSI_CMD_SET_MAX }; diff --git a/techpack/display/msm/dsi/dsi_display.c b/techpack/display/msm/dsi/dsi_display.c index cc8302977a56..f552c2cb9a9e 100644 --- a/techpack/display/msm/dsi/dsi_display.c +++ b/techpack/display/msm/dsi/dsi_display.c @@ -5070,10 +5070,81 @@ static ssize_t sysfs_hbm_write(struct device *dev, return ret == 0 ? count : ret; } +static ssize_t sysfs_display_mode_read(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct dsi_display *display = dev_get_drvdata(dev); + if (!display->panel) + return 0; + + return scnprintf(buf, PAGE_SIZE, "%s\n", + display->panel->display_mode == DISPLAY_MODE_SRGB ? "srgb" : + display->panel->display_mode == DISPLAY_MODE_DCI_P3 ? "dci-p3" : + display->panel->display_mode == DISPLAY_MODE_WIDE_COLOR ? "widecolor" : + "default"); +} + +static ssize_t sysfs_display_mode_write(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct dsi_display *display = dev_get_drvdata(dev); + enum dsi_panel_display_mode mode; + int ret = 0; + + if (!display->panel) + return -EINVAL; + + if (!strcmp(buf, "srgb")) + mode = DISPLAY_MODE_SRGB; + else if (!strcmp(buf, "dci-p3")) + mode = DISPLAY_MODE_DCI_P3; + else if (!strcmp(buf, "widecolor")) + mode = DISPLAY_MODE_WIDE_COLOR; + else if (!strcmp(buf, "default")) + mode = DISPLAY_MODE_DEFAULT; + else + return -EINVAL; + + mutex_lock(&display->display_lock); + + display->panel->display_mode = mode; + if (!dsi_panel_initialized(display->panel)) { + printk("not initialized\n"); + goto error; + } + + ret = dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_ON); + if (ret) { + pr_err("[%s] failed to enable DSI core clocks, rc=%d\n", + display->name, ret); + goto error; + } + + ret = dsi_panel_apply_display_mode(display->panel); + if (ret) + pr_err("unable to set display mode\n"); + + ret = dsi_display_clk_ctrl(display->dsi_clk_handle, + DSI_CORE_CLK, DSI_CLK_OFF); + if (ret) { + pr_err("[%s] failed to disable DSI core clocks, rc=%d\n", + display->name, ret); + goto error; + } +error: + mutex_unlock(&display->display_lock); + return ret == 0 ? count : ret; +} + static DEVICE_ATTR(hbm, 0644, sysfs_hbm_read, sysfs_hbm_write); +static DEVICE_ATTR(display_mode, 0644, + sysfs_display_mode_read, + sysfs_display_mode_write); static struct attribute *display_attrs[] = { &dev_attr_hbm.attr, + &dev_attr_display_mode.attr, NULL, }; diff --git a/techpack/display/msm/dsi/dsi_panel.c b/techpack/display/msm/dsi/dsi_panel.c index f9ab8ed5cdfd..a9c2c74907f0 100644 --- a/techpack/display/msm/dsi/dsi_panel.c +++ b/techpack/display/msm/dsi/dsi_panel.c @@ -545,7 +545,7 @@ static int dsi_panel_tx_cmd_set(struct dsi_panel *panel, SDE_EVT32(type, state, count); if (count == 0) { - DSI_DEBUG("[%s] No commands to be sent for state(%d)\n", + DSI_ERR("[%s] No commands to be sent for state(%d)\n", panel->name, type); goto error; } @@ -1841,6 +1841,10 @@ const char *cmd_set_prop_map[DSI_CMD_SET_MAX] = { "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-display-srgb-color-mode-on-command", + "qcom,mdss-dsi-panel-display-p3-mode-on-command", + "qcom,mdss-dsi-panel-display-wide-color-mode-on-command", + "qcom,mdss-dsi-panel-dci-p3-off-command", // also disables SRGB and wide color modes }; const char *cmd_set_state_map[DSI_CMD_SET_MAX] = { @@ -1873,6 +1877,10 @@ const char *cmd_set_state_map[DSI_CMD_SET_MAX] = { "qcom,mdss-dsi-hbm-on-command-state", "qcom,mdss-dsi-hbm-on-command-state", "qcom,mdss-dsi-hbm-on-command-state", + "qcom,mdss-dsi-panel-display-srgb-color-mode-on-command-state", + "qcom,mdss-dsi-panel-display-p3-mode-on-command-state", + "qcom,mdss-dsi-panel-display-wide-color-mode-on-command-state", + "qcom,mdss-dsi-panel-dci-p3-off-command-state", }; static int dsi_panel_get_cmd_pkt_count(const char *data, u32 length, u32 *cnt) @@ -4511,6 +4519,8 @@ int dsi_panel_enable(struct dsi_panel *panel) if (panel->hbm_mode) dsi_panel_apply_hbm_mode(panel); + if (panel->display_mode != DISPLAY_MODE_DEFAULT) + dsi_panel_apply_display_mode(panel); return rc; } @@ -4672,3 +4682,22 @@ int dsi_panel_apply_hbm_mode(struct dsi_panel *panel) return rc; } + +int dsi_panel_apply_display_mode(struct dsi_panel *panel) +{ + enum dsi_cmd_set_type type; + int rc; + + switch (panel->display_mode) { + case DISPLAY_MODE_SRGB: type = DSI_CMD_SET_MODE_SRGB; break; + case DISPLAY_MODE_DCI_P3: type = DSI_CMD_SET_MODE_DCI_P3; break; + case DISPLAY_MODE_WIDE_COLOR: type = DSI_CMD_SET_MODE_WIDE_COLOR; break; + default: type = DSI_CMD_SET_MODE_DEFAULT; break; + } + + mutex_lock(&panel->panel_lock); + rc = dsi_panel_tx_cmd_set(panel, type); + mutex_unlock(&panel->panel_lock); + + return rc; +} diff --git a/techpack/display/msm/dsi/dsi_panel.h b/techpack/display/msm/dsi/dsi_panel.h index 803022c08480..7465c79216f9 100644 --- a/techpack/display/msm/dsi/dsi_panel.h +++ b/techpack/display/msm/dsi/dsi_panel.h @@ -173,6 +173,13 @@ struct drm_panel_esd_config { u32 groups; }; +enum dsi_panel_display_mode { + DISPLAY_MODE_DEFAULT, + DISPLAY_MODE_SRGB, + DISPLAY_MODE_DCI_P3, + DISPLAY_MODE_WIDE_COLOR, +}; + struct dsi_panel { const char *name; const char *type; @@ -206,6 +213,7 @@ struct dsi_panel { struct drm_panel_esd_config esd_config; int hbm_mode; + enum dsi_panel_display_mode display_mode; struct dsi_parser_utils utils; @@ -314,6 +322,8 @@ int dsi_panel_post_unprepare(struct dsi_panel *panel); int dsi_panel_apply_hbm_mode(struct dsi_panel *panel); +int dsi_panel_apply_display_mode(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); From 80feef36b8a9e7c5ac80087f2770d56dd5d3a77b Mon Sep 17 00:00:00 2001 From: Danny Baumann Date: Thu, 19 Jul 2018 15:42:06 +0200 Subject: [PATCH 229/356] techpack: display: Symlink main DSI display sysfs to its parent (MDSS) Allows user space to unambiguously find it. Change-Id: I944944e601c050c8213365301696521654af52c9 --- techpack/display/msm/dsi/dsi_display.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/techpack/display/msm/dsi/dsi_display.c b/techpack/display/msm/dsi/dsi_display.c index f552c2cb9a9e..874a73f463db 100644 --- a/techpack/display/msm/dsi/dsi_display.c +++ b/techpack/display/msm/dsi/dsi_display.c @@ -5152,12 +5152,18 @@ static struct attribute_group display_attrs_group = { .attrs = display_attrs, }; -static int dsi_display_sysfs_init(struct dsi_display *display) +static int dsi_display_sysfs_init(struct dsi_display *display, + struct device *master) { int rc = 0; struct device *dev = &display->pdev->dev; + struct dsi_panel *panel; + panel = display->panel; rc = sysfs_create_group(&dev->kobj, &display_attrs_group); + if (rc == 0 && !strcmp(display->display_type, "primary")) + rc = sysfs_create_link(&master->kobj, + &dev->kobj, "main_display"); if (rc) DSI_ERR("failed to create display sysfs attributes\n"); @@ -5239,7 +5245,7 @@ static int dsi_display_bind(struct device *dev, goto error; } - rc = dsi_display_sysfs_init(display); + rc = dsi_display_sysfs_init(display, master); if (rc) goto error; From 7131c0b7ebb2190be6c037ed78f6b3e22dcdeeed Mon Sep 17 00:00:00 2001 From: LuK1337 Date: Thu, 27 Jun 2019 12:30:23 +0200 Subject: [PATCH 230/356] techpack: display: Import FOD changes from OnePlus 6T Change-Id: I0152542579d8bcd3160f1a4b999797a84873f7c8 --- drivers/gpu/drm/drm_internal.h | 7 + drivers/gpu/drm/drm_sysfs.c | 199 ++++++++++ techpack/display/msm/dsi/dsi_defs.h | 10 + techpack/display/msm/dsi/dsi_display.c | 228 +++++++++++ techpack/display/msm/dsi/dsi_display.h | 2 + techpack/display/msm/dsi/dsi_panel.c | 259 +++++++++++++ techpack/display/msm/dsi/dsi_panel.h | 13 + techpack/display/msm/msm_atomic.c | 2 + techpack/display/msm/msm_drv.h | 6 + techpack/display/msm/sde/sde_connector.c | 165 ++++++++ techpack/display/msm/sde/sde_crtc.c | 457 +++++++++++++++++++++++ techpack/display/msm/sde/sde_crtc.h | 3 + techpack/display/msm/sde/sde_encoder.c | 32 +- techpack/display/msm/sde/sde_hw_mdss.h | 7 + techpack/display/msm/sde/sde_plane.c | 12 + 15 files changed, 1401 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h index 8750f3f02b3f..0918ee4baf39 100644 --- a/drivers/gpu/drm/drm_internal.h +++ b/drivers/gpu/drm/drm_internal.h @@ -118,6 +118,13 @@ 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); +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_aod_mode(struct drm_connector *connector, int level); +int dsi_display_get_aod_mode(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); + /* drm_debugfs.c drm_debugfs_crc.c */ #if defined(CONFIG_DEBUG_FS) int drm_debugfs_init(struct drm_minor *minor, int minor_id, diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c index 74857fafb0b8..a4cbf47560d8 100644 --- a/drivers/gpu/drm/drm_sysfs.c +++ b/drivers/gpu/drm/drm_sysfs.c @@ -227,16 +227,215 @@ static ssize_t modes_show(struct device *device, return written; } +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, "%d\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; + + ret = kstrtoint(buf, 10, &hbm_mode); + if (ret) { + pr_err("kstrtoint failed. ret=%d\n", ret); + return ret; + } + + 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 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; + } + printk(KERN_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; +} + + +int oneplus_force_screenfp = 0; +int oneplus_panel_alpha = 0; +extern int oneplus_get_panel_brightness_to_alpha(void); + +static ssize_t oneplus_display_get_dim_alpha(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%d\n", oneplus_get_panel_brightness_to_alpha()); +} + +static ssize_t oneplus_display_set_dim_alpha(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + sscanf(buf, "%x", &oneplus_panel_alpha); + + return count; +} + +static ssize_t oneplus_display_get_forcescreenfp(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 sprintf(buf, "%d\n", oneplus_force_screenfp); + +} + +static ssize_t oneplus_display_set_forcescreenfp(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 = 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; +} + +extern ssize_t oneplus_display_notify_fp_press(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count); + +extern ssize_t oneplus_display_notify_dim(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count); + +extern ssize_t oneplus_display_notify_aod_hid(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t 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(hbm); +static DEVICE_ATTR_RW(op_friginer_print_hbm); +static DEVICE_ATTR_RW(aod); +static DEVICE_ATTR(force_screenfp, S_IRUGO | S_IWUSR, oneplus_display_get_forcescreenfp, oneplus_display_set_forcescreenfp); +static DEVICE_ATTR(notify_fppress, S_IRUGO | S_IWUSR, NULL, oneplus_display_notify_fp_press); +static DEVICE_ATTR(dim_alpha, S_IRUGO | S_IWUSR, oneplus_display_get_dim_alpha, oneplus_display_set_dim_alpha); +static DEVICE_ATTR(notify_dim, S_IRUGO | S_IWUSR, NULL, oneplus_display_notify_dim); +static DEVICE_ATTR(notify_aod, S_IRUGO | S_IWUSR, NULL, oneplus_display_notify_aod_hid); static struct attribute *connector_dev_attrs[] = { &dev_attr_status.attr, &dev_attr_enabled.attr, &dev_attr_dpms.attr, &dev_attr_modes.attr, + &dev_attr_hbm.attr, + &dev_attr_op_friginer_print_hbm.attr, + &dev_attr_aod.attr, + &dev_attr_force_screenfp.attr, + &dev_attr_dim_alpha.attr, + &dev_attr_notify_fppress.attr, + &dev_attr_notify_dim.attr, + &dev_attr_notify_aod.attr, NULL }; diff --git a/techpack/display/msm/dsi/dsi_defs.h b/techpack/display/msm/dsi/dsi_defs.h index 3af6926a2ac5..a75dbe84a1e2 100644 --- a/techpack/display/msm/dsi/dsi_defs.h +++ b/techpack/display/msm/dsi/dsi_defs.h @@ -308,6 +308,7 @@ enum dsi_cmd_set_type { DSI_CMD_SET_QSYNC_ON, DSI_CMD_SET_QSYNC_OFF, DSI_CMD_SET_HBM_OFF, + DSI_CMD_SET_HBM_ON, DSI_CMD_SET_HBM_ON_1, DSI_CMD_SET_HBM_ON_2, DSI_CMD_SET_HBM_ON_3, @@ -317,6 +318,15 @@ enum dsi_cmd_set_type { DSI_CMD_SET_MODE_DCI_P3, DSI_CMD_SET_MODE_WIDE_COLOR, DSI_CMD_SET_MODE_DEFAULT, + DSI_CMD_SET_AOD_ON_1, + DSI_CMD_SET_AOD_ON_2, + DSI_CMD_SET_AOD_OFF, + DSI_CMD_HBM_MAX_BRIGHTNESS_SET_ON, + DSI_CMD_HBM_MAX_BRIGHTNESS_SET_OFF, + DSI_CMD_AOD_OFF_HBM_ON_SETTING, + DSI_CMD_HBM_OFF_AOD_ON_SETTING, + DSI_CMD_SET_AOD_OFF_SAMSUNG, + DSI_CMD_SET_AOD_OFF_NEW, DSI_CMD_SET_MAX }; diff --git a/techpack/display/msm/dsi/dsi_display.c b/techpack/display/msm/dsi/dsi_display.c index 874a73f463db..cc04554c5ad4 100644 --- a/techpack/display/msm/dsi/dsi_display.c +++ b/techpack/display/msm/dsi/dsi_display.c @@ -22,6 +22,7 @@ #include "sde_dbg.h" #include "dsi_parser.h" +#define to_dsi_bridge(x) container_of((x), struct dsi_bridge, base) #define to_dsi_display(x) container_of(x, struct dsi_display, host) #define INT_BASE_10 10 @@ -46,6 +47,8 @@ static const struct of_device_id dsi_display_dt_match[] = { {} }; +static struct dsi_display *primary_display; + static void dsi_display_mask_ctrl_error_interrupts(struct dsi_display *display, u32 mask, bool enable) { @@ -207,6 +210,7 @@ int dsi_display_set_backlight(struct drm_connector *connector, mutex_lock(&panel->panel_lock); if (!dsi_panel_initialized(panel)) { + panel->hbm_backlight = bl_lvl; rc = -EINVAL; goto error; } @@ -6603,6 +6607,7 @@ int dsi_display_get_modes(struct dsi_display *display, exit: *out_modes = display->modes; + primary_display = display; rc = 0; error: @@ -7302,6 +7307,131 @@ static void dsi_display_register_error_handler(struct dsi_display *display) } } +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) { + pr_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) + pr_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) { + pr_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; +} + + +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) { + pr_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) + pr_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) { + pr_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; +} + static void dsi_display_unregister_error_handler(struct dsi_display *display) { int i = 0; @@ -8107,6 +8237,104 @@ int dsi_display_unprepare(struct dsi_display *display) return rc; } +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; + if (strcmp(dsi_display->panel->name, "samsung s6e3fc2x01 cmd mode dsi panel") == 0) { + printk(KERN_ERR "dsi_display_set_aod_mode\n"); + } else { + dsi_display->panel->aod_mode = 0; + return 0; + } + 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) { + pr_err("[%s] failed to enable DSI core clocks, rc=%d\n", + dsi_display->name, rc); + goto error; + } + rc = dsi_panel_set_aod_mode(panel, level); + if (rc) + pr_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) { + pr_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_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; +} + +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(); diff --git a/techpack/display/msm/dsi/dsi_display.h b/techpack/display/msm/dsi/dsi_display.h index 88bca968605e..e5a0208ed5b2 100644 --- a/techpack/display/msm/dsi/dsi_display.h +++ b/techpack/display/msm/dsi/dsi_display.h @@ -735,6 +735,8 @@ int dsi_display_cont_splash_config(void *display); int dsi_display_get_panel_vfp(void *display, int h_active, int v_active); +struct dsi_display *get_main_display(void); + extern int connector_state_crtc_index; extern int msm_drm_notifier_call_chain(unsigned long val, void *v); diff --git a/techpack/display/msm/dsi/dsi_panel.c b/techpack/display/msm/dsi/dsi_panel.c index a9c2c74907f0..d9d76557deda 100644 --- a/techpack/display/msm/dsi/dsi_panel.c +++ b/techpack/display/msm/dsi/dsi_panel.c @@ -753,6 +753,7 @@ int dsi_panel_set_backlight(struct dsi_panel *panel, u32 bl_lvl) 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: @@ -1837,6 +1838,7 @@ const char *cmd_set_prop_map[DSI_CMD_SET_MAX] = { "qcom,mdss-dsi-qsync-off-commands", "qcom,mdss-dsi-panel-hbm-off-command", "qcom,mdss-dsi-panel-hbm-on-command", + "qcom,mdss-dsi-panel-hbm-on-command", "qcom,mdss-dsi-panel-hbm-on-command-2", "qcom,mdss-dsi-panel-hbm-on-command-3", "qcom,mdss-dsi-panel-hbm-on-command-4", @@ -1845,6 +1847,15 @@ const char *cmd_set_prop_map[DSI_CMD_SET_MAX] = { "qcom,mdss-dsi-panel-display-p3-mode-on-command", "qcom,mdss-dsi-panel-display-wide-color-mode-on-command", "qcom,mdss-dsi-panel-dci-p3-off-command", // also disables SRGB and wide color modes + "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-hbm-max-brightness-command-on", + "qcom,mdss-dsi-panel-hbm-max-brightness-command-off", + "qcom,mdss-dsi-panel-aod-off-hbm-on-command", + "qcom,mdss-dsi-panel-hbm-off-aod-on-command", + "qcom,mdss-dsi-panel-aod-off-samsung-command", + "qcom,mdss-dsi-panel-aod-off-new-command", }; const char *cmd_set_state_map[DSI_CMD_SET_MAX] = { @@ -1881,6 +1892,16 @@ const char *cmd_set_state_map[DSI_CMD_SET_MAX] = { "qcom,mdss-dsi-panel-display-p3-mode-on-command-state", "qcom,mdss-dsi-panel-display-wide-color-mode-on-command-state", "qcom,mdss-dsi-panel-dci-p3-off-command-state", + "qcom,mdss-dsi-hbm-on-command-state", + "qcom,mdss-dsi-aod-on-command-state", + "qcom,mdss-dsi-aod-on-command-state", + "qcom,mdss-dsi-aod-off-command-state", + "qcom,mdss-dsi-panel-hbm-max-brightness-command-on-state", + "qcom,mdss-dsi-panel-hbm-max-brightness-command-off-state", + "qcom,mdss-dsi-panel-aod-off-hbm-on-command-state", + "qcom,mdss-dsi-panel-hbm-off-aod-on-command-state", + "qcom,mdss-dsi-panel-aod-off-samsung-command-state", + "qcom,mdss-dsi-panel-aod-off-new-command-state", }; static int dsi_panel_get_cmd_pkt_count(const char *data, u32 length, u32 *cnt) @@ -4521,6 +4542,13 @@ int dsi_panel_enable(struct dsi_panel *panel) dsi_panel_apply_hbm_mode(panel); if (panel->display_mode != DISPLAY_MODE_DEFAULT) dsi_panel_apply_display_mode(panel); + if (panel->aod_mode == 2) { + rc = dsi_panel_set_aod_mode(panel, 2); + panel->aod_status = 1; + } else if (panel->aod_mode == 0) { + rc = dsi_panel_set_aod_mode(panel, 0); + panel->aod_status = 0; + } return rc; } @@ -4570,6 +4598,8 @@ int dsi_panel_pre_disable(struct dsi_panel *panel) return rc; } +bool HBM_flag = false; + int dsi_panel_disable(struct dsi_panel *panel) { int rc = 0; @@ -4579,8 +4609,13 @@ int dsi_panel_disable(struct dsi_panel *panel) return -EINVAL; } + panel->panel_initialized = false; + mutex_lock(&panel->panel_lock); + if (panel->aod_mode == 2) + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_AOD_OFF_SAMSUNG); + /* Avoid sending panel off commands when ESD recovery is underway */ if (!atomic_read(&panel->esd_recovery_pending)) { /* @@ -4592,6 +4627,11 @@ int dsi_panel_disable(struct dsi_panel *panel) panel->power_mode == SDE_MODE_DPMS_LP2)) dsi_pwr_panel_regulator_mode_set(&panel->power_info, "ibb", REGULATOR_MODE_STANDBY); + HBM_flag = false; + if (panel->aod_mode == 2) + panel->aod_status = 1; + else if (panel->aod_mode == 0) + panel->aod_status = 0; rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_OFF); if (rc) { /* @@ -4683,6 +4723,168 @@ int dsi_panel_apply_hbm_mode(struct dsi_panel *panel) 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) { + pr_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) { + pr_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); + printk(KERN_ERR "When HBM OFF -->hbm_backight = %d panel->bl_config.bl_level =%d\n", panel->hbm_backlight, panel->bl_config.bl_level); + rc = dsi_panel_update_backlight(panel,panel->hbm_backlight); + } + break; + + case 1: + count = mode->priv_info->cmd_sets[DSI_CMD_SET_HBM_ON].count; + if (!count) { + pr_err("This panel does not support HBM mode.\n"); + goto error; + } else { + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_HBM_ON); + } + break; + + case 2: + count = mode->priv_info->cmd_sets[DSI_CMD_SET_HBM_ON_2].count; + if (!count) { + pr_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); + } + break; + + case 3: + count = mode->priv_info->cmd_sets[DSI_CMD_SET_HBM_ON_3].count; + if (!count) { + pr_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); + } + break; + + case 4: + count = mode->priv_info->cmd_sets[DSI_CMD_SET_HBM_ON_4].count; + if (!count) { + pr_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); + } + break; + + case 5: + count = mode->priv_info->cmd_sets[DSI_CMD_SET_HBM_ON_5].count; + if (!count) { + pr_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); + } + break; + case 6: + count = mode->priv_info->cmd_sets[DSI_CMD_HBM_MAX_BRIGHTNESS_SET_ON].count; + if (!count) { + pr_err("This panel does not support HBM mode max\n"); + goto error; + } else { + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_HBM_MAX_BRIGHTNESS_SET_ON); + } + break; + case 7: + count = mode->priv_info->cmd_sets[DSI_CMD_HBM_MAX_BRIGHTNESS_SET_OFF].count; + if (!count) { + pr_err("This panel does not support HBM mode max off\n"); + goto error; + } else { + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_HBM_MAX_BRIGHTNESS_SET_OFF); + printk(KERN_ERR "When HBM MAX OFF -->hbm_backight = %d panel->bl_config.bl_level =%d\n", panel->hbm_backlight, panel->bl_config.bl_level); + rc = dsi_panel_update_backlight(panel, panel->hbm_backlight); + } + break; + default: + break; + + } + pr_err("Set HBM Mode = %d\n", level); + if (level == 5) + pr_err("HBM == 5 for fingerprint\n"); + +error: + mutex_unlock(&panel->panel_lock); + + 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) { + pr_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) { + pr_err("This panel does not support HBM mode off.\n"); + goto error; + } else { + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_HBM_OFF); + printk(KERN_ERR "When HBM OFF -->hbm_backight = %d panel->bl_config.bl_level =%d\n", panel->hbm_backlight, panel->bl_config.bl_level); + rc= dsi_panel_update_backlight(panel,panel->hbm_backlight); + } + break; + + case 1: + count = mode->priv_info->cmd_sets[DSI_CMD_SET_HBM_ON_5].count; + if (!count) { + pr_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; + + } + pr_err("Set HBM Mode = %d\n", level); + if (level == 5) + pr_err("HBM == 5 for fingerprint\n"); + +error: + mutex_unlock(&panel->panel_lock); + + return rc; +} + int dsi_panel_apply_display_mode(struct dsi_panel *panel) { enum dsi_cmd_set_type type; @@ -4701,3 +4903,60 @@ int dsi_panel_apply_display_mode(struct dsi_panel *panel) return rc; } + +bool aod_real_flag = false; +bool aod_complete = false; + +int dsi_panel_set_aod_mode(struct dsi_panel *panel, int level) +{ + int rc = 0; + struct dsi_display_mode *mode; + if (!panel || !panel->cur_mode) { + pr_err("Invalid params\n"); + return -EINVAL; + } + if (panel->aod_disable) + return 0; + mode = panel->cur_mode; + if (level == 1) { + if (panel->aod_status == 0) { + printk(KERN_ERR "send AOD ON commd mode 1 start \n"); + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_AOD_ON_1); + printk(KERN_ERR "send AOD ON commd mode 1 end \n"); + panel->aod_status = 1; + } + } else if (level == 2) { + if (panel->aod_status == 0) { + panel->aod_status = 1; + printk(KERN_ERR "send AOD ON commd mode 2 start \n"); + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_AOD_ON_2); + aod_real_flag = false; + aod_complete = true; + printk(KERN_ERR "send AOD ON commd mode 2 end \n"); + + } + } else { + if (panel->aod_status) { + panel->aod_status = 0; + printk(KERN_ERR "send AOD OFF commd start \n"); + if (aod_real_flag) { + printk(KERN_ERR "send DSI_CMD_SET_AOD_OFF \n"); + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_AOD_OFF); + } + if (!aod_real_flag) { + printk(KERN_ERR "send DSI_CMD_SET_AOD_OFF_NEW \n"); + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_AOD_OFF_NEW); + rc = dsi_panel_update_backlight(panel,panel->bl_config.bl_level); + } + if (panel->display_mode != DISPLAY_MODE_DEFAULT) + dsi_panel_apply_display_mode(panel); + + printk(KERN_ERR "send AOD OFF commd end \n"); + aod_complete = false; + } + } + + panel->aod_curr_mode = level; + pr_err("AOD MODE = %d\n", level); +return rc; +} diff --git a/techpack/display/msm/dsi/dsi_panel.h b/techpack/display/msm/dsi/dsi_panel.h index 7465c79216f9..58991db3b988 100644 --- a/techpack/display/msm/dsi/dsi_panel.h +++ b/techpack/display/msm/dsi/dsi_panel.h @@ -215,6 +215,15 @@ struct dsi_panel { int hbm_mode; enum dsi_panel_display_mode display_mode; + int aod_mode; + int aod_status; + int aod_curr_mode; + int aod_disable; + int hbm_backlight; + bool is_hbm_enabled; + int op_force_screenfp; + bool dim_status; + struct dsi_parser_utils utils; bool lp11_init; @@ -360,4 +369,8 @@ void dsi_panel_ext_bridge_put(struct dsi_panel *panel); void dsi_panel_calc_dsi_transfer_time(struct dsi_host_common_cfg *config, struct dsi_display_mode *mode, u32 frame_threshold_us); +int dsi_panel_set_hbm_mode(struct dsi_panel *panel, int level); +int dsi_panel_op_set_hbm_mode(struct dsi_panel *panel, int level); +int dsi_panel_set_aod_mode(struct dsi_panel *panel, int level); + #endif /* _DSI_PANEL_H_ */ diff --git a/techpack/display/msm/msm_atomic.c b/techpack/display/msm/msm_atomic.c index c6c85fe215cf..b8698f563354 100644 --- a/techpack/display/msm/msm_atomic.c +++ b/techpack/display/msm/msm_atomic.c @@ -606,6 +606,8 @@ static void complete_commit(struct msm_commit *c) drm_atomic_state_put(state); + priv->commit_end_time = ktime_get(); + commit_destroy(c); } diff --git a/techpack/display/msm/msm_drv.h b/techpack/display/msm/msm_drv.h index c9902e33fb6b..39cf42921a9f 100644 --- a/techpack/display/msm/msm_drv.h +++ b/techpack/display/msm/msm_drv.h @@ -165,6 +165,7 @@ enum msm_mdp_crtc_property { CRTC_PROP_CAPTURE_OUTPUT, CRTC_PROP_IDLE_PC_STATE, + CRTC_PROP_CUSTOM, /* total # of properties */ CRTC_PROP_COUNT @@ -203,6 +204,8 @@ enum msm_mdp_conn_property { CONNECTOR_PROP_QSYNC_MODE, CONNECTOR_PROP_CMD_FRAME_TRIGGER_MODE, + CONNECTOR_PROP_CUSTOM, + /* total # of properties */ CONNECTOR_PROP_COUNT }; @@ -713,6 +716,9 @@ struct msm_drm_private { bool shutdown_in_progress; struct msm_idle idle; + + /* commit end time */ + ktime_t commit_end_time; }; /* get struct msm_kms * from drm_device * */ diff --git a/techpack/display/msm/sde/sde_connector.c b/techpack/display/msm/sde/sde_connector.c index 35f678373c1d..7a2623471c6c 100644 --- a/techpack/display/msm/sde/sde_connector.c +++ b/techpack/display/msm/sde/sde_connector.c @@ -17,6 +17,7 @@ #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 @@ -690,6 +691,160 @@ static int _sde_connector_update_hdr_metadata(struct sde_connector *c_conn, return rc; } +extern bool sde_crtc_get_fingerprint_mode(struct drm_crtc_state *crtc_state); +static int dsi_panel_tx_cmd_set_op(struct dsi_panel *panel, + enum dsi_cmd_set_type type) +{ + int rc = 0, i = 0; + ssize_t len; + struct dsi_cmd_desc *cmds; + u32 count; + enum dsi_cmd_set_state state; + struct dsi_display_mode *mode; + const struct mipi_dsi_host_ops *ops = panel->host->ops; + + if (!panel || !panel->cur_mode) + return -EINVAL; + + mode = panel->cur_mode; + + cmds = mode->priv_info->cmd_sets[type].cmds; + count = mode->priv_info->cmd_sets[type].count; + state = mode->priv_info->cmd_sets[type].state; + + if (count == 0) { + 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; +} + +extern bool HBM_flag ; +extern int oneplus_dim_status; +extern bool aod_real_flag; +extern bool aod_complete; + +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 (dsi_display->panel->aod_status == 1) { + if (!aod_complete) { + return 0; + } + if (oneplus_dim_status == 5) + fingerprint_mode = false; + else + fingerprint_mode = !!oneplus_dim_status; + } 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); + } + + if (fingerprint_mode != dsi_display->panel->is_hbm_enabled) { + dsi_display->panel->is_hbm_enabled = fingerprint_mode; + if (fingerprint_mode) { + HBM_flag = true; + mutex_lock(&dsi_display->panel->panel_lock); + if (dsi_display->panel->aod_status == 1) { + printk(KERN_ERR "DSI_CMD_AOD_OFF_HBM_ON_SETTING\n"); + rc = dsi_panel_tx_cmd_set_op(dsi_display->panel, DSI_CMD_AOD_OFF_HBM_ON_SETTING); + aod_real_flag = true; + } else { + printk(KERN_ERR "DSI_CMD_SET_HBM_ON_5\n"); + rc = dsi_panel_tx_cmd_set_op(dsi_display->panel, DSI_CMD_SET_HBM_ON_5); + } + SDE_ATRACE_END("set_hbm_on"); + mutex_unlock(&dsi_display->panel->panel_lock); + if (rc) { + pr_err("failed to send DSI_CMD_HBM_ON cmds, rc=%d\n", rc); + return rc; + } + } else { + HBM_flag = false; + mutex_lock(&dsi_display->panel->panel_lock); + if (dsi_display->panel->aod_status == 1) { + if (oneplus_dim_status == 5) { + printk(KERN_ERR "DSI_CMD_SET_HBM_OFF \n"); + rc = dsi_panel_tx_cmd_set_op(dsi_display->panel, DSI_CMD_SET_HBM_OFF); + aod_real_flag = true; + oneplus_dim_status = 0; + + } else { + printk(KERN_ERR "DSI_CMD_HBM_OFF_AOD_ON_SETTING \n"); + rc = dsi_panel_tx_cmd_set_op(dsi_display->panel, DSI_CMD_HBM_OFF_AOD_ON_SETTING); + } + } + else + { + HBM_flag = false; + printk(KERN_ERR "DSI_CMD_SET_HBM_OFF\n"); + rc = dsi_panel_tx_cmd_set_op(dsi_display->panel, DSI_CMD_SET_HBM_OFF); + } + SDE_ATRACE_END("set_hbm_off"); + mutex_unlock(&dsi_display->panel->panel_lock); + _sde_connector_update_bl_scale(c_conn); + if (rc) { + pr_err("failed to send DSI_CMD_HBM_OFF cmds, rc=%d\n", rc); + return rc; + } + } + } + return 0; +} + static int _sde_connector_update_dirty_properties( struct drm_connector *connector) { @@ -797,6 +952,12 @@ int sde_connector_pre_kickoff(struct drm_connector *connector) goto end; } + 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; @@ -2536,6 +2697,10 @@ static int _sde_connector_install_properties(struct drm_device *dev, 0x0, 0, MAX_SV_BL_SCALE_LEVEL, MAX_SV_BL_SCALE_LEVEL, CONNECTOR_PROP_SV_BL_SCALE); + msm_property_install_range(&c_conn->property_info, "CONNECTOR_CUST", + 0x0, 0, INT_MAX, 0, + CONNECTOR_PROP_CUSTOM); + c_conn->bl_scale_dirty = false; c_conn->bl_scale = MAX_BL_SCALE_LEVEL; c_conn->bl_scale_sv = MAX_SV_BL_SCALE_LEVEL; diff --git a/techpack/display/msm/sde/sde_crtc.c b/techpack/display/msm/sde/sde_crtc.c index 602476ba8a4a..617a2f5a3d5b 100644 --- a/techpack/display/msm/sde/sde_crtc.c +++ b/techpack/display/msm/sde/sde_crtc.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -28,6 +29,7 @@ #include #include +#include "dsi_display.h" #include "sde_kms.h" #include "sde_hw_lm.h" #include "sde_hw_ctl.h" @@ -1474,6 +1476,9 @@ static void _sde_crtc_blend_setup_mixer(struct drm_crtc *crtc, for (i = 0; i < cstate->num_dim_layers; i++) _sde_crtc_setup_dim_layer_cfg(crtc, sde_crtc, mixer, &cstate->dim_layer[i]); + if (cstate->fingerprint_dim_layer) + _sde_crtc_setup_dim_layer_cfg(crtc, sde_crtc, + mixer, cstate->fingerprint_dim_layer); } _sde_crtc_program_lm_output_roi(crtc); @@ -2453,6 +2458,8 @@ static void sde_crtc_frame_event_work(struct kthread_work *work) SDE_ATRACE_END("crtc_frame_event"); } +extern int msm_drm_notifier_call_chain(unsigned long val, void *v); + void sde_crtc_complete_commit(struct drm_crtc *crtc, struct drm_crtc_state *old_state) { @@ -2467,6 +2474,30 @@ void sde_crtc_complete_commit(struct drm_crtc *crtc, SDE_EVT32_VERBOSE(DRMID(crtc)); sde_core_perf_crtc_update(crtc, 0, false); + { + struct sde_crtc_state *old_cstate; + struct sde_crtc_state *cstate; + struct msm_drm_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 = ␣ + notifier_data.id = MSM_DRM_PRIMARY_DISPLAY; + pr_err("fingerprint status: %s", + blank ? "pressed" : "up"); + SDE_ATRACE_BEGIN("press_event_notify"); + msm_drm_notifier_call_chain(MSM_DRM_ONSCREENFINGERPRINT_EVENT, + ¬ifier_data); + SDE_ATRACE_END("press_event_notify"); + } + } } /** @@ -2578,6 +2609,285 @@ static void _sde_crtc_set_dim_layer_v1(struct drm_crtc *crtc, } } +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_dim_layer; +} + +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[] = { + {0, 0xff}, + {1, 0xf1}, + {2, 0xec}, + {3, 0xeb}, + {4, 0xea}, + {6, 0xe8}, + {10, 0xe4}, + {20, 0xdc}, + {30, 0xd4}, + {45, 0xcc}, + {70, 0xbe}, + {100, 0xb3}, + {150, 0xa6}, + {227, 0x90}, + {300, 0x83}, + {400, 0x70}, + {500, 0x60}, + {600, 0x53}, + {800, 0x3c}, + {1023, 0x22}, + {2000, 0x83}, +}; + +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 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; + + return brightness_to_alpha(display->panel->hbm_backlight); +} + +int oneplus_onscreenaod_hid = 0; +int oneplus_aod_hid = 0; + +ssize_t oneplus_display_notify_aod_hid(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("oneplus_display_notify_fp_press"); + 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 oneplus_display_notify_fp_press(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct dsi_display *display = get_main_display(); + struct drm_device *drm_dev = display->drm_dev; + struct drm_connector *dsi_connector = display->drm_conn; + struct drm_mode_config *mode_config = &drm_dev->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; + sscanf(buf, "%du", &onscreenfp_status); + onscreenfp_status = !!onscreenfp_status; + if (onscreenfp_status == oneplus_onscreenfp_status) { + SDE_ATRACE_END("oneplus_display_notify_fp_press"); + 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) && 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("oneplus_display_notify_fp_press"); + return count; +} + +extern bool HBM_flag; +int oneplus_dim_status = 0; + +ssize_t oneplus_display_notify_dim(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct dsi_display *display = get_main_display(); + struct drm_device *drm_dev = display->drm_dev; + struct drm_connector *dsi_connector = display->drm_conn; + struct drm_mode_config *mode_config = &drm_dev->mode_config; + struct drm_atomic_state *state; + struct drm_crtc_state *crtc_state; + struct drm_crtc *crtc; + int dim_status = 0; + int err; + sscanf(buf, "%du", &dim_status); + //dim_status = !!dim_status; + pr_err("notify dim %d\n", dim_status); + + if (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("oneplus_display_notify_dim"); + return count; + } else if (display->panel->aod_status == 1 && dim_status == 2) { + oneplus_onscreenfp_status = 1; + } else if (display->panel->aod_status == 1 && dim_status == 0) { + oneplus_onscreenfp_status = 0; + } + + if (dim_status == oneplus_dim_status) + return count; + oneplus_dim_status = dim_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); + if ((oneplus_dim_status != 0) && + !(oneplus_dim_status == 5 && display->panel->aod_status == 0)) { + err = drm_atomic_commit(state); + if (err < 0) + drm_atomic_state_clear(state); + } + drm_modeset_unlock_all(drm_dev); + SDE_ATRACE_END("oneplus_display_notify_dim"); + 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; + + kms = _sde_crtc_get_kms(crtc_state->crtc); + + if (!kms || !kms->catalog) { + SDE_ERROR("invalid kms\n"); + return -EINVAL; + } + + 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 @@ -4770,6 +5080,145 @@ static int _sde_crtc_check_zpos(struct drm_crtc_state *state, return rc; } +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 zpos = INT_MAX; + int mode; + int fp_mode = oneplus_onscreenfp_status; + int dim_mode = oneplus_dim_status; + int aod_mode = -1; + int i; + struct dsi_display *display = get_main_display(); + + if (!display) + 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) { + fp_mode = 1; + dim_mode = 0; + } + } + + if (oneplus_onscreenaod_hid && oneplus_dim_status == 5) + oneplus_aod_hid = 1; + 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; + else if (mode == 2) + fppressed_index = i; + else if (mode == 3) + aod_index = i; + } + + if (fp_index >=0) + display->panel->dim_status = true; + else + display->panel->dim_status = false; + + if (aod_index <0) + oneplus_aod_hid = 0; + + if (fp_index >= 0 || fppressed_index >= 0 || oneplus_force_screenfp) { + 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 (fp_mode == 0) { + pstates[fppressed_index].sde_pstate->property_values[PLANE_PROP_ALPHA].value = 0; + fppressed_index = -1; + } else { + pstates[fppressed_index].sde_pstate->property_values[PLANE_PROP_ALPHA].value = 0xff; + } + } + if (fp_index >= 0) { + if (dim_mode == 0) { + pstates[fp_index].sde_pstate->property_values[PLANE_PROP_ALPHA].value = 0; + fp_index = -1; + } else { + pstates[fp_index].sde_pstate->property_values[PLANE_PROP_ALPHA].value = 0xff; + } + } + + if (aod_index >= 0) { + if (aod_mode == 1) { + 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 (aod_index >= 0) { + if (zpos > pstates[aod_index].stage) + zpos = pstates[aod_index].stage; + pstates[aod_index].stage++; + } + + 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 || i == aod_index) + continue; + + if (pstates[i].stage >= zpos) + 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 && 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; + } + + if (fp_index < 0) + cstate->fingerprint_dim_layer = NULL; + + if (fppressed_index < 0) + cstate->fingerprint_pressed = false; + + return 0; +} + static int _sde_crtc_atomic_check_pstates(struct drm_crtc *crtc, struct drm_crtc_state *state, struct plane_state *pstates, @@ -4799,6 +5248,10 @@ static int _sde_crtc_atomic_check_pstates(struct drm_crtc *crtc, 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) @@ -5125,6 +5578,10 @@ static void sde_crtc_install_properties(struct drm_crtc *crtc, "idle_time", 0, 0, U64_MAX, 0, CRTC_PROP_IDLE_TIMEOUT); + msm_property_install_range(&sde_crtc->property_info, + "CRTC_CUST", 0, 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, diff --git a/techpack/display/msm/sde/sde_crtc.h b/techpack/display/msm/sde/sde_crtc.h index bd16cd3da6fe..2269452dfff7 100644 --- a/techpack/display/msm/sde/sde_crtc.h +++ b/techpack/display/msm/sde/sde_crtc.h @@ -439,6 +439,9 @@ struct sde_crtc_state { struct sde_core_perf_params new_perf; int secure_session; + + bool fingerprint_pressed; + struct sde_hw_dim_layer *fingerprint_dim_layer; }; enum sde_crtc_irq_state { diff --git a/techpack/display/msm/sde/sde_encoder.c b/techpack/display/msm/sde/sde_encoder.c index cbb8b5b87bbc..ee212f82b36a 100644 --- a/techpack/display/msm/sde/sde_encoder.c +++ b/techpack/display/msm/sde/sde_encoder.c @@ -4474,6 +4474,35 @@ void sde_encoder_trigger_kickoff_pending(struct drm_encoder *drm_enc) sde_enc->idle_pc_restore = false; } +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, + 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 = 6; + dither.c1_bitdepth = 6; + dither.c2_bitdepth = 6; + dither.c3_bitdepth = 6; + dither.temporal_en = 1; + + phys->hw_pp->ops.setup_dither(phys->hw_pp, &dither, len); + + return 0; +} + static void _sde_encoder_setup_dither(struct sde_encoder_phys *phys) { void *dither_cfg; @@ -4517,7 +4546,8 @@ static void _sde_encoder_setup_dither(struct sde_encoder_phys *phys) } } } else { - phys->hw_pp->ops.setup_dither(phys->hw_pp, dither_cfg, len); + if (_sde_encoder_setup_dither_for_onscreenfingerprint(phys, dither_cfg, len)) + phys->hw_pp->ops.setup_dither(phys->hw_pp, dither_cfg, len); } } diff --git a/techpack/display/msm/sde/sde_hw_mdss.h b/techpack/display/msm/sde/sde_hw_mdss.h index 15f0b91d3c2a..c12a58536f8b 100644 --- a/techpack/display/msm/sde/sde_hw_mdss.h +++ b/techpack/display/msm/sde/sde_hw_mdss.h @@ -568,6 +568,13 @@ struct sde_hw_dim_layer { struct sde_rect rect; }; +struct fingerprint_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 diff --git a/techpack/display/msm/sde/sde_plane.c b/techpack/display/msm/sde/sde_plane.c index 3e83fb961cd5..574b05d7348b 100644 --- a/techpack/display/msm/sde/sde_plane.c +++ b/techpack/display/msm/sde/sde_plane.c @@ -1665,6 +1665,18 @@ void sde_plane_clear_multirect(const struct drm_plane_state *drm_state) pstate->multirect_mode = SDE_SSPP_MULTIRECT_NONE; } +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 From e3fbed25851abf0359d2fd7b3d21fb36cc54400b Mon Sep 17 00:00:00 2001 From: Danny Baumann Date: Tue, 12 Nov 2019 12:50:32 +0100 Subject: [PATCH 231/356] techpack: display: Deduplicate HBM code. Change-Id: Iefb5dd3589a61e368d622ec05ac7c1e40dd36685 --- techpack/display/msm/dsi/dsi_defs.h | 3 +- techpack/display/msm/dsi/dsi_display.c | 20 ++- techpack/display/msm/dsi/dsi_panel.c | 176 +---------------------- techpack/display/msm/dsi/dsi_panel.h | 3 +- techpack/display/msm/sde/sde_connector.c | 4 - 5 files changed, 25 insertions(+), 181 deletions(-) diff --git a/techpack/display/msm/dsi/dsi_defs.h b/techpack/display/msm/dsi/dsi_defs.h index a75dbe84a1e2..a4094c461dd0 100644 --- a/techpack/display/msm/dsi/dsi_defs.h +++ b/techpack/display/msm/dsi/dsi_defs.h @@ -314,6 +314,7 @@ enum dsi_cmd_set_type { DSI_CMD_SET_HBM_ON_3, DSI_CMD_SET_HBM_ON_4, DSI_CMD_SET_HBM_ON_5, + DSI_CMD_SET_HBM_ON_6, DSI_CMD_SET_MODE_SRGB, DSI_CMD_SET_MODE_DCI_P3, DSI_CMD_SET_MODE_WIDE_COLOR, @@ -321,8 +322,6 @@ enum dsi_cmd_set_type { DSI_CMD_SET_AOD_ON_1, DSI_CMD_SET_AOD_ON_2, DSI_CMD_SET_AOD_OFF, - DSI_CMD_HBM_MAX_BRIGHTNESS_SET_ON, - DSI_CMD_HBM_MAX_BRIGHTNESS_SET_OFF, DSI_CMD_AOD_OFF_HBM_ON_SETTING, DSI_CMD_HBM_OFF_AOD_ON_SETTING, DSI_CMD_SET_AOD_OFF_SAMSUNG, diff --git a/techpack/display/msm/dsi/dsi_display.c b/techpack/display/msm/dsi/dsi_display.c index cc04554c5ad4..3327f3b87573 100644 --- a/techpack/display/msm/dsi/dsi_display.c +++ b/techpack/display/msm/dsi/dsi_display.c @@ -7325,6 +7325,11 @@ int dsi_display_set_hbm_mode(struct drm_connector *connector, int level) if ((dsi_display == NULL) || (dsi_display->panel == NULL)) return -EINVAL; + if (level == 7) { + // For some reason, OnePlus' user space treats 0 and 7 the same + level = 0; + } + panel = dsi_display->panel; mutex_lock(&dsi_display->display_lock); @@ -7342,10 +7347,15 @@ int dsi_display_set_hbm_mode(struct drm_connector *connector, int level) goto error; } - rc = dsi_panel_set_hbm_mode(panel, level); + rc = dsi_panel_apply_hbm_mode(panel); if (rc) pr_err("unable to set hbm mode\n"); + if (level == 0) { + printk(KERN_ERR "When HBM OFF -->hbm_backight = %d panel->bl_config.bl_level =%d\n", panel->hbm_backlight, panel->bl_config.bl_level); + dsi_panel_update_backlight(panel,panel->hbm_backlight); + } + rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, DSI_CORE_CLK, DSI_CLK_OFF); if (rc) { @@ -7402,6 +7412,7 @@ int dsi_display_set_fp_hbm_mode(struct drm_connector *connector, int level) mutex_lock(&dsi_display->display_lock); + panel->hbm_mode = level > 0 ? 5 : 0; panel->op_force_screenfp = level; oneplus_force_screenfp=panel->op_force_screenfp; @@ -7416,10 +7427,15 @@ int dsi_display_set_fp_hbm_mode(struct drm_connector *connector, int level) goto error; } - rc = dsi_panel_op_set_hbm_mode(panel, level); + rc = dsi_panel_apply_hbm_mode(panel); if (rc) pr_err("unable to set hbm mode\n"); + if (level == 0) { + printk(KERN_ERR "When HBM OFF -->hbm_backight = %d panel->bl_config.bl_level =%d\n", panel->hbm_backlight, panel->bl_config.bl_level); + dsi_panel_update_backlight(panel,panel->hbm_backlight); + } + rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, DSI_CORE_CLK, DSI_CLK_OFF); if (rc) { diff --git a/techpack/display/msm/dsi/dsi_panel.c b/techpack/display/msm/dsi/dsi_panel.c index d9d76557deda..c731bf4dbe39 100644 --- a/techpack/display/msm/dsi/dsi_panel.c +++ b/techpack/display/msm/dsi/dsi_panel.c @@ -654,7 +654,7 @@ static int dsi_panel_dcs_set_display_brightness_c2(struct mipi_dsi_device *dsi, -static int dsi_panel_update_backlight(struct dsi_panel *panel, +int dsi_panel_update_backlight(struct dsi_panel *panel, u32 bl_lvl) { int rc = 0; @@ -1843,6 +1843,7 @@ const char *cmd_set_prop_map[DSI_CMD_SET_MAX] = { "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-max-brightness-command-on", "qcom,mdss-dsi-panel-display-srgb-color-mode-on-command", "qcom,mdss-dsi-panel-display-p3-mode-on-command", "qcom,mdss-dsi-panel-display-wide-color-mode-on-command", @@ -1850,8 +1851,6 @@ const char *cmd_set_prop_map[DSI_CMD_SET_MAX] = { "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-hbm-max-brightness-command-on", - "qcom,mdss-dsi-panel-hbm-max-brightness-command-off", "qcom,mdss-dsi-panel-aod-off-hbm-on-command", "qcom,mdss-dsi-panel-hbm-off-aod-on-command", "qcom,mdss-dsi-panel-aod-off-samsung-command", @@ -1888,6 +1887,7 @@ const char *cmd_set_state_map[DSI_CMD_SET_MAX] = { "qcom,mdss-dsi-hbm-on-command-state", "qcom,mdss-dsi-hbm-on-command-state", "qcom,mdss-dsi-hbm-on-command-state", + "qcom,mdss-dsi-panel-hbm-max-brightness-command-on-state", "qcom,mdss-dsi-panel-display-srgb-color-mode-on-command-state", "qcom,mdss-dsi-panel-display-p3-mode-on-command-state", "qcom,mdss-dsi-panel-display-wide-color-mode-on-command-state", @@ -1896,8 +1896,6 @@ const char *cmd_set_state_map[DSI_CMD_SET_MAX] = { "qcom,mdss-dsi-aod-on-command-state", "qcom,mdss-dsi-aod-on-command-state", "qcom,mdss-dsi-aod-off-command-state", - "qcom,mdss-dsi-panel-hbm-max-brightness-command-on-state", - "qcom,mdss-dsi-panel-hbm-max-brightness-command-off-state", "qcom,mdss-dsi-panel-aod-off-hbm-on-command-state", "qcom,mdss-dsi-panel-hbm-off-aod-on-command-state", "qcom,mdss-dsi-panel-aod-off-samsung-command-state", @@ -4598,8 +4596,6 @@ int dsi_panel_pre_disable(struct dsi_panel *panel) return rc; } -bool HBM_flag = false; - int dsi_panel_disable(struct dsi_panel *panel) { int rc = 0; @@ -4627,7 +4623,6 @@ int dsi_panel_disable(struct dsi_panel *panel) panel->power_mode == SDE_MODE_DPMS_LP2)) dsi_pwr_panel_regulator_mode_set(&panel->power_info, "ibb", REGULATOR_MODE_STANDBY); - HBM_flag = false; if (panel->aod_mode == 2) panel->aod_status = 1; else if (panel->aod_mode == 0) @@ -4705,7 +4700,8 @@ int dsi_panel_apply_hbm_mode(struct dsi_panel *panel) 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_ON_5, + DSI_CMD_SET_HBM_ON_6, }; enum dsi_cmd_set_type type; @@ -4723,168 +4719,6 @@ int dsi_panel_apply_hbm_mode(struct dsi_panel *panel) 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) { - pr_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) { - pr_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); - printk(KERN_ERR "When HBM OFF -->hbm_backight = %d panel->bl_config.bl_level =%d\n", panel->hbm_backlight, panel->bl_config.bl_level); - rc = dsi_panel_update_backlight(panel,panel->hbm_backlight); - } - break; - - case 1: - count = mode->priv_info->cmd_sets[DSI_CMD_SET_HBM_ON].count; - if (!count) { - pr_err("This panel does not support HBM mode.\n"); - goto error; - } else { - rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_HBM_ON); - } - break; - - case 2: - count = mode->priv_info->cmd_sets[DSI_CMD_SET_HBM_ON_2].count; - if (!count) { - pr_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); - } - break; - - case 3: - count = mode->priv_info->cmd_sets[DSI_CMD_SET_HBM_ON_3].count; - if (!count) { - pr_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); - } - break; - - case 4: - count = mode->priv_info->cmd_sets[DSI_CMD_SET_HBM_ON_4].count; - if (!count) { - pr_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); - } - break; - - case 5: - count = mode->priv_info->cmd_sets[DSI_CMD_SET_HBM_ON_5].count; - if (!count) { - pr_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); - } - break; - case 6: - count = mode->priv_info->cmd_sets[DSI_CMD_HBM_MAX_BRIGHTNESS_SET_ON].count; - if (!count) { - pr_err("This panel does not support HBM mode max\n"); - goto error; - } else { - rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_HBM_MAX_BRIGHTNESS_SET_ON); - } - break; - case 7: - count = mode->priv_info->cmd_sets[DSI_CMD_HBM_MAX_BRIGHTNESS_SET_OFF].count; - if (!count) { - pr_err("This panel does not support HBM mode max off\n"); - goto error; - } else { - rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_HBM_MAX_BRIGHTNESS_SET_OFF); - printk(KERN_ERR "When HBM MAX OFF -->hbm_backight = %d panel->bl_config.bl_level =%d\n", panel->hbm_backlight, panel->bl_config.bl_level); - rc = dsi_panel_update_backlight(panel, panel->hbm_backlight); - } - break; - default: - break; - - } - pr_err("Set HBM Mode = %d\n", level); - if (level == 5) - pr_err("HBM == 5 for fingerprint\n"); - -error: - mutex_unlock(&panel->panel_lock); - - 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) { - pr_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) { - pr_err("This panel does not support HBM mode off.\n"); - goto error; - } else { - rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_HBM_OFF); - printk(KERN_ERR "When HBM OFF -->hbm_backight = %d panel->bl_config.bl_level =%d\n", panel->hbm_backlight, panel->bl_config.bl_level); - rc= dsi_panel_update_backlight(panel,panel->hbm_backlight); - } - break; - - case 1: - count = mode->priv_info->cmd_sets[DSI_CMD_SET_HBM_ON_5].count; - if (!count) { - pr_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; - - } - pr_err("Set HBM Mode = %d\n", level); - if (level == 5) - pr_err("HBM == 5 for fingerprint\n"); - -error: - mutex_unlock(&panel->panel_lock); - - return rc; -} - int dsi_panel_apply_display_mode(struct dsi_panel *panel) { enum dsi_cmd_set_type type; diff --git a/techpack/display/msm/dsi/dsi_panel.h b/techpack/display/msm/dsi/dsi_panel.h index 58991db3b988..7a2b0cdd160c 100644 --- a/techpack/display/msm/dsi/dsi_panel.h +++ b/techpack/display/msm/dsi/dsi_panel.h @@ -369,8 +369,7 @@ void dsi_panel_ext_bridge_put(struct dsi_panel *panel); void dsi_panel_calc_dsi_transfer_time(struct dsi_host_common_cfg *config, struct dsi_display_mode *mode, u32 frame_threshold_us); -int dsi_panel_set_hbm_mode(struct dsi_panel *panel, int level); -int dsi_panel_op_set_hbm_mode(struct dsi_panel *panel, int level); int dsi_panel_set_aod_mode(struct dsi_panel *panel, int level); +int dsi_panel_update_backlight(struct dsi_panel *panel, u32 bl_lvl); #endif /* _DSI_PANEL_H_ */ diff --git a/techpack/display/msm/sde/sde_connector.c b/techpack/display/msm/sde/sde_connector.c index 7a2623471c6c..d3faa370b1ff 100644 --- a/techpack/display/msm/sde/sde_connector.c +++ b/techpack/display/msm/sde/sde_connector.c @@ -740,7 +740,6 @@ static int dsi_panel_tx_cmd_set_op(struct dsi_panel *panel, return rc; } -extern bool HBM_flag ; extern int oneplus_dim_status; extern bool aod_real_flag; extern bool aod_complete; @@ -796,7 +795,6 @@ static int _sde_connector_update_hbm(struct sde_connector *c_conn) if (fingerprint_mode != dsi_display->panel->is_hbm_enabled) { dsi_display->panel->is_hbm_enabled = fingerprint_mode; if (fingerprint_mode) { - HBM_flag = true; mutex_lock(&dsi_display->panel->panel_lock); if (dsi_display->panel->aod_status == 1) { printk(KERN_ERR "DSI_CMD_AOD_OFF_HBM_ON_SETTING\n"); @@ -813,7 +811,6 @@ static int _sde_connector_update_hbm(struct sde_connector *c_conn) return rc; } } else { - HBM_flag = false; mutex_lock(&dsi_display->panel->panel_lock); if (dsi_display->panel->aod_status == 1) { if (oneplus_dim_status == 5) { @@ -829,7 +826,6 @@ static int _sde_connector_update_hbm(struct sde_connector *c_conn) } else { - HBM_flag = false; printk(KERN_ERR "DSI_CMD_SET_HBM_OFF\n"); rc = dsi_panel_tx_cmd_set_op(dsi_display->panel, DSI_CMD_SET_HBM_OFF); } From c2b1c50ef4266b6244dff10517de63272a142ab6 Mon Sep 17 00:00:00 2001 From: LuK1337 Date: Wed, 8 Jan 2020 15:13:50 +0100 Subject: [PATCH 232/356] techpack: display: Import OnePlus dsi_ctrl_hw_2_2.c changes --- techpack/display/msm/dsi/dsi_ctrl_hw_2_2.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/techpack/display/msm/dsi/dsi_ctrl_hw_2_2.c b/techpack/display/msm/dsi/dsi_ctrl_hw_2_2.c index 56821e857a91..864094315531 100644 --- a/techpack/display/msm/dsi/dsi_ctrl_hw_2_2.c +++ b/techpack/display/msm/dsi/dsi_ctrl_hw_2_2.c @@ -8,7 +8,8 @@ #include "dsi_hw.h" #include "dsi_catalog.h" -#define DISP_CC_MISC_CMD_REG_OFF 0x00 +#define DISP_CC_MISC_CMD_REG_OFF 0x5000 +#define DISP_CC_CORE_GDSCR 0x00 /* register to configure DMA scheduling */ #define DSI_DMA_SCHEDULE_CTRL 0x100 @@ -26,14 +27,20 @@ void dsi_ctrl_hw_22_phy_reset_config(struct dsi_ctrl_hw *ctrl, bool enable) { u32 reg = 0; + u32 gdscr_reg = 0; reg = DSI_DISP_CC_R32(ctrl, DISP_CC_MISC_CMD_REG_OFF); /* Mask/unmask disable PHY reset bit */ - if (enable) + if (enable) { reg &= ~BIT(ctrl->index); - else + /* Enable GDSC retention flops during idle exit */ + gdscr_reg = DSI_DISP_CC_R32(ctrl, DISP_CC_CORE_GDSCR); + gdscr_reg |= BIT(11); + DSI_DISP_CC_W32(ctrl, DISP_CC_CORE_GDSCR, gdscr_reg); + } else { reg |= BIT(ctrl->index); + } DSI_DISP_CC_W32(ctrl, DISP_CC_MISC_CMD_REG_OFF, reg); } From 3c3aa916d8c8c0e76d643aed4645ea9f63026810 Mon Sep 17 00:00:00 2001 From: Danny Baumann Date: Thu, 9 Jan 2020 09:26:57 +0100 Subject: [PATCH 233/356] techpack: display: Apply display mode commands after taking over display from cont splash This matches what is done after enabling the panel. Change-Id: I4a3e2a29f97f008fcfe99bb0b7ecbc62b6c4a42d --- techpack/display/msm/dsi/dsi_display.c | 1 + techpack/display/msm/dsi/dsi_panel.c | 9 +++++++++ techpack/display/msm/dsi/dsi_panel.h | 2 ++ 3 files changed, 12 insertions(+) diff --git a/techpack/display/msm/dsi/dsi_display.c b/techpack/display/msm/dsi/dsi_display.c index 3327f3b87573..90de57a6e814 100644 --- a/techpack/display/msm/dsi/dsi_display.c +++ b/techpack/display/msm/dsi/dsi_display.c @@ -7926,6 +7926,7 @@ int dsi_display_enable(struct dsi_display *display) } display->panel->panel_initialized = true; + dsi_panel_init_display_modes(display->panel); DSI_DEBUG("cont splash enabled, display enable not required\n"); return 0; } diff --git a/techpack/display/msm/dsi/dsi_panel.c b/techpack/display/msm/dsi/dsi_panel.c index c731bf4dbe39..bb20f3a025d6 100644 --- a/techpack/display/msm/dsi/dsi_panel.c +++ b/techpack/display/msm/dsi/dsi_panel.c @@ -4536,6 +4536,15 @@ int dsi_panel_enable(struct dsi_panel *panel) panel->panel_initialized = true; mutex_unlock(&panel->panel_lock); + dsi_panel_init_display_modes(panel); + + return rc; +} + +int dsi_panel_init_display_modes(struct dsi_panel *panel) +{ + int rc; + if (panel->hbm_mode) dsi_panel_apply_hbm_mode(panel); if (panel->display_mode != DISPLAY_MODE_DEFAULT) diff --git a/techpack/display/msm/dsi/dsi_panel.h b/techpack/display/msm/dsi/dsi_panel.h index 7a2b0cdd160c..37777ad3fe5c 100644 --- a/techpack/display/msm/dsi/dsi_panel.h +++ b/techpack/display/msm/dsi/dsi_panel.h @@ -321,6 +321,8 @@ int dsi_panel_enable(struct dsi_panel *panel); int dsi_panel_post_enable(struct dsi_panel *panel); +int dsi_panel_init_display_modes(struct dsi_panel *panel); + int dsi_panel_pre_disable(struct dsi_panel *panel); int dsi_panel_disable(struct dsi_panel *panel); From c262ebf5a23c59a74ca7a9476776bcb2d78d68a6 Mon Sep 17 00:00:00 2001 From: Danny Baumann Date: Thu, 30 Jan 2020 11:25:12 +0100 Subject: [PATCH 234/356] techpack: display: Apply display mode unconditionally after turning on panel. Since setting up the default display mode isn't part of the init sequence, we need to apply the display mode even if it's set to default. Change-Id: Iba23794c49dbfa52f9290cef8949c0284baa4a83 --- techpack/display/msm/dsi/dsi_panel.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/techpack/display/msm/dsi/dsi_panel.c b/techpack/display/msm/dsi/dsi_panel.c index bb20f3a025d6..16de17b7c004 100644 --- a/techpack/display/msm/dsi/dsi_panel.c +++ b/techpack/display/msm/dsi/dsi_panel.c @@ -4547,8 +4547,7 @@ int dsi_panel_init_display_modes(struct dsi_panel *panel) if (panel->hbm_mode) dsi_panel_apply_hbm_mode(panel); - if (panel->display_mode != DISPLAY_MODE_DEFAULT) - dsi_panel_apply_display_mode(panel); + dsi_panel_apply_display_mode(panel); if (panel->aod_mode == 2) { rc = dsi_panel_set_aod_mode(panel, 2); panel->aod_status = 1; From b63719d2f11f5dfac6204fe5737176004514f4ee Mon Sep 17 00:00:00 2001 From: jabashque Date: Sun, 5 Apr 2020 17:33:35 -0700 Subject: [PATCH 235/356] techpack: display: Actually restore brightness val when turning off HBM via sysfs It seems that in some Samsung s6e3fc2x01 panels (used in fajita), sending the command to turn off high brightness mode results in the panel returning to some brightness value in the middle between max and min brightness. The dsi_display_set_hbm_mode() function already calls dsi_panel_update_backlight() to set the brightness to the right value after turning off HBM, but sysfs_hbm_write() calls dsi_panel_apply_hbm_mode() by itself and doesn't rely on dsi_display_set_hbm_mode(), so sysfs_hbm_write() also needs to manually set the brightness. Change-Id: Ia374b0f924330ce962c16635d4c3afd4b4d436ef --- techpack/display/msm/dsi/dsi_display.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/techpack/display/msm/dsi/dsi_display.c b/techpack/display/msm/dsi/dsi_display.c index 90de57a6e814..b8adb9252a92 100644 --- a/techpack/display/msm/dsi/dsi_display.c +++ b/techpack/display/msm/dsi/dsi_display.c @@ -5062,6 +5062,13 @@ static ssize_t sysfs_hbm_write(struct device *dev, if (ret) pr_err("unable to set hbm mode\n"); + if (hbm_mode == 0) { + /* hbm off cmd in some Samsung s6e3fc2x01 panels sets brightness to an + * arbitrary value; setting it to the right value needs to be done + * separately */ + dsi_panel_update_backlight(display->panel,display->panel->hbm_backlight); + } + ret = dsi_display_clk_ctrl(display->dsi_clk_handle, DSI_CORE_CLK, DSI_CLK_OFF); if (ret) { From 3e0b3b37810fdf80418911702b8a6c2db01cbc91 Mon Sep 17 00:00:00 2001 From: LuK1337 Date: Wed, 27 May 2020 13:08:05 +0200 Subject: [PATCH 236/356] techpack: display: Update FOD related code from Q OOS release Change-Id: I2ffc2f0e1aecc64ff72beb78f97d47995600ad92 --- techpack/display/msm/dsi/dsi_panel.c | 4 + techpack/display/msm/sde/sde_connector.c | 41 +++--- techpack/display/msm/sde/sde_crtc.c | 174 +++++++++++++++-------- techpack/display/msm/sde/sde_crtc.h | 1 + 4 files changed, 139 insertions(+), 81 deletions(-) diff --git a/techpack/display/msm/dsi/dsi_panel.c b/techpack/display/msm/dsi/dsi_panel.c index 16de17b7c004..d6ccad0ac9cc 100644 --- a/techpack/display/msm/dsi/dsi_panel.c +++ b/techpack/display/msm/dsi/dsi_panel.c @@ -654,6 +654,8 @@ static int dsi_panel_dcs_set_display_brightness_c2(struct mipi_dsi_device *dsi, +bool HBM_flag; + int dsi_panel_update_backlight(struct dsi_panel *panel, u32 bl_lvl) { @@ -676,6 +678,8 @@ int dsi_panel_update_backlight(struct dsi_panel *panel, rc = dsi_panel_dcs_set_display_brightness_c2(dsi, bl_lvl); else { if (panel->bl_config.bl_high2bit) { + if (HBM_flag == true) + return 0; rc = mipi_dsi_dcs_set_display_brightness_samsung(dsi, bl_lvl); } else { rc = mipi_dsi_dcs_set_display_brightness(dsi, bl_lvl); diff --git a/techpack/display/msm/sde/sde_connector.c b/techpack/display/msm/sde/sde_connector.c index d3faa370b1ff..0edad9044ccc 100644 --- a/techpack/display/msm/sde/sde_connector.c +++ b/techpack/display/msm/sde/sde_connector.c @@ -740,6 +740,8 @@ static int dsi_panel_tx_cmd_set_op(struct dsi_panel *panel, return rc; } +int aod_layer_hide; +extern bool HBM_flag; extern int oneplus_dim_status; extern bool aod_real_flag; extern bool aod_complete; @@ -750,7 +752,7 @@ static int _sde_connector_update_hbm(struct sde_connector *c_conn) struct dsi_display *dsi_display; struct sde_connector_state *c_state; int rc = 0; - int fingerprint_mode; + int fingerprint_mode = 0; if (!c_conn) { SDE_ERROR("Invalid params sde_connector null\n"); @@ -775,14 +777,12 @@ static int _sde_connector_update_hbm(struct sde_connector *c_conn) return 0; } + // vikas.kala@MULTIMEDIA, 2019/09/20, [EIDQ-4842] Hide Aod Layer before HBM if (dsi_display->panel->aod_status == 1) { - if (!aod_complete) { - return 0; - } - if (oneplus_dim_status == 5) + if (!(sde_crtc_get_fingerprint_mode(c_conn->encoder->crtc->state))) fingerprint_mode = false; else - fingerprint_mode = !!oneplus_dim_status; + 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; @@ -795,45 +795,50 @@ static int _sde_connector_update_hbm(struct sde_connector *c_conn) if (fingerprint_mode != dsi_display->panel->is_hbm_enabled) { dsi_display->panel->is_hbm_enabled = fingerprint_mode; if (fingerprint_mode) { + HBM_flag = true; + SDE_ATRACE_BEGIN("set_hbm_on"); mutex_lock(&dsi_display->panel->panel_lock); if (dsi_display->panel->aod_status == 1) { - printk(KERN_ERR "DSI_CMD_AOD_OFF_HBM_ON_SETTING\n"); + pr_err("Send DSI_CMD_AOD_OFF_HBM_ON_SETTING cmds\n"); rc = dsi_panel_tx_cmd_set_op(dsi_display->panel, DSI_CMD_AOD_OFF_HBM_ON_SETTING); aod_real_flag = true; } else { - printk(KERN_ERR "DSI_CMD_SET_HBM_ON_5\n"); + pr_err("DSI_CMD_SET_HBM_ON_5\n"); rc = dsi_panel_tx_cmd_set_op(dsi_display->panel, DSI_CMD_SET_HBM_ON_5); } - SDE_ATRACE_END("set_hbm_on"); + mutex_unlock(&dsi_display->panel->panel_lock); + SDE_ATRACE_END("set_hbm_on"); if (rc) { - pr_err("failed to send DSI_CMD_HBM_ON cmds, rc=%d\n", rc); + pr_err("failed to send DSI_CMD_HBM_ON rc=%d\n", rc); return rc; } } else { + SDE_ATRACE_BEGIN("set_hbm_off"); + HBM_flag = false; mutex_lock(&dsi_display->panel->panel_lock); if (dsi_display->panel->aod_status == 1) { if (oneplus_dim_status == 5) { - printk(KERN_ERR "DSI_CMD_SET_HBM_OFF \n"); rc = dsi_panel_tx_cmd_set_op(dsi_display->panel, DSI_CMD_SET_HBM_OFF); + pr_err("Send DSI_CMD_SET_HBM_OFF cmds\n"); aod_real_flag = true; oneplus_dim_status = 0; - + aod_layer_hide = 1; } else { - printk(KERN_ERR "DSI_CMD_HBM_OFF_AOD_ON_SETTING \n"); rc = dsi_panel_tx_cmd_set_op(dsi_display->panel, DSI_CMD_HBM_OFF_AOD_ON_SETTING); + pr_err("Send DSI_CMD_HBM_OFF_AOD_ON_SETTING cmds\n"); } - } - else - { - printk(KERN_ERR "DSI_CMD_SET_HBM_OFF\n"); + } else { + HBM_flag = false; + pr_info("DSI_CMD_SET_HBM_OFF\n"); rc = dsi_panel_tx_cmd_set_op(dsi_display->panel, DSI_CMD_SET_HBM_OFF); + //oneplus_dim_status = 0; } 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); + pr_err("failed to send DSI_CMD_HBM_OFF rc=%d\n", rc); return rc; } } diff --git a/techpack/display/msm/sde/sde_crtc.c b/techpack/display/msm/sde/sde_crtc.c index 617a2f5a3d5b..e660eb54bc3c 100644 --- a/techpack/display/msm/sde/sde_crtc.c +++ b/techpack/display/msm/sde/sde_crtc.c @@ -2617,7 +2617,7 @@ bool sde_crtc_get_fingerprint_mode(struct drm_crtc_state *crtc_state) return false; cstate = to_sde_crtc_state(crtc_state); - return !!cstate->fingerprint_dim_layer; + return !!cstate->fingerprint_mode; } bool sde_crtc_get_fingerprint_pressed(struct drm_crtc_state *crtc_state) @@ -2789,6 +2789,9 @@ ssize_t oneplus_display_notify_fp_press(struct device *dev, } extern bool HBM_flag; +extern int aod_layer_hide; +int oneplus_aod_fod = 0; +int oneplus_aod_dc = 0; int oneplus_dim_status = 0; ssize_t oneplus_display_notify_dim(struct device *dev, @@ -2805,40 +2808,63 @@ ssize_t oneplus_display_notify_dim(struct device *dev, struct drm_crtc *crtc; int dim_status = 0; int err; - sscanf(buf, "%du", &dim_status); + + SDE_ATRACE_BEGIN("oneplus_display_notify_dim"); + err = sscanf(buf, "%du", &dim_status); + if (err < 0) + pr_err("oneplus_display_notify_dim sscanf failed"); + //dim_status = !!dim_status; - pr_err("notify dim %d\n", dim_status); + pr_info("notify dim %d\n", dim_status); if (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("oneplus_display_notify_dim"); return count; + } else if (display->panel->aod_status == 1 && dim_status == 2) { oneplus_onscreenfp_status = 1; + oneplus_aod_fod = 1; } else if (display->panel->aod_status == 1 && dim_status == 0) { oneplus_onscreenfp_status = 0; + } else if (display->panel->aod_status == 1 && dim_status == 5) { + oneplus_aod_dc = 1; } + if (dim_status == 0) + oneplus_onscreenfp_status = 0; + if (dim_status == oneplus_dim_status) return count; + oneplus_dim_status = dim_status; + if (oneplus_dim_status == 1 && HBM_flag) { + pr_err("notify dim not commit"); + 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 && display->panel->aod_status == 0)) { + if ((oneplus_dim_status != 0) && (oneplus_dim_status != 5)) { err = drm_atomic_commit(state); + pr_info("oneplus_dim_status = %d, err = %d, dim_status = %d", + oneplus_dim_status, err, dim_status); + pr_info("oneplus_onscreenfp_status %d hide %d", + oneplus_onscreenfp_status, aod_layer_hide); if (err < 0) drm_atomic_state_clear(state); } drm_modeset_unlock_all(drm_dev); SDE_ATRACE_END("oneplus_display_notify_dim"); + return count; } @@ -2849,6 +2875,9 @@ static int sde_crtc_config_fingerprint_dim_layer(struct drm_crtc_state *crtc_sta 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->panel->aod_status == 1 && oneplus_dim_status == 2) + alpha = 255; kms = _sde_crtc_get_kms(crtc_state->crtc); @@ -2883,7 +2912,6 @@ static int sde_crtc_config_fingerprint_dim_layer(struct drm_crtc_state *crtc_sta 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; } @@ -5080,20 +5108,22 @@ static int _sde_crtc_check_zpos(struct drm_crtc_state *state, return rc; } +bool finger_type = false; + 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 aod_index = -1, aod_mode = -1; + int fppressed_index_rt = -1; int zpos = INT_MAX; - int mode; + int mode = 0, i = 0; int fp_mode = oneplus_onscreenfp_status; int dim_mode = oneplus_dim_status; - int aod_mode = -1; - int i; struct dsi_display *display = get_main_display(); + int dim_backlight = 0; if (!display) return 0; @@ -5101,15 +5131,16 @@ static int sde_crtc_onscreenfinger_atomic_check(struct sde_crtc_state *cstate, if (display->panel->aod_status == 1) { if (oneplus_dim_status == 2 && oneplus_onscreenfp_status == 1) { fp_mode = 1; - dim_mode = 0; + //dim_mode = 0; } else if (oneplus_dim_status == 2 && oneplus_onscreenfp_status == 0) { - fp_mode = 1; + fp_mode = 0; dim_mode = 0; } } - - if (oneplus_onscreenaod_hid && oneplus_dim_status == 5) + if (oneplus_dim_status == 5 || aod_layer_hide == 1) { oneplus_aod_hid = 1; + dim_mode = 0; + } aod_mode = oneplus_aod_hid; if ((oneplus_dim_status == 5) && display->panel->aod_status == 0) @@ -5119,59 +5150,38 @@ static int sde_crtc_onscreenfinger_atomic_check(struct sde_crtc_state *cstate, mode = sde_plane_check_fingerprint_layer(pstates[i].drm_pstate); if (mode == 1) fp_index = i; - else if (mode == 2) + if (mode == 2) { fppressed_index = i; - else if (mode == 3) + fppressed_index_rt = i; + } + if (mode == 3) aod_index = i; } - if (fp_index >=0) + if (fp_index >= 0 && dim_mode != 0) display->panel->dim_status = true; else display->panel->dim_status = false; - if (aod_index <0) + 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 (fp_index >= 0 || fppressed_index >= 0 || oneplus_force_screenfp) { + 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"); + if (pstates[fp_index].stage >= + pstates[fppressed_index].stage) { + SDE_ERROR("fp layer top of fppressed layer\n"); return -EINVAL; } } - if (fppressed_index >= 0) { - if (fp_mode == 0) { - pstates[fppressed_index].sde_pstate->property_values[PLANE_PROP_ALPHA].value = 0; - fppressed_index = -1; - } else { - pstates[fppressed_index].sde_pstate->property_values[PLANE_PROP_ALPHA].value = 0xff; - } - } - if (fp_index >= 0) { - if (dim_mode == 0) { - pstates[fp_index].sde_pstate->property_values[PLANE_PROP_ALPHA].value = 0; - fp_index = -1; - } else { - pstates[fp_index].sde_pstate->property_values[PLANE_PROP_ALPHA].value = 0xff; - } - } - - if (aod_index >= 0) { - if (aod_mode == 1) { - 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 (aod_index >= 0) { - if (zpos > pstates[aod_index].stage) - zpos = pstates[aod_index].stage; - pstates[aod_index].stage++; - } - if (fppressed_index >= 0) { if (zpos > pstates[fppressed_index].stage) zpos = pstates[fppressed_index].stage; @@ -5184,11 +5194,12 @@ static int sde_crtc_onscreenfinger_atomic_check(struct sde_crtc_state *cstate, pstates[fp_index].stage++; } for (i = 0; i < cnt; i++) { - if (i == fp_index || i == fppressed_index || i == aod_index) + if (i == fp_index || i == fppressed_index) continue; - - if (pstates[i].stage >= zpos) + if (pstates[i].stage >= zpos) { + // SDE_ERROR("Warn!!: the fp layer not on top"); pstates[i].stage++; + } } if (zpos == INT_MAX) { zpos = 0; @@ -5199,7 +5210,46 @@ static int sde_crtc_onscreenfinger_atomic_check(struct sde_crtc_state *cstate, zpos++; } - if (fp_index >= 0 && sde_crtc_config_fingerprint_dim_layer(&cstate->base, 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) { + for (i = 0; i < cnt; i++) { + if (i != fppressed_index) { + if (pstates[i].sde_pstate->property_values[PLANE_PROP_ALPHA].value == 0) + pstates[i].sde_pstate->property_values[PLANE_PROP_ALPHA].value = 0xff; + } + } + } + fppressed_index = -1; + } else { + pstates[fppressed_index].sde_pstate->property_values[PLANE_PROP_ALPHA].value = 0xff; + } + } + + if (aod_index >= 0) { + if (aod_mode == 1) { + SDE_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; } @@ -5208,14 +5258,12 @@ static int sde_crtc_onscreenfinger_atomic_check(struct sde_crtc_state *cstate, cstate->fingerprint_pressed = true; else cstate->fingerprint_pressed = false; + } else { + cstate->fingerprint_pressed = false; + cstate->fingerprint_mode = false; } - - if (fp_index < 0) + if (fp_index < 0 && !dim_backlight) cstate->fingerprint_dim_layer = NULL; - - if (fppressed_index < 0) - cstate->fingerprint_pressed = false; - return 0; } diff --git a/techpack/display/msm/sde/sde_crtc.h b/techpack/display/msm/sde/sde_crtc.h index 2269452dfff7..270c8da1ee5b 100644 --- a/techpack/display/msm/sde/sde_crtc.h +++ b/techpack/display/msm/sde/sde_crtc.h @@ -440,6 +440,7 @@ struct sde_crtc_state { struct sde_core_perf_params new_perf; int secure_session; + bool fingerprint_mode; bool fingerprint_pressed; struct sde_hw_dim_layer *fingerprint_dim_layer; }; From 268e49447792d4b1dd0e5fac67eac77302895002 Mon Sep 17 00:00:00 2001 From: Art_Chen Date: Tue, 9 Mar 2021 12:04:06 +0800 Subject: [PATCH 237/356] techpack: display: Rework PLANE_PROP_ALPHA handling * matches with our z-order fix Co-authored-by: alk3pInjection Signed-off-by: alk3pInjection Change-Id: Ic65ac6dc5489980ed9e2aebc4965b17886de6030 --- techpack/display/msm/sde/sde_crtc.c | 43 ++++------------------------- 1 file changed, 6 insertions(+), 37 deletions(-) diff --git a/techpack/display/msm/sde/sde_crtc.c b/techpack/display/msm/sde/sde_crtc.c index e660eb54bc3c..51fb08b02dbd 100644 --- a/techpack/display/msm/sde/sde_crtc.c +++ b/techpack/display/msm/sde/sde_crtc.c @@ -5210,47 +5210,16 @@ static int sde_crtc_onscreenfinger_atomic_check(struct sde_crtc_state *cstate, 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) { - for (i = 0; i < cnt; i++) { - if (i != fppressed_index) { - if (pstates[i].sde_pstate->property_values[PLANE_PROP_ALPHA].value == 0) - pstates[i].sde_pstate->property_values[PLANE_PROP_ALPHA].value = 0xff; - } - } - } - fppressed_index = -1; - } else { - pstates[fppressed_index].sde_pstate->property_values[PLANE_PROP_ALPHA].value = 0xff; - } - } - - if (aod_index >= 0) { - if (aod_mode == 1) { - SDE_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"); + + if (fp_index >= 0) + pstates[fp_index].sde_pstate->property_values[PLANE_PROP_ALPHA].value = 0; + + if (sde_crtc_config_fingerprint_dim_layer(&cstate->base, zpos)) { + //SDE_ERROR("Failed to config dim layer\n"); return -EINVAL; } From 370ad23569b0faa7fa8528fff2218559a3baecf6 Mon Sep 17 00:00:00 2001 From: Art_Chen Date: Tue, 9 Mar 2021 12:04:06 +0800 Subject: [PATCH 238/356] techpack: display: Refactor fod dimming * Check oneplus_dimlayer_hbm_enable instead of fp_index to activate fod dimming mode. Co-authored-by: alk3pInjection Signed-off-by: alk3pInjection Change-Id: I8cd87ccab8e8dbbd0653ddbeadb5d8bafb72cd71 --- techpack/display/msm/sde/sde_crtc.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/techpack/display/msm/sde/sde_crtc.c b/techpack/display/msm/sde/sde_crtc.c index 51fb08b02dbd..74960d96e15a 100644 --- a/techpack/display/msm/sde/sde_crtc.c +++ b/techpack/display/msm/sde/sde_crtc.c @@ -2700,6 +2700,7 @@ int brightness_to_alpha(int brightness) brightness_alpha_lut[i].alpha); } +bool oneplus_dimlayer_hbm_enable; int oneplus_get_panel_brightness_to_alpha(void) { struct dsi_display *display = get_main_display(); @@ -2843,6 +2844,7 @@ ssize_t oneplus_display_notify_dim(struct device *dev, return count; oneplus_dim_status = dim_status; + oneplus_dimlayer_hbm_enable = oneplus_dim_status != 0; if (oneplus_dim_status == 1 && HBM_flag) { pr_err("notify dim not commit"); return count; @@ -5173,8 +5175,7 @@ static int sde_crtc_onscreenfinger_atomic_check(struct sde_crtc_state *cstate, oneplus_aod_dc = 0; } - if (fp_index >= 0 || fppressed_index >= 0 || oneplus_force_screenfp || - dim_backlight == 1) { + if (oneplus_dimlayer_hbm_enable || oneplus_force_screenfp || dim_backlight == 1) { if (fp_index >= 0 && fppressed_index >= 0) { if (pstates[fp_index].stage >= pstates[fppressed_index].stage) { @@ -5210,7 +5211,7 @@ static int sde_crtc_onscreenfinger_atomic_check(struct sde_crtc_state *cstate, zpos++; } - if (fp_index >= 0) + if (oneplus_dimlayer_hbm_enable) cstate->fingerprint_mode = true; else cstate->fingerprint_mode = false; @@ -5228,11 +5229,15 @@ static int sde_crtc_onscreenfinger_atomic_check(struct sde_crtc_state *cstate, else cstate->fingerprint_pressed = false; } else { + cstate->fingerprint_dim_layer = NULL; cstate->fingerprint_pressed = false; cstate->fingerprint_mode = false; } - if (fp_index < 0 && !dim_backlight) - cstate->fingerprint_dim_layer = NULL; + if (fp_mode == 1 && !oneplus_dimlayer_hbm_enable) { + cstate->fingerprint_mode = true; + cstate->fingerprint_pressed = true; + return 0; + } return 0; } From 20d5a08aa2fe3f8ba2f4ac15c2288e39f49ec35a Mon Sep 17 00:00:00 2001 From: LuK1337 Date: Sun, 3 Oct 2021 15:42:32 +0200 Subject: [PATCH 239/356] techpack: display: Apply correct panel mode on setting backlight lvl This follows similar behavior present in OxygenOS kernel and fixes invalid panel mode after toggling the screen off and on again on 6T. Change-Id: Ia90a40b31c3956df9d8ce75b0fad82c9f4d8ef9d --- techpack/display/msm/dsi/dsi_display.c | 3 +++ techpack/display/msm/dsi/dsi_panel.c | 14 +++++++++++--- techpack/display/msm/dsi/dsi_panel.h | 1 + 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/techpack/display/msm/dsi/dsi_display.c b/techpack/display/msm/dsi/dsi_display.c index b8adb9252a92..ca458fca5dea 100644 --- a/techpack/display/msm/dsi/dsi_display.c +++ b/techpack/display/msm/dsi/dsi_display.c @@ -215,6 +215,9 @@ int dsi_display_set_backlight(struct drm_connector *connector, goto error; } + if (bl_lvl != 0 && panel->bl_config.bl_level == 0) + dsi_panel_apply_display_mode_locked(panel); + panel->bl_config.bl_level = bl_lvl; /* scale backlight */ diff --git a/techpack/display/msm/dsi/dsi_panel.c b/techpack/display/msm/dsi/dsi_panel.c index d6ccad0ac9cc..283b170e69c0 100644 --- a/techpack/display/msm/dsi/dsi_panel.c +++ b/techpack/display/msm/dsi/dsi_panel.c @@ -4731,11 +4731,10 @@ int dsi_panel_apply_hbm_mode(struct dsi_panel *panel) return rc; } -int dsi_panel_apply_display_mode(struct dsi_panel *panel) +int dsi_panel_apply_display_mode_locked(struct dsi_panel *panel) { enum dsi_cmd_set_type type; int rc; - switch (panel->display_mode) { case DISPLAY_MODE_SRGB: type = DSI_CMD_SET_MODE_SRGB; break; case DISPLAY_MODE_DCI_P3: type = DSI_CMD_SET_MODE_DCI_P3; break; @@ -4743,8 +4742,17 @@ int dsi_panel_apply_display_mode(struct dsi_panel *panel) default: type = DSI_CMD_SET_MODE_DEFAULT; break; } - mutex_lock(&panel->panel_lock); rc = dsi_panel_tx_cmd_set(panel, type); + + return rc; +} + +int dsi_panel_apply_display_mode(struct dsi_panel *panel) +{ + int rc; + + mutex_lock(&panel->panel_lock); + rc = dsi_panel_apply_display_mode_locked(panel); mutex_unlock(&panel->panel_lock); return rc; diff --git a/techpack/display/msm/dsi/dsi_panel.h b/techpack/display/msm/dsi/dsi_panel.h index 37777ad3fe5c..d2e67295eb57 100644 --- a/techpack/display/msm/dsi/dsi_panel.h +++ b/techpack/display/msm/dsi/dsi_panel.h @@ -333,6 +333,7 @@ int dsi_panel_post_unprepare(struct dsi_panel *panel); int dsi_panel_apply_hbm_mode(struct dsi_panel *panel); +int dsi_panel_apply_display_mode_locked(struct dsi_panel *panel); int dsi_panel_apply_display_mode(struct dsi_panel *panel); int dsi_panel_set_backlight(struct dsi_panel *panel, u32 bl_lvl); From d464377e59969bf072c7f02d8acfad85229e3f25 Mon Sep 17 00:00:00 2001 From: Demon000 Date: Thu, 21 May 2020 02:06:33 +0300 Subject: [PATCH 240/356] techpack: display: sde: Translate zpos property to cust property Co-authored-by: LuK1337 Change-Id: I7e8562ed3eda675d160d6dabee7e568a1a72e849 --- include/uapi/drm/sde_drm.h | 6 +++++ techpack/display/msm/sde/sde_plane.c | 37 ++++++++++++++-------------- 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/include/uapi/drm/sde_drm.h b/include/uapi/drm/sde_drm.h index 029393041408..5aae512709aa 100644 --- a/include/uapi/drm/sde_drm.h +++ b/include/uapi/drm/sde_drm.h @@ -501,4 +501,10 @@ struct sde_drm_roi_v1 { * Implementation may be platform and base-format specific. */ #define DRM_FORMAT_MOD_QCOM_FSC_TILE fourcc_mod_code(QCOM, 0x10) + +/** + * sde fod dim layer + */ +#define FOD_PRESSED_LAYER_ZORDER 0x20000000u + #endif /* _SDE_DRM_H_ */ diff --git a/techpack/display/msm/sde/sde_plane.c b/techpack/display/msm/sde/sde_plane.c index 574b05d7348b..51b5962b1a06 100644 --- a/techpack/display/msm/sde/sde_plane.c +++ b/techpack/display/msm/sde/sde_plane.c @@ -3554,7 +3554,7 @@ static void _sde_plane_install_properties(struct drm_plane *plane, 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_max = INT_MAX; int zpos_def = 0; char feature_name[256]; @@ -3572,21 +3572,6 @@ static void _sde_plane_install_properties(struct drm_plane *plane, 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); @@ -4014,6 +3999,8 @@ static int sde_plane_atomic_set_property(struct drm_plane *plane, { struct sde_plane *psde = plane ? to_sde_plane(plane) : NULL; struct sde_plane_state *pstate; + struct drm_property *fod_property; + int fod_val = 0; int idx, ret = -EINVAL; SDE_DEBUG_PLANE(psde, "\n"); @@ -4024,11 +4011,25 @@ static int sde_plane_atomic_set_property(struct drm_plane *plane, SDE_ERROR_PLANE(psde, "invalid state\n"); } else { pstate = to_sde_plane_state(state); + idx = msm_property_index(&psde->property_info, + property); + if (idx == PLANE_PROP_ZPOS) { + if (val & FOD_PRESSED_LAYER_ZORDER) { + val &= ~FOD_PRESSED_LAYER_ZORDER; + fod_val = 2; // pressed + } + + fod_property = psde->property_info. + property_array[PLANE_PROP_CUSTOM]; + ret = msm_property_atomic_set(&psde->property_info, + &pstate->property_state, + fod_property, fod_val); + if (ret) + SDE_ERROR("failed to set fod prop"); + } 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); From d52ee8393798cb291ce83a1782155472a7d3f888 Mon Sep 17 00:00:00 2001 From: alk3pInjection Date: Tue, 9 Nov 2021 14:32:18 +0800 Subject: [PATCH 241/356] techpack: display: Handle dim for udfps * Apparently, los fod impl is better than udfps cuz it has onShow/HideFodView hook, which allows us to toggle dimlayer seamlessly. Since udfps only partially supports the former one, we'd better kill dim in kernel. This is kinda a hack but it works well, bringing perfect fod experience back to us. Co-authored-by: Art_Chen Signed-off-by: alk3pInjection Change-Id: I80bfd508dacac5db89f4fff0283529c256fb30ce --- techpack/display/msm/dsi/dsi_panel.c | 14 ++++++++++++++ techpack/display/msm/sde/sde_crtc.c | 10 +++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/techpack/display/msm/dsi/dsi_panel.c b/techpack/display/msm/dsi/dsi_panel.c index 283b170e69c0..a7d7928d5388 100644 --- a/techpack/display/msm/dsi/dsi_panel.c +++ b/techpack/display/msm/dsi/dsi_panel.c @@ -4521,6 +4521,11 @@ int dsi_panel_post_switch(struct dsi_panel *panel) return rc; } +extern bool oneplus_dimlayer_hbm_enable; +extern bool backup_dimlayer_hbm; +extern int oneplus_dim_status; +extern int backup_dim_status; + int dsi_panel_enable(struct dsi_panel *panel) { int rc = 0; @@ -4538,6 +4543,11 @@ int dsi_panel_enable(struct dsi_panel *panel) panel->name, rc); else panel->panel_initialized = true; + + oneplus_dimlayer_hbm_enable = backup_dimlayer_hbm; + oneplus_dim_status = backup_dim_status; + pr_err("Restore dim when panel goes on"); + mutex_unlock(&panel->panel_lock); dsi_panel_init_display_modes(panel); @@ -4635,6 +4645,10 @@ int dsi_panel_disable(struct dsi_panel *panel) panel->power_mode == SDE_MODE_DPMS_LP2)) dsi_pwr_panel_regulator_mode_set(&panel->power_info, "ibb", REGULATOR_MODE_STANDBY); + oneplus_dimlayer_hbm_enable = false; + oneplus_dim_status = 0; + pr_err("Kill dim when panel goes off"); + if (panel->aod_mode == 2) panel->aod_status = 1; else if (panel->aod_mode == 0) diff --git a/techpack/display/msm/sde/sde_crtc.c b/techpack/display/msm/sde/sde_crtc.c index 74960d96e15a..dfaee52d0340 100644 --- a/techpack/display/msm/sde/sde_crtc.c +++ b/techpack/display/msm/sde/sde_crtc.c @@ -2794,6 +2794,8 @@ extern int aod_layer_hide; int oneplus_aod_fod = 0; int oneplus_aod_dc = 0; int oneplus_dim_status = 0; +int backup_dim_status = 0; +bool backup_dimlayer_hbm = false; ssize_t oneplus_display_notify_dim(struct device *dev, struct device_attribute *attr, @@ -2845,6 +2847,8 @@ ssize_t oneplus_display_notify_dim(struct device *dev, oneplus_dim_status = dim_status; oneplus_dimlayer_hbm_enable = oneplus_dim_status != 0; + backup_dimlayer_hbm = oneplus_dimlayer_hbm_enable; + backup_dim_status = oneplus_dim_status; if (oneplus_dim_status == 1 && HBM_flag) { pr_err("notify dim not commit"); return count; @@ -5145,8 +5149,12 @@ static int sde_crtc_onscreenfinger_atomic_check(struct sde_crtc_state *cstate, } aod_mode = oneplus_aod_hid; - if ((oneplus_dim_status == 5) && display->panel->aod_status == 0) + if ((oneplus_dim_status == 5) && display->panel->aod_status == 0) { dim_mode = 0; + oneplus_dim_status = 0; + oneplus_dimlayer_hbm_enable = false; + pr_err("current dim = %d, oneplus_dimlayer_hbm_enable = %d\n", oneplus_dim_status, oneplus_dimlayer_hbm_enable); + } for (i = 0; i < cnt; i++) { mode = sde_plane_check_fingerprint_layer(pstates[i].drm_pstate); From 639924abd12be94323eda1ba9b963363a019275a Mon Sep 17 00:00:00 2001 From: Art_Chen Date: Tue, 9 Nov 2021 14:32:18 +0800 Subject: [PATCH 242/356] techpack: display: Implement panel status check * to ensure dimlayer has been killed when the panel is off. Signed-off-by: alk3pInjection Change-Id: I30606f5fb4fcd493a94b41792a75997c86ba4545 --- drivers/gpu/drm/drm_sysfs.c | 18 ++++++++++++++++++ techpack/display/msm/dsi/dsi_panel.c | 13 +++++++++++++ techpack/display/msm/sde/sde_crtc.c | 3 +++ 3 files changed, 34 insertions(+) diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c index a4cbf47560d8..a41a3977a468 100644 --- a/drivers/gpu/drm/drm_sysfs.c +++ b/drivers/gpu/drm/drm_sysfs.c @@ -410,6 +410,22 @@ extern ssize_t oneplus_display_notify_aod_hid(struct device *dev, const char *buf, size_t count); +int oneplus_panel_status = 0; +static ssize_t op_display_get_power_status(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", oneplus_panel_status); +} + +static ssize_t op_display_set_power_status(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + sscanf(buf, "%d", &oneplus_panel_status); + + return count; +} + static DEVICE_ATTR_RW(status); static DEVICE_ATTR_RO(enabled); static DEVICE_ATTR_RO(dpms); @@ -422,6 +438,7 @@ static DEVICE_ATTR(notify_fppress, S_IRUGO | S_IWUSR, NULL, oneplus_display_noti static DEVICE_ATTR(dim_alpha, S_IRUGO | S_IWUSR, oneplus_display_get_dim_alpha, oneplus_display_set_dim_alpha); static DEVICE_ATTR(notify_dim, S_IRUGO | S_IWUSR, NULL, oneplus_display_notify_dim); static DEVICE_ATTR(notify_aod, S_IRUGO | S_IWUSR, NULL, oneplus_display_notify_aod_hid); +static DEVICE_ATTR(power_status, S_IRUGO | S_IWUSR, op_display_get_power_status, op_display_set_power_status); static struct attribute *connector_dev_attrs[] = { &dev_attr_status.attr, @@ -436,6 +453,7 @@ static struct attribute *connector_dev_attrs[] = { &dev_attr_notify_fppress.attr, &dev_attr_notify_dim.attr, &dev_attr_notify_aod.attr, + &dev_attr_power_status.attr, NULL }; diff --git a/techpack/display/msm/dsi/dsi_panel.c b/techpack/display/msm/dsi/dsi_panel.c index a7d7928d5388..d5066722e392 100644 --- a/techpack/display/msm/dsi/dsi_panel.c +++ b/techpack/display/msm/dsi/dsi_panel.c @@ -4123,6 +4123,7 @@ int dsi_panel_update_pps(struct dsi_panel *panel) return rc; } +extern int oneplus_panel_status; int dsi_panel_set_lp1(struct dsi_panel *panel) { int rc = 0; @@ -4151,6 +4152,9 @@ int dsi_panel_set_lp1(struct dsi_panel *panel) if (rc) DSI_ERR("[%s] failed to send DSI_CMD_SET_LP1 cmd, rc=%d\n", panel->name, rc); + + oneplus_panel_status = 3; // DISPLAY_POWER_DOZE + exit: mutex_unlock(&panel->panel_lock); return rc; @@ -4173,6 +4177,9 @@ int dsi_panel_set_lp2(struct dsi_panel *panel) if (rc) DSI_ERR("[%s] failed to send DSI_CMD_SET_LP2 cmd, rc=%d\n", panel->name, rc); + + oneplus_panel_status = 4; // DISPLAY_POWER_DOZE_SUSPEND + exit: mutex_unlock(&panel->panel_lock); return rc; @@ -4203,6 +4210,9 @@ int dsi_panel_set_nolp(struct dsi_panel *panel) if (rc) DSI_ERR("[%s] failed to send DSI_CMD_SET_NOLP cmd, rc=%d\n", panel->name, rc); + + oneplus_panel_status = 2; // DISPLAY_POWER_ON + exit: mutex_unlock(&panel->panel_lock); return rc; @@ -4544,6 +4554,7 @@ int dsi_panel_enable(struct dsi_panel *panel) else panel->panel_initialized = true; + oneplus_panel_status = 2; // DISPLAY_POWER_ON oneplus_dimlayer_hbm_enable = backup_dimlayer_hbm; oneplus_dim_status = backup_dim_status; pr_err("Restore dim when panel goes on"); @@ -4666,6 +4677,7 @@ int dsi_panel_disable(struct dsi_panel *panel) rc = 0; } } + oneplus_panel_status = 0; // DISPLAY_POWER_OFF panel->panel_initialized = false; panel->power_mode = SDE_MODE_DPMS_OFF; @@ -4823,6 +4835,7 @@ int dsi_panel_set_aod_mode(struct dsi_panel *panel, int level) aod_complete = false; } } + oneplus_panel_status = 0; // DISPLAY_POWER_OFF panel->aod_curr_mode = level; pr_err("AOD MODE = %d\n", level); diff --git a/techpack/display/msm/sde/sde_crtc.c b/techpack/display/msm/sde/sde_crtc.c index dfaee52d0340..91c4af1b7ab8 100644 --- a/techpack/display/msm/sde/sde_crtc.c +++ b/techpack/display/msm/sde/sde_crtc.c @@ -2791,6 +2791,7 @@ ssize_t oneplus_display_notify_fp_press(struct device *dev, extern bool HBM_flag; extern int aod_layer_hide; +extern int oneplus_panel_status; int oneplus_aod_fod = 0; int oneplus_aod_dc = 0; int oneplus_dim_status = 0; @@ -2819,6 +2820,8 @@ ssize_t oneplus_display_notify_dim(struct device *dev, //dim_status = !!dim_status; pr_info("notify dim %d\n", dim_status); + if (oneplus_panel_status == 0) + dim_status = 0; if (display->panel->aod_status == 0 && (dim_status == 2)) { pr_err("fp set it in normal status\n"); From f0f22f25e79daea787fbe505d181c6527c82ad76 Mon Sep 17 00:00:00 2001 From: alk3pInjection Date: Sat, 22 Jan 2022 12:34:45 +0800 Subject: [PATCH 243/356] techpack: display: Allow hooking dim when screen goes on Change-Id: I5ca0b3905ebfb7200cd04bfae28ad1feb06d1a44 Signed-off-by: alk3pInjection --- drivers/gpu/drm/drm_sysfs.c | 18 ++++++++++++++++++ techpack/display/msm/dsi/dsi_panel.c | 14 +++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c index a41a3977a468..3c8b61d729d0 100644 --- a/drivers/gpu/drm/drm_sysfs.c +++ b/drivers/gpu/drm/drm_sysfs.c @@ -410,7 +410,23 @@ extern ssize_t oneplus_display_notify_aod_hid(struct device *dev, const char *buf, size_t count); +int oneplus_auth_status = 0; int oneplus_panel_status = 0; +static ssize_t op_display_get_auth_status(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", oneplus_auth_status); +} + +static ssize_t op_display_set_auth_status(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + sscanf(buf, "%d", &oneplus_auth_status); + + return count; +} + static ssize_t op_display_get_power_status(struct device *dev, struct device_attribute *attr, char *buf) { @@ -438,6 +454,7 @@ static DEVICE_ATTR(notify_fppress, S_IRUGO | S_IWUSR, NULL, oneplus_display_noti static DEVICE_ATTR(dim_alpha, S_IRUGO | S_IWUSR, oneplus_display_get_dim_alpha, oneplus_display_set_dim_alpha); static DEVICE_ATTR(notify_dim, S_IRUGO | S_IWUSR, NULL, oneplus_display_notify_dim); static DEVICE_ATTR(notify_aod, S_IRUGO | S_IWUSR, NULL, oneplus_display_notify_aod_hid); +static DEVICE_ATTR(auth_status, S_IRUGO | S_IWUSR, op_display_get_auth_status, op_display_set_auth_status); static DEVICE_ATTR(power_status, S_IRUGO | S_IWUSR, op_display_get_power_status, op_display_set_power_status); static struct attribute *connector_dev_attrs[] = { @@ -453,6 +470,7 @@ static struct attribute *connector_dev_attrs[] = { &dev_attr_notify_fppress.attr, &dev_attr_notify_dim.attr, &dev_attr_notify_aod.attr, + &dev_attr_auth_status.attr, &dev_attr_power_status.attr, NULL }; diff --git a/techpack/display/msm/dsi/dsi_panel.c b/techpack/display/msm/dsi/dsi_panel.c index d5066722e392..a9b8e2b3687a 100644 --- a/techpack/display/msm/dsi/dsi_panel.c +++ b/techpack/display/msm/dsi/dsi_panel.c @@ -4533,6 +4533,7 @@ int dsi_panel_post_switch(struct dsi_panel *panel) extern bool oneplus_dimlayer_hbm_enable; extern bool backup_dimlayer_hbm; +extern int oneplus_auth_status; extern int oneplus_dim_status; extern int backup_dim_status; @@ -4555,9 +4556,20 @@ int dsi_panel_enable(struct dsi_panel *panel) panel->panel_initialized = true; oneplus_panel_status = 2; // DISPLAY_POWER_ON + + if (oneplus_auth_status == 2) { + backup_dimlayer_hbm = 0; + backup_dim_status = 0; + } else if (oneplus_auth_status == 1) { + backup_dimlayer_hbm = 1; + backup_dim_status = 1; + } + oneplus_dimlayer_hbm_enable = backup_dimlayer_hbm; oneplus_dim_status = backup_dim_status; - pr_err("Restore dim when panel goes on"); + if (oneplus_auth_status != 2) + pr_err("Restore dim when panel goes on"); + oneplus_auth_status = 0; mutex_unlock(&panel->panel_lock); From 9afb2afe33eba462ebdd80909620f25a807753ed Mon Sep 17 00:00:00 2001 From: Tim Schumacher Date: Sun, 3 Apr 2022 14:03:58 +0200 Subject: [PATCH 244/356] techpack: display: Import OnePlus DC dimming code Change-Id: I6664a3f5d759b28a401476bd464616d0502174cf --- drivers/gpu/drm/drm_sysfs.c | 40 ++++++++++++ techpack/display/msm/dsi/dsi_panel.c | 6 ++ techpack/display/msm/sde/sde_connector.c | 19 ++++++ techpack/display/msm/sde/sde_crtc.c | 81 +++++++++++++++++++++++- techpack/display/msm/sde/sde_encoder.c | 8 ++- 5 files changed, 151 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c index 3c8b61d729d0..81455fe4cec6 100644 --- a/drivers/gpu/drm/drm_sysfs.c +++ b/drivers/gpu/drm/drm_sysfs.c @@ -340,6 +340,8 @@ static ssize_t aod_store(struct device *dev, int oneplus_force_screenfp = 0; int oneplus_panel_alpha = 0; +int op_dimlayer_bl_enable = 0; +int op_dp_enable = 0; extern int oneplus_get_panel_brightness_to_alpha(void); static ssize_t oneplus_display_get_dim_alpha(struct device *dev, @@ -395,6 +397,40 @@ static ssize_t oneplus_display_set_forcescreenfp(struct device *dev, return count; } +static ssize_t op_display_get_dimlayer_enable(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", op_dimlayer_bl_enable); +} + +static ssize_t op_display_set_dimlayer_enable(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int err = sscanf(buf, "%d", &op_dimlayer_bl_enable); + + if (err < 0) + pr_err("op_display_set_dimlayer_enable sscanf failed"); + return count; +} + +static ssize_t op_display_get_dp_enable(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", op_dp_enable); +} + +static ssize_t op_display_set_dp_enable(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int err = sscanf(buf, "%d", &op_dp_enable); + + if (err < 0) + pr_err("op_display_set_dp_enable sscanf failed"); + return count; +} + extern ssize_t oneplus_display_notify_fp_press(struct device *dev, struct device_attribute *attr, const char *buf, @@ -456,6 +492,8 @@ static DEVICE_ATTR(notify_dim, S_IRUGO | S_IWUSR, NULL, oneplus_display_notify_d static DEVICE_ATTR(notify_aod, S_IRUGO | S_IWUSR, NULL, oneplus_display_notify_aod_hid); static DEVICE_ATTR(auth_status, S_IRUGO | S_IWUSR, op_display_get_auth_status, op_display_set_auth_status); static DEVICE_ATTR(power_status, S_IRUGO | S_IWUSR, op_display_get_power_status, op_display_set_power_status); +static DEVICE_ATTR(dimlayer_bl_en, S_IRUGO | S_IWUSR, op_display_get_dimlayer_enable, op_display_set_dimlayer_enable); +static DEVICE_ATTR(dp_en, S_IRUGO | S_IWUSR, op_display_get_dp_enable, op_display_set_dp_enable); static struct attribute *connector_dev_attrs[] = { &dev_attr_status.attr, @@ -472,6 +510,8 @@ static struct attribute *connector_dev_attrs[] = { &dev_attr_notify_aod.attr, &dev_attr_auth_status.attr, &dev_attr_power_status.attr, + &dev_attr_dimlayer_bl_en.attr, + &dev_attr_dp_en.attr, NULL }; diff --git a/techpack/display/msm/dsi/dsi_panel.c b/techpack/display/msm/dsi/dsi_panel.c index a9b8e2b3687a..b1a95d089e66 100644 --- a/techpack/display/msm/dsi/dsi_panel.c +++ b/techpack/display/msm/dsi/dsi_panel.c @@ -654,6 +654,8 @@ static int dsi_panel_dcs_set_display_brightness_c2(struct mipi_dsi_device *dsi, +extern int op_dimlayer_bl_alpha; +extern int op_dimlayer_bl_enabled; bool HBM_flag; int dsi_panel_update_backlight(struct dsi_panel *panel, @@ -671,6 +673,10 @@ int dsi_panel_update_backlight(struct dsi_panel *panel, dsi = &panel->mipi_device; bl = &panel->bl_config; + if (op_dimlayer_bl_enabled) { + bl_lvl = op_dimlayer_bl_alpha; + } + if (panel->bl_config.bl_inverted_dbv) bl_lvl = (((bl_lvl & 0xff) << 8) | (bl_lvl >> 8)); diff --git a/techpack/display/msm/sde/sde_connector.c b/techpack/display/msm/sde/sde_connector.c index 0edad9044ccc..a8fae56fc7c0 100644 --- a/techpack/display/msm/sde/sde_connector.c +++ b/techpack/display/msm/sde/sde_connector.c @@ -745,6 +745,25 @@ extern bool HBM_flag; extern int oneplus_dim_status; extern bool aod_real_flag; extern bool aod_complete; +extern int op_dimlayer_bl; +extern int op_dimlayer_bl_enabled; + +int sde_connector_update_backlight(struct drm_connector *connector) +{ + if (op_dimlayer_bl != op_dimlayer_bl_enabled) { + struct sde_connector *c_conn = to_sde_connector(connector); + + if (!c_conn) { + SDE_ERROR("Invalid params sde_connector null\n"); + return -EINVAL; + } + + op_dimlayer_bl_enabled = op_dimlayer_bl; + _sde_connector_update_bl_scale(c_conn); + } + + return 0; +} static int _sde_connector_update_hbm(struct sde_connector *c_conn) { diff --git a/techpack/display/msm/sde/sde_crtc.c b/techpack/display/msm/sde/sde_crtc.c index 91c4af1b7ab8..5a0253327b29 100644 --- a/techpack/display/msm/sde/sde_crtc.c +++ b/techpack/display/msm/sde/sde_crtc.c @@ -2609,6 +2609,17 @@ static void _sde_crtc_set_dim_layer_v1(struct drm_crtc *crtc, } } +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; @@ -2664,6 +2675,27 @@ struct ba brightness_alpha_lut[] = { {2000, 0x83}, }; +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}, +}; + static int interpolate(int x, int xa, int xb, int ya, int yb) { int bf, factor, plus; @@ -2700,6 +2732,28 @@ int brightness_to_alpha(int brightness) brightness_alpha_lut[i].alpha); } +int bl_to_alpha_dc(int brightness) +{ + int level = ARRAY_SIZE(brightness_alpha_lut_dc); + int i = 0; + + for (i = 0; i < ARRAY_SIZE(brightness_alpha_lut_dc); i++) { + if (brightness_alpha_lut_dc[i].brightness >= brightness) + break; + } + + if (i == 0) + return brightness_alpha_lut_dc[0].alpha; + else if (i == level) + return brightness_alpha_lut_dc[level - 1].alpha; + + return 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); +} + bool oneplus_dimlayer_hbm_enable; int oneplus_get_panel_brightness_to_alpha(void) { @@ -2711,7 +2765,10 @@ int oneplus_get_panel_brightness_to_alpha(void) if (oneplus_panel_alpha) return oneplus_panel_alpha; - return brightness_to_alpha(display->panel->hbm_backlight); + if (oneplus_dimlayer_hbm_enable) + return brightness_to_alpha(display->panel->hbm_backlight); + else + return bl_to_alpha_dc(display->panel->hbm_backlight); } int oneplus_onscreenaod_hid = 0; @@ -5117,7 +5174,12 @@ static int _sde_crtc_check_zpos(struct drm_crtc_state *state, return rc; } +int op_dimlayer_bl_alpha = 260; +int op_dimlayer_bl_enabled = 0; +int op_dimlayer_bl = 0; bool finger_type = false; +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, @@ -5186,6 +5248,23 @@ static int sde_crtc_onscreenfinger_atomic_check(struct sde_crtc_state *cstate, oneplus_aod_dc = 0; } + if ((fp_index >= 0 && dim_mode != 0) || + (display->panel->aod_status == 1 && oneplus_aod_dc == 0)) { + op_dimlayer_bl = 0; + } else { + if (op_dimlayer_bl_enable && !op_dp_enable) { + if (display->panel->bl_config.bl_level != 0 && + display->panel->bl_config.bl_level < op_dimlayer_bl_alpha) { + dim_backlight = 1; + op_dimlayer_bl = 1; + } else { + op_dimlayer_bl = 0; + } + } else { + op_dimlayer_bl = 0; + } + } + if (oneplus_dimlayer_hbm_enable || oneplus_force_screenfp || dim_backlight == 1) { if (fp_index >= 0 && fppressed_index >= 0) { if (pstates[fp_index].stage >= diff --git a/techpack/display/msm/sde/sde_encoder.c b/techpack/display/msm/sde/sde_encoder.c index ee212f82b36a..9dfb35d91f1d 100644 --- a/techpack/display/msm/sde/sde_encoder.c +++ b/techpack/display/msm/sde/sde_encoder.c @@ -4474,7 +4474,7 @@ void sde_encoder_trigger_kickoff_pending(struct drm_encoder *drm_enc) sde_enc->idle_pc_restore = false; } -extern bool sde_crtc_get_fingerprint_mode(struct drm_crtc_state *crtc_state); +extern bool sde_crtc_get_dimlayer_mode(struct drm_crtc_state *crtc_state); static bool _sde_encoder_setup_dither_for_onscreenfingerprint(struct sde_encoder_phys *phys, void *dither_cfg, int len) @@ -4485,7 +4485,7 @@ _sde_encoder_setup_dither_for_onscreenfingerprint(struct sde_encoder_phys *phys, if (!drm_enc || !drm_enc->crtc) return -EFAULT; - if (!sde_crtc_get_fingerprint_mode(drm_enc->crtc->state)) + if (!sde_crtc_get_dimlayer_mode(drm_enc->crtc->state)) return -EINVAL; if (len != sizeof(dither)) @@ -4904,6 +4904,7 @@ void sde_encoder_needs_hw_reset(struct drm_encoder *drm_enc) } } +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) { @@ -4940,6 +4941,9 @@ int sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc, _sde_encoder_helper_hdr_plus_mempool_update(sde_enc); + if (sde_enc->cur_master) + sde_connector_update_backlight(sde_enc->cur_master->connector); + /* 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++) { From fccfd6acaefeaba48fc461972100dc9a7807c188 Mon Sep 17 00:00:00 2001 From: Luca Stefani Date: Thu, 13 Sep 2018 13:29:58 +0200 Subject: [PATCH 245/356] drivers: usb: Import OnePlus changes EdwinMoq: Adapt for 4.19 Change-Id: I6135ccf5e0bf9067c7d43908a464fdfd391ba038 --- drivers/usb/dwc3/core.c | 8 ++ drivers/usb/dwc3/core.h | 1 + drivers/usb/dwc3/dwc3-msm.c | 17 ++- drivers/usb/dwc3/ep0.c | 20 +++ drivers/usb/dwc3/gadget.c | 2 - drivers/usb/host/xhci-mem.c | 7 +- drivers/usb/host/xhci.c | 18 +++ drivers/usb/pd/policy_engine.c | 17 +++ drivers/usb/phy/phy-msm-qusb-v2.c | 208 +++++++++++++++++++++++++++--- 9 files changed, 278 insertions(+), 20 deletions(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index d58bc668ee7f..183a95540817 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -1357,6 +1357,8 @@ static void dwc3_get_properties(struct dwc3 *dwc) &dwc->hsphy_interface); device_property_read_u32(dev, "snps,quirk-frame-length-adjustment", &dwc->fladj); + dwc->enable_super_speed = device_property_read_bool(dev, + "op,enable_super_speed"); dwc->enable_bus_suspend = device_property_read_bool(dev, "snps,bus-suspend-enable"); dwc->usb3_u1u2_disable = device_property_read_bool(dev, @@ -1383,6 +1385,12 @@ static void dwc3_get_properties(struct dwc3 *dwc) device_property_read_u32(dev, "snps,gen2-tx-de-emph3", &dwc->gen2_tx_de_emph3); + if (!dwc->enable_super_speed) { + pr_info("Force USB running as High speed"); + dwc->max_hw_supp_speed = USB_SPEED_HIGH; + dwc->maximum_speed = USB_SPEED_HIGH; + } + dwc->lpm_nyet_threshold = lpm_nyet_threshold; dwc->tx_de_emphasis = tx_de_emphasis; diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 573e935cf9d1..75a045b7a673 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -1327,6 +1327,7 @@ struct dwc3 { unsigned disable_clk_gating:1; unsigned enable_bus_suspend:1; unsigned usb3_u1u2_disable:1; + unsigned enable_super_speed:1; atomic_t in_lpm; bool b_suspend; diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index 8f125e73de25..e83e61ca5e82 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -76,6 +76,7 @@ MODULE_PARM_DESC(bc12_compliance, "Disable sending dp pulse for CDP"); #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) @@ -2308,6 +2309,7 @@ static void dwc3_msm_power_collapse_por(struct dwc3_msm *mdwc) static int dwc3_msm_prepare_suspend(struct dwc3_msm *mdwc) { + struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); unsigned long timeout; u32 reg = 0; @@ -2335,8 +2337,19 @@ static int dwc3_msm_prepare_suspend(struct dwc3_msm *mdwc) 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, diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 9fc071514b30..5a566ea4c5a0 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); @@ -847,6 +863,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 711ee1005618..9ecb28489644 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -3692,8 +3692,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); diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index bf2a25633551..1a2574f03886 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -17,6 +17,11 @@ #include "xhci.h" #include "xhci-trace.h" #include "xhci-debugfs.h" +#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, @@ -2337,7 +2342,7 @@ 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) { + 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.c b/drivers/usb/host/xhci.c index 493aff432a56..c51c5fdb12d1 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -1062,6 +1062,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 */ @@ -2963,6 +2976,11 @@ static int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) } } + if (hcd->state == HC_STATE_QUIESCING) { + xhci_warn(xhci, "hcd->state=%d\n", hcd->state); + goto command_cleanup; + } + ret = xhci_configure_endpoint(xhci, udev, command, false, false); if (ret) diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c index 6dca69d619b4..2d47d5b3d377 100644 --- a/drivers/usb/pd/policy_engine.c +++ b/drivers/usb/pd/policy_engine.c @@ -3870,6 +3870,23 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr) if (pd->typec_mode == typec_mode) return 0; + 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; + } + + if ((typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT) || + (typec_mode == POWER_SUPPLY_TYPEC_SOURCE_MEDIUM) || + (typec_mode == POWER_SUPPLY_TYPEC_SOURCE_HIGH)) { + if (val.intval == POWER_SUPPLY_TYPE_UNKNOWN) { + usbpd_err(&pd->dev, "typec_mode:%d, psy_type:%d\n", + typec_mode, val.intval); + return 0; + } + } + pd->typec_mode = typec_mode; usbpd_dbg(&pd->dev, "typec mode:%d present:%d orientation:%d\n", diff --git a/drivers/usb/phy/phy-msm-qusb-v2.c b/drivers/usb/phy/phy-msm-qusb-v2.c index dd21f2a64c7f..a8b42d2eda75 100644 --- a/drivers/usb/phy/phy-msm-qusb-v2.c +++ b/drivers/usb/phy/phy-msm-qusb-v2.c @@ -48,6 +48,14 @@ #define CORE_RESET BIT(5) #define CORE_RESET_MUX BIT(6) +#define QUSB2PHY_PORT_TUNE1 0x240 +#define QUSB2PHY_PORT_TUNE2 0x244 +#define QUSB2PHY_PORT_TUNE3 0x248 +#define QUSB2PHY_PORT_TUNE4 0x24c +#define QUSB2PHY_PORT_TUNE5 0x250 +#define QUSB2PHY_PORT_BIAS1 0x194 +#define QUSB2PHY_PORT_BIAS2 0x198 + #define QUSB2PHY_1P8_VOL_MIN 1800000 /* uV */ #define QUSB2PHY_1P8_VOL_MAX 1800000 /* uV */ #define QUSB2PHY_1P8_HPM_LOAD 30000 /* uA */ @@ -75,6 +83,27 @@ /* STAT5 register bits */ #define VSTATUS_PLL_LOCK_STATUS_MASK BIT(0) +unsigned int phy_tune1; +module_param(phy_tune1, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(phy_tune1, "QUSB PHY v2 TUNE1"); +unsigned int phy_tune2; +module_param(phy_tune2, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(phy_tune2, "QUSB PHY v2 TUNE2"); +unsigned int phy_tune3; +module_param(phy_tune3, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(phy_tune3, "QUSB PHY v2 TUNE3"); +unsigned int phy_tune4; +module_param(phy_tune4, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(phy_tune4, "QUSB PHY v2 TUNE4"); +unsigned int phy_tune5; +module_param(phy_tune5, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(phy_tune5, "QUSB PHY v2 TUNE5"); +unsigned int phy_bias1; +module_param(phy_bias1, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(phy_bias1, "QUSB PHY v2 BIAS1"); +unsigned int phy_bias2; +module_param(phy_bias2, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(phy_bias2, "QUSB PHY v2 BIAS2"); /* DEBUG_CTRL4 register bits */ #define FORCED_UTMI_DPPULLDOWN BIT(2) @@ -116,6 +145,9 @@ struct qusb_phy { int vdd_levels[3]; /* none, low, high */ int init_seq_len; int *qusb_phy_init_seq; +/*2018/03/31 @BSP add host mode phy init parameters*/ + int ophost_init_seq_len; + int *qusb_phy_ophost_init_seq; int host_init_seq_len; int *qusb_phy_host_init_seq; @@ -123,6 +155,8 @@ struct qusb_phy { int qusb_phy_reg_offset_cnt; u32 tune_val; +/*2018/02/21 BSP@Infi do not need override the bias2 value*/ + bool overwrite_bias2_disable; int efuse_bit_pos; int efuse_num_of_bits; @@ -137,6 +171,11 @@ struct qusb_phy { struct pinctrl_state *atest_usb_suspend; struct pinctrl_state *atest_usb_active; +/*2018/06/28 @BSP Add HW-SW WR to optimize the usb diagram*/ + struct pinctrl_state *usb_oe_active; + struct pinctrl_state *usb_oe_suspend; + bool usb_oe_exist; + /* emulation targets specific */ void __iomem *emu_phy_base; bool emulation; @@ -448,6 +487,7 @@ static void qusb_phy_get_tune1_param(struct qusb_phy *qphy) qphy->tune_val = TUNE_VAL_MASK(qphy->tune_val, qphy->efuse_bit_pos, bit_mask); reg = readb_relaxed(qphy->base + qphy->phy_reg[PORT_TUNE1]); + pr_debug("%s(): tune1 value:0x%x before change\n",__func__, reg); reg = reg & 0x0f; reg |= (qphy->tune_val << 4); @@ -553,11 +593,6 @@ static void qusb_phy_host_init(struct usb_phy *phy) (4 * p_index)); } - if (qphy->refgen_north_bg_reg && qphy->override_bias_ctrl2) - if (readl_relaxed(qphy->refgen_north_bg_reg) & BANDGAP_BYPASS) - writel_relaxed(BIAS_CTRL_2_OVERRIDE_VAL, - qphy->base + qphy->phy_reg[BIAS_CTRL_2]); - if (qphy->bias_ctrl2) writel_relaxed(qphy->bias_ctrl2, qphy->base + qphy->phy_reg[BIAS_CTRL_2]); @@ -624,9 +659,18 @@ static int qusb_phy_init(struct usb_phy *phy) PWR_CTRL1_POWR_DOWN, qphy->base + qphy->phy_reg[PWR_CTRL1]); - if (qphy->qusb_phy_init_seq) - qusb_phy_write_seq(qphy->base, qphy->qusb_phy_init_seq, - qphy->init_seq_len, 0); +/*2018/03/31 @BSP add host mode phy init parameters*/ + if (qphy->qusb_phy_init_seq || qphy->qusb_phy_ophost_init_seq){ + if ((qphy->phy.flags & PHY_HOST_MODE) && qphy->qusb_phy_ophost_init_seq){ + dev_info(phy->dev, "%s PHY_HOST_MODE!\n", __func__); + qusb_phy_write_seq(qphy->base, qphy->qusb_phy_ophost_init_seq, + qphy->init_seq_len, 0); + } + else + qusb_phy_write_seq(qphy->base, qphy->qusb_phy_init_seq, + qphy->init_seq_len, 0); + } + if (qphy->efuse_reg) { qusb_phy_get_tune1_param(qphy); @@ -638,20 +682,74 @@ static int qusb_phy_init(struct usb_phy *phy) /* if debugfs based tunex params are set, use that value. */ for (p_index = 0; p_index < 5; p_index++) { - if (qphy->tune[p_index]) + if (qphy->tune[p_index]){ + pr_debug("%s(): Programming TUNE%d parameter as:%x\n", __func__,p_index+1, + qphy->tune_val); writel_relaxed(qphy->tune[p_index], qphy->base + qphy->phy_reg[PORT_TUNE1] + (4 * p_index)); + } } - if (qphy->refgen_north_bg_reg && qphy->override_bias_ctrl2) - if (readl_relaxed(qphy->refgen_north_bg_reg) & BANDGAP_BYPASS) - writel_relaxed(BIAS_CTRL_2_OVERRIDE_VAL, - qphy->base + qphy->phy_reg[BIAS_CTRL_2]); - if (qphy->bias_ctrl2) writel_relaxed(qphy->bias_ctrl2, qphy->base + qphy->phy_reg[BIAS_CTRL_2]); +/*2018/02/21 BSP@Infi do not need override the bias2 value*/ + if (qphy->refgen_north_bg_reg && !qphy->overwrite_bias2_disable) + if (readl_relaxed(qphy->refgen_north_bg_reg) & BANDGAP_BYPASS){ + pr_debug("%s(): overwrite bias2\n", __func__); + writel_relaxed(BIAS_CTRL_2_OVERRIDE_VAL, + qphy->base + qphy->phy_reg[BIAS_CTRL_2]); + } + /* If phy_tune1 modparam set, override tune1 value */ + if (phy_tune1) { + pr_err("%s(): (modparam) TUNE1 val:0x%02x\n", + __func__, phy_tune1); + writel_relaxed(phy_tune1, + qphy->base + qphy->phy_reg[PORT_TUNE1]); + } + /* If phy_tune2 modparam set, override tune2 value */ + if (phy_tune2) { + pr_err("%s(): (modparam) TUNE2 val:0x%02x\n", + __func__, phy_tune2); + writel_relaxed(phy_tune2, + qphy->base + qphy->phy_reg[PORT_TUNE1]+4); + } + /* If phy_tune3 modparam set, override tune3 value */ + if (phy_tune3) { + pr_err("%s(): (modparam) TUNE3 val:0x%02x\n", + __func__, phy_tune3); + writel_relaxed(phy_tune3, + qphy->base + qphy->phy_reg[PORT_TUNE1]+8); + } + /* If phy_tune4 modparam set, override tune4 value */ + if (phy_tune4) { + pr_err("%s(): (modparam) TUNE4 val:0x%02x\n", + __func__, phy_tune4); + writel_relaxed(phy_tune4, + qphy->base + qphy->phy_reg[PORT_TUNE1]+0xc); + } + /* If phy_tune5 modparam set, override tune5 value */ + if (phy_tune5) { + pr_err("%s(): (modparam) TUNE5 val:0x%02x\n", + __func__, phy_tune5); + writel_relaxed(phy_tune5, + qphy->base + qphy->phy_reg[PORT_TUNE1]+0x10); + } + /* If phy_BIAS1 modparam set, override bias1 value */ + if (phy_bias1) { + pr_err("%s(): (modparam) bias1 val:0x%02x\n", + __func__, phy_bias1); + writel_relaxed(phy_bias1, + qphy->base + qphy->phy_reg[BIAS_CTRL_2]-4); + } + /* If phy_BIAS2 modparam set, override bias2 value */ + if (phy_bias2) { + pr_err("%s(): (modparam) bias2 val:0x%02x\n", + __func__, phy_bias2); + writel_relaxed(phy_bias2, + qphy->base + qphy->phy_reg[BIAS_CTRL_2]); + } /* ensure above writes are completed before re-enabling PHY */ wmb(); @@ -687,6 +785,14 @@ static enum hrtimer_restart qusb_dis_ext_pulldown_timer(struct hrtimer *timer) if (ret < 0) dev_err(qphy->phy.dev, "pinctrl state suspend select failed\n"); +/*2018/06/28 @BSP Add HW-SW WR to optimize the usb diagram*/ + if (qphy->usb_oe_exist && qphy->usb_oe_active) { + ret = pinctrl_select_state(qphy->pinctrl, + qphy->usb_oe_active); + if (ret < 0) + dev_err(qphy->phy.dev, + "pinctrl state usb_oe_active select failed\n"); + } } return HRTIMER_NORESTART; @@ -707,11 +813,35 @@ static void qusb_phy_enable_ext_pulldown(struct usb_phy *phy) "pinctrl state active select failed\n"); return; } - +/*2018/06/28 @BSP Add HW-SW WR to optimize the usb diagram*/ + if (qphy->usb_oe_exist && qphy->usb_oe_suspend) { + ret = pinctrl_select_state(qphy->pinctrl, + qphy->usb_oe_suspend); + if (ret < 0) + dev_err(phy->dev, + "pinctrl state usb_oe_suspend select failed\n"); + } hrtimer_start(&qphy->timer, ms_to_ktime(10), HRTIMER_MODE_REL); } } +/*2018/06/28 @BSP Add HW-SW WR to optimize the usb diagram*/ +static void qusb_phy_enable_usb_oe(struct usb_phy *phy) +{ + struct qusb_phy *qphy = container_of(phy, struct qusb_phy, phy); + int ret = 0; + + dev_dbg(phy->dev, "%s\n", __func__); + + if (qphy->pinctrl && qphy->usb_oe_active) { + ret = pinctrl_select_state(qphy->pinctrl, + qphy->usb_oe_active); + if (ret < 0) + dev_err(phy->dev, + "pinctrl state usb_oe_active select failed\n"); + } +} + static void qusb_phy_shutdown(struct usb_phy *phy) { struct qusb_phy *qphy = container_of(phy, struct qusb_phy, phy); @@ -1126,6 +1256,9 @@ static int qusb_phy_probe(struct platform_device *pdev) qphy->efuse_reg = devm_ioremap_nocache(dev, res->start, resource_size(res)); if (!IS_ERR_OR_NULL(qphy->efuse_reg)) { +/*2018/02/21 BSP@Infi do not need override the bias2 value*/ + qphy->overwrite_bias2_disable = of_property_read_bool(dev->of_node, + "qcom,overwrite-bias2-disable"); ret = of_property_read_u32(dev->of_node, "qcom,efuse-bit-pos", &qphy->efuse_bit_pos); @@ -1317,6 +1450,31 @@ static int qusb_phy_probe(struct platform_device *pdev) } } +/*2018/03/31 @BSP add host mode phy init parameters*/ + size = 0; + of_get_property(dev->of_node, "qcom,qusb-phy-ophost-init-seq", &size); + if (size) { + dev_info(dev,"%s:qusb-phy-ophost-init-seq got!",__func__); + qphy->qusb_phy_ophost_init_seq = devm_kzalloc(dev, + size, GFP_KERNEL); + if (qphy->qusb_phy_ophost_init_seq) { + qphy->ophost_init_seq_len = + (size / sizeof(*qphy->qusb_phy_ophost_init_seq)); + if (qphy->ophost_init_seq_len % 2) { + dev_err(dev, "invalid ophost_init_seq_len\n"); + return -EINVAL; + } + + of_property_read_u32_array(dev->of_node, + "qcom,qusb-phy-ophost-init-seq", + qphy->qusb_phy_ophost_init_seq, + qphy->ophost_init_seq_len); + } else { + dev_err(dev, + "error allocating memory for phy_ophost_init_seq\n"); + } + } + qphy->host_init_seq_len = of_property_count_elems_of_size(dev->of_node, "qcom,qusb-phy-host-init-seq", sizeof(*qphy->qusb_phy_host_init_seq)); @@ -1380,6 +1538,22 @@ static int qusb_phy_probe(struct platform_device *pdev) dev_err(dev, "pinctrl lookup active failed\n"); } +/*2018/06/28 @BSP Add HW-SW WR to optimize the usb diagram*/ + qphy->usb_oe_exist = of_property_read_bool(dev->of_node, + "qcom,usb-oe-exist"); + dev_info(dev, "usb_oe_exist=%d\n", qphy->usb_oe_exist); + if (qphy->usb_oe_exist) { + qphy->usb_oe_suspend = pinctrl_lookup_state(qphy->pinctrl, + "usb_oe_suspend"); + if (IS_ERR(qphy->usb_oe_suspend)) + dev_err(dev, "pinctrl lookup usb_oe_suspend failed\n"); + + qphy->usb_oe_active = pinctrl_lookup_state(qphy->pinctrl, + "usb_oe_active"); + if (IS_ERR(qphy->usb_oe_active)) + dev_err(dev, "pinctrl lookup usb_oe_active failed\n"); + } + hrtimer_init(&qphy->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); qphy->timer.function = qusb_dis_ext_pulldown_timer; @@ -1406,6 +1580,10 @@ static int qusb_phy_probe(struct platform_device *pdev) usb_remove_phy(&qphy->phy); qphy->suspended = true; + +/*2018/06/28 @BSP Add HW-SW WR to optimize the usb diagram*/ + if (qphy->usb_oe_exist) + qusb_phy_enable_usb_oe(&qphy->phy); qusb_phy_create_debugfs(qphy); /* From 481bf414d64e6304326e7d6f502eefe195482071 Mon Sep 17 00:00:00 2001 From: LuK1337 Date: Fri, 1 Feb 2019 18:21:35 +0100 Subject: [PATCH 246/356] firmware: Add /vendor/etc/firmware to firmware paths Change-Id: Ic36688ba5708866fd985e3f88fdf7a90fd32aebe --- drivers/base/firmware_loader/main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/base/firmware_loader/main.c b/drivers/base/firmware_loader/main.c index 94b96a9a4e66..79a2d944cf22 100644 --- a/drivers/base/firmware_loader/main.c +++ b/drivers/base/firmware_loader/main.c @@ -287,7 +287,8 @@ static const char * const fw_path[] = { "/lib/firmware/updates/" UTS_RELEASE, "/lib/firmware/updates", "/lib/firmware/" UTS_RELEASE, - "/lib/firmware" + "/lib/firmware", + "/vendor/etc/firmware/" }; /* From 4c6367c8b645843153ee47df1fb81b45bd7bb893 Mon Sep 17 00:00:00 2001 From: LuK1337 Date: Thu, 7 Nov 2019 19:39:18 +0100 Subject: [PATCH 247/356] cpuidle: Import OnePlus changes Change-Id: Ib62019aa4a49ae9cf6d4014d43c74a5843763e41 --- drivers/cpuidle/lpm-levels.c | 6 ++++++ include/linux/pm_qos.h | 2 ++ 2 files changed, 8 insertions(+) diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c index a87df3c9faf1..ba5973bbee89 100644 --- a/drivers/cpuidle/lpm-levels.c +++ b/drivers/cpuidle/lpm-levels.c @@ -125,6 +125,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 * diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h index 1d6f8439d67b..fece2c4804bb 100644 --- a/include/linux/pm_qos.h +++ b/include/linux/pm_qos.h @@ -157,6 +157,8 @@ int pm_qos_remove_notifier(int pm_qos_class, struct notifier_block *notifier); int pm_qos_request_active(struct pm_qos_request *req); s32 pm_qos_read_value(struct pm_qos_constraints *c); +extern void msm_cpuidle_set_sleep_disable(bool disable); + #ifdef CONFIG_PM enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev, s32 mask); enum pm_qos_flags_status dev_pm_qos_flags(struct device *dev, s32 mask); From d576d6eb575a99deff232eb877fb23e039d5db34 Mon Sep 17 00:00:00 2001 From: Luca Stefani Date: Sat, 28 Jul 2018 10:36:39 +0200 Subject: [PATCH 248/356] drivers: msm_geni: Import OnePlus changes Change-Id: I464efe6f332ac12eba9e2b666e6996e8479fed4b --- drivers/tty/serial/msm_geni_serial.c | 63 ++++++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 3 deletions(-) diff --git a/drivers/tty/serial/msm_geni_serial.c b/drivers/tty/serial/msm_geni_serial.c index 1bc8b9bb0476..8ee13e679130 100644 --- a/drivers/tty/serial/msm_geni_serial.c +++ b/drivers/tty/serial/msm_geni_serial.c @@ -3953,6 +3953,7 @@ static struct uart_driver msm_geni_serial_hs_driver = { .nr = GENI_UART_NR_PORTS, }; +static int msm_serial_oem_pinctrl_init(void); static int __init msm_geni_serial_init(void) { int ret = 0; @@ -3972,9 +3973,11 @@ 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; + if (false) { + ret = console_register(&msm_geni_console_driver); + if (ret) + return ret; + } ret = uart_register_driver(&msm_geni_serial_hs_driver); if (ret) { @@ -3989,6 +3992,8 @@ static int __init msm_geni_serial_init(void) return ret; } + msm_serial_oem_pinctrl_init(); + pr_info("%s: Driver initialized\n", __func__); return ret; @@ -4003,6 +4008,58 @@ static void __exit msm_geni_serial_exit(void) } module_exit(msm_geni_serial_exit); +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); + MODULE_DESCRIPTION("Serial driver for GENI based QTI serial cores"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("tty:msm_geni_geni_serial"); From c7f6ba2495179cdb2fef08ab4f2e9b6478f6b748 Mon Sep 17 00:00:00 2001 From: Luca Stefani Date: Sat, 28 Jul 2018 10:40:52 +0200 Subject: [PATCH 249/356] drivers: input: qpnp-power-on: Import OnePlus changes Change-Id: Id18d77d2bb5d6ad03f532b7285559d4fe4ceaaad --- drivers/input/misc/qpnp-power-on.c | 38 ------------------ include/linux/input/qpnp-power-on.h | 60 +++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 38 deletions(-) diff --git a/drivers/input/misc/qpnp-power-on.c b/drivers/input/misc/qpnp-power-on.c index 56918e9ef768..fbd44239815a 100644 --- a/drivers/input/misc/qpnp-power-on.c +++ b/drivers/input/misc/qpnp-power-on.c @@ -191,44 +191,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; - bool log_kpd_event; -}; - static int pon_ship_mode_en; module_param_named( ship_mode_en, pon_ship_mode_en, int, 0600 diff --git a/include/linux/input/qpnp-power-on.h b/include/linux/input/qpnp-power-on.h index d80ab2b31d43..d29b29fabb78 100644 --- a/include/linux/input/qpnp-power-on.h +++ b/include/linux/input/qpnp-power-on.h @@ -46,6 +46,45 @@ enum pon_power_off_type { PON_POWER_OFF_MAX_TYPE = 0x10, }; +/* david.liu@bsp, 20171023 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 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; + bool log_kpd_event; +}; + enum pon_restart_reason { PON_RESTART_REASON_UNKNOWN = 0x00, PON_RESTART_REASON_RECOVERY = 0x01, @@ -54,8 +93,29 @@ 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_AGING = 0x07, + PON_RESTART_REASON_REBOOT = 0x10, + PON_RESTART_REASON_FACTORY = 0x11, + PON_RESTART_REASON_WLAN = 0x12, + PON_RESTART_REASON_RF = 0x13, + PON_RESTART_REASON_MOS = 0x14, + PON_RESTART_REASON_KERNEL = 0x15, + PON_RESTART_REASON_ANDROID = 0x16, + PON_RESTART_REASON_MODEM = 0x17, + PON_RESTART_REASON_PANIC = 0x18, }; +/* Define OEM reboot mode magic*/ +#define AGING_MODE 0x77665510 +#define FACTORY_MODE 0x77665504 +#define WLAN_MODE 0x77665505 +#define RF_MODE 0x77665506 +#define MOS_MODE 0x77665507 +#define KERNEL_MODE 0x7766550d +#define ANDROID_MODE 0x7766550c +#define MODEM_MODE 0x7766550b +#define OEM_PANIC 0x77665518 + #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); From 107aeef8bd1484794d1de8e037918061e9213cca Mon Sep 17 00:00:00 2001 From: Luca Stefani Date: Sat, 28 Jul 2018 10:35:07 +0200 Subject: [PATCH 250/356] drivers: qcom: Import project_info Change-Id: Ib33032c63dae39e9ba6f06e9f297248611f7a321 --- drivers/soc/qcom/Makefile | 1 + drivers/soc/qcom/project_info.c | 889 ++++++++++++++++++++++++++++++++ include/linux/project_info.h | 95 ++++ 3 files changed, 985 insertions(+) create mode 100644 drivers/soc/qcom/project_info.c create mode 100644 include/linux/project_info.h diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index d18ccb6f9a2c..8b07513be726 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -111,3 +111,4 @@ obj-$(CONFIG_QTI_CRYPTO_TZ) += crypto-qti-tz.o obj-$(CONFIG_QTI_HW_KEY_MANAGER) += hwkm_qti.o hwkm_qti-y += hwkm.o obj-$(CONFIG_MSM_BAM_DMUX) += bam_dmux.o +obj-y += project_info.o diff --git a/drivers/soc/qcom/project_info.c b/drivers/soc/qcom/project_info.c new file mode 100644 index 000000000000..ddf9347daf75 --- /dev/null +++ b/drivers/soc/qcom/project_info.c @@ -0,0 +1,889 @@ +/* For OEM project information + *such as project name, hardware ID + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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; + +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(modem, 0444, project_info_get, NULL); +static DEVICE_ATTR(operator_no, 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(feature_id, 0444, project_info_get, NULL); +static DEVICE_ATTR(aboard_id, 0444, project_info_get, NULL); + +void save_dump_reason_to_smem(char *info, char *function_name) +{ + int strl = 0, strl1 = 0; + static int flag = 0; + + /* Make sure save_dump_reason_to_smem() is not called + infinite times by panic() during DDR bit flip crash etc */ + if (flag > 1) + return; + + dp_info = smem_alloc(SMEM_DUMP_INFO, + sizeof(struct dump_info), 0, + SMEM_ANY_HOST_FLAG); + + if (IS_ERR_OR_NULL(dp_info)) + pr_err("%s: get dp_info failure\n", __func__); + else { + pr_err("%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) < DUMP_REASON_SIZE)) { + strncat(dp_info->dump_reason,function_name,strl1); + strncat(dp_info->dump_reason,"\n",1); + } + } + pr_err("\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_modem) + return snprintf(buf, BUF_SIZE, "%d\n", + project_info_desc->modem); + if (attr == &dev_attr_operator_no) + return snprintf(buf, BUF_SIZE, "%d\n", + project_info_desc->operator); + 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_feature_id) + return snprintf(buf, BUF_SIZE, "%d\n", + project_info_desc->feature_id); + + if (attr == &dev_attr_aboard_id) + return snprintf(buf, BUF_SIZE, "%d\n", + project_info_desc->a_board_version); + } + + 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_modem.attr, + &dev_attr_operator_no.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_feature_id.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(r_camera, 0444, component_info_get, NULL); +static DEVICE_ATTR(second_r_camera, 0444, component_info_get, NULL); +static DEVICE_ATTR(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(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_r_camera.attr, + &dev_attr_second_r_camera.attr, + &dev_attr_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_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_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_ois) + return snprintf(buf, BUF_SIZE, "VER:\t%s\nMANU:\t%s\n", + get_component_version(OIS), + get_component_manufacture(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) { + //op_aboard_read_gpio(); + 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_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[] = { + {194, "MSM8974AC "}, + {217, "MSM8974AA "}, + {218, "MSM8974AB "}, + {207, "MSM8994 "}, + {246, "MSM8996 "}, + {292, "MSM8998 "}, + {302, "MSM8996L "}, + {305, "MSM8996SG "}, + {310, "MSM8996AU "}, + {321, "SDM845 "}, + {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, BUF_SIZE, "%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, BUF_SIZE, + "%s", cpu_list_msm[i].name); + break; + } + } + } +} + +static char mainboard_version[16] = {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_borad_version{ + + int version; + char name[16]; +}; + +struct a_borad_version a_borad_version_string_arry[]={ + + {1, "TMO"}, + {2, "US/EU" }, + {3, "CN/IN"}, + {4, "Unknown"}, + {5, "Unknown" }, +}; + + +struct a_borad_version a_borad_version_string_arry_gpio[]={ + + {0, "TMO"}, + {1, "US/EU/TMO" }, + {2, "CN/IN"}, + {3, "Unknown"}, + {4, "Unknown" }, + {5, "Unknown"}, + +}; + +uint32 get_hw_version(void) +{ + project_info_desc = smem_find(SMEM_PROJECT_INFO, + sizeof(struct project_info), + 0, + SMEM_ANY_HOST_FLAG); + + 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; +} + +int __init init_project_info(void) +{ + static bool project_info_init_done; + int ddr_size = 0; + + if (project_info_init_done) + return 0; + + project_info_desc = smem_find(SMEM_PROJECT_INFO, + sizeof(struct project_info), + 0, + SMEM_ANY_HOST_FLAG); + + if (IS_ERR_OR_NULL(project_info_desc)) { + pr_err("%s: get project_info failure\n", __func__); + return 0; + } + pr_err("%s: project_name: %s hw_version: %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->rf_v1, + project_info_desc->rf_v2, + project_info_desc->rf_v3, + project_info_desc->platform_id); + + switch (project_info_desc->hw_version) { + case 11: + snprintf(mainboard_version, sizeof(mainboard_version), "%s %s", + project_info_desc->project_name, "EVB"); + break; + case 12: + snprintf(mainboard_version, sizeof(mainboard_version), "%s %s", + project_info_desc->project_name, "T0"); + break; + case 13: + snprintf(mainboard_version, sizeof(mainboard_version), "%s %s", + project_info_desc->project_name, "T1"); + break; + case 14: + snprintf(mainboard_version, sizeof(mainboard_version), "%s %s", + project_info_desc->project_name, "EVT1"); + break; + case 15: + snprintf(mainboard_version, sizeof(mainboard_version), "%s %s", + project_info_desc->project_name, "EVT2"); + break; + case 21: + snprintf(mainboard_version, sizeof(mainboard_version), "%s %s", + project_info_desc->project_name, "DVT"); + break; + case 22: + snprintf(mainboard_version, sizeof(mainboard_version), "%s %s", + project_info_desc->project_name, "PVT"); + break; + case 23: + snprintf(mainboard_version, sizeof(mainboard_version), "%s %s", + project_info_desc->project_name, "PVT"); + break; + case 24: + snprintf(mainboard_version, sizeof(mainboard_version), "%s %s", + project_info_desc->project_name, "PVT_MCU"); + break; + case 25: + snprintf(mainboard_version, sizeof(mainboard_version), "%s %s", + project_info_desc->project_name, "DVTBACKUP"); + break; + + case 31: + snprintf(mainboard_version, sizeof(mainboard_version), "%s %s", + project_info_desc->project_name, "EVB"); + break; + case 32: + snprintf(mainboard_version, sizeof(mainboard_version), "%s %s", + project_info_desc->project_name, "T0"); + break; + case 33: + snprintf(mainboard_version, sizeof(mainboard_version), "%s %s", + project_info_desc->project_name, "EVT1"); + break; + case 34: + snprintf(mainboard_version, sizeof(mainboard_version), "%s %s", + project_info_desc->project_name, "DVT"); + break; + case 35: + snprintf(mainboard_version, sizeof(mainboard_version), "%s %s", + project_info_desc->project_name, "2ND"); + break; + case 41: + snprintf(mainboard_version, sizeof(mainboard_version), "%s %s", + project_info_desc->project_name, "PVT"); + break; + case 42: + snprintf(mainboard_version, sizeof(mainboard_version), "%s %s", + project_info_desc->project_name, "PVT2nd"); + break; + case 43: + snprintf(mainboard_version, sizeof(mainboard_version), "%s %s", + project_info_desc->project_name, "PVT-1"); + break; + case 44: + snprintf(mainboard_version, sizeof(mainboard_version), "%s %s", + project_info_desc->project_name, "PVTSpec"); + break; + case 45: + snprintf(mainboard_version, sizeof(mainboard_version), "%s %s", + project_info_desc->project_name, "MPSpec"); + break; + case 55: + snprintf(mainboard_version, sizeof(mainboard_version), "%s %s", + project_info_desc->project_name, "DVTUSB30"); + break; + + default: + snprintf(mainboard_version, sizeof(mainboard_version), "%d", + project_info_desc->hw_version); + break; + } + push_component_info(MAINBOARD, + mainboard_version, + mainboard_manufacture); + + if( project_info_desc->hw_version <= 32 ) { + snprintf(Aboard_version, sizeof(Aboard_version), "%d %s", + project_info_desc->a_board_version,project_info_desc->a_board_version <=5 ? + a_borad_version_string_arry[project_info_desc->a_board_version -1].name:"Unknown"); + + push_component_info(ABOARD, Aboard_version, mainboard_manufacture); + pr_err("%s: Aboard_gpio(%s)\n", __func__, Aboard_version); + + } + + 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(); + if (totalram_pages > 9*(1<<18)) + ddr_size = 10; + else if (totalram_pages > 6*(1<<18)) + ddr_size = 8; + else if (totalram_pages > 5*(1<<18)) + ddr_size = 6; + else if (totalram_pages > 4*(1<<18)) + ddr_size = 5; + else if (totalram_pages > 3*(1<<18)) + ddr_size = 4; + else if (totalram_pages > 2*(1<<18)) + ddr_size = 3; + else if (totalram_pages > 1*(1<<18)) + ddr_size = 2; + + 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; + + return 0; +} +struct aborad_data { + int aboard_gpio_0;//gpio33 + int aboard_gpio_1;//gpio34 + struct pinctrl *pinctrl; + struct pinctrl_state *pinctrl_state_active; + struct pinctrl_state *pinctrl_state_suspend; + + struct device *dev; +}; +static struct aborad_data *data = NULL ; + +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 ) + { + return 0 ; + } + gpio0 = gpio_get_value(data->aboard_gpio_0); + gpio1 = gpio_get_value(data->aboard_gpio_1); + + pr_err("%s: gpio0=%d gpio1=%d\n", __func__, gpio0,gpio1); + + if( gpio0 == 0 && gpio1 == 0 ) + { + project_info_desc->a_board_version = 0 ; + } + else if( gpio0 == 0 && gpio1 == 1 ) + { + project_info_desc->a_board_version = 1 ; + } + else if( gpio0 == 1 && gpio1 == 0 ) + { + project_info_desc->a_board_version = 2 ; + } + else + { + project_info_desc->a_board_version = -1 ; + } + snprintf(Aboard_version, sizeof(Aboard_version), "%d %s", + project_info_desc->a_board_version,project_info_desc->a_board_version <3 ? + a_borad_version_string_arry_gpio[project_info_desc->a_board_version].name:"Unknown"); + + 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 aborad_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: op_rf_request_named_gpio gpio-0 fail\n", + __func__); + goto exit_gpio; + } + rc = op_aboard_request_named_gpio("oem,aboard-gpio-1",&data->aboard_gpio_1); + if (rc) { + pr_err("%s: op_rf_request_named_gpio gpio-1 fail\n", + __func__); + goto exit_gpio; + } + + 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); + } + + gpio_direction_input(data->aboard_gpio_0); + gpio_direction_input(data->aboard_gpio_1); + op_aboard_read_gpio(); + pr_err("%s: probe ok!\n", __func__); + return 0; + +err_pinctrl_lookup: + devm_pinctrl_put(data->pinctrl); +err_pinctrl_get: + data->pinctrl = NULL; +exit_gpio: + 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; + + init_project_info(); + + if( project_info_desc->hw_version > 32 ){ + ret = platform_driver_register(&aboard_driver); + if (ret) + pr_err("aboard_driver register failed: %d\n", ret); + }else { + ret = 0; + } + return ret; +} + + +subsys_initcall(init_project); diff --git a/include/linux/project_info.h b/include/linux/project_info.h new file mode 100644 index 000000000000..670e5d07b156 --- /dev/null +++ b/include/linux/project_info.h @@ -0,0 +1,95 @@ +#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 + +#include +#include +//extern uint32_t chip_serial_num; +extern unsigned long totalram_pages __read_mostly; + +struct project_info { + char project_name[8]; //eg, 16859 + uint32 hw_version; //PCB number, T0, EVT + uint32 rf_v1; //v1 for mainboard_rf_version + uint32 rf_v2; //v2 for aboard_rf_version + uint32 rf_v3; + uint32 modem; + uint32 operator; + uint32 ddr_manufacture_info; + uint32 ddr_row; + uint32 ddr_column; + uint32 ddr_fw_version; + uint32 ddr_reserve_info; + uint32 platform_id; + uint32 ftm_uart_boot_mode; + uint32 feature_id; + uint32 a_board_version; +}; + +#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, + R_CAMERA, + SECOND_R_CAMERA, + 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, + CPU, + RF_VERSION, + COMPONENT_MAX, +}; + +enum { + SMEM_ID_VENDOR1, + SMEM_DUMP_INFO = SMEM_ID_VENDOR1, + /*For more details, could check boot_iamges/core/api/mproc/smem_type.h*/ + SMEM_PROJECT_INFO = 136, +}; + +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 From 64502d5087bcff81cf3f3e6cb63c88f5343eb322 Mon Sep 17 00:00:00 2001 From: LuK1337 Date: Thu, 7 Nov 2019 21:56:03 +0100 Subject: [PATCH 251/356] drivers: qcom: Import op_rf_cable_monitor Change-Id: I52789ebad63d190d95cb03b94b619846bfa8ab80 --- drivers/soc/qcom/Kconfig | 8 + drivers/soc/qcom/Makefile | 1 + drivers/soc/qcom/op_rf_cable_monitor.c | 342 +++++++++++++++++++++++++ drivers/soc/qcom/subsystem_restart.c | 16 ++ include/linux/op_rf_cable_monitor.h | 10 + 5 files changed, 377 insertions(+) create mode 100644 drivers/soc/qcom/op_rf_cable_monitor.c create mode 100644 include/linux/op_rf_cable_monitor.h diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 3bde0c2a3108..7e82e9f0e748 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -994,4 +994,12 @@ config ICNSS_QMI and configurations. It also send WLAN on/off control message to FW over QMI channel. +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. + source "drivers/soc/qcom/wcnss/Kconfig" diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 8b07513be726..fb630ad88791 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -112,3 +112,4 @@ obj-$(CONFIG_QTI_HW_KEY_MANAGER) += hwkm_qti.o hwkm_qti-y += hwkm.o obj-$(CONFIG_MSM_BAM_DMUX) += bam_dmux.o obj-y += project_info.o +obj-$(CONFIG_RF_CABLE_DETECT) += op_rf_cable_monitor.o diff --git a/drivers/soc/qcom/op_rf_cable_monitor.c b/drivers/soc/qcom/op_rf_cable_monitor.c new file mode 100644 index 000000000000..32e8a96b4afc --- /dev/null +++ b/drivers/soc/qcom/op_rf_cable_monitor.c @@ -0,0 +1,342 @@ +/*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 + +static struct project_info *project_info_desc; + +struct cable_data { + int irq_0; + int irq_1; + int cable_gpio_0;//gpio32 + int cable_gpio_1;//gpio86 + struct delayed_work work; + struct workqueue_struct *wqueue; + struct device *dev; + struct wakeup_source wl; + atomic_t running; + int rf_v3; + int rf_v3_pre; + spinlock_t lock; + int enable; +}; +static struct cable_data *_cdata; +static DEFINE_MUTEX(sem); + +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) +{ + project_info_desc = smem_find(SMEM_PROJECT_INFO, + sizeof(struct project_info), 0, + SMEM_ANY_HOST_FLAG); + + 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; +} + + +static void rf_cable_work(struct work_struct *work) +{ + unsigned long flags; + + spin_lock_irqsave(&_cdata->lock, flags); + disable_irq_nosync(_cdata->irq_0); + disable_irq_nosync(_cdata->irq_1); + spin_unlock_irqrestore(&_cdata->lock, flags); + pr_err("modem :kevin debug:%s, %d:_cdata->rf_v3_pre=%d, _cdata->rf_v3=%d,\n", + __func__, __LINE__, _cdata->rf_v3_pre, _cdata->rf_v3); + + _cdata->rf_v3 = + gpio_get_value(_cdata->cable_gpio_0) || + gpio_get_value(_cdata->cable_gpio_1); + + modify_rf_cable_smem_info(_cdata->rf_v3); + if (_cdata->rf_v3 != _cdata->rf_v3_pre) + op_restart_modem(); + + _cdata->rf_v3_pre = + gpio_get_value(_cdata->cable_gpio_0) || + gpio_get_value(_cdata->cable_gpio_1); + + + spin_lock_irqsave(&_cdata->lock, flags); + enable_irq(_cdata->irq_0); + enable_irq(_cdata->irq_1); + spin_unlock_irqrestore(&_cdata->lock, flags); +} + +irqreturn_t cable_interrupt(int irq, void *_dev) +{ + __pm_wakeup_event(&_cdata->wl, + msecs_to_jiffies(CABLE_WAKELOCK_HOLD_TIME)); + queue_delayed_work(_cdata->wqueue, + &_cdata->work, msecs_to_jiffies(1)); + return IRQ_HANDLED; +} + +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", _cdata->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) +{ + unsigned long flags; + 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; + + + if (enable != _cdata->enable) { + _cdata->enable = enable; + if (!_cdata->enable) { + spin_lock_irqsave(&_cdata->lock, flags); + disable_irq_nosync(_cdata->irq_0); + disable_irq_nosync(_cdata->irq_1); + spin_unlock_irqrestore(&_cdata->lock, flags); + _cdata->rf_v3 = 1; + + modify_rf_cable_smem_info(1); + if (!_cdata->rf_v3_pre) + op_restart_modem(); + _cdata->rf_v3_pre = 1; + } else { + spin_lock_irqsave(&_cdata->lock, flags); + enable_irq(_cdata->irq_0); + enable_irq(_cdata->irq_1); + spin_unlock_irqrestore(&_cdata->lock, flags); + + _cdata->rf_v3 = gpio_get_value(_cdata->cable_gpio_0) || + gpio_get_value(_cdata->cable_gpio_1); + + modify_rf_cable_smem_info(_cdata->rf_v3); + if (_cdata->rf_v3 != _cdata->rf_v3_pre) + op_restart_modem(); + _cdata->rf_v3_pre = + gpio_get_value(_cdata->cable_gpio_0) || + gpio_get_value(_cdata->cable_gpio_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; + } + _cdata->enable = 1; + return ret; +} + +static int op_rf_request_named_gpio(const char *label, int *gpio) +{ + struct device *dev = _cdata->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_rf_cable_probe(struct platform_device *pdev) +{ + int rc = 0; + struct device *dev = &pdev->dev; + + if (cmdline_find_option("ftm_mode")) { + pr_err("%s: ftm_mode FOUND! use 1 always\n", __func__); + modify_rf_cable_smem_info(1); + } else { + _cdata = kzalloc(sizeof(struct cable_data), GFP_KERNEL); + if (!_cdata) { + pr_err("%s: failed to allocate memory\n", __func__); + rc = -ENOMEM; + goto exit; + } + + _cdata->dev = dev; + dev_set_drvdata(dev, _cdata); +//request gpio 0 .gpio 1. + rc = op_rf_request_named_gpio("rf,cable-gpio-0", + &_cdata->cable_gpio_0); + if (rc) { + pr_err("%s: op_rf_request_named_gpio gpio-0 fail\n", + __func__); + goto exit_gpio; + } + rc = op_rf_request_named_gpio("rf,cable-gpio-1", + &_cdata->cable_gpio_1); + if (rc) { + pr_err("%s: op_rf_request_named_gpio gpio-1 fail\n", + __func__); + goto exit_gpio; + } +//set input and gpio to irq. + gpio_direction_input(_cdata->cable_gpio_0); + _cdata->irq_0 = gpio_to_irq(_cdata->cable_gpio_0); + if (_cdata->irq_0 < 0) { + pr_err("Unable to get irq number for GPIO %d, error %d\n", + _cdata->cable_gpio_0, _cdata->irq_0); + rc = _cdata->irq_0; + goto exit_gpio; + } + + gpio_direction_input(_cdata->cable_gpio_1); + _cdata->irq_1 = gpio_to_irq(_cdata->cable_gpio_1); + if (_cdata->irq_1 < 0) { + pr_err("Unable to get irq number for GPIO %d, error %d\n", + _cdata->cable_gpio_1, _cdata->irq_1); + rc = _cdata->irq_1; + goto exit_gpio; + } +//creat workqueue. + _cdata->wqueue = create_singlethread_workqueue( + "op_rf_cable_wqueue"); + INIT_DELAYED_WORK(&_cdata->work, rf_cable_work); + +//request _irq0 + rc = request_irq(_cdata->irq_0, cable_interrupt, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + "op_rf_cable", _cdata); + if (rc) { + pr_err("could not request irq %d\n", _cdata->irq_0); + goto exit_gpio; + } + pr_err("requested irq %d\n", _cdata->irq_0); + enable_irq_wake(_cdata->irq_0); + +//request _irq1 + rc = request_irq(_cdata->irq_1, cable_interrupt, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + "op_rf_cable", _cdata); + if (rc) { + pr_err("could not request irq %d\n", _cdata->irq_1); + goto exit_gpio; + } + + pr_err("requested irq %d\n", _cdata->irq_1); + enable_irq_wake(_cdata->irq_1); + + wakeup_source_init(&_cdata->wl, + "rf_cable_wake_lock"); + spin_lock_init(&_cdata->lock); + atomic_set(&_cdata->running, + gpio_get_value(_cdata->cable_gpio_0) || + gpio_get_value(_cdata->cable_gpio_1)); + + modify_rf_cable_smem_info( + gpio_get_value(_cdata->cable_gpio_0) || + gpio_get_value(_cdata->cable_gpio_1)); + create_rf_cable_procfs(); + } + pr_err("%s: probe ok!\n", __func__); + return 0; + +exit_gpio: + kfree(_cdata); +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"); +subsys_initcall(op_rf_cable_init); diff --git a/drivers/soc/qcom/subsystem_restart.c b/drivers/soc/qcom/subsystem_restart.c index 2479632e103b..b25637ac1f6a 100644 --- a/drivers/soc/qcom/subsystem_restart.c +++ b/drivers/soc/qcom/subsystem_restart.c @@ -831,6 +831,22 @@ struct subsys_device *find_subsys_device(const char *str) } EXPORT_SYMBOL(find_subsys_device); +static int restart_level;/*system original val*/ +int op_restart_modem(void) +{ + struct subsys_device *subsys = find_subsys_device("modem"); + + if (!subsys) + return -ENODEV; + restart_level = subsys->restart_level; + subsys->restart_level = RESET_SUBSYS_COUPLED; + if (subsystem_restart("modem") == -ENODEV) + pr_err("%s: SSR call failed\n", __func__); + subsys->restart_level = restart_level; + return 0; +} +EXPORT_SYMBOL(op_restart_modem); + static int subsys_start(struct subsys_device *subsys) { int ret; diff --git a/include/linux/op_rf_cable_monitor.h b/include/linux/op_rf_cable_monitor.h new file mode 100644 index 000000000000..9a43dded248c --- /dev/null +++ b/include/linux/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 From 98062f7f7a112a981b257e77b09658014054360f Mon Sep 17 00:00:00 2001 From: Luca Stefani Date: Sat, 28 Jul 2018 10:25:29 +0200 Subject: [PATCH 252/356] drivers: input: Import Synaptics driver Change-Id: I346ec465e6ec87398103dd523d80bc1e8b386761 --- drivers/input/touchscreen/Kconfig | 6 + drivers/input/touchscreen/Makefile | 3 + drivers/input/touchscreen/fw_update_v7.if | 1877 +++++ .../input/touchscreen/synaptics_baseline.h | 362 + .../touchscreen/synaptics_driver_s3320.c | 6466 +++++++++++++++++ .../input/touchscreen/synaptics_dsx_core.h | 552 ++ .../touchscreen/synaptics_dsx_fw_update.c | 4094 +++++++++++ .../input/touchscreen/synaptics_redremote.h | 15 + .../touchscreen/synaptics_s3320_redremote.c | 984 +++ 9 files changed, 14359 insertions(+) create mode 100644 drivers/input/touchscreen/fw_update_v7.if create mode 100755 drivers/input/touchscreen/synaptics_baseline.h create mode 100644 drivers/input/touchscreen/synaptics_driver_s3320.c create mode 100644 drivers/input/touchscreen/synaptics_dsx_core.h create mode 100644 drivers/input/touchscreen/synaptics_dsx_fw_update.c create mode 100644 drivers/input/touchscreen/synaptics_redremote.h create mode 100644 drivers/input/touchscreen/synaptics_s3320_redremote.c diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 3ee51c5d49a7..aca45775154a 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -1350,6 +1350,12 @@ config TOUCHSCREEN_SYNAPTICS_TCM To compile this driver as a module, choose M here: the module will be called synaptics_tcm. +config TOUCHSCREEN_SYNAPTICS_S3320_I2C_RMI + tristate "Synaptics s3320 i2c touchscreen" + depends on I2C + help + This enables support for Synaptics s1302 RMI over I2C based touch key. + source "drivers/input/touchscreen/synaptics_tcm/Kconfig" source "drivers/input/touchscreen/focaltech_touch/Kconfig" diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 8b766e754948..7af7aa4c6ab4 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -114,3 +114,6 @@ obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX) += synaptics_dsx/ obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_TCM) += synaptics_tcm/ obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_touch/ obj-$(CONFIG_TOUCHSCREEN_NT36XXX) += nt36xxx/ +obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_S3320_I2C_RMI) += synaptics_driver_s3320.o +obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_S3320_I2C_RMI) += synaptics_s3320_redremote.o +obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_S3320_I2C_RMI) += synaptics_dsx_fw_update.o diff --git a/drivers/input/touchscreen/fw_update_v7.if b/drivers/input/touchscreen/fw_update_v7.if new file mode 100644 index 000000000000..026855b17d90 --- /dev/null +++ b/drivers/input/touchscreen/fw_update_v7.if @@ -0,0 +1,1877 @@ +/* + * Synaptics DSX touchscreen driver + * + * Copyright (C) 2012 Synaptics Incorporated + * + * Copyright (C) 2012 Alexandra Chin + * Copyright (C) 2012 Scott Lin + * + * 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 + + +#define DO_STARTUP_FW_UPDATE + +#ifdef DO_STARTUP_FW_UPDATE +#ifdef CONFIG_FB +#define WAIT_FOR_FB_READY +#define FB_READY_WAIT_MS 100 +#define FB_READY_TIMEOUT_S 30 +#endif +#endif + +#define FORCE_UPDATE false +#define DO_LOCKDOWN false + +#define MAX_IMAGE_NAME_LEN 256 +#define MAX_FIRMWARE_ID_LEN 10 + +#define IMAGE_HEADER_VERSION_05 0x05 +#define IMAGE_HEADER_VERSION_06 0x06 +#define IMAGE_HEADER_VERSION_10 0x10 + +#define IMAGE_AREA_OFFSET 0x100 +#define LOCKDOWN_SIZE 0x50 + +#define V5V6_BOOTLOADER_ID_OFFSET 0 + +#define V5_PROPERTIES_OFFSET 2 +#define V5_BLOCK_SIZE_OFFSET 3 +#define V5_BLOCK_COUNT_OFFSET 5 +#define V5_BLOCK_NUMBER_OFFSET 0 +#define V5_BLOCK_DATA_OFFSET 2 + +#define V6_PROPERTIES_OFFSET 1 +#define V6_BLOCK_SIZE_OFFSET 2 +#define V6_BLOCK_COUNT_OFFSET 3 +#define V6_PROPERTIES_2_OFFSET 4 +#define V6_GUEST_CODE_BLOCK_COUNT_OFFSET 5 +#define V6_BLOCK_NUMBER_OFFSET 0 +#define V6_BLOCK_DATA_OFFSET 1 +#define V6_FLASH_COMMAND_OFFSET 2 +#define V6_FLASH_STATUS_OFFSET 3 + +#define V7_FLASH_STATUS_OFFSET 0 +#define V7_PARTITION_ID_OFFSET 1 +#define V7_BLOCK_NUMBER_OFFSET 2 +#define V7_TRANSFER_LENGTH_OFFSET 3 +#define V7_COMMAND_OFFSET 4 +#define V7_PAYLOAD_OFFSET 5 + +#define V7_PARTITION_SUPPORT_BYTES 4 + +#define F35_ERROR_CODE_OFFSET 0 +#define F35_CHUNK_NUM_LSB_OFFSET 0 +#define F35_CHUNK_NUM_MSB_OFFSET 1 +#define F35_CHUNK_DATA_OFFSET 2 +#define F35_CHUNK_COMMAND_OFFSET 18 + +#define F35_CHUNK_SIZE 16 +#define F35_ERASE_ALL_WAIT_MS 3000 +#define F35_RESET_WAIT_MS 250 + +#define SLEEP_MODE_NORMAL (0x00) +#define SLEEP_MODE_SENSOR_SLEEP (0x01) +#define SLEEP_MODE_RESERVED0 (0x02) +#define SLEEP_MODE_RESERVED1 (0x03) + +#define ENABLE_WAIT_MS (1 * 1000) +#define WRITE_WAIT_MS (3 * 1000) +#define ERASE_WAIT_MS (5 * 1000) + +#define MIN_SLEEP_TIME_US 50 +#define MAX_SLEEP_TIME_US 100 + +#define INT_DISABLE_WAIT_MS 20 +#define ENTER_FLASH_PROG_WAIT_MS 20 + +#define PRODUCT_ID_SIZE 10 + +#define MASK_16BIT 0xFFFF +#define MASK_8BIT 0xFF +#define MASK_7BIT 0x7F +#define MASK_6BIT 0x3F +#define MASK_5BIT 0x1F +#define MASK_4BIT 0x0F +#define MASK_3BIT 0x07 +#define MASK_2BIT 0x03 +#define MASK_1BIT 0x01 + +enum f34_version { + F34_V0 = 0, + F34_V1, + F34_V2, +}; + +enum bl_version { + BL_V5 = 5, + BL_V6 = 6, + BL_V7 = 7, +}; + +enum flash_area { + NONE = 0, + UI_FIRMWARE, + UI_CONFIG, +}; + +enum update_mode { + NORMAL = 1, + FORCE = 2, + LOCKDOWN = 8, +}; + +enum config_area { + UI_CONFIG_AREA = 0, + PM_CONFIG_AREA, + BL_CONFIG_AREA, + DP_CONFIG_AREA, + FLASH_CONFIG_AREA, +}; + +enum v7_partition_id { + BOOTLOADER_PARTITION = 0x01, + DEVICE_CONFIG_PARTITION, + FLASH_CONFIG_PARTITION, + MANUFACTURING_BLOCK_PARTITION, + GUEST_SERIALIZATION_PARTITION, + GLOBAL_PARAMETERS_PARTITION, + CORE_CODE_PARTITION, + CORE_CONFIG_PARTITION, + GUEST_CODE_PARTITION, + DISPLAY_CONFIG_PARTITION, +}; + +enum v7_flash_command { + CMD_V7_IDLE = 0x00, + CMD_V7_ENTER_BL, + CMD_V7_READ, + CMD_V7_WRITE, + CMD_V7_ERASE, + CMD_V7_ERASE_AP, + CMD_V7_SENSOR_ID, +}; + +enum v5v6_flash_command { + CMD_V5V6_IDLE = 0x0, + CMD_V5V6_WRITE_FW = 0x2, + CMD_V5V6_ERASE_ALL = 0x3, + CMD_V5V6_WRITE_LOCKDOWN = 0x4, + CMD_V5V6_READ_CONFIG = 0x5, + CMD_V5V6_WRITE_CONFIG = 0x6, + CMD_V5V6_ERASE_UI_CONFIG = 0x7, + CMD_V5V6_ERASE_BL_CONFIG = 0x9, + CMD_V5V6_ERASE_DISP_CONFIG = 0xa, + CMD_V5V6_ERASE_GUEST_CODE = 0xb, + CMD_V5V6_WRITE_GUEST_CODE = 0xc, + CMD_V5V6_ENABLE_FLASH_PROG = 0xf, +}; + +enum flash_command { + CMD_IDLE = 0, + CMD_WRITE_FW, + CMD_WRITE_CONFIG, + CMD_WRITE_LOCKDOWN, + CMD_WRITE_GUEST_CODE, + CMD_READ_CONFIG, + CMD_ERASE_ALL, + CMD_ERASE_UI_FIRMWARE, + CMD_ERASE_UI_CONFIG, + CMD_ERASE_BL_CONFIG, + CMD_ERASE_DISP_CONFIG, + CMD_ERASE_FLASH_CONFIG, + CMD_ERASE_GUEST_CODE, + CMD_ENABLE_FLASH_PROG, +}; + +enum f35_flash_command { + CMD_F35_IDLE = 0x0, + CMD_F35_RESERVED = 0x1, + CMD_F35_WRITE_CHUNK = 0x2, + CMD_F35_ERASE_ALL = 0x3, + CMD_F35_RESET = 0x10, +}; + +enum container_id { + TOP_LEVEL_CONTAINER = 0, + UI_CONTAINER, + UI_CONFIG_CONTAINER, + BL_CONTAINER, + BL_IMAGE_CONTAINER, + BL_CONFIG_CONTAINER, + BL_LOCKDOWN_INFO_CONTAINER, + PERMANENT_CONFIG_CONTAINER, + GUEST_CODE_CONTAINER, + BL_PROTOCOL_DESCRIPTOR_CONTAINER, + UI_PROTOCOL_DESCRIPTOR_CONTAINER, + RMI_SELF_DISCOVERY_CONTAINER, + RMI_PAGE_CONTENT_CONTAINER, + GENERAL_INFORMATION_CONTAINER, + DEVICE_CONFIG_CONTAINER, + FLASH_CONFIG_CONTAINER, + GUEST_SERIALIZATION_CONTAINER, + GLOBAL_PARAMETERS_CONTAINER, + CORE_CODE_CONTAINER, + CORE_CONFIG_CONTAINER, + DISPLAY_CONFIG_CONTAINER, +}; + +struct pdt_properties { + union { + struct { + unsigned char reserved_1:6; + unsigned char has_bsr:1; + unsigned char reserved_2:1; + } __packed; + unsigned char data[1]; + }; +}; + +struct partition_table { + unsigned char partition_id:5; + unsigned char byte_0_reserved:3; + unsigned char byte_1_reserved; + unsigned char partition_length_7_0; + unsigned char partition_length_15_8; + unsigned char start_physical_address_7_0; + unsigned char start_physical_address_15_8; + unsigned char partition_properties_7_0; + unsigned char partition_properties_15_8; +} __packed; + +struct f01_device_control { + union { + struct { + unsigned char sleep_mode:2; + unsigned char nosleep:1; + unsigned char reserved:2; + unsigned char charger_connected:1; + unsigned char report_rate:1; + unsigned char configured:1; + } __packed; + unsigned char data[1]; + }; +}; + +struct f34_v7_query_0 { + union { + struct { + unsigned char subpacket_1_size:3; + unsigned char has_config_id:1; + unsigned char f34_query0_b4:1; + unsigned char has_thqa:1; + unsigned char f34_query0_b6__7:2; + } __packed; + unsigned char data[1]; + }; +}; + +struct f34_v7_query_1_7 { + union { + struct { + /* query 1 */ + unsigned char bl_minor_revision; + unsigned char bl_major_revision; + + /* query 2 */ + unsigned char bl_fw_id_7_0; + unsigned char bl_fw_id_15_8; + unsigned char bl_fw_id_23_16; + unsigned char bl_fw_id_31_24; + + /* query 3 */ + unsigned char minimum_write_size; + unsigned char block_size_7_0; + unsigned char block_size_15_8; + unsigned char flash_page_size_7_0; + unsigned char flash_page_size_15_8; + + /* query 4 */ + unsigned char adjustable_partition_area_size_7_0; + unsigned char adjustable_partition_area_size_15_8; + + /* query 5 */ + unsigned char flash_config_length_7_0; + unsigned char flash_config_length_15_8; + + /* query 6 */ + unsigned char payload_length_7_0; + unsigned char payload_length_15_8; + + /* query 7 */ + unsigned char f34_query7_b0:1; + unsigned char has_bootloader:1; + unsigned char has_device_config:1; + unsigned char has_flash_config:1; + unsigned char has_manufacturing_block:1; + unsigned char has_guest_serialization:1; + unsigned char has_global_parameters:1; + unsigned char has_core_code:1; + unsigned char has_core_config:1; + unsigned char has_guest_code:1; + unsigned char has_display_config:1; + unsigned char f34_query7_b11__15:5; + unsigned char f34_query7_b16__23; + unsigned char f34_query7_b24__31; + } __packed; + unsigned char data[21]; + }; +}; + +struct f34_v7_data_1_5 { + union { + struct { + unsigned char partition_id:5; + unsigned char f34_data1_b5__7:3; + unsigned char block_offset_7_0; + unsigned char block_offset_15_8; + unsigned char transfer_length_7_0; + unsigned char transfer_length_15_8; + unsigned char command; + unsigned char payload_0; + unsigned char payload_1; + } __packed; + unsigned char data[8]; + }; +}; + +struct f34_v5v6_flash_properties { + union { + struct { + unsigned char reg_map:1; + unsigned char unlocked:1; + unsigned char has_config_id:1; + unsigned char has_pm_config:1; + unsigned char has_bl_config:1; + unsigned char has_disp_config:1; + unsigned char has_ctrl1:1; + unsigned char has_query4:1; + } __packed; + unsigned char data[1]; + }; +}; + +struct register_offset { + unsigned char properties; + unsigned char properties_2; + unsigned char block_size; + unsigned char block_count; + unsigned char gc_block_count; + unsigned char flash_status; + unsigned char partition_id; + unsigned char block_number; + unsigned char transfer_length; + unsigned char flash_cmd; + unsigned char payload; +}; + +struct block_count { + unsigned short ui_firmware; + unsigned short ui_config; + unsigned short dp_config; + unsigned short fl_config; + unsigned short pm_config; + unsigned short bl_config; + unsigned short lockdown; + unsigned short guest_code; +}; + +struct physical_address { + unsigned short ui_firmware; + unsigned short ui_config; + unsigned short dp_config; + unsigned short guest_code; + unsigned short pm_config; +}; + +struct container_descriptor { + unsigned char content_checksum[4]; + unsigned char container_id[2]; + unsigned char minor_version; + unsigned char major_version; + unsigned char reserved_08; + unsigned char reserved_09; + unsigned char reserved_0a; + unsigned char reserved_0b; + unsigned char container_option_flags[4]; + unsigned char content_options_length[4]; + unsigned char content_options_address[4]; + unsigned char content_length[4]; + unsigned char content_address[4]; +}; + +struct image_header_10 { + unsigned char checksum[4]; + unsigned char reserved_04; + unsigned char reserved_05; + unsigned char minor_header_version; + unsigned char major_header_version; + unsigned char reserved_08; + unsigned char reserved_09; + unsigned char reserved_0a; + unsigned char reserved_0b; + unsigned char top_level_container_start_addr[4]; +}; + +struct block_data { + unsigned int size; + const unsigned char *data; +}; + +struct image_metadata { + bool contains_firmware_id; + bool contains_bootloader; + bool contains_disp_config; + bool contains_guest_code; + bool contains_flash_config; + unsigned int firmware_id; + unsigned int checksum; + unsigned int bootloader_size; + unsigned int disp_config_offset; + unsigned char bl_version; + unsigned char product_id[PRODUCT_ID_SIZE + 1]; + unsigned char cstmr_product_id[PRODUCT_ID_SIZE + 1]; + struct block_data bootloader; + struct block_data ui_firmware; + struct block_data ui_config; + struct block_data dp_config; + struct block_data fl_config; + struct block_data bl_config; + struct block_data guest_code; + struct block_data lockdown; + struct block_count blkcount; + struct physical_address phyaddr; +}; +struct synaptics_rmi4_fn_desc { + union { + struct { + unsigned char query_base_addr; + unsigned char cmd_base_addr; + unsigned char ctrl_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; + unsigned char data[6]; + }; +}; + + +struct synaptics_rmi4_fwu_handle { + enum bl_version bl_version; + bool initialized; + bool in_bl_mode; + bool in_ub_mode; + bool force_update; + bool do_lockdown; + bool has_guest_code; + bool new_partition_table; + unsigned int data_pos; + unsigned char *ext_data_source; + unsigned char *read_config_buf; + unsigned char intr_mask; + unsigned char command; + unsigned char bootloader_id[2]; + unsigned char flash_status; + unsigned char partitions; + unsigned short block_size; + unsigned short config_size; + unsigned short config_area; + unsigned short config_block_count; + unsigned short flash_config_length; + unsigned short payload_length; + unsigned short partition_table_bytes; + unsigned short read_config_buf_size; + const unsigned char *config_data; + const unsigned char *image; + unsigned char *image_name; + unsigned int image_size; + unsigned char bl_reset_add; + struct image_metadata img; + struct register_offset off; + struct block_count blkcount; + struct physical_address phyaddr; + struct f34_v5v6_flash_properties flash_properties; + struct synaptics_rmi4_fn_desc f34_fd; + struct synaptics_rmi4_fn_desc f35_fd; + struct workqueue_struct *fwu_workqueue; + struct work_struct fwu_work; + struct i2c_client *client; +}; + +static struct synaptics_rmi4_fwu_handle *fwu; + +static unsigned int le_to_uint(const unsigned char *ptr) +{ + return (unsigned int)ptr[0] + + (unsigned int)ptr[1] * 0x100 + + (unsigned int)ptr[2] * 0x10000 + + (unsigned int)ptr[3] * 0x1000000; +} +/* +static void fwu_compare_partition_tables(void) +{ + if (fwu->phyaddr.ui_firmware != fwu->img.phyaddr.ui_firmware) { + fwu->new_partition_table = true; + return; + } + + if (fwu->phyaddr.ui_config != fwu->img.phyaddr.ui_config) { + fwu->new_partition_table = true; + return; + } + + if (fwu->flash_properties.has_disp_config) { + if (fwu->phyaddr.dp_config != fwu->img.phyaddr.dp_config) { + fwu->new_partition_table = true; + return; + } + } + + if (fwu->flash_properties.has_disp_config) { + if (fwu->phyaddr.dp_config != fwu->img.phyaddr.dp_config) { + fwu->new_partition_table = true; + return; + } + } + + if (fwu->has_guest_code) { + if (fwu->phyaddr.guest_code != fwu->img.phyaddr.guest_code) { + fwu->new_partition_table = true; + return; + } + } + + fwu->new_partition_table = false; + + return; +} +*/ + +static void fwu_parse_partition_table(const unsigned char *partition_table, + struct block_count *blkcount, struct physical_address *phyaddr) +{ + unsigned char ii; + unsigned char index; + //unsigned char offset; + unsigned short partition_length; + unsigned short physical_address; + struct partition_table *ptable; + + for (ii = 0; ii < fwu->partitions; ii++) { + index = ii * 8 + 2; + ptable = (struct partition_table *)&partition_table[index]; + partition_length = ptable->partition_length_15_8 << 8 | + ptable->partition_length_7_0; + physical_address = ptable->start_physical_address_15_8 << 8 | + ptable->start_physical_address_7_0; + TPD_DEBUG("%s: Partition entry %d:\n", + __func__, ii); +/* + for (offset = 0; offset < 8; offset++) { + TPD_DEBUG("%s: 0x%02x\n", + __func__, + partition_table[index + offset]); + } +*/ + switch (ptable->partition_id) { + case CORE_CODE_PARTITION: + blkcount->ui_firmware = partition_length; + phyaddr->ui_firmware = physical_address; + TPD_DEBUG("%s: Core code block count: %d\n", + __func__, blkcount->ui_firmware); + break; + case CORE_CONFIG_PARTITION: + blkcount->ui_config = partition_length; + phyaddr->ui_config = physical_address; + TPD_DEBUG("%s: Core config block count: %d\n", + __func__, blkcount->ui_config); + break; + case DISPLAY_CONFIG_PARTITION: + blkcount->dp_config = partition_length; + phyaddr->dp_config = physical_address; + TPD_DEBUG("%s: Display config block count: %d\n", + __func__, blkcount->dp_config); + break; + case FLASH_CONFIG_PARTITION: + blkcount->fl_config = partition_length; + TPD_DEBUG("%s: Flash config block count: %d\n", + __func__, blkcount->fl_config); + break; + case GUEST_CODE_PARTITION: + blkcount->guest_code = partition_length; + phyaddr->guest_code = physical_address; + TPD_DEBUG("%s: Guest code block count: %d\n", + __func__, blkcount->guest_code); + break; + case GUEST_SERIALIZATION_PARTITION: + blkcount->pm_config = partition_length; + TPD_DEBUG("%s: Guest serialization block count: %d\n", + __func__, blkcount->pm_config); + break; + case GLOBAL_PARAMETERS_PARTITION: + blkcount->bl_config = partition_length; + TPD_DEBUG("%s: Global parameters block count: %d\n", + __func__, blkcount->bl_config); + break; + case DEVICE_CONFIG_PARTITION: + blkcount->lockdown = partition_length; + TPD_DEBUG("%s: Device config block count: %d\n", + __func__, blkcount->lockdown); + break; + }; + } + + return; +} + + +static void fwu_parse_image_header_10_bl_container(const unsigned char *image) +{ + unsigned char ii; + unsigned char num_of_containers; + unsigned int addr; + unsigned int container_id; + unsigned int length; + const unsigned char *content; + struct container_descriptor *descriptor; + + num_of_containers = (fwu->img.bootloader.size - 4) / 4; + + for (ii = 1; ii <= num_of_containers; ii++) { + addr = le_to_uint(fwu->img.bootloader.data + (ii * 4)); + descriptor = (struct container_descriptor *)(image + addr); + container_id = descriptor->container_id[0] | + descriptor->container_id[1] << 8; + content = image + le_to_uint(descriptor->content_address); + length = le_to_uint(descriptor->content_length); + switch (container_id) { + case BL_CONFIG_CONTAINER: + case GLOBAL_PARAMETERS_CONTAINER: + fwu->img.bl_config.data = content; + fwu->img.bl_config.size = length; + break; + case BL_LOCKDOWN_INFO_CONTAINER: + case DEVICE_CONFIG_CONTAINER: + fwu->img.lockdown.data = content; + fwu->img.lockdown.size = length; + break; + default: + break; + }; + } + + return; +} + +static void fwu_parse_image_header_10(void) +{ + unsigned char ii; + unsigned char num_of_containers; + unsigned int addr; + unsigned int offset; + unsigned int container_id; + unsigned int length; + const unsigned char *image; + const unsigned char *content; + struct container_descriptor *descriptor; + struct image_header_10 *header; + + image = fwu->image; + header = (struct image_header_10 *)image; + + fwu->img.checksum = le_to_uint(header->checksum); + + /* address of top level container */ + offset = le_to_uint(header->top_level_container_start_addr); + descriptor = (struct container_descriptor *)(image + offset); + + /* address of top level container content */ + offset = le_to_uint(descriptor->content_address); + num_of_containers = le_to_uint(descriptor->content_length) / 4; + + for (ii = 0; ii < num_of_containers; ii++) { + addr = le_to_uint(image + offset); + offset += 4; + descriptor = (struct container_descriptor *)(image + addr); + container_id = descriptor->container_id[0] | + descriptor->container_id[1] << 8; + content = image + le_to_uint(descriptor->content_address); + length = le_to_uint(descriptor->content_length); + switch (container_id) { + case UI_CONTAINER: + case CORE_CODE_CONTAINER: + fwu->img.ui_firmware.data = content; + fwu->img.ui_firmware.size = length; + TPD_DEBUG("%s ui_firmware_pointer[%p]\n",__func__,fwu->img.ui_firmware.data); + break; + case UI_CONFIG_CONTAINER: + case CORE_CONFIG_CONTAINER: + fwu->img.ui_config.data = content; + fwu->img.ui_config.size = length; + break; + case BL_CONTAINER: + fwu->img.bl_version = *content; + fwu->img.bootloader.data = content; + fwu->img.bootloader.size = length; + fwu_parse_image_header_10_bl_container(image); + break; + case GUEST_CODE_CONTAINER: + fwu->img.contains_guest_code = true; + fwu->img.guest_code.data = content; + fwu->img.guest_code.size = length; + break; + case DISPLAY_CONFIG_CONTAINER: + fwu->img.contains_disp_config = true; + fwu->img.dp_config.data = content; + fwu->img.dp_config.size = length; + break; + case FLASH_CONFIG_CONTAINER: + fwu->img.contains_flash_config = true; + fwu->img.fl_config.data = content; + fwu->img.fl_config.size = length; + break; + case GENERAL_INFORMATION_CONTAINER: + fwu->img.contains_firmware_id = true; + fwu->img.firmware_id = le_to_uint(content + 4); + break; + default: + break; + } + } + + return; +} + +static int fwu_parse_image_info(unsigned char *fw) +{ + struct image_header_10 *header; + + header = (struct image_header_10 *)fw; + + memset(&fwu->img, 0x00, sizeof(fwu->img)); + + fwu_parse_image_header_10(); + + if (!fwu->img.contains_flash_config) { + return -EINVAL; + } + + //fwu_parse_partition_table(fwu->img.fl_config.data, + //&fwu->img.blkcount, &fwu->img.phyaddr); + + //fwu_compare_partition_tables(); + + return 0; +} + +static int fwu_read_flash_status(void) +{ + int retval; + unsigned char status; + unsigned char command; + + retval = synaptics_rmi4_i2c_read_block(fwu->client, + fwu->f34_fd.data_base_addr + fwu->off.flash_status,sizeof(status),&status); + if (retval < 0) { + return retval; + } + //TPD_ERR("flash_status_address[0x%x] status[0x%x]\n",fwu->f34_fd.data_base_addr + fwu->off.flash_status,status); + fwu->in_bl_mode = status >> 7; + + if (fwu->bl_version == BL_V5) + fwu->flash_status = (status >> 4) & MASK_3BIT; + else if (fwu->bl_version == BL_V6) + fwu->flash_status = status & MASK_3BIT; + else if (fwu->bl_version == BL_V7) + fwu->flash_status = status & MASK_5BIT; + + if (fwu->flash_status != 0x00) { + TPD_ERR("%s: Flash status = %d, command = 0x%02x\n", + __func__, fwu->flash_status, fwu->command); + } + + retval = synaptics_rmi4_i2c_read_block(fwu->client, + fwu->f34_fd.data_base_addr + fwu->off.flash_cmd, + sizeof(command),&command); + if (retval < 0) { + TPD_ERR("%s: Failed to read flash command[%d]\n", + __func__,command); + return retval; + } + //TPD_ERR("flash_command_address[0x%x] command[0x%x]\n",fwu->f34_fd.data_base_addr + fwu->off.flash_cmd,command); + + if (fwu->bl_version == BL_V5) + fwu->command = command & MASK_4BIT; + else if (fwu->bl_version == BL_V6) + fwu->command = command & MASK_6BIT; + else if (fwu->bl_version == BL_V7) + fwu->command = command; + + return 0; +} + +static int fwu_wait_for_idle(int timeout_ms, bool poll) +{ + int count = 0; + int timeout_count = ((timeout_ms * 1000) / MAX_SLEEP_TIME_US) + 1; + + do { + usleep_range(MIN_SLEEP_TIME_US, MAX_SLEEP_TIME_US); + + count++; + if (poll || (count == timeout_count)) + fwu_read_flash_status(); + + if ((fwu->command == CMD_IDLE) && (fwu->flash_status == 0x00)) + return 0; + } while (count < timeout_count); + + TPD_ERR("%s: Timed out waiting for idle status command[%d],flash_status[%d]\n", + __func__,fwu->command,fwu->flash_status); + + return -ETIMEDOUT; +} +static int fwu_write_f34_v7_command_single_transaction(unsigned char cmd) +{ + int retval; + unsigned char base; + struct f34_v7_data_1_5 data_1_5; + + base = fwu->f34_fd.data_base_addr; + + memset(data_1_5.data, 0x00, sizeof(data_1_5.data)); + retval = synaptics_rmi4_i2c_read_block(fwu->client, + base + fwu->off.partition_id, + sizeof(data_1_5.data),data_1_5.data); + if (retval < 0) { + TPD_ERR("%s: Failed to read queries 1 to 7\n", + __func__); + return retval; + } + + switch (cmd) { + case CMD_ERASE_ALL: + data_1_5.partition_id = CORE_CODE_PARTITION; + data_1_5.command = CMD_V7_ERASE_AP; + break; + case CMD_ERASE_UI_FIRMWARE: + data_1_5.partition_id = CORE_CODE_PARTITION; + data_1_5.command = CMD_V7_ERASE; + break; + case CMD_ERASE_BL_CONFIG: + data_1_5.partition_id = GLOBAL_PARAMETERS_PARTITION; + data_1_5.command = CMD_V7_ERASE; + break; + case CMD_ERASE_UI_CONFIG: + data_1_5.partition_id = CORE_CONFIG_PARTITION; + data_1_5.command = CMD_V7_ERASE; + break; + case CMD_ERASE_DISP_CONFIG: + data_1_5.partition_id = DISPLAY_CONFIG_PARTITION; + data_1_5.command = CMD_V7_ERASE; + break; + case CMD_ERASE_FLASH_CONFIG: + data_1_5.partition_id = FLASH_CONFIG_PARTITION; + data_1_5.command = CMD_V7_ERASE; + break; + case CMD_ERASE_GUEST_CODE: + data_1_5.partition_id = GUEST_CODE_PARTITION; + data_1_5.command = CMD_V7_ERASE; + break; + case CMD_ENABLE_FLASH_PROG: + data_1_5.partition_id = BOOTLOADER_PARTITION; + data_1_5.command = CMD_V7_ENTER_BL; + break; + }; + + data_1_5.payload_0 = fwu->bootloader_id[0]; + data_1_5.payload_1 = fwu->bootloader_id[1]; + + retval = synaptics_rmi4_i2c_write_block(fwu->client, + base + fwu->off.partition_id, + sizeof(data_1_5.data),data_1_5.data); + if (retval < 0) { + TPD_ERR("%s: Failed to write single transaction command\n", + __func__); + return retval; + } + + return 0; +} + +static int fwu_write_f34_v7_command(unsigned char cmd) +{ + int retval; + unsigned char base; + unsigned char command; + + base = fwu->f34_fd.data_base_addr; + + switch (cmd) { + case CMD_WRITE_FW: + case CMD_WRITE_CONFIG: + case CMD_WRITE_GUEST_CODE: + command = CMD_V7_WRITE; + break; + case CMD_READ_CONFIG: + command = CMD_V7_READ; + break; + case CMD_ERASE_ALL: + command = CMD_V7_ERASE_AP; + break; + case CMD_ERASE_UI_FIRMWARE: + case CMD_ERASE_BL_CONFIG: + case CMD_ERASE_UI_CONFIG: + case CMD_ERASE_DISP_CONFIG: + case CMD_ERASE_FLASH_CONFIG: + case CMD_ERASE_GUEST_CODE: + command = CMD_V7_ERASE; + break; + case CMD_ENABLE_FLASH_PROG: + command = CMD_V7_ENTER_BL; + break; + default: + TPD_ERR("%s: Invalid command 0x%02x\n", + __func__, cmd); + return -EINVAL; + }; + + fwu->command = command; + + switch (cmd) { + case CMD_ERASE_ALL: + case CMD_ERASE_UI_FIRMWARE: + case CMD_ERASE_BL_CONFIG: + case CMD_ERASE_UI_CONFIG: + case CMD_ERASE_DISP_CONFIG: + case CMD_ERASE_FLASH_CONFIG: + case CMD_ERASE_GUEST_CODE: + case CMD_ENABLE_FLASH_PROG: + retval = fwu_write_f34_v7_command_single_transaction(cmd); + if (retval < 0) + return retval; + else + return 0; + default: + break; + }; + + retval = synaptics_rmi4_i2c_write_block(fwu->client, + base + fwu->off.flash_cmd, + sizeof(command),&command); + if (retval < 0) { + TPD_ERR("%s: Failed to write flash command\n", + __func__); + return retval; + } + + return 0; +} + +static int fwu_write_f34_command(unsigned char cmd) +{ + int retval; + + retval = fwu_write_f34_v7_command(cmd); + + return retval; +} + +static int fwu_write_f34_v7_partition_id(unsigned char cmd) +{ + int retval; + unsigned char base; + unsigned char partition = 0; + + base = fwu->f34_fd.data_base_addr; + + switch (cmd) { + case CMD_WRITE_FW: + partition = CORE_CODE_PARTITION; + break; + case CMD_WRITE_CONFIG: + case CMD_READ_CONFIG: + if (fwu->config_area == UI_CONFIG_AREA) + partition = CORE_CONFIG_PARTITION; + else if (fwu->config_area == DP_CONFIG_AREA) + partition = DISPLAY_CONFIG_PARTITION; + else if (fwu->config_area == PM_CONFIG_AREA) + partition = GUEST_SERIALIZATION_PARTITION; + else if (fwu->config_area == BL_CONFIG_AREA) + partition = GLOBAL_PARAMETERS_PARTITION; + else if (fwu->config_area == FLASH_CONFIG_AREA) + partition = FLASH_CONFIG_PARTITION; + break; + case CMD_WRITE_GUEST_CODE: + partition = GUEST_CODE_PARTITION; + break; + case CMD_ERASE_ALL: + partition = CORE_CODE_PARTITION; + break; + case CMD_ERASE_BL_CONFIG: + partition = GLOBAL_PARAMETERS_PARTITION; + break; + case CMD_ERASE_UI_CONFIG: + partition = CORE_CONFIG_PARTITION; + break; + case CMD_ERASE_DISP_CONFIG: + partition = DISPLAY_CONFIG_PARTITION; + break; + case CMD_ERASE_FLASH_CONFIG: + partition = FLASH_CONFIG_PARTITION; + break; + case CMD_ERASE_GUEST_CODE: + partition = GUEST_CODE_PARTITION; + break; + case CMD_ENABLE_FLASH_PROG: + partition = BOOTLOADER_PARTITION; + break; + default: + TPD_ERR("%s: Invalid command 0x%02x\n", + __func__, cmd); + return -EINVAL; + }; + + retval = synaptics_rmi4_i2c_write_block(fwu->client, + base + fwu->off.partition_id, + sizeof(partition),&partition); + if (retval < 0) { + TPD_ERR("%s: Failed to write partition ID\n", + __func__); + return retval; + } + + return 0; +} + +static int fwu_write_f34_partition_id(unsigned char cmd) +{ + int retval; + + retval = fwu_write_f34_v7_partition_id(cmd); + + return retval; +} + +static int fwu_read_f34_v7_partition_table(void) +{ + int retval; + unsigned char base; + unsigned char length[2]; + unsigned short block_number = 0; + + base = fwu->f34_fd.data_base_addr; + + fwu->config_area = FLASH_CONFIG_AREA; + + retval = fwu_write_f34_partition_id(CMD_READ_CONFIG); + if (retval < 0) + return retval; + + retval = synaptics_rmi4_i2c_write_block(fwu->client, + base + fwu->off.block_number, + sizeof(block_number),(unsigned char *)&block_number); + if (retval < 0) { + TPD_ERR("%s: Failed to write block number\n", + __func__); + return retval; + } + + length[0] = (unsigned char)(fwu->flash_config_length & MASK_8BIT); + length[1] = (unsigned char)(fwu->flash_config_length >> 8); + + retval = synaptics_rmi4_i2c_write_block(fwu->client, + base + fwu->off.transfer_length, + sizeof(length), length); + if (retval < 0) { + TPD_ERR("%s: Failed to write transfer length\n", + __func__); + return retval; + } + + retval = fwu_write_f34_command(CMD_READ_CONFIG); + if (retval < 0) { + TPD_ERR("%s: Failed to write command\n", + __func__); + return retval; + } + + retval = fwu_wait_for_idle(WRITE_WAIT_MS, true); + if (retval < 0) { + TPD_ERR("%s: Failed to wait for idle status\n", + __func__); + return retval; + } + + retval = synaptics_rmi4_i2c_read_block(fwu->client, + base + fwu->off.payload,fwu->partition_table_bytes,fwu->read_config_buf); + if (retval < 0) { + TPD_ERR("%s: Failed to read block data\n", + __func__); + return retval; + } + + return 0; +} + +static int fwu_read_f34_v7_queries(void) +{ + int retval; + unsigned char ii; + unsigned char base; + unsigned char index; + unsigned char offset; + unsigned char *ptable; + struct f34_v7_query_0 query_0; + struct f34_v7_query_1_7 query_1_7; + + base = fwu->f34_fd.query_base_addr; + + retval = synaptics_rmi4_i2c_read_block(fwu->client, + base, + sizeof(query_0.data),query_0.data); + if (retval < 0) { + TPD_ERR("%s: Failed to read query 0\n", + __func__); + return retval; + } + + offset = query_0.subpacket_1_size + 1; + + retval = synaptics_rmi4_i2c_read_block(fwu->client, + base + offset, + sizeof(query_1_7.data),query_1_7.data); + if (retval < 0) { + TPD_ERR("%s: Failed to read queries 1 to 7\n", + __func__); + return retval; + } + + fwu->bootloader_id[0] = query_1_7.bl_minor_revision; + fwu->bootloader_id[1] = query_1_7.bl_major_revision; + + fwu->block_size = query_1_7.block_size_15_8 << 8 | + query_1_7.block_size_7_0; + + fwu->flash_config_length = query_1_7.flash_config_length_15_8 << 8 | + query_1_7.flash_config_length_7_0; + + fwu->payload_length = query_1_7.payload_length_15_8 << 8 | + query_1_7.payload_length_7_0; + + fwu->off.flash_status = V7_FLASH_STATUS_OFFSET; + fwu->off.partition_id = V7_PARTITION_ID_OFFSET; + fwu->off.block_number = V7_BLOCK_NUMBER_OFFSET; + fwu->off.transfer_length = V7_TRANSFER_LENGTH_OFFSET; + fwu->off.flash_cmd = V7_COMMAND_OFFSET; + fwu->off.payload = V7_PAYLOAD_OFFSET; + + fwu->flash_properties.has_disp_config = query_1_7.has_display_config; + fwu->flash_properties.has_pm_config = query_1_7.has_guest_serialization; + fwu->flash_properties.has_bl_config = query_1_7.has_global_parameters; + + fwu->has_guest_code = query_1_7.has_guest_code; + + index = sizeof(query_1_7.data) - V7_PARTITION_SUPPORT_BYTES; + + fwu->partitions = 0; + for (offset = 0; offset < V7_PARTITION_SUPPORT_BYTES; offset++) { + for (ii = 0; ii < 8; ii++) { + if (query_1_7.data[index + offset] & (1 << ii)) + fwu->partitions++; + } + } + + fwu->partition_table_bytes = fwu->partitions * 8 + 2; + + kfree(fwu->read_config_buf); + fwu->read_config_buf = kzalloc(fwu->partition_table_bytes, GFP_KERNEL); + if (!fwu->read_config_buf) { + TPD_ERR("%s: Failed to alloc mem for fwu->read_config_buf\n", + __func__); + fwu->read_config_buf_size = 0; + return -ENOMEM; + } + fwu->read_config_buf_size = fwu->partition_table_bytes; + ptable = fwu->read_config_buf; + + retval = fwu_read_f34_v7_partition_table(); + if (retval < 0) { + TPD_ERR("%s: Failed to read partition table\n", + __func__); + return retval; + } + + fwu_parse_partition_table(ptable, &fwu->blkcount, &fwu->phyaddr); + + return 0; +} + +static int fwu_read_f34_queries(void) +{ + int retval; + + memset(&fwu->blkcount, 0x00, sizeof(fwu->blkcount)); + memset(&fwu->phyaddr, 0x00, sizeof(fwu->phyaddr)); + retval = fwu_read_f34_v7_queries(); + + return retval; +} +static int fwu_write_f34_v7_blocks(unsigned char *block_ptr, + unsigned short block_cnt, unsigned char command) +{ + int retval; + unsigned char base; + unsigned char length[2]; + unsigned short transfer; + unsigned short max_transfer; + unsigned short remaining = block_cnt; + unsigned short block_number = 0; + int send_cnt = 1; + + base = fwu->f34_fd.data_base_addr; + + retval = fwu_wait_for_idle(WRITE_WAIT_MS, true); + if (retval < 0) { + TPD_ERR("%s: line[%d]Failed to wait for idle status\n",__func__, __LINE__); + } + + retval = fwu_write_f34_partition_id(command); + if (retval < 0) + return retval; + + retval = synaptics_rmi4_i2c_write_block(fwu->client, + base + fwu->off.block_number, + sizeof(block_number),(unsigned char *)&block_number); + if (retval < 0) { + TPD_ERR("%s: Failed to write block number\n",__func__); + return retval; + } + + if (fwu->payload_length > (PAGE_SIZE / fwu->block_size)) + max_transfer = PAGE_SIZE / fwu->block_size; + else + max_transfer = fwu->payload_length; + + do { + if (remaining / max_transfer) + transfer = max_transfer; + else + transfer = remaining; + + TPD_DEBUG("send_cnt[%d],transfer_block[%d],remaining[%d]\n",send_cnt++,transfer,remaining); + length[0] = (unsigned char)(transfer & MASK_8BIT); + length[1] = (unsigned char)(transfer >> 8); + + retval = synaptics_rmi4_i2c_write_block(fwu->client, + base + fwu->off.transfer_length, + sizeof(length),length); + if (retval < 0) { + TPD_ERR("%s: Failed to write transfer length (%d blocks remaining)\n", + __func__, remaining); + return retval; + } + + retval = fwu_write_f34_command(command); + if (retval < 0) { + TPD_ERR("%s: Failed to write command (%d blocks remaining)\n", + __func__, remaining); + return retval; + } + + retval = synaptics_rmi4_i2c_write_block(fwu->client, + base + fwu->off.payload, + transfer * fwu->block_size,block_ptr); + if (retval < 0) { + TPD_ERR("%s: Failed to write block data (%d blocks remaining)\n", + __func__, remaining); + return retval; + } + + retval = fwu_wait_for_idle(WRITE_WAIT_MS, true); + if (retval < 0) { + TPD_ERR("%s: Failed to wait for idle status (%d blocks remaining)\n", + __func__, remaining); + return retval; + } + + block_ptr += (transfer * fwu->block_size); + remaining -= transfer; + } while (remaining); + + return 0; +} + +static int fwu_write_f34_blocks(unsigned char *block_ptr, + unsigned short block_cnt, unsigned char cmd) +{ + int retval; + retval = fwu_write_f34_v7_blocks(block_ptr, block_cnt, cmd); + return retval; +} + +static int fwu_read_f34_v7_blocks(unsigned short block_cnt, + unsigned char command) +{ + int retval; + unsigned char base; + unsigned char length[2]; + unsigned short transfer; + unsigned short max_transfer; + unsigned short remaining = block_cnt; + unsigned short block_number = 0; + unsigned short index = 0; + + base = fwu->f34_fd.data_base_addr; + + retval = fwu_write_f34_partition_id(command); + if (retval < 0) + return retval; + + retval = synaptics_rmi4_i2c_write_block(fwu->client, + base + fwu->off.block_number, + sizeof(block_number),(unsigned char *)&block_number); + if (retval < 0) { + TPD_ERR("%s: Failed to write block number\n", + __func__); + return retval; + } + + if (fwu->payload_length > (PAGE_SIZE / fwu->block_size)) + max_transfer = PAGE_SIZE / fwu->block_size; + else + max_transfer = fwu->payload_length; + + do { + if (remaining / max_transfer) + transfer = max_transfer; + else + transfer = remaining; + + length[0] = (unsigned char)(transfer & MASK_8BIT); + length[1] = (unsigned char)(transfer >> 8); + + retval = synaptics_rmi4_i2c_write_block(fwu->client, + base + fwu->off.transfer_length,sizeof(length),length); + if (retval < 0) { + TPD_ERR("%s: Failed to write transfer length (%d blocks remaining)\n", + __func__, remaining); + return retval; + } + + retval = fwu_write_f34_command(command); + if (retval < 0) { + TPD_ERR("%s: Failed to write command (%d blocks remaining)\n", + __func__, remaining); + return retval; + } + + retval = fwu_wait_for_idle(WRITE_WAIT_MS, false); + if (retval < 0) { + TPD_ERR("%s: Failed to wait for idle status (%d blocks remaining)\n", + __func__, remaining); + return retval; + } + + retval = synaptics_rmi4_i2c_read_block(fwu->client, + base + fwu->off.payload, + transfer * fwu->block_size,&fwu->read_config_buf[index]); + if (retval < 0) { + TPD_ERR("%s: Failed to read block data (%d blocks remaining)\n", + __func__, remaining); + return retval; + } + + index += (transfer * fwu->block_size); + remaining -= transfer; + } while (remaining); + + return 0; +} + +static int fwu_read_f34_blocks(unsigned short block_cnt, unsigned char cmd) +{ + int retval; + + retval = fwu_read_f34_v7_blocks(block_cnt, cmd); + + return retval; +} + +static int fwu_check_ui_firmware_size(void) +{ + unsigned short block_count; + + block_count = fwu->img.ui_firmware.size / fwu->block_size; + + if (block_count != fwu->blkcount.ui_firmware) { + TPD_ERR("%s: UI firmware size mismatch\n",__func__); + return -EINVAL; + } + + return 0; +} + +static int fwu_check_ui_configuration_size(void) +{ + unsigned short block_count; + + block_count = fwu->img.ui_config.size / fwu->block_size; + + if (block_count != fwu->blkcount.ui_config) { + TPD_ERR("%s: UI configuration size mismatch\n",__func__); + return -EINVAL; + } + + return 0; +} + +static int fwu_check_bl_configuration_size(void) +{ + unsigned short block_count; + + block_count = fwu->img.bl_config.size / fwu->block_size; + + if (block_count != fwu->blkcount.bl_config) { + TPD_ERR("%s: Bootloader configuration size mismatch\n",__func__); + return -EINVAL; + } + + return 0; +} + +static int fwu_write_firmware(void) +{ + unsigned short firmware_block_count; + + firmware_block_count = fwu->img.ui_firmware.size / fwu->block_size; + + return fwu_write_f34_blocks((unsigned char *)fwu->img.ui_firmware.data, + firmware_block_count, CMD_WRITE_FW); +} + +static int fwu_erase_configuration(void) +{ + int retval; + + switch (fwu->config_area) { + case UI_CONFIG_AREA: + retval = fwu_write_f34_command(CMD_ERASE_UI_CONFIG); + if (retval < 0) + return retval; + break; + case DP_CONFIG_AREA: + retval = fwu_write_f34_command(CMD_ERASE_DISP_CONFIG); + if (retval < 0) + return retval; + break; + case BL_CONFIG_AREA: + retval = fwu_write_f34_command(CMD_ERASE_BL_CONFIG); + if (retval < 0) + return retval; + break; + } + + + retval = fwu_wait_for_idle(ERASE_WAIT_MS, false); + if (retval < 0) + return retval; + + + return retval; +} + +static int fwu_erase_all(void) +{ + int retval; + + if (fwu->bl_version == BL_V7) { + retval = fwu_write_f34_command(CMD_ERASE_UI_FIRMWARE); + if (retval < 0) + return retval; + + TPD_ERR("%s: Erase command written\n",__func__); + + retval = fwu_wait_for_idle(ERASE_WAIT_MS, false); + if (retval < 0) + return retval; + + TPD_ERR("%s: Idle status detected\n",__func__); + + fwu->config_area = UI_CONFIG_AREA; + retval = fwu_erase_configuration(); + if (retval < 0) + return retval; + } else { + retval = fwu_write_f34_command(CMD_ERASE_ALL); + if (retval < 0) + return retval; + + TPD_ERR("%s: Erase all command written\n",__func__); + + retval = fwu_wait_for_idle(ERASE_WAIT_MS, false); + if (retval < 0) + return retval; + + TPD_ERR("%s: Idle status detected\n",__func__); + } + + if (fwu->flash_properties.has_disp_config) { + fwu->config_area = DP_CONFIG_AREA; + retval = fwu_erase_configuration(); + if (retval < 0) + return retval; + } + + return 0; +} + +static int fwu_write_configuration(void) +{ + return fwu_write_f34_blocks((unsigned char *)fwu->config_data, + fwu->config_block_count, CMD_WRITE_CONFIG); +} + +static int fwu_write_ui_configuration(void) +{ + fwu->config_area = UI_CONFIG_AREA; + fwu->config_data = fwu->img.ui_config.data; + fwu->config_size = fwu->img.ui_config.size; + fwu->config_block_count = fwu->config_size / fwu->block_size; + + return fwu_write_configuration(); +} + +static int fwu_write_flash_configuration(void) +{ + int retval; + + TPD_ERR("%s: enter!!\n",__func__); + fwu->config_area = FLASH_CONFIG_AREA; + fwu->config_data = fwu->img.fl_config.data; + fwu->config_size = fwu->img.fl_config.size; + fwu->config_block_count = fwu->config_size / fwu->block_size; + + if (fwu->config_block_count != fwu->blkcount.fl_config) { + TPD_ERR("%s: Flash configuration size mismatch\n",__func__); + return -EINVAL; + } + + retval = fwu_write_f34_command(CMD_ERASE_FLASH_CONFIG); + if (retval < 0) + return retval; + + + retval = fwu_wait_for_idle(ERASE_WAIT_MS, false); + if (retval < 0){ + TPD_ERR("Erase configuration wait Idle status timeout!\n"); + return retval; + } + + retval = fwu_write_configuration(); + if (retval < 0){ + TPD_ERR("write configuration error!\n"); + return retval; + } + TPD_ERR("%s: finish!!\n",__func__); + return 0; +} + +static int fwu_write_partition_table(void) +{ + int retval; + unsigned short block_count; + + block_count = fwu->blkcount.bl_config; + fwu->config_area = BL_CONFIG_AREA; + fwu->config_size = fwu->block_size * block_count; + kfree(fwu->read_config_buf); + fwu->read_config_buf = kzalloc(fwu->config_size, GFP_KERNEL); + if (!fwu->read_config_buf) { + TPD_ERR("%s: Failed to alloc mem for fwu->read_config_buf\n",__func__); + fwu->read_config_buf_size = 0; + return -ENOMEM; + } + fwu->read_config_buf_size = fwu->config_size; + + retval = fwu_read_f34_blocks(block_count, CMD_READ_CONFIG); + if (retval < 0) + return retval; + + retval = fwu_write_flash_configuration(); + if (retval < 0) + return retval; + + fwu->config_area = BL_CONFIG_AREA; + fwu->config_data = fwu->read_config_buf; + fwu->config_size = fwu->img.bl_config.size; + fwu->config_block_count = fwu->config_size / fwu->block_size; + + retval = fwu_write_configuration(); + if (retval < 0) + return retval; + + return 0; +} + +static int fwu_do_reflash(void) +{ + int retval; + + if (!fwu->new_partition_table) { + retval = fwu_check_ui_firmware_size(); + if (retval < 0) + return retval; + + retval = fwu_check_ui_configuration_size(); + if (retval < 0) + return retval; + + retval = fwu_check_bl_configuration_size(); + if (retval < 0) + return retval; + } + + retval = fwu_erase_all(); + if (retval < 0) + return retval; + + if (fwu->new_partition_table) { + retval = fwu_write_partition_table(); + if (retval < 0) + return retval; + pr_notice("%s: Partition table programmed\n", __func__); + } + + retval = fwu_write_firmware(); + if (retval < 0) + return retval; + pr_notice("%s: Firmware programmed\n", __func__); + + fwu->config_area = UI_CONFIG_AREA; + retval = fwu_write_ui_configuration(); + if (retval < 0) + return retval; + pr_notice("%s: Configuration programmed\n", __func__); + + return retval; +} + +static int scan_pdt(void) +{ + int retval = 0; + char add_buf[6] = { 0 }; + + retval = synaptics_rmi4_i2c_read_block(fwu->client,0xE9,sizeof(add_buf),add_buf); + if (retval < 0) + return retval; + fwu->f34_fd.query_base_addr = add_buf[0]; + fwu->f34_fd.ctrl_base_addr = add_buf[2]; + fwu->f34_fd.data_base_addr = add_buf[3]; + if (add_buf[4]>>5 && 0x2) + fwu->bl_version = BL_V7; + TPD_ERR("F34_query_base_addr[0x%x],F34_ctrl_base_addr[0x%x],F34_data_base_addr[0x%x]\n",\ + add_buf[0],add_buf[2],add_buf[3]); + + retval = synaptics_rmi4_i2c_read_block(fwu->client,0xE3,sizeof(add_buf),add_buf); + fwu->bl_reset_add = add_buf[1]; + + return retval; +} + +static int fwu_read_f34_serialization(void) +{ + int retval; + unsigned char base; + unsigned char length[2]; + unsigned short block_number = 0; + unsigned char buffer[32]; + //static bool judge_version = true; + base = fwu->f34_fd.data_base_addr; + + fwu->config_area = PM_CONFIG_AREA; + + retval = fwu_write_f34_partition_id(CMD_READ_CONFIG); + if (retval < 0) + return retval; + + retval = synaptics_rmi4_i2c_write_block(fwu->client, + base + fwu->off.block_number, + sizeof(block_number),(unsigned char *)&block_number); + if (retval < 0) { + TPD_ERR("%s: Failed to write block number\n", + __func__); + return retval; + } + + length[0] = (unsigned char)(fwu->blkcount.pm_config & MASK_8BIT); + length[1] = (unsigned char)(fwu->blkcount.pm_config >> 8); + + retval = synaptics_rmi4_i2c_write_block(fwu->client, + base + fwu->off.transfer_length, + sizeof(length), length); + if (retval < 0) { + TPD_ERR("%s: Failed to write transfer length\n", + __func__); + return retval; + } + + retval = fwu_write_f34_command(CMD_READ_CONFIG); + if (retval < 0) { + TPD_ERR("%s: Failed to write command\n", + __func__); + return retval; + } + + retval = fwu_wait_for_idle(WRITE_WAIT_MS, true); + if (retval < 0) { + TPD_ERR("%s: Failed to wait for idle status\n", + __func__); + return retval; + } + /*buffer = kzalloc(fwu->blkcount.pm_config, GFP_KERNEL); + if (!buffer) { + TPD_ERR("%s: Failed to alloc mem for fwu->blkcount->pm_config\n", + __func__); + return -ENOMEM; + } + */ + retval = synaptics_rmi4_i2c_read_block(fwu->client, + base + fwu->off.payload,fwu->blkcount.pm_config,buffer); + if (retval < 0) { + TPD_ERR("%s: Failed to read block data\n", + __func__); + return retval; + } + TPD_ERR("%s:buffer5[0x%02x]\n",__func__,buffer[5]); + if(!(buffer[0] || buffer[1] || buffer[2] || buffer[4] || buffer[5])){ + TPD_ERR("%s:tp hardware version is 15801\n",__func__); + return 1; + }else{ + TPD_ERR("%s:tp hardware version is 15801vb\n",__func__); + return 0; + } +} + +int fwu_start_reflash_check(const unsigned char *fw_image, struct i2c_client *client) +{ + int retval; + //unsigned char *fw = (unsigned char *)fw_image; + + fwu = kzalloc(sizeof(*fwu), GFP_KERNEL); + if (!fwu) { + TPD_ERR("%s: Failed to alloc mem for fwu\n",__func__); + return -1; + } + + fwu->client = client; + + retval = scan_pdt(); + if (retval < 0) + return retval; + fwu->image = fw_image; + + memset(&fwu->blkcount, 0x00, sizeof(fwu->blkcount)); + memset(&fwu->phyaddr, 0x00, sizeof(fwu->phyaddr)); + retval = fwu_read_f34_v7_queries(); + if (retval < 0) { + TPD_ERR("%s: fwu_read_f34_v7_queries\n",__func__); + return retval; + } + TPD_DEBUG("%s: fwu_read_f34_serialization\n",__func__); + + retval = fwu_read_f34_serialization(); + kfree(fwu); + return retval; + } + +int fwu_start_reflash(const unsigned char *fw_image, struct i2c_client *client) +{ + int retval = 0; + unsigned char *fw = (unsigned char *)fw_image; + fwu = kzalloc(sizeof(*fwu), GFP_KERNEL); + if (!fwu) { + TPD_ERR("%s: Failed to alloc mem for fwu\n",__func__); + return -ENOMEM; + } + fwu->client = client; + + retval = scan_pdt(); + fwu->image = fw_image; + + fwu_read_f34_queries(); + retval = fwu_parse_image_info(fw); + + retval = fwu_read_flash_status(); + if (retval < 0) + goto exit_free_fwu; + + msleep(INT_DISABLE_WAIT_MS); + + retval = fwu_write_f34_command(CMD_ENABLE_FLASH_PROG); + if (retval < 0) + goto exit_free_fwu; + + retval = fwu_wait_for_idle(ENABLE_WAIT_MS, false); + if (retval < 0){ + goto exit_free_fwu; + } + if (!fwu->in_bl_mode) { + kfree(fwu); + fwu = NULL; + TPD_ERR("%s: BL mode not entered\n",__func__); + return -EINVAL; + } + TPD_ERR("fwu->bl_version[%d] fwu->in_bl_mode[%d]\n",fwu->bl_version,fwu->in_bl_mode); + retval = scan_pdt(); + + TPD_ERR("CMD_ERASE_UI_FIRMWARE.....................\n"); + retval = fwu_write_f34_command(CMD_ERASE_UI_FIRMWARE); + + retval = fwu_wait_for_idle(ERASE_WAIT_MS, true); + if (retval < 0){ + TPD_ERR("CMD_ERASE_UI_FIRMWARE timeout!\n"); + goto exit_free_fwu; + } + TPD_ERR("CMD_ERASE_UI_CONFIG.............\n"); + retval = fwu_write_f34_command(CMD_ERASE_UI_CONFIG); + retval = fwu_wait_for_idle(ERASE_WAIT_MS, true); + if (retval < 0){ + TPD_ERR("CMD_ERASE_UI_FIRMWARE timeout!\n"); + goto exit_free_fwu; + } + + if (1){ + retval = fwu_write_firmware(); + }else{ + retval = fwu_do_reflash(); + } + retval = fwu_write_ui_configuration(); + synaptics_rmi4_i2c_write_byte(fwu->client,fwu->bl_reset_add,0x01);//reset tp + return retval; + +exit_free_fwu: + kfree(fwu); + fwu = NULL; + return retval; +} diff --git a/drivers/input/touchscreen/synaptics_baseline.h b/drivers/input/touchscreen/synaptics_baseline.h new file mode 100755 index 000000000000..8f74826fc710 --- /dev/null +++ b/drivers/input/touchscreen/synaptics_baseline.h @@ -0,0 +1,362 @@ +#ifndef SYNAPTICS_BASELINE_H +#define SYNAPTICS_BASELINE_H + +#define TX_NUMBER (17) +#define TX_17801_NUMBER (15) +#define RX_NUMBER (30) + +#define TX_17819_NUMBER (16) +#define RX_17819_NUMBER (33) + +/*17819 s3706 TX 16 RX 33*/ +const int16_t baseline_cap_17819_data[2][TX_17819_NUMBER][RX_17819_NUMBER*2] = { +//enable cbc Notice it is opposite to the xls format. +{ + {386, 901, 618, 1441, 645, 1506, 651, 1519, 642, 1498, 638, 1489, 641, 1495, 643, 1500, 649, 1514, 637, 1485, 642, 1499, 649, 1515, 641, 1496, 648, 1512, 648, 1513, 644, 1503, 644, 1502, 644, 1502, 647, 1509, 653, 1525, 652, 1522, 658, 1535, 680, 1586, 667, 1556, 659, 1539, 663, 1547, 651, 1520, 662, 1545, 668, 1558, 663, 1546, 660, 1540, 665, 1551, 630, 1471}, + {665, 1553, 667, 1555, 669, 1560, 676, 1576, 665, 1552, 662, 1544, 664, 1549, 667, 1557, 672, 1567, 663, 1546, 666, 1553, 673, 1570, 668, 1559, 676, 1577, 671, 1566, 667, 1556, 672, 1568, 670, 1563, 669, 1562, 676, 1577, 679, 1583, 676, 1576, 681, 1588, 685, 1598, 713, 1664, 686, 1601, 676, 1578, 687, 1602, 688, 1605, 688, 1605, 681, 1589, 691, 1613, 695, 1622}, + {650, 1517, 662, 1545, 663, 1548, 671, 1565, 660, 1539, 656, 1531, 658, 1536, 661, 1543, 667, 1556, 657, 1533, 661, 1542, 668, 1559, 663, 1546, 670, 1564, 666, 1555, 662, 1544, 666, 1553, 665, 1551, 665, 1551, 671, 1566, 674, 1573, 704, 1643, 676, 1577, 678, 1582, 675, 1576, 679, 1585, 671, 1565, 681, 1590, 682, 1591, 683, 1593, 675, 1575, 686, 1601, 687, 1602}, + {644, 1503, 660, 1539, 661, 1543, 668, 1559, 657, 1532, 654, 1525, 656, 1530, 658, 1535, 664, 1549, 654, 1526, 658, 1536, 664, 1549, 660, 1540, 667, 1557, 663, 1547, 658, 1536, 663, 1546, 661, 1543, 662, 1544, 702, 1639, 670, 1564, 667, 1557, 672, 1567, 675, 1575, 673, 1571, 676, 1577, 667, 1556, 678, 1582, 679, 1584, 705, 1646, 672, 1569, 683, 1593, 683, 1594}, + {644, 1503, 659, 1538, 660, 1540, 667, 1555, 656, 1530, 653, 1523, 654, 1527, 658, 1534, 699, 1631, 653, 1525, 656, 1531, 663, 1547, 659, 1538, 667, 1556, 661, 1543, 658, 1534, 662, 1544, 660, 1540, 660, 1540, 667, 1555, 669, 1561, 665, 1553, 670, 1564, 673, 1571, 671, 1565, 674, 1573, 665, 1553, 677, 1579, 677, 1580, 677, 1579, 670, 1564, 681, 1588, 680, 1587}, + {643, 1501, 685, 1597, 659, 1537, 666, 1554, 655, 1529, 687, 1602, 654, 1526, 656, 1531, 662, 1545, 652, 1522, 656, 1530, 663, 1546, 658, 1534, 665, 1552, 661, 1543, 656, 1530, 660, 1540, 659, 1537, 658, 1536, 665, 1552, 667, 1557, 664, 1549, 668, 1559, 671, 1567, 669, 1562, 672, 1568, 664, 1550, 674, 1573, 676, 1577, 675, 1576, 669, 1560, 680, 1586, 678, 1582}, + {583, 1360, 657, 1534, 660, 1539, 666, 1554, 655, 1529, 651, 1520, 655, 1528, 656, 1532, 662, 1545, 652, 1522, 657, 1532, 663, 1546, 658, 1536, 665, 1551, 662, 1544, 693, 1616, 661, 1542, 659, 1538, 659, 1538, 666, 1554, 668, 1558, 664, 1550, 668, 1559, 671, 1566, 669, 1561, 672, 1568, 663, 1548, 675, 1575, 675, 1576, 675, 1576, 669, 1561, 679, 1584, 677, 1580}, + {398, 930, 637, 1486, 659, 1539, 667, 1556, 691, 1613, 652, 1522, 655, 1527, 656, 1532, 663, 1546, 652, 1522, 657, 1532, 663, 1546, 658, 1536, 665, 1552, 662, 1544, 657, 1532, 661, 1542, 659, 1538, 658, 1535, 666, 1554, 666, 1554, 664, 1549, 668, 1559, 671, 1567, 669, 1560, 672, 1568, 664, 1548, 674, 1574, 675, 1575, 674, 1573, 668, 1559, 678, 1582, 676, 1576}, + {416, 970, 645, 1505, 658, 1536, 665, 1551, 654, 1526, 651, 1519, 653, 1524, 656, 1530, 661, 1543, 651, 1519, 655, 1529, 662, 1545, 657, 1532, 665, 1551, 660, 1541, 656, 1531, 660, 1539, 659, 1537, 658, 1535, 665, 1552, 666, 1554, 664, 1548, 668, 1558, 706, 1647, 668, 1559, 671, 1567, 663, 1547, 673, 1571, 674, 1573, 674, 1573, 668, 1558, 679, 1583, 672, 1568}, + {603, 1406, 657, 1534, 658, 1534, 664, 1548, 654, 1525, 650, 1516, 652, 1520, 656, 1530, 660, 1541, 651, 1520, 655, 1528, 697, 1627, 657, 1533, 665, 1551, 661, 1541, 655, 1528, 660, 1539, 658, 1534, 658, 1534, 665, 1551, 665, 1552, 663, 1547, 667, 1557, 670, 1564, 668, 1560, 670, 1564, 663, 1546, 673, 1570, 674, 1572, 674, 1573, 667, 1556, 678, 1583, 667, 1556}, + {659, 1538, 658, 1535, 657, 1533, 665, 1551, 653, 1525, 651, 1518, 652, 1521, 656, 1530, 660, 1541, 651, 1518, 655, 1528, 661, 1542, 657, 1533, 664, 1549, 660, 1539, 655, 1529, 659, 1539, 658, 1535, 658, 1535, 665, 1552, 666, 1554, 663, 1547, 668, 1558, 671, 1565, 668, 1559, 707, 1650, 662, 1544, 673, 1570, 674, 1573, 672, 1569, 667, 1556, 678, 1581, 672, 1569}, + {659, 1539, 658, 1535, 658, 1534, 665, 1551, 653, 1524, 650, 1516, 653, 1524, 655, 1528, 660, 1541, 651, 1518, 655, 1528, 662, 1545, 656, 1532, 664, 1550, 660, 1540, 655, 1529, 659, 1538, 658, 1535, 695, 1622, 665, 1553, 667, 1555, 663, 1546, 667, 1557, 671, 1565, 668, 1559, 671, 1567, 663, 1547, 673, 1570, 674, 1572, 674, 1573, 667, 1557, 677, 1580, 671, 1566}, + {661, 1542, 659, 1537, 658, 1536, 665, 1552, 654, 1525, 651, 1518, 653, 1523, 656, 1530, 661, 1543, 651, 1520, 692, 1615, 662, 1545, 658, 1534, 665, 1552, 661, 1543, 656, 1531, 660, 1540, 659, 1538, 660, 1539, 667, 1555, 668, 1559, 665, 1552, 670, 1563, 673, 1571, 672, 1568, 675, 1575, 667, 1556, 678, 1582, 680, 1586, 680, 1587, 674, 1572, 685, 1599, 680, 1586}, + {666, 1555, 662, 1546, 662, 1544, 668, 1560, 657, 1534, 654, 1526, 657, 1533, 696, 1624, 666, 1553, 656, 1531, 660, 1541, 666, 1555, 662, 1546, 669, 1562, 665, 1552, 661, 1542, 665, 1551, 663, 1548, 663, 1547, 670, 1564, 671, 1566, 668, 1559, 672, 1568, 676, 1577, 673, 1570, 676, 1578, 669, 1560, 679, 1585, 680, 1587, 681, 1589, 674, 1573, 686, 1600, 681, 1589}, + {659, 1537, 663, 1546, 662, 1545, 668, 1559, 658, 1535, 654, 1526, 692, 1615, 659, 1538, 665, 1553, 655, 1528, 659, 1539, 666, 1554, 661, 1542, 669, 1560, 665, 1551, 661, 1541, 664, 1549, 663, 1547, 663, 1547, 670, 1563, 672, 1568, 668, 1559, 673, 1570, 676, 1578, 674, 1573, 677, 1579, 669, 1561, 679, 1584, 681, 1590, 681, 1589, 675, 1576, 687, 1602, 679, 1585}, + {575, 1343, 672, 1567, 677, 1579, 679, 1584, 665, 1552, 659, 1538, 660, 1539, 660, 1540, 664, 1549, 652, 1522, 656, 1530, 661, 1542, 656, 1530, 662, 1546, 694, 1619, 652, 1522, 656, 1530, 654, 1526, 653, 1524, 660, 1539, 660, 1541, 657, 1533, 661, 1543, 664, 1549, 661, 1542, 663, 1548, 655, 1528, 666, 1554, 668, 1558, 668, 1558, 663, 1548, 678, 1582, 651, 1520}, +}, +/*disable cbc*/ +{ + {397, 927, 628, 1466, 653, 1524, 660, 1539, 649, 1513, 647, 1509, 650, 1517, 651, 1518, 657, 1532, 646, 1506, 652, 1520, 657, 1533, 652, 1521, 659, 1539, 658, 1536, 651, 1519, 655, 1528, 654, 1526, 654, 1526, 662, 1545, 664, 1549, 665, 1552, 677, 1579, 674, 1572, 668, 1558, 672, 1567, 662, 1545, 673, 1569, 677, 1581, 675, 1575, 669, 1560, 672, 1567, 637, 1486}, + {672, 1568, 673, 1570, 675, 1575, 682, 1592, 671, 1566, 668, 1558, 671, 1567, 672, 1569, 678, 1583, 668, 1558, 672, 1569, 680, 1586, 674, 1572, 682, 1590, 678, 1583, 673, 1570, 678, 1582, 676, 1577, 676, 1577, 683, 1594, 684, 1597, 682, 1591, 687, 1603, 691, 1613, 708, 1652, 693, 1617, 683, 1594, 694, 1618, 695, 1621, 695, 1621, 688, 1606, 696, 1625, 701, 1635}, + {656, 1531, 668, 1559, 670, 1564, 678, 1582, 666, 1553, 664, 1549, 666, 1554, 668, 1558, 674, 1573, 664, 1548, 668, 1559, 675, 1575, 669, 1561, 678, 1581, 673, 1570, 669, 1560, 673, 1571, 671, 1566, 671, 1566, 678, 1582, 681, 1590, 699, 1630, 683, 1595, 686, 1600, 682, 1591, 686, 1602, 677, 1580, 688, 1606, 690, 1609, 690, 1611, 683, 1594, 692, 1615, 693, 1616}, + {653, 1523, 667, 1557, 670, 1562, 677, 1579, 665, 1552, 662, 1545, 665, 1552, 666, 1553, 672, 1569, 662, 1545, 667, 1555, 673, 1569, 668, 1559, 676, 1576, 672, 1568, 666, 1555, 671, 1566, 670, 1563, 670, 1564, 699, 1630, 679, 1584, 675, 1575, 680, 1587, 683, 1594, 680, 1587, 684, 1595, 676, 1577, 686, 1600, 687, 1604, 714, 1666, 681, 1589, 689, 1608, 689, 1608}, + {652, 1521, 668, 1558, 668, 1558, 675, 1574, 663, 1547, 661, 1541, 662, 1546, 666, 1554, 694, 1618, 662, 1544, 665, 1551, 671, 1567, 667, 1555, 674, 1572, 670, 1563, 665, 1551, 670, 1563, 668, 1559, 668, 1558, 675, 1576, 676, 1577, 673, 1570, 677, 1580, 682, 1590, 678, 1581, 682, 1591, 674, 1572, 684, 1596, 684, 1596, 685, 1599, 679, 1584, 687, 1602, 686, 1602}, + {650, 1518, 691, 1612, 666, 1553, 672, 1569, 662, 1546, 682, 1592, 662, 1545, 662, 1546, 668, 1560, 659, 1537, 664, 1548, 669, 1562, 665, 1551, 672, 1567, 668, 1559, 662, 1546, 667, 1557, 665, 1553, 665, 1552, 672, 1568, 674, 1574, 671, 1565, 676, 1577, 679, 1583, 676, 1576, 679, 1584, 672, 1567, 681, 1590, 683, 1594, 683, 1593, 676, 1578, 685, 1598, 684, 1595}, + {590, 1376, 664, 1549, 666, 1555, 673, 1569, 661, 1543, 659, 1537, 662, 1544, 662, 1545, 668, 1560, 658, 1536, 663, 1548, 670, 1563, 665, 1551, 672, 1569, 669, 1561, 688, 1606, 668, 1558, 665, 1553, 665, 1552, 672, 1569, 674, 1574, 671, 1566, 675, 1575, 678, 1583, 676, 1576, 679, 1584, 671, 1566, 682, 1590, 682, 1591, 682, 1592, 676, 1576, 685, 1598, 683, 1594}, + {406, 947, 644, 1502, 666, 1554, 674, 1572, 686, 1600, 660, 1540, 662, 1544, 663, 1546, 669, 1561, 659, 1538, 663, 1548, 670, 1563, 665, 1552, 673, 1570, 669, 1560, 664, 1549, 668, 1558, 667, 1556, 665, 1552, 673, 1570, 674, 1572, 671, 1566, 675, 1575, 678, 1582, 676, 1577, 679, 1584, 672, 1567, 681, 1588, 682, 1590, 683, 1593, 676, 1576, 684, 1597, 682, 1591}, + {423, 988, 653, 1524, 665, 1552, 672, 1569, 661, 1542, 659, 1537, 662, 1544, 662, 1544, 668, 1560, 659, 1537, 663, 1547, 669, 1562, 665, 1552, 672, 1569, 668, 1559, 663, 1547, 668, 1559, 666, 1553, 666, 1554, 673, 1570, 674, 1572, 671, 1566, 676, 1578, 704, 1642, 675, 1576, 679, 1584, 671, 1565, 681, 1589, 681, 1590, 682, 1591, 676, 1577, 684, 1596, 680, 1586}, + {611, 1426, 666, 1553, 666, 1553, 672, 1569, 661, 1542, 659, 1537, 661, 1542, 662, 1545, 669, 1561, 659, 1537, 663, 1547, 696, 1623, 665, 1552, 673, 1570, 669, 1560, 663, 1547, 668, 1558, 666, 1553, 665, 1552, 673, 1570, 673, 1569, 671, 1566, 675, 1575, 679, 1584, 676, 1576, 679, 1585, 671, 1566, 680, 1588, 681, 1590, 682, 1592, 675, 1576, 685, 1598, 673, 1571}, + {667, 1556, 665, 1552, 665, 1551, 672, 1567, 660, 1539, 657, 1534, 661, 1541, 661, 1542, 668, 1558, 658, 1535, 662, 1546, 669, 1561, 664, 1549, 671, 1567, 667, 1557, 662, 1545, 667, 1556, 665, 1553, 664, 1550, 672, 1568, 673, 1570, 670, 1564, 675, 1575, 678, 1581, 675, 1575, 705, 1645, 670, 1563, 680, 1586, 681, 1589, 682, 1591, 675, 1574, 683, 1594, 679, 1584}, + {667, 1556, 665, 1552, 665, 1552, 672, 1569, 661, 1542, 658, 1535, 660, 1541, 662, 1545, 668, 1558, 658, 1536, 663, 1547, 670, 1563, 665, 1551, 672, 1569, 668, 1559, 663, 1547, 667, 1556, 666, 1555, 691, 1612, 672, 1569, 674, 1573, 671, 1566, 675, 1576, 678, 1582, 675, 1576, 679, 1583, 671, 1566, 680, 1588, 682, 1591, 682, 1592, 675, 1575, 684, 1596, 678, 1581}, + {669, 1562, 667, 1556, 666, 1553, 673, 1570, 661, 1543, 659, 1537, 662, 1544, 663, 1548, 669, 1560, 659, 1539, 689, 1608, 671, 1565, 665, 1552, 673, 1570, 670, 1562, 665, 1551, 669, 1562, 668, 1558, 666, 1555, 675, 1575, 676, 1577, 674, 1572, 678, 1581, 681, 1590, 678, 1583, 683, 1594, 675, 1575, 686, 1600, 688, 1606, 688, 1606, 682, 1591, 692, 1614, 687, 1602}, + {673, 1570, 668, 1558, 668, 1558, 674, 1573, 663, 1547, 661, 1542, 664, 1550, 690, 1611, 673, 1570, 663, 1547, 668, 1558, 674, 1572, 668, 1558, 677, 1579, 673, 1569, 667, 1557, 672, 1568, 670, 1564, 669, 1562, 677, 1581, 679, 1584, 675, 1576, 680, 1587, 683, 1593, 679, 1585, 684, 1595, 675, 1576, 686, 1601, 688, 1606, 688, 1606, 682, 1591, 692, 1614, 687, 1603}, + {667, 1556, 671, 1565, 670, 1562, 676, 1577, 664, 1550, 663, 1547, 689, 1608, 667, 1556, 673, 1569, 662, 1546, 667, 1557, 674, 1573, 668, 1559, 677, 1579, 673, 1569, 668, 1558, 672, 1569, 671, 1566, 670, 1564, 678, 1582, 679, 1583, 676, 1577, 680, 1588, 684, 1596, 681, 1588, 685, 1598, 677, 1579, 688, 1604, 689, 1608, 689, 1609, 683, 1594, 693, 1618, 685, 1599}, + {582, 1359, 678, 1583, 684, 1596, 686, 1600, 671, 1567, 666, 1555, 667, 1557, 666, 1554, 671, 1566, 659, 1538, 663, 1548, 668, 1560, 662, 1546, 671, 1565, 690, 1610, 659, 1539, 663, 1548, 661, 1542, 660, 1540, 667, 1556, 668, 1558, 664, 1549, 668, 1559, 671, 1565, 667, 1556, 671, 1567, 663, 1547, 672, 1569, 674, 1574, 676, 1577, 671, 1565, 684, 1596, 658, 1535}, + +} +}; + +const int16_t baseline_cap_data[2][TX_NUMBER][RX_NUMBER*2] = +{ + //enable cbc + { + {403,748,441,819,451,837,451,837,450,836,459,852,450,836,448,832,456,846,451,837,454,844,458,850,463,861,498,926,499,927,501,930,515,956,526,978,529,982,528,980,531,987,544,1010,554,1030,557,1034,561,1041,568,1056,568,1056,587,1091,741,1375,776,1440}, + {424,787,460,854,468,870,468,870,468,870,476,884,468,868,468,868,472,876,470,872,473,879,485,901,485,901,522,969,522,969,522,969,531,987,534,992,547,1017,545,1013,557,1034,561,1041,574,1066,592,1099,576,1070,592,1099,592,1099,601,1115,774,1437,791,1469}, + {419,779,456,846,464,862,464,862,463,861,471,875,464,862,462,858,470,872,466,865,470,872,473,879,477,887,522,969,522,969,522,969,526,978,530,984,542,1006,540,1002,545,1013,557,1034,566,1052,568,1056,571,1060,580,1076,578,1074,592,1099,757,1405,783,1455}, + {420,780,456,846,466,865,466,865,464,862,473,879,466,865,463,861,470,872,468,868,470,872,473,879,477,887,522,969,522,969,522,969,528,980,530,984,543,1009,541,1005,544,1010,566,1052,566,1052,566,1052,571,1060,578,1074,578,1073,592,1099,756,1404,783,1453}, + {421,783,454,844,464,862,464,862,464,862,473,879,464,862,463,861,470,872,466,865,468,870,472,876,476,884,512,952,510,948,522,969,526,978,529,982,541,1005,540,1002,552,1024,557,1034,564,1048,565,1049,567,1053,575,1067,574,1066,592,1099,756,1404,777,1443}, + {421,783,454,844,464,862,464,862,464,862,473,879,464,862,463,861,470,872,468,868,468,870,473,879,477,887,522,970,511,949,522,969,526,976,528,980,540,1002,539,1001,543,1009,557,1034,565,1049,565,1049,567,1053,575,1067,574,1066,582,1082,752,1396,774,1437}, + {418,776,453,841,464,862,466,865,463,861,472,876,463,861,462,858,479,889,466,865,468,870,472,876,476,884,510,948,510,948,512,952,524,974,528,980,540,1002,539,1001,540,1002,552,1024,562,1044,563,1045,565,1049,572,1062,572,1062,578,1074,750,1394,774,1437}, + {415,771,456,846,468,868,468,868,466,865,474,880,466,865,463,861,472,876,468,868,471,875,473,879,477,887,511,949,511,949,522,969,526,976,530,984,540,1002,547,1017,540,1002,552,1024,562,1044,562,1044,563,1045,574,1066,571,1060,578,1073,752,1396,774,1437}, + {405,751,456,846,468,868,468,870,468,868,474,880,468,868,466,865,473,879,479,889,472,876,475,883,480,891,522,969,522,969,522,969,526,978,530,984,542,1006,539,1001,542,1006,557,1034,565,1049,561,1041,563,1045,572,1062,572,1062,575,1067,752,1396,774,1437}, + {415,771,460,854,472,876,472,876,471,875,480,891,471,875,470,872,476,884,472,876,476,884,479,889,485,901,522,969,522,969,526,978,530,984,533,991,544,1010,541,1005,543,1009,557,1034,566,1052,565,1049,566,1052,574,1066,574,1066,576,1070,750,1394,774,1437}, + {428,794,463,861,473,879,474,880,473,879,485,901,474,880,473,879,480,891,476,884,477,887,485,901,485,901,522,969,522,969,522,969,532,988,534,992,545,1013,542,1006,544,1010,557,1034,565,1049,565,1049,566,1052,574,1066,582,1082,574,1066,760,1412,762,1416}, + {442,822,468,868,477,887,479,889,476,884,485,901,477,887,475,883,485,901,477,887,491,913,485,901,489,907,522,969,522,969,522,969,534,992,536,996,551,1023,543,1009,547,1017,557,1035,584,1084,565,1049,566,1052,574,1066,574,1066,570,1058,750,1394,762,1416}, + {450,836,470,872,479,889,479,889,476,884,487,904,479,889,476,884,485,901,485,901,485,901,485,901,489,909,524,972,522,969,522,970,544,1010,536,996,547,1017,544,1010,547,1017,557,1035,565,1049,565,1049,567,1053,574,1066,574,1066,568,1056,753,1398,774,1437}, + {454,844,472,876,485,901,485,901,480,891,487,905,485,901,479,889,487,904,485,901,485,901,487,905,491,913,524,974,522,970,522,970,536,995,536,996,549,1019,544,1010,547,1017,559,1037,567,1053,566,1052,578,1073,575,1067,575,1067,574,1066,756,1404,774,1437}, + {463,861,476,884,485,901,487,905,485,901,489,909,485,901,485,901,489,907,485,901,487,904,494,918,494,918,528,980,526,976,526,978,539,1001,540,1002,557,1034,547,1017,551,1023,562,1044,574,1066,574,1066,574,1066,582,1082,584,1084,595,1105,762,1414,791,1469}, + {498,926,498,926,498,926,498,926,494,918,498,926,494,918,498,926,494,918,489,909,489,909,494,918,498,926,534,992,534,992,530,984,543,1009,543,1009,570,1058,547,1017,552,1024,561,1041,589,1095,570,1058,574,1066,582,1082,582,1082,596,1106,769,1429,800,1486}, + {498,926,498,926,498,926,498,926,494,918,498,926,494,918,498,926,494,918,489,909,489,909,494,918,498,926,534,992,534,992,530,984,543,1009,543,1009,570,1058,547,1017,552,1024,561,1041,589,1095,570,1058,574,1066,582,1082,582,1082,596,1106,500,3000,500,3000}, + }, + /*disable cbc*/ + { + {608,1130,650,1208,655,1216,652,1210,652,1212,658,1222,652,1212,655,1216,650,1208,655,1216,656,1218,668,1240,677,1257,673,1249,681,1265,691,1283,685,1273,713,1325,713,1325,723,1343,725,1347,731,1357,734,1362,739,1372,734,1362,747,1387,741,1375,776,1440,741,1375,776,1440}, + {633,1175,670,1244,677,1257,671,1247,673,1249,678,1258,673,1251,677,1257,668,1240,677,1257,677,1257,704,1307,704,1307,704,1307,704,1307,712,1322,706,1310,723,1343,739,1372,743,1379,747,1387,756,1404,756,1404,774,1437,756,1404,774,1437,774,1437,791,1469,774,1437,791,1469}, + {633,1175,668,1240,673,1249,669,1243,670,1244,675,1253,671,1247,673,1251,668,1240,673,1249,673,1251,685,1273,704,1307,704,1307,710,1318,708,1316,704,1307,721,1339,731,1357,741,1375,743,1379,747,1387,750,1394,756,1404,749,1391,762,1416,757,1405,783,1455,757,1405,783,1455}, + {633,1175,668,1240,673,1249,669,1243,671,1247,678,1258,673,1249,675,1253,668,1240,673,1251,676,1255,688,1278,704,1307,704,1307,704,1307,710,1318,704,1307,722,1340,732,1359,741,1375,743,1379,757,1405,752,1396,753,1398,748,1390,762,1414,756,1404,783,1453,756,1404,783,1453}, + {633,1175,668,1240,670,1244,668,1240,670,1244,675,1253,673,1249,673,1251,668,1240,671,1247,675,1253,687,1275,704,1307,704,1307,704,1307,708,1314,704,1307,721,1339,729,1355,739,1372,752,1396,745,1383,748,1390,752,1396,745,1383,760,1411,756,1404,777,1443,756,1404,777,1443}, + {633,1175,664,1232,669,1243,668,1240,668,1240,673,1251,670,1244,671,1247,668,1240,670,1244,673,1249,685,1273,704,1307,704,1307,704,1307,706,1310,704,1307,718,1333,727,1351,739,1372,739,1372,743,1379,747,1387,748,1390,743,1379,756,1404,752,1396,774,1437,752,1396,774,1437}, + {621,1153,662,1229,668,1240,668,1240,668,1240,673,1251,670,1244,671,1247,675,1253,670,1244,673,1249,685,1273,704,1307,704,1307,704,1307,706,1310,704,1307,718,1333,727,1351,739,1372,739,1372,743,1379,747,1387,748,1390,743,1379,757,1405,750,1394,774,1437,750,1394,774,1437}, + {620,1151,668,1240,671,1247,668,1240,670,1244,677,1257,673,1249,673,1251,668,1240,673,1251,675,1253,688,1278,704,1307,704,1307,704,1307,708,1314,704,1307,721,1339,729,1355,747,1387,739,1372,743,1379,747,1387,750,1394,744,1382,757,1405,752,1396,774,1437,752,1396,774,1437}, + {621,1153,668,1240,675,1253,670,1244,673,1251,678,1258,673,1251,677,1257,669,1243,685,1273,678,1258,704,1307,704,1307,704,1307,704,1307,710,1318,704,1308,721,1339,731,1357,739,1372,739,1373,743,1379,749,1391,750,1394,744,1382,757,1405,752,1396,774,1437,752,1396,774,1437}, + {633,1175,668,1240,676,1255,673,1251,676,1255,681,1265,677,1257,679,1261,673,1249,677,1257,679,1261,704,1307,704,1307,704,1307,704,1308,723,1343,706,1312,723,1343,732,1359,739,1373,741,1375,745,1383,750,1394,752,1396,744,1382,756,1404,750,1394,774,1437,750,1394,774,1437}, + {639,1187,671,1247,678,1258,675,1253,677,1257,683,1268,679,1261,680,1264,673,1251,679,1261,681,1265,704,1307,704,1307,704,1307,706,1310,713,1325,708,1314,723,1343,732,1359,741,1375,741,1377,745,1383,747,1387,749,1391,743,1379,756,1404,760,1412,762,1416,760,1412,762,1416}, + {647,1201,675,1253,679,1261,677,1257,679,1261,685,1273,681,1265,683,1268,677,1257,681,1265,704,1307,704,1307,704,1307,704,1307,708,1314,716,1330,710,1318,725,1347,739,1372,741,1377,743,1379,747,1387,774,1437,750,1394,744,1382,756,1404,750,1394,762,1416,750,1394,762,1416}, + {655,1216,678,1258,683,1269,680,1264,681,1265,688,1278,683,1268,685,1273,679,1261,685,1273,685,1273,704,1307,706,1310,704,1307,710,1318,718,1333,722,1340,727,1351,739,1372,744,1382,744,1382,748,1390,750,1394,752,1396,746,1386,758,1408,753,1398,774,1437,753,1398,774,1437}, + {660,1226,681,1265,685,1273,681,1265,683,1268,704,1307,685,1273,687,1275,680,1264,685,1273,688,1278,704,1307,706,1312,704,1307,710,1318,718,1333,712,1322,727,1351,739,1372,744,1382,744,1382,748,1390,752,1396,752,1396,756,1404,760,1411,756,1404,774,1437,756,1404,774,1437}, + {668,1240,685,1273,688,1278,704,1307,687,1275,704,1307,687,1275,704,1307,681,1265,688,1278,704,1307,706,1312,711,1320,706,1312,714,1326,721,1339,714,1326,732,1359,741,1377,748,1390,747,1387,753,1398,757,1405,758,1408,753,1398,774,1437,762,1414,791,1469,762,1414,791,1469}, + {716,1330,716,1330,716,1330,701,1301,701,1301,712,1322,699,1297,716,1330,699,1297,699,1297,699,1297,716,1330,725,1347,721,1339,734,1362,734,1362,725,1347,734,1362,769,1429,760,1412,760,1412,764,1420,787,1461,764,1420,764,1420,769,1429,769,1429,800,1486,769,1429,800,1486}, + {716,1330,716,1330,716,1330,701,1301,701,1301,712,1322,699,1297,716,1330,699,1297,699,1297,699,1297,716,1330,725,1347,721,1339,734,1362,734,1362,725,1347,734,1362,769,1429,760,1412,760,1412,764,1420,787,1461,764,1420,764,1420,769,1429,769,1429,800,1486,500,3000,500,3000}, + } +}; + +const int16_t baseline_cap_17801_data[2][TX_17801_NUMBER][RX_NUMBER*2] = { +/*enable cbc*/ + { + {662, 1544, 509, 1188, 510, 1189, 510, 1191, 510, + 1189, 511, 1192, 510, 1190, 511, 1192, 512, 1195, + 512, 1194, 514, 1199, 514, 1199, 515, 1202, 518, + 1209, 517, 1207, 521, 1215, 523, 1219, 525, 1225, + 526, 1228, 535, 1249, 528, 1233, 532, 1240, 533, + 1244, 533, 1244, 535, 1249, 538, 1255, 537, 1252, + 537, 1253, 539, 1259, 740, 1727}, + {560, 1307, 592, 1381, 593, 1384, 594, 1387, 594, + 1385, 595, 1388, 594, 1386, 595, 1387, 596, 1391, + 595, 1389, 598, 1395, 597, 1394, 599, 1398, 602, + 1405, 601, 1402, 605, 1411, 614, 1433, 609, 1421, + 610, 1424, 612, 1427, 612, 1428, 616, 1436, 617, + 1440, 617, 1441, 620, 1446, 622, 1451, 621, 1449, + 621, 1449, 623, 1453, 625, 1459}, + {562, 1311, 593, 1383, 595, 1387, 596, 1390, 595, + 1388, 596, 1391, 595, 1389, 596, 1391, 598, 1394, + 597, 1392, 599, 1398, 599, 1397, 600, 1400, 603, + 1407, 602, 1405, 613, 1430, 607, 1417, 610, 1422, + 611, 1425, 612, 1429, 613, 1429, 616, 1437, 618, + 1441, 618, 1441, 620, 1446, 622, 1451, 621, 1449, + 621, 1449, 622, 1452, 622, 1451}, + {563, 1313, 592, 1381, 594, 1386, 595, 1389, 594, + 1387, 596, 1390, 595, 1388, 595, 1389, 597, 1393, + 596, 1391, 599, 1397, 598, 1396, 600, 1399, 603, + 1406, 601, 1403, 604, 1410, 606, 1414, 609, 1421, + 610, 1424, 611, 1427, 612, 1427, 615, 1435, 617, + 1439, 624, 1457, 618, 1443, 620, 1448, 619, 1445, + 619, 1445, 621, 1448, 619, 1444}, + {563, 1314, 591, 1379, 593, 1384, 594, 1387, 594, + 1386, 595, 1389, 594, 1386, 595, 1388, 596, 1392, + 596, 1390, 598, 1395, 597, 1394, 599, 1398, 602, + 1404, 601, 1401, 604, 1408, 605, 1413, 608, 1418, + 617, 1440, 611, 1425, 611, 1425, 614, 1432, 615, + 1436, 615, 1436, 617, 1440, 619, 1445, 618, 1442, + 618, 1441, 619, 1444, 616, 1437}, + {564, 1316, 591, 1378, 593, 1383, 594, 1386, 594, + 1385, 595, 1388, 594, 1386, 594, 1387, 596, 1391, + 595, 1389, 597, 1394, 597, 1393, 599, 1397, 601, + 1403, 600, 1401, 603, 1408, 605, 1412, 608, 1418, + 609, 1420, 610, 1423, 610, 1423, 613, 1431, 615, + 1434, 615, 1434, 624, 1456, 618, 1443, 617, 1440, + 617, 1439, 618, 1442, 613, 1431}, + {565, 1319, 591, 1379, 593, 1384, 594, 1387, 594, + 1385, 595, 1388, 594, 1386, 594, 1387, 596, 1390, + 595, 1388, 597, 1394, 597, 1393, 598, 1396, 601, + 1403, 600, 1400, 603, 1408, 605, 1412, 607, 1417, + 608, 1420, 610, 1422, 617, 1441, 613, 1430, 614, + 1433, 614, 1433, 616, 1437, 618, 1442, 617, 1439, + 616, 1438, 617, 1440, 611, 1426}, + {568, 1324, 591, 1380, 593, 1385, 595, 1388, 594, + 1386, 595, 1389, 594, 1386, 595, 1388, 596, 1391, + 595, 1389, 598, 1394, 597, 1393, 599, 1397, 601, + 1403, 600, 1401, 603, 1408, 605, 1412, 615, 1436, + 609, 1420, 610, 1422, 610, 1422, 613, 1429, 614, + 1432, 614, 1432, 616, 1436, 618, 1441, 616, 1438, + 616, 1437, 617, 1439, 610, 1423}, + {570, 1330, 592, 1382, 594, 1386, 595, 1389, 595, + 1388, 596, 1390, 595, 1388, 595, 1389, 597, 1393, + 596, 1391, 598, 1396, 598, 1395, 599, 1399, 602, + 1405, 609, 1420, 604, 1409, 605, 1413, 608, 1418, + 609, 1420, 610, 1423, 610, 1423, 613, 1429, 614, + 1432, 614, 1432, 615, 1436, 617, 1440, 616, 1437, + 616, 1437, 617, 1439, 610, 1424}, + {572, 1335, 593, 1383, 595, 1388, 596, 1391, 595, + 1389, 596, 1392, 596, 1390, 596, 1391, 598, 1395, + 597, 1393, 599, 1398, 599, 1397, 600, 1400, 603, + 1406, 601, 1403, 604, 1410, 606, 1414, 608, 1419, + 609, 1421, 610, 1424, 610, 1424, 613, 1430, 614, + 1433, 614, 1432, 616, 1436, 617, 1440, 616, 1437, + 616, 1437, 624, 1457, 607, 1417}, + {576, 1345, 595, 1387, 596, 1392, 598, 1395, 597, + 1393, 598, 1396, 598, 1394, 598, 1396, 600, 1399, + 599, 1397, 601, 1402, 601, 1401, 602, 1404, 612, + 1428, 603, 1407, 606, 1413, 607, 1417, 609, 1422, + 610, 1424, 611, 1427, 611, 1426, 614, 1433, 615, + 1435, 615, 1434, 616, 1438, 618, 1442, 616, 1438, + 616, 1438, 617, 1440, 606, 1413}, + {578, 1349, 594, 1387, 596, 1391, 597, 1394, 597, + 1392, 598, 1395, 597, 1393, 598, 1395, 599, 1398, + 598, 1396, 601, 1402, 600, 1401, 602, 1404, 604, + 1409, 603, 1406, 605, 1413, 607, 1416, 609, 1421, + 610, 1423, 611, 1426, 611, 1425, 614, 1432, 615, + 1434, 614, 1434, 616, 1437, 625, 1459, 616, 1438, + 616, 1438, 617, 1440, 605, 1411}, + {582, 1357, 594, 1387, 596, 1391, 597, 1393, 596, + 1392, 598, 1395, 597, 1393, 598, 1394, 599, 1398, + 598, 1396, 601, 1401, 600, 1400, 601, 1403, 604, + 1409, 603, 1406, 606, 1413, 607, 1416, 609, 1421, + 610, 1423, 611, 1425, 611, 1425, 622, 1450, 615, + 1434, 615, 1434, 616, 1438, 618, 1443, 617, 1440, + 617, 1440, 619, 1445, 612, 1429}, + {587, 1370, 594, 1385, 595, 1388, 596, 1390, 595, + 1388, 596, 1391, 596, 1390, 596, 1392, 598, 1396, + 598, 1394, 600, 1400, 600, 1400, 602, 1405, 604, + 1410, 603, 1407, 606, 1415, 608, 1418, 610, 1424, + 611, 1427, 612, 1429, 613, 1429, 616, 1437, 625, + 1458, 617, 1441, 620, 1446, 622, 1452, 622, 1451, + 623, 1453, 626, 1461, 615, 1435}, + {738, 1721, 599, 1398, 595, 1388, 592, 1381, 597, + 1392, 588, 1373, 586, 1367, 585, 1365, 586, 1366, + 584, 1362, 585, 1365, 584, 1363, 585, 1364, 587, + 1369, 585, 1365, 587, 1370, 588, 1373, 590, 1376, + 591, 1378, 591, 1380, 591, 1378, 593, 1385, 594, + 1387, 598, 1396, 596, 1391, 598, 1396, 598, 1395, + 599, 1399, 613, 1431, 762, 1777}, + }, +/*disable cbc*/ + { + {821, 1915, 491, 1145, 491, 1146, 492, 1148, 492, + 1148, 492, 1149, 492, 1147, 492, 1149, 494, 1152, + 494, 1153, 496, 1158, 496, 1157, 498, 1161, 501, + 1168, 500, 1166, 503, 1174, 505, 1179, 508, 1185, + 509, 1188, 518, 1209, 511, 1192, 514, 1200, 516, + 1204, 516, 1204, 518, 1209, 521, 1216, 519, 1211, + 519, 1212, 523, 1220, 901, 2103}, + {598, 1395, 630, 1470, 631, 1473, 633, 1476, 632, + 1475, 633, 1477, 632, 1475, 633, 1476, 634, 1480, + 634, 1480, 637, 1486, 636, 1485, 638, 1488, 641, + 1496, 640, 1494, 644, 1502, 653, 1525, 648, 1512, + 650, 1516, 651, 1519, 651, 1520, 655, 1528, 657, + 1532, 657, 1533, 659, 1538, 662, 1544, 660, 1539, + 660, 1539, 662, 1546, 665, 1551}, + {598, 1394, 629, 1467, 631, 1472, 632, 1475, 632, + 1474, 632, 1476, 632, 1474, 632, 1475, 634, 1479, + 634, 1479, 636, 1485, 636, 1483, 637, 1487, 640, + 1494, 639, 1491, 650, 1518, 644, 1504, 647, 1510, + 648, 1513, 650, 1516, 650, 1517, 654, 1525, 655, + 1529, 655, 1529, 657, 1534, 660, 1539, 658, 1535, + 658, 1535, 660, 1540, 660, 1540}, + {598, 1395, 627, 1463, 629, 1469, 631, 1472, 631, + 1472, 631, 1473, 631, 1471, 631, 1473, 633, 1476, + 633, 1476, 635, 1482, 634, 1480, 636, 1484, 639, + 1491, 638, 1488, 641, 1496, 643, 1500, 646, 1506, + 647, 1510, 648, 1513, 649, 1513, 652, 1521, 654, + 1525, 661, 1543, 655, 1529, 658, 1534, 655, 1529, + 655, 1529, 658, 1535, 656, 1531}, + {598, 1395, 626, 1461, 629, 1467, 630, 1470, 630, + 1470, 631, 1471, 630, 1469, 630, 1471, 632, 1474, + 632, 1475, 634, 1480, 634, 1479, 635, 1482, 638, + 1489, 637, 1486, 640, 1494, 642, 1498, 645, 1504, + 654, 1526, 647, 1510, 648, 1511, 651, 1519, 652, + 1522, 652, 1522, 654, 1526, 656, 1531, 654, 1526, + 654, 1526, 656, 1531, 653, 1523}, + {599, 1398, 626, 1461, 628, 1466, 630, 1470, 630, + 1469, 630, 1471, 629, 1469, 630, 1470, 631, 1473, + 631, 1473, 634, 1479, 633, 1478, 635, 1481, 638, + 1488, 637, 1485, 640, 1493, 642, 1497, 644, 1503, + 645, 1506, 647, 1509, 647, 1509, 650, 1517, 652, + 1520, 652, 1520, 661, 1543, 655, 1529, 653, 1524, + 653, 1524, 655, 1529, 650, 1518}, + {601, 1401, 626, 1461, 629, 1467, 630, 1470, 630, + 1469, 630, 1470, 629, 1469, 630, 1470, 631, 1473, + 631, 1473, 634, 1479, 633, 1477, 635, 1481, 638, + 1488, 637, 1485, 640, 1493, 642, 1497, 644, 1503, + 645, 1505, 646, 1508, 654, 1526, 650, 1516, 651, + 1519, 651, 1519, 653, 1523, 655, 1528, 653, 1523, + 652, 1522, 654, 1527, 648, 1513}, + {603, 1406, 627, 1463, 629, 1468, 631, 1471, 630, + 1471, 631, 1472, 630, 1470, 630, 1471, 632, 1474, + 632, 1474, 634, 1479, 634, 1478, 635, 1482, 638, + 1489, 637, 1486, 640, 1494, 642, 1497, 652, 1522, + 645, 1506, 646, 1508, 647, 1509, 650, 1516, 651, + 1519, 651, 1519, 653, 1523, 655, 1528, 653, 1523, + 652, 1522, 654, 1526, 647, 1510}, + {605, 1411, 627, 1464, 630, 1469, 631, 1473, 631, + 1472, 631, 1473, 630, 1471, 631, 1473, 632, 1476, + 632, 1476, 635, 1481, 634, 1480, 636, 1483, 638, + 1490, 645, 1505, 640, 1494, 642, 1498, 644, 1504, + 646, 1506, 647, 1509, 647, 1509, 650, 1516, 651, + 1519, 651, 1518, 652, 1522, 654, 1527, 652, 1522, + 652, 1521, 654, 1526, 648, 1511}, + {607, 1417, 628, 1466, 630, 1471, 632, 1474, 632, + 1474, 632, 1475, 631, 1473, 632, 1475, 633, 1478, + 633, 1478, 636, 1483, 635, 1482, 636, 1485, 639, + 1492, 638, 1489, 641, 1495, 643, 1499, 645, 1505, + 646, 1507, 647, 1510, 647, 1510, 650, 1517, 651, + 1519, 651, 1519, 653, 1523, 654, 1527, 652, 1522, + 652, 1521, 662, 1544, 644, 1504}, + {612, 1427, 630, 1470, 632, 1475, 634, 1479, 633, + 1478, 634, 1479, 633, 1478, 634, 1479, 635, 1483, + 635, 1482, 637, 1487, 637, 1486, 638, 1489, 649, + 1514, 640, 1492, 642, 1499, 644, 1503, 646, 1508, + 647, 1510, 648, 1513, 648, 1513, 651, 1519, 652, + 1522, 652, 1521, 653, 1524, 655, 1528, 653, 1523, + 653, 1523, 655, 1528, 643, 1500}, + {614, 1432, 630, 1470, 632, 1475, 634, 1478, 633, + 1478, 634, 1479, 633, 1477, 634, 1479, 635, 1482, + 635, 1482, 638, 1488, 637, 1486, 638, 1489, 641, + 1495, 639, 1492, 642, 1499, 644, 1502, 646, 1508, + 647, 1510, 648, 1512, 648, 1512, 651, 1519, 652, + 1521, 652, 1521, 653, 1524, 663, 1547, 653, 1523, + 653, 1523, 655, 1528, 642, 1499}, + {617, 1440, 630, 1470, 632, 1474, 633, 1477, 633, + 1477, 634, 1478, 633, 1477, 634, 1478, 635, 1482, + 635, 1482, 637, 1487, 637, 1486, 638, 1489, 641, + 1495, 640, 1492, 643, 1499, 644, 1503, 646, 1508, + 647, 1510, 648, 1512, 648, 1512, 659, 1537, 652, + 1522, 652, 1521, 653, 1525, 656, 1530, 654, 1525, + 654, 1525, 657, 1533, 650, 1517}, + {622, 1452, 629, 1469, 630, 1471, 632, 1474, 631, + 1473, 632, 1475, 631, 1473, 632, 1475, 634, 1479, + 634, 1480, 637, 1486, 636, 1485, 639, 1491, 641, + 1496, 640, 1493, 643, 1501, 645, 1505, 647, 1510, + 648, 1513, 650, 1516, 650, 1516, 653, 1523, 662, + 1546, 655, 1528, 657, 1533, 660, 1539, 658, 1536, + 659, 1538, 664, 1549, 653, 1523}, + {892, 2082, 636, 1484, 632, 1474, 629, 1468, 634, + 1480, 625, 1459, 623, 1453, 622, 1452, 623, 1453, + 622, 1451, 623, 1453, 622, 1451, 622, 1452, 624, + 1457, 623, 1453, 625, 1459, 626, 1461, 628, 1465, + 629, 1467, 629, 1468, 629, 1467, 631, 1473, 633, + 1476, 636, 1485, 634, 1479, 637, 1485, 635, 1483, + 637, 1486, 652, 1520, 918, 2143}, + } +}; + +const int16_t baseline_cap_data_old[2][TX_NUMBER][RX_NUMBER*2] = +{ + /*enable cbc*/ + { + {557, 1035, 604, 1122, 605, 1123, 604, 1122, 608, 1130, 601, 1117, 608, 1130, 615, 1141, 613, 1139, 614, 1140, 610, 1132, 609, 1131, 620, 1151, 625, 1161, 638, 1184, 641, 1191, 648, 1203, 669, 1243, 661, 1227, 671, 1245, 676, 1256, 685, 1273, 690, 1282, 694, 1288, 689, 1279, 696, 1292, 696, 1292, 724, 1344, 682, 1266, 724, 1344}, + {574, 1066, 622, 1154, 622, 1156, 620, 1151, 624, 1158, 618, 1148, 625, 1161, 631, 1173, 630, 1170, 630, 1170, 627, 1164, 624, 1160, 636, 1180, 641, 1191, 653, 1213, 656, 1218, 662, 1230, 676, 1255, 676, 1255, 687, 1275, 694, 1288, 703, 1305, 707, 1313, 721, 1339, 706, 1310, 711, 1321, 711, 1321, 734, 1364, 671, 1245, 694, 1288}, + {573, 1065, 619, 1149, 618, 1148, 617, 1147, 620, 1152, 614, 1140, 622, 1154, 628, 1166, 629, 1167, 628, 1166, 623, 1157, 622, 1154, 633, 1175, 638, 1186, 661, 1227, 653, 1213, 660, 1226, 673, 1249, 673, 1249, 684, 1270, 690, 1282, 701, 1301, 704, 1307, 707, 1313, 701, 1303, 707, 1313, 707, 1313, 729, 1355, 666, 1238, 687, 1277}, + {573, 1063, 616, 1144, 616, 1144, 614, 1140, 618, 1148, 611, 1135, 619, 1149, 624, 1160, 625, 1161, 625, 1161, 622, 1154, 620, 1152, 630, 1170, 637, 1183, 650, 1206, 652, 1210, 659, 1223, 670, 1244, 671, 1247, 683, 1268, 688, 1278, 706, 1312, 701, 1301, 704, 1308, 699, 1297, 704, 1308, 703, 1305, 724, 1344, 659, 1223, 673, 1249}, + {573, 1063, 615, 1141, 615, 1141, 613, 1138, 616, 1144, 610, 1132, 618, 1148, 624, 1158, 624, 1158, 624, 1160, 622, 1154, 620, 1151, 630, 1170, 636, 1182, 648, 1204, 651, 1209, 659, 1223, 670, 1244, 671, 1245, 680, 1264, 696, 1292, 694, 1290, 699, 1297, 701, 1303, 696, 1292, 701, 1301, 699, 1297, 718, 1333, 649, 1205, 663, 1231}, + {574, 1066, 615, 1143, 615, 1143, 613, 1139, 616, 1144, 610, 1134, 617, 1147, 624, 1158, 625, 1161, 625, 1161, 622, 1156, 622, 1154, 631, 1173, 646, 1200, 650, 1206, 651, 1209, 659, 1223, 671, 1247, 671, 1245, 681, 1265, 687, 1275, 694, 1288, 697, 1295, 699, 1297, 694, 1288, 699, 1297, 697, 1295, 713, 1325, 645, 1199, 658, 1222}, + {578, 1073, 617, 1147, 616, 1144, 615, 1141, 618, 1148, 611, 1135, 619, 1149, 625, 1161, 636, 1180, 628, 1166, 624, 1158, 624, 1158, 634, 1177, 638, 1186, 651, 1209, 652, 1212, 660, 1226, 673, 1249, 673, 1249, 681, 1265, 687, 1275, 694, 1288, 697, 1295, 699, 1299, 694, 1290, 699, 1297, 697, 1294, 713, 1323, 643, 1193, 654, 1214}, + {582, 1080, 619, 1149, 619, 1149, 616, 1144, 619, 1149, 613, 1139, 620, 1152, 627, 1165, 628, 1166, 629, 1167, 625, 1161, 624, 1160, 636, 1180, 641, 1191, 652, 1212, 655, 1216, 661, 1227, 673, 1251, 673, 1251, 692, 1284, 687, 1275, 693, 1287, 697, 1294, 699, 1299, 694, 1288, 699, 1297, 698, 1296, 713, 1325, 645, 1197, 655, 1216}, + {583, 1083, 619, 1149, 618, 1148, 615, 1143, 620, 1151, 613, 1138, 620, 1152, 627, 1164, 627, 1165, 638, 1184, 624, 1160, 624, 1158, 634, 1178, 638, 1186, 652, 1210, 653, 1213, 660, 1226, 671, 1245, 671, 1245, 679, 1261, 683, 1269, 690, 1282, 694, 1288, 696, 1292, 690, 1281, 694, 1290, 693, 1287, 707, 1313, 649, 1205, 655, 1217}, + {589, 1095, 623, 1157, 622, 1156, 619, 1149, 623, 1157, 616, 1144, 624, 1158, 630, 1170, 631, 1173, 631, 1173, 629, 1167, 627, 1165, 638, 1186, 643, 1193, 655, 1216, 666, 1236, 662, 1230, 673, 1251, 673, 1249, 680, 1264, 684, 1270, 692, 1284, 697, 1294, 697, 1295, 692, 1286, 697, 1295, 696, 1292, 707, 1313, 650, 1206, 655, 1216}, + {594, 1104, 628, 1166, 624, 1160, 622, 1156, 627, 1164, 618, 1148, 627, 1164, 632, 1174, 634, 1177, 634, 1178, 630, 1170, 629, 1169, 641, 1190, 644, 1196, 656, 1218, 659, 1223, 664, 1234, 675, 1253, 673, 1251, 681, 1265, 685, 1271, 693, 1287, 694, 1290, 697, 1295, 693, 1287, 699, 1299, 708, 1316, 710, 1318, 649, 1205, 652, 1210}, + {597, 1109, 629, 1169, 628, 1166, 624, 1160, 628, 1166, 620, 1152, 627, 1165, 633, 1175, 634, 1178, 634, 1178, 641, 1191, 631, 1173, 641, 1191, 646, 1200, 659, 1223, 661, 1227, 666, 1236, 676, 1255, 676, 1256, 681, 1265, 685, 1273, 692, 1286, 713, 1325, 699, 1297, 694, 1288, 701, 1301, 701, 1301, 708, 1316, 646, 1200, 649, 1205}, + {601, 1115, 630, 1170, 629, 1167, 625, 1161, 628, 1166, 620, 1151, 628, 1166, 633, 1175, 634, 1178, 636, 1180, 631, 1173, 630, 1170, 641, 1191, 646, 1200, 659, 1225, 660, 1226, 674, 1252, 676, 1255, 673, 1251, 680, 1264, 685, 1271, 692, 1286, 694, 1290, 698, 1296, 693, 1287, 699, 1299, 702, 1304, 713, 1323, 645, 1199, 647, 1201}, + {606, 1125, 632, 1174, 629, 1169, 627, 1164, 629, 1169, 622, 1154, 629, 1167, 634, 1178, 634, 1178, 637, 1183, 633, 1175, 630, 1170, 642, 1192, 647, 1201, 659, 1223, 660, 1226, 666, 1236, 676, 1255, 673, 1251, 681, 1265, 685, 1271, 693, 1287, 697, 1294, 701, 1301, 704, 1308, 702, 1304, 706, 1310, 718, 1334, 638, 1184, 641, 1190}, + {613, 1138, 634, 1177, 631, 1173, 630, 1170, 632, 1174, 624, 1158, 633, 1175, 637, 1183, 638, 1186, 641, 1190, 636, 1180, 637, 1183, 645, 1199, 651, 1209, 662, 1229, 664, 1232, 670, 1244, 680, 1262, 680, 1262, 688, 1278, 692, 1284, 699, 1297, 704, 1307, 707, 1313, 704, 1307, 712, 1322, 715, 1329, 743, 1379, 643, 1193, 644, 1196}, + {629, 1169, 639, 1187, 634, 1178, 629, 1169, 629, 1169, 620, 1152, 627, 1165, 641, 1191, 630, 1170, 633, 1175, 627, 1165, 624, 1160, 634, 1178, 639, 1187, 656, 1218, 652, 1210, 657, 1221, 667, 1239, 678, 1258, 673, 1251, 678, 1258, 685, 1271, 706, 1310, 692, 1284, 689, 1279, 697, 1294, 701, 1301, 727, 1349, 643, 1193, 644, 1196}, + {757, 1407, 748, 1388, 705, 1309, 698, 1296, 686, 1274, 678, 1260, 685, 1271, 683, 1269, 661, 1227, 671, 1245, 655, 1217, 669, 1242, 659, 1223, 665, 1235, 665, 1235, 661, 1227, 649, 1205, 646, 1200, 641, 1191, 649, 1205, 664, 1232, 629, 1167, 645, 1199, 629, 1167, 645, 1199, 622, 1154, 629, 1167, 629, 1167, 500, 3000, 500, 3000}, + }, + //disable cbc + { + {557, 1035, 604, 1122, 605, 1123, 604, 1122, 608, 1130, 601, 1117, 608, 1130, 615, 1141, 613, 1139, 614, 1140, 610, 1132, 609, 1131, 620, 1151, 625, 1161, 638, 1184, 641, 1191, 648, 1203, 669, 1243, 661, 1227, 671, 1245, 676, 1256, 685, 1273, 690, 1282, 694, 1288, 689, 1279, 696, 1292, 696, 1292, 724, 1344, 682, 1266, 724, 1344}, + {574, 1066, 622, 1154, 622, 1156, 620, 1151, 624, 1158, 618, 1148, 625, 1161, 631, 1173, 630, 1170, 630, 1170, 627, 1164, 624, 1160, 636, 1180, 641, 1191, 653, 1213, 656, 1218, 662, 1230, 676, 1255, 676, 1255, 687, 1275, 694, 1288, 703, 1305, 707, 1313, 721, 1339, 706, 1310, 711, 1321, 711, 1321, 734, 1364, 671, 1245, 694, 1288}, + {573, 1065, 619, 1149, 618, 1148, 617, 1147, 620, 1152, 614, 1140, 622, 1154, 628, 1166, 629, 1167, 628, 1166, 623, 1157, 622, 1154, 633, 1175, 638, 1186, 661, 1227, 653, 1213, 660, 1226, 673, 1249, 673, 1249, 684, 1270, 690, 1282, 701, 1301, 704, 1307, 707, 1313, 701, 1303, 707, 1313, 707, 1313, 729, 1355, 666, 1238, 687, 1277}, + {573, 1063, 616, 1144, 616, 1144, 614, 1140, 618, 1148, 611, 1135, 619, 1149, 624, 1160, 625, 1161, 625, 1161, 622, 1154, 620, 1152, 630, 1170, 637, 1183, 650, 1206, 652, 1210, 659, 1223, 670, 1244, 671, 1247, 683, 1268, 688, 1278, 706, 1312, 701, 1301, 704, 1308, 699, 1297, 704, 1308, 703, 1305, 724, 1344, 659, 1223, 673, 1249}, + {573, 1063, 615, 1141, 615, 1141, 613, 1138, 616, 1144, 610, 1132, 618, 1148, 624, 1158, 624, 1158, 624, 1160, 622, 1154, 620, 1151, 630, 1170, 636, 1182, 648, 1204, 651, 1209, 659, 1223, 670, 1244, 671, 1245, 680, 1264, 696, 1292, 694, 1290, 699, 1297, 701, 1303, 696, 1292, 701, 1301, 699, 1297, 718, 1333, 649, 1205, 663, 1231}, + {574, 1066, 615, 1143, 615, 1143, 613, 1139, 616, 1144, 610, 1134, 617, 1147, 624, 1158, 625, 1161, 625, 1161, 622, 1156, 622, 1154, 631, 1173, 646, 1200, 650, 1206, 651, 1209, 659, 1223, 671, 1247, 671, 1245, 681, 1265, 687, 1275, 694, 1288, 697, 1295, 699, 1297, 694, 1288, 699, 1297, 697, 1295, 713, 1325, 645, 1199, 658, 1222}, + {578, 1073, 617, 1147, 616, 1144, 615, 1141, 618, 1148, 611, 1135, 619, 1149, 625, 1161, 636, 1180, 628, 1166, 624, 1158, 624, 1158, 634, 1177, 638, 1186, 651, 1209, 652, 1212, 660, 1226, 673, 1249, 673, 1249, 681, 1265, 687, 1275, 694, 1288, 697, 1295, 699, 1299, 694, 1290, 699, 1297, 697, 1294, 713, 1323, 643, 1193, 654, 1214}, + {582, 1080, 619, 1149, 619, 1149, 616, 1144, 619, 1149, 613, 1139, 620, 1152, 627, 1165, 628, 1166, 629, 1167, 625, 1161, 624, 1160, 636, 1180, 641, 1191, 652, 1212, 655, 1216, 661, 1227, 673, 1251, 673, 1251, 692, 1284, 687, 1275, 693, 1287, 697, 1294, 699, 1299, 694, 1288, 699, 1297, 698, 1296, 713, 1325, 645, 1197, 655, 1216}, + {583, 1083, 619, 1149, 618, 1148, 615, 1143, 620, 1151, 613, 1138, 620, 1152, 627, 1164, 627, 1165, 638, 1184, 624, 1160, 624, 1158, 634, 1178, 638, 1186, 652, 1210, 653, 1213, 660, 1226, 671, 1245, 671, 1245, 679, 1261, 683, 1269, 690, 1282, 694, 1288, 696, 1292, 690, 1281, 694, 1290, 693, 1287, 707, 1313, 649, 1205, 655, 1217}, + {589, 1095, 623, 1157, 622, 1156, 619, 1149, 623, 1157, 616, 1144, 624, 1158, 630, 1170, 631, 1173, 631, 1173, 629, 1167, 627, 1165, 638, 1186, 643, 1193, 655, 1216, 666, 1236, 662, 1230, 673, 1251, 673, 1249, 680, 1264, 684, 1270, 692, 1284, 697, 1294, 697, 1295, 692, 1286, 697, 1295, 696, 1292, 707, 1313, 650, 1206, 655, 1216}, + {594, 1104, 628, 1166, 624, 1160, 622, 1156, 627, 1164, 618, 1148, 627, 1164, 632, 1174, 634, 1177, 634, 1178, 630, 1170, 629, 1169, 641, 1190, 644, 1196, 656, 1218, 659, 1223, 664, 1234, 675, 1253, 673, 1251, 681, 1265, 685, 1271, 693, 1287, 694, 1290, 697, 1295, 693, 1287, 699, 1299, 708, 1316, 710, 1318, 649, 1205, 652, 1210}, + {597, 1109, 629, 1169, 628, 1166, 624, 1160, 628, 1166, 620, 1152, 627, 1165, 633, 1175, 634, 1178, 634, 1178, 641, 1191, 631, 1173, 641, 1191, 646, 1200, 659, 1223, 661, 1227, 666, 1236, 676, 1255, 676, 1256, 681, 1265, 685, 1273, 692, 1286, 713, 1325, 699, 1297, 694, 1288, 701, 1301, 701, 1301, 708, 1316, 646, 1200, 649, 1205}, + {601, 1115, 630, 1170, 629, 1167, 625, 1161, 628, 1166, 620, 1151, 628, 1166, 633, 1175, 634, 1178, 636, 1180, 631, 1173, 630, 1170, 641, 1191, 646, 1200, 659, 1225, 660, 1226, 674, 1252, 676, 1255, 673, 1251, 680, 1264, 685, 1271, 692, 1286, 694, 1290, 698, 1296, 693, 1287, 699, 1299, 702, 1304, 713, 1323, 645, 1199, 647, 1201}, + {606, 1125, 632, 1174, 629, 1169, 627, 1164, 629, 1169, 622, 1154, 629, 1167, 634, 1178, 634, 1178, 637, 1183, 633, 1175, 630, 1170, 642, 1192, 647, 1201, 659, 1223, 660, 1226, 666, 1236, 676, 1255, 673, 1251, 681, 1265, 685, 1271, 693, 1287, 697, 1294, 701, 1301, 704, 1308, 702, 1304, 706, 1310, 718, 1334, 638, 1184, 641, 1190}, + {613, 1138, 634, 1177, 631, 1173, 630, 1170, 632, 1174, 624, 1158, 633, 1175, 637, 1183, 638, 1186, 641, 1190, 636, 1180, 637, 1183, 645, 1199, 651, 1209, 662, 1229, 664, 1232, 670, 1244, 680, 1262, 680, 1262, 688, 1278, 692, 1284, 699, 1297, 704, 1307, 707, 1313, 704, 1307, 712, 1322, 715, 1329, 743, 1379, 643, 1193, 644, 1196}, + {629, 1169, 639, 1187, 634, 1178, 629, 1169, 629, 1169, 620, 1152, 627, 1165, 641, 1191, 630, 1170, 633, 1175, 627, 1165, 624, 1160, 634, 1178, 639, 1187, 656, 1218, 652, 1210, 657, 1221, 667, 1239, 678, 1258, 673, 1251, 678, 1258, 685, 1271, 706, 1310, 692, 1284, 689, 1279, 697, 1294, 701, 1301, 727, 1349, 643, 1193, 644, 1196}, + {757, 1407, 748, 1388, 705, 1309, 698, 1296, 686, 1274, 678, 1260, 685, 1271, 683, 1269, 661, 1227, 671, 1245, 655, 1217, 669, 1242, 659, 1223, 665, 1235, 665, 1235, 661, 1227, 649, 1205, 646, 1200, 641, 1191, 649, 1205, 664, 1232, 629, 1167, 645, 1199, 629, 1167, 645, 1199, 622, 1154, 629, 1167, 629, 1167, 500, 3000, 500, 3000}, + } + +}; + +#endif diff --git a/drivers/input/touchscreen/synaptics_driver_s3320.c b/drivers/input/touchscreen/synaptics_driver_s3320.c new file mode 100644 index 000000000000..f927252a5fdd --- /dev/null +++ b/drivers/input/touchscreen/synaptics_driver_s3320.c @@ -0,0 +1,6466 @@ +/************************************************************************************ + ** File: - /android/kernel/drivers/input/touchscreen/synaptic_s3320.c + ** Copyright (C), 2008-2012, OEM Mobile Comm Corp., Ltd + ** + ** Description: + ** touch panel driver for synaptics + ** can change MAX_POINT_NUM value to support multipoint + ** Version: 1.0 + ** Date created: 10:49:46,18/01/2012 + ** Author: Yixue.Ge@BasicDrv.TP + ** + ** --------------------------- Revision History: -------------------------------- + ** + ** morgan.gu@BSP.TP modified for oem 2017-10-30 s3706 tp_driver + ************************************************************************************/ +#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 + +/*modify by morgan.gu for sdm845 */ +#define CONFIG_MSM_RDM_NOTIFY +#undef CONFIG_FB + +#ifdef CONFIG_FB +#include +#include +#elif defined(CONFIG_MSM_RDM_NOTIFY) +#include +#include +#endif + +#include + +#include "synaptics_redremote.h" +#include +#include "synaptics_baseline.h" +#include "synaptics_dsx_core.h" +#include +#include +/*------------------------------------------------Global Define--------------------------------------------*/ + +#define TP_UNKNOWN 0 +#define TP_G2Y 1 +#define TP_TPK 2 +#define TP_TRULY 3 +#define TP_OFILM 4 +#define TP_JDI_TPK 6 +#define TP_TEST_ENABLE 1 + +#define DiagonalUpperLimit 1100 +#define DiagonalLowerLimit 900 + +#define PAGESIZE 512 +#define TPD_USE_EINT + +#define TPD_DEVICE "synaptics,s3320" + +//#define SUPPORT_SLEEP_POWEROFF +#define SUPPORT_GESTURE +#define RESET_ONESECOND +//#define SUPPORT_GLOVES_MODE +//#define REPORT_2D_PRESSURE +//#define SUPPORT_VIRTUAL_KEY + + +#define SUPPORT_TP_SLEEP_MODE +#define TYPE_B_PROTOCOL //Multi-finger operation +#define TP_FW_NAME_MAX_LEN 128 +#define SUPPORT_TP_TOUCHKEY + +#define TEST_MAGIC1 0x494D494C +#define TEST_MAGIC2 0x474D4954 + +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 fp_underscreen_info { + uint8_t touch_state; + uint8_t area_rate; + uint16_t x; + uint16_t y; +}; + +#define PM_QOS_VALUE_TP 400 +struct pm_qos_request pm_qos_req_tp; + +/******************for Red function*****************/ +#define CONFIG_SYNAPTIC_RED + +/*********************for gesture*******************/ +#ifdef SUPPORT_GESTURE +#define ENABLE_UNICODE 0x40 +#define ENABLE_VEE 0x20 +#define ENABLE_CIRCLE 0x08 +#define ENABLE_SWIPE 0x02 +#define ENABLE_DTAP 0x01 + +#define UNICODE_DETECT 0x0b +#define VEE_DETECT 0x0a +#define CIRCLE_DETECT 0x08 +#define SWIPE_DETECT 0x07 +#define DTAP_DETECT 0x03 + +#define FINGER_DOWN 0x0f +#define FINGER_UP 0x1f +#define SINGLE_TAP 0x10 + +#define UnkownGestrue 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 Sgestrue 14 // S +#define SingleTap 15 // single tap + +//ruanbanmao@BSP add for tp gesture 2015-05-06, begin +#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) + +int LeftVee_gesture = 0; //">" +int RightVee_gesture = 0; //"<" +int DouSwip_gesture = 0; // "||" +int Circle_gesture = 0; // "O" +int UpVee_gesture = 0; //"V" +int DownVee_gesture = 0; //"^" +int DouTap_gesture = 0; //"double tap" + +int Left2RightSwip_gesture=0;//"(-->)" +int Right2LeftSwip_gesture=0;//"(<--)" +int Up2DownSwip_gesture =0;//"up to down |" +int Down2UpSwip_gesture =0;//"down to up |" + +int Wgestrue_gesture =0;//"(W)" +int Mgestrue_gesture =0;//"(M)" +int Sgestrue_gesture =0;//"(S)" +int Single_gesture = 0; //"(SingleTap)" +int Enable_gesture =0; +static int gesture_switch = 0; +//ruanbanmao@BSP add for tp gesture 2015-05-06, end +#endif + +/*********************for Debug LOG switch*******************/ +#define TPD_ERR(a, arg...) pr_err(TPD_DEVICE ": " a, ##arg) +#define TPDTM_DMESG(a, arg...) printk(TPD_DEVICE ": " a, ##arg) + +#define TPD_DEBUG(a,arg...)\ + do{\ + if(tp_debug)\ + pr_err(TPD_DEVICE ": " a,##arg);\ + }while(0) + +/*---------------------------------------------Global Variable----------------------------------------------*/ +static int baseline_ret = 0; +static long int TP_FW; +static int tp_dev = 6; +unsigned int tp_debug; +static int button_map[3]; +static int tx_rx_num[2]; +static int16_t Rxdata[33][33];/*s3706 tx rx 16 33 s3508 tx rx 15 30*/ +static int16_t delta_baseline[33][33]; +static int16_t baseline[33][33]; +static int16_t delta[33][33]; +static int TX_NUM; +static int RX_NUM; +static int report_key_point_y = 0; +static int force_update = 0; +static int LCD_WIDTH ; +static int LCD_HEIGHT ; +static int get_tp_base = 0; +#define ENABLE_TPEDGE_LIMIT +#ifdef ENABLE_TPEDGE_LIMIT +static int F51_GRIP_CONFIGURATION; +static int limit_enable=1; +static void synaptics_tpedge_limitfunc(void); +#endif +//static int ch_getbase_status = 0; +struct timeval tpstart, tpend; +int not_getbase; +int need_reset; +int singer_touch_mun; +int recored_pointx[2] = {0, 0}; +int recored_pointy[2] = {0, 0}; + +#ifdef SUPPORT_TP_SLEEP_MODE +static int sleep_enable; +#endif +#ifdef SUPPORT_TP_TOUCHKEY +static int key_switch = 0; +static bool key_back_disable=false,key_appselect_disable=false; +#endif +static struct synaptics_ts_data *ts_g = NULL; +static struct workqueue_struct *synaptics_wq = NULL; +static struct workqueue_struct *synaptics_report = NULL; +static struct workqueue_struct *get_base_report = NULL; +static struct proc_dir_entry *prEntry_tp = NULL; + + +#ifdef SUPPORT_GESTURE +static uint32_t clockwise; +static uint32_t gesture; + +/****point position*****/ +struct Coordinate { + uint32_t x; + uint32_t y; +}; +static struct Coordinate Point_start; +static struct Coordinate Point_end; +static struct Coordinate Point_1st; +static struct Coordinate Point_2nd; +static struct Coordinate Point_3rd; +static struct Coordinate Point_4th; +#endif + +/*-----------------------------------------Global Registers----------------------------------------------*/ +static unsigned short SynaF34DataBase; +static unsigned short SynaF34QueryBase; +static unsigned short SynaF01DataBase; +static unsigned short SynaF01CommandBase; + +static unsigned short SynaF34Reflash_BlockNum; +static unsigned short SynaF34Reflash_BlockData; +static unsigned short SynaF34ReflashQuery_BootID; +static unsigned short SynaF34ReflashQuery_FlashPropertyQuery; +static unsigned short SynaF34ReflashQuery_FirmwareBlockSize; +static unsigned short SynaF34ReflashQuery_FirmwareBlockCount; +static unsigned short SynaF34ReflashQuery_ConfigBlockSize; +static unsigned short SynaF34ReflashQuery_ConfigBlockCount; + +static unsigned short SynaFirmwareBlockSize; +static unsigned short SynaF34_FlashControl; + +static int F01_RMI_QUERY_BASE; +static int F01_RMI_CMD_BASE; +static int F01_RMI_CTRL_BASE; +static int F01_RMI_DATA_BASE; + +static int F12_2D_QUERY_BASE; +static int F12_2D_CMD_BASE; +static int F12_2D_CTRL_BASE; +static int F12_2D_DATA_BASE; +static int F12_2D_DATA15; + +static int F34_FLASH_QUERY_BASE; +static int F34_FLASH_CMD_BASE; +static int F34_FLASH_CTRL_BASE; +static int F34_FLASH_DATA_BASE; + +static int F51_CUSTOM_QUERY_BASE; +static int F51_CUSTOM_CMD_BASE; +static int F51_CUSTOM_CTRL_BASE; +static int F51_CUSTOM_DATA_BASE; + +static int F01_RMI_QUERY11; +static int F01_RMI_DATA01; +static int F01_RMI_CMD00; +static int F01_RMI_CTRL00; +static int F01_RMI_CTRL01; +static int F01_RMI_CTRL02; + +static int F12_2D_CTRL08; +static int F12_2D_CTRL32; +static int F12_2D_DATA04; +static int F12_2D_DATA38; +static int F12_2D_DATA39; +static int F12_2D_CMD00; +static int F12_2D_CTRL20; +static int F12_2D_CTRL27; + +static int F34_FLASH_CTRL00; + +static int F51_CUSTOM_CTRL00; +static int F51_CUSTOM_DATA04; +static int F51_CUSTOM_DATA11; +static int version_is_s3508=0; +#if TP_TEST_ENABLE +static int F54_ANALOG_QUERY_BASE;//0x73 +static int F54_ANALOG_COMMAND_BASE;//0x72 +static int F54_ANALOG_CONTROL_BASE;//0x0d +static int F54_ANALOG_DATA_BASE;//0x00 +#endif + +/*------------------------------------------Fuction Declare----------------------------------------------*/ +static int synaptics_i2c_suspend(struct device *dev); +static int synaptics_i2c_resume(struct device *dev); +/**************I2C resume && suspend end*********/ +static void speedup_synaptics_resume(struct work_struct *work); +static int synaptics_ts_resume(struct device *dev); +static int synaptics_ts_suspend(struct device *dev); +static int synaptics_ts_remove(struct i2c_client *client); +static int synaptics_ts_probe(struct i2c_client *client, const struct i2c_device_id *id); +static ssize_t synaptics_rmi4_baseline_show(struct device *dev, char *buf, bool savefile) ; +static ssize_t synaptics_rmi4_vendor_id_show(struct device *dev, struct device_attribute *attr, char *buf); +static int synapitcs_ts_update(struct i2c_client *client, const uint8_t *data, uint32_t data_len ,bool force); + +static int synaptics_rmi4_i2c_read_byte(struct i2c_client* client, + unsigned char addr); + +static int synaptics_rmi4_i2c_write_byte(struct i2c_client* client, + unsigned char addr,unsigned char data); + +static int synaptics_rmi4_i2c_read_word(struct i2c_client* client, + unsigned char addr); + +static int synaptics_rmi4_i2c_write_word(struct i2c_client* client, + unsigned char addr,unsigned short data); +static int synaptics_mode_change(int mode); +int tp_single_tap_en(struct synaptics_ts_data *ts, bool enable); +int opticalfp_irq_handler(struct fp_underscreen_info* tp_info); +int gf_opticalfp_irq_handler(int event); + +#ifdef TPD_USE_EINT +static irqreturn_t synaptics_irq_thread_fn(int irq, void *dev_id); +#endif + +#if defined(CONFIG_FB) +static int fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data); +#elif defined(CONFIG_MSM_RDM_NOTIFY) +static int msm_drm_notifier_callback( + struct notifier_block *self, unsigned long event, void *data); +#endif +static int synaptics_soft_reset(struct synaptics_ts_data *ts); +static void synaptics_hard_reset(struct synaptics_ts_data *ts); +static int set_changer_bit(struct synaptics_ts_data *ts); +static int tp_baseline_get(struct synaptics_ts_data *ts,bool flag); +static void set_doze_time(int doze_time); +static int synaptics_soft_reset(struct synaptics_ts_data *ts); +static int touch_hold_en(struct synaptics_ts_data *ts, bool enable); + + +/*-------------------------------Using Struct----------------------------------*/ +struct point_info { + unsigned char status; + int x; + int raw_x; + int y; + int raw_y; + int z; +#ifdef REPORT_2D_PRESSURE + unsigned char pressure; +#endif +}; + +static const struct i2c_device_id synaptics_ts_id[] = { + { TPD_DEVICE, 0 }, + { } +}; + +static struct of_device_id synaptics_match_table[] = { + { .compatible = TPD_DEVICE,}, + { }, +}; + +static const struct dev_pm_ops synaptic_pm_ops = { +#ifdef CONFIG_PM + .suspend = synaptics_i2c_suspend, + .resume = synaptics_i2c_resume, +#else + .suspend = NULL, + .resume = NULL, +#endif +}; + +//add by jiachenghui for boot time optimize 2015-5-13 +static int probe_ret; +struct synaptics_optimize_data{ + struct delayed_work work; + struct workqueue_struct *workqueue; + struct i2c_client *client; + const struct i2c_device_id *dev_id; +}; +static struct synaptics_optimize_data optimize_data; +static void synaptics_ts_probe_func(struct work_struct *w) +{ + struct i2c_client *client_optimize = optimize_data.client; + const struct i2c_device_id *dev_id = optimize_data.dev_id; + TPD_ERR("after on cpu [%d]\n",smp_processor_id()); + probe_ret = synaptics_ts_probe(client_optimize,dev_id); +} + +static int oem_synaptics_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + int i; + optimize_data.client = client; + optimize_data.dev_id = id; + optimize_data.workqueue = create_workqueue("tpd_probe_optimize"); + INIT_DELAYED_WORK(&(optimize_data.work), synaptics_ts_probe_func); + TPD_ERR("before on cpu [%d]\n",smp_processor_id()); + + //add by lifeng@bsp 2015-12-10 for only one cpu on line + for (i = 0; i < NR_CPUS; i++){ + TPD_ERR("check CPU[%d] is [%s]\n",i,cpu_is_offline(i)?"offline":"online"); + if (cpu_online(i) && (i != smp_processor_id())) + break; + } + queue_delayed_work_on(i != NR_CPUS?i:0,optimize_data.workqueue,&(optimize_data.work),msecs_to_jiffies(300)); + //end add by lifeng@bsp 2015-12-10 for only one cpu on line + + return probe_ret; +} +//end add by jiachenghui for boot time optimize 2015-5-13 + +static struct i2c_driver tpd_i2c_driver = { +//add by jiachenghui for boot time optimize 2015-5-13 + .probe = oem_synaptics_ts_probe, + .remove = synaptics_ts_remove, + .id_table = synaptics_ts_id, + .driver = { + // .owner = THIS_MODULE, + .name = TPD_DEVICE, + .of_match_table = synaptics_match_table, + .pm = &synaptic_pm_ops, + }, +}; + +struct synaptics_ts_data { + struct i2c_client *client; + struct mutex mutex; + struct mutex mutexreport; + int irq; + int irq_gpio; + atomic_t irq_enable; + int id1_gpio; + int id2_gpio; + int id3_gpio; + int reset_gpio; + int v1p8_gpio; + int support_hw_poweroff; + int support_1080x2160_tp; + int support_1080x2340_tp; + int enable2v8_gpio; + int max_num; + int enable_remote; + int regulator_vdd_vmin; + int regulator_vdd_vmax; + int regulator_vdd_current; + int regulator_avdd_vmin; + int regulator_avdd_vmax; + int regulator_avdd_current; + struct wakeup_source source; + + uint32_t irq_flags; + uint32_t max_x; + uint32_t max_y; + uint32_t max_y_real; + uint32_t btn_state; + uint32_t pre_finger_state; + uint32_t pre_btn_state; + struct delayed_work base_work; + struct work_struct report_work; + struct delayed_work speed_up_work; + struct input_dev *input_dev; + struct hrtimer timer; +#if defined(CONFIG_FB) + struct notifier_block fb_notif; +#elif defined(CONFIG_MSM_RDM_NOTIFY) + struct notifier_block msm_drm_notif; +#endif + /******gesture*******/ + int gesture_enable; + int in_gesture_mode; + int glove_enable; + int changer_connet; + int is_suspended; + atomic_t is_stop; + spinlock_t lock; + + /********test*******/ + int i2c_device_test; + + /******power*******/ + struct regulator *vdd_2v8; + struct regulator *vcc_i2c_1v8; + + /*pinctrl******/ + struct device *dev; + struct pinctrl *pinctrl; + struct pinctrl_state *pinctrl_state_active; + struct pinctrl_state *pinctrl_state_suspend; + + /*******for FW update*******/ + bool loading_fw; + bool support_ft;/*support force touch*/ + char fw_name[TP_FW_NAME_MAX_LEN]; + char test_limit_name[TP_FW_NAME_MAX_LEN]; + char fw_id[20]; + char manu_name[30]; +#ifdef SUPPORT_VIRTUAL_KEY + struct kobject *properties_kobj; +#endif + uint8_t fp_up_down; + unsigned int en_up_down; + unsigned int fp_aod_cnt; + unsigned int unlock_succes; + int project_version; +}; + +static struct device_attribute attrs_oem[] = { + // __ATTR(baseline_test, 0664, synaptics_rmi4_baseline_show, NULL), + __ATTR(vendor_id, 0664, synaptics_rmi4_vendor_id_show, NULL), +}; + +static struct synaptics_rmi4_data *rmi4_data_s3706; + +static ssize_t fp_irq_get(struct device *device, + struct device_attribute *attribute, + char *buf) +{ + struct synaptics_ts_data *ts = ts_g; + + return scnprintf(buf, PAGE_SIZE, "%i\n", ts->fp_up_down); +} +static DEVICE_ATTR(fp_irq, 0400, fp_irq_get, NULL); + + +static void touch_enable (struct synaptics_ts_data *ts) +{ + spin_lock(&ts->lock); + if(0 == atomic_read(&ts->irq_enable)) + { + if(ts->irq) + enable_irq(ts->irq); + atomic_set(&ts->irq_enable,1); + //TPD_ERR("test %%%% enable irq\n"); + } + spin_unlock(&ts->lock); +} + +static void touch_disable(struct synaptics_ts_data *ts) +{ + spin_lock(&ts->lock); + if(1 == atomic_read(&ts->irq_enable)) + { + if(ts->irq) + disable_irq_nosync(ts->irq); + atomic_set(&ts->irq_enable,0); + //TPD_ERR("test ****************** disable irq\n"); + } + spin_unlock(&ts->lock); +} + +static int tpd_hw_pwron(struct synaptics_ts_data *ts) +{ + int rc = 0; + + /***enable the 2v8 power*****/ + if (!IS_ERR(ts->vdd_2v8)) { + //regulator_set_optimum_mode(ts->vdd_2v8,100000); + rc = regulator_enable(ts->vdd_2v8); + if(rc){ + dev_err(&ts->client->dev, + "Regulator vdd enable failed rc=%d\n", rc); + //return rc; + } + } + /*add for mrogan for 3V delay 10ms ,1.8v delay 10ms*/ + usleep_range(10*1000, 10*1000); + if( ts->v1p8_gpio > 0 ) { + TPD_DEBUG("synaptics:enable the v1p8_gpio\n"); + gpio_direction_output(ts->v1p8_gpio, 1); + } + //msleep(100); + + if( ts->enable2v8_gpio > 0 ) { + TPD_DEBUG("synaptics:enable the enable2v8_gpio\n"); + gpio_direction_output(ts->enable2v8_gpio, 1); + } + /*usleep_range(10*1000, 10*1000);*/ + if (!IS_ERR(ts->vcc_i2c_1v8)) { + //regulator_set_optimum_mode(ts->vcc_i2c_1v8,100000); + rc = regulator_enable( ts->vcc_i2c_1v8 ); + if(rc) { + dev_err(&ts->client->dev, "Regulator vcc_i2c enable failed rc=%d\n", rc); + //return rc; + } + } + usleep_range(10*1000, 10*1000); + if( ts->reset_gpio > 0 ) { + gpio_direction_output(ts->reset_gpio, 1); + usleep_range(10*1000, 10*1000); + gpio_direction_output(ts->reset_gpio, 0); + usleep_range(10*1000, 10*1000); + gpio_direction_output(ts->reset_gpio, 1); + TPD_DEBUG("synaptics:enable the reset_gpio\n"); + } + return rc; +} + +static int tpd_hw_pwroff(struct synaptics_ts_data *ts) +{ + int rc = 0; + if( ts->reset_gpio > 0 ) { + TPD_DEBUG("%s set reset gpio low\n",__func__); + gpio_direction_output(ts->reset_gpio, 0); + } + + if (!IS_ERR(ts->vcc_i2c_1v8)) { + rc = regulator_disable( ts->vcc_i2c_1v8 ); + if(rc) { + dev_err(&ts->client->dev, "Regulator vcc_i2c enable failed rc=%d\n", rc); + return rc; + } + } + if( ts->v1p8_gpio > 0 ) { + TPD_DEBUG("synaptics:disable the v1p8_gpio\n"); + gpio_direction_output(ts->v1p8_gpio, 0); + } + if (!IS_ERR(ts->vdd_2v8)) { + rc = regulator_disable(ts->vdd_2v8); + if (rc) { + dev_err(&ts->client->dev, "Regulator vdd disable failed rc=%d\n", rc); + return rc; + } + } + if( ts->enable2v8_gpio > 0 ) { + TPD_DEBUG("synaptics:enable the enable2v8_gpio\n"); + gpio_direction_output(ts->enable2v8_gpio, 0); + } + return rc; +} + +static int tpd_power(struct synaptics_ts_data *ts, unsigned int on) +{ + int ret; + if(on) + ret = tpd_hw_pwron(ts); + else + ret = tpd_hw_pwroff(ts); + + return ret; +} + +static int synaptics_read_register_map(struct synaptics_ts_data *ts) +{ + uint8_t buf[4]; + int ret; + memset(buf, 0, sizeof(buf)); + ret = synaptics_rmi4_i2c_write_byte( ts->client, 0xff, 0x0 ); + if( ret < 0 ){ + TPD_ERR("synaptics_read_register_map: failed for page select\n"); + return -1; + } + ret = synaptics_rmi4_i2c_read_block(ts->client, 0xDD, 4, &(buf[0x0])); + if( ret < 0 ){ + TPD_ERR("failed for page select!\n"); + return -1; + } + + F12_2D_QUERY_BASE = buf[0]; + F12_2D_CMD_BASE = buf[1]; + F12_2D_CTRL_BASE = buf[2]; + F12_2D_DATA_BASE = buf[3]; + + TPD_ERR("F12_2D_QUERY_BASE = %x \n \ + F12_2D_CMD_BASE = %x \n\ + F12_2D_CTRL_BASE = %x \n\ + F12_2D_DATA_BASE = %x \n\ + ",F12_2D_QUERY_BASE,F12_2D_CMD_BASE,F12_2D_CTRL_BASE,F12_2D_DATA_BASE); + + + ret = synaptics_rmi4_i2c_read_block(ts->client, 0xE3, 4, &(buf[0x0])); + F01_RMI_QUERY_BASE = buf[0]; + F01_RMI_CMD_BASE = buf[1]; + F01_RMI_CTRL_BASE = buf[2]; + F01_RMI_DATA_BASE = buf[3]; + TPD_DEBUG("F01_RMI_QUERY_BASE = %x \n\ + F01_RMI_CMD_BASE = %x \n\ + F01_RMI_CTRL_BASE = %x \n\ + F01_RMI_DATA_BASE = %x \n\ + ", F01_RMI_QUERY_BASE, F01_RMI_CMD_BASE, F01_RMI_CTRL_BASE, F01_RMI_DATA_BASE); + + ret = synaptics_rmi4_i2c_read_block( ts->client, 0xE9, 4, &(buf[0x0]) ); + F34_FLASH_QUERY_BASE = buf[0]; + F34_FLASH_CMD_BASE = buf[1]; + F34_FLASH_CTRL_BASE = buf[2]; + F34_FLASH_DATA_BASE = buf[3]; + TPD_ERR("F34_FLASH_QUERY_BASE = %x \n\ + F34_FLASH_CMD_BASE = %x \n\ + F34_FLASH_CTRL_BASE = %x \n\ + F34_FLASH_DATA_BASE = %x \n\ + ", F34_FLASH_QUERY_BASE, F34_FLASH_CMD_BASE, F34_FLASH_CTRL_BASE, F34_FLASH_DATA_BASE); + + F01_RMI_QUERY11 = F01_RMI_QUERY_BASE+11; + F01_RMI_CTRL00 = F01_RMI_CTRL_BASE; + F01_RMI_CTRL01 = F01_RMI_CTRL_BASE + 1; + F01_RMI_CTRL02 = F01_RMI_CTRL_BASE + 2; + F01_RMI_CMD00 = F01_RMI_CMD_BASE; + F01_RMI_DATA01 = F01_RMI_DATA_BASE + 1; + + F12_2D_CTRL08 = F12_2D_CTRL_BASE; + F12_2D_CTRL32 = F12_2D_CTRL_BASE + 15; + F12_2D_DATA38 = F12_2D_DATA_BASE + 54; + F12_2D_DATA39 = F12_2D_DATA_BASE + 55; + F12_2D_CMD00 = F12_2D_CMD_BASE; + if (version_is_s3508 == 2)/*s3706*/ + F12_2D_CTRL20 = F12_2D_CTRL_BASE + 0x06; + else + F12_2D_CTRL20 = F12_2D_CTRL_BASE + 0x07; + F12_2D_CTRL27 = F12_2D_CTRL_BASE + 0x0c; + + + F34_FLASH_CTRL00 = F34_FLASH_CTRL_BASE; + + ret = synaptics_rmi4_i2c_write_byte(ts->client, 0xff, 0x4); + if( ret < 0 ){ + TPD_DEBUG("synaptics_read_register_map: failed for page select\n"); + return -1; + } + ret = synaptics_rmi4_i2c_read_block(ts->client, 0xE9, 4, &(buf[0x0])); + F51_CUSTOM_QUERY_BASE = buf[0]; + F51_CUSTOM_CMD_BASE = buf[1]; + F51_CUSTOM_CTRL_BASE = buf[2]; + F51_CUSTOM_DATA_BASE = buf[3]; + F51_CUSTOM_CTRL00 = F51_CUSTOM_CTRL_BASE; + F51_CUSTOM_DATA04 = F51_CUSTOM_DATA_BASE; + F51_CUSTOM_DATA11 = F51_CUSTOM_DATA_BASE; + + TPD_DEBUG("F51_CUSTOM_QUERY_BASE = %x \n\ + F51_CUSTOM_CMD_BASE = %x \n\ + F51_CUSTOM_CTRL_BASE = %x \n\ + F51_CUSTOM_DATA_BASE = %x \n\ + ", F51_CUSTOM_QUERY_BASE, F51_CUSTOM_CMD_BASE, F51_CUSTOM_CTRL_BASE, F51_CUSTOM_DATA_BASE); + +#if TP_TEST_ENABLE + ret = synaptics_rmi4_i2c_write_byte(ts->client, 0xff, 0x01); + if(ret < 0) { + TPD_ERR("synaptics_read_register_map: failed for page select\n"); + return -1; + } + ret = synaptics_rmi4_i2c_read_block(ts->client, 0xE9, 4, &(buf[0x0])); + F54_ANALOG_QUERY_BASE = buf[0]; + F54_ANALOG_COMMAND_BASE = buf[1]; + F54_ANALOG_CONTROL_BASE = buf[2]; + F54_ANALOG_DATA_BASE = buf[3]; + TPD_ERR("F54_QUERY_BASE = %x \n\ + F54_CMD_BASE = %x \n\ + F54_CTRL_BASE = %x \n\ + F54_DATA_BASE = %x \n\ + ", F54_ANALOG_QUERY_BASE, F54_ANALOG_COMMAND_BASE , F54_ANALOG_CONTROL_BASE, F54_ANALOG_DATA_BASE); +#endif + ret = synaptics_rmi4_i2c_write_byte(ts->client, 0xff, 0x00); + return 0; +} + +#ifdef SUPPORT_GESTURE +static int synaptics_enable_interrupt_for_gesture(struct synaptics_ts_data *ts, int enable) +{ + int ret; + unsigned char reportbuf[4]; + //chenggang.li@BSP.TP modified for gesture + TPD_DEBUG("%s is called\n", __func__); + ret = synaptics_rmi4_i2c_write_byte(ts->client, 0xff, 0x0); + if( ret < 0 ) { + TPD_ERR("%s: select page failed ret = %d\n", __func__, ret); + return -1; + } + ret = i2c_smbus_read_i2c_block_data( ts->client, F12_2D_CTRL20, 3, &(reportbuf[0x0]) ); + if( ret < 0 ) { + TPD_DEBUG("read reg F12_2D_CTRL20[0x%x] failed\n",F12_2D_CTRL20); + return -1; + } + + if( enable ) { + ts->in_gesture_mode = 1; + reportbuf[2] |= 0x02 ; + } else { + ts->in_gesture_mode = 0; + reportbuf[2] &= 0xfd ; + } + TPD_DEBUG("F12_2D_CTRL20:0x%x=[2]:0x%x\n", F12_2D_CTRL20, reportbuf[2]); + ret = i2c_smbus_write_i2c_block_data( ts->client, F12_2D_CTRL20, 3, &(reportbuf[0x0]) ); + if( ret < 0 ){ + TPD_ERR("%s :Failed to write report buffer\n", __func__); + return -1; + } + gesture = UnkownGestrue; + return 0; +} +#endif + +#ifdef SUPPORT_GLOVES_MODE +#define GLOVES_ADDR 0x001f //0x001D 0x001f +static int synaptics_glove_mode_enable(struct synaptics_ts_data *ts) +{ + int ret; + TPD_DEBUG("glove mode enable\n"); + /* page select = 0x4 */ + if( 1 == ts->glove_enable) { + ret = i2c_smbus_write_byte_data(ts->client, 0xff, 0x00); + if( ret < 0 ){ + TPD_DEBUG("i2c_smbus_write_byte_data failed for mode select\n"); + goto GLOVE_ENABLE_END; + } + ret = i2c_smbus_read_byte_data(ts->client, GLOVES_ADDR); + //TPDTM_DMESG("enable glove ret is %x ret|0x20 is %x\n", ret, ret|0x20); + ret = i2c_smbus_write_byte_data(ts->client, GLOVES_ADDR, ret | 0x01); + if( ret < 0 ){ + TPD_DEBUG("i2c_smbus_write_byte_data failed for mode select\n"); + goto GLOVE_ENABLE_END; + } + }else{ + ret = i2c_smbus_write_byte_data(ts->client, 0xff, 0x0); + if( ret < 0 ){ + TPD_DEBUG("i2c_smbus_write_byte_data failed for mode select\n"); + goto GLOVE_ENABLE_END; + } + ret = i2c_smbus_read_byte_data(ts->client, GLOVES_ADDR); + ret = i2c_smbus_write_byte_data(ts->client, GLOVES_ADDR, ret & 0xFE); + if( ret < 0 ){ + TPD_DEBUG("i2c_smbus_write_byte_data failed for mode select\n"); + goto GLOVE_ENABLE_END; + } + } + ret = i2c_smbus_write_byte_data(ts->client, 0xff, 0x00); + if( ret < 0 ){ + TPD_DEBUG("i2c_smbus_write_byte_data failed for page select\n"); + goto GLOVE_ENABLE_END; + } + +GLOVE_ENABLE_END: + return ret; +} +#endif + +#ifdef SUPPORT_TP_SLEEP_MODE +static int synaptics_sleep_mode_enable(struct synaptics_ts_data *ts) +{ + int ret; + /* page select = 0x0 */ + ret = i2c_smbus_write_byte_data(ts->client, 0xff, 0x00); + if( ret < 0 ){ + TPD_ERR("i2c_smbus_write_byte_data failed for page select\n"); + goto SLEEP_ENABLE_END; + } + if( 1 == sleep_enable ){ + /*0x00:enable glove mode,0x02:disable glove mode,*/ + TPDTM_DMESG("sleep mode enable\n"); + ret = synaptics_mode_change(0x01); + if( ret < 0 ){ + TPD_ERR("i2c_smbus_write_byte_data failed for mode select\n"); + goto SLEEP_ENABLE_END; + } + }else{ + TPDTM_DMESG("sleep mode disable\n"); + ret = synaptics_mode_change(0x84); + if( ret < 0 ){ + TPD_ERR("i2c_smbus_write_byte_data failed for mode select\n"); + goto SLEEP_ENABLE_END; + } + } + ret = i2c_smbus_write_byte_data(ts->client, 0xff, 0x00); + if( ret < 0 ){ + TPD_ERR("i2c_smbus_write_byte_data failed for page select\n"); + goto SLEEP_ENABLE_END; + } + +SLEEP_ENABLE_END: + return ret; +} +#endif + +static int synaptics_read_product_id(struct synaptics_ts_data *ts) +{ + uint8_t buf1[11]; + int ret ; + + memset(buf1, 0 , sizeof(buf1)); + ret = synaptics_rmi4_i2c_write_byte(ts->client, 0xff, 0x0); + if( ret < 0 ){ + TPDTM_DMESG("synaptics_read_product_id: failed for page select\n"); + return -1; + } + ret = synaptics_rmi4_i2c_read_block(ts->client, F01_RMI_QUERY11, 8, &(buf1[0x0])); + ret = synaptics_rmi4_i2c_read_block(ts->client, F01_RMI_QUERY_BASE+19, 2, &(buf1[0x8])); + if( ret < 0 ){ + TPD_ERR("synaptics_read_product_id: failed to read product info\n"); + return -1; + } + return 0; +} + +static int synaptics_init_panel(struct synaptics_ts_data *ts) +{ + int ret; + + TPD_DEBUG("%s is called!\n",__func__); + ret = i2c_smbus_write_byte_data(ts->client, 0xff, 0x0); + if( ret < 0 ){ + TPD_ERR("init_panel failed for page select\n"); + return -1; + } + /*device control: normal operation, configur=1*/ + + ret = synaptics_mode_change(0x80);//change tp to doze mode + if( ret < 0 ){ + msleep(150); + ret = synaptics_mode_change(0x80); + if( ret < 0 ){ + TPD_ERR("%s failed for mode select\n",__func__); + } + } + + return ret; +} + +static int synaptics_enable_interrupt(struct synaptics_ts_data *ts, int enable) +{ + int ret; + uint8_t abs_status_int; + + ret = synaptics_rmi4_i2c_write_byte(ts->client, 0xff, 0x0); + if( ret < 0 ) { + TPDTM_DMESG("synaptics_enable_interrupt: select page failed ret = %d\n", + ret); + return -1; + } + if( enable ) { + abs_status_int = 0x7f; + /*clear interrupt bits for previous touch*/ + ret = synaptics_rmi4_i2c_read_byte(ts->client, F01_RMI_DATA_BASE+1); + if( ret < 0 ) { + TPDTM_DMESG("synaptics_enable_interrupt :clear interrupt bits failed\n"); + return -1; + } + } else { + abs_status_int = 0x0; + } + ret = synaptics_rmi4_i2c_write_byte(ts->client, F01_RMI_CTRL00+1, abs_status_int); + if( ret < 0 ) { + TPDTM_DMESG("%s: enable or disable abs \ + interrupt failed,abs_int =%d\n", __func__, abs_status_int); + return -1; + } + ret = synaptics_rmi4_i2c_read_byte(ts->client, F01_RMI_CTRL00+1); + return 0; +} + +static void delay_qt_ms(unsigned long w_ms) +{ + unsigned long i; + unsigned long j; + for(i = 0; i < w_ms; i++) { + for (j = 0; j < 1000; j++) { + udelay(1); + } + } +} +/* +static void int_state(struct synaptics_ts_data *ts) +{ + int ret = -1; + ret = i2c_smbus_write_byte_data(ts->client, F01_RMI_CMD00, 0x01); + if(ret){ + TPD_ERR("%s:error cannot reset touch panel!\n",__func__); + return; + } + //delay_qt_ms(170); + delay_qt_ms(100); +#ifdef SUPPORT_GLOVES_MODE + synaptics_glove_mode_enable(ts); +#endif + ret = synaptics_init_panel(ts); + if( ret < 0 ){ + TPD_DEBUG("%s:error cannot change mode!\n",__func__); + return; + } + ret = synaptics_enable_interrupt(ts, 1); + if(ret){ + TPD_DEBUG("%s:error cannot enable interrupt!\n",__func__); + return; + } +} +*/ +/*Added for larger than 32 length read!*/ + +int synaptics_rmi4_i2c_read_block( + struct i2c_client *client, + unsigned char addr, + unsigned short length, + unsigned char *data) +{ + int retval; + unsigned char retry; + unsigned char buf; + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .len = 1, + .buf = &buf, + }, + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = length, + .buf = data, + }, + }; + buf = addr & 0xFF; + for( retry = 0; retry < 2; retry++ ) { + if( i2c_transfer(client->adapter, msg, 2) == 2) { + retval = length; + break; + } + msleep(20); + } + if( retry == 2 ) { + dev_err(&client->dev, + "%s: I2C read over retry limit\n", + __func__); + //rst_flag_counter = 1;//reset tp + retval = -5; + } else { + //rst_flag_counter = 0; + } + return retval; +} + +int synaptics_rmi4_i2c_write_block( + struct i2c_client *client, + unsigned char addr, + unsigned short length, + unsigned char const *data) +{ + int retval; + unsigned char retry; + unsigned char buf[length + 1]; + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .len = length + 1, + .buf = buf, + } + }; + + buf[0] = addr & 0xff; + memcpy(&buf[1], &data[0], length); + + for (retry = 0; retry < 2; retry++) { + if (i2c_transfer(client->adapter, msg, 1) == 1) { + retval = length; + break; + } + msleep(20); + } + if (retry == 2) { + //rst_flag_counter = 1;//rest tp + retval = -EIO; + } else { + //rst_flag_counter = 0; + } + return retval; +} + +static int synaptics_rmi4_i2c_read_byte(struct i2c_client* client, + unsigned char addr) +{ + int retval = 0; + unsigned char buf[2] = {0}; + retval = synaptics_rmi4_i2c_read_block(client,addr,1,buf); + if(retval >= 0) + retval = buf[0]&0xff; + return retval; +} + +static int synaptics_rmi4_i2c_write_byte(struct i2c_client* client, + unsigned char addr,unsigned char data) +{ + int retval; + unsigned char data_send = data; + retval = synaptics_rmi4_i2c_write_block(client,addr,1,&data_send); + return retval; +} + +static int synaptics_rmi4_i2c_read_word(struct i2c_client* client, + unsigned char addr) +{ + int retval; + unsigned char buf[2] = {0}; + retval = synaptics_rmi4_i2c_read_block(client,addr,2,buf); + if(retval >= 0) + retval = buf[1]<<8|buf[0]; + return retval; +} + +static int synaptics_rmi4_i2c_write_word(struct i2c_client* client, + unsigned char addr,unsigned short data) +{ + int retval; + unsigned char buf[2] = {data&0xff,(data>>8)&0xff}; + retval = synaptics_rmi4_i2c_write_block(client,addr,2,buf); + if(retval >= 0) + retval = buf[1]<<8|buf[0]; + return retval; +} + +//chenggang.li@BSP.TP modified for oem 2014-08-05 gesture_judge +/***************start****************/ +#ifdef SUPPORT_GESTURE +static void synaptics_get_coordinate_point(struct synaptics_ts_data *ts) +{ + int ret,i; + uint8_t coordinate_buf[25] = {0}; + uint16_t trspoint = 0; +/* add by lifeng 2016/1/19 workarounds for the gestrue two interrupts begin*/ + static uint8_t coordinate_buf_last[25]= {0}; +/* add by lifeng 2016/1/19 workarounds for the gestrue two interrupts end*/ + + TPD_DEBUG("%s is called!\n",__func__); + ret = synaptics_rmi4_i2c_write_byte(ts->client, 0xff, 0x4); + if (version_is_s3508 == 2) { + ret = i2c_smbus_read_i2c_block_data(ts->client, + F51_CUSTOM_DATA_BASE, + sizeof(coordinate_buf), + &(coordinate_buf[0])); + } else if (version_is_s3508 == 1 || version_is_s3508 == 0) { + ret = i2c_smbus_read_i2c_block_data(ts->client, F51_CUSTOM_DATA11, 8, &(coordinate_buf[0])); + ret = i2c_smbus_read_i2c_block_data(ts->client, F51_CUSTOM_DATA11 + 8, 8, &(coordinate_buf[8])); + ret = i2c_smbus_read_i2c_block_data(ts->client, F51_CUSTOM_DATA11 + 16, 8, &(coordinate_buf[16])); + ret = i2c_smbus_read_i2c_block_data(ts->client, F51_CUSTOM_DATA11 + 24, 1, &(coordinate_buf[24])); + } +/* add by lifeng 2016/1/19 workarounds for the gestrue two interrupts begin*/ + if (!memcmp(coordinate_buf_last, coordinate_buf, + sizeof(coordinate_buf))) { + TPD_ERR("%s reject the same gestrue[%d]\n", __func__, gesture); + gesture = UnkownGestrue; + } + memcpy(coordinate_buf_last,coordinate_buf,sizeof(coordinate_buf)); +/* strcpy(coordinate_buf_last, coordinate_buf, sizeof(coordinate_buf)); + * add by lifeng 2016/1/19 workarounds for the gestrue two interrupts end + */ + + for(i = 0; i< 23; i += 2) { + trspoint = coordinate_buf[i]|coordinate_buf[i+1] << 8; + TPD_DEBUG("synaptics TP read coordinate_point[%d] = %d\n",i,trspoint); + } + + TPD_DEBUG("synaptics TP coordinate_buf = 0x%x\n",coordinate_buf[24]); + + ret = synaptics_rmi4_i2c_write_byte(ts->client, 0xff, 0x0); + Point_start.x = (coordinate_buf[0] | (coordinate_buf[1] << 8)) * LCD_WIDTH/ (ts->max_x); + Point_start.y = (coordinate_buf[2] | (coordinate_buf[3] << 8)) * LCD_HEIGHT/ (ts->max_y); + Point_end.x = (coordinate_buf[4] | (coordinate_buf[5] << 8)) * LCD_WIDTH / (ts->max_x); + Point_end.y = (coordinate_buf[6] | (coordinate_buf[7] << 8)) * LCD_HEIGHT / (ts->max_y); + Point_1st.x = (coordinate_buf[8] | (coordinate_buf[9] << 8)) * LCD_WIDTH / (ts->max_x); + Point_1st.y = (coordinate_buf[10] | (coordinate_buf[11] << 8)) * LCD_HEIGHT / (ts->max_y); + Point_2nd.x = (coordinate_buf[12] | (coordinate_buf[13] << 8)) * LCD_WIDTH / (ts->max_x); + Point_2nd.y = (coordinate_buf[14] | (coordinate_buf[15] << 8)) * LCD_HEIGHT / (ts->max_y); + Point_3rd.x = (coordinate_buf[16] | (coordinate_buf[17] << 8)) * LCD_WIDTH / (ts->max_x); + Point_3rd.y = (coordinate_buf[18] | (coordinate_buf[19] << 8)) * LCD_HEIGHT / (ts->max_y); + Point_4th.x = (coordinate_buf[20] | (coordinate_buf[21] << 8)) * LCD_WIDTH / (ts->max_x); + Point_4th.y = (coordinate_buf[22] | (coordinate_buf[23] << 8)) * LCD_HEIGHT / (ts->max_y); + clockwise = (coordinate_buf[24] & 0x10) ? 1 : + (coordinate_buf[24] & 0x20) ? 0 : 2; // 1--clockwise, 0--anticlockwise, not circle, report 2 +} + +static int set_tp_info(struct synaptics_ts_data *ts, uint8_t up_down) +{ + int ret = 0; + uint8_t tp_infor[8] = {0}; + struct fp_underscreen_info tp_info; + + ret = synaptics_rmi4_i2c_write_byte(ts->client, 0xff, 0x4); + ret = i2c_smbus_read_i2c_block_data(ts->client, + F51_CUSTOM_DATA_BASE, + sizeof(tp_infor), + &(tp_infor[0])); + ret = synaptics_rmi4_i2c_write_byte(ts->client, 0xff, 0x00); + TPD_DEBUG("%s:tp info %d %d %d %d\n", __func__, + tp_infor[0]|tp_infor[1]<<8,tp_infor[2]|tp_infor[3]<<8, + tp_infor[4]|tp_infor[5]<<8,tp_infor[6]|tp_infor[7]<<8); + tp_info.x = tp_infor[1]<<8|tp_infor[0]; + tp_info.y = tp_infor[3]<<8|tp_infor[2]; + tp_info.area_rate = tp_infor[5]<<8|tp_infor[4]; + tp_info.touch_state = up_down; + opticalfp_irq_handler(&tp_info); + + return ret; +} + +static int recored_xy(struct synaptics_ts_data *ts, int x) +{ + int ret = 0; + uint8_t tp_info[8] = {0}; + + ret = synaptics_rmi4_i2c_write_byte(ts->client, 0xff, 0x4); + ret = i2c_smbus_read_i2c_block_data(ts->client, + F51_CUSTOM_DATA_BASE, + sizeof(tp_info), + &(tp_info[0])); + ret = synaptics_rmi4_i2c_write_byte(ts->client, 0xff, 0x00); + TPD_DEBUG("%s:recored_xy %d %d %d %d\n", __func__, + tp_info[0]|tp_info[1]<<8, tp_info[2]|tp_info[3]<<8, + tp_info[4]|tp_info[5]<<8, tp_info[6]|tp_info[7]<<8); + recored_pointx[x] = tp_info[1]<<8|tp_info[0]; + recored_pointy[x] = tp_info[3]<<8|tp_info[2]; + TPD_DEBUG("%s:recored_xy[%d] x= %d y= %d\n", __func__, + x, recored_pointx[x], recored_pointy[x]); + + return ret; +} + +static void fp_detect(struct synaptics_ts_data *ts) +{ + int ret = 0, gesture_sign; + uint8_t gesture_buffer[10]; + + ret = i2c_smbus_write_byte_data( + ts->client, 0xff, 0x00); + ret = i2c_smbus_read_i2c_block_data( + ts->client, + 0x000A, 5, + &(gesture_buffer[0])); + + gesture_sign = gesture_buffer[0]; + switch (gesture_sign) { + case FINGER_DOWN: + ts->fp_up_down = 1; + sysfs_notify(&ts->dev->kobj, NULL, + dev_attr_fp_irq.attr.name); + TPD_DEBUG("%s:FINGER_DOWN %d\n", __func__, + ts->fp_up_down); + /*update tp info*/ + set_tp_info(ts, 1); + gf_opticalfp_irq_handler(1); + need_reset = 0; + break; + case FINGER_UP: + ts->fp_up_down = 0; + sysfs_notify(&ts->dev->kobj, NULL, + dev_attr_fp_irq.attr.name); + TPD_DEBUG("%s:FINGER_UP %d\n", __func__, + ts->fp_up_down); + /*update tp info*/ + set_tp_info(ts, 0); + gf_opticalfp_irq_handler(0); + if (ts->fp_aod_cnt > 0) + need_reset = 1; + not_getbase = 0; + ts->fp_aod_cnt = 0; + break; + } + ret = i2c_smbus_write_byte_data( + ts->client, 0xff, 0x00); +} + +static int time_recored(bool start_time) +{ + int timeuse = 0; + + if (start_time) { + do_gettimeofday(&tpstart); + } else { + do_gettimeofday(&tpend); + timeuse = 1000000 * (tpend.tv_sec-tpstart.tv_sec) + + tpend.tv_usec-tpstart.tv_usec; + TPD_DEBUG("Use time: %d uSeconds!!", timeuse); + } + if ((timeuse > 600000) || (timeuse < 0)) + return 0; + + return 1; +} + +static int double_tap(struct synaptics_ts_data *ts) +{ + int time_use = 0; + int ret = 0; + + if (singer_touch_mun == 0) { + time_recored(true); + recored_xy(ts, 0); + singer_touch_mun = 1; + } else { + time_use = time_recored(false); + recored_xy(ts, 1); + singer_touch_mun = 0; + if ((abs(recored_pointx[0] - recored_pointx[1]) < 100) + && (abs(recored_pointy[0] - recored_pointy[1]) < 120) + && (time_use)) { + ret = 1; + } else { + time_recored(true); + recored_xy(ts, 0); + singer_touch_mun = 1; + ret = -1; + } + } + + return ret; +} + + +static void gesture_judge(struct synaptics_ts_data *ts) +{ + unsigned int keyCode = KEY_F4; + int ret = 0, regswipe = 0; + uint8_t gesture_buffer[10]; + uint8_t gesture_sign = 0; + unsigned char reportbuf[3]; + uint8_t regswipe_s3706[25]; + int is_double_tap = 0; + + if (version_is_s3508 == 1) + F12_2D_DATA04 = 0x0008; + else if (version_is_s3508 == 2) /*s3706*/ + F12_2D_DATA04 = 0x000A; + else + F12_2D_DATA04 = 0x000A; + TPD_DEBUG("%s start!\n",__func__); + ret = synaptics_rmi4_i2c_write_byte(ts->client, 0xff, 0x00); + if (ret < 0) { + TPDTM_DMESG("failed to transfer the data, ret = %d\n", ret); + } + ret = i2c_smbus_write_byte_data( + ts->client, 0xff, 0x00); + ret = i2c_smbus_read_i2c_block_data( + ts->client, + F12_2D_DATA04, 5, + &(gesture_buffer[0])); + ret = i2c_smbus_write_byte_data(ts->client, 0xff, 0x4); + if (version_is_s3508 == 2) { + ret = i2c_smbus_read_i2c_block_data( + ts->client, F51_CUSTOM_DATA_BASE, + sizeof(regswipe_s3706), &(regswipe_s3706[0])); + if (ret < 0) + TPDTM_DMESG("failed to transfer the data, ret = %d\n", ret); + } else if (version_is_s3508 == 1) + regswipe = i2c_smbus_read_byte_data(ts->client, + F51_CUSTOM_DATA04+0x18); + else + regswipe = i2c_smbus_read_byte_data(ts->client, + F51_CUSTOM_DATA04+0x18); + if (version_is_s3508 == 2) { + TPD_DEBUG("GestureType[0x%x]=[0x%x]\n", + F12_2D_DATA04, gesture_buffer[0]); + TPD_DEBUG("lpwgSwipeID[0x4%x] = [0x%x]\n", + F51_CUSTOM_DATA_BASE, regswipe_s3706[24]); + } else if (version_is_s3508 == 1) { + TPD_DEBUG("GestureType[0x%x]=[0x%x]\n", + F12_2D_DATA04, gesture_buffer[0]); + TPD_DEBUG("lpwgSwipeID[0x4%x] = [0x%x]\n", + (F51_CUSTOM_DATA04+0x18), regswipe); + } else + TPD_DEBUG("Gesture Type[0x%x]=[0x%x],lpwg Swipe ID[0x4%x] = [0x%x]\n",\ + F12_2D_DATA04,gesture_buffer[0],(F51_CUSTOM_DATA04+0x18),regswipe); + ret = i2c_smbus_write_byte_data(ts->client, 0xff, 0x00); + gesture_sign = gesture_buffer[0]; + + if (ts->project_version == 0x03) { + if (DouTap_gesture) { + if (gesture_sign == SINGLE_TAP) { + is_double_tap = double_tap(ts); + if (is_double_tap == 1) { + gesture_sign = DTAP_DETECT; + } + } + } + } + //detect the gesture mode + switch (gesture_sign) { + case DTAP_DETECT: + gesture = DouTap; + break; + case SWIPE_DETECT: + if (version_is_s3508 == 2) { + gesture = + (regswipe_s3706[24] == 0x41) ? Left2RightSwip : + (regswipe_s3706[24] == 0x42) ? Right2LeftSwip : + (regswipe_s3706[24] == 0x44) ? Up2DownSwip : + (regswipe_s3706[24] == 0x48) ? Down2UpSwip : + (regswipe_s3706[24] == 0x80) ? DouSwip : + UnkownGestrue; + break; + } else if (version_is_s3508 == 1) { + gesture = (regswipe == 0x41) ? Left2RightSwip : + (regswipe == 0x42) ? Right2LeftSwip : + (regswipe == 0x44) ? Up2DownSwip : + (regswipe == 0x48) ? Down2UpSwip : + (regswipe == 0x80) ? DouSwip : + UnkownGestrue; + break; + }else{ + gesture = (regswipe == 0x41) ? Left2RightSwip : + (regswipe == 0x42) ? Right2LeftSwip : + (regswipe == 0x44) ? Up2DownSwip : + (regswipe == 0x48) ? Down2UpSwip : + (regswipe == 0x84) ? DouSwip : + UnkownGestrue; + break; + } + case CIRCLE_DETECT: + gesture = Circle; + break; + case VEE_DETECT: + gesture = (gesture_buffer[2] == 0x01) ? DownVee : + (gesture_buffer[2] == 0x02) ? UpVee : + (gesture_buffer[2] == 0x04) ? RightVee : + (gesture_buffer[2] == 0x08) ? LeftVee : + UnkownGestrue; + break; + case FINGER_DOWN: + if (ts->project_version == 0x03) { + ts->fp_up_down = 1; + ts->fp_aod_cnt = 1; + sysfs_notify(&ts->dev->kobj, NULL, + dev_attr_fp_irq.attr.name); + TPD_DEBUG("%s:FINGER_DOWN %d\n", __func__, + ts->fp_up_down); + /*update tp info*/ + set_tp_info(ts, 1); + gf_opticalfp_irq_handler(1); + not_getbase = 1; + need_reset = 0; + } + gesture = UnkownGestrue; + break; + case FINGER_UP: + if (ts->project_version == 0x03) { + ts->fp_up_down = 0; + ts->fp_aod_cnt = 0; + sysfs_notify(&ts->dev->kobj, NULL, + dev_attr_fp_irq.attr.name); + TPD_DEBUG("%s:FINGER_UP %d\n", __func__, + ts->fp_up_down); + /*update tp info*/ + set_tp_info(ts, 0); + gf_opticalfp_irq_handler(0); + } + gesture = UnkownGestrue; + break; + case SINGLE_TAP: + if (ts->project_version == 0x03) { + TPD_DEBUG("%s:SINGLE TAP\n", __func__); + gesture = SingleTap; + } + break; + case UNICODE_DETECT: + gesture = (gesture_buffer[2] == 0x77) ? Wgestrue : + (gesture_buffer[2] == 0x6d) ? Mgestrue : + (gesture_buffer[2] == 0x73) ? Sgestrue : + UnkownGestrue; + break; + default: + gesture = UnkownGestrue; + break; + } + + TPD_ERR("detect %s gesture\n", gesture == DouTap ? "(double tap)" : + gesture == UpVee ? "(V)" : + gesture == DownVee ? "(^)" : + gesture == LeftVee ? "(>)" : + gesture == RightVee ? "(<)" : + gesture == Circle ? "(O)" : + gesture == DouSwip ? "(||)" : + gesture == Left2RightSwip ? "(-->)" : + gesture == Right2LeftSwip ? "(<--)" : + gesture == Up2DownSwip ? "(up to down |)" : + gesture == Down2UpSwip ? "(down to up |)" : + gesture == Mgestrue ? "(M)" : + gesture == Sgestrue ? "(S)" : + gesture == Wgestrue ? "(W)" : + gesture == SingleTap ? "(single tap)" : "[unknown]"); + if ((gesture != SingleTap) && (gesture != DouTap)) + synaptics_get_coordinate_point(ts); + + TPD_DEBUG("gesture suport LeftVee:%d RightVee:%d DouSwip:%d Circle:%d UpVee:%d DouTap:%d\n",\ + LeftVee_gesture,RightVee_gesture,DouSwip_gesture,Circle_gesture,UpVee_gesture,DouTap_gesture); + if((gesture == DouTap && DouTap_gesture)||(gesture == RightVee && RightVee_gesture)\ + ||(gesture == LeftVee && LeftVee_gesture)||(gesture == UpVee && UpVee_gesture)\ + ||(gesture == Circle && Circle_gesture)||(gesture == DouSwip && DouSwip_gesture)\ + ||(gesture == Sgestrue && Sgestrue_gesture)||(gesture == Wgestrue && Wgestrue_gesture)\ + ||(gesture == Mgestrue && Mgestrue_gesture)||(gesture == SingleTap && Single_gesture)) { + input_report_key(ts->input_dev, keyCode, 1); + input_sync(ts->input_dev); + input_report_key(ts->input_dev, keyCode, 0); + input_sync(ts->input_dev); + }else{ + + ret = i2c_smbus_read_i2c_block_data( ts->client, F12_2D_CTRL20, 3, &(reportbuf[0x0]) ); + ret = reportbuf[2] & 0x20; + if(ret == 0) + reportbuf[2] |= 0x02 ; + ret = i2c_smbus_write_i2c_block_data( ts->client, F12_2D_CTRL20, 3, &(reportbuf[0x0]) ); //enable gesture + if (ret < 0) + TPD_ERR("%s :Failed to write report buffer\n", __func__); + } + TPD_DEBUG("%s end!\n",__func__); +} +#endif +/***************end****************/ +static char prlog_count = 0; +#ifdef REPORT_2D_PRESSURE +static unsigned char pres_value = 1; +#endif +#ifdef SUPPORT_VIRTUAL_KEY //WayneChang, 2015/12/02, add for key to abs, simulate key in abs through virtual key system +//extern struct completion key_cm; +bool key_back_pressed = 0; +bool key_appselect_pressed = 0; +bool key_home_pressed =0; +extern bool virtual_key_enable; +#endif +void int_touch(void) +{ + int ret = -1,i = 0; + uint8_t buf[90]; + uint8_t count_data = 0; + uint8_t object_attention[2]; + uint16_t total_status = 0; + uint8_t finger_num = 0; + uint8_t finger_status = 0; + struct point_info points; + uint32_t finger_info = 0; + static uint8_t current_status = 0; + uint8_t last_status = 0 ; +#ifdef SUPPORT_VIRTUAL_KEY //WayneChang, 2015/12/02, add for key to abs, simulate key in abs through virtual key system + bool key_appselect_check = false; + bool key_back_check = false; + bool key_home_check = false; + bool key_pressed = key_appselect_pressed || key_back_pressed;// || key_home_pressed; +#endif + struct synaptics_ts_data *ts = ts_g; + + memset(buf, 0, sizeof(buf)); + points.x = 0; + points.y = 0; + points.z = 0; + points.status = 0; + + mutex_lock(&ts->mutexreport); +#ifdef REPORT_2D_PRESSURE + if (ts->support_ft){ + ret = i2c_smbus_write_byte_data(ts->client, 0xff, 0x4); + ret = synaptics_rmi4_i2c_read_block(ts->client, 0x19,\ + sizeof(points.pressure), &points.pressure); + if (ret < 0) { + TPD_ERR("synaptics_int_touch: i2c_transfer failed\n"); + goto INT_TOUCH_END; + } + if (0 == points.pressure)//workaround for have no pressure value input reader into hover mode + { + pres_value++; + if (255 == pres_value) + pres_value = 1; + } + else + { + pres_value = points.pressure; + } + } +#endif + ret = i2c_smbus_write_byte_data(ts->client, 0xff, 0x0); + if (version_is_s3508 == 1) + F12_2D_DATA15 = 0x0009; + else if (version_is_s3508 == 0) + F12_2D_DATA15 = 0x000C; + else if (version_is_s3508 == 2) + F12_2D_DATA15 = 0x000B;/*s3706 for 17819*/ + ret = synaptics_rmi4_i2c_read_block(ts->client, F12_2D_DATA15, 2, object_attention); + if (ret < 0) { + TPD_ERR("synaptics_int_touch F12_2D_DATA15: i2c_transfer failed\n"); + goto INT_TOUCH_END; + } + total_status = (object_attention[1] << 8) | object_attention[0]; + + if(total_status){ + while(total_status){ + count_data++; + total_status >>= 1; + } + }else{ + count_data = 0; + } + if(count_data > 10){ + TPD_ERR("count_data is: %d\n", count_data); + goto INT_TOUCH_END; + } + ret = synaptics_rmi4_i2c_read_block(ts->client, F12_2D_DATA_BASE, count_data*8+1, buf); + if (ret < 0) { + TPD_ERR("synaptics_int_touch F12_2D_DATA_BASE: i2c_transfer failed\n"); + goto INT_TOUCH_END; + } + for( i = 0; i < count_data; i++ ) { + points.status = buf[i*8]; + points.x = ((buf[i*8+2]&0x0f)<<8) | (buf[i*8+1] & 0xff); + points.raw_x = buf[i*8+6] & 0x0f; + points.y = ((buf[i*8+4]&0x0f)<<8) | (buf[i*8+3] & 0xff); + points.raw_y = buf[i*8+7] & 0x0f; + points.z = buf[i*8+5]; + finger_info <<= 1; + finger_status = points.status & 0x03; +#ifdef SUPPORT_VIRTUAL_KEY //WayneChang, 2015/12/02, add for key to abs, simulate key in abs through virtual key system + if(virtual_key_enable){ + if(points.y > 0x780 && key_pressed){ + TPD_DEBUG("Drop TP event due to key pressed\n"); + finger_status = 0; + }else{ + finger_status = points.status & 0x03; + } + }else{ + finger_status = points.status & 0x03; + } + if(virtual_key_enable){ + if (!finger_status){ + if (key_appselect_pressed && !key_appselect_check){ + points.x = 0xb4; + points.y = 0x7e2; + points.z = 0x33; + points.raw_x = 4; + points.raw_y = 6; + key_appselect_check = true; + points.status = 1; + finger_status = points.status & 0x03; + }else if (key_back_pressed && !key_back_check){ + points.x = 0x384; + points.y = 0x7e2; + points.z = 0x33; + points.raw_x = 4; + points.raw_y = 6; + key_back_check = true; + points.status = 1; + finger_status = points.status & 0x03; + }else if(key_home_pressed && !key_home_check){ + points.x = 0x21c; + points.y = 0x7e2; + points.z = 0x33; + points.raw_x = 4; + points.raw_y = 6; + key_home_check = true; + points.status = 1; + finger_status = points.status & 0x03; + }else{ + //TPD_DEBUG(" finger %d with !finger_statue and no key match\n",i); + } + } + } +#endif + if (version_is_s3508 == 0){//for 15811 panel + points.x = 1079 - points.x; + points.y = 1919 - points.y; + } + if (finger_status) { + input_mt_slot(ts->input_dev, i); + input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, finger_status); + input_report_key(ts->input_dev, BTN_TOOL_FINGER, 1); + input_report_abs(ts->input_dev, ABS_MT_POSITION_X, points.x); + input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, points.y); + //#ifdef REPORT_2D_W + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, max(points.raw_x, points.raw_y)); + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MINOR, min(points.raw_x, points.raw_y)); +#ifdef REPORT_2D_PRESSURE + if (ts->support_ft){ + input_report_abs(ts->input_dev,ABS_MT_PRESSURE,pres_value); + TPD_DEBUG("%s: pressure%d[%d]\n",__func__,i,pres_value); + } +#endif +#ifndef TYPE_B_PROTOCOL + input_mt_sync(ts->input_dev); +#endif +#ifdef SUPPORT_VIRTUAL_KEY //WayneChang, 2015/12/02, add for key to abs, simulate key in abs through virtual key system + if(virtual_key_enable){ + // complete(&key_cm); + } +#endif + finger_num++; + finger_info |= 1 ; + //TPD_DEBUG("%s: Finger %d: status = 0x%02x " + //"x = %4d, y = %4d, wx = %2d, wy = %2d\n", + //__func__, i, points.status, points.x, points.y, points.raw_x, points.raw_y); + + } + } + + finger_info <<= (ts->max_num - count_data); + + for ( i = 0; i < ts->max_num; i++ ) + { + finger_status = (finger_info>>(ts->max_num-i-1)) & 1 ; + if(!finger_status) + { + input_mt_slot(ts->input_dev, i); + input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, finger_status); + } + + } + + last_status = current_status & 0x02; + + if (finger_num == 0/* && last_status && (check_key <= 1)*/) { + if (3 == (++prlog_count % 6)) + TPD_ERR("all finger up\n"); + if (ts->project_version == 0x03) { + if ((ts->unlock_succes == 1) && (need_reset ==1) && (ts->is_suspended == 0)) { + TPD_DEBUG("touch hold reset %d\n", need_reset); + need_reset = 0; + not_getbase = 0; + ts->unlock_succes = 0; + mutex_lock(&ts->mutex); + ret = synaptics_soft_reset(ts); + if (ret < 0) + TPD_ERR("%s reset failed\n", __func__); + mutex_unlock(&ts->mutex); + } + } + 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); + + if ((finger_num == 0) && (get_tp_base == 0)){//all finger up do get base once + get_tp_base = 1; + TPD_ERR("start get base data:%d\n",get_tp_base); + if (!ts->en_up_down) + tp_baseline_get(ts, false); + } + +INT_TOUCH_END: + mutex_unlock(&ts->mutexreport); +} +static char log_count = 0; +#ifdef SUPPORT_TP_TOUCHKEY +#define OEM_KEY_BACK (key_switch?KEY_APPSELECT:KEY_BACK) +#define OEM_KEY_APPSELECT (key_switch?KEY_BACK:KEY_APPSELECT) +#else +#define OEM_KEY_BACK KEY_BACK +#define OEM_KEY_APPSELECT KEY_APPSELECT +#endif +static void int_key_report_s3508(struct synaptics_ts_data *ts) +{ + int ret= 0; + int F1A_0D_DATA00=0x00; + int button_key; + + if (ts->is_suspended == 1) + return; + + ret = synaptics_rmi4_i2c_write_byte(ts->client, 0xff, 0x02 ); + if (ret < 0) { + TPD_ERR("%s: line[%d]Failed to change page!!\n",__func__,__LINE__); + return; + } + button_key = synaptics_rmi4_i2c_read_byte(ts->client,F1A_0D_DATA00); + if (1 == (++log_count % 4)) + TPD_ERR("touch_key[0x%x],touchkey_state[0x%x]\n",button_key,ts->pre_btn_state); + if((button_key & 0x01) && !(ts->pre_btn_state & 0x01) && !key_back_disable)//back + { + input_report_key(ts->input_dev, OEM_KEY_BACK, 1); + input_sync(ts->input_dev); + }else if(!(button_key & 0x01) && (ts->pre_btn_state & 0x01) && !key_back_disable){ + input_report_key(ts->input_dev, OEM_KEY_BACK, 0); + input_sync(ts->input_dev); + } + + if((button_key & 0x02) && !(ts->pre_btn_state & 0x02) && !key_appselect_disable)//menu + { + input_report_key(ts->input_dev, OEM_KEY_APPSELECT, 1); + input_sync(ts->input_dev); + }else if(!(button_key & 0x02) && (ts->pre_btn_state & 0x02) && !key_appselect_disable){ + input_report_key(ts->input_dev, OEM_KEY_APPSELECT, 0); + input_sync(ts->input_dev); + } + + ts->pre_btn_state = button_key & 0x07; + //input_sync(ts->input_dev); + ret = synaptics_rmi4_i2c_write_byte(ts->client, 0xff, 0x00); + if (ret < 0) { + TPD_ERR("%s: line[%d]Failed to change page!!\n",__func__,__LINE__); + return; + } + return; +} + +static int synaptics_rmi4_free_fingers(struct synaptics_ts_data *ts) +{ + unsigned char i; + +#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); + + return 0; +} + +static void synaptics_ts_work_func(struct work_struct *work) +{ + int ret,status_check; + uint8_t status = 0; + uint8_t inte = 0; + + struct synaptics_ts_data *ts = ts_g; + + pm_qos_add_request(&pm_qos_req_tp, PM_QOS_CPU_DMA_LATENCY, + PM_QOS_VALUE_TP); + if (atomic_read(&ts->is_stop) == 1) + { + touch_disable(ts); + goto EXIT; + } + + if( ts->enable_remote) { + goto END; + } + ret = synaptics_rmi4_i2c_write_byte(ts->client, 0xff, 0x00 ); + ret = synaptics_rmi4_i2c_read_word(ts->client, F01_RMI_DATA_BASE); + + if( ret < 0 ) { + TPDTM_DMESG("Synaptic:ret = %d\n", ret); + synaptics_hard_reset(ts); + if (ts->is_suspended == 1 && ts->gesture_enable == 0) { + touch_disable(ts); + goto EXIT; + } + goto END; + } + status = ret & 0xff; + inte = (ret & 0x7f00)>>8; + //TPD_ERR("%s status[0x%x],inte[0x%x]\n",__func__,status,inte); + if(status & 0x80){ + TPD_DEBUG("enter reset tp status,and ts->in_gesture_mode is:%d\n",ts->in_gesture_mode); + status_check = synaptics_init_panel(ts); + if (status_check < 0) { + TPD_ERR("synaptics_init_panel failed\n"); + } + if ((ts->is_suspended == 1) && (ts->gesture_enable == 1)){ + synaptics_enable_interrupt_for_gesture(ts, 1); + if (ts->project_version == 0x03) { + mutex_lock(&ts->mutex); + tp_single_tap_en(ts, true); + if (ts->en_up_down) + touch_hold_en(ts, true); + mutex_unlock(&ts->mutex); + } + } + } +/* + if(0 != status && 1 != status) {//0:no error;1: after hard reset;the two state don't need soft reset + TPD_ERR("%s status[0x%x],inte[0x%x]\n",__func__,status,inte); + int_state(ts); + goto END; + } +*/ + if (inte == 1) { + TPD_ERR("%s: spontaneous reset detected\n", __func__); + ret = synaptics_rmi4_free_fingers(ts); + if (ret < 0) + TPD_ERR("%s: Failed to reinit device\n", __func__); + } + + if( inte & 0x04 ) { + + if (ts->project_version == 0x03) { + if (ts->en_up_down && ts->in_gesture_mode == 0) + fp_detect(ts); + } + + if (ts->is_suspended == 1) { + #ifdef SUPPORT_GESTURE + if (ts->in_gesture_mode == 1) { + mutex_lock(&ts->mutex); + gesture_judge(ts); + mutex_unlock(&ts->mutex); + } + #endif + } else { + int_touch(); + } + } + if( inte & 0x10 ){ + int_key_report_s3508(ts); + } + + +END: + //ret = set_changer_bit(ts); + touch_enable(ts); +EXIT: + pm_qos_remove_request(&pm_qos_req_tp); + return; +} + +#ifndef TPD_USE_EINT +static enum hrtimer_restart synaptics_ts_timer_func(struct hrtimer *timer) +{ + struct synaptics_ts_data *ts = container_of(timer, struct synaptics_ts_data, timer); + mutex_lock(&ts->mutex); + synaptics_ts_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 synaptics_irq_thread_fn(int irq, void *dev_id) +{ + struct synaptics_ts_data *ts = (struct synaptics_ts_data *)dev_id; + touch_disable(ts); + __pm_stay_awake(&ts->source); //avoid system enter suspend lead to i2c error + synaptics_ts_work_func(&ts->report_work); + __pm_relax(&ts->source); + return IRQ_HANDLED; +} +#endif + +//wangwenxue@BSP add for change baseline_test to "proc\touchpanel\baseline_test" begin +static ssize_t tp_baseline_test_read_func(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + char page[PAGESIZE]; + struct synaptics_ts_data *ts = ts_g; + if(!ts) + return baseline_ret; + if(baseline_ret == 0){ + count = synaptics_rmi4_baseline_show(ts->dev,page,1); + baseline_ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + }else{ + baseline_ret = 0; + } + return baseline_ret; +} +//wangwenxue@BSP add for change baseline_test to "proc\touchpanel\baseline_test" end + +static ssize_t i2c_device_test_read_func(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[PAGESIZE]; + struct synaptics_ts_data *ts = ts_g; + if(!ts_g) + return ret; + TPD_DEBUG("gesture enable is: %d\n", ts->gesture_enable); + ret = sprintf(page, "%d\n", ts->i2c_device_test); + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + return ret; +} + +#ifdef SUPPORT_GESTURE +static ssize_t tp_gesture_read_func(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[PAGESIZE]; + struct synaptics_ts_data *ts = ts_g; + if(!ts) + return ret; + 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 tp_gesture_write_func(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + char buf[10]; + struct synaptics_ts_data *ts = ts_g; + if(!ts) + return count; + if( count > 3 || ts->is_suspended) + return count; + if( copy_from_user(buf, buffer, count) ){ + TPD_ERR(KERN_INFO "%s: read proc input error.\n", __func__); + return count; + } + //ruanbanmao@BSP add for tp gesture 2015-05-06, begin + TPD_ERR("%s write argc1[0x%x],argc2[0x%x]\n",__func__,buf[0],buf[1]); + + UpVee_gesture = (buf[0] & BIT0)?1:0; //"V" + DouSwip_gesture = (buf[0] & BIT1)?1:0;//"||" + LeftVee_gesture = (buf[0] & BIT3)?1:0; //">" + RightVee_gesture = (buf[0] & BIT4)?1:0;//"<" + Circle_gesture = (buf[0] & BIT6)?1:0; //"O" + DouTap_gesture = (buf[0] & BIT7)?1:0; //double tap + + Sgestrue_gesture = (buf[1] & BIT0)?1:0;//"S" + Mgestrue_gesture = (buf[1] & BIT1)?1:0; //"M" + Wgestrue_gesture = (buf[1] & BIT2)?1:0; //"W" + Single_gesture = (buf[1] & BIT3)?1:0; //"Single_gesture" + //enable gesture + Enable_gesture = (buf[1] & BIT7)?1:0; + + if (DouTap_gesture || Circle_gesture || UpVee_gesture + || LeftVee_gesture || RightVee_gesture || DouSwip_gesture + || Sgestrue_gesture || Mgestrue_gesture || Wgestrue_gesture + || Enable_gesture || Single_gesture) { + ts->gesture_enable = 1; + } + else + { + ts->gesture_enable = 0; + } + //ruanbanmao@BSP add for tp gesture 2015-05-06, end + return count; +} +static ssize_t coordinate_proc_read_func(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[PAGESIZE]; + TPD_ERR("%s:gesture_upload = %d \n", __func__, gesture); + ret = sprintf(page, "%d,%d:%d,%d:%d,%d:%d,%d:%d,%d:%d,%d:%d,%d\n", + gesture, Point_start.x, Point_start.y, Point_end.x, Point_end.y, + Point_1st.x, Point_1st.y, Point_2nd.x, Point_2nd.y, + Point_3rd.x, Point_3rd.y, Point_4th.x, Point_4th.y, + clockwise); + + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + return ret; +} + +static ssize_t gesture_switch_read_func(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[PAGESIZE]; + struct synaptics_ts_data *ts = ts_g; + if(!ts) + return ret; + ret = sprintf(page, "gesture_switch:%d\n", gesture_switch); + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + return ret; +} + +static ssize_t gesture_switch_write_func(struct file *file, const char __user *page, size_t count, loff_t *ppos) +{ + int ret,write_flag=0; + char buf[10]={0}; + struct synaptics_ts_data *ts = ts_g; + + if(ts->loading_fw) { + TPD_ERR("%s FW is updating break!!\n",__func__); + return count; + } + if( copy_from_user(buf, page, count) ){ + TPD_ERR("%s: read proc input error.\n", __func__); + return count; + } + __pm_stay_awake(&ts->source); //avoid system enter suspend lead to i2c error + mutex_lock(&ts->mutex); + ret = sscanf(buf,"%d",&write_flag); + gesture_switch = write_flag; + TPD_ERR("gesture_switch:%d,suspend:%d,gesture:%d\n",gesture_switch,ts->is_suspended,ts->gesture_enable); + if (1 == gesture_switch){ + if ((ts->is_suspended == 1) && (ts->gesture_enable == 1)){ + i2c_smbus_write_byte_data(ts->client, 0xff, 0x0); + synaptics_mode_change(0x80); + //synaptics_enable_interrupt_for_gesture(ts, 1); + //change active mode no need to write gesture mode. + touch_enable(ts); + } + }else if(2 == gesture_switch){ + if ((ts->is_suspended == 1) && (ts->gesture_enable == 1)){ + i2c_smbus_write_byte_data(ts->client, 0xff, 0x0); + synaptics_mode_change(0x81); + touch_disable(ts); + //synaptics_enable_interrupt_for_gesture(ts, 0); + //change slepp mode no need to write gesture mode. + } + } + mutex_unlock(&ts->mutex); + __pm_relax(&ts->source); + + return count; +} + +// chenggang.li@BSP.TP modified for oem 2014-08-08 create node +/******************************start****************************/ +static const struct file_operations tp_gesture_proc_fops = { + .write = tp_gesture_write_func, + .read = tp_gesture_read_func, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static const struct file_operations gesture_switch_proc_fops = { + .write = gesture_switch_write_func, + .read = gesture_switch_read_func, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static const struct file_operations coordinate_proc_fops = { + .read = coordinate_proc_read_func, + .open = simple_open, + .owner = THIS_MODULE, +}; +#endif +static int page ,address,block; +static ssize_t synap_read_address(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret; + char buffer[PAGESIZE]; + char buf[128]; + int i; + int cnt = 0; + + struct synaptics_ts_data *ts = ts_g; + TPD_DEBUG("%s page=0x%x,address=0x%x,block=0x%x\n",__func__,page,address,block); + cnt += sprintf(&(buffer[cnt]), "page=0x%x,address=0x%x,block=0x%x\n",page,address,block); + ret = synaptics_rmi4_i2c_write_byte(ts->client,0xff,page); + ret = synaptics_rmi4_i2c_read_block(ts->client,address,block,buf); + for (i=0;i < block;i++) + { + cnt += sprintf(&(buffer[cnt]), "buf[%d]=0x%x\n",i,buf[i]); + TPD_DEBUG("buffer[%d]=0x%x\n",i,buffer[i]); + } + ret = simple_read_from_buffer(user_buf, count, ppos, buffer, strlen(buffer)); + return ret; +} + +static ssize_t synap_write_address(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + int buf[128]; + char buffer_local[128]; + int ret, i; + struct synaptics_ts_data *ts = ts_g; + int temp_block, wbyte; + char reg[30]; + + if (count > 128) + return count; + if (copy_from_user(buffer_local, buffer, count)) { + TPD_ERR("%s: write proc error.\n", __func__); + return count; + } + + ret = sscanf(buffer_local, + "%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x", + &buf[0], &buf[1], &buf[2], &buf[3], &buf[4], + &buf[5], &buf[6], &buf[7], &buf[8], &buf[9], + &buf[10], &buf[11], &buf[12], &buf[13], &buf[14], + &buf[15], &buf[16], &buf[17]); + for (i = 0;i < ret;i++) + { + TPD_DEBUG("buf[i]=0x%x,",buf[i]); + } + TPD_DEBUG("\n"); + page= buf[0]; + address = buf[1]; + temp_block = buf[2]; + wbyte = buf[3]; + if (0xFF == temp_block)//the mark is to write register else read register + { + for (i=0;i < wbyte;i++) + { + reg[i] = (char)buf[4+i]; + } + ret = synaptics_rmi4_i2c_write_byte(ts->client,0xff,page); + ret = synaptics_rmi4_i2c_write_block(ts->client,(char)address,wbyte,reg); + TPD_DEBUG("%s write page=0x%x,address=0x%x\n",__func__,page,address); + for (i=0;i < wbyte;i++) + { + TPD_DEBUG("reg=0x%x\n",reg[i]); + } + } + else + block = temp_block; + return count; +} + +#ifdef SUPPORT_GLOVES_MODE +static ssize_t tp_glove_read_func(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[PAGESIZE]; + struct synaptics_ts_data *ts = ts_g; + if(!ts) + return ret; + TPD_DEBUG("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 ssize_t tp_glove_write_func(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + struct synaptics_ts_data *ts= ts_g; + int ret = 0 ; + char buf[10]={0}; + + if( count > 10 ) + goto GLOVE_ENABLE_END; + if( copy_from_user( buf, buffer, count) ){ + TPD_ERR("%s: read proc input error.\n", __func__); + goto GLOVE_ENABLE_END; + } + sscanf(buf, "%d", &ret); + if(!ts) + return count; + TPDTM_DMESG("tp_glove_write_func:buf = %d,ret = %d\n", *buf, ret); + if( (ret == 0 ) || (ret == 1) ){ + ts->glove_enable = ret; + synaptics_glove_mode_enable(ts); + } + switch(ret){ + case 0: + TPDTM_DMESG("tp_glove_func will be disable\n"); + break; + case 1: + TPDTM_DMESG("tp_glove_func will be enable\n"); + break; + default: + TPDTM_DMESG("Please enter 0 or 1 to open or close the glove function\n"); + } +GLOVE_ENABLE_END: + return count; +} +#endif + + +#ifdef SUPPORT_TP_SLEEP_MODE +static ssize_t tp_sleep_read_func(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[PAGESIZE]; + TPD_DEBUG("sleep mode enable is: %d\n", sleep_enable); + ret = sprintf(page, "%d\n", sleep_enable); + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + return ret; +} + +static ssize_t tp_sleep_write_func(struct file *file, const char *buffer, size_t count, loff_t *ppos) +{ + char buf[10]={0}; + struct synaptics_ts_data *ts = ts_g; + int ret = 0 ; + if( count > 10 ) + return count; + if(!ts) + return count; + if( copy_from_user( buf, buffer, count) ) { + TPD_ERR(KERN_INFO "%s: read proc input error.\n", __func__); + return count; + } + sscanf(buf, "%d", &ret); + TPDTM_DMESG("tp_sleep_write_func:buf = %d,ret = %d\n", *buf, ret); + if( (ret == 0 ) || (ret == 1) ) { + sleep_enable = ret; + synaptics_sleep_mode_enable(ts); + } + switch(ret) { + case 0: + TPDTM_DMESG("tp_sleep_func will be disable\n"); + break; + case 1: + TPDTM_DMESG("tp_sleep_func will be enable\n"); + break; + default: + TPDTM_DMESG("Please enter 0 or 1 to open or close the sleep function\n"); + } + return count; +} +#endif + +static ssize_t tp_show(struct device_driver *ddri, char *buf) +{ + // uint8_t ret = 0; + struct synaptics_ts_data *ts = ts_g; + int a ; + int b,c; + if(!ts) + return 0; + a = synaptics_rmi4_i2c_read_word(ts->client, F01_RMI_DATA_BASE); + if( a < 0 ) + TPD_ERR("tp_show read i2c err\n"); + b = synaptics_rmi4_i2c_read_byte(ts->client, F01_RMI_DATA01); + if( b < 0 ) + TPD_ERR("tp_show read i2c err\n"); + c = synaptics_rmi4_i2c_read_byte(ts->client, F12_2D_DATA_BASE); + if( c < 0 ) + TPD_ERR("tp_show read i2c err\n"); + + return sprintf(buf, "F01_RMI_DATA_BASE[0x%x]=0x%x;F01_RMI_DATA01[0x%x]=0x%x;F12_2D_DATA_BASE[0x%x]=0x%x;\n", \ + F01_RMI_DATA_BASE,a,F01_RMI_DATA01,b,F12_2D_DATA_BASE,c); +} + +static ssize_t store_tp(struct device_driver *ddri, const char *buf, size_t count) +{ + int tmp = 0; + if( 1 == sscanf(buf, "%d", &tmp) ){ + tp_debug = tmp; + } else { + TPDTM_DMESG("invalid content: '%s', length = %zd\n", buf, count); + } + return count; +} +static ssize_t vendor_id_read_func(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[4]; + ret = sprintf(page, "%d\n",7); + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + return ret; +} + +#if TP_TEST_ENABLE +static int synaptics_read_register_map_page1(struct synaptics_ts_data *ts) +{ + unsigned char buf[4]; + int ret; + ret = synaptics_rmi4_i2c_write_byte(ts->client, 0xff, 0x1); + if( ret < 0 ) { + TPD_ERR("synaptics_rmi4_i2c_write_byte failed for page select\n"); + return -1; + } + ret = synaptics_rmi4_i2c_read_block(ts->client, 0xE9, 4, &(buf[0x0])); + F54_ANALOG_QUERY_BASE = buf[0]; + F54_ANALOG_COMMAND_BASE = buf[1]; + F54_ANALOG_CONTROL_BASE = buf[2]; + F54_ANALOG_DATA_BASE = buf[3]; + + TPD_ERR("F54_ANALOG_QUERY_BASE = 0x%x \n \ + F54_ANALOG_COMMAND_BASE = 0x%x \n\ + F54_ANALOG_CONTROL_BASE = 0x%x \n\ + F54_ANALOG_DATA_BASE = 0x%x \n\ + ",F54_ANALOG_QUERY_BASE,F54_ANALOG_COMMAND_BASE,F54_ANALOG_CONTROL_BASE,F54_ANALOG_DATA_BASE); + return 0; +} + +static void checkCMD(int delay_time) +{ + int ret; + int flag_err = 0; + struct synaptics_ts_data *ts = ts_g; + do { + delay_qt_ms(delay_time); /*wait delay_time ms*/ + ret = synaptics_rmi4_i2c_read_byte(ts->client, F54_ANALOG_COMMAND_BASE); + flag_err++; + } while ((ret > 0x00) && (flag_err < 60)); + if (ret > 0x00 || flag_err >= 60) + TPD_ERR("checkCMD error ret is %x flag_err is %d\n", ret, flag_err); +} + +static void checkCMD_RT133(void) +{ + int ret = 0; + int err_count = 0; + struct synaptics_ts_data *ts = ts_g; + do { + if (version_is_s3508 == 2) + delay_qt_ms(80); + else + delay_qt_ms(10); + ret = synaptics_rmi4_i2c_read_byte(ts->client, F54_ANALOG_COMMAND_BASE); + err_count++; + }while( (ret & 0x01) && (err_count < 30) ); + if( ret & 0x01 || err_count >= 30) + TPD_ERR("%s line%d %x count %d\n", __func__, __LINE__, ret, err_count); +} + +#endif + +static ssize_t tp_baseline_show(struct device_driver *ddri, char *buf) +{ + int ret = 0; + int x, y; + ssize_t num_read_chars = 0; + uint8_t tmp_l = 0,tmp_h = 0; + uint16_t tmp_old = 0; + uint16_t tmp_new = 0; + uint16_t count = 0; + struct synaptics_ts_data *ts = ts_g; + if(!ts) + return count; + memset(delta_baseline,0,sizeof(delta_baseline)); + /*disable irq when read data from IC*/ + touch_disable(ts); + mutex_lock(&ts->mutex); + synaptics_hard_reset(ts); + synaptics_read_register_map_page1(ts); + + TPD_DEBUG("\nstep 1:select report type 0x03 baseline\n"); + msm_cpuidle_set_sleep_disable(true); + /*step 1:check raw capacitance*/ + ret = i2c_smbus_write_byte_data(ts->client, F54_ANALOG_DATA_BASE, 0x03);//select report type 0x03 + if( ret < 0 ){ + TPD_ERR("step 1: select report type 0x03 failed \n"); + //return sprintf(buf, "i2c err!"); + } + + ret = i2c_smbus_write_byte_data(ts->client, F54_ANALOG_CONTROL_BASE+20, 0x01); + + if (version_is_s3508 != 2) { + ret = i2c_smbus_read_byte_data(ts->client, F54_ANALOG_CONTROL_BASE+23); + tmp_old = ret & 0xff; + ret = i2c_smbus_write_byte_data(ts->client, F54_ANALOG_CONTROL_BASE+23, (tmp_old & 0xef)); + ret = i2c_smbus_write_word_data(ts->client, F54_ANALOG_COMMAND_BASE, 0x04); + ret = i2c_smbus_read_byte_data(ts->client,F54_ANALOG_CONTROL_BASE+27); + tmp_new = ret & 0xdf; + i2c_smbus_write_byte_data(ts->client, + F54_ANALOG_CONTROL_BASE+27, tmp_new); + } else if (version_is_s3508 == 2) { + /* s3706 no nedd 0D CBC Settings */ + ret = i2c_smbus_write_word_data(ts->client, + F54_ANALOG_COMMAND_BASE, 0x04); + ret = i2c_smbus_read_byte_data(ts->client, + F54_ANALOG_CONTROL_BASE+23);/* Analog Control 1 */ + tmp_new = ret & 0xdf; + i2c_smbus_write_byte_data(ts->client, + F54_ANALOG_CONTROL_BASE+23, tmp_new); + } + + ret = i2c_smbus_write_word_data(ts->client, F54_ANALOG_COMMAND_BASE, 0x04); // force update + + ret = i2c_smbus_write_byte_data(ts->client, F54_ANALOG_CONTROL_BASE+7, 0x01);// Forbid NoiseMitigation + + ret = i2c_smbus_write_word_data(ts->client, F54_ANALOG_COMMAND_BASE, 0x04); // force update + checkCMD(10); + //TPDTM_DMESG("forbid Forbid NoiseMitigation oK\n"); + ret = i2c_smbus_write_byte_data(ts->client, F54_ANALOG_COMMAND_BASE, 0X02);//force Cal + checkCMD(10); + //TPDTM_DMESG("Force Cal oK\n"); + ret = i2c_smbus_write_word_data(ts->client, F54_ANALOG_DATA_BASE+1, 0x00);//set fifo 00 + ret = i2c_smbus_write_byte_data(ts->client, F54_ANALOG_COMMAND_BASE, 0x01);//get report + checkCMD(10); + count = 0; + for( x = 0; x < TX_NUM; x++ ){ + //printk("\n[%d]", x); + num_read_chars += sprintf(&(buf[num_read_chars]), "\n[%d]", x); + for( y = 0; y < RX_NUM; y++ ){ + ret = i2c_smbus_read_byte_data(ts->client, F54_ANALOG_DATA_BASE+3); + tmp_l = ret&0xff; + ret = i2c_smbus_read_byte_data(ts->client, F54_ANALOG_DATA_BASE+3); + tmp_h = ret&0xff; + delta_baseline[x][y] = (tmp_h << 8)|tmp_l; + //printk("%d,", delta_baseline[x][y]); + num_read_chars += sprintf(&(buf[num_read_chars]), "%5d", delta_baseline[x][y]); + } + } + num_read_chars += sprintf(&(buf[num_read_chars]), "\n"); + TPD_DEBUG("\nread all is oK\n"); + ret = i2c_smbus_write_byte_data(ts->client, F54_ANALOG_COMMAND_BASE, 0X02); + delay_qt_ms(60); + msm_cpuidle_set_sleep_disable(false); +#ifdef SUPPORT_GLOVES_MODE + synaptics_glove_mode_enable(ts); +#endif + synaptics_init_panel(ts); +//modify by zhouwenping for solve cat tp_baseline_image node cause touch disable 20160225 start + synaptics_enable_interrupt(ts,1); + ret = synaptics_soft_reset(ts); + if (ret < 0){ + TPD_ERR("%s faile to reset device\n",__func__); + } + mutex_unlock(&ts->mutex); +//modify by zhouwenping 20160225 end + return num_read_chars; + +} + +static ssize_t tp_rawdata_show(struct device_driver *ddri, char *buf) +{ + int ret = 0; + int x, y; + ssize_t num_read_chars = 0; + uint8_t tmp_l = 0, tmp_h = 0; + uint16_t count = 0; + struct synaptics_ts_data *ts = ts_g; + if(!ts) + return 0; + memset(delta_baseline, 0, sizeof(delta_baseline)); + /*disable irq when read data from IC*/ + touch_disable(ts); + mutex_lock(&ts->mutex); + synaptics_read_register_map_page1(ts); + + //TPD_DEBUG("\nstep 2:report type2 delta image\n"); + memset(delta_baseline, 0, sizeof(delta_baseline)); + ret = synaptics_rmi4_i2c_write_byte(ts->client, F54_ANALOG_DATA_BASE, 0x02);//select report type 0x02 + ret = synaptics_rmi4_i2c_write_word(ts->client, F54_ANALOG_DATA_BASE+1, 0x00);//set fifo 00 + ret = synaptics_rmi4_i2c_write_byte(ts->client, F54_ANALOG_COMMAND_BASE, 0X01);//get report + checkCMD(10); + count = 0; + for( x = 0; x < TX_NUM; x++ ){ + //printk("\n[%d]", x); + num_read_chars += sprintf(&(buf[num_read_chars]), "\n[%d]", x); + for( y = 0; y < RX_NUM; y++ ){ + ret = synaptics_rmi4_i2c_read_byte(ts->client, F54_ANALOG_DATA_BASE+3); + tmp_l = ret&0xff; + ret = synaptics_rmi4_i2c_read_byte(ts->client, F54_ANALOG_DATA_BASE+3); + tmp_h = ret&0xff; + delta_baseline[x][y] = (tmp_h<<8)|tmp_l; + //printk("%3d,", delta_baseline[x][y]); + num_read_chars += sprintf(&(buf[num_read_chars]), "%3d ", delta_baseline[x][y]); + } + } + num_read_chars += sprintf(&(buf[num_read_chars]), "\n"); + ret = i2c_smbus_write_byte_data(ts->client,F54_ANALOG_COMMAND_BASE,0X02); + delay_qt_ms(60); + synaptics_enable_interrupt(ts, 1); + mutex_unlock(&ts->mutex); + touch_enable(ts); + return num_read_chars; +} + +static ssize_t tp_delta_store(struct device_driver *ddri, + const char *buf, size_t count) +{ + TPDTM_DMESG("tp_test_store is not support\n"); + return count; +} + +static ssize_t synaptics_rmi4_baseline_show_s3508(struct device *dev, char *buf, bool savefile) +{ + + ssize_t num_read_chars = 0; +#if TP_TEST_ENABLE + int ret = 0; + uint8_t x,y; + int tx_datal; + int16_t err_RT251 = 0, err_RT251_self = 0, err_RT253 = 0; + int16_t baseline_data = 0; + uint16_t unsigned_baseline_data = 0; + uint8_t tmp_old = 0; + uint8_t tmp_new = 0; + uint8_t tmp_l = 0,tmp_h = 0; + uint16_t count = 0; + int error_count = 0; + uint8_t buffer[9]={0}; + int16_t *baseline_data_test; + int enable_cbc = 0; + int readdata_fail=0,first_check=0; + int16_t left_ramdata=0,right_ramdata=0; + int fd = -1; + struct timespec now_time; + struct rtc_time rtc_now_time; + uint8_t data_buf[64]; + mm_segment_t old_fs; + uint32_t CURRENT_FIRMWARE_ID = 0 ; + struct synaptics_ts_data *ts = dev_get_drvdata(dev); + /* + const struct firmware *fw = NULL; + struct test_header *ph = NULL; + ret = request_firmware(&fw, ts->test_limit_name, dev); + if (ret < 0) { + TPD_ERR("Request firmware failed - %s (%d)\n",ts->test_limit_name, ret); + error_count++; + num_read_chars += sprintf(&(buf[num_read_chars]), "imageid=0x%x,deviceid=0x%x\n",TP_FW,TP_FW); + num_read_chars += sprintf(&(buf[num_read_chars]), "%d error(s). %s\n", error_count, error_count?"":"All test passed."); + return num_read_chars; + } + + //ph = (struct test_header *)(fw->data); + */ + + ret = synaptics_rmi4_i2c_write_byte(ts->client, 0xff, 0x0); + synaptics_rmi4_i2c_read_block(ts->client, F34_FLASH_CTRL00, 4, buf); + CURRENT_FIRMWARE_ID = (buf[0]<<24) | (buf[1]<<16) | (buf[2]<<8) | buf[3]; + TPD_ERR("[sk]CURRENT_FIRMWARE_ID = 0x%x\n", CURRENT_FIRMWARE_ID); + sprintf(ts->fw_id,"0x%x",CURRENT_FIRMWARE_ID); + push_component_info(TP, ts->fw_id, ts->manu_name); +READDATA_AGAIN: + msleep(30); + mutex_lock(&ts->mutex); + touch_disable(ts); + + memset(Rxdata, 0, sizeof(Rxdata)); + synaptics_read_register_map_page1(ts); + //TPDTM_DMESG("step 1:select report type 0x03\n"); + + if(savefile) { + 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.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 = sys_open(data_buf, O_WRONLY | O_CREAT | O_TRUNC, 0); + if (fd < 0) { + TPD_ERR("Open log file '%s' failed.\n", data_buf); + set_fs(old_fs); + } + } + + //step 1:check raw capacitance. +TEST_WITH_CBC_s3508: + ret = i2c_smbus_write_byte_data(ts->client, F54_ANALOG_DATA_BASE, 0x03);//select report type 0x03 + if( ret < 0 ){ + TPD_ERR("read_baseline: i2c_smbus_write_byte_data failed \n"); + goto END; + } + ret = i2c_smbus_write_byte_data(ts->client, F54_ANALOG_CONTROL_BASE+20, 0x01); + ret = i2c_smbus_read_byte_data(ts->client,F54_ANALOG_CONTROL_BASE+23); + tmp_old = ret&0xff; + + if(enable_cbc){ + TPD_DEBUG("ret = %x ,tmp_old =%x ,tmp_new = %x\n",ret,tmp_old,(tmp_old | 0x10)); + ret = i2c_smbus_write_byte_data(ts->client,F54_ANALOG_CONTROL_BASE+23,(tmp_old | 0x10)); + ret = i2c_smbus_write_word_data(ts->client,F54_ANALOG_COMMAND_BASE,0x04); + checkCMD(30); + ret = i2c_smbus_read_byte_data(ts->client,F54_ANALOG_CONTROL_BASE+27); + tmp_new = ret | 0x20; + i2c_smbus_write_byte_data(ts->client, F54_ANALOG_CONTROL_BASE+27, tmp_new); + ret = i2c_smbus_write_word_data(ts->client, F54_ANALOG_COMMAND_BASE, 0x04); + TPD_DEBUG("Test open cbc\n"); + if(CURRENT_FIRMWARE_ID == 0xAB056006) + baseline_data_test = (int16_t *)baseline_cap_data_old[0]; + else { + if (ts->support_1080x2160_tp) + baseline_data_test = (int16_t *)baseline_cap_17801_data[0]; + else + baseline_data_test = (int16_t *)baseline_cap_data[0]; + } + }else{ + TPD_DEBUG("ret = %x ,tmp_old =%x ,tmp_new = %x\n",ret,tmp_old,(tmp_old & 0xef)); + ret = i2c_smbus_write_byte_data(ts->client,F54_ANALOG_CONTROL_BASE+23,(tmp_old & 0xef)); + ret = i2c_smbus_write_word_data(ts->client, F54_ANALOG_COMMAND_BASE, 0x04); + ret = i2c_smbus_read_byte_data(ts->client,F54_ANALOG_CONTROL_BASE+27); + tmp_new = ret & 0xdf; + i2c_smbus_write_byte_data(ts->client, F54_ANALOG_CONTROL_BASE+27, tmp_new); + ret = i2c_smbus_write_word_data(ts->client, F54_ANALOG_COMMAND_BASE, 0x04); // force update + ret = i2c_smbus_write_byte_data(ts->client, F54_ANALOG_CONTROL_BASE+7, 0x01);// Forbid NoiseMitigation + if(CURRENT_FIRMWARE_ID == 0xAB056006) + baseline_data_test = (int16_t *)baseline_cap_data_old[1]; + else { + if (ts->support_1080x2160_tp) + baseline_data_test = (int16_t *)baseline_cap_17801_data[1]; + else + baseline_data_test = (int16_t *)baseline_cap_data[1]; + } + } + /******write No Relax to 1******/ + ret = i2c_smbus_write_word_data(ts->client, F54_ANALOG_COMMAND_BASE, 0x04); // force update + checkCMD(30); + TPD_DEBUG("forbid Forbid NoiseMitigation oK\n"); + ret = i2c_smbus_write_byte_data(ts->client, F54_ANALOG_COMMAND_BASE, 0X02);//force Cal + checkCMD(30); + TPD_DEBUG("Force Cal oK\n"); + ret = i2c_smbus_write_word_data(ts->client, F54_ANALOG_DATA_BASE+1, 0x00);//set fifo 00 + ret = i2c_smbus_write_byte_data(ts->client, F54_ANALOG_COMMAND_BASE, 0x01);//get report + checkCMD(30); + + count = 0; + for( x = 0; x < TX_NUM; x++ ){ + + for( y = 0; y < RX_NUM; y++ ){ + ret = i2c_smbus_read_byte_data(ts->client, F54_ANALOG_DATA_BASE+3); + tmp_l = ret&0xff; + ret = i2c_smbus_read_byte_data(ts->client, F54_ANALOG_DATA_BASE+3); + tmp_h = ret&0xff; + baseline_data = (tmp_h<<8)|tmp_l; + if (fd >= 0){ + sprintf(data_buf, "%d,", baseline_data); + sys_write(fd, data_buf, strlen(data_buf)); + } + if( (y < RX_NUM ) && (x < TX_NUM) ){ + //printk("%4d ,",baseline_data); + if (x == (TX_NUM-1) && y == (RX_NUM-1)) + left_ramdata = baseline_data; + else if (x == (TX_NUM-1) && y == (RX_NUM-2)) + right_ramdata = baseline_data; + if(((baseline_data+60) < *(baseline_data_test+count*2)) || ((baseline_data-60) > *(baseline_data_test+count*2+1))){ + if((x == (TX_NUM-1) && (y != RX_NUM-1 || y != RX_NUM-2))||\ + (x != (TX_NUM-1) && (y == RX_NUM-1 || y == RX_NUM-2)))//the last tx and rx last two line for touchkey,others no need take care + { + count++; + continue; + } + TPD_ERR("touchpanel failed,RX_NUM:%d,TX_NUM:%d,baseline_data is %d,TPK_array_limit[%d*2]=%d,TPK_array_limit[%d*2+1]=%d\n ",y,x,baseline_data,count,*(baseline_data_test+count*2),count,*(baseline_data_test+count*2+1)); + if((baseline_data <= 0) && (first_check == 0)){ + first_check = 1; + readdata_fail = 1; + } + num_read_chars += sprintf(&(buf[num_read_chars]), "0 raw data erro baseline_data[%d][%d]=%d[%d,%d]\n",x,y,baseline_data,*(baseline_data_test+count*2), *(baseline_data_test+count*2+1)); + error_count++; + goto END; + } + } + /* + //test virtual key + if( (y==(RX_NUM-1)) && (x>= TX_NUM-3) ){ + TPD_DEBUG("synaptics:test virtual key,y= %d ,x = %d\n",y,x); + TPD_DEBUG("Synaptic:test virtual key;baseline_data is %d,TPK_array_limit[%d*2]=%d,TPK_array_limit[%d*2+1]=%d\n ",baseline_data,count,*(baseline_data_test+count*2),count,*(baseline_data_test+count*2+1)); + if((baseline_data < *(baseline_data_test+count*2)) || (baseline_data > *(baseline_data_test+count*2+1))){ + TPD_ERR("Synaptic:test virtual key failed------------;baseline_data is %d,TPK_array_limit[%d*2]=%d,TPK_array_limit[%d*2+1]=%d\n ",baseline_data,count,*(baseline_data_test+count*2),count,*(baseline_data_test+count*2+1)); + num_read_chars += sprintf(&(buf[num_read_chars]), "0 raw data erro baseline_data[%d][%d]=%d[%d,%d]\n",x,y,baseline_data,*(baseline_data_test+count*2), *(baseline_data_test+count*2+1)); + error_count++; + goto END; + } + } + */ + count++; + } + //printk("\n synaptics:s3320 TX_NUM:%d\n",x); + if (fd >= 0){ + sys_write(fd, "\n", 1); + } + } + + if(!enable_cbc){ + enable_cbc = 1; + if (fd >= 0){ + sys_write(fd, "\n", 1); + } + TPD_ERR("enable cbc baseline test again\n"); + goto TEST_WITH_CBC_s3508; + } + + ret = synaptics_rmi4_i2c_write_byte(ts->client, 0xff, 0x1); + if( ret < 0 ) { + TPD_ERR("%s line%d failed\n",__func__,__LINE__); + error_count++; + goto END; + } + + //Step2 : Check trx-to-ground + TPD_ERR("step 2:Check trx-to-ground\n" ); + ret = i2c_smbus_write_byte_data(ts->client, F54_ANALOG_DATA_BASE, 0x19);//select report type 25 + ret = i2c_smbus_write_word_data(ts->client, F54_ANALOG_DATA_BASE+1, 0x0); + ret = i2c_smbus_write_byte_data(ts->client, F54_ANALOG_COMMAND_BASE, 0x01);//get report + checkCMD(10); + tx_datal = i2c_smbus_read_i2c_block_data(ts->client, F54_ANALOG_DATA_BASE+3, 7, buffer); + if (ts->support_1080x2160_tp) { + buffer[0] |= 0x20;/*no care 5 31 32 34 36 37 40 52 53chanel*/ + buffer[3] |= 0x80; + buffer[4] |= 0x35; + buffer[5] |= 0x01; + buffer[6] |= 0xc0; + } else { + buffer[0] |= 0x10;/*no care 4 31 32 40 50 51 52chanel*/ + buffer[3] |= 0x80; + buffer[5] |= 0x01; + buffer[6] |= 0xc0; + } + for(x = 0;x < 7; x++) + { + if(0xff != buffer[x]){ + error_count++; + TPD_ERR("step 2:error_count[%d] buff%d[0x%x] ERROR!\n",error_count,x,buffer[x]); + goto END; + } + } + + ret = synaptics_rmi4_i2c_write_byte(ts->client, 0xff, 0x0); + if( ret < 0 ) { + TPD_ERR("%s line%d failed\n",__func__,__LINE__); + error_count++; + goto END; + } + + ret = i2c_smbus_write_byte_data(ts->client, F01_RMI_CMD_BASE, 0x01);//software reset TP + msleep(50); + ret = synaptics_rmi4_i2c_write_byte(ts->client, 0xff, 0x1); + if( ret < 0 ) { + TPD_ERR("%s line%d failed\n",__func__,__LINE__); + error_count++; + goto END; + } + + //step 3 :check tx-to-tx and tx-to-vdd + TPD_ERR("step 3:check TRx-TRx & TRx-Vdd short\n" ); + ret = i2c_smbus_write_byte_data(ts->client, F54_ANALOG_DATA_BASE, 0x1A);//select report type 26 + ret = i2c_smbus_write_word_data(ts->client, F54_ANALOG_DATA_BASE+1, 0x0); + ret = i2c_smbus_write_byte_data(ts->client, F54_ANALOG_COMMAND_BASE, 0x01);//get report + checkCMD(10); + tx_datal = i2c_smbus_read_i2c_block_data(ts->client, F54_ANALOG_DATA_BASE+3, 7, buffer); + buffer[0] &= 0xef;/*no care 4 31 32 40 50 51 52chanel*/ + buffer[3] &= 0x7f; + buffer[5] &= 0xfe; + buffer[6] &= 0x3f; + for(x = 0;x < 7; x++) + { + if(buffer[x]){ + error_count++; + TPD_ERR("step 3:error_count[%d] buff%d[0x%x] ERROR!\n",error_count,x,buffer[x]); + goto END; + } + } + + ret = synaptics_rmi4_i2c_write_byte(ts->client, 0xff, 0x0); + if( ret < 0 ) { + TPD_ERR("%s line%d failed\n",__func__,__LINE__); + error_count++; + goto END; + } + + ret = i2c_smbus_write_byte_data(ts->client, F01_RMI_CMD_BASE, 0x01);//software reset TP + msleep(50); + ret = synaptics_rmi4_i2c_write_byte(ts->client, 0xff, 0x1); + if( ret < 0 ) { + TPD_ERR("%s line%d failed\n",__func__,__LINE__); + error_count++; + goto END; + } + //Step4 : Check RT133 + TPD_ERR("step 4:Check RT133\n" ); + ret = i2c_smbus_write_byte_data(ts->client, F54_ANALOG_DATA_BASE, 0x85);//select report type 133 + ret = i2c_smbus_write_word_data(ts->client, F54_ANALOG_DATA_BASE+1, 0x0);//set fifo 0 + ret = i2c_smbus_write_byte_data(ts->client, F54_ANALOG_COMMAND_BASE, 0x01);//get report + checkCMD_RT133(); + for (y = 0; y < RX_NUM; y++) { + ret = i2c_smbus_read_byte_data(ts->client, F54_ANALOG_DATA_BASE+3); + tmp_l = ret&0xff; + ret = i2c_smbus_read_byte_data(ts->client, F54_ANALOG_DATA_BASE+3); + tmp_h = ret&0xff; + baseline_data = (tmp_h<<8)|tmp_l; + if(baseline_data > 100){ + error_count++; + TPD_ERR("step 4:error_count[%d] baseline_data%d[0x%x] ERROR!\n",error_count,y,baseline_data); + goto END; + } + } + /*Step 5 : Check RT251 for random touch event*/ + TPD_ERR("Step 5 : Check RT251 for random touch event\n"); + ret = i2c_smbus_write_byte_data(ts->client, F54_ANALOG_DATA_BASE, 0xFB);/*select report type 0xFB*/ + ret = i2c_smbus_write_word_data(ts->client, F54_ANALOG_DATA_BASE+1, 0x00);/*set fifo 00*/ + ret = i2c_smbus_write_byte_data(ts->client, F54_ANALOG_COMMAND_BASE, 0x01);/*get report*/ + checkCMD(100); + + for (x = 0; x < TX_NUM; x++) { + + for (y = 0; y < RX_NUM; y++) { + ret = i2c_smbus_read_byte_data(ts->client, F54_ANALOG_DATA_BASE+3); + tmp_l = ret; + ret = i2c_smbus_read_byte_data(ts->client, F54_ANALOG_DATA_BASE+3); + tmp_h = ret; + baseline_data = (tmp_h << 8) | tmp_l; + if ((x < TX_NUM-1) && (y < RX_NUM-2) && (baseline_data > 20)) { /*red zone, test capacitance,if half num large than 20, fail*/ + if (++err_RT251 > ((TX_NUM - 1) * (RX_NUM - 2) / 2)) { + error_count++; + TPD_ERR("Step 5 : Check RT251 for random touch event error, capacitance, err_RT251 is %d\n", err_RT251); + goto END; + } + } + + if ((x != TX_NUM - 1) && (y == RX_NUM - 1) && baseline_data > 500) { /*blue zone, test self capaccitance, if half num large than 500, fail*/ + if (++err_RT251_self > (TX_NUM - 1) / 2) { + error_count++; + TPD_ERR("Step 5 : Check RT251 for random touch event error, self capacitance, err_RT251_self is %d\n", err_RT251_self); + goto END; + } + } + } + } + TPD_ERR("ROLAND----> err_RT251 is %d err_RT251_self is %d\n", err_RT251, err_RT251_self); + /*Step 6 : Check RT252 for random touch event*/ + TPD_ERR("Step 6 : Check RT252 for random touch event\n"); + ret = i2c_smbus_write_byte_data(ts->client, F54_ANALOG_DATA_BASE, 0xFC);/*select report type 0xFC*/ + ret = i2c_smbus_write_word_data(ts->client, F54_ANALOG_DATA_BASE + 1, 0x00);/*set fifo 00*/ + ret = i2c_smbus_write_byte_data(ts->client, F54_ANALOG_COMMAND_BASE, 0x01);/*get report*/ + checkCMD(70); + for (y = 0; y < RX_NUM + TX_NUM - 3; y++) { + ret = i2c_smbus_read_byte_data(ts->client, F54_ANALOG_DATA_BASE + 3); + tmp_l = ret & 0xff; + ret = i2c_smbus_read_byte_data(ts->client, F54_ANALOG_DATA_BASE + 3); + tmp_h = ret & 0xff; + unsigned_baseline_data = (tmp_h << 8) | tmp_l; + if (unsigned_baseline_data < 10000) { + error_count++; + TPD_ERR("Step 6 : Check RT252 for random touch event, error_line is y =%d,data = %hu\n", y, unsigned_baseline_data); + goto END; + } + } + /*Step 7 : Check RT253 for random touch event*/ + TPD_ERR("Step 7 : Check RT253 for random touch event\n"); + ret = i2c_smbus_write_byte_data(ts->client, F54_ANALOG_DATA_BASE, 0xFD);/*select report type 0xFD*/ + ret = i2c_smbus_write_word_data(ts->client, F54_ANALOG_DATA_BASE + 1, 0x00);/*set fifo 00*/ + ret = i2c_smbus_write_byte_data(ts->client, F54_ANALOG_COMMAND_BASE, 0x01);/*get report*/ + checkCMD(70); + + for (x = 0; x < TX_NUM; x++) { + for (y = 0; y < RX_NUM; y++) { + ret = i2c_smbus_read_byte_data(ts->client, F54_ANALOG_DATA_BASE+3); + tmp_l = ret; + ret = i2c_smbus_read_byte_data(ts->client, F54_ANALOG_DATA_BASE+3); + tmp_h = ret; + baseline_data = (tmp_h << 8) | tmp_l; + if (baseline_data > 20) { + if (++err_RT253 > (TX_NUM * RX_NUM) / 2) { + error_count++; + TPD_ERR("Step 7 : Check RT253 for random touch event, self capacitance, err_RT253 is %d\n", err_RT253); + goto END; + } + } + } + } + TPD_ERR("ROLAND----> err_RT253 is %d\n", err_RT253); +END: + if (fd >= 0) { + sys_close(fd); + set_fs(old_fs); + } + //release_firmware(fw); + ret = i2c_smbus_write_byte_data(ts->client, F54_ANALOG_COMMAND_BASE, 0X02); + delay_qt_ms(60); + ret = i2c_smbus_write_byte_data(ts->client, 0xff, 0x00); + ret = i2c_smbus_write_byte_data(ts->client, F01_RMI_CMD00, 0x01); + msleep(150); + +#ifdef SUPPORT_GLOVES_MODE + synaptics_glove_mode_enable(ts); +#endif + synaptics_init_panel(ts); + synaptics_enable_interrupt(ts, 1); + touch_enable(ts); + TPD_ERR("\n\nstep5 reset and open irq complete\n"); + mutex_unlock(&ts->mutex); +#endif + if(readdata_fail == 1){ + TPD_ERR("readdata_fail...try again:%d\n",first_check); + readdata_fail =0; + goto READDATA_AGAIN; + } +#ifdef ENABLE_TPEDGE_LIMIT + synaptics_tpedge_limitfunc(); +#endif + TPD_ERR("status...first_check:%d:readdata_fail:%d\n", + first_check, readdata_fail); + num_read_chars += snprintf(&(buf[num_read_chars]), 128, + "imageid=0x%lx,deviceid=0x%lx\n", TP_FW, TP_FW); + num_read_chars += snprintf(&(buf[num_read_chars]), 128, + "left:=%d,right:%d\n", left_ramdata, right_ramdata); + num_read_chars += snprintf(&(buf[num_read_chars]), 128, + "%d error(s). %s\n", error_count, + error_count?"":"All test passed."); + return num_read_chars; +} + +static ssize_t synaptics_rmi4_baseline_show_s3706( + struct device *dev, char *buf, bool savefile) +{ + ssize_t num_read_chars = 0; +#if TP_TEST_ENABLE + int ret = 0; + uint8_t x, y; + int tx_datal; + int16_t baseline_data = 0; + uint32_t unsigned_baseline_data = 0; + uint8_t tmp_old = 0; + uint8_t tmp_new = 0; + uint8_t tmp_l = 0, tmp_h = 0; + uint16_t count = 0; + int error_count = 0; + uint8_t buffer[9] = {0}; + int16_t *baseline_data_test; + int enable_cbc = 0; + int readdata_fail = 0, first_check = 0; + int16_t left_ramdata = 0, right_ramdata = 0; + int fd = -1; + struct timespec now_time; + struct rtc_time rtc_now_time; + uint8_t data_buf[64]; + mm_segment_t old_fs; + unsigned long int CURRENT_FIRMWARE_ID = 0; + + struct synaptics_ts_data *ts = dev_get_drvdata(dev); + + msm_cpuidle_set_sleep_disable(true); + ret = synaptics_rmi4_i2c_write_byte(ts->client, 0xff, 0x0); + synaptics_rmi4_i2c_read_block(ts->client, + F34_FLASH_CTRL00, 8, buf); + CURRENT_FIRMWARE_ID = (buf[0] << 24) | + (buf[1] << 16) | (buf[2] << 8) | buf[3]; + CURRENT_FIRMWARE_ID = CURRENT_FIRMWARE_ID << 32 | + ((buf[4]<<24) | (buf[5]<<16) | (buf[6]<<8) | buf[7]); + TPD_ERR("[sk]CURRENT_FIRMWARE_ID = 0x%lx\n", + CURRENT_FIRMWARE_ID); + snprintf(ts->fw_id, 20, "0x%lx", CURRENT_FIRMWARE_ID); + push_component_info(TP, ts->fw_id, ts->manu_name); +READDATA_AGAIN: + msleep(30); + mutex_lock(&ts->mutex); + touch_disable(ts); + + memset(Rxdata, 0, sizeof(Rxdata)); + synaptics_hard_reset(ts); + synaptics_read_register_map_page1(ts); + + if (savefile) { + getnstimeofday(&now_time); + rtc_time_to_tm(now_time.tv_sec, &rtc_now_time); + snprintf(data_buf, 40, + "/sdcard/tp_testlimit_%02d%02d%02d-%02d%02d%02d.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 = sys_open(data_buf, O_WRONLY | O_CREAT | O_TRUNC, 0); + if (fd < 0) { + TPD_ERR("Open log file '%s' failed.\n", data_buf); + set_fs(old_fs); + } + } + + /*step 1:check raw capacitance.*/ +TEST_WITH_CBC_s3508: + ret = i2c_smbus_write_byte_data(ts->client, + F54_ANALOG_DATA_BASE, 0x03);/*select report type 0x03*/ + if (ret < 0) { + TPD_ERR("read_baseline: i2c_smbus_write_byte_data failed\n"); + goto END; + } + ret = i2c_smbus_write_byte_data(ts->client, + F54_ANALOG_CONTROL_BASE+20, 0x01); + ret = i2c_smbus_read_byte_data(ts->client, + F54_ANALOG_CONTROL_BASE+23); + tmp_old = ret & 0xff; + + if (enable_cbc) { + synaptics_hard_reset(ts); + synaptics_read_register_map_page1(ts); + + ret = i2c_smbus_write_byte_data(ts->client, + F54_ANALOG_DATA_BASE, 0x03);/*select report type 0x03*/ + if (ret < 0) { + TPD_ERR("read_baseline: i2c_smbus_write_byte_data failed\n"); + goto END; + } + ret = i2c_smbus_write_byte_data(ts->client, + F54_ANALOG_CONTROL_BASE+20, 0x01); + ret = i2c_smbus_read_byte_data(ts->client, + F54_ANALOG_CONTROL_BASE+23); + + ret = i2c_smbus_write_word_data(ts->client, + F54_ANALOG_COMMAND_BASE, 0x04); + checkCMD(30); + ret = i2c_smbus_read_byte_data(ts->client, + F54_ANALOG_CONTROL_BASE+23); + tmp_new = ret | 0x20;/*CBC Xmtr carrier select bit 5*/ + i2c_smbus_write_byte_data(ts->client, + F54_ANALOG_CONTROL_BASE+23, tmp_new); + ret = i2c_smbus_write_word_data(ts->client, + F54_ANALOG_COMMAND_BASE, 0x04); + checkCMD(30); + TPD_DEBUG("Test open cbc\n"); + baseline_data_test = (int16_t *)baseline_cap_17819_data[0]; + } else { + ret = i2c_smbus_write_word_data(ts->client, + F54_ANALOG_COMMAND_BASE, 0x04); + checkCMD(30); + ret = i2c_smbus_read_byte_data(ts->client, + F54_ANALOG_CONTROL_BASE+23); + tmp_new = ret & 0xdf;/*CBC Xmtr carrier select bit 5*/ + i2c_smbus_write_byte_data(ts->client, + F54_ANALOG_CONTROL_BASE+23, tmp_new); + ret = i2c_smbus_write_word_data(ts->client, + F54_ANALOG_COMMAND_BASE, 0x04); + /* force update*/ + checkCMD(30); + ret = i2c_smbus_write_byte_data(ts->client, + F54_ANALOG_CONTROL_BASE+7, 0x01); + /* Forbid NoiseMitigation*/ + baseline_data_test = (int16_t *)baseline_cap_17819_data[1]; + } + /******write No Relax to 1******/ + ret = i2c_smbus_write_word_data(ts->client, + F54_ANALOG_COMMAND_BASE, 0x04); /* force update*/ + checkCMD(30); + TPD_DEBUG("forbid Forbid NoiseMitigation oK\n"); + ret = i2c_smbus_write_byte_data(ts->client, + F54_ANALOG_COMMAND_BASE, 0X02);/*force Cal*/ + checkCMD(30); + TPD_DEBUG("Force Cal oK\n"); + ret = i2c_smbus_write_word_data(ts->client, + F54_ANALOG_DATA_BASE+1, 0x00);//set fifo 00 + ret = i2c_smbus_write_byte_data(ts->client, + F54_ANALOG_COMMAND_BASE, 0x01);//get report + checkCMD(30); + + count = 0; + for (x = 0; x < TX_NUM; x++) { + for (y = 0; y < RX_NUM; y++) { + ret = i2c_smbus_read_byte_data(ts->client, + F54_ANALOG_DATA_BASE+3); + tmp_l = ret & 0xff; + ret = i2c_smbus_read_byte_data(ts->client, + F54_ANALOG_DATA_BASE+3); + tmp_h = ret & 0xff; + usleep_range(1000, 1001); + baseline_data = (tmp_h << 8) | tmp_l; + if (fd >= 0) { + snprintf(data_buf, 20, "%d,", baseline_data); + sys_write(fd, data_buf, strlen(data_buf)); + } + if ((y < RX_NUM) && (x < TX_NUM)) { + /*printk("%4d ,",baseline_data);*/ + if (x == (TX_NUM-1) && + y == (RX_NUM-1)) + left_ramdata = baseline_data; + else if (x == (TX_NUM-1) && + y == (RX_NUM-2)) + right_ramdata = baseline_data; + if (((baseline_data+60) < + *(baseline_data_test+count*2)) || + ((baseline_data-60) > + *(baseline_data_test+count*2+1))) { + if (ts->support_1080x2340_tp) { + if ((y == 0) && (x >= 7) && (x <= 8)) { + count++; + TPD_ERR("RX_NU:%dTX_NU:%dbaslin_da%d\n", + y, x, baseline_data); + continue; + } + } else { + if ((y == 0) && (x >= 6) && (x <= 9)) { + count++; + TPD_ERR("RX_NU:%dTX_NU:%dbaslin_da%d\n", + y, x, baseline_data); + continue; + } + } + TPD_ERR("failed,RX_NU:%d,TX_NU:%d,baslin_da is%d\n", + y, x, baseline_data); + TPD_ERR("failed,TPK_arrlimit[%d*2]=%d,TPK_arrlimit[%d*2+1]=%d\n", + count, *(baseline_data_test+count*2), + count, *(baseline_data_test+count*2+1)); + if ((baseline_data <= 0) && + (first_check == 0)) { + first_check = 1; + readdata_fail = 1; + } + num_read_chars += + snprintf(&(buf[num_read_chars]), 60, + "0 raw data erro baseline_data[%d][%d]=%d[%d,%d]\n", + x, y, baseline_data, + *(baseline_data_test+count*2), + *(baseline_data_test+count*2+1)); + error_count++; + goto END; + } + } + count++; + } + /*printk("\n synaptics:s3320 TX_NUM:%d\n",x);*/ + if (fd >= 0) + sys_write(fd, "\n", 1); + } + + if (!enable_cbc) { + enable_cbc = 1; + if (fd >= 0) + sys_write(fd, "\n", 1); + TPD_ERR("enable cbc baseline test again\n"); + goto TEST_WITH_CBC_s3508; + } + synaptics_hard_reset(ts); + synaptics_read_register_map_page1(ts); + + ret = synaptics_rmi4_i2c_write_byte(ts->client, 0xff, 0x1); + if (ret < 0) { + TPD_ERR("%s line%d failed\n", __func__, __LINE__); + error_count++; + goto END; + } + + /*Step2 : Check trx-to-ground*/ + TPD_ERR("step 2:Check trx-to-ground\n"); + ret = i2c_smbus_write_byte_data(ts->client, + F54_ANALOG_DATA_BASE, 0x19);/*select report type 25*/ + ret = i2c_smbus_write_word_data(ts->client, + F54_ANALOG_DATA_BASE+1, 0x0); + ret = i2c_smbus_write_byte_data(ts->client, + F54_ANALOG_COMMAND_BASE, 0x01);/*get report*/ + checkCMD(10); + tx_datal = i2c_smbus_read_i2c_block_data(ts->client, + F54_ANALOG_DATA_BASE+3, 7, buffer); + + for (x = 0; x < 7; x++) { + if (buffer[x] != 0xff) { + error_count++; + TPD_ERR("step 2:error_count[%d] buff%d[0x%x] ERROR!\n", + error_count, x, buffer[x]); + goto END; + } + } + + ret = synaptics_rmi4_i2c_write_byte(ts->client, 0xff, 0x0); + if (ret < 0) { + TPD_ERR("%s line%d failed\n", __func__, __LINE__); + error_count++; + goto END; + } + + synaptics_hard_reset(ts); + synaptics_read_register_map_page1(ts); + + ret = synaptics_rmi4_i2c_write_byte(ts->client, 0xff, 0x1); + if (ret < 0) { + TPD_ERR("%s line%d failed\n", __func__, __LINE__); + error_count++; + goto END; + } + + /*step 3 :check tx-to-tx and tx-to-vdd*/ + TPD_ERR("step 3:check TRx-TRx & TRx-Vdd short\n"); + ret = i2c_smbus_write_byte_data(ts->client, + F54_ANALOG_DATA_BASE, 0x1A);/*select report type 26*/ + ret = i2c_smbus_write_word_data(ts->client, + F54_ANALOG_DATA_BASE+1, 0x0); + ret = i2c_smbus_write_byte_data(ts->client, + F54_ANALOG_COMMAND_BASE, 0x01);/*get report*/ + checkCMD(80); + tx_datal = i2c_smbus_read_i2c_block_data(ts->client, + F54_ANALOG_DATA_BASE+3, 7, buffer); + buffer[0] &= 0xFC;/*buf = 03*/ + buffer[4] &= 0xFC;/*buf = 03*/ + for (x = 0; x < 7; x++) { + if (buffer[x]) { + error_count++; + TPD_ERR("step 3:error_count[%d] buff%d[0x%x] ERROR!\n", + error_count, x, buffer[x]); + goto END; + } + } + + ret = synaptics_rmi4_i2c_write_byte(ts->client, 0xff, 0x0); + if (ret < 0) { + TPD_ERR("%s line%d failed\n", __func__, __LINE__); + error_count++; + goto END; + } + + /*hard reset TP*/ + synaptics_hard_reset(ts); + synaptics_read_register_map_page1(ts); + + ret = synaptics_rmi4_i2c_write_byte(ts->client, 0xff, 0x1); + if (ret < 0) { + TPD_ERR("%s line%d failed\n", __func__, __LINE__); + error_count++; + goto END; + } + /*Step4 : Check RT133*/ + TPD_ERR("step 4:Check RT133\n"); + ret = i2c_smbus_write_byte_data(ts->client, + F54_ANALOG_DATA_BASE, 0x85);/*select report type 133*/ + ret = i2c_smbus_write_word_data(ts->client, + F54_ANALOG_DATA_BASE+1, 0x0);/*set fifo 0*/ + ret = i2c_smbus_write_byte_data(ts->client, + F54_ANALOG_COMMAND_BASE, 0x01);/*get report*/ + checkCMD_RT133(); + for (y = 0; y < RX_NUM; y++) { + ret = i2c_smbus_read_byte_data(ts->client, + F54_ANALOG_DATA_BASE+3); + tmp_l = ret & 0xff; + ret = i2c_smbus_read_byte_data(ts->client, + F54_ANALOG_DATA_BASE+3); + tmp_h = ret & 0xff; + baseline_data = (tmp_h << 8) | tmp_l; + if (baseline_data > 100) { + error_count++; + TPD_ERR("step 4:error_count[%d] baseline_data%d[0x%x] ERROR!\n", + error_count, y, baseline_data); + goto END; + } + } + /*must add reset for RT150 */ + synaptics_hard_reset(ts); + synaptics_read_register_map_page1(ts); + /*Step 5 : Check RT150 for random touch event*/ + TPD_ERR("Step 5 : Check RT150 for Hybrid Absolute\n"); + ret = i2c_smbus_write_byte_data(ts->client, + F54_ANALOG_DATA_BASE, 0x96);/*select report type 0x96*/ + ret = i2c_smbus_write_word_data(ts->client, + F54_ANALOG_DATA_BASE + 1, 0x00);/*set fifo 00*/ + ret = i2c_smbus_write_byte_data(ts->client, + F54_ANALOG_COMMAND_BASE, 0x01);/*get report*/ + checkCMD(10); + /*all channel 16+33 */ + for (y = 0; y < RX_NUM + TX_NUM ; y++) { + ret = i2c_smbus_read_byte_data(ts->client, + F54_ANALOG_DATA_BASE + 3); + tmp_l = ret & 0xff; + ret = i2c_smbus_read_byte_data(ts->client, + F54_ANALOG_DATA_BASE + 3); + tmp_h = ret & 0xff; + unsigned_baseline_data = (tmp_h << 8) | tmp_l; + + if (unsigned_baseline_data < 10000) { + error_count++; + TPD_ERR("Step5 RT150 ,error_line is y =%d,data = %hu\n", + y, unsigned_baseline_data); + goto END; + } + } +END: + if (fd >= 0) { + sys_close(fd); + set_fs(old_fs); + } + + ret = i2c_smbus_write_byte_data(ts->client, + F54_ANALOG_COMMAND_BASE, 0X02); + delay_qt_ms(60); + ret = i2c_smbus_write_byte_data(ts->client, 0xff, 0x00); + ret = i2c_smbus_write_byte_data(ts->client, F01_RMI_CMD00, 0x01); + /*hard reset TP*/ + synaptics_hard_reset(ts); + synaptics_read_register_map_page1(ts); + +#ifdef SUPPORT_GLOVES_MODE + synaptics_glove_mode_enable(ts); +#endif + synaptics_init_panel(ts); + synaptics_enable_interrupt(ts, 1); + touch_enable(ts); + TPD_ERR("\n\nstep5 reset and open irq complete\n"); + mutex_unlock(&ts->mutex); +#endif + if (readdata_fail == 1) { + TPD_ERR("readdata_fail...try again:%d\n", first_check); + readdata_fail = 0; + goto READDATA_AGAIN; + } +#ifdef ENABLE_TPEDGE_LIMIT + synaptics_tpedge_limitfunc(); +#endif + TPD_ERR("status...first_check:%d:readdata_fail:%d\n", + first_check, readdata_fail); + msm_cpuidle_set_sleep_disable(false); + num_read_chars += snprintf(&(buf[num_read_chars]), 128, + "imageid=0x%lx,deviceid=0x%lx\n", + TP_FW, TP_FW); + num_read_chars += snprintf(&(buf[num_read_chars]), 128, + "left:=%d,right:%d\n", left_ramdata, + right_ramdata); + num_read_chars += snprintf(&(buf[num_read_chars]), 128, + "%d error(s). %s\n", error_count, + error_count?"":"All test passed."); + return num_read_chars; +} + + +static ssize_t tp_baseline_show_with_cbc(struct device_driver *ddri, char *buf) +{ + int ret = 0; + int x,y; + ssize_t num_read_chars = 0; + uint8_t tmp_l = 0,tmp_h = 0; + uint8_t tmp_old, tmp_new; + uint16_t count = 0; + struct synaptics_ts_data *ts = ts_g; + if (ts->is_suspended == 1) + return count; + memset(delta_baseline, 0, sizeof(delta_baseline)); + if (!ts) + return 0; + /*disable irq when read data from IC*/ + touch_disable(ts); + mutex_lock(&ts->mutex); + synaptics_hard_reset(ts); + synaptics_read_register_map_page1(ts); + TPD_DEBUG("\nstep 1:select report type 0x03 baseline\n"); + msm_cpuidle_set_sleep_disable(true); + //step 1:check raw capacitance. + //select report type 0x03/* Report Type */ + ret = synaptics_rmi4_i2c_write_byte(ts->client, + F54_ANALOG_DATA_BASE, 0x03); + if (ret < 0) { + TPDTM_DMESG("step 1: select report type 0x03 failed \n"); + //return sprintf(buf, "i2c err!"); + } + if (version_is_s3508 == 2) { + /* Multi Metric Noise Mitigation Control */ + ret = i2c_smbus_write_byte_data(ts->client, + F54_ANALOG_CONTROL_BASE+20, 0x01); + /* Analog Command 0 *//*force update*/ + ret = i2c_smbus_write_word_data(ts->client, + F54_ANALOG_COMMAND_BASE, 0x04); + checkCMD(10); + TPD_DEBUG("open CBC oK\n"); + /* Analog Control 1 s3508 is 27 s3706 is 27*/ + ret = i2c_smbus_read_byte_data(ts->client, + F54_ANALOG_CONTROL_BASE+23); + tmp_new = ret | 0x20;/*CBC Xmtr carrier select*/ + i2c_smbus_write_byte_data(ts->client, + F54_ANALOG_CONTROL_BASE+23, tmp_new); + } else { + /* Multi Metric Noise Mitigation Control */ + ret = i2c_smbus_write_byte_data(ts->client, + F54_ANALOG_CONTROL_BASE+20, 0x01); + /* 0D CBC Settings */ + ret = i2c_smbus_read_byte_data(ts->client, + F54_ANALOG_CONTROL_BASE+23); + tmp_old = ret&0xff; + TPD_DEBUG("ret = %x ,tmp_old =%x ,tmp_new = %x\n", + ret, tmp_old, (tmp_old | 0x10)); + ret = i2c_smbus_write_byte_data(ts->client, + F54_ANALOG_CONTROL_BASE+23, + (tmp_old | 0x10)); + /* Analog Command 0 *//*force update*/ + ret = i2c_smbus_write_word_data(ts->client, + F54_ANALOG_COMMAND_BASE, 0x04); + checkCMD(10); + TPD_DEBUG("open CBC oK\n"); + /* Analog Control 1 s3508 is 27 s3706 is 27*/ + ret = i2c_smbus_read_byte_data(ts->client, + F54_ANALOG_CONTROL_BASE+27); + tmp_new = ret | 0x20;/*CBC Xmtr carrier select*/ + ret = i2c_smbus_write_byte_data(ts->client, + F54_ANALOG_CONTROL_BASE+27, tmp_new); + } + ret = i2c_smbus_write_word_data(ts->client, + F54_ANALOG_COMMAND_BASE, 0x04); + + /*force F54_ANALOG_CMD00*/ + ret = synaptics_rmi4_i2c_write_byte(ts->client, + F54_ANALOG_COMMAND_BASE, 0X04); + checkCMD(10); + TPD_DEBUG("forbid Forbid NoiseMitigation oK\n"); + /*Force Cal, F54_ANALOG_CMD00*/ + ret = synaptics_rmi4_i2c_write_byte(ts->client, + F54_ANALOG_COMMAND_BASE, 0X02); + checkCMD(10); + TPDTM_DMESG("Force Cal oK\n"); + /* Report Index LSB //set fifo 00 */ + ret = synaptics_rmi4_i2c_write_word(ts->client, + F54_ANALOG_DATA_BASE+1, 0x00); + /*get report*/ + ret = synaptics_rmi4_i2c_write_byte(ts->client, + F54_ANALOG_COMMAND_BASE, 0x01); + checkCMD(10); + count = 0; + for(x = 0;x < TX_NUM; x++) { + TPD_DEBUG("\n[%d]",x); + num_read_chars += sprintf(&(buf[num_read_chars]), "\n[%d]",x); + for(y = 0; y < RX_NUM; y++){ + ret = synaptics_rmi4_i2c_read_byte(ts->client,F54_ANALOG_DATA_BASE+3); + tmp_l = ret&0xff; + ret = synaptics_rmi4_i2c_read_byte(ts->client,F54_ANALOG_DATA_BASE+3); + tmp_h = ret&0xff; + delta_baseline[x][y] = (tmp_h<<8)|tmp_l; + TPD_DEBUG("%d,",delta_baseline[x][y]); + num_read_chars += sprintf(&(buf[num_read_chars]), "%d ",delta_baseline[x][y]); + } + } + + ret = synaptics_rmi4_i2c_write_byte(ts->client,F54_ANALOG_COMMAND_BASE,0X02); + delay_qt_ms(60); + msm_cpuidle_set_sleep_disable(false); + synaptics_enable_interrupt(ts,1); + mutex_unlock(&ts->mutex); + touch_enable(ts); + return num_read_chars; +} + +static ssize_t synaptics_rmi4_baseline_show(struct device *dev, char *buf, bool savefile) +{ + if (version_is_s3508 == 2) { + return synaptics_rmi4_baseline_show_s3706(dev, buf, savefile); + } else { + return synaptics_rmi4_baseline_show_s3508(dev, buf, savefile); + } +} + +static ssize_t tp_test_store(struct device_driver *ddri, + const char *buf, size_t count) +{ + TPDTM_DMESG("tp_test_store is not support\n"); + return count; +} + +static ssize_t synaptics_rmi4_vendor_id_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + if( (tp_dev == TP_G2Y) || (tp_dev == TP_TPK) ) + return sprintf(buf, "%d\n", TP_TPK); + if(tp_dev == TP_TRULY) + return sprintf(buf, "%d\n", TP_TRULY); + if(tp_dev == TP_OFILM) + return sprintf(buf, "%d\n", TP_OFILM); + return sprintf(buf, "%d\n", tp_dev); +} + + +static int synaptics_input_init(struct synaptics_ts_data *ts) +{ + int attr_count = 0; + int ret = 0; + + TPD_DEBUG("%s is called\n",__func__); + ts->input_dev = input_allocate_device(); + if (ts->input_dev == NULL) { + ret = -ENOMEM; + TPD_ERR("synaptics_ts_probe: Failed to allocate input device\n"); + return ret; + } + ts->input_dev->name = TPD_DEVICE;; + ts->input_dev->dev.parent = &ts->client->dev; + 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_TOOL_FINGER, ts->input_dev->keybit); +#ifdef SUPPORT_GESTURE + set_bit(KEY_F4 , ts->input_dev->keybit);//doulbe-tap resume + set_bit(KEY_APPSELECT, ts->input_dev->keybit); + set_bit(KEY_BACK, ts->input_dev->keybit); +#endif + /* For multi touch */ + input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); + input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MINOR, 0,255, 0, 0); + input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0, (ts->max_x-1), 0, 0); + input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, (ts->max_y-1), 0, 0); +#ifdef REPORT_2D_PRESSURE + if (ts->support_ft){ + input_set_abs_params(ts->input_dev,ABS_MT_PRESSURE,0,255, 0, 0); + } +#endif +#ifdef TYPE_B_PROTOCOL + input_mt_init_slots(ts->input_dev, ts->max_num, 0); +#endif + input_set_drvdata(ts->input_dev, ts); + + if(input_register_device(ts->input_dev)) { + TPD_ERR("%s: Failed to register input device\n",__func__); + input_unregister_device(ts->input_dev); + input_free_device(ts->input_dev); + return -1; + } + for (attr_count = 0; attr_count < ARRAY_SIZE(attrs_oem); attr_count++) { + ret = sysfs_create_file(&ts->input_dev->dev.kobj, + &attrs_oem[attr_count].attr); + if (ret < 0) { + dev_err(&ts->client->dev, + "%s: Failed to create sysfs attributes\n", + __func__); + for (attr_count--; attr_count >= 0; attr_count--) { + sysfs_remove_file(&ts->input_dev->dev.kobj, + &attrs_oem[attr_count].attr); + } + return -1; + } + } + return 0; +} + +#include "fw_update_v7.if" +static int check_hardware_version(struct device *dev) +{ + int ret; + struct synaptics_ts_data *ts = dev_get_drvdata(dev); + const struct firmware *fw = NULL; + if(!ts->client) { + TPD_ERR("i2c client point is NULL\n"); + return 0; + } + ret = request_firmware(&fw, ts->fw_name, dev); + if (ret < 0) { + TPD_ERR("Request firmware failed - %s (%d)\n",ts->fw_name, ret); + return ret; + } + ret = fwu_start_reflash_check(fw->data,ts->client); + release_firmware(fw); + if (ret < 0) + return -1; + else + return ret; +} +static int check_version = 0; + +/*FW Update Func for s3706*/ +static int synaptics_rmi4_sw_reset(struct i2c_client *client) +{ + int retval; + unsigned char command = 0x01; + + retval = synaptics_rmi4_i2c_write_block(client, + F01_RMI_CTRL_BASE, + sizeof(command), + &command); + + return retval; +} + +static int synaptics_rmi4_reset_device(struct i2c_client *client, + bool rebuild) +{ + int retval; + + rebuild = 1; + /*mutex_lock(&(rmi4_data->rmi4_reset_mutex));*/ + + retval = synaptics_rmi4_sw_reset(client); + if (retval < 0) { + TPD_ERR("%s: Failed to issue reset command\n", + __func__); + return retval; + } + /*mutex_unlock(&(rmi4_data->rmi4_reset_mutex));*/ + return retval; +} + +/*FW Update Func**/ +static int synatpitcs_fw_update(struct device *dev, bool force) +{ + struct synaptics_ts_data *ts = dev_get_drvdata(dev); + const struct firmware *fw = NULL; + int ret; + char fw_id_temp[20]; + uint8_t buf[8]; + unsigned long int CURRENT_FIRMWARE_ID = 0; + + static bool check_onetime = true; + + TPD_DEBUG("%s is called\n",__func__); + if(!ts->client) { + TPD_ERR("i2c client point is NULL\n"); + return 0; + } + if (!strncmp(ts->manu_name, "S3706", 5)) { + TPD_ERR("enter version 17819 update mode\n"); + ret = request_firmware(&fw, ts->fw_name, dev); + if (ret < 0) { + TPD_ERR("Request firmware failed - %s (%d)\n", + ts->fw_name, ret); + return ret; + } + } else if (!strncmp(ts->manu_name, "S3718", 5)) { + if(check_onetime){ + check_onetime = false; + check_version = check_hardware_version(dev); + TPD_ERR("%s:first check hardware version %d\n",__func__,check_version); + if(check_version < 0){ + TPD_ERR("checkversion fail....\n"); + return -1; + } + } + + if(1 == check_version ) { + TPD_DEBUG("enter version 15801 update mode\n"); + strcpy(ts->fw_name,"tp/fw_synaptics_15801.img"); + //push_component_info(TP, ts->fw_id, "S3718_vA"); + ret = request_firmware(&fw, ts->fw_name, dev); + if (ret < 0) { + TPD_ERR("Request firmware failed - %s (%d)\n",ts->fw_name, ret); + return ret; + } + + }else{ + TPD_DEBUG("enter version 15801 vb update mode\n"); + //push_component_info(TP, ts->fw_id, "S3718_vB"); + ret = request_firmware(&fw, ts->fw_name, dev); + if (ret < 0) { + TPD_ERR("Request firmware failed - %s (%d)\n",ts->fw_name, ret); + return ret; + } + } + + }else if(!strncmp(ts->manu_name,"s3508",5) || !strncmp(ts->manu_name,"15811",5)){ + TPD_ERR("enter version 16859 update mode\n"); + //push_component_info(TP, ts->fw_id, "s3508"); + ret = request_firmware(&fw, ts->fw_name, dev); + if (ret < 0) { + TPD_ERR("Request firmware failed - %s (%d)\n",ts->fw_name, ret); + return ret; + } + }else{ + TPD_ERR("firmware name not match\n"); + return -1; + } + + ret = synapitcs_ts_update(ts->client, fw->data, fw->size, force); + if(ret < 0){ + TPD_ERR("FW update not success try again\n"); + ret = synapitcs_ts_update(ts->client, fw->data, fw->size, true); + if(ret < 0){ + TPD_ERR("FW update failed twice, quit updating process!\n"); + return ret; + } + } + release_firmware(fw); + ret = synaptics_rmi4_i2c_write_byte(ts->client, 0xff, 0x0); + ret = synaptics_rmi4_i2c_read_block(ts->client, + F34_FLASH_CTRL00, 8, buf); + CURRENT_FIRMWARE_ID = (buf[0]<<24) | (buf[1]<<16) | + (buf[2]<<8) | buf[3]; + if (version_is_s3508 == 2) + CURRENT_FIRMWARE_ID = CURRENT_FIRMWARE_ID << 32 | + ((buf[4]<<24) | (buf[5]<<16) | (buf[6]<<8) | buf[7]); + TPD_ERR("CURRENT_FIRMWARE_ID 0x%lx!\n", CURRENT_FIRMWARE_ID); + snprintf(fw_id_temp, 20, "0x%lx", CURRENT_FIRMWARE_ID); + strcpy(ts->fw_id,fw_id_temp); + TP_FW = CURRENT_FIRMWARE_ID; + report_key_point_y = ts->max_y*button_map[2]/LCD_HEIGHT; +#ifdef SUPPORT_GLOVES_MODE + synaptics_glove_mode_enable(ts); +#endif + synaptics_init_panel(ts); + synaptics_enable_interrupt(ts,1); + return 0; +} + +static ssize_t synaptics_update_fw_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct synaptics_ts_data *data = dev_get_drvdata(dev); + return snprintf(buf, 2, "%d\n", data->loading_fw); +} + +static ssize_t synaptics_update_fw_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct synaptics_ts_data *ts = dev_get_drvdata(dev); + unsigned long val; + int rc; + + int bootmode; + + bootmode = get_boot_mode(); + TPD_ERR("synaptics bootmode %d !\n", bootmode); + if ((bootmode == MSM_BOOT_MODE__FACTORY) + || (bootmode == MSM_BOOT_MODE__RF) + || (bootmode == MSM_BOOT_MODE__WLAN)) { + TPD_ERR("synaptics disable tp update firmware update\n"); + return size; + } + + if (ts->is_suspended && ts->support_hw_poweroff){ + TPD_ERR("power off firmware abort!\n"); + return size; + } + if (version_is_s3508 == 1) { + if (strncmp(ts->manu_name,"s3508",5) && strncmp(ts->manu_name,"15811",5)){ + TPD_ERR("product name[%s] do not update!\n",ts->manu_name); + return size; + } + } else if (version_is_s3508 == 2) { + if (strncmp(ts->manu_name, "S3706", 5)) { + TPD_ERR("product name[%s] do not update!\n", + ts->manu_name); + return size; + } + }else{ + if (strncmp(ts->manu_name,"S3718",5)){ + TPD_ERR("product name[%s] do not update!\n",ts->manu_name); + return size; + } + } + TPD_ERR("start update ******* fw_name:%s,ts->manu_name:%s\n",ts->fw_name,ts->manu_name); + + if (size > 2) + return -EINVAL; + + rc = kstrtoul(buf, 10, &val); + if (rc != 0) + return rc; + + if(!val) + val = force_update; + + touch_disable(ts); + mutex_lock(&ts->mutex); + ts->loading_fw = true; + synatpitcs_fw_update(dev, val); + ts->loading_fw = false; + mutex_unlock(&ts->mutex); + touch_enable(ts); + force_update = 0; + return size; +} +/*********************FW Update Func End*************************************/ + + +static ssize_t synaptics_test_limit_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct synaptics_ts_data *ts = dev_get_drvdata(dev); + int ret = 0; + uint16_t *prow = NULL; + uint16_t *prowcbc = NULL; + const struct firmware *fw = NULL; + struct test_header *ph = NULL; + int i = 0; + int temp = 0; + static int cat_cbc_change = 0; + ret = request_firmware(&fw, ts->test_limit_name, dev); + if (ret < 0) { + TPD_ERR("Request firmware failed - %s (%d)\n", + ts->test_limit_name, ret); + temp = temp + sprintf(&buf[temp],"Request failed,Check the path %d",temp); + return temp; + } + + 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_DEBUG("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"); + if(cat_cbc_change == 0 || ph->withCBC == 0) { + temp += sprintf(buf, "Without cbc:"); + for(i = 0 ;i < (ph->array_limit_size/2 ); i++){ + if(i % (2*RX_NUM) == 0) + temp += sprintf(&(buf[temp]), "\n[%d] ",(i/RX_NUM)/2); + temp += sprintf(&buf[temp],"%d,",prow[i]); + printk("%d,",prow[i]); + } + cat_cbc_change = 1; + }else{ + temp += sprintf(buf, "With cbc:"); + cat_cbc_change = 0; + if( ph->withCBC == 0){ + return temp; + } + for(i = 0 ;i < (ph->array_limitcbc_size/2 ); i++){ + if(i % (2*RX_NUM) == 0) + temp += sprintf(&(buf[temp]), "\n[%d] ",(i/RX_NUM)/2); + temp += sprintf(&buf[temp],"%d,",prowcbc[i]); + printk("%d,",prowcbc[i]); + } + } + release_firmware(fw); + return temp; +} + +static ssize_t synaptics_test_limit_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + return size; +} + +static ssize_t tp_doze_time_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret = 0; + int doze_time = 0; + struct synaptics_ts_data *ts = dev_get_drvdata(dev); + + ret = synaptics_rmi4_i2c_write_byte(ts->client, 0xff, 0x00); + if (ret < 0) + return snprintf(buf, 16, "switch page err\n"); + + doze_time = i2c_smbus_read_byte_data(ts->client, F01_RMI_CTRL02); + return snprintf(buf, 2, "%d\n", doze_time); +} + +static ssize_t tp_doze_time_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + return size; +} + +static int touch_hold_en(struct synaptics_ts_data *ts, bool enable) +{ + int ret = 0; + int touch_hold_enable = 0; + + /* SYNA_F51_CUSTOM_CTRL20_00 0x0428*/ + ret = synaptics_rmi4_i2c_write_byte(ts->client, 0xff, 0x04); + if (ret < 0) + TPD_ERR("%s: set page 0x04 fail!\n", __func__); + touch_hold_enable = i2c_smbus_read_byte_data(ts->client, 0x2c); + + if (enable == 1) + touch_hold_enable = touch_hold_enable | 0x01; + else if (enable == 0) + touch_hold_enable = touch_hold_enable & 0xfe; + + ret = synaptics_rmi4_i2c_write_byte(ts->client, + 0x2c, touch_hold_enable); + if (ret < 0) + TPD_ERR("%s: set reg fail!\n", __func__); + + ret = synaptics_rmi4_i2c_write_byte(ts->client, 0xff, 0x00); + if (ret < 0) + TPD_ERR("%s: set page 00 fail!\n", __func__); + + return ret; + +} + +int tp_single_tap_en(struct synaptics_ts_data *ts, bool enable) +{ + uint8_t ret = 0; + + ret = synaptics_rmi4_i2c_write_byte(ts->client, 0xff, 0x04); + if (ret < 0) + return ret; + if (enable) { + ret = synaptics_rmi4_i2c_write_byte(ts->client, + 0x22, 0x01); + ret = synaptics_rmi4_i2c_write_byte(ts->client, + 0x23, 0x1e); + ret = synaptics_rmi4_i2c_write_byte(ts->client, + 0x24, 0x1e); + ret = synaptics_rmi4_i2c_write_byte(ts->client, + 0x25, 0x32); + ret = i2c_smbus_write_word_data(ts->client, + F54_ANALOG_COMMAND_BASE, 0x04); // force update + TPD_DEBUG("%s: force update %x\n", + __func__, F54_ANALOG_COMMAND_BASE); + } else + ret = synaptics_rmi4_i2c_write_byte(ts->client, + 0x22, 0x00); + + ret = synaptics_rmi4_i2c_write_byte(ts->client, 0xff, 0x00); + if (ret < 0) + TPD_ERR("%s: set page 00 fail!\n", __func__); + + return ret; +} + +static ssize_t tp_gesture_touch_hold_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret = 0; + int touch_hold_enable = 0; + struct synaptics_ts_data *ts = dev_get_drvdata(dev); + /* SYNA_F51_CUSTOM_CTRL20_00 0x0428*/ + ret = synaptics_rmi4_i2c_write_byte(ts->client, 0xff, 0x04); + if (ret < 0) + return snprintf(buf, 16, "switch page err\n"); + touch_hold_enable = i2c_smbus_read_byte_data(ts->client, 0x2c); + ret = synaptics_rmi4_i2c_write_byte(ts->client, 0xff, 0x00); + if (ret < 0) + TPD_ERR("%s: set page 00 fail!\n", __func__); + return snprintf(buf, 6, "0x%x\n", touch_hold_enable); +} + +static ssize_t tp_gesture_touch_hold_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + int tmp = 0; + int touch_hold_enable = 0; + int touchhold_tmp = 0; + int ret = 0; + int touch_hold_retry = 0; + struct synaptics_ts_data *ts = dev_get_drvdata(dev); + + ret = kstrtoint(buf, 10, &tmp); + if (ret < 0) { + TPDTM_DMESG("invalid content: '%s', length = %zd\n", buf, size); + return size; + } + + TPD_ERR("%s: set %d\n", __func__, tmp); + if (tmp == 2 && ts->fp_aod_cnt > 0) { + ts->fp_up_down = 0; + ts->unlock_succes = 1; + return size; + } + + if (tmp == 3) { + ts->unlock_succes = 0; + return size; + } + + mutex_lock(&ts->mutex); + /* SYNA_F51_CUSTOM_CTRL20_00 0x0428*/ + while (1) { + if((tmp != 1) && (tmp != 0)) + break; + touch_hold_retry ++; + ret = synaptics_rmi4_i2c_write_byte(ts->client, + 0xff, 0x04); + if (ret < 0) + TPD_ERR("set page first fail!\n"); + + touch_hold_enable = i2c_smbus_read_byte_data(ts->client, 0x2c); + TPDTM_DMESG("%s:read reg 0x%x\n", + __func__, touch_hold_enable); + + if (tmp == 1) { + touch_hold_enable = touch_hold_enable | 0x01; + ts->en_up_down = 1; + } else if (tmp == 0) { + touch_hold_enable = touch_hold_enable & 0xfe; + ts->en_up_down = 0; + } + ret = synaptics_rmi4_i2c_write_byte(ts->client, + 0x2c, touch_hold_enable); + if (ret < 0) + TPD_ERR("set first fail!\n"); + touchhold_tmp = i2c_smbus_read_byte_data(ts->client, 0x2c); + TPDTM_DMESG("%s:read reg again 0x%x,0x%x,%d\n", __func__, + touch_hold_enable, touchhold_tmp, touch_hold_retry); + ret = synaptics_rmi4_i2c_write_byte(ts->client, + 0xff, 0x00); + if (ret < 0) + TPD_ERR("set page 00 fail!\n"); + if (touch_hold_enable == touchhold_tmp) + break; + if (touch_hold_retry == 5) + break; + msleep(10); + } + mutex_unlock(&ts->mutex); + + return size; +} + +//static DRIVER_ATTR(tp_baseline_image_with_cbc, 0664, tp_baseline_show_with_cbc, tp_test_store); +static DEVICE_ATTR(test_limit, 0664, synaptics_test_limit_show, synaptics_test_limit_store); +static DRIVER_ATTR(tp_baseline_image, 0664, tp_baseline_show, tp_delta_store); +static DRIVER_ATTR(tp_baseline_image_with_cbc, 0664, tp_baseline_show_with_cbc, tp_test_store); +static DRIVER_ATTR(tp_delta_image, 0664, tp_rawdata_show, NULL); +static DRIVER_ATTR(tp_debug_log, 0664, tp_show, store_tp); +static DEVICE_ATTR(tp_fw_update, 0664, synaptics_update_fw_show, synaptics_update_fw_store); +static DEVICE_ATTR(tp_doze_time, 0664, tp_doze_time_show, tp_doze_time_store); +static DEVICE_ATTR(tp_gesture_touch_hold, 0664, + tp_gesture_touch_hold_show, tp_gesture_touch_hold_store); +static int synaptics_dsx_pinctrl_init(struct synaptics_ts_data *ts); + +static ssize_t tp_debug_log_write_func( + struct file *file, const char *buffer, + size_t count, loff_t *ppos) +{ + int ret, tmp = 0; + char buf[4] = {0}; + + if (count > 4) + return count; + if (copy_from_user(buf, buffer, count)) { + TPD_ERR(KERN_INFO "%s: read proc input error.\n", __func__); + return count; + } + + ret = kstrtoint(buf, 10, &tmp); + if (ret >= 0) { + tp_debug = tmp; + } else { + TPDTM_DMESG("invalid content: '%s', length = %zd\n", + buf, count); + } + return count; +} + +static ssize_t tp_debug_log_read_func( + struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[4]; + + ret = snprintf(page, 4, "%d\n", tp_debug); + ret = simple_read_from_buffer(user_buf, count, + ppos, page, strlen(page)); + return ret; +} + +static const struct file_operations tp_debug_log_proc_fops = { + .write = tp_debug_log_write_func, + .read = tp_debug_log_read_func, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static ssize_t synaptics_main_reg_read_func( + struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[PAGESIZE]; + int device_contrl = 0; + int doze_interval = 0; + unsigned char reportbuf[4] = {0}; + struct synaptics_ts_data *ts = ts_g; + + if (!ts) + return ret; + + ret = synaptics_rmi4_i2c_write_byte(ts->client, 0xff, 0x00); + if (ret < 0) + TPD_ERR("%s: chage page failed:%d\n", __func__, ret); + + ret = i2c_smbus_read_byte_data(ts->client, F01_RMI_CTRL00); + if (ret < 0) + TPD_ERR("%s: read failed:%d\n", __func__, ret); + + TPD_ERR("%s Device Control 0x%x=0x%x\n", __func__, F01_RMI_CTRL00, ret); + device_contrl = ret; + + ret = i2c_smbus_read_byte_data(ts->client, F01_RMI_CTRL02); + if (ret < 0) + TPD_ERR("%s: read failed:%d\n", __func__, ret); + + TPD_ERR("Doze Interval 0x%x=0x%x\n", F01_RMI_CTRL02, ret); + doze_interval = ret; + + ret = i2c_smbus_read_i2c_block_data(ts->client, F12_2D_CTRL20, + 3, &(reportbuf[0x0])); + if (ret < 0) + TPD_ERR("read reg F12_2D_CTRL20[0x%x] failed\n", F12_2D_CTRL20); + + TPD_ERR("Gesture Report Flag 0x%x=[2]:0x%x\n", + F12_2D_CTRL20, reportbuf[2]); + + ret = snprintf(page, 128, "0x%x:0x%x:0x%x\n", + device_contrl, doze_interval, reportbuf[2]); + ret = simple_read_from_buffer(user_buf, count, + ppos, page, strlen(page)); + return ret; +} + +static const struct file_operations tp_main_reg = { + .read = synaptics_main_reg_read_func, + .open = simple_open, + .owner = THIS_MODULE, +}; + + +static ssize_t tp_reset_write_func (struct file *file, const char *buffer, size_t count, loff_t *ppos) +{ + int ret, write_flag, i; + char buf[10] = {0}; + struct synaptics_ts_data *ts = ts_g; + + if (count > 10) + return count; + if (!ts) + return count; + if (ts->loading_fw) { + TPD_ERR("%s FW is updating break!!\n", __func__); + return count; + } + if (copy_from_user(buf, buffer, count)) { + TPD_ERR(KERN_INFO "%s: read proc input error.\n", __func__); + return count; + } + ret = sscanf(buf, "%d", &write_flag); + + TPD_ERR("%s write [%d]\n",__func__,write_flag); + if (1 == write_flag) + { + ret = synaptics_soft_reset(ts); + } + else if(2 == write_flag) + { + synaptics_hard_reset(ts); + } + else if(3 == write_flag) + { + disable_irq_nosync(ts->irq); + } + else if(4 == write_flag) + { + enable_irq(ts->irq); + } + else if(8 == write_flag) + { + touch_enable(ts); + } + else if(9 == write_flag) + { + touch_disable(ts); + } + else if(5 == write_flag) + { + synaptics_read_register_map(ts); + } + else if(6 == write_flag) + { + 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, 1); + input_mt_slot(ts->input_dev, i); + input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0); + } + #ifndef TYPE_B_PROTOCOL + input_mt_sync(ts->input_dev); + #endif + input_report_key(ts->input_dev, BTN_TOOL_FINGER, 0); + input_sync(ts->input_dev); + } + return count; +} + +//chenggang.li@bsp add for 14045 +static const struct file_operations base_register_address= { + .write = synap_write_address, + .read = synap_read_address, + .open = simple_open, + .owner = THIS_MODULE, +}; + + +//wangwenxue@BSP add for change baseline_test to "proc\touchpanel\baseline_test" begin +static const struct file_operations i2c_device_test_fops = { + .read = i2c_device_test_read_func, + .open = simple_open, + .owner = THIS_MODULE, +}; + +//wangwenxue@BSP add for change baseline_test to "proc\touchpanel\baseline_test" begin +static const struct file_operations tp_baseline_test_proc_fops = { + .read = tp_baseline_test_read_func, + .open = simple_open, + .owner = THIS_MODULE, +}; +//wangwenxue@BSP add for change baseline_test to "proc\touchpanel\baseline_test" end + +#ifdef SUPPORT_GLOVES_MODE +static const struct file_operations glove_mode_enable_proc_fops = { + .write = tp_glove_write_func, + .read = tp_glove_read_func, + .open = simple_open, + .owner = THIS_MODULE, +}; +#endif + +static const struct file_operations sleep_mode_enable_proc_fops = { + .write = tp_sleep_write_func, + .read = tp_sleep_read_func, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static const struct file_operations tp_reset_proc_fops = { + .write = tp_reset_write_func, + //.read = tp_sleep_read_func, + .open = simple_open, + .owner = THIS_MODULE, +}; +static const struct file_operations vendor_id_proc_fops = { + .read = vendor_id_read_func, + .open = simple_open, + .owner = THIS_MODULE, +}; +static int set_changer_bit(struct synaptics_ts_data *ts) +{ + int mode; + int ret; + mode = i2c_smbus_read_byte_data(ts_g->client, F01_RMI_CTRL00); + if (ts->changer_connet) + mode = mode | 0x20; + else + mode = mode & 0xDF; + ret = i2c_smbus_write_byte_data(ts_g->client, F01_RMI_CTRL00, mode); + return ret; +} +static ssize_t changer_read_func(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[PAGESIZE]; + struct synaptics_ts_data *ts = ts_g; + if(!ts) + return ret; + ret = sprintf(page, "the changer is %s!\n", ts->changer_connet?("conneted"):("disconneted")); + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + return ret; +} + +static ssize_t changer_write_func(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + struct synaptics_ts_data *ts= ts_g; + int ret = 0 ; + char buf[4] = {0}; + + if (count > 2) + return count; + + if (copy_from_user(buf, buffer, count)) { + TPD_ERR(KERN_INFO "%s: write proc input error.\n", __func__); + return count; + } + + if (-1 == sscanf(buf, "%d", &ret)) { + TPD_ERR("%s sscanf error\n", __func__); + return count; + } + if(!ts) + return count; + if( (ret == 0 ) || (ret == 1) ){ + ts->changer_connet = ret; + ret = set_changer_bit(ts); + } + TPDTM_DMESG("%s:ts->changer_connet = %d\n",__func__,ts->changer_connet); + return count; +} +static const struct file_operations changer_ops = { + .write = changer_write_func, + .read = changer_read_func, + .open = simple_open, + .owner = THIS_MODULE, +}; + +static void set_doze_time(int doze_time) +{ + static int pre_doze_time; + int ret = 0; + struct synaptics_ts_data *ts = ts_g; + + /* change to page 0 */ + if (ts == NULL) { + TPD_ERR("ts crash!\n"); + return; + } + if (pre_doze_time == doze_time) { + TPD_ERR("set time have already been set\n"); + return; + } + + ret = synaptics_rmi4_i2c_write_byte(ts->client, 0xff, 0x00); + if (ret < 0) { + TPD_ERR("%s: chage page failed:%d\n", __func__, ret); + return; + } + + TPD_ERR("%s: set doze time: %d\n", __func__, doze_time); + ret = i2c_smbus_write_byte_data(ts->client, F01_RMI_CTRL02, doze_time); + if (ret < 0) { + TPD_ERR("%s: set doze time err:%d\n", __func__, ret); + return; + } + pre_doze_time = doze_time; + + /* use the read out circle to delay */ + ret = i2c_smbus_read_byte_data(ts->client, F01_RMI_CTRL02); + if (ret < 0) + return; + if (ret != doze_time) { + TPD_ERR("reset doze time\n"); + ret = i2c_smbus_write_byte_data(ts->client, + F01_RMI_CTRL02, doze_time); + if (ret < 0) { + TPD_ERR("%s: reset doze time err:%d\n", __func__, ret); + return; + } + } +} + +#define SUBABS(x,y) ((x)-(y)) +static int tp_baseline_get(struct synaptics_ts_data *ts, bool flag) +{ + int ret = 0; + int x, y; + uint8_t *value; + int k = 0; + int touch_hold_enable = 0; + int touch_hold_retry = 0; + + if(!ts) + return -1; + + atomic_set(&ts->is_stop,1); + touch_disable(ts); + TPD_DEBUG("%s start!\n",__func__); + value = kzalloc(TX_NUM*RX_NUM*2, GFP_KERNEL); + memset(delta_baseline,0,sizeof(delta_baseline)); + + mutex_lock(&ts->mutex); + if (ts->gesture_enable) { + synaptics_enable_interrupt_for_gesture(ts,false); + synaptics_mode_change(0x00); + //change to active later getbase data + } else { + synaptics_mode_change(0x00); + //change to active later getbase data + } + ret = synaptics_rmi4_i2c_write_byte(ts->client, 0xff, 0x1); + + ret = i2c_smbus_write_byte_data(ts->client, F54_ANALOG_DATA_BASE, 0x03);//select report type 0x03 + ret = i2c_smbus_write_word_data(ts->client, F54_ANALOG_DATA_BASE+1, 0);//set fifo 00 + ret = i2c_smbus_write_byte_data(ts->client, F54_ANALOG_COMMAND_BASE, 0x01);//get report + checkCMD(10); + + ret = synaptics_rmi4_i2c_read_block(ts->client,F54_ANALOG_DATA_BASE+3,2*TX_NUM*RX_NUM,value); + for( x = 0; x < TX_NUM; x++ ){ + for( y = 0; y < RX_NUM; y++ ){ + delta_baseline[x][y] = (int16_t)(((uint16_t)( value [k])) | ((uint16_t)( value [k+1] << 8))); + k = k + 2; + + if (flag) + delta[x][y] = SUBABS(delta_baseline[x][y],baseline[x][y]); + else + baseline[x][y] = delta_baseline[x][y]; + } + } + //ret = i2c_smbus_write_byte_data(ts->client, + //F54_ANALOG_COMMAND_BASE, 0X02); + + if (ts->project_version != 0x03) { + ret = synaptics_rmi4_i2c_write_byte(ts->client, + 0xff, 0x0); + ret = i2c_smbus_write_byte_data(ts->client, + F01_RMI_CMD_BASE, 0x01);//soft reset + msleep(100); + TPD_DEBUG("resume soft reset"); + } else { + if ((not_getbase == 0) && (ts->unlock_succes == 0)) { + TPD_DEBUG("not touchhold status reset\n"); + ret = synaptics_rmi4_i2c_write_byte(ts->client, + 0xff, 0x0); + ret = i2c_smbus_write_byte_data(ts->client, + F01_RMI_CMD_BASE, 0x01);//soft reset + msleep(100); + } + } + mutex_unlock(&ts->mutex); + atomic_set(&ts->is_stop, 0); + if (ts->gesture_enable) + set_doze_time(1); + touch_enable(ts); +#ifdef ENABLE_TPEDGE_LIMIT + synaptics_tpedge_limitfunc(); +#endif + if (ts->project_version == 0x03) { + ts->fp_up_down = 0; + TPD_DEBUG("%s:fp_down_up %d gesture %d, en_down_up %d\n", + __func__, ts->fp_up_down, + ts->in_gesture_mode, ts->en_up_down); + while (ts->en_up_down) { + touch_hold_enable = 0; + touch_hold_retry++; + ret = synaptics_rmi4_i2c_write_byte(ts->client, + 0xff, 0x04); + if (ret < 0) + TPD_ERR("set page first fail!\n"); + touch_hold_enable = + i2c_smbus_read_byte_data(ts->client, 0x2c); + TPDTM_DMESG("%s:read reg 0x%x\n", + __func__, touch_hold_enable); + touch_hold_enable = touch_hold_enable | 0x01; + ret = synaptics_rmi4_i2c_write_byte(ts->client, + 0x2c, touch_hold_enable); + if (ret < 0) + TPD_ERR("set first fail!\n"); + ret = i2c_smbus_read_byte_data(ts->client, 0x2c); + TPDTM_DMESG("%s:read reg again 0x%x,0x%x\n", __func__, + touch_hold_enable, ret); + ret = synaptics_rmi4_i2c_write_byte(ts->client, + 0xff, 0x00); + if (ret < 0) + TPD_ERR("set page 00 fail!\n"); + if (touch_hold_enable == ret) + break; + if (touch_hold_retry == 3) + break; + } + } + TPD_DEBUG("%s end! \n",__func__); + kfree(value); + return 0; +} +static void tp_baseline_get_work(struct work_struct *work) +{ + struct synaptics_ts_data *ts= ts_g; + + tp_baseline_get(ts, true);//get the delta data +} + +static ssize_t touch_press_status_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + int x,y; + int press_points = 0; + int points_misspresee =0; + int str_n = 0; + + char *page = kzalloc(1024*2,GFP_KERNEL); + if (!page){ + TPD_ERR("%s malloc memery error!",__func__); + return -ENOMEM; + } + TPD_ERR("%s",__func__); + + for (x = 0; x < TX_NUM; x++) { + for (y = 0; y < RX_NUM; y++) { + if (ts_g->support_1080x2160_tp) { + if (x > (TX_NUM-1) || y > (RX_NUM-15)) + continue; + } else { + if (x > (TX_NUM-1) || y < (RX_NUM-12)) + continue; + } + if ((delta[x][y] < -30) && (delta[x][y] > -250)) + { + //str_n += sprintf(&page[str_n],"x%d,y%d = %4d\n", x, y, delta[x][y]); + press_points++; + } + if((delta[x][y] > 30) && (delta[x][y] < 200)) + points_misspresee ++; + } + + } + + if(points_misspresee > 4) + get_tp_base = 0; + TPD_ERR("points_mispressee num:%d,get_tp_base:%d\n",points_misspresee,get_tp_base); + str_n += sprintf(&page[str_n], "\n%s %d points delta > [25]\n",(press_points>4)?"near":"away", press_points); + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + kfree(page); + return ret; +} + +static ssize_t touch_press_status_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + struct synaptics_ts_data *ts= ts_g; + int ret = 0 ; + char buf[4] = {0}; + + if (count > 2) + return count; + + if (copy_from_user(buf, buffer, count)) { + TPD_ERR("%s write error\n", __func__); + return count; + } + if (-1 == sscanf(buf, "%d", &ret)) { + TPD_ERR("%s sscanf error\n", __func__); + return count; + } + if(!ts) + return count; + + TPD_ERR("%s write %d\n",__func__,ret); + if (ret == 0){ + tp_baseline_get(ts,false); + } + else if(ret == 1) { + if (0 == ts->gesture_enable) + queue_delayed_work(get_base_report, &ts->base_work,msecs_to_jiffies(120)); + else + queue_delayed_work(get_base_report, &ts->base_work,msecs_to_jiffies(1)); + } + return count; +} +static const struct file_operations touch_press_status = { + .write = touch_press_status_write, + .read = touch_press_status_read, + .open = simple_open, + .owner = THIS_MODULE, +}; + +#ifdef ENABLE_TPEDGE_LIMIT +static ssize_t limit_enable_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + ssize_t ret =0; + char page[PAGESIZE]; + + TPD_DEBUG("the limit_enable is: %d\n", limit_enable); + ret = sprintf(page, "%d\n", limit_enable); + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + return ret; +} + +static ssize_t limit_enable_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + int ret; + char buf[8]={0}; + int limit_mode = 0; + + if (version_is_s3508 == 2) { + F51_GRIP_CONFIGURATION = F51_CUSTOM_CTRL_BASE+0x0a; + } else if (version_is_s3508 == 0) { + F51_GRIP_CONFIGURATION = F51_CUSTOM_CTRL_BASE+0x34; + } else if (version_is_s3508 == 1) { + F51_GRIP_CONFIGURATION = F51_CUSTOM_CTRL_BASE+0x1b; + } else + F51_GRIP_CONFIGURATION = F51_CUSTOM_CTRL_BASE+0x0a; + + if( count > 2) + count = 2; + if(ts_g == NULL) + { + TPD_ERR("ts_g is NULL!\n"); + return -1; + } + if(copy_from_user(buf, buffer, count)) + { + TPD_DEBUG("%s: read proc input error.\n", __func__); + return count; + } + + if('0' == buf[0]){ + limit_enable = 0; + }else if('1' == buf[0]){ + limit_enable = 1; + } + msleep(30); + mutex_lock(&ts_g->mutex); + ret = i2c_smbus_write_byte_data(ts_g->client, 0xff, 0x4); + limit_mode = i2c_smbus_read_byte_data(ts_g->client, + F51_GRIP_CONFIGURATION); + TPD_ERR("%s_proc limit_enable =%d,mode:0x%x,grip:0x%x!\n", + __func__, limit_enable, limit_mode, + F51_GRIP_CONFIGURATION); + if(limit_mode){ + i2c_smbus_write_byte_data(ts_g->client, 0xff, 0x4); + if(0 == limit_enable) + { + limit_mode = limit_mode & 0xFE; + ret = i2c_smbus_write_byte_data(ts_g->client, + F51_GRIP_CONFIGURATION, limit_mode); + } + else if(1 == limit_enable) + { + limit_mode = limit_mode | 0x1; + ret = i2c_smbus_write_byte_data(ts_g->client, + F51_GRIP_CONFIGURATION, limit_mode); + } + } + i2c_smbus_write_byte_data(ts_g->client, 0xff, 0x0); + mutex_unlock(&ts_g->mutex); + return count; +} + +static const struct file_operations proc_limit_enable = +{ + .read = limit_enable_read, + .write = limit_enable_write, + .open = simple_open, + .owner = THIS_MODULE, +}; +#endif +#ifdef SUPPORT_TP_TOUCHKEY +static ssize_t key_switch_read_func(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[PAGESIZE]; + struct synaptics_ts_data *ts = ts_g; + if(!ts) + return ret; + TPD_ERR("%s left:%s right:%s\n", __func__, + key_switch?"key_back":"key_appselect", + key_switch?"key_appselect":"key_back"); + ret = snprintf(page, PAGE_SIZE, "key_switch left:%s right:%s\n", + key_switch?"key_back":"key_appselect", + key_switch?"key_appselect":"key_back"); + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + return ret; +} + +static ssize_t key_switch_write_func(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + char buf[4] = {0}; + struct synaptics_ts_data *ts = ts_g; + if(!ts) + return count; + if(count > 2) + return count; + if(copy_from_user(buf, buffer, count)) + { + TPD_ERR("%s copy error\n", __func__); + return count; + } + sscanf(&buf[0], "%d", &key_switch); + TPD_ERR("%s write [%d]\n", __func__, key_switch); + TPD_ERR("left:%s right:%s\n", key_switch?"key_back":"key_appselect", + key_switch?"key_appselect":"key_back"); + return count; +} + +static const struct file_operations key_switch_proc_fops = { + .write = key_switch_write_func, + .read = key_switch_read_func, + .open = simple_open, + .owner = THIS_MODULE, +}; +static ssize_t key_disable_read_func(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) +{ + int ret = 0; + char page[PAGESIZE]; + struct synaptics_ts_data *ts = ts_g; + if(!ts) + return ret; + TPD_ERR("%s key_back:%s key_appselect:%s\n",__func__,key_back_disable?"disable":"enable",key_appselect_disable?"disable":"enable"); + ret = sprintf(page, "cmd:enable,disable\nkey_back:%s key_appselect:%s\n",key_back_disable?"disable":"enable",key_appselect_disable?"disable":"enable"); + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); + return ret; +} + +static ssize_t key_disable_write_func(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +{ + char buf[PAGESIZE]; + struct synaptics_ts_data *ts = ts_g; + if(!ts) + return count; + if( count > sizeof(buf)){ + TPD_ERR("%s error\n",__func__); + return count; + } + + if(copy_from_user(buf, buffer, count)) + { + TPD_ERR("%s copy error\n", __func__); + return count; + } + if (NULL != strstr(buf,"disable")) + { + key_back_disable =true; + key_appselect_disable = true; + } + else if (NULL != strstr(buf,"enable")) + { + key_back_disable =false; + key_appselect_disable = false; + } + TPD_ERR("%s key_back:%d key_appselect:%d\n",__func__,key_back_disable,key_appselect_disable); + return count; +} + +static const struct file_operations key_disable_proc_fops = { + .write = key_disable_write_func, + .read = key_disable_read_func, + .open = simple_open, + .owner = THIS_MODULE, +}; +#endif +static int init_synaptics_proc(void) +{ + int ret = 0; + struct proc_dir_entry *prEntry_tmp = NULL; + prEntry_tp = proc_mkdir("touchpanel", NULL); + if( prEntry_tp == NULL ){ + ret = -ENOMEM; + TPD_ERR("Couldn't create touchpanel\n"); + } + +#ifdef SUPPORT_GESTURE + prEntry_tmp = proc_create( "gesture_enable", 0666, prEntry_tp, &tp_gesture_proc_fops); + if(prEntry_tmp == NULL){ + ret = -ENOMEM; + TPD_ERR("Couldn't create gesture_enable\n"); + } + prEntry_tmp = proc_create( "gesture_switch", 0666, prEntry_tp, &gesture_switch_proc_fops); + if(prEntry_tmp == NULL){ + ret = -ENOMEM; + TPD_ERR("Couldn't create gesture_switch\n"); + } + prEntry_tmp = proc_create("coordinate", 0444, prEntry_tp, &coordinate_proc_fops); + if(prEntry_tmp == NULL){ + ret = -ENOMEM; + TPD_ERR("Couldn't create coordinate\n"); + } +#endif + +#ifdef SUPPORT_GLOVES_MODE + prEntry_tmp = proc_create( "glove_mode_enable", 0666, prEntry_tp,&glove_mode_enable_proc_fops); + if(prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_ERR("Couldn't create glove_mode_enable\n"); + } +#endif + +#ifdef SUPPORT_TP_SLEEP_MODE + prEntry_tmp = proc_create("sleep_mode_enable", 0666, prEntry_tp, &sleep_mode_enable_proc_fops); + if( prEntry_tmp == NULL ){ + ret = -ENOMEM; + TPD_ERR("Couldn't create sleep_mode_enable\n"); + } +#endif + +#ifdef RESET_ONESECOND + prEntry_tmp = proc_create( "tp_reset", 0666, prEntry_tp, &tp_reset_proc_fops); + if( prEntry_tmp == NULL ){ + ret = -ENOMEM; + TPD_ERR("Couldn't create tp_reset\n"); + } +#endif +#ifdef ENABLE_TPEDGE_LIMIT + prEntry_tmp = proc_create("tpedge_limit_enable", 0666, prEntry_tp, &proc_limit_enable); + if( prEntry_tmp == NULL ){ + ret = -ENOMEM; + TPD_ERR("Couldn't create tp_limit_enable\n"); + } +#endif + + //wangwenxue@BSP add for change baseline_test to "proc\touchpanel\baseline_test" begin + prEntry_tmp = proc_create( "baseline_test", 0666, prEntry_tp, &tp_baseline_test_proc_fops); + if(prEntry_tmp == NULL){ + ret = -ENOMEM; + TPD_ERR("Couldn't create baseline_test\n"); + } + //wangwenxue@BSP add for change baseline_test to "proc\touchpanel\baseline_test" end + //wangwenxue@BSP add for change baseline_test to "proc\touchpanel\i2c_device_test" begin + prEntry_tmp = proc_create( "i2c_device_test", 0666, prEntry_tp, &i2c_device_test_fops); + if(prEntry_tmp == NULL){ + ret = -ENOMEM; + TPD_ERR("Couldn't create i2c_device_test\n"); + } + + prEntry_tmp = proc_create( "radd", 0777, prEntry_tp, &base_register_address); + if(prEntry_tmp == NULL){ + ret = -ENOMEM; + TPD_ERR("Couldn't create radd\n"); + } + prEntry_tmp = proc_create("vendor_id", 0444, prEntry_tp, &vendor_id_proc_fops); + if(prEntry_tmp == NULL){ + ret = -ENOMEM; + TPD_ERR("Couldn't create vendor_id\n"); + } + prEntry_tmp = proc_create("changer_connet", 0666, prEntry_tp, &changer_ops); + if(prEntry_tmp == NULL){ + ret = -ENOMEM; + TPD_ERR("Couldn't create changer_connet\n"); + } + + prEntry_tmp = proc_create("touch_press", 0666, prEntry_tp, &touch_press_status); + if(prEntry_tmp == NULL){ + ret = -ENOMEM; + TPD_ERR("Couldn't create touch_press\n"); + } +#ifdef SUPPORT_TP_TOUCHKEY + prEntry_tmp = proc_create("key_switch", 0666, prEntry_tp, &key_switch_proc_fops); + if(prEntry_tmp == NULL){ + ret = -ENOMEM; + TPD_ERR("Couldn't create key_switch\n"); + } + + prEntry_tmp = proc_create("key_disable", 0666, prEntry_tp, &key_disable_proc_fops); + if(prEntry_tmp == NULL){ + ret = -ENOMEM; + TPD_ERR("Couldn't create key_disable\n"); + } +#endif + + /*morgan.gu add for logkit to dump main registor*/ + prEntry_tmp = proc_create("tp_main_reg", 0444, + prEntry_tp, &tp_main_reg); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_ERR("Couldn't create tp_main_reg\n"); + } + + /*morgan.gu add for logkit to open more log*/ + prEntry_tmp = proc_create("tp_debug_log", 0664, + prEntry_tp, &tp_debug_log_proc_fops); + if (prEntry_tmp == NULL) { + ret = -ENOMEM; + TPD_ERR("Couldn't create tp_debug_log_proc_fops\n"); + } + + return ret; +} +/******************************end****************************/ + +/****************************S3203*****update**********************************/ +#define SYNAPTICS_RMI4_PRODUCT_ID_SIZE 10 +#define SYNAPTICS_RMI4_PRODUCT_INFO_SIZE 2 + +static void re_scan_PDT(struct i2c_client *client) +{ + uint8_t buf[8]; + i2c_smbus_read_i2c_block_data(client, 0xE9, 6, buf); + SynaF34DataBase = buf[3]; + SynaF34QueryBase = buf[0]; + i2c_smbus_read_i2c_block_data(client, 0xE3, 6, buf); + SynaF01DataBase = buf[3]; + SynaF01CommandBase = buf[1]; + i2c_smbus_read_i2c_block_data(client, 0xDD, 6, buf); + + SynaF34Reflash_BlockNum = SynaF34DataBase; + SynaF34Reflash_BlockData = SynaF34DataBase + 1; + SynaF34ReflashQuery_BootID = SynaF34QueryBase; + SynaF34ReflashQuery_FlashPropertyQuery = SynaF34QueryBase + 1; + SynaF34ReflashQuery_FirmwareBlockSize = SynaF34QueryBase + 2; + SynaF34ReflashQuery_FirmwareBlockCount = SynaF34QueryBase +3; + SynaF34ReflashQuery_ConfigBlockSize = SynaF34QueryBase + 3; + SynaF34ReflashQuery_ConfigBlockCount = SynaF34QueryBase + 3; + i2c_smbus_read_i2c_block_data(client, SynaF34ReflashQuery_FirmwareBlockSize, 2, buf); + SynaFirmwareBlockSize = buf[0] | (buf[1] << 8); + TPD_DEBUG("SynaFirmwareBlockSize 3310 is %d\n", SynaFirmwareBlockSize); + SynaF34_FlashControl = SynaF34DataBase + 2; +} +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; + unsigned char options_reserved:6; + 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 */ + unsigned char reserved_20_2f[16]; + /* 0x30 - 0x3f */ + unsigned char ds_id[16]; + /* 0x40 - 0x4f */ + unsigned char ds_info[10]; + unsigned char reserved_4a_4f[6]; + /* 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; + unsigned char bootloader_version; + unsigned char product_id[SYNAPTICS_RMI4_PRODUCT_ID_SIZE + 1]; + unsigned char product_info[SYNAPTICS_RMI4_PRODUCT_INFO_SIZE]; +}; + +static 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; +} + +static void 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(" debug checksume is %x", header->checksum); + header->bootloader_version = data->bootloader_version; + TPD_DEBUG(" debug bootloader_version is %d\n", header->bootloader_version); + + header->firmware_size = extract_uint_le(data->firmware_size); + TPD_DEBUG(" debug firmware_size is %x", header->firmware_size); + + header->config_size = extract_uint_le(data->config_size); + TPD_DEBUG(" debug header->config_size is %x", header->config_size); + + 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(" 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; +} + +static int checkFlashState(struct i2c_client *client) +{ + int ret ; + int count = 0; + ret = synaptics_rmi4_i2c_read_byte(client,SynaF34_FlashControl+1); + while ( (ret != 0x80)&&(count < 8) ) { + msleep(3); //wait 3ms + ret = synaptics_rmi4_i2c_read_byte(client,SynaF34_FlashControl+1); + count++; + } + if(count == 8) + return 1; + else + return 0; +} + +static int synaptics_fw_check(struct synaptics_ts_data *ts ) +{ + int ret; + uint8_t buf[4]; + uint32_t bootloader_mode; + int max_y_ic = 0; + int max_x_ic = 0; + if(!ts){ + TPD_ERR("%s ts is NULL\n",__func__); + return -1; + } + + ret = synaptics_enable_interrupt(ts, 0); + if(ret < 0) { + TPDTM_DMESG(" synaptics_ts_probe: disable interrupt failed\n"); + } + + /*read product id */ + ret = synaptics_read_product_id(ts); + if(ret) { + TPD_ERR("failed to read product info \n"); + return -1; + } + /*read max_x ,max_y*/ + ret = synaptics_rmi4_i2c_write_byte(ts->client, 0xff, 0x0); + if (ret < 0) { + ret = synaptics_rmi4_i2c_write_byte(ts->client, 0xff, 0x0); + if(ret < 0 ){ + TPD_ERR("synaptics_rmi4_i2c_write_byte failed for page select\n"); + return -1; + } + } + + i2c_smbus_read_i2c_block_data(ts->client, F12_2D_CTRL08, 4, buf); + max_x_ic = ( (buf[1]<<8)&0xffff ) | (buf[0]&0xffff); + max_y_ic = ( (buf[3]<<8)&0xffff ) | (buf[2]&0xffff); + + TPD_ERR("max_x = %d,max_y = %d; max_x_ic = %d,max_y_ic = %d\n",ts->max_x,ts->max_y,max_x_ic,max_y_ic); + if((ts->max_x == 0) ||(ts->max_y ==0 )) { + ts->max_x = max_x_ic; + ts->max_y = max_y_ic; + } + bootloader_mode = synaptics_rmi4_i2c_read_byte(ts->client,F01_RMI_DATA_BASE); + bootloader_mode = bootloader_mode&0xff; + bootloader_mode = bootloader_mode&0x40; + TPD_DEBUG("afte fw update,program memory self-check bootloader_mode = 0x%x\n",bootloader_mode); + + if((max_x_ic == 0)||(max_y_ic == 0)||(bootloader_mode == 0x40)) { + TPD_ERR("Something terrible wrong \n Trying Update the Firmware again\n"); + return -1; + } + return 0; +} + +static void re_scan_PDT_s3508(struct i2c_client *client) +{ + uint8_t buf[8]; + i2c_smbus_read_i2c_block_data(client, 0xE9, 6, buf); + SynaF34DataBase = buf[3]; + SynaF34QueryBase = buf[0]; + i2c_smbus_read_i2c_block_data(client, 0xE3, 6, buf); + SynaF01DataBase = buf[3]; + SynaF01CommandBase = buf[1]; + i2c_smbus_read_i2c_block_data(client, 0xDD, 6, buf); + + SynaF34Reflash_BlockNum = SynaF34DataBase; + SynaF34Reflash_BlockData = SynaF34DataBase + 1; + SynaF34ReflashQuery_BootID = SynaF34QueryBase; + SynaF34ReflashQuery_FlashPropertyQuery = SynaF34QueryBase + 1; + SynaF34ReflashQuery_FirmwareBlockSize = SynaF34QueryBase + 2; + SynaF34ReflashQuery_FirmwareBlockCount = SynaF34QueryBase +3; + SynaF34ReflashQuery_ConfigBlockSize = SynaF34QueryBase + 3; + SynaF34ReflashQuery_ConfigBlockCount = SynaF34QueryBase + 3; + i2c_smbus_read_i2c_block_data(client, SynaF34ReflashQuery_FirmwareBlockSize, 2, buf); + SynaFirmwareBlockSize = buf[0] | (buf[1] << 8); + TPD_DEBUG("SynaFirmwareBlockSize 3310 is %d\n", SynaFirmwareBlockSize); + SynaF34_FlashControl = SynaF34DataBase + 2; +} + +#define F01_BUID_ID_OFFSET 18 + +static int synaptics_rmi4_query_firmware_id_s3706( + struct i2c_client *client, + unsigned int *firmware_id_s3706, + unsigned char *conifg_id_s3706) +{ + int retval; + unsigned char build_id[3]; + unsigned int firmware_id; + unsigned char config_id[32]; + + retval = synaptics_rmi4_i2c_read_block(client, + F01_RMI_QUERY_BASE + F01_BUID_ID_OFFSET, + sizeof(build_id), build_id); + if (retval < 0) + return retval; + firmware_id = (unsigned int)build_id[0] + + (unsigned int)build_id[1] * 0x100 + + (unsigned int)build_id[2] * 0x10000; + *firmware_id_s3706 = firmware_id; + + retval = synaptics_rmi4_i2c_read_block(client, + F34_FLASH_CTRL_BASE, + sizeof(config_id), config_id); + if (retval < 0) + return retval; + conifg_id_s3706 = config_id; + return 0; +} + + +static int synapitcs_ts_update(struct i2c_client *client, const uint8_t *data, uint32_t data_len ,bool force) +{ + int ret,j; + uint8_t buf[8]; + uint8_t bootloder_id[10]; + uint16_t block,firmware,configuration; + uint32_t CURRENT_FIRMWARE_ID = 0 , FIRMWARE_ID = 0; + unsigned char CURRENT_CONFIG_ID[32] = {0}; + const uint8_t *Config_Data = NULL; + const uint8_t *Firmware_Data = NULL; + struct image_header_data header; + struct synaptics_ts_data *ts = dev_get_drvdata(&client->dev); + TPD_DEBUG("%s is called\n", __func__); + if(!client) + return -1; + if (!strncmp(ts->manu_name, "S3706", 5)) { + synaptics_rmi4_query_firmware_id_s3706( + client, + &CURRENT_FIRMWARE_ID, + CURRENT_CONFIG_ID); + TPD_ERR("FW_ID:%d--CONFIG_ID %s FW_NAME:%s\n", + CURRENT_FIRMWARE_ID, + CURRENT_CONFIG_ID, + ts->fw_name); + rmi4_data_s3706->firmware_id = CURRENT_FIRMWARE_ID; + rmi4_data_s3706->force = force; + ret = synaptics_rmi4_fwu_init(rmi4_data_s3706, data, client); + if (ret < 0) { + return ret; + } + } else if (!strncmp(ts->manu_name, "S3718", 5)) { + Config_Data = data + 0x8f0; + ret = synaptics_rmi4_i2c_write_byte(client, 0xff, 0x0); + ret = synaptics_rmi4_i2c_read_block(client, F34_FLASH_CTRL00, 4, buf); + CURRENT_FIRMWARE_ID = (buf[0]<<24)|(buf[1]<<16)|(buf[2]<<8)|buf[3]; + FIRMWARE_ID = (Config_Data[0]<<24)|(Config_Data[1]<<16)|(Config_Data[2]<<8)|Config_Data[3]; + if(1 == check_version) + TPD_ERR("15801CURRENT_FW_ID:%x----, FW_ID:%x----,FW_NAME:%s\n", CURRENT_FIRMWARE_ID, FIRMWARE_ID,ts->fw_name); + else + TPD_ERR("15801CURRENT_FW_ID:%xvB----, FW_ID:%xvB----,FW_NAME:%s\n", CURRENT_FIRMWARE_ID, FIRMWARE_ID,ts->fw_name); + //TPD_ERR("synaptics force is %d\n", force); + if(!force) { + if(CURRENT_FIRMWARE_ID == FIRMWARE_ID) { + return 0; + } + } + ret = fwu_start_reflash(data,client); + if (ret){ + return -1; + } + }else if(!strncmp(ts->manu_name,"s3508",5) || !strncmp(ts->manu_name,"15811",5)){ + parse_header(&header,data); + if((header.firmware_size + header.config_size + 0x100) > data_len) { + TPDTM_DMESG("firmware_size + config_size + 0x100 > data_len data_len = %d \n",data_len); + return -1; + } + Firmware_Data = data + 0x100; + Config_Data = Firmware_Data + header.firmware_size; + ret = i2c_smbus_write_byte_data(client, 0xff, 0x0); + + ret = i2c_smbus_read_i2c_block_data(client, F34_FLASH_CTRL00, 4, buf); + CURRENT_FIRMWARE_ID = (buf[0]<<24)|(buf[1]<<16)|(buf[2]<<8)|buf[3]; + FIRMWARE_ID = (Config_Data[0]<<24)|(Config_Data[1]<<16)|(Config_Data[2]<<8)|Config_Data[3]; + TPD_ERR("15811CURRENT_FW_ID:%x----, FW_ID:%x----,FW_NAME:%s\n", CURRENT_FIRMWARE_ID, FIRMWARE_ID,ts->fw_name); + TPD_ERR("synaptics force is %d\n", force); + if(!force) { + if(CURRENT_FIRMWARE_ID == FIRMWARE_ID) { + return 0; + } + } + re_scan_PDT_s3508(client); + block = 16; + TPD_DEBUG("block is %d \n",block); + firmware = (header.firmware_size)/16; + TPD_DEBUG("firmware is %d \n",firmware); + configuration = (header.config_size)/16; + TPD_DEBUG("configuration is %d \n",configuration); + + ret = i2c_smbus_read_i2c_block_data(client, SynaF34ReflashQuery_BootID, 8, &(bootloder_id[0])); + TPD_DEBUG("bootloader id is %x \n",(bootloder_id[1] << 8)|bootloder_id[0]); + ret=i2c_smbus_write_i2c_block_data(client, SynaF34Reflash_BlockData, 2, &(bootloder_id[0x0])); + TPD_DEBUG("Write bootloader id SynaF34_FlashControl is 0x00%x ret is %d\n",SynaF34_FlashControl,ret); + + i2c_smbus_write_byte_data(client,SynaF34_FlashControl,0x0F); + msleep(10); + TPD_DEBUG("attn step 4\n"); + ret=checkFlashState(client); + if(ret > 0) { + TPD_ERR("Get in prog:The status(Image) of flashstate is %x\n",ret); + return -1; + } + ret = i2c_smbus_read_byte_data(client,0x04); + TPD_DEBUG("The status(device state) is %x\n",ret); + ret= i2c_smbus_read_byte_data(client,F01_RMI_CTRL_BASE); + TPD_DEBUG("The status(control f01_RMI_CTRL_DATA) is %x\n",ret); + ret= i2c_smbus_write_byte_data(client,F01_RMI_CTRL_BASE,ret&0x04); + /********************get into prog end************/ + ret=i2c_smbus_write_i2c_block_data(client, SynaF34Reflash_BlockData, 2, &(bootloder_id[0x0])); + TPD_DEBUG("ret is %d\n",ret); + re_scan_PDT_s3508(client); + i2c_smbus_read_i2c_block_data(client,SynaF34ReflashQuery_BootID,2,buf); + i2c_smbus_write_i2c_block_data(client,SynaF34Reflash_BlockData,2,buf); + i2c_smbus_write_byte_data(client,SynaF34_FlashControl,0x03); + msleep(2500); + ret = i2c_smbus_read_byte_data(client, SynaF34_FlashControl); + if(ret != 0x00) + msleep(2000); + ret = i2c_smbus_read_byte_data(client,SynaF34_FlashControl+1); + TPDTM_DMESG("The status(erase) is %x\n",ret); + TPD_ERR("15811update-----------------update------------------update!\n"); + TPD_DEBUG("cnt %d\n",firmware); + for(j=0; j>8; + i2c_smbus_write_i2c_block_data(client,SynaF34Reflash_BlockNum,2,buf); + i2c_smbus_write_i2c_block_data(client,SynaF34Reflash_BlockData,16,&Firmware_Data[j*16]); + + i2c_smbus_write_byte_data(client,SynaF34_FlashControl,0x02); + ret=checkFlashState(client); + if(ret > 0) { + TPD_ERR("Firmware:The status(Image) of flash data3 is %x,time =%d\n",ret,j); + return -1; + } + } + //step 7 configure data + //TPD_ERR("going to flash configuration area\n"); + //TPD_ERR("header.firmware_size is 0x%x\n", header.firmware_size); + //TPD_ERR("bootloader_size is 0x%x\n", bootloader_size); + for(j=0;j>8; + i2c_smbus_write_i2c_block_data(client,SynaF34Reflash_BlockNum,2,buf); + //b) write data + + i2c_smbus_write_i2c_block_data(client,SynaF34Reflash_BlockData,16,&Config_Data[j*16]); + + //c) issue write + i2c_smbus_write_byte_data(client,SynaF34_FlashControl,0x06); + //d) wait attn + ret = checkFlashState(client); + if(ret > 0) { + TPD_ERR("Configuration:The status(Image) of flash data3 is %x,time =%d\n",ret,j); + return -1; + } + } + //step 1 issue reset + i2c_smbus_write_byte_data(client,SynaF01CommandBase,0X01); + }else{ + parse_header(&header,data); + if((header.firmware_size + header.config_size + 0x100) > data_len) { + TPDTM_DMESG("firmware_size + config_size + 0x100 > data_len data_len = %d \n",data_len); + return -1; + } + + Firmware_Data = data + 0x100; + Config_Data = Firmware_Data + header.firmware_size; + ret = synaptics_rmi4_i2c_write_byte(client, 0xff, 0x0); + + ret = synaptics_rmi4_i2c_read_block(client, F34_FLASH_CTRL00, 4, buf); + CURRENT_FIRMWARE_ID = (buf[0]<<24)|(buf[1]<<16)|(buf[2]<<8)|buf[3]; + FIRMWARE_ID = (Config_Data[0]<<24)|(Config_Data[1]<<16)|(Config_Data[2]<<8)|Config_Data[3]; + + //TPD_ERR("synaptics force is %d\n", force); + if(!force) { + if(CURRENT_FIRMWARE_ID == FIRMWARE_ID) { + return 0; + } + } + re_scan_PDT(client); + block = 16; + TPD_DEBUG("block is %d \n",block); + firmware = (header.firmware_size)/16; + TPD_DEBUG("firmware is %d \n",firmware); + configuration = (header.config_size)/16; + TPD_DEBUG("configuration is %d \n",configuration); + + + ret = i2c_smbus_read_i2c_block_data(client, SynaF34ReflashQuery_BootID, 8, &(bootloder_id[0])); + TPD_DEBUG("bootloader id is %x \n",(bootloder_id[1] << 8)|bootloder_id[0]); + ret=i2c_smbus_write_i2c_block_data(client, SynaF34Reflash_BlockData, 2, &(bootloder_id[0x0])); + TPDTM_DMESG("Write bootloader id SynaF34_FlashControl is 0x00%x ret is %d\n",SynaF34_FlashControl,ret); + + synaptics_rmi4_i2c_write_byte(client,SynaF34_FlashControl,0x0F); + msleep(10); + TPD_DEBUG("attn step 4\n"); + ret=checkFlashState(client); + if(ret > 0) { + TPD_ERR("Get in prog:The status(Image) of flashstate is %x\n",ret); + return -1; + } + ret = i2c_smbus_read_byte_data(client,0x04); + TPD_DEBUG("The status(device state) is %x\n",ret); + ret= i2c_smbus_read_byte_data(client,F01_RMI_CTRL_BASE); + TPD_DEBUG("The status(control f01_RMI_CTRL_DATA) is %x\n",ret); + ret= i2c_smbus_write_byte_data(client,F01_RMI_CTRL_BASE,ret&0x04); + /********************get into prog end************/ + ret=i2c_smbus_write_i2c_block_data(client, SynaF34Reflash_BlockData, 2, &(bootloder_id[0x0])); + TPD_DEBUG("ret is %d\n",ret); + re_scan_PDT(client); + i2c_smbus_read_i2c_block_data(client,SynaF34ReflashQuery_BootID,2,buf); + i2c_smbus_write_i2c_block_data(client,SynaF34Reflash_BlockData,2,buf); + i2c_smbus_write_byte_data(client,SynaF34_FlashControl,0x03); + msleep(2000); + ret = i2c_smbus_read_byte_data(client,SynaF34_FlashControl); + TPDTM_DMESG("going to flash firmware area synaF34_FlashControl %d\n",ret); + + TPD_ERR("update-----------------firmware ------------------update!\n"); + TPD_DEBUG("cnt %d\n",firmware); + for(j=0; j>8; + synaptics_rmi4_i2c_write_block(client,SynaF34Reflash_BlockNum,2,buf); + synaptics_rmi4_i2c_write_block(client,SynaF34Reflash_BlockData,16,&Firmware_Data[j*16]); + synaptics_rmi4_i2c_write_byte(client,SynaF34_FlashControl,0x02); + ret=checkFlashState(client); + if(ret > 0) { + TPD_ERR("Firmware:The status(Image) of flash data3 is %x,time =%d\n",ret,j); + return -1; + } + } + //step 7 configure data + //TPD_ERR("going to flash configuration area\n"); + //TPD_ERR("header.firmware_size is 0x%x\n", header.firmware_size); + //TPD_ERR("bootloader_size is 0x%x\n", bootloader_size); + TPD_ERR("update-----------------configuration ------------------update!\n"); + for(j=0;j>8; + synaptics_rmi4_i2c_write_block(client,SynaF34Reflash_BlockNum,2,buf); + //b) write data + synaptics_rmi4_i2c_write_block(client,SynaF34Reflash_BlockData,16,&Config_Data[j*16]); + //c) issue write + synaptics_rmi4_i2c_write_byte(client,SynaF34_FlashControl,0x06); + //d) wait attn + ret = checkFlashState(client); + if(ret > 0) { + TPD_ERR("Configuration:The status(Image) of flash data3 is %x,time =%d\n",ret,j); + return -1; + } + } + + //step 1 issue reset + synaptics_rmi4_i2c_write_byte(client,SynaF01CommandBase,0x01); + } + //step2 wait ATTN + //delay_qt_ms(1000); + mdelay(1500); + synaptics_read_register_map(ts); + //FW flash check! + ret =synaptics_fw_check(ts); + if(ret < 0 ) { + TPD_ERR("Firmware self check failed\n"); + return -1; + } + TPD_ERR("Firmware self check success\n"); + return 0; +} +#ifdef ENABLE_TPEDGE_LIMIT +static void synaptics_tpedge_limitfunc(void) +{ + int limit_mode=0; + int ret; + + if (version_is_s3508 == 2) { + F51_GRIP_CONFIGURATION = F51_CUSTOM_CTRL_BASE+0x0a; + } else if (version_is_s3508 == 0) { + F51_GRIP_CONFIGURATION = F51_CUSTOM_CTRL_BASE+0x34; + } else if (version_is_s3508 == 1) { + F51_GRIP_CONFIGURATION = F51_CUSTOM_CTRL_BASE+0x1b; + } else + F51_GRIP_CONFIGURATION = F51_CUSTOM_CTRL_BASE+0x0a; + + TPD_DEBUG("%s line %d F51_GRIP_CONFIGURATION = 0x%x\n", + __func__, __LINE__, F51_GRIP_CONFIGURATION); + //msleep(60); + ret = i2c_smbus_write_byte_data(ts_g->client, 0xff, 0x4); + limit_mode = i2c_smbus_read_byte_data(ts_g->client, + F51_GRIP_CONFIGURATION); + TPD_ERR("%s limit_enable =%d,mode:0x%x !\n", + __func__, limit_enable, limit_mode); + if(limit_mode){ + i2c_smbus_write_byte_data(ts_g->client, 0xff, 0x4); + if(0 == limit_enable) + { + if(limit_mode & 0x1){ + //TPD_ERR("000 limit_enable:0x%xs !\n",limit_mode); + limit_mode = limit_mode & 0xFE; + ret = i2c_smbus_write_byte_data(ts_g->client, + F51_GRIP_CONFIGURATION, limit_mode); + } + } + else if(1 == limit_enable) + { + if(!(limit_mode & 0x1)){ + //TPD_ERR("111 limit_enable:x%xs !\n",limit_mode); + limit_mode = limit_mode | 0x1; + ret = i2c_smbus_write_byte_data(ts_g->client, + F51_GRIP_CONFIGURATION, limit_mode); + } + } + } + i2c_smbus_write_byte_data(ts_g->client, 0xff, 0x0); +} + +#endif +static int synaptics_soft_reset(struct synaptics_ts_data *ts) +{ + int ret; + if(ts->loading_fw) { + TPD_ERR("%s FW is updating break!\n",__func__); + return -1; + } + touch_disable(ts); + ret = i2c_smbus_write_byte_data(ts->client, F01_RMI_CMD_BASE, 0x01); + if (ret < 0){ + TPD_ERR("reset error ret=%d\n",ret); + } + TPD_ERR("%s !!!\n",__func__); + msleep(100); + touch_enable(ts); +#ifdef ENABLE_TPEDGE_LIMIT + synaptics_tpedge_limitfunc(); +#endif + return ret; +} +static void synaptics_hard_reset(struct synaptics_ts_data *ts) +{ + if(ts->reset_gpio > 0) + { + gpio_set_value(ts->reset_gpio,0); + msleep(5); + gpio_set_value(ts->reset_gpio,1); + msleep(100); + TPD_ERR("%s !!!\n",__func__); + } + +} +static int synaptics_parse_dts(struct device *dev, struct synaptics_ts_data *ts) +{ + int rc; + struct device_node *np; + int temp_array[2]; + u32 voltage_supply[2]; + u32 current_supply; + + np = dev->of_node; + ts->irq_gpio = of_get_named_gpio_flags(np, "synaptics,irq-gpio", 0, &(ts->irq_flags)); + if( ts->irq_gpio < 0 ){ + TPD_DEBUG("ts->irq_gpio not specified\n"); + } + + ts->reset_gpio = of_get_named_gpio(np, "synaptics,reset-gpio", 0); + if( ts->reset_gpio < 0 ){ + TPD_DEBUG("ts->reset-gpio not specified\n"); + } + ts->v1p8_gpio = of_get_named_gpio(np, "synaptics,1v8-gpio", 0); + if( ts->v1p8_gpio < 0 ){ + TPD_DEBUG("ts->1v8-gpio not specified\n"); + } + + if (of_property_read_bool(np, "oem,support_1080x2160_tp")) + ts->support_1080x2160_tp = true; + else + ts->support_1080x2160_tp = false; + + if (of_property_read_bool(np, "oem,support_1080x2340_tp")) + ts->support_1080x2340_tp = true; + else + ts->support_1080x2340_tp = false; + + if(of_property_read_bool(np, "oem,support_hw_poweroff")) + ts->support_hw_poweroff=true; + else + ts->support_hw_poweroff=false; + + TPD_ERR("%s ts->support_hw_poweroff =%d\n",__func__,ts->support_hw_poweroff); + + ts->enable2v8_gpio = of_get_named_gpio(np, "synaptics,enable2v8-gpio", 0); + if( ts->enable2v8_gpio < 0 ){ + TPD_DEBUG("ts->enable2v8_gpio not specified\n"); + } + + rc = of_property_read_u32(np, "synaptics,max-num-support", &ts->max_num); + if(rc){ + TPD_DEBUG("ts->max_num not specified\n"); + ts->max_num = 10; + } + + rc = of_property_read_u32_array(np, "synaptics,button-map", button_map, 3); + if(rc){ + TPD_DEBUG("button-map not specified\n"); + //button_map[0] = 180; + //button_map[1] = 180; + //button_map[2] = 2021; + } + TPD_DEBUG("synaptics:button map readed is %d %d %d\n", button_map[0], button_map[1], button_map[2]); + + rc = of_property_read_u32_array(np, "synaptics,tx-rx-num", tx_rx_num,2); + if(rc){ + TPD_ERR("button-map not specified\n"); + TX_NUM = 30; + RX_NUM = 17; + }else{ + TX_NUM = tx_rx_num[0];/*s3706 16 33*/ + RX_NUM = tx_rx_num[1]; + } + TPD_ERR("synaptics,tx-rx-num is %d %d \n", TX_NUM,RX_NUM); + + rc = of_property_read_u32_array(np, "synaptics,display-coords", temp_array, 2); + if(rc){ + TPD_ERR("lcd size not specified\n"); + LCD_WIDTH = 1080; + LCD_HEIGHT = 1920; + }else{ + LCD_WIDTH = temp_array[0]; + LCD_HEIGHT = temp_array[1]; + } + + rc = of_property_read_u32_array(np, "synaptics,panel-coords", temp_array, 2); + if(rc){ + ts->max_x = 1080; + ts->max_y = 1920; + }else{ + ts->max_x = temp_array[0]; + ts->max_y = temp_array[1]; + } + + TPDTM_DMESG("synaptic:ts->irq_gpio:%d irq_flags:%u max_num %d\n"\ + ,ts->irq_gpio, ts->irq_flags, ts->max_num); + + /***********power regulator_get****************/ + ts->vdd_2v8 = regulator_get(&ts->client->dev, "vdd_2v8"); + if( IS_ERR(ts->vdd_2v8) ){ + rc = PTR_ERR(ts->vdd_2v8); + TPD_DEBUG("Regulator get failed vdd rc=%d\n", rc); + } + rc = of_property_read_u32(np,"synaptics,avdd-current", ¤t_supply); + if (rc < 0) { + TPD_ERR("%s: Failed to get regulator avdd current\n", __func__); + + } else { + ts->regulator_avdd_current = current_supply; + TPD_ERR("%s: avdd current = %d\n", + __func__, ts->regulator_avdd_current); + rc = regulator_set_load(ts->vdd_2v8, + ts->regulator_avdd_current); + if (rc < 0) + TPD_ERR("%s: Failed to set avdd\n", __func__); + } + + + rc = of_property_read_u32_array(np, "synaptics,avdd-voltage", voltage_supply, 2); + if (rc < 0) { + TPD_ERR("%s: Failed to get regulator vdd voltage\n",__func__); + } else { + ts->regulator_avdd_vmin = voltage_supply[0]; + ts->regulator_avdd_vmax = voltage_supply[1]; + TPD_ERR("%s:avdd_vmin=%d,avdd_vmax=%d\n", __func__, + ts->regulator_avdd_vmin, ts->regulator_avdd_vmax); + + rc = regulator_set_voltage(ts->vdd_2v8, + ts->regulator_avdd_vmin, ts->regulator_avdd_vmax); + if (rc < 0) + TPD_ERR("%s:Failed to set avdd\n", __func__); + } + + + ts->vcc_i2c_1v8 = regulator_get(&ts->client->dev, "vcc_i2c_1v8"); + if( IS_ERR(ts->vcc_i2c_1v8) ){ + rc = PTR_ERR(ts->vcc_i2c_1v8); + TPD_DEBUG("Regulator get failed vcc_i2c rc=%d\n", rc); + } + + rc = of_property_read_u32(np,"synaptics,vdd-current", ¤t_supply); + if (rc < 0) { + TPD_ERR("%s: Failed to get regulator vdd current\n", __func__); + } else { + ts->regulator_vdd_current = current_supply; + TPD_ERR("%s: vdd current = %d\n", __func__, + ts->regulator_vdd_current); + rc = regulator_set_load(ts->vcc_i2c_1v8, + ts->regulator_vdd_current); + if (rc < 0) + TPD_ERR("%s: Failed to set vdd\n", __func__); + } + + + rc = of_property_read_u32_array(np, "synaptics,vdd-voltage", voltage_supply, 2); + if (rc < 0) { + TPD_ERR("%s: Failed to get regulator vdd voltage\n", __func__); + } else { + ts->regulator_vdd_vmin = voltage_supply[0]; + ts->regulator_vdd_vmax = voltage_supply[1]; + TPD_ERR("%s:vdd_vmin=%d,vdd_vmax=%d\n", __func__, + ts->regulator_vdd_vmin, ts->regulator_vdd_vmax); + + rc = regulator_set_voltage(ts->vcc_i2c_1v8, + ts->regulator_vdd_vmin, ts->regulator_vdd_vmax); + if (rc < 0) + TPD_ERR("%s:Failed to set vdd\n", __func__); + } + + + + if( ts->reset_gpio > 0){ + if( gpio_is_valid(ts->reset_gpio) ){ + rc = gpio_request(ts->reset_gpio, "tp-s3320-reset"); + if(rc){ + TPD_ERR("unable to request reset_gpio [%d]\n", ts->reset_gpio); + } + gpio_direction_output(ts->reset_gpio, 0); + } + } + if( ts->v1p8_gpio > 0){ + if( gpio_is_valid(ts->v1p8_gpio) ){ + rc = gpio_request(ts->v1p8_gpio, "tp-s3320-1v8"); + if(rc){ + TPD_ERR("unable to request v1p8_gpio [%d]\n", ts->v1p8_gpio); + } + } + } + + if( ts->enable2v8_gpio > 0){ + if( gpio_is_valid(ts->enable2v8_gpio) ){ + rc = gpio_request(ts->enable2v8_gpio, "rmi4-enable2v8-gpio"); + if(rc) + TPD_ERR("unable to request enable2v8_gpio [%d]\n", ts->enable2v8_gpio); + + } + } + + return rc; +} + +static int synaptics_dsx_pinctrl_init(struct synaptics_ts_data *ts) +{ + int retval; + + /* Get pinctrl if target uses pinctrl */ + ts->pinctrl = devm_pinctrl_get((ts->dev)); + if (IS_ERR_OR_NULL(ts->pinctrl)) { + retval = PTR_ERR(ts->pinctrl); + TPD_ERR("%s pinctrl error!\n",__func__); + goto err_pinctrl_get; + } + + ts->pinctrl_state_active + = pinctrl_lookup_state(ts->pinctrl, "pmx_ts_active"); + if (IS_ERR_OR_NULL(ts->pinctrl_state_active)) { + retval = PTR_ERR(ts->pinctrl_state_active); + TPD_ERR("%s pinctrl state active error!\n",__func__); + goto err_pinctrl_lookup; + } + + ts->pinctrl_state_suspend + = pinctrl_lookup_state(ts->pinctrl, "pmx_ts_suspend"); + if (IS_ERR_OR_NULL(ts->pinctrl_state_suspend)) { + retval = PTR_ERR(ts->pinctrl_state_suspend); + TPD_ERR("%s pinctrl state suspend error!\n",__func__); + goto err_pinctrl_lookup; + } + return 0; + +err_pinctrl_lookup: + devm_pinctrl_put(ts->pinctrl); +err_pinctrl_get: + ts->pinctrl = NULL; + return retval; +} + +#ifdef SUPPORT_VIRTUAL_KEY +#define VK_KEY_X 180 +#define VK_CENTER_Y 2020//2260 +#define VK_WIDTH 170 +#define VK_HIGHT 200 +static ssize_t vk_syna_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + int len ; + + len = sprintf(buf, + __stringify(EV_KEY) ":" __stringify(KEY_APPSELECT) ":%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", + VK_KEY_X, VK_CENTER_Y, VK_WIDTH, VK_HIGHT, + VK_KEY_X*3, VK_CENTER_Y, VK_WIDTH, VK_HIGHT, + VK_KEY_X*5, VK_CENTER_Y, VK_WIDTH, VK_HIGHT); + + return len ; +} + +static struct kobj_attribute vk_syna_attr = { + .attr = { + .name = "virtualkeys."TPD_DEVICE, + .mode = S_IRUGO, + }, + .show = &vk_syna_show, +}; + +static struct attribute *syna_properties_attrs[] = { + &vk_syna_attr.attr, + NULL +}; + +static struct attribute_group syna_properties_attr_group = { + .attrs = syna_properties_attrs, +}; +static int synaptics_ts_init_virtual_key(struct synaptics_ts_data *ts ) +{ + int ret = 0; + + /* virtual keys */ + if(ts->properties_kobj) + return 0 ; + ts->properties_kobj = kobject_create_and_add("board_properties", NULL); + if (ts->properties_kobj) + ret = sysfs_create_group(ts->properties_kobj, &syna_properties_attr_group); + + if (!ts->properties_kobj || ret) + printk("%s: failed to create board_properties\n", __func__); + /* virtual keys */ + return ret; +} +#endif + +static int synaptics_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ +#ifdef CONFIG_SYNAPTIC_RED + struct remotepanel_data *premote_data = NULL; +#endif + struct synaptics_ts_data *ts = NULL; + int ret = -1; + uint8_t buf[8]; + unsigned long int CURRENT_FIRMWARE_ID = 0; + uint32_t bootloader_mode; + uint32_t bootmode; + + TPD_ERR("%s is called\n",__func__); + + ts = kzalloc(sizeof(struct synaptics_ts_data), GFP_KERNEL); + if( ts == NULL ) { + ret = -ENOMEM; + goto err_alloc_data_failed; + } + + ts->client = client; + i2c_set_clientdata(client, ts); + ts->dev = &client->dev; + ts->loading_fw = false; + ts->support_ft = true; + ts_g = ts; + get_tp_base = 0; + + synaptics_parse_dts(&client->dev, ts); + ts->project_version = 0x00; + if (of_property_read_bool(ts->dev->of_node, "oem,fajta")) + ts->project_version = 0x03; + /***power_init*****/ + ret = tpd_power(ts, 1); + if( ret < 0 ) + TPD_ERR("regulator_enable is called\n"); + ret = synaptics_dsx_pinctrl_init(ts); + if (!ret && ts->pinctrl) { + ret = pinctrl_select_state(ts->pinctrl, + ts->pinctrl_state_active); + } + + msleep(100);//after power on tp need sometime from bootloader to ui mode + mutex_init(&ts->mutex); + mutex_init(&ts->mutexreport); + atomic_set(&ts->irq_enable,0); + + ts->is_suspended = 0; + atomic_set(&ts->is_stop,0); + spin_lock_init(&ts->lock); + /*****power_end*********/ + if( !i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA) ){ + TPD_ERR("%s [ERR]need I2C_FUNC_I2C\n", __func__); + ret = -ENODEV; + goto err_check_functionality_failed; + } + + ret = synaptics_rmi4_i2c_read_byte(client, 0x13); + if( ret < 0 ) { + ret = synaptics_rmi4_i2c_read_byte(client, 0x13); + if( ret < 0 ) { + #ifdef SUPPORT_VIRTUAL_KEY + virtual_key_enable = 0;//if touch is no valid report key + #endif + TPD_ERR("tp is no exist!\n"); + goto err_check_functionality_failed; + } + } + + ts->i2c_device_test = ret; + rmi4_data_s3706 = kzalloc(sizeof(struct synaptics_rmi4_data), + GFP_KERNEL); + if (rmi4_data_s3706 == NULL) { + TPD_ERR("Request rmi4_data_s3706 failed\n"); + goto err_check_functionality_failed; + } + rmi4_data_s3706->reset_device = synaptics_rmi4_reset_device; + mutex_init(&(rmi4_data_s3706->rmi4_reset_mutex)); + mutex_init(&(rmi4_data_s3706->rmi4_report_mutex)); + mutex_init(&(rmi4_data_s3706->rmi4_io_ctrl_mutex)); + mutex_init(&(rmi4_data_s3706->rmi4_exp_init_mutex)); + mutex_init(&(rmi4_data_s3706->rmi4_irq_enable_mutex)); + + synaptics_read_register_map(ts); + bootloader_mode = synaptics_rmi4_i2c_read_byte(ts->client, F01_RMI_DATA_BASE); + + bootloader_mode = bootloader_mode&0x40; + TPD_ERR("before fw update bootloader_mode[0x%x]\n", bootloader_mode); + + memset(ts->fw_name, 0, TP_FW_NAME_MAX_LEN); + memset(ts->test_limit_name, 0, TP_FW_NAME_MAX_LEN); + + //sprintf(ts->manu_name, "TP_SYNAPTICS"); + synaptics_rmi4_i2c_read_block(ts->client, F01_RMI_QUERY11,\ + sizeof(ts->manu_name), ts->manu_name); + if (!strncmp(ts->manu_name,"S3718",5)){ + strcpy(ts->fw_name,"tp/fw_synaptics_15801b.img"); + version_is_s3508 = 0; + } else if (!strncmp(ts->manu_name, "S3706", 5)) { + strlcpy(ts->fw_name, "tp/fw_synaptics_17819.img", + sizeof(ts->fw_name)); + version_is_s3508 = 2;/*for s3706*/ + TX_NUM = 16;/*s3706 16 33*/ + RX_NUM = 33; + if (ts->support_1080x2340_tp) { + strlcpy(ts->fw_name, "tp/fw_synaptics_18801.img", + sizeof(ts->fw_name)); + ts->max_x = 1080; + ts->max_y = 2340; + } else { + ts->max_x = 1080; + ts->max_y = 2280; + } + F12_2D_CTRL20 = F12_2D_CTRL_BASE + 0x06;/*0x07 for s3508*/ + F12_2D_CTRL27 = F12_2D_CTRL_BASE + 0x09; + } else { + if (ts->support_1080x2160_tp) + strlcpy(ts->fw_name, "tp/fw_synaptics_17801.img", + sizeof(ts->fw_name)); + else + strlcpy(ts->fw_name, "tp/fw_synaptics_16859.img", + sizeof(ts->fw_name)); + + version_is_s3508 = 1; + } + strcpy(ts->test_limit_name,"tp/14049/14049_Limit_jdi.img"); + + TPD_DEBUG("synatpitcs fw_name=%s\n", + ts->fw_name); + TPD_DEBUG("synatpitcs manu_name:%s\n", + ts->manu_name); + + synaptics_rmi4_i2c_read_block(ts->client, + F34_FLASH_CTRL00, 8, buf); + CURRENT_FIRMWARE_ID = (buf[0]<<24) | (buf[1]<<16) | + (buf[2]<<8) | buf[3]; + if (version_is_s3508 == 2) + CURRENT_FIRMWARE_ID = CURRENT_FIRMWARE_ID << 32 | + ((buf[4]<<24) | (buf[5]<<16) | + (buf[6]<<8) | buf[7]); + TPD_ERR("CURRENT_FIRMWARE_ID = 0x%lx\n", + CURRENT_FIRMWARE_ID); + TP_FW = CURRENT_FIRMWARE_ID; + snprintf(ts->fw_id, 20, "0x%lx", TP_FW); + + push_component_info(TOUCH_KEY, ts->fw_id, ts->manu_name); + push_component_info(TP, ts->fw_id, ts->manu_name); + + synaptics_wq = create_singlethread_workqueue("synaptics_wq"); + if( !synaptics_wq ){ + ret = -ENOMEM; + goto exit_createworkqueue_failed; + } + INIT_DELAYED_WORK(&ts->speed_up_work,speedup_synaptics_resume); + + + memset(baseline,0,sizeof(baseline)); + get_base_report = create_singlethread_workqueue("get_base_report"); + if( !get_base_report ){ + ret = -ENOMEM; + goto exit_createworkqueue_failed; + } + INIT_DELAYED_WORK(&ts->base_work,tp_baseline_get_work); + wakeup_source_init(&ts->source, "tp_syna"); + + ret = synaptics_init_panel(ts); /* will also switch back to page 0x04 */ + if (ret < 0) { + TPD_ERR("synaptics_init_panel failed\n"); + } + + //Detect whether TP FW is error, max_x,max_y may be incoorect while it has been damaged! + ret = synaptics_fw_check(ts); + if(ret < 0 ) { + force_update = 1; + TPD_ERR("This FW need to be updated!\n"); + } else { + force_update = 0; + } + /*disable interrupt*/ + ret = synaptics_enable_interrupt(ts, 0); + if( ret < 0 ) { + TPD_ERR(" synaptics_ts_probe: disable interrupt failed\n"); + } + ret = synaptics_soft_reset(ts); + if (ret < 0){ + TPD_ERR("%s faile to reset device\n",__func__); + } + ret = synaptics_input_init(ts); + if(ret < 0) { + TPD_ERR("synaptics_input_init failed!\n"); + } +#if defined(CONFIG_FB) + ts->fb_notif.notifier_call = fb_notifier_callback; + ret = fb_register_client(&ts->fb_notif); + if(ret) + TPD_ERR("Unable to register fb_notifier: %d\n", ret); +#elif defined(CONFIG_MSM_RDM_NOTIFY) + ts->msm_drm_notif.notifier_call = msm_drm_notifier_callback; + ret = msm_drm_register_client(&ts->msm_drm_notif); + if (ret) + TPD_ERR("Unable to register msm_drm_notifier: %d\n", ret); +#endif + + + +#ifndef TPD_USE_EINT + hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + ts->timer.function = synaptics_ts_timer_func; + hrtimer_start(&ts->timer, ktime_set(3, 0), HRTIMER_MODE_REL); +#endif + +#ifdef TPD_USE_EINT + /**************** + shoud set the irq GPIO + *******************/ + if (gpio_is_valid(ts->irq_gpio)) { + /* configure touchscreen irq gpio */ + ret = gpio_request(ts->irq_gpio,"tp-s3320-irq"); + if (ret) { + TPD_ERR("unable to request gpio [%d]\n",ts->irq_gpio); + } + ret = gpio_direction_input(ts->irq_gpio); + msleep(50); + ts->irq = gpio_to_irq(ts->irq_gpio); + } + TPD_ERR("synaptic:ts->irq is %d\n",ts->irq); + + ret = request_threaded_irq(ts->irq, NULL, + synaptics_irq_thread_fn, + ts->irq_flags | IRQF_ONESHOT, + TPD_DEVICE, ts); + if(ret < 0) + TPD_ERR("%s request_threaded_irq ret is %d\n",__func__,ret); + msleep(5); + ret = synaptics_enable_interrupt(ts, 1); + if(ret < 0) + TPD_ERR("%s enable interrupt error ret=%d\n",__func__,ret); +#endif + + if (device_create_file(&client->dev, &dev_attr_test_limit)) { + TPDTM_DMESG("driver_create_file failt\n"); + goto exit_init_failed; + } + TPD_DEBUG("synaptics_ts_probe: going to create files--tp_fw_update\n"); + if (device_create_file(&client->dev, &dev_attr_tp_fw_update)) { + TPDTM_DMESG("driver_create_file failt\n"); + goto exit_init_failed; + } + if (device_create_file(&client->dev, &dev_attr_tp_doze_time)) { + TPDTM_DMESG("device_create_file failt\n"); + goto exit_init_failed; + } + if( driver_create_file(&tpd_i2c_driver.driver, &driver_attr_tp_debug_log)) { + TPDTM_DMESG("driver_create_file failt\n"); + goto exit_init_failed; + } + if (driver_create_file(&tpd_i2c_driver.driver, &driver_attr_tp_baseline_image_with_cbc)) { + TPDTM_DMESG("driver_create_file failt\n"); + goto exit_init_failed; + } + if( driver_create_file(&tpd_i2c_driver.driver, &driver_attr_tp_baseline_image)) { + TPDTM_DMESG("driver_create_file failt\n"); + goto exit_init_failed; + } + if( driver_create_file(&tpd_i2c_driver.driver, &driver_attr_tp_delta_image)) { + TPDTM_DMESG("driver_create_file failt\n"); + goto exit_init_failed; + } + if (ts->project_version == 0x03) { + if (device_create_file(&client->dev, + &dev_attr_tp_gesture_touch_hold)) { + TPDTM_DMESG("tp_gesture_touch_hold failt\n"); + goto exit_init_failed; + } + if (device_create_file(&client->dev, &dev_attr_fp_irq)) { + TPDTM_DMESG("driver_create_file fail fp_irq\n"); + goto exit_init_failed; + } + ts->fp_up_down = 0; + ts->en_up_down = 0; + ts->fp_aod_cnt = 0; + ts->unlock_succes = 0; + } + +#ifdef SUPPORT_VIRTUAL_KEY + synaptics_ts_init_virtual_key(ts); +#endif +#ifdef CONFIG_SYNAPTIC_RED + premote_data = remote_alloc_panel_data(); + if(premote_data) { + premote_data->client = client; + premote_data->input_dev = ts->input_dev; + premote_data->pmutex = &ts->mutex; + premote_data->irq_gpio = ts->irq_gpio; + premote_data->irq = client->irq; + premote_data->enable_remote = &(ts->enable_remote); + register_remote_device(premote_data); + + } +#endif + init_synaptics_proc(); + TPDTM_DMESG("synaptics_ts_probe 3203: normal end\n"); + + bootmode = get_boot_mode(); + TPD_ERR("synaptics bootmode %d !\n", bootmode); + if ((bootmode == MSM_BOOT_MODE__FACTORY) + || (bootmode == MSM_BOOT_MODE__RF) + || (bootmode == MSM_BOOT_MODE__WLAN)) { + touch_disable(ts); + TPD_ERR("synaptics ftm mode disable int \n"); + return 0; + } + + return 0; + +exit_init_failed: + free_irq(client->irq,ts); +exit_createworkqueue_failed: + destroy_workqueue(synaptics_wq); + synaptics_wq = NULL; + destroy_workqueue(synaptics_report); + synaptics_report = NULL; + destroy_workqueue(get_base_report); + get_base_report = NULL; + +err_check_functionality_failed: + tpd_power(ts, 0); + /*add for morgan for if no tp no pull gpio*/ + if (ts->pinctrl) { + ret = pinctrl_select_state(ts->pinctrl, + ts->pinctrl_state_suspend); + } +err_alloc_data_failed: + tpd_i2c_driver.driver.pm=NULL; + kfree(ts); + ts = NULL; + kfree(rmi4_data_s3706); + rmi4_data_s3706 = NULL; + ts_g = NULL; + TPD_ERR("synaptics_ts_probe: not normal end\n"); + return ret; +} + +static int synaptics_ts_remove(struct i2c_client *client) +{ + int attr_count; + struct synaptics_ts_data *ts = i2c_get_clientdata(client); + + TPD_ERR("%s is called\n",__func__); +#ifdef CONFIG_SYNAPTIC_RED + unregister_remote_device(); +#endif + +#if defined(CONFIG_FB) + if( fb_unregister_client(&ts->fb_notif) ) + dev_err(&client->dev, "Error occurred while unregistering fb_notifier.\n"); +#elif defined(CONFIG_MSM_RDM_NOTIFY) + if (msm_drm_unregister_client(&ts->msm_drm_notif)) + dev_err(&client->dev, "Error occurred while unregistering msm_drm_notifier.\n"); +#endif + +#ifndef TPD_USE_EINT + hrtimer_cancel(&ts->timer); +#endif + + for(attr_count = 0; attr_count < ARRAY_SIZE(attrs_oem); attr_count++){ + sysfs_remove_file(&ts->input_dev->dev.kobj, &attrs_oem[attr_count].attr); + } + input_unregister_device(ts->input_dev); + input_free_device(ts->input_dev); + kfree(ts); + tpd_power(ts,0); + return 0; +} + +static int synaptics_ts_suspend(struct device *dev) +{ + int ret,i; + struct synaptics_ts_data *ts = dev_get_drvdata(dev); + + if(ts->input_dev == NULL) { + ret = -ENOMEM; + TPD_ERR("input_dev registration is not complete\n"); + return -1; + } + TPD_DEBUG("%s enter\n", __func__); + + if (ts->pre_btn_state & 0x01){//if press key and suspend release key + ts->pre_btn_state &= 0x02;//clear bit0 + input_report_key(ts->input_dev, OEM_KEY_BACK, 0); + input_sync(ts->input_dev); + }else if (ts->pre_btn_state & 0x02){ + ts->pre_btn_state &= 0x01;//clear bit1 + input_report_key(ts->input_dev, OEM_KEY_APPSELECT, 0); + input_sync(ts->input_dev); + } + 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_TOOL_FINGER, 0); + input_sync(ts->input_dev); + +#ifndef TPD_USE_EINT + hrtimer_cancel(&ts->timer); +#endif + +#ifdef SUPPORT_GESTURE + if( ts->gesture_enable ){ + atomic_set(&ts->is_stop,0); + if (mutex_trylock(&ts->mutex)){ + touch_enable(ts); + synaptics_enable_interrupt_for_gesture(ts, 1); + mutex_unlock(&ts->mutex); + TPD_ERR("enter gesture mode\n"); + } + //set_doze_time(2); /*change dozeinterval by firmware*/ + //just for fajita + if (ts->project_version == 0x03) { + mutex_lock(&ts->mutex); + tp_single_tap_en(ts, true); + mutex_unlock(&ts->mutex); + } + } + else{ + if (!ts->loading_fw) { + //loading_fw tp cannot enter sleep mode; + ret = synaptics_mode_change(0x01); + //when gesture disable TP sleep eary + if (ret < 0) { + TPD_ERR("%s line%d ERROR %d!\n", + __func__, __LINE__, ret); + } + } + } +#endif + TPD_DEBUG("%s normal end\n", __func__); + return 0; +} + +static void speedup_synaptics_resume(struct work_struct *work) +{ + int ret; + struct synaptics_ts_data *ts = ts_g; + +/*#ifdef SUPPORT_SLEEP_POWEROFF*/ + TPD_DEBUG("%s enter!\n", __func__); + if (ts->support_hw_poweroff) { + if (ts->gesture_enable == 0) { + ret = tpd_power(ts, 1); + if (ret < 0) + TPD_ERR("%s power on err\n", __func__); + if (ts->pinctrl) { + ret = pinctrl_select_state(ts->pinctrl, + ts->pinctrl_state_active); + } + } + } + TPD_DEBUG("%s end!\n", __func__); +/*#endif*/ +} + +static int synaptics_ts_resume(struct device *dev) +{ + int ret; + struct synaptics_ts_data *ts = dev_get_drvdata(dev); + int i; + + TPD_DEBUG("%s enter!\n", __func__); + + if(ts->loading_fw) { + TPD_ERR("%s FW is updating break!\n",__func__); + return -1; + } + + if(ts->input_dev == NULL) { + ret = -ENOMEM; + TPD_ERR("input_dev registration is not complete\n"); + goto ERR_RESUME; + } + 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, 1); + 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_TOOL_FINGER, 0); + input_sync(ts->input_dev); + + //touch_enable(ts); + + TPD_DEBUG("%s:normal end!\n", __func__); +ERR_RESUME: + return 0; +} + +static int synaptics_i2c_suspend(struct device *dev) +{ + int ret; + struct synaptics_ts_data *ts = dev_get_drvdata(dev); + + TPD_DEBUG("%s: is called\n", __func__); + if (ts->gesture_enable == 1){ + /*enable gpio wake system through intterrupt*/ + enable_irq_wake(ts->irq); + } +//#ifdef SUPPORT_SLEEP_POWEROFF + if(ts->loading_fw) { + TPD_ERR("FW is updating while suspending"); + return -1; + } + if(ts->support_hw_poweroff && (ts->gesture_enable == 0)){ + ret = tpd_power(ts,0); + if (ret < 0) + TPD_ERR("%s power off err\n",__func__); + if (ts->pinctrl){ + ret = pinctrl_select_state(ts->pinctrl, + ts->pinctrl_state_suspend); + } + } + return 0; +} + +static int synaptics_i2c_resume(struct device *dev) +{ + struct synaptics_ts_data *ts = dev_get_drvdata(dev); + + TPD_DEBUG("%s is called\n", __func__); + queue_delayed_work(synaptics_wq,&ts->speed_up_work, msecs_to_jiffies(1)); + if (ts->gesture_enable == 1){ + /*disable gpio wake system through intterrupt*/ + disable_irq_wake(ts->irq); + } + return 0; +} + +static int synaptics_mode_change(int mode) +{ + int ret; + int tmp_mode; + tmp_mode = i2c_smbus_read_byte_data(ts_g->client, F01_RMI_CTRL00); + tmp_mode = tmp_mode & 0xF8;//bit0-bit2(mode) + tmp_mode = tmp_mode | mode; + if (ts_g->changer_connet) + tmp_mode = tmp_mode | 0x20;//set bit6(change status) + else + tmp_mode = tmp_mode & 0xDF;//clear bit6(change status) + TPD_DEBUG("%s: set TP to mode[0x%x]\n", __func__,tmp_mode); + ret = i2c_smbus_write_byte_data(ts_g->client, F01_RMI_CTRL00, tmp_mode); + if(ret<0) + TPD_ERR("%s: set dose mode[0x%x] err!!\n", __func__,tmp_mode); + return ret; +} +#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; + static int gesture_flag; + + struct synaptics_ts_data *ts = container_of(self, struct synaptics_ts_data, fb_notif); + + if(FB_EARLY_EVENT_BLANK != event && FB_EVENT_BLANK != event) + return 0; + if((evdata) && (evdata->data) && (ts) && (ts->client)) + { + blank = evdata->data; + TPD_DEBUG("%s blank[%d],event[0x%lx]\n", __func__,*blank,event); + + if ((*blank == FB_BLANK_UNBLANK) + && (event == FB_EARLY_EVENT_BLANK)) { + if (gesture_flag == 1) { + ts->gesture_enable = 0; + DouTap_gesture = 0; + synaptics_enable_interrupt_for_gesture(ts, 0); + set_doze_time(1); + gesture_flag = 0; + } else if (gesture_flag == 2) { + DouTap_gesture = 0; + gesture_flag = 0; + } + if (ts->is_suspended == 1) + { + TPD_DEBUG("%s going TP resume start\n", __func__); + ts->is_suspended = 0; + queue_delayed_work(get_base_report, &ts->base_work,msecs_to_jiffies(80)); + synaptics_ts_resume(&ts->client->dev); + //atomic_set(&ts->is_stop,0); + TPD_DEBUG("%s going TP resume end\n", __func__); + } + } else if (*blank == FB_BLANK_NORMAL) { + if (ts->gesture_enable == 0) { + DouTap_gesture = 1; + ts->gesture_enable = 1; + i2c_smbus_write_byte_data(ts->client, 0xff, 0x0); + synaptics_mode_change(0x80); + synaptics_ts_suspend(&ts->client->dev); + gesture_flag = 1; + } else if ((ts->gesture_enable == 1) && (DouTap_gesture == 0)) { + DouTap_gesture = 1; + gesture_flag = 2; + } + }else if( *blank == FB_BLANK_POWERDOWN && (event == FB_EARLY_EVENT_BLANK )){ + if (gesture_flag == 1) { + ts->gesture_enable = 0; + DouTap_gesture = 0; + synaptics_enable_interrupt_for_gesture(ts, 0); + set_doze_time(1); + ts->is_suspended = 0; + gesture_flag = 0; + } else if (gesture_flag == 2) { + DouTap_gesture = 0; + ts->is_suspended = 0; + gesture_flag = 0; + } + if (ts->is_suspended == 0){ + TPD_DEBUG("%s : going TP suspend start\n", __func__); + ts->is_suspended = 1; + atomic_set(&ts->is_stop,1); + if (!(ts->gesture_enable)) + touch_disable(ts); + synaptics_ts_suspend(&ts->client->dev); + TPD_DEBUG("%s : going TP suspend end\n", __func__); + } + } + } + return 0; +} +#elif defined(CONFIG_MSM_RDM_NOTIFY) +static int msm_drm_notifier_callback( + struct notifier_block *self, unsigned long event, void *data) +{ + struct msm_drm_notifier *evdata = data; + int *blank; + + struct synaptics_ts_data *ts = container_of( + self, struct synaptics_ts_data, msm_drm_notif); + + if (event != MSM_DRM_EARLY_EVENT_BLANK + && MSM_DRM_EVENT_BLANK != event) + return 0; + if ((evdata) && (evdata->data) && (ts) && (ts->client)) { + blank = evdata->data; + TPD_ERR("%s blank[%d],event[0x%lx],evdata->id[%d]\n", + __func__, *blank, event, evdata->id); + + if ((*blank == MSM_DRM_BLANK_UNBLANK_CUST) + && (event == MSM_DRM_EARLY_EVENT_BLANK)) { + if (ts->is_suspended == 1) { + TPD_DEBUG("%s TP resume start\n", __func__); + ts->is_suspended = 0; + queue_delayed_work(get_base_report, + &ts->base_work, msecs_to_jiffies(10)); + synaptics_ts_resume(&ts->client->dev); + //atomic_set(&ts->is_stop,0); + TPD_DEBUG("%sTP resume end\n", __func__); + } + } else if (((*blank == MSM_DRM_BLANK_POWERDOWN_CUST) + && (event == MSM_DRM_EARLY_EVENT_BLANK)) + || (*blank == MSM_DRM_BLANK_NORMAL)) { + if (ts->is_suspended == 0) { + TPD_DEBUG("%s:TP suspend start\n", __func__); + ts->is_suspended = 1; + atomic_set(&ts->is_stop, 1); + cancel_delayed_work_sync(&ts->base_work); + flush_workqueue(get_base_report); + if (!(ts->gesture_enable)) + touch_disable(ts); + synaptics_ts_suspend(&ts->client->dev); + TPD_DEBUG("%s:TP suspend end\n", __func__); + } + } + if (ts->project_version == 0x03) + if (*blank == MSM_DRM_BLANK_POWERDOWN && + event == MSM_DRM_EVENT_BLANK && + ts->fp_aod_cnt > 0) { + set_tp_info(ts, 0); + gf_opticalfp_irq_handler(0); + } + } + return 0; + + +} +#endif + +static int __init tpd_driver_init(void) +{ + TPD_ERR("%s enter\n", __func__); + if( i2c_add_driver(&tpd_i2c_driver)!= 0 ){ + TPD_ERR("unable to add i2c driver.\n"); + return -1; + } + return 0; +} + +/* should never be called */ +static void __exit tpd_driver_exit(void) +{ + i2c_del_driver(&tpd_i2c_driver); + if(synaptics_wq ){ + destroy_workqueue(synaptics_wq); + synaptics_wq = NULL; + } + return; +} + +module_init(tpd_driver_init); +module_exit(tpd_driver_exit); + +MODULE_DESCRIPTION("Synaptics S3203 Touchscreen Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/synaptics_dsx_core.h b/drivers/input/touchscreen/synaptics_dsx_core.h new file mode 100644 index 000000000000..3ef54391a715 --- /dev/null +++ b/drivers/input/touchscreen/synaptics_dsx_core.h @@ -0,0 +1,552 @@ +/* + * Synaptics DSX touchscreen driver + * + * Copyright (C) 2012-2016 Synaptics Incorporated. All rights reserved. + * + * Copyright (C) 2012 Alexandra Chin + * Copyright (C) 2012 Scott Lin + * + * 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. + * + * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS + * EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, + * AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS. + * IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION + * WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED + * AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES + * NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS' + * TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S. + * DOLLARS. + */ + +#ifndef _SYNAPTICS_DSX_RMI4_H_ +#define _SYNAPTICS_DSX_RMI4_H_ + +#define SYNAPTICS_DS4 (1 << 0) +#define SYNAPTICS_DS5 (1 << 1) +#define SYNAPTICS_DSX_DRIVER_PRODUCT (SYNAPTICS_DS4 | SYNAPTICS_DS5) +#define SYNAPTICS_DSX_DRIVER_VERSION 0x206a + +#include +/*delete by morgan.gu for sdm845 */ +#undef CONFIG_FB + +#ifdef CONFIG_FB +#include +#include +#endif +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if (KERNEL_VERSION(2, 6, 38) < LINUX_VERSION_CODE) +#define KERNEL_ABOVE_2_6_38 +#endif + +#if (KERNEL_VERSION(3, 7, 0) <= LINUX_VERSION_CODE) +#define KERNEL_ABOVE_3_6 +#endif + +#ifdef KERNEL_ABOVE_2_6_38 +#define sstrtoul(...) kstrtoul(__VA_ARGS__) +#else +#define sstrtoul(...) kstrtoul(__VA_ARGS__) +#endif +/* + *#define F51_DISCRETE_FORCE + *#ifdef F51_DISCRETE_FORCE + *#define FORCE_LEVEL_ADDR 0x0419 + *#define FORCE_LEVEL_MAX 255 + *#define CAL_DATA_SIZE 144 + *#endif + */ + +#define PDT_PROPS (0X00EF) +#define PDT_START (0x00E9) +#define PDT_END (0x00D0) +#define PDT_ENTRY_SIZE (0x0006) +#define PAGES_TO_SERVICE (10) +#define PAGE_SELECT_LEN (2) +#define ADDRESS_LEN (2) + +#define SYNAPTICS_RMI4_F01 (0x01) +#define SYNAPTICS_RMI4_F11 (0x11) +#define SYNAPTICS_RMI4_F12 (0x12) +#define SYNAPTICS_RMI4_F1A (0x1A) +#define SYNAPTICS_RMI4_F21 (0x21) +#define SYNAPTICS_RMI4_F34 (0x34) +#define SYNAPTICS_RMI4_F35 (0x35) +#define SYNAPTICS_RMI4_F38 (0x38) +#define SYNAPTICS_RMI4_F51 (0x51) +#define SYNAPTICS_RMI4_F54 (0x54) +#define SYNAPTICS_RMI4_F55 (0x55) +#define SYNAPTICS_RMI4_FDB (0xDB) + +#define PRODUCT_INFO_SIZE 2 +#define PRODUCT_ID_SIZE 10 +#define BUILD_ID_SIZE 3 + +#define F12_FINGERS_TO_SUPPORT 10 +#define F12_NO_OBJECT_STATUS 0x00 +#define F12_FINGER_STATUS 0x01 +#define F12_ACTIVE_STYLUS_STATUS 0x02 +#define F12_PALM_STATUS 0x03 +#define F12_HOVERING_FINGER_STATUS 0x05 +#define F12_GLOVED_FINGER_STATUS 0x06 +#define F12_NARROW_OBJECT_STATUS 0x07 +#define F12_HAND_EDGE_STATUS 0x08 +#define F12_COVER_STATUS 0x0A +#define F12_STYLUS_STATUS 0x0B +#define F12_ERASER_STATUS 0x0C +#define F12_SMALL_OBJECT_STATUS 0x0D + +#define F12_GESTURE_DETECTION_LEN 5 + +#define MAX_NUMBER_OF_BUTTONS 4 +#define MAX_INTR_REGISTERS 4 + +#define MASK_16BIT 0xFFFF +#define MASK_8BIT 0xFF +#define MASK_7BIT 0x7F +#define MASK_6BIT 0x3F +#define MASK_5BIT 0x1F +#define MASK_4BIT 0x0F +#define MASK_3BIT 0x07 +#define MASK_2BIT 0x03 +#define MASK_1BIT 0x01 + +enum exp_fn { + RMI_DEV = 0, + RMI_FW_UPDATER, + RMI_TEST_REPORTING, + RMI_PROXIMITY, + RMI_ACTIVE_PEN, + RMI_GESTURE, + RMI_VIDEO, + RMI_DEBUG, + RMI_LAST, +}; + +/* + * struct synaptics_rmi4_fn_desc2- function descriptor fields in PDT entry + * @query_base_addr: base address for query registers + * @cmd_base_addr: base address for command registers + * @ctrl_base_addr: base address for control registers + * @data_base_addr: base address for data registers + * @intr_src_count: number of interrupt sources + * @fn_version: version of function + * @fn_number: function number + */ +struct synaptics_rmi4_fn_desc2 { + union { + struct { + unsigned char query_base_addr; + unsigned char cmd_base_addr; + unsigned char ctrl_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; + unsigned char data[6]; + }; +}; + +/* + * synaptics_rmi4_fn_full_addr - full 16-bit base addresses + * @query_base: 16-bit base address for query registers + * @cmd_base: 16-bit base address for command registers + * @ctrl_base: 16-bit base address for control registers + * @data_base: 16-bit base address for data registers + */ +struct synaptics_rmi4_fn_full_addr { + unsigned short query_base; + unsigned short cmd_base; + unsigned short ctrl_base; + unsigned short data_base; +}; + +/* + * struct synaptics_rmi4_f11_extra_data - extra data of F$11 + * @data38_offset: offset to F11_2D_DATA38 register + */ +struct synaptics_rmi4_f11_extra_data { + unsigned char data38_offset; +}; + +/* + * struct synaptics_rmi4_f12_extra_data - extra data of F$12 + * @data1_offset: offset to F12_2D_DATA01 register + * @data4_offset: offset to F12_2D_DATA04 register + * @data15_offset: offset to F12_2D_DATA15 register + * @data15_size: size of F12_2D_DATA15 register + * @data15_data: buffer for reading F12_2D_DATA15 register + * @data29_offset: offset to F12_2D_DATA29 register + * @data29_size: size of F12_2D_DATA29 register + * @data29_data: buffer for reading F12_2D_DATA29 register + * @ctrl20_offset: offset to F12_2D_CTRL20 register + */ +struct synaptics_rmi4_f12_extra_data { + unsigned char data1_offset; + unsigned char data4_offset; + unsigned char data15_offset; + unsigned char data15_size; + unsigned char data15_data[(F12_FINGERS_TO_SUPPORT + 7) / 8]; + unsigned char data29_offset; + unsigned char data29_size; + unsigned char data29_data[F12_FINGERS_TO_SUPPORT]; + unsigned char ctrl20_offset; +}; + +/* + * struct synaptics_rmi4_fn - RMI function handler + * @fn_number: function number + * @num_of_data_sources: number of data sources + * @num_of_data_points: maximum number of fingers supported + * @intr_reg_num: index to associated interrupt register + * @intr_mask: interrupt mask + * @full_addr: full 16-bit base addresses of function registers + * @link: linked list for function handlers + * @data_size: size of private data + * @data: pointer to private data + * @extra: pointer to extra data + */ +struct synaptics_rmi4_fn { + unsigned char fn_number; + unsigned char num_of_data_sources; + unsigned char num_of_data_points; + unsigned char intr_reg_num; + unsigned char intr_mask; + struct synaptics_rmi4_fn_full_addr full_addr; + struct list_head link; + int data_size; + void *data; + void *extra; +}; + +/* + * struct synaptics_rmi4_input_settings - current input settings + * @num_of_fingers: maximum number of fingers for 2D touch + * @valid_button_count: number of valid 0D buttons + * @max_touch_width: maximum touch width + * @sensor_max_x: maximum x coordinate for 2D touch + * @sensor_max_y: maximum y coordinate for 2D touch + * @force_min: minimum force value + * @force_max: maximum force value + * @stylus_enable: flag to indicate reporting of stylus data + * @eraser_enable: flag to indicate reporting of eraser data + */ +struct synaptics_rmi4_input_settings { + unsigned char num_of_fingers; + unsigned char valid_button_count; + unsigned char max_touch_width; + int sensor_max_x; + int sensor_max_y; + int force_min; + int force_max; + bool stylus_enable; + bool eraser_enable; +}; + +/* + * struct synaptics_rmi4_device_info - device information + * @version_major: RMI protocol major version number + * @version_minor: RMI protocol minor version number + * @manufacturer_id: manufacturer ID + * @product_props: product properties + * @product_info: product information + * @product_id_string: product ID + * @build_id: firmware build ID + * @support_fn_list: linked list for function handlers + */ +struct synaptics_rmi4_device_info { + unsigned int version_major; + unsigned int version_minor; + unsigned char manufacturer_id; + unsigned char product_props; + unsigned char product_info[PRODUCT_INFO_SIZE]; + unsigned char product_id_string[PRODUCT_ID_SIZE + 1]; + unsigned char build_id[BUILD_ID_SIZE]; + struct list_head support_fn_list; +}; + +/* + * struct synaptics_rmi4_data - RMI4 device instance data + * @pdev: pointer to platform device + * @input_dev: pointer to associated input device + * @stylus_dev: pointer to associated stylus device + * @hw_if: pointer to hardware interface data + * @rmi4_mod_info: device information + * @board_prop_dir: /sys/board_properties directory for virtual key map file + * @pwr_reg: pointer to regulator for power control + * @bus_reg: pointer to regulator for bus pullup control + * @rmi4_reset_mutex: mutex for software reset + * @rmi4_report_mutex: mutex for input event reporting + * @rmi4_io_ctrl_mutex: mutex for communication interface I/O + * @rmi4_exp_init_mutex: mutex for expansion function module initialization + * @rmi4_irq_enable_mutex: mutex for enabling/disabling interrupt + * @rb_work: work for rebuilding input device + * @rb_workqueue: workqueue for rebuilding input device + * @fb_notifier: framebuffer notifier client + * @reset_work: work for issuing reset after display framebuffer ready + * @reset_workqueue: workqueue for issuing reset after display framebuffer ready + * @early_suspend: early suspend power management + * @current_page: current RMI page for register access + * @button_0d_enabled: switch for enabling 0d button support + * @num_of_tx: number of Tx channels for 2D touch + * @num_of_rx: number of Rx channels for 2D touch + * @num_of_fingers: maximum number of fingers for 2D touch + * @max_touch_width: maximum touch width + * @valid_button_count: number of valid 0D buttons + * @report_enable: input data to report for F$12 + * @no_sleep_setting: default setting of NoSleep in F01_RMI_CTRL00 register + * @gesture_detection: detected gesture type and properties + * @intr_mask: interrupt enable mask + * @button_txrx_mapping: Tx Rx mapping of 0D buttons + * @num_of_intr_regs: number of interrupt registers + * @f01_query_base_addr: query base address for f$01 + * @f01_cmd_base_addr: command base address for f$01 + * @f01_ctrl_base_addr: control base address for f$01 + * @f01_data_base_addr: data base address for f$01 + * @f51_query_base_addr: query base address for f$51 + * @firmware_id: firmware build ID + * @irq: attention interrupt + * @sensor_max_x: maximum x coordinate for 2D touch + * @sensor_max_y: maximum y coordinate for 2D touch + * @force_min: minimum force value + * @force_max: maximum force value + * @flash_prog_mode: flag to indicate flash programming mode status + * @irq_enabled: flag to indicate attention interrupt enable status + * @fingers_on_2d: flag to indicate presence of fingers in 2D area + * @suspend: flag to indicate whether in suspend state + * @sensor_sleep: flag to indicate sleep state of sensor + * @stay_awake: flag to indicate whether to stay awake during suspend + * @fb_ready: flag to indicate whether display framebuffer in ready state + * @f11_wakeup_gesture: flag to indicate support for wakeup gestures in F$11 + * @f12_wakeup_gesture: flag to indicate support for wakeup gestures in F$12 + * @enable_wakeup_gesture: flag to indicate usage of wakeup gestures + * @wedge_sensor: flag to indicate use of wedge sensor + * @report_pressure: flag to indicate reporting of pressure data + * @stylus_enable: flag to indicate reporting of stylus data + * @eraser_enable: flag to indicate reporting of eraser data + * @external_afe_buttons: flag to indicate presence of external AFE buttons + * @reset_device: pointer to device reset function + * @irq_enable: pointer to interrupt enable function + * @sleep_enable: pointer to sleep enable function + * @report_touch: pointer to touch reporting function + */ +struct synaptics_rmi4_data { + struct platform_device *pdev; + struct input_dev *input_dev; + struct input_dev *stylus_dev; + const struct synaptics_dsx_hw_interface *hw_if; + struct synaptics_rmi4_device_info rmi4_mod_info; + struct synaptics_rmi4_input_settings input_settings; + struct kobject *board_prop_dir; + struct regulator *pwr_reg; + struct regulator *bus_reg; + struct mutex rmi4_reset_mutex; + struct mutex rmi4_report_mutex; + struct mutex rmi4_io_ctrl_mutex; + struct mutex rmi4_exp_init_mutex; + struct mutex rmi4_irq_enable_mutex; + struct delayed_work rb_work; + struct workqueue_struct *rb_workqueue; +#ifdef CONFIG_FB + struct notifier_block fb_notifier; + struct work_struct reset_work; + struct workqueue_struct *reset_workqueue; +#endif +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend early_suspend; +#endif + unsigned char current_page; + unsigned char button_0d_enabled; + unsigned char num_of_tx; + unsigned char num_of_rx; + unsigned char num_of_fingers; + unsigned char max_touch_width; + unsigned char valid_button_count; + unsigned char report_enable; + unsigned char no_sleep_setting; + unsigned char gesture_detection[F12_GESTURE_DETECTION_LEN]; + unsigned char intr_mask[MAX_INTR_REGISTERS]; + unsigned char *button_txrx_mapping; + unsigned short num_of_intr_regs; + unsigned short f01_query_base_addr; + unsigned short f01_cmd_base_addr; + unsigned short f01_ctrl_base_addr; + unsigned short f01_data_base_addr; +#ifdef F51_DISCRETE_FORCE + unsigned short f51_query_base_addr; +#endif + unsigned int firmware_id; + int irq; + int sensor_max_x; + int sensor_max_y; + int force_min; + int force_max; + bool flash_prog_mode; + bool irq_enabled; + bool fingers_on_2d; + bool suspend; + bool sensor_sleep; + bool stay_awake; + bool fb_ready; + bool f11_wakeup_gesture; + bool f12_wakeup_gesture; + bool enable_wakeup_gesture; + bool wedge_sensor; + bool report_pressure; + bool stylus_enable; + bool eraser_enable; + bool external_afe_buttons; + int (*reset_device)(struct i2c_client *client, + bool rebuild); + int (*irq_enable)(struct synaptics_rmi4_data *rmi4_data, bool enable, + bool attn_only); + void (*sleep_enable)(struct synaptics_rmi4_data *rmi4_data, + bool enable); + void (*report_touch)(struct synaptics_rmi4_data *rmi4_data, + struct synaptics_rmi4_fn *fhandler); + struct device *s3706_dev; + bool force; +}; + +struct synaptics_dsx_bus_access { + unsigned char type; + int (*read)(struct synaptics_rmi4_data *rmi4_data, unsigned short addr, + unsigned char *data, unsigned short length); + int (*write)(struct synaptics_rmi4_data *rmi4_data, unsigned short addr, + unsigned char *data, unsigned short length); +}; + +struct synaptics_dsx_hw_interface { + struct synaptics_dsx_board_data *board_data; + const struct synaptics_dsx_bus_access *bus_access; + int (*bl_hw_init)(struct synaptics_rmi4_data *rmi4_data); + int (*ui_hw_init)(struct synaptics_rmi4_data *rmi4_data); +}; + +struct synaptics_rmi4_exp_fn { + enum exp_fn fn_type; + int (*init)(struct synaptics_rmi4_data *rmi4_data); + void (*remove)(struct synaptics_rmi4_data *rmi4_data); + void (*reset)(struct synaptics_rmi4_data *rmi4_data); + void (*reinit)(struct synaptics_rmi4_data *rmi4_data); + void (*early_suspend)(struct synaptics_rmi4_data *rmi4_data); + void (*suspend)(struct synaptics_rmi4_data *rmi4_data); + void (*resume)(struct synaptics_rmi4_data *rmi4_data); + void (*late_resume)(struct synaptics_rmi4_data *rmi4_data); + void (*attn)(struct synaptics_rmi4_data *rmi4_data, + unsigned char intr_mask); +}; + +extern unsigned int tp_debug; +int synaptics_rmi4_bus_init(void); +void synaptics_rmi4_bus_exit(void); +void synaptics_rmi4_new_function( + struct synaptics_rmi4_exp_fn *exp_fn_module, + bool insert); +int synaptics_fw_updater( + const unsigned char *fw_data, + const unsigned char *fw_image); +int synaptics_rmi4_fwu_init( + struct synaptics_rmi4_data *rmi4_data, + const unsigned char *fw_image, struct i2c_client *client); +/*Added for larger than 32 length read!*/ +extern int synaptics_rmi4_i2c_read_block( + struct i2c_client *client, + unsigned char addr, + unsigned short length, + unsigned char *data); +extern int synaptics_rmi4_i2c_write_block( + struct i2c_client *client, + unsigned char addr, + unsigned short length, + unsigned char const *data); +static inline int synaptics_rmi4_reg_read( + struct i2c_client *i2c, + unsigned short addr, + unsigned char *data, + unsigned short len) +{ + return synaptics_rmi4_i2c_read_block(i2c, addr, len, data); +} + +static inline int synaptics_rmi4_reg_write( + struct i2c_client *i2c, + unsigned short addr, + unsigned char *data, + unsigned short len) +{ + return synaptics_rmi4_i2c_write_block(i2c, addr, len, data); +} + +static inline ssize_t synaptics_rmi4_show_error(struct device *dev, + struct device_attribute *attr, char *buf) +{ + dev_warn(dev, "%s Attempted to read from write-only attribute %s\n", + __func__, attr->attr.name); + return -EPERM; +} + +static inline ssize_t synaptics_rmi4_store_error(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + dev_warn(dev, "%s Attempted to write to read-only attribute %s\n", + __func__, attr->attr.name); + return -EPERM; +} + +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) + return -EINVAL; + + memcpy((void *)dest, (const void *)src, count); + + return 0; +} + +static inline void batohs(unsigned short *dest, unsigned char *src) +{ + *dest = src[1] * 0x100 + src[0]; +} + +static inline void hstoba(unsigned char *dest, unsigned short src) +{ + dest[0] = src % 0x100; + dest[1] = src / 0x100; +} + +#endif diff --git a/drivers/input/touchscreen/synaptics_dsx_fw_update.c b/drivers/input/touchscreen/synaptics_dsx_fw_update.c new file mode 100644 index 000000000000..719fcfc30103 --- /dev/null +++ b/drivers/input/touchscreen/synaptics_dsx_fw_update.c @@ -0,0 +1,4094 @@ +/* + * Synaptics DSX touchscreen driver + * + * Copyright (C) 2012-2016 Synaptics Incorporated. All rights reserved. + * + * Copyright (C) 2012 Alexandra Chin + * Copyright (C) 2012 Scott Lin + * + * 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. + * + * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS + * EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, + * AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS. + * IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION + * WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED + * AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES + * NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS' + * TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S. + * DOLLARS. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "synaptics_dsx_core.h" + +#define FW_IHEX_NAME "tp/fw_synaptics_17819.img" +#define FW_IMAGE_NAME "tp/fw_synaptics_17819.img" + +/*#define DO_STARTUP_FW_UPDATE*/ +/*delete by morgan.gu for sdm845 */ +#undef CONFIG_FB + +#ifdef DO_STARTUP_FW_UPDATE +#ifdef CONFIG_FB +#define WAIT_FOR_FB_READY +#define FB_READY_WAIT_MS 100 +#define FB_READY_TIMEOUT_S 30 +#endif +#endif + +/*********************for Debug LOG switch*******************/ +#define TPD_DEVICE "synaptics,s3320_firmware" +#define TPD_ERR(a, arg...) pr_err(TPD_DEVICE ": " a, ##arg) +#define TPDTM_DMESG(a, arg...) printk(TPD_DEVICE ": " a, ##arg) + +#define TPD_DEBUG(a, arg...)\ + do {\ + if (tp_debug) \ + pr_err(TPD_DEVICE ": " a, ##arg);\ + } while (0) + +#define MAX_WRITE_SIZE 4096 + +#define FORCE_UPDATE false +#define DO_LOCKDOWN false + +#define MAX_IMAGE_NAME_LEN 256 +#define MAX_FIRMWARE_ID_LEN 10 + +#define IMAGE_HEADER_VERSION_05 0x05 +#define IMAGE_HEADER_VERSION_06 0x06 +#define IMAGE_HEADER_VERSION_10 0x10 + +#define IMAGE_AREA_OFFSET 0x100 +#define LOCKDOWN_SIZE 0x50 + +#define MAX_UTILITY_PARAMS 20 + +#define V5V6_BOOTLOADER_ID_OFFSET 0 +#define V5V6_CONFIG_ID_SIZE 4 + +#define V5_PROPERTIES_OFFSET 2 +#define V5_BLOCK_SIZE_OFFSET 3 +#define V5_BLOCK_COUNT_OFFSET 5 +#define V5_BLOCK_NUMBER_OFFSET 0 +#define V5_BLOCK_DATA_OFFSET 2 + +#define V6_PROPERTIES_OFFSET 1 +#define V6_BLOCK_SIZE_OFFSET 2 +#define V6_BLOCK_COUNT_OFFSET 3 +#define V6_PROPERTIES_2_OFFSET 4 +#define V6_GUEST_CODE_BLOCK_COUNT_OFFSET 5 +#define V6_BLOCK_NUMBER_OFFSET 0 +#define V6_BLOCK_DATA_OFFSET 1 +#define V6_FLASH_COMMAND_OFFSET 2 +#define V6_FLASH_STATUS_OFFSET 3 + +#define V7_CONFIG_ID_SIZE 32 + +#define V7_FLASH_STATUS_OFFSET 0 +#define V7_PARTITION_ID_OFFSET 1 +#define V7_BLOCK_NUMBER_OFFSET 2 +#define V7_TRANSFER_LENGTH_OFFSET 3 +#define V7_COMMAND_OFFSET 4 +#define V7_PAYLOAD_OFFSET 5 + +#define V7_PARTITION_SUPPORT_BYTES 4 + +#define F35_ERROR_CODE_OFFSET 0 +#define F35_FLASH_STATUS_OFFSET 5 +#define F35_CHUNK_NUM_LSB_OFFSET 0 +#define F35_CHUNK_NUM_MSB_OFFSET 1 +#define F35_CHUNK_DATA_OFFSET 2 +#define F35_CHUNK_COMMAND_OFFSET 18 + +#define F35_CHUNK_SIZE 16 +#define F35_ERASE_ALL_WAIT_MS 5000 +#define F35_RESET_WAIT_MS 250 + +#define SLEEP_MODE_NORMAL (0x00) +#define SLEEP_MODE_SENSOR_SLEEP (0x01) +#define SLEEP_MODE_RESERVED0 (0x02) +#define SLEEP_MODE_RESERVED1 (0x03) + +#define ENABLE_WAIT_MS (1 * 1000) +#define WRITE_WAIT_MS (3 * 1000) +#define ERASE_WAIT_MS (5 * 1000) + +#define MIN_SLEEP_TIME_US 50 +#define MAX_SLEEP_TIME_US 100 + +#define INT_DISABLE_WAIT_MS 20 +#define ENTER_FLASH_PROG_WAIT_MS 20 + +static int fwu_do_reflash(void); + +static int fwu_recovery_check_status(void); + +enum f34_version { + F34_V0 = 0, + F34_V1, + F34_V2, +}; + +enum bl_version { + BL_V5 = 5, + BL_V6 = 6, + BL_V7 = 7, + BL_V8 = 8, +}; + +enum flash_area { + NONE = 0, + UI_FIRMWARE, + UI_CONFIG, +}; + +enum update_mode { + NORMAL = 1, + FORCE = 2, + LOCKDOWN = 8, +}; + +enum config_area { + UI_CONFIG_AREA = 0, + PM_CONFIG_AREA, + BL_CONFIG_AREA, + DP_CONFIG_AREA, + FLASH_CONFIG_AREA, + UPP_AREA, +}; + +enum v7_status { + SUCCESS = 0x00, + DEVICE_NOT_IN_BOOTLOADER_MODE, + INVALID_PARTITION, + INVALID_COMMAND, + INVALID_BLOCK_OFFSET, + INVALID_TRANSFER, + NOT_ERASED, + FLASH_PROGRAMMING_KEY_INCORRECT, + BAD_PARTITION_TABLE, + CHECKSUM_FAILED, + FLASH_HARDWARE_FAILURE = 0x1f, +}; + +enum v7_partition_id { + BOOTLOADER_PARTITION = 0x01, + DEVICE_CONFIG_PARTITION, + FLASH_CONFIG_PARTITION, + MANUFACTURING_BLOCK_PARTITION, + GUEST_SERIALIZATION_PARTITION, + GLOBAL_PARAMETERS_PARTITION, + CORE_CODE_PARTITION, + CORE_CONFIG_PARTITION, + GUEST_CODE_PARTITION, + DISPLAY_CONFIG_PARTITION, + EXTERNAL_TOUCH_AFE_CONFIG_PARTITION, + UTILITY_PARAMETER_PARTITION, +}; + +enum v7_flash_command { + CMD_V7_IDLE = 0x00, + CMD_V7_ENTER_BL, + CMD_V7_READ, + CMD_V7_WRITE, + CMD_V7_ERASE, + CMD_V7_ERASE_AP, + CMD_V7_SENSOR_ID, +}; + +enum v5v6_flash_command { + CMD_V5V6_IDLE = 0x0, + CMD_V5V6_WRITE_FW = 0x2, + CMD_V5V6_ERASE_ALL = 0x3, + CMD_V5V6_WRITE_LOCKDOWN = 0x4, + CMD_V5V6_READ_CONFIG = 0x5, + CMD_V5V6_WRITE_CONFIG = 0x6, + CMD_V5V6_ERASE_UI_CONFIG = 0x7, + CMD_V5V6_ERASE_BL_CONFIG = 0x9, + CMD_V5V6_ERASE_DISP_CONFIG = 0xa, + CMD_V5V6_ERASE_GUEST_CODE = 0xb, + CMD_V5V6_WRITE_GUEST_CODE = 0xc, + CMD_V5V6_ENABLE_FLASH_PROG = 0xf, +}; + +enum flash_command { + CMD_IDLE = 0, + CMD_WRITE_FW, + CMD_WRITE_CONFIG, + CMD_WRITE_LOCKDOWN, + CMD_WRITE_GUEST_CODE, + CMD_WRITE_BOOTLOADER, + CMD_WRITE_UTILITY_PARAM, + CMD_READ_CONFIG, + CMD_ERASE_ALL, + CMD_ERASE_UI_FIRMWARE, + CMD_ERASE_UI_CONFIG, + CMD_ERASE_BL_CONFIG, + CMD_ERASE_DISP_CONFIG, + CMD_ERASE_FLASH_CONFIG, + CMD_ERASE_GUEST_CODE, + CMD_ERASE_BOOTLOADER, + CMD_ERASE_UTILITY_PARAMETER, + CMD_ENABLE_FLASH_PROG, +}; + +enum f35_flash_command { + CMD_F35_IDLE = 0x0, + CMD_F35_RESERVED = 0x1, + CMD_F35_WRITE_CHUNK = 0x2, + CMD_F35_ERASE_ALL = 0x3, + CMD_F35_RESET = 0x10, +}; + +enum container_id { + TOP_LEVEL_CONTAINER = 0, + UI_CONTAINER, + UI_CONFIG_CONTAINER, + BL_CONTAINER, + BL_IMAGE_CONTAINER, + BL_CONFIG_CONTAINER, + BL_LOCKDOWN_INFO_CONTAINER, + PERMANENT_CONFIG_CONTAINER, + GUEST_CODE_CONTAINER, + BL_PROTOCOL_DESCRIPTOR_CONTAINER, + UI_PROTOCOL_DESCRIPTOR_CONTAINER, + RMI_SELF_DISCOVERY_CONTAINER, + RMI_PAGE_CONTENT_CONTAINER, + GENERAL_INFORMATION_CONTAINER, + DEVICE_CONFIG_CONTAINER, + FLASH_CONFIG_CONTAINER, + GUEST_SERIALIZATION_CONTAINER, + GLOBAL_PARAMETERS_CONTAINER, + CORE_CODE_CONTAINER, + CORE_CONFIG_CONTAINER, + DISPLAY_CONFIG_CONTAINER, + EXTERNAL_TOUCH_AFE_CONFIG_CONTAINER, + UTILITY_CONTAINER, + UTILITY_PARAMETER_CONTAINER, +}; + +enum utility_parameter_id { + UNUSED = 0, + FORCE_PARAMETER, + ANTI_BENDING_PARAMETER, +}; + +struct pdt_properties { + union { + struct { + unsigned char reserved_1:6; + unsigned char has_bsr:1; + unsigned char reserved_2:1; + } __packed; + unsigned char data[1]; + }; +}; + +struct partition_table { + unsigned char partition_id:5; + unsigned char byte_0_reserved:3; + unsigned char byte_1_reserved; + unsigned char partition_length_7_0; + unsigned char partition_length_15_8; + unsigned char start_physical_address_7_0; + unsigned char start_physical_address_15_8; + unsigned char partition_properties_7_0; + unsigned char partition_properties_15_8; +} __packed; + +struct f01_device_control { + union { + struct { + unsigned char sleep_mode:2; + unsigned char nosleep:1; + unsigned char reserved:2; + unsigned char charger_connected:1; + unsigned char report_rate:1; + unsigned char configured:1; + } __packed; + unsigned char data[1]; + }; +}; + +struct f34_v7_query_0 { + union { + struct { + unsigned char subpacket_1_size:3; + unsigned char has_config_id:1; + unsigned char f34_query0_b4:1; + unsigned char has_thqa:1; + unsigned char f34_query0_b6__7:2; + } __packed; + unsigned char data[1]; + }; +}; + +struct f34_v7_query_1_7 { + union { + struct { + /* query 1 */ + unsigned char bl_minor_revision; + unsigned char bl_major_revision; + + /* query 2 */ + unsigned char bl_fw_id_7_0; + unsigned char bl_fw_id_15_8; + unsigned char bl_fw_id_23_16; + unsigned char bl_fw_id_31_24; + + /* query 3 */ + unsigned char minimum_write_size; + unsigned char block_size_7_0; + unsigned char block_size_15_8; + unsigned char flash_page_size_7_0; + unsigned char flash_page_size_15_8; + + /* query 4 */ + unsigned char adjustable_partition_area_size_7_0; + unsigned char adjustable_partition_area_size_15_8; + + /* query 5 */ + unsigned char flash_config_length_7_0; + unsigned char flash_config_length_15_8; + + /* query 6 */ + unsigned char payload_length_7_0; + unsigned char payload_length_15_8; + + /* query 7 */ + unsigned char f34_query7_b0:1; + unsigned char has_bootloader:1; + unsigned char has_device_config:1; + unsigned char has_flash_config:1; + unsigned char has_manufacturing_block:1; + unsigned char has_guest_serialization:1; + unsigned char has_global_parameters:1; + unsigned char has_core_code:1; + unsigned char has_core_config:1; + unsigned char has_guest_code:1; + unsigned char has_display_config:1; + unsigned char f34_query7_b11__15:5; + unsigned char f34_query7_b16__23; + unsigned char f34_query7_b24__31; + } __packed; + unsigned char data[21]; + }; +}; + +struct f34_v7_data0 { + union { + struct { + unsigned char operation_status:5; + unsigned char device_cfg_status:2; + unsigned char bl_mode:1; + } __packed; + unsigned char data[1]; + }; +}; + +struct f34_v7_data_1_5 { + union { + struct { + unsigned char partition_id:5; + unsigned char f34_data1_b5__7:3; + unsigned char block_offset_7_0; + unsigned char block_offset_15_8; + unsigned char transfer_length_7_0; + unsigned char transfer_length_15_8; + unsigned char command; + unsigned char payload_0; + unsigned char payload_1; + } __packed; + unsigned char data[8]; + }; +}; + +struct f34_v5v6_flash_properties { + union { + struct { + unsigned char reg_map:1; + unsigned char unlocked:1; + unsigned char has_config_id:1; + unsigned char has_pm_config:1; + unsigned char has_bl_config:1; + unsigned char has_disp_config:1; + unsigned char has_ctrl1:1; + unsigned char has_query4:1; + } __packed; + unsigned char data[1]; + }; +}; + +struct f34_v5v6_flash_properties_2 { + union { + struct { + unsigned char has_guest_code:1; + unsigned char reserved:7; + } __packed; + unsigned char data[1]; + }; +}; + +struct register_offset { + unsigned char properties; + unsigned char properties_2; + unsigned char block_size; + unsigned char block_count; + unsigned char gc_block_count; + unsigned char flash_status; + unsigned char partition_id; + unsigned char block_number; + unsigned char transfer_length; + unsigned char flash_cmd; + unsigned char payload; +}; + +struct block_count { + unsigned short ui_firmware; + unsigned short ui_config; + unsigned short dp_config; + unsigned short pm_config; + unsigned short fl_config; + unsigned short bl_image; + unsigned short bl_config; + unsigned short utility_param; + unsigned short lockdown; + unsigned short guest_code; + unsigned short total_count; +}; + +struct physical_address { + unsigned short ui_firmware; + unsigned short ui_config; + unsigned short dp_config; + unsigned short pm_config; + unsigned short fl_config; + unsigned short bl_image; + unsigned short bl_config; + unsigned short utility_param; + unsigned short lockdown; + unsigned short guest_code; +}; + +struct container_descriptor { + unsigned char content_checksum[4]; + unsigned char container_id[2]; + unsigned char minor_version; + unsigned char major_version; + unsigned char reserved_08; + unsigned char reserved_09; + unsigned char reserved_0a; + unsigned char reserved_0b; + unsigned char container_option_flags[4]; + unsigned char content_options_length[4]; + unsigned char content_options_address[4]; + unsigned char content_length[4]; + unsigned char content_address[4]; +}; + +struct image_header_10 { + unsigned char checksum[4]; + unsigned char reserved_04; + unsigned char reserved_05; + unsigned char minor_header_version; + unsigned char major_header_version; + unsigned char reserved_08; + unsigned char reserved_09; + unsigned char reserved_0a; + unsigned char reserved_0b; + unsigned char top_level_container_start_addr[4]; +}; + +struct image_header_05_06 { + /* 0x00 - 0x0f */ + unsigned char checksum[4]; + unsigned char reserved_04; + unsigned char reserved_05; + unsigned char options_firmware_id:1; + unsigned char options_bootloader:1; + unsigned char options_guest_code:1; + unsigned char options_tddi:1; + unsigned char options_reserved:4; + unsigned char header_version; + unsigned char firmware_size[4]; + unsigned char config_size[4]; + /* 0x10 - 0x1f */ + unsigned char product_id[PRODUCT_ID_SIZE]; + unsigned char package_id[2]; + unsigned char package_id_revision[2]; + unsigned char product_info[PRODUCT_INFO_SIZE]; + /* 0x20 - 0x2f */ + unsigned char bootloader_addr[4]; + unsigned char bootloader_size[4]; + unsigned char ui_addr[4]; + unsigned char ui_size[4]; + /* 0x30 - 0x3f */ + unsigned char ds_id[16]; + /* 0x40 - 0x4f */ + union { + struct { + unsigned char cstmr_product_id[PRODUCT_ID_SIZE]; + unsigned char reserved_4a_4f[6]; + }; + struct { + unsigned char dsp_cfg_addr[4]; + unsigned char dsp_cfg_size[4]; + unsigned char reserved_48_4f[8]; + }; + }; + /* 0x50 - 0x53 */ + unsigned char firmware_id[4]; +}; + +struct block_data { + unsigned int size; + const unsigned char *data; +}; + +struct image_metadata { + bool contains_firmware_id; + bool contains_bootloader; + bool contains_guest_code; + bool contains_disp_config; + bool contains_perm_config; + bool contains_flash_config; + bool contains_utility_param; + unsigned int firmware_id; + unsigned int checksum; + unsigned int bootloader_size; + unsigned int disp_config_offset; + unsigned char bl_version; + unsigned char product_id[PRODUCT_ID_SIZE + 1]; + unsigned char cstmr_product_id[PRODUCT_ID_SIZE + 1]; + unsigned char utility_param_id[MAX_UTILITY_PARAMS]; + struct block_data bootloader; + struct block_data utility; + struct block_data ui_firmware; + struct block_data ui_config; + struct block_data dp_config; + struct block_data pm_config; + struct block_data fl_config; + struct block_data bl_image; + struct block_data bl_config; + struct block_data utility_param[MAX_UTILITY_PARAMS]; + struct block_data lockdown; + struct block_data guest_code; + struct block_count blkcount; + struct physical_address phyaddr; +}; + +struct synaptics_rmi4_fwu_handle { + enum bl_version bl_version; + bool initialized; + bool in_bl_mode; + bool in_ub_mode; + bool bl_mode_device; + bool force_update; + bool do_lockdown; + bool has_guest_code; + bool has_utility_param; + bool new_partition_table; + bool incompatible_partition_tables; + bool write_bootloader; + unsigned int data_pos; + unsigned char *ext_data_source; + unsigned char *read_config_buf; + unsigned char intr_mask; + unsigned char command; + unsigned char bootloader_id[2]; + unsigned char config_id[32]; + unsigned char flash_status; + unsigned char partitions; +#ifdef F51_DISCRETE_FORCE + unsigned char *cal_data; + unsigned short cal_data_off; + unsigned short cal_data_size; + unsigned short cal_data_buf_size; + unsigned short cal_packet_data_size; +#endif + unsigned short block_size; + unsigned short config_size; + unsigned short config_area; + unsigned short config_block_count; + unsigned short flash_config_length; + unsigned short payload_length; + unsigned short partition_table_bytes; + unsigned short read_config_buf_size; + const unsigned char *config_data; + const unsigned char *image; + unsigned char *image_name; + unsigned int image_size; + struct image_metadata img; + struct register_offset off; + struct block_count blkcount; + struct physical_address phyaddr; + struct f34_v5v6_flash_properties flash_properties; + struct synaptics_rmi4_fn_desc2 f34_fd; + struct synaptics_rmi4_fn_desc2 f35_fd; + struct synaptics_rmi4_data *rmi4_data; + struct workqueue_struct *fwu_workqueue; + struct work_struct fwu_work; + struct i2c_client *client; + unsigned char bl_reset_add; +}; + +static struct synaptics_rmi4_fwu_handle *fwu; + +DECLARE_COMPLETION(fwu_remove_complete); + +static void calculate_checksum(unsigned short *data, unsigned long len, + unsigned long *result) +{ + unsigned long temp; + unsigned long sum1 = 0xffff; + unsigned long sum2 = 0xffff; + + *result = 0xffffffff; + + while (len--) { + temp = *data; + sum1 += temp; + sum2 += sum1; + sum1 = (sum1 & 0xffff) + (sum1 >> 16); + sum2 = (sum2 & 0xffff) + (sum2 >> 16); + data++; + } + + *result = sum2 << 16 | sum1; + +} + +static void convert_to_little_endian(unsigned char *dest, unsigned long src) +{ + dest[0] = (unsigned char)(src & 0xff); + dest[1] = (unsigned char)((src >> 8) & 0xff); + dest[2] = (unsigned char)((src >> 16) & 0xff); + dest[3] = (unsigned char)((src >> 24) & 0xff); + +} + +static unsigned int le_to_uint(const unsigned char *ptr) +{ + return (unsigned int)ptr[0] + + (unsigned int)ptr[1] * 0x100 + + (unsigned int)ptr[2] * 0x10000 + + (unsigned int)ptr[3] * 0x1000000; +} + +#ifdef F51_DISCRETE_FORCE +static int fwu_f51_force_data_init(void) +{ + int retval; + unsigned char query_count; + unsigned char packet_info; + unsigned char offset[2]; + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; + + retval = synaptics_rmi4_reg_read(fwu->client, + rmi4_data->f51_query_base_addr + 7, + offset, + sizeof(offset)); + if (retval < 0) { + TPD_ERR("%s: Failed to read force data offset\n", + __func__); + return retval; + } + + fwu->cal_data_off = offset[0] | offset[1] << 8; + + retval = synaptics_rmi4_reg_read(fwu->client, + rmi4_data->f51_query_base_addr, + &query_count, + sizeof(query_count)); + if (retval < 0) { + TPD_ERR("%s: Failed to read number of F51 query registers\n", + __func__); + return retval; + } + + if (query_count >= 10) { + retval = synaptics_rmi4_reg_read(fwu->client, + rmi4_data->f51_query_base_addr + 9, + &packet_info, + sizeof(packet_info)); + if (retval < 0) { + TPD_ERR("%s: Failed to read F51 packet register info\n", + __func__); + return retval; + } + + if (packet_info & MASK_1BIT) { + fwu->cal_packet_data_size = packet_info >> 1; + fwu->cal_packet_data_size *= 2; + } else { + fwu->cal_packet_data_size = 0; + } + } else { + fwu->cal_packet_data_size = 0; + } + + fwu->cal_data_size = CAL_DATA_SIZE + fwu->cal_packet_data_size; + if (fwu->cal_data_size > fwu->cal_data_buf_size) { + kfree(fwu->cal_data); + fwu->cal_data_buf_size = fwu->cal_data_size; + fwu->cal_data = kmalloc(fwu->cal_data_buf_size, GFP_KERNEL); + if (!fwu->cal_data) { + TPD_ERR("%s: Failed to alloc mem for fwu->cal_data\n", + __func__); + fwu->cal_data_buf_size = 0; + return -ENOMEM; + } + } + + return 0; +} +#endif + +static int fwu_allocate_read_config_buf(unsigned int count) +{ + + if (count > fwu->read_config_buf_size) { + kfree(fwu->read_config_buf); + fwu->read_config_buf = kzalloc(count, GFP_KERNEL); + if (!fwu->read_config_buf) { + TPD_ERR("%s:Failed to alloc mem read_config_buf\n", + __func__); + fwu->read_config_buf_size = 0; + return -ENOMEM; + } + fwu->read_config_buf_size = count; + } + + return 0; +} + +static void fwu_compare_partition_tables(void) +{ + fwu->incompatible_partition_tables = false; + + if (fwu->phyaddr.bl_image != fwu->img.phyaddr.bl_image) + fwu->incompatible_partition_tables = true; + else if (fwu->phyaddr.lockdown != fwu->img.phyaddr.lockdown) + fwu->incompatible_partition_tables = true; + else if (fwu->phyaddr.bl_config != fwu->img.phyaddr.bl_config) + fwu->incompatible_partition_tables = true; + else if (fwu->phyaddr.utility_param != fwu->img.phyaddr.utility_param) + fwu->incompatible_partition_tables = true; + + if (fwu->bl_version == BL_V7) { + if (fwu->phyaddr.fl_config != fwu->img.phyaddr.fl_config) + fwu->incompatible_partition_tables = true; + } + + fwu->new_partition_table = false; + + if (fwu->phyaddr.ui_firmware != fwu->img.phyaddr.ui_firmware) + fwu->new_partition_table = true; + else if (fwu->phyaddr.ui_config != fwu->img.phyaddr.ui_config) + fwu->new_partition_table = true; + + if (fwu->flash_properties.has_disp_config) { + if (fwu->phyaddr.dp_config != fwu->img.phyaddr.dp_config) + fwu->new_partition_table = true; + } + + if (fwu->has_guest_code) { + if (fwu->phyaddr.guest_code != fwu->img.phyaddr.guest_code) + fwu->new_partition_table = true; + } + +} + +static void fwu_parse_partition_table(const unsigned char *partition_table, + struct block_count *blkcount, struct physical_address *phyaddr) +{ + unsigned char ii; + unsigned char index; + unsigned char offset; + unsigned short partition_length; + unsigned short physical_address; + struct partition_table *ptable; + + for (ii = 0; ii < fwu->partitions; ii++) { + index = ii * 8 + 2; + ptable = (struct partition_table *)&partition_table[index]; + partition_length = ptable->partition_length_15_8 << 8 | + ptable->partition_length_7_0; + physical_address = ptable->start_physical_address_15_8 << 8 | + ptable->start_physical_address_7_0; + TPD_DEBUG("%s: Partition entry %d:\n", + __func__, ii); + for (offset = 0; offset < 8; offset++) { + TPD_DEBUG("%s: 0x%02x\n", + __func__, + partition_table[index + offset]); + } + switch (ptable->partition_id) { + case CORE_CODE_PARTITION: + blkcount->ui_firmware = partition_length; + phyaddr->ui_firmware = physical_address; + TPD_DEBUG("%s: Core code block count: %d\n", + __func__, blkcount->ui_firmware); + blkcount->total_count += partition_length; + break; + case CORE_CONFIG_PARTITION: + blkcount->ui_config = partition_length; + phyaddr->ui_config = physical_address; + TPD_DEBUG("%s: Core config block count: %d\n", + __func__, blkcount->ui_config); + blkcount->total_count += partition_length; + break; + case BOOTLOADER_PARTITION: + blkcount->bl_image = partition_length; + phyaddr->bl_image = physical_address; + TPD_DEBUG("%s: Bootloader block count: %d\n", + __func__, blkcount->bl_image); + blkcount->total_count += partition_length; + break; + case UTILITY_PARAMETER_PARTITION: + blkcount->utility_param = partition_length; + phyaddr->utility_param = physical_address; + TPD_DEBUG("%s: Utility parameter block count: %d\n", + __func__, blkcount->utility_param); + blkcount->total_count += partition_length; + break; + case DISPLAY_CONFIG_PARTITION: + blkcount->dp_config = partition_length; + phyaddr->dp_config = physical_address; + TPD_DEBUG("%s: Display config block count: %d\n", + __func__, blkcount->dp_config); + blkcount->total_count += partition_length; + break; + case FLASH_CONFIG_PARTITION: + blkcount->fl_config = partition_length; + phyaddr->fl_config = physical_address; + TPD_DEBUG("%s: Flash config block count: %d\n", + __func__, blkcount->fl_config); + blkcount->total_count += partition_length; + break; + case GUEST_CODE_PARTITION: + blkcount->guest_code = partition_length; + phyaddr->guest_code = physical_address; + TPD_DEBUG("%s: Guest code block count: %d\n", + __func__, blkcount->guest_code); + blkcount->total_count += partition_length; + break; + case GUEST_SERIALIZATION_PARTITION: + blkcount->pm_config = partition_length; + phyaddr->pm_config = physical_address; + TPD_DEBUG("%s: Guest serialization block count: %d\n", + __func__, blkcount->pm_config); + blkcount->total_count += partition_length; + break; + case GLOBAL_PARAMETERS_PARTITION: + blkcount->bl_config = partition_length; + phyaddr->bl_config = physical_address; + TPD_DEBUG("%s: Global parameters block count: %d\n", + __func__, blkcount->bl_config); + blkcount->total_count += partition_length; + break; + case DEVICE_CONFIG_PARTITION: + blkcount->lockdown = partition_length; + phyaddr->lockdown = physical_address; + TPD_DEBUG("%s: Device config block count: %d\n", + __func__, blkcount->lockdown); + blkcount->total_count += partition_length; + break; + }; + } + +} + +static void fwu_parse_image_header_10_utility(const unsigned char *image) +{ + unsigned char ii; + unsigned char num_of_containers; + unsigned int addr; + unsigned int container_id; + unsigned int length; + const unsigned char *content; + struct container_descriptor *descriptor; + + num_of_containers = fwu->img.utility.size / 4; + + for (ii = 0; ii < num_of_containers; ii++) { + if (ii >= MAX_UTILITY_PARAMS) + continue; + addr = le_to_uint(fwu->img.utility.data + (ii * 4)); + descriptor = (struct container_descriptor *)(image + addr); + container_id = descriptor->container_id[0] | + descriptor->container_id[1] << 8; + content = image + le_to_uint(descriptor->content_address); + length = le_to_uint(descriptor->content_length); + switch (container_id) { + case UTILITY_PARAMETER_CONTAINER: + fwu->img.utility_param[ii].data = content; + fwu->img.utility_param[ii].size = length; + fwu->img.utility_param_id[ii] = content[0]; + break; + default: + break; + }; + } + +} + +static void fwu_parse_image_header_10_bootloader(const unsigned char *image) +{ + unsigned char ii; + unsigned char num_of_containers; + unsigned int addr; + unsigned int container_id; + unsigned int length; + const unsigned char *content; + struct container_descriptor *descriptor; + + num_of_containers = (fwu->img.bootloader.size - 4) / 4; + + for (ii = 1; ii <= num_of_containers; ii++) { + addr = le_to_uint(fwu->img.bootloader.data + (ii * 4)); + descriptor = (struct container_descriptor *)(image + addr); + container_id = descriptor->container_id[0] | + descriptor->container_id[1] << 8; + content = image + le_to_uint(descriptor->content_address); + length = le_to_uint(descriptor->content_length); + switch (container_id) { + case BL_IMAGE_CONTAINER: + fwu->img.bl_image.data = content; + fwu->img.bl_image.size = length; + break; + case BL_CONFIG_CONTAINER: + case GLOBAL_PARAMETERS_CONTAINER: + fwu->img.bl_config.data = content; + fwu->img.bl_config.size = length; + break; + case BL_LOCKDOWN_INFO_CONTAINER: + case DEVICE_CONFIG_CONTAINER: + fwu->img.lockdown.data = content; + fwu->img.lockdown.size = length; + break; + default: + break; + }; + } + +} + +static void fwu_parse_image_header_10(void) +{ + unsigned char ii; + unsigned char num_of_containers; + unsigned int addr; + unsigned int offset; + unsigned int container_id; + unsigned int length; + const unsigned char *image; + const unsigned char *content; + struct container_descriptor *descriptor; + struct image_header_10 *header; + + TPD_DEBUG("%s: enter\n", __func__); + image = fwu->image; + header = (struct image_header_10 *)image; + + fwu->img.checksum = le_to_uint(header->checksum); + + /* address of top level container */ + offset = le_to_uint(header->top_level_container_start_addr); + descriptor = (struct container_descriptor *)(image + offset); + + /* address of top level container content */ + offset = le_to_uint(descriptor->content_address); + num_of_containers = le_to_uint(descriptor->content_length) / 4; + + for (ii = 0; ii < num_of_containers; ii++) { + addr = le_to_uint(image + offset); + offset += 4; + descriptor = (struct container_descriptor *)(image + addr); + container_id = descriptor->container_id[0] | + descriptor->container_id[1] << 8; + content = image + le_to_uint(descriptor->content_address); + length = le_to_uint(descriptor->content_length); + switch (container_id) { + case UI_CONTAINER: + case CORE_CODE_CONTAINER: + fwu->img.ui_firmware.data = content; + fwu->img.ui_firmware.size = length; + break; + case UI_CONFIG_CONTAINER: + case CORE_CONFIG_CONTAINER: + fwu->img.ui_config.data = content; + fwu->img.ui_config.size = length; + break; + case BL_CONTAINER: + fwu->img.bl_version = *content; + fwu->img.bootloader.data = content; + fwu->img.bootloader.size = length; + fwu_parse_image_header_10_bootloader(image); + break; + case UTILITY_CONTAINER: + fwu->img.utility.data = content; + fwu->img.utility.size = length; + fwu_parse_image_header_10_utility(image); + break; + case GUEST_CODE_CONTAINER: + fwu->img.contains_guest_code = true; + fwu->img.guest_code.data = content; + fwu->img.guest_code.size = length; + break; + case DISPLAY_CONFIG_CONTAINER: + fwu->img.contains_disp_config = true; + fwu->img.dp_config.data = content; + fwu->img.dp_config.size = length; + break; + case PERMANENT_CONFIG_CONTAINER: + case GUEST_SERIALIZATION_CONTAINER: + fwu->img.contains_perm_config = true; + fwu->img.pm_config.data = content; + fwu->img.pm_config.size = length; + break; + case FLASH_CONFIG_CONTAINER: + fwu->img.contains_flash_config = true; + fwu->img.fl_config.data = content; + fwu->img.fl_config.size = length; + break; + case GENERAL_INFORMATION_CONTAINER: + fwu->img.contains_firmware_id = true; + fwu->img.firmware_id = le_to_uint(content + 4); + break; + default: + break; + } + } + +} + +static void fwu_parse_image_header_05_06(void) +{ + int retval; + const unsigned char *image; + struct image_header_05_06 *header; + + TPD_ERR("%s: enter\n", __func__); + + image = fwu->image; + header = (struct image_header_05_06 *)image; + + fwu->img.checksum = le_to_uint(header->checksum); + + fwu->img.bl_version = header->header_version; + + fwu->img.contains_bootloader = header->options_bootloader; + if (fwu->img.contains_bootloader) + fwu->img.bootloader_size = le_to_uint(header->bootloader_size); + + fwu->img.ui_firmware.size = le_to_uint(header->firmware_size); + if (fwu->img.ui_firmware.size) { + fwu->img.ui_firmware.data = image + IMAGE_AREA_OFFSET; + if (fwu->img.contains_bootloader) + fwu->img.ui_firmware.data += fwu->img.bootloader_size; + } + + if ((fwu->img.bl_version == BL_V6) && header->options_tddi) + fwu->img.ui_firmware.data = image + IMAGE_AREA_OFFSET; + + fwu->img.ui_config.size = le_to_uint(header->config_size); + if (fwu->img.ui_config.size) { + fwu->img.ui_config.data = fwu->img.ui_firmware.data + + fwu->img.ui_firmware.size; + } + + if (fwu->img.contains_bootloader || header->options_tddi) + fwu->img.contains_disp_config = true; + else + fwu->img.contains_disp_config = false; + + if (fwu->img.contains_disp_config) { + fwu->img.disp_config_offset = le_to_uint(header->dsp_cfg_addr); + fwu->img.dp_config.size = le_to_uint(header->dsp_cfg_size); + fwu->img.dp_config.data = image + fwu->img.disp_config_offset; + } else { + retval = secure_memcpy(fwu->img.cstmr_product_id, + sizeof(fwu->img.cstmr_product_id), + header->cstmr_product_id, + sizeof(header->cstmr_product_id), + PRODUCT_ID_SIZE); + if (retval < 0) { + TPD_ERR("%s: Failed to copy custom product ID string\n", + __func__); + } + fwu->img.cstmr_product_id[PRODUCT_ID_SIZE] = 0; + } + + fwu->img.contains_firmware_id = header->options_firmware_id; + if (fwu->img.contains_firmware_id) + fwu->img.firmware_id = le_to_uint(header->firmware_id); + + retval = secure_memcpy(fwu->img.product_id, + sizeof(fwu->img.product_id), + header->product_id, + sizeof(header->product_id), + PRODUCT_ID_SIZE); + if (retval < 0) { + TPD_ERR("%s: Failed to copy product ID string\n", + __func__); + } + fwu->img.product_id[PRODUCT_ID_SIZE] = 0; + + fwu->img.lockdown.size = LOCKDOWN_SIZE; + fwu->img.lockdown.data = image + IMAGE_AREA_OFFSET - LOCKDOWN_SIZE; + +} + +static int fwu_parse_image_info(void) +{ + struct image_header_10 *header; + + TPD_DEBUG("%s: enter\n", __func__); + header = (struct image_header_10 *)fwu->image; + + memset(&fwu->img, 0x00, sizeof(fwu->img)); + switch (header->major_header_version) { + case IMAGE_HEADER_VERSION_10: + fwu_parse_image_header_10(); + break; + case IMAGE_HEADER_VERSION_05: + case IMAGE_HEADER_VERSION_06: + fwu_parse_image_header_05_06(); + break; + default: + TPD_ERR("%s: Unsupported image file format (0x%02x)\n", + __func__, header->major_header_version); + return -EINVAL; + } + + if (fwu->bl_version == BL_V7 || fwu->bl_version == BL_V8) { + if (!fwu->img.contains_flash_config) { + TPD_ERR("%s: No flash config found in firmware image\n", + __func__); + return -EINVAL; + } + + fwu_parse_partition_table(fwu->img.fl_config.data, + &fwu->img.blkcount, &fwu->img.phyaddr); + + if (fwu->img.blkcount.utility_param) + fwu->img.contains_utility_param = true; + + fwu_compare_partition_tables(); + } else { + fwu->new_partition_table = false; + fwu->incompatible_partition_tables = false; + } + + return 0; +} + +static int fwu_read_flash_status(void) +{ + int retval; + unsigned char status; + unsigned char command; + + TPD_DEBUG("%s: enter\n", __func__); + retval = synaptics_rmi4_reg_read(fwu->client, + fwu->f34_fd.data_base_addr + fwu->off.flash_status, + &status, + sizeof(status)); + if (retval < 0) { + TPD_ERR("%s: Failed to read flash status\n", + __func__); + return retval; + } + + fwu->in_bl_mode = status >> 7; + + if (fwu->bl_version == BL_V5) + fwu->flash_status = (status >> 4) & MASK_3BIT; + else if (fwu->bl_version == BL_V6) + fwu->flash_status = status & MASK_3BIT; + else if (fwu->bl_version == BL_V7 || fwu->bl_version == BL_V8) + fwu->flash_status = status & MASK_5BIT; + + if (fwu->write_bootloader) + fwu->flash_status = 0x00; + + if (fwu->flash_status != 0x00) { + TPD_ERR("%s: Flash status = %d, command = 0x%02x\n", + __func__, fwu->flash_status, fwu->command); + } + + if (fwu->bl_version == BL_V7 || fwu->bl_version == BL_V8) { + if (fwu->flash_status == 0x08) + fwu->flash_status = 0x00; + } + + retval = synaptics_rmi4_reg_read(fwu->client, + fwu->f34_fd.data_base_addr + fwu->off.flash_cmd, + &command, + sizeof(command)); + if (retval < 0) { + TPD_ERR("%s: Failed to read flash command\n", + __func__); + return retval; + } + + if (fwu->bl_version == BL_V5) + fwu->command = command & MASK_4BIT; + else if (fwu->bl_version == BL_V6) + fwu->command = command & MASK_6BIT; + else if (fwu->bl_version == BL_V7 || fwu->bl_version == BL_V8) + fwu->command = command; + + if (fwu->write_bootloader) + fwu->command = 0x00; + + return 0; +} + +static int fwu_wait_for_idle(int timeout_ms, bool poll) +{ + int count = 0; + int timeout_count = ((timeout_ms * 1000) / MAX_SLEEP_TIME_US) + 1; + + TPD_DEBUG("%s: enter\n", __func__); + do { + usleep_range(MIN_SLEEP_TIME_US, MAX_SLEEP_TIME_US); + + count++; + if (poll || (count == timeout_count)) + fwu_read_flash_status(); + + if ((fwu->command == CMD_IDLE) && (fwu->flash_status == 0x00)) + return 0; + } while (count < timeout_count); + + TPD_ERR("%s: Timed out waiting for idle status\n", + __func__); + + return -ETIMEDOUT; +} + +static int fwu_write_f34_v7_command_single_transaction(unsigned char cmd) +{ + int retval; + unsigned char data_base; + struct f34_v7_data_1_5 data_1_5; + + + data_base = fwu->f34_fd.data_base_addr; + + memset(data_1_5.data, 0x00, sizeof(data_1_5.data)); + + switch (cmd) { + case CMD_ERASE_ALL: + data_1_5.partition_id = CORE_CODE_PARTITION; + data_1_5.command = CMD_V7_ERASE_AP; + break; + case CMD_ERASE_UI_FIRMWARE: + data_1_5.partition_id = CORE_CODE_PARTITION; + data_1_5.command = CMD_V7_ERASE; + break; + case CMD_ERASE_BL_CONFIG: + data_1_5.partition_id = GLOBAL_PARAMETERS_PARTITION; + data_1_5.command = CMD_V7_ERASE; + break; + case CMD_ERASE_UI_CONFIG: + data_1_5.partition_id = CORE_CONFIG_PARTITION; + data_1_5.command = CMD_V7_ERASE; + break; + case CMD_ERASE_DISP_CONFIG: + data_1_5.partition_id = DISPLAY_CONFIG_PARTITION; + data_1_5.command = CMD_V7_ERASE; + break; + case CMD_ERASE_FLASH_CONFIG: + data_1_5.partition_id = FLASH_CONFIG_PARTITION; + data_1_5.command = CMD_V7_ERASE; + break; + case CMD_ERASE_GUEST_CODE: + data_1_5.partition_id = GUEST_CODE_PARTITION; + data_1_5.command = CMD_V7_ERASE; + break; + case CMD_ERASE_BOOTLOADER: + data_1_5.partition_id = BOOTLOADER_PARTITION; + data_1_5.command = CMD_V7_ERASE; + break; + case CMD_ERASE_UTILITY_PARAMETER: + data_1_5.partition_id = UTILITY_PARAMETER_PARTITION; + data_1_5.command = CMD_V7_ERASE; + break; + case CMD_ENABLE_FLASH_PROG: + data_1_5.partition_id = BOOTLOADER_PARTITION; + data_1_5.command = CMD_V7_ENTER_BL; + break; + }; + + data_1_5.payload_0 = fwu->bootloader_id[0]; + data_1_5.payload_1 = fwu->bootloader_id[1]; + + retval = synaptics_rmi4_reg_write(fwu->client, + data_base + fwu->off.partition_id, + data_1_5.data, + sizeof(data_1_5.data)); + if (retval < 0) { + TPD_ERR("%s: Failed to write single transaction command\n", + __func__); + return retval; + } + + return 0; +} + +static int fwu_write_f34_v7_command(unsigned char cmd) +{ + int retval; + unsigned char data_base; + unsigned char command; + + + data_base = fwu->f34_fd.data_base_addr; + + switch (cmd) { + case CMD_WRITE_FW: + case CMD_WRITE_CONFIG: + case CMD_WRITE_LOCKDOWN: + case CMD_WRITE_GUEST_CODE: + case CMD_WRITE_BOOTLOADER: + case CMD_WRITE_UTILITY_PARAM: + command = CMD_V7_WRITE; + break; + case CMD_READ_CONFIG: + command = CMD_V7_READ; + break; + case CMD_ERASE_ALL: + command = CMD_V7_ERASE_AP; + break; + case CMD_ERASE_UI_FIRMWARE: + case CMD_ERASE_BL_CONFIG: + case CMD_ERASE_UI_CONFIG: + case CMD_ERASE_DISP_CONFIG: + case CMD_ERASE_FLASH_CONFIG: + case CMD_ERASE_GUEST_CODE: + case CMD_ERASE_BOOTLOADER: + case CMD_ERASE_UTILITY_PARAMETER: + command = CMD_V7_ERASE; + break; + case CMD_ENABLE_FLASH_PROG: + command = CMD_V7_ENTER_BL; + break; + default: + TPD_ERR("%s: Invalid command 0x%02x\n", + __func__, cmd); + return -EINVAL; + }; + + fwu->command = command; + + switch (cmd) { + case CMD_ERASE_ALL: + case CMD_ERASE_UI_FIRMWARE: + case CMD_ERASE_BL_CONFIG: + case CMD_ERASE_UI_CONFIG: + case CMD_ERASE_DISP_CONFIG: + case CMD_ERASE_FLASH_CONFIG: + case CMD_ERASE_GUEST_CODE: + case CMD_ERASE_BOOTLOADER: + case CMD_ERASE_UTILITY_PARAMETER: + case CMD_ENABLE_FLASH_PROG: + retval = fwu_write_f34_v7_command_single_transaction(cmd); + if (retval < 0) + return retval; + else + return 0; + default: + break; + }; + + retval = synaptics_rmi4_reg_write(fwu->client, + data_base + fwu->off.flash_cmd, + &command, + sizeof(command)); + if (retval < 0) { + TPD_ERR("%s: Failed to write flash command\n", + __func__); + return retval; + } + + return 0; +} + +static int fwu_write_f34_v5v6_command(unsigned char cmd) +{ + int retval; + unsigned char data_base; + unsigned char command; + + + data_base = fwu->f34_fd.data_base_addr; + + switch (cmd) { + case CMD_IDLE: + command = CMD_V5V6_IDLE; + break; + case CMD_WRITE_FW: + command = CMD_V5V6_WRITE_FW; + break; + case CMD_WRITE_CONFIG: + command = CMD_V5V6_WRITE_CONFIG; + break; + case CMD_WRITE_LOCKDOWN: + command = CMD_V5V6_WRITE_LOCKDOWN; + break; + case CMD_WRITE_GUEST_CODE: + command = CMD_V5V6_WRITE_GUEST_CODE; + break; + case CMD_READ_CONFIG: + command = CMD_V5V6_READ_CONFIG; + break; + case CMD_ERASE_ALL: + command = CMD_V5V6_ERASE_ALL; + break; + case CMD_ERASE_UI_CONFIG: + command = CMD_V5V6_ERASE_UI_CONFIG; + break; + case CMD_ERASE_DISP_CONFIG: + command = CMD_V5V6_ERASE_DISP_CONFIG; + break; + case CMD_ERASE_GUEST_CODE: + command = CMD_V5V6_ERASE_GUEST_CODE; + break; + case CMD_ENABLE_FLASH_PROG: + command = CMD_V5V6_ENABLE_FLASH_PROG; + break; + default: + TPD_ERR("%s: Invalid command 0x%02x\n", + __func__, cmd); + return -EINVAL; + } + + switch (cmd) { + case CMD_ERASE_ALL: + case CMD_ERASE_UI_CONFIG: + case CMD_ERASE_DISP_CONFIG: + case CMD_ERASE_GUEST_CODE: + case CMD_ENABLE_FLASH_PROG: + retval = synaptics_rmi4_reg_write(fwu->client, + data_base + fwu->off.payload, + fwu->bootloader_id, + sizeof(fwu->bootloader_id)); + if (retval < 0) { + TPD_ERR("%s: Failed to write bootloader ID\n", + __func__); + return retval; + } + break; + default: + break; + }; + + fwu->command = command; + + retval = synaptics_rmi4_reg_write(fwu->client, + data_base + fwu->off.flash_cmd, + &command, + sizeof(command)); + if (retval < 0) { + TPD_ERR("%s: Failed to write command 0x%02x\n", + __func__, command); + return retval; + } + + return 0; +} + +static int fwu_write_f34_command(unsigned char cmd) +{ + int retval; + + if (fwu->bl_version == BL_V7 || fwu->bl_version == BL_V8) + retval = fwu_write_f34_v7_command(cmd); + else + retval = fwu_write_f34_v5v6_command(cmd); + + return retval; +} + +static int fwu_write_f34_v7_partition_id(unsigned char cmd) +{ + int retval; + unsigned char data_base; + unsigned char partition = 0; + + data_base = fwu->f34_fd.data_base_addr; + + switch (cmd) { + case CMD_WRITE_FW: + partition = CORE_CODE_PARTITION; + break; + case CMD_WRITE_CONFIG: + case CMD_READ_CONFIG: + if (fwu->config_area == UI_CONFIG_AREA) + partition = CORE_CONFIG_PARTITION; + else if (fwu->config_area == DP_CONFIG_AREA) + partition = DISPLAY_CONFIG_PARTITION; + else if (fwu->config_area == PM_CONFIG_AREA) + partition = GUEST_SERIALIZATION_PARTITION; + else if (fwu->config_area == BL_CONFIG_AREA) + partition = GLOBAL_PARAMETERS_PARTITION; + else if (fwu->config_area == FLASH_CONFIG_AREA) + partition = FLASH_CONFIG_PARTITION; + else if (fwu->config_area == UPP_AREA) + partition = UTILITY_PARAMETER_PARTITION; + break; + case CMD_WRITE_LOCKDOWN: + partition = DEVICE_CONFIG_PARTITION; + break; + case CMD_WRITE_GUEST_CODE: + partition = GUEST_CODE_PARTITION; + break; + case CMD_WRITE_BOOTLOADER: + partition = BOOTLOADER_PARTITION; + break; + case CMD_WRITE_UTILITY_PARAM: + partition = UTILITY_PARAMETER_PARTITION; + break; + case CMD_ERASE_ALL: + partition = CORE_CODE_PARTITION; + break; + case CMD_ERASE_BL_CONFIG: + partition = GLOBAL_PARAMETERS_PARTITION; + break; + case CMD_ERASE_UI_CONFIG: + partition = CORE_CONFIG_PARTITION; + break; + case CMD_ERASE_DISP_CONFIG: + partition = DISPLAY_CONFIG_PARTITION; + break; + case CMD_ERASE_FLASH_CONFIG: + partition = FLASH_CONFIG_PARTITION; + break; + case CMD_ERASE_GUEST_CODE: + partition = GUEST_CODE_PARTITION; + break; + case CMD_ERASE_BOOTLOADER: + partition = BOOTLOADER_PARTITION; + break; + case CMD_ENABLE_FLASH_PROG: + partition = BOOTLOADER_PARTITION; + break; + default: + TPD_ERR("%s: Invalid command 0x%02x\n", + __func__, cmd); + return -EINVAL; + }; + + retval = synaptics_rmi4_reg_write(fwu->client, + data_base + fwu->off.partition_id, + &partition, + sizeof(partition)); + if (retval < 0) { + TPD_ERR("%s: Failed to write partition ID\n", + __func__); + return retval; + } + + return 0; +} + +static int fwu_write_f34_partition_id(unsigned char cmd) +{ + int retval; + + if (fwu->bl_version == BL_V7 || fwu->bl_version == BL_V8) + retval = fwu_write_f34_v7_partition_id(cmd); + else + retval = 0; + + return retval; +} + +static int fwu_read_f34_v7_partition_table(unsigned char *partition_table) +{ + int retval; + unsigned char data_base; + unsigned char length[2]; + unsigned short block_number = 0; + + data_base = fwu->f34_fd.data_base_addr; + + fwu->config_area = FLASH_CONFIG_AREA; + + retval = fwu_write_f34_partition_id(CMD_READ_CONFIG); + if (retval < 0) + return retval; + + retval = synaptics_rmi4_reg_write(fwu->client, + data_base + fwu->off.block_number, + (unsigned char *)&block_number, + sizeof(block_number)); + if (retval < 0) { + TPD_ERR("%s: Failed to write block number\n", + __func__); + return retval; + } + + length[0] = (unsigned char)(fwu->flash_config_length & MASK_8BIT); + length[1] = (unsigned char)(fwu->flash_config_length >> 8); + + retval = synaptics_rmi4_reg_write(fwu->client, + data_base + fwu->off.transfer_length, + length, + sizeof(length)); + if (retval < 0) { + TPD_ERR("%s: Failed to write transfer length\n", + __func__); + return retval; + } + + retval = fwu_write_f34_command(CMD_READ_CONFIG); + if (retval < 0) { + TPD_ERR("%s: Failed to write command\n", + __func__); + return retval; + } + + retval = fwu_wait_for_idle(WRITE_WAIT_MS, true); + if (retval < 0) { + TPD_ERR("%s: Failed to wait for idle status\n", + __func__); + return retval; + } + + retval = synaptics_rmi4_reg_read(fwu->client, + data_base + fwu->off.payload, + partition_table, + fwu->partition_table_bytes); + if (retval < 0) { + TPD_ERR("%s: Failed to read block data\n", + __func__); + return retval; + } + + return 0; +} + +static int fwu_read_f34_v7_queries(void) +{ + int retval; + unsigned char ii; + unsigned char query_base; + unsigned char index; + unsigned char offset; + unsigned char *ptable; + struct f34_v7_query_0 query_0; + struct f34_v7_query_1_7 query_1_7; + + query_base = fwu->f34_fd.query_base_addr; + + retval = synaptics_rmi4_reg_read(fwu->client, + query_base, + query_0.data, + sizeof(query_0.data)); + if (retval < 0) { + TPD_ERR("%s: Failed to read query 0\n", + __func__); + return retval; + } + + offset = query_0.subpacket_1_size + 1; + + retval = synaptics_rmi4_reg_read(fwu->client, + query_base + offset, + query_1_7.data, + sizeof(query_1_7.data)); + if (retval < 0) { + TPD_ERR("%s: Failed to read queries 1 to 7\n", + __func__); + return retval; + } + + fwu->bootloader_id[0] = query_1_7.bl_minor_revision; + fwu->bootloader_id[1] = query_1_7.bl_major_revision; + + if (fwu->bootloader_id[1] == BL_V8) + fwu->bl_version = BL_V8; + + fwu->block_size = query_1_7.block_size_15_8 << 8 | + query_1_7.block_size_7_0; + + fwu->flash_config_length = query_1_7.flash_config_length_15_8 << 8 | + query_1_7.flash_config_length_7_0; + + fwu->payload_length = query_1_7.payload_length_15_8 << 8 | + query_1_7.payload_length_7_0; + + fwu->off.flash_status = V7_FLASH_STATUS_OFFSET; + fwu->off.partition_id = V7_PARTITION_ID_OFFSET; + fwu->off.block_number = V7_BLOCK_NUMBER_OFFSET; + fwu->off.transfer_length = V7_TRANSFER_LENGTH_OFFSET; + fwu->off.flash_cmd = V7_COMMAND_OFFSET; + fwu->off.payload = V7_PAYLOAD_OFFSET; + + index = sizeof(query_1_7.data) - V7_PARTITION_SUPPORT_BYTES; + + fwu->partitions = 0; + for (offset = 0; offset < V7_PARTITION_SUPPORT_BYTES; offset++) { + for (ii = 0; ii < 8; ii++) { + if (query_1_7.data[index + offset] & (1 << ii)) + fwu->partitions++; + } + + TPD_DEBUG("%s: Supported partitions: 0x%02x\n", + __func__, query_1_7.data[index + offset]); + } + + fwu->partition_table_bytes = fwu->partitions * 8 + 2; + + ptable = kzalloc(fwu->partition_table_bytes, GFP_KERNEL); + if (!ptable) { + TPD_ERR("%s: Failed to alloc mem for partition table\n", + __func__); + return -ENOMEM; + } + + retval = fwu_read_f34_v7_partition_table(ptable); + if (retval < 0) { + TPD_ERR("%s: Failed to read partition table\n", + __func__); + kfree(ptable); + return retval; + } + + fwu_parse_partition_table(ptable, &fwu->blkcount, &fwu->phyaddr); + + if (fwu->blkcount.dp_config) + fwu->flash_properties.has_disp_config = 1; + else + fwu->flash_properties.has_disp_config = 0; + + if (fwu->blkcount.pm_config) + fwu->flash_properties.has_pm_config = 1; + else + fwu->flash_properties.has_pm_config = 0; + + if (fwu->blkcount.bl_config) + fwu->flash_properties.has_bl_config = 1; + else + fwu->flash_properties.has_bl_config = 0; + + if (fwu->blkcount.guest_code) + fwu->has_guest_code = 1; + else + fwu->has_guest_code = 0; + + if (fwu->blkcount.utility_param) + fwu->has_utility_param = 1; + else + fwu->has_utility_param = 0; + + kfree(ptable); + + return 0; +} + +static int fwu_read_f34_v5v6_queries(void) +{ + int retval; + unsigned char count; + unsigned char query_base; + unsigned char buf[10]; + struct f34_v5v6_flash_properties_2 properties_2; + + query_base = fwu->f34_fd.query_base_addr; + + retval = synaptics_rmi4_reg_read(fwu->client, + query_base + V5V6_BOOTLOADER_ID_OFFSET, + fwu->bootloader_id, + sizeof(fwu->bootloader_id)); + if (retval < 0) { + TPD_ERR("%s: Failed to read bootloader ID\n", + __func__); + return retval; + } + + if (fwu->bl_version == BL_V5) { + fwu->off.properties = V5_PROPERTIES_OFFSET; + fwu->off.block_size = V5_BLOCK_SIZE_OFFSET; + fwu->off.block_count = V5_BLOCK_COUNT_OFFSET; + fwu->off.block_number = V5_BLOCK_NUMBER_OFFSET; + fwu->off.payload = V5_BLOCK_DATA_OFFSET; + } else if (fwu->bl_version == BL_V6) { + fwu->off.properties = V6_PROPERTIES_OFFSET; + fwu->off.properties_2 = V6_PROPERTIES_2_OFFSET; + fwu->off.block_size = V6_BLOCK_SIZE_OFFSET; + fwu->off.block_count = V6_BLOCK_COUNT_OFFSET; + fwu->off.gc_block_count = V6_GUEST_CODE_BLOCK_COUNT_OFFSET; + fwu->off.block_number = V6_BLOCK_NUMBER_OFFSET; + fwu->off.payload = V6_BLOCK_DATA_OFFSET; + } + + retval = synaptics_rmi4_reg_read(fwu->client, + query_base + fwu->off.block_size, + buf, + 2); + if (retval < 0) { + TPD_ERR("%s: Failed to read block size info\n", + __func__); + return retval; + } + + batohs(&fwu->block_size, &(buf[0])); + + if (fwu->bl_version == BL_V5) { + fwu->off.flash_cmd = fwu->off.payload + fwu->block_size; + fwu->off.flash_status = fwu->off.flash_cmd; + } else if (fwu->bl_version == BL_V6) { + fwu->off.flash_cmd = V6_FLASH_COMMAND_OFFSET; + fwu->off.flash_status = V6_FLASH_STATUS_OFFSET; + } + + retval = synaptics_rmi4_reg_read(fwu->client, + query_base + fwu->off.properties, + fwu->flash_properties.data, + sizeof(fwu->flash_properties.data)); + if (retval < 0) { + TPD_ERR("%s: Failed to read flash properties\n", + __func__); + return retval; + } + + count = 4; + + if (fwu->flash_properties.has_pm_config) + count += 2; + + if (fwu->flash_properties.has_bl_config) + count += 2; + + if (fwu->flash_properties.has_disp_config) + count += 2; + + retval = synaptics_rmi4_reg_read(fwu->client, + query_base + fwu->off.block_count, + buf, + count); + if (retval < 0) { + TPD_ERR("%s: Failed to read block count info\n", + __func__); + return retval; + } + + batohs(&fwu->blkcount.ui_firmware, &(buf[0])); + batohs(&fwu->blkcount.ui_config, &(buf[2])); + + count = 4; + + if (fwu->flash_properties.has_pm_config) { + batohs(&fwu->blkcount.pm_config, &(buf[count])); + count += 2; + } + + if (fwu->flash_properties.has_bl_config) { + batohs(&fwu->blkcount.bl_config, &(buf[count])); + count += 2; + } + + if (fwu->flash_properties.has_disp_config) + batohs(&fwu->blkcount.dp_config, &(buf[count])); + + fwu->has_guest_code = false; + + if (fwu->flash_properties.has_query4) { + retval = synaptics_rmi4_reg_read(fwu->client, + query_base + fwu->off.properties_2, + properties_2.data, + sizeof(properties_2.data)); + if (retval < 0) { + TPD_ERR("%s: Failed to read flash properties 2\n", + __func__); + return retval; + } + + if (properties_2.has_guest_code) { + retval = synaptics_rmi4_reg_read(fwu->client, + query_base + fwu->off.gc_block_count, + buf, + 2); + if (retval < 0) { + TPD_ERR("%s: Failed to read guest count\n", + __func__); + return retval; + } + + batohs(&fwu->blkcount.guest_code, &(buf[0])); + fwu->has_guest_code = true; + } + } + + fwu->has_utility_param = false; + + return 0; +} + +static int fwu_read_f34_queries(void) +{ + int retval; + + memset(&fwu->blkcount, 0x00, sizeof(fwu->blkcount)); + memset(&fwu->phyaddr, 0x00, sizeof(fwu->phyaddr)); + + if (fwu->bl_version == BL_V7) + retval = fwu_read_f34_v7_queries(); + else + retval = fwu_read_f34_v5v6_queries(); + + return retval; +} + +static int fwu_write_f34_v7_blocks(unsigned char *block_ptr, + unsigned short block_cnt, unsigned char command) +{ + int retval; + unsigned char data_base; + unsigned char length[2]; + unsigned short transfer; + unsigned short remaining = block_cnt; + unsigned short block_number = 0; + unsigned short left_bytes; + unsigned short write_size; + unsigned short max_write_size; + + TPD_DEBUG("%s enter\n", __func__); + data_base = fwu->f34_fd.data_base_addr; + + retval = fwu_write_f34_partition_id(command); + if (retval < 0) + return retval; + + retval = synaptics_rmi4_reg_write(fwu->client, + data_base + fwu->off.block_number, + (unsigned char *)&block_number, + sizeof(block_number)); + if (retval < 0) { + TPD_ERR("%s: Failed to write block number\n", + __func__); + return retval; + } + + do { + if (remaining / fwu->payload_length) + transfer = fwu->payload_length; + else + transfer = remaining; + + length[0] = (unsigned char)(transfer & MASK_8BIT); + length[1] = (unsigned char)(transfer >> 8); + + retval = synaptics_rmi4_reg_write(fwu->client, + data_base + fwu->off.transfer_length, + length, + sizeof(length)); + if (retval < 0) { + TPD_ERR("%s:Failed write transfer length remaining %d)\n", + __func__, remaining); + return retval; + } + + retval = fwu_write_f34_command(command); + if (retval < 0) { + TPD_ERR("%s:Failedwrite command remaining%d)\n", + __func__, remaining); + return retval; + } + +#ifdef MAX_WRITE_SIZE + max_write_size = MAX_WRITE_SIZE; + if (max_write_size >= transfer * fwu->block_size) + max_write_size = transfer * fwu->block_size; + else if (max_write_size > fwu->block_size) + max_write_size -= max_write_size % fwu->block_size; + else + max_write_size = fwu->block_size; +#else + max_write_size = transfer * fwu->block_size; +#endif + left_bytes = transfer * fwu->block_size; + + do { + if (left_bytes / max_write_size) + write_size = max_write_size; + else + write_size = left_bytes; + + retval = synaptics_rmi4_reg_write(fwu->client, + data_base + fwu->off.payload, + block_ptr, + write_size); + if (retval < 0) { + TPD_ERR("%s: Failed to write (remaining = %d)\n", + __func__, remaining); + return retval; + } + + block_ptr += write_size; + left_bytes -= write_size; + } while (left_bytes); + /*moragan the pollingwap to increase firmware time */ + retval = fwu_wait_for_idle(WRITE_WAIT_MS, true); + /*#endif */ + if (retval < 0) { + TPD_ERR("%s: Failed to wait idle (remaining %d)\n", + __func__, remaining); + return retval; + } + + remaining -= transfer; + } while (remaining); + + return 0; +} + +static int fwu_write_f34_v5v6_blocks(unsigned char *block_ptr, + unsigned short block_cnt, unsigned char command) +{ + int retval; + unsigned char data_base; + unsigned char block_number[] = {0, 0}; + unsigned short blk; + + data_base = fwu->f34_fd.data_base_addr; + + block_number[1] |= (fwu->config_area << 5); + + retval = synaptics_rmi4_reg_write(fwu->client, + data_base + fwu->off.block_number, + block_number, + sizeof(block_number)); + if (retval < 0) { + TPD_ERR("%s: Failed to write block number\n", + __func__); + return retval; + } + + for (blk = 0; blk < block_cnt; blk++) { + retval = synaptics_rmi4_reg_write(fwu->client, + data_base + fwu->off.payload, + block_ptr, + fwu->block_size); + if (retval < 0) { + TPD_ERR("%s: Failed to write block data (block %d)\n", + __func__, blk); + return retval; + } + + retval = fwu_write_f34_command(command); + if (retval < 0) { + TPD_ERR("%s: Failed to write command for block %d\n", + __func__, blk); + return retval; + } + + retval = fwu_wait_for_idle(WRITE_WAIT_MS, false); + if (retval < 0) { + TPD_ERR("%s Failed wait idle status (block %d)\n", + __func__, blk); + return retval; + } + + block_ptr += fwu->block_size; + } + + return 0; +} + +static int fwu_write_f34_blocks(unsigned char *block_ptr, + unsigned short block_cnt, unsigned char cmd) +{ + int retval; + + if (fwu->bl_version == BL_V7 || fwu->bl_version == BL_V8) + retval = fwu_write_f34_v7_blocks(block_ptr, block_cnt, cmd); + else + retval = fwu_write_f34_v5v6_blocks(block_ptr, block_cnt, cmd); + + return retval; +} + +static int fwu_read_f34_v7_blocks(unsigned short block_cnt, + unsigned char command) +{ + int retval; + unsigned char data_base; + unsigned char length[2]; + unsigned short transfer; + unsigned short remaining = block_cnt; + unsigned short block_number = 0; + unsigned short index = 0; + + data_base = fwu->f34_fd.data_base_addr; + + retval = fwu_write_f34_partition_id(command); + if (retval < 0) + return retval; + + retval = synaptics_rmi4_reg_write(fwu->client, + data_base + fwu->off.block_number, + (unsigned char *)&block_number, + sizeof(block_number)); + if (retval < 0) { + TPD_ERR("%s: Failed to writeblocknumber\n", + __func__); + return retval; + } + + do { + if (remaining / fwu->payload_length) + transfer = fwu->payload_length; + else + transfer = remaining; + + length[0] = (unsigned char)(transfer & MASK_8BIT); + length[1] = (unsigned char)(transfer >> 8); + + retval = synaptics_rmi4_reg_write(fwu->client, + data_base + fwu->off.transfer_length, + length, + sizeof(length)); + if (retval < 0) { + TPD_ERR("%s Failed write transferlengthremaining%d)\n", + __func__, remaining); + return retval; + } + + retval = fwu_write_f34_command(command); + if (retval < 0) { + TPD_ERR("%s:Failedwrite command remaining %d)\n", + __func__, remaining); + return retval; + } + + retval = fwu_wait_for_idle(WRITE_WAIT_MS, false); + if (retval < 0) { + TPD_ERR("%s:Failed to wait dle remaining %d)\n", + __func__, remaining); + return retval; + } + + retval = synaptics_rmi4_reg_read(fwu->client, + data_base + fwu->off.payload, + &fwu->read_config_buf[index], + transfer * fwu->block_size); + if (retval < 0) { + TPD_ERR("%s:Failed read dataremaining%d)\n", + __func__, remaining); + return retval; + } + + index += (transfer * fwu->block_size); + remaining -= transfer; + } while (remaining); + + return 0; +} + +static int fwu_read_f34_v5v6_blocks(unsigned short block_cnt, + unsigned char command) +{ + int retval; + unsigned char data_base; + unsigned char block_number[] = {0, 0}; + unsigned short blk; + unsigned short index = 0; + + data_base = fwu->f34_fd.data_base_addr; + + block_number[1] |= (fwu->config_area << 5); + + retval = synaptics_rmi4_reg_write(fwu->client, + data_base + fwu->off.block_number, + block_number, + sizeof(block_number)); + if (retval < 0) { + TPD_ERR("%s: Failed to write block number\n", + __func__); + return retval; + } + + for (blk = 0; blk < block_cnt; blk++) { + retval = fwu_write_f34_command(command); + if (retval < 0) { + TPD_ERR("%s: Failed to write read config command\n", + __func__); + return retval; + } + + retval = fwu_wait_for_idle(WRITE_WAIT_MS, false); + if (retval < 0) { + TPD_ERR("%s: Failed to wait for idle status\n", + __func__); + return retval; + } + + retval = synaptics_rmi4_reg_read(fwu->client, + data_base + fwu->off.payload, + &fwu->read_config_buf[index], + fwu->block_size); + if (retval < 0) { + TPD_ERR("%s: Failed to read block data (block %d)\n", + __func__, blk); + return retval; + } + + index += fwu->block_size; + } + + return 0; +} + +static int fwu_read_f34_blocks(unsigned short block_cnt, unsigned char cmd) +{ + int retval; + + if (fwu->bl_version == BL_V7 || fwu->bl_version == BL_V8) + retval = fwu_read_f34_v7_blocks(block_cnt, cmd); + else + retval = fwu_read_f34_v5v6_blocks(block_cnt, cmd); + + return retval; +} + +static int fwu_get_image_firmware_id(unsigned int *fw_id) +{ + int retval; + unsigned char index = 0; + char *strptr; + char *firmware_id; + + TPD_DEBUG("%s enter\n", __func__); + if (fwu->img.contains_firmware_id) { + *fw_id = fwu->img.firmware_id; + } else { + strptr = strnstr(fwu->image_name, "PR", MAX_IMAGE_NAME_LEN); + if (!strptr) { + TPD_ERR("%s: No valid PR number found in image name(%s)\n", + __func__, fwu->image_name); + return -EINVAL; + } + TPD_DEBUG("%s enter 2 strptr %s\n", __func__, strptr); + strptr += 2; + firmware_id = kzalloc(MAX_FIRMWARE_ID_LEN, GFP_KERNEL); + if (!firmware_id) { + TPD_ERR("%s: Failed to alloc mem for firmware_id\n", + __func__); + return -ENOMEM; + } + while (strptr[index] >= '0' && strptr[index] <= '9') { + firmware_id[index] = strptr[index]; + index++; + } + TPD_DEBUG("%s enter 3 firmware_id %s\n", + __func__, firmware_id); + retval = sstrtoul(firmware_id, 10, (unsigned long *)fw_id); + kfree(firmware_id); + if (retval) { + TPD_ERR("%s: Failed to obtain image firmware ID\n", + __func__); + return -EINVAL; + } + } + + return 0; +} + +static int fwu_get_device_config_id(void) +{ + int retval; + unsigned char config_id_size; + + TPD_DEBUG("%s enter\n", __func__); + if (fwu->bl_version == BL_V7 || fwu->bl_version == BL_V8) + config_id_size = V7_CONFIG_ID_SIZE; + else + config_id_size = V5V6_CONFIG_ID_SIZE; + + retval = synaptics_rmi4_reg_read(fwu->client, + fwu->f34_fd.ctrl_base_addr, + fwu->config_id, + config_id_size); + if (retval < 0) + return retval; + + return 0; +} + +static enum flash_area fwu_go_nogo(void) +{ + int retval; + enum flash_area flash_area = NONE; + unsigned char ii; + unsigned char config_id_size; + unsigned int device_fw_id; + unsigned int image_fw_id; + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; + + TPD_DEBUG("%s enter\n", __func__); + + if (rmi4_data->force) { + flash_area = UI_FIRMWARE; + TPD_ERR("%s force update firmware\n", __func__); + goto exit; + } + + if (fwu->force_update) { + flash_area = UI_FIRMWARE; + goto exit; + } + + /* Update both UI and config if device is in bootloader mode */ + if (fwu->bl_mode_device) { + flash_area = UI_FIRMWARE; + goto exit; + } + + /* Get device firmware ID */ + device_fw_id = rmi4_data->firmware_id; + TPD_ERR("%s: Device firmware ID = %d\n", + __func__, device_fw_id); + + /* Get image firmware ID */ + retval = fwu_get_image_firmware_id(&image_fw_id); + if (retval < 0) { + flash_area = NONE; + goto exit; + } + TPD_ERR("%s: Image firmware ID = %d\n", + __func__, image_fw_id); + + if (image_fw_id > device_fw_id) { + flash_area = UI_FIRMWARE; + goto exit; + } else if (image_fw_id < device_fw_id) { + TPD_ERR("%s: Image firmware ID older than device firmware ID\n", + __func__); + flash_area = NONE; + goto exit; + } + + /* Get device config ID */ + retval = fwu_get_device_config_id(); + if (retval < 0) { + TPD_ERR("%s: Failed to read device config ID\n", + __func__); + flash_area = NONE; + goto exit; + } + + if (fwu->bl_version == BL_V7 || fwu->bl_version == BL_V8) + config_id_size = V7_CONFIG_ID_SIZE; + else + config_id_size = V5V6_CONFIG_ID_SIZE; + + for (ii = 0; ii < config_id_size; ii++) { + if (fwu->img.ui_config.data[ii] > fwu->config_id[ii]) { + flash_area = UI_CONFIG; + goto exit; + } else if (fwu->img.ui_config.data[ii] < fwu->config_id[ii]) { + flash_area = NONE; + goto exit; + } + } + + flash_area = NONE; + +exit: + if (flash_area == NONE) { + TPD_ERR("%s: No need to do reflash\n", + __func__); + } else { + TPD_ERR("%s: Updating %s\n", + __func__, + flash_area == UI_FIRMWARE ? + "UI firmware and config" : + "UI config only"); + } + + return flash_area; +} + +static int fwu_scan_pdt(void) +{ + int retval; + unsigned char ii; + unsigned char intr_count = 0; + unsigned char intr_off; + unsigned char intr_src; + unsigned short addr; + bool f01found = false; + bool f34found = false; + bool f35found = false; + struct synaptics_rmi4_fn_desc2 rmi_fd; + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; + + char add_buf[6] = { 0 }; + + fwu->in_ub_mode = false; + + for (addr = PDT_START; addr > PDT_END; addr -= PDT_ENTRY_SIZE) { + retval = synaptics_rmi4_reg_read(fwu->client, + addr, + (unsigned char *)&rmi_fd, + sizeof(rmi_fd)); + if (retval < 0) + return retval; + + if (rmi_fd.fn_number) { + TPD_DEBUG("%s: Found F%02x\n", + __func__, rmi_fd.fn_number); + switch (rmi_fd.fn_number) { + case SYNAPTICS_RMI4_F01: + f01found = true; + + rmi4_data->f01_query_base_addr = + rmi_fd.query_base_addr; + rmi4_data->f01_ctrl_base_addr = + rmi_fd.ctrl_base_addr; + rmi4_data->f01_data_base_addr = + rmi_fd.data_base_addr; + rmi4_data->f01_cmd_base_addr = + rmi_fd.cmd_base_addr; + break; + case SYNAPTICS_RMI4_F34: + f34found = true; + fwu->f34_fd.query_base_addr = + rmi_fd.query_base_addr; + fwu->f34_fd.ctrl_base_addr = + rmi_fd.ctrl_base_addr; + fwu->f34_fd.data_base_addr = + rmi_fd.data_base_addr; + + switch (rmi_fd.fn_version) { + case F34_V0: + fwu->bl_version = BL_V5; + break; + case F34_V1: + fwu->bl_version = BL_V6; + break; + case F34_V2: + fwu->bl_version = BL_V7; + break; + default: + TPD_ERR("%s:Unrecog F34 V\n", + __func__); + return -EINVAL; + } + + fwu->intr_mask = 0; + intr_src = rmi_fd.intr_src_count; + intr_off = intr_count % 8; + for (ii = intr_off; + ii < (intr_src + intr_off); + ii++) { + fwu->intr_mask |= 1 << ii; + } + break; + case SYNAPTICS_RMI4_F35: + f35found = true; + fwu->f35_fd.query_base_addr = + rmi_fd.query_base_addr; + fwu->f35_fd.ctrl_base_addr = + rmi_fd.ctrl_base_addr; + fwu->f35_fd.data_base_addr = + rmi_fd.data_base_addr; + fwu->f35_fd.cmd_base_addr = + rmi_fd.cmd_base_addr; + break; + } + } else { + break; + } + + intr_count += rmi_fd.intr_src_count; + } + + if (!f01found || !f34found) { + TPD_ERR("%s: Failed to find both F01 and F34\n", + __func__); + if (!f35found) { + TPD_ERR("%s: Failed to find F35\n", + __func__); + return -EINVAL; + } else { + fwu->in_ub_mode = true; + TPD_ERR("%s: In microbootloader mode\n", + __func__); + fwu_recovery_check_status(); + return 0; + } + } + + rmi4_data->intr_mask[0] |= fwu->intr_mask; + + addr = rmi4_data->f01_ctrl_base_addr + 1; + + retval = synaptics_rmi4_reg_write(fwu->client, + addr, + &(rmi4_data->intr_mask[0]), + sizeof(rmi4_data->intr_mask[0])); + if (retval < 0) { + TPD_ERR("%s: Failed to set interrupt enable bit\n", + __func__); + return retval; + } + retval = synaptics_rmi4_i2c_read_block(fwu->client, + 0xE3, sizeof(add_buf), add_buf); + fwu->bl_reset_add = add_buf[1];/*0xe4*/ + return 0; +} + +static int fwu_enter_flash_prog(void) +{ + int retval; + struct f01_device_control f01_device_control; + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; + + TPD_DEBUG("%s enter\n", __func__); + retval = fwu_read_flash_status(); + if (retval < 0) + return retval; + + if (fwu->in_bl_mode) + return 0; + + retval = fwu_write_f34_command(CMD_ENABLE_FLASH_PROG); + if (retval < 0) + return retval; + + retval = fwu_wait_for_idle(ENABLE_WAIT_MS, false); + if (retval < 0) + return retval; + + if (!fwu->in_bl_mode) { + TPD_ERR("%s: BL mode not entered\n", + __func__); + return -EINVAL; + } + + retval = fwu_scan_pdt(); + if (retval < 0) + return retval; + + retval = fwu_read_f34_queries(); + if (retval < 0) + return retval; + + retval = synaptics_rmi4_reg_read(fwu->client, + rmi4_data->f01_ctrl_base_addr, + f01_device_control.data, + sizeof(f01_device_control.data)); + if (retval < 0) { + TPD_ERR("%s: Failed to read F01 device control\n", + __func__); + return retval; + } + + f01_device_control.nosleep = true; + f01_device_control.sleep_mode = SLEEP_MODE_NORMAL; + + retval = synaptics_rmi4_reg_write(fwu->client, + rmi4_data->f01_ctrl_base_addr, + f01_device_control.data, + sizeof(f01_device_control.data)); + if (retval < 0) { + TPD_ERR("%s: Failed to write F01 device control\n", + __func__); + return retval; + } + + msleep(ENTER_FLASH_PROG_WAIT_MS); + + return retval; +} + +static int fwu_check_ui_firmware_size(void) +{ + unsigned short block_count; + + block_count = fwu->img.ui_firmware.size / fwu->block_size; + + if (block_count != fwu->blkcount.ui_firmware) { + TPD_ERR("%s: UI firmware size mismatch\n", + __func__); + return -EINVAL; + } + + return 0; +} + +static int fwu_check_ui_configuration_size(void) +{ + unsigned short block_count; + + block_count = fwu->img.ui_config.size / fwu->block_size; + + if (block_count != fwu->blkcount.ui_config) { + TPD_ERR("%s: UI configuration size mismatch\n", + __func__); + return -EINVAL; + } + + return 0; +} + +static int fwu_check_dp_configuration_size(void) +{ + unsigned short block_count; + + block_count = fwu->img.dp_config.size / fwu->block_size; + + if (block_count != fwu->blkcount.dp_config) { + TPD_ERR("%s: Display configuration size mismatch\n", + __func__); + return -EINVAL; + } + + return 0; +} + +static int fwu_check_bl_configuration_size(void) +{ + unsigned short block_count; + + block_count = fwu->img.bl_config.size / fwu->block_size; + + if (block_count != fwu->blkcount.bl_config) { + TPD_ERR("%s: Bootloader configuration size mismatch\n", + __func__); + return -EINVAL; + } + + return 0; +} + +static int fwu_check_guest_code_size(void) +{ + unsigned short block_count; + + block_count = fwu->img.guest_code.size / fwu->block_size; + if (block_count != fwu->blkcount.guest_code) { + TPD_ERR("%s: Guest code size mismatch\n", + __func__); + return -EINVAL; + } + + return 0; +} + +static int fwu_erase_configuration(void) +{ + int retval; + + switch (fwu->config_area) { + case UI_CONFIG_AREA: + retval = fwu_write_f34_command(CMD_ERASE_UI_CONFIG); + if (retval < 0) + return retval; + break; + case DP_CONFIG_AREA: + retval = fwu_write_f34_command(CMD_ERASE_DISP_CONFIG); + if (retval < 0) + return retval; + break; + case BL_CONFIG_AREA: + retval = fwu_write_f34_command(CMD_ERASE_BL_CONFIG); + if (retval < 0) + return retval; + break; + case FLASH_CONFIG_AREA: + retval = fwu_write_f34_command(CMD_ERASE_FLASH_CONFIG); + if (retval < 0) + return retval; + break; + case UPP_AREA: + retval = fwu_write_f34_command(CMD_ERASE_UTILITY_PARAMETER); + if (retval < 0) + return retval; + default: + TPD_ERR("%s: Invalid config area\n", + __func__); + return -EINVAL; + } + + TPD_DEBUG("%s: Erase command written\n", + __func__); + + retval = fwu_wait_for_idle(ERASE_WAIT_MS, false); + if (retval < 0) + return retval; + + TPD_DEBUG("%s: Idle status detected\n", + __func__); + + return retval; +} + +static int fwu_erase_bootloader(void) +{ + int retval; + + retval = fwu_write_f34_command(CMD_ERASE_BOOTLOADER); + if (retval < 0) + return retval; + + TPD_DEBUG("%s: Erase command written\n", + __func__); + + retval = fwu_wait_for_idle(ERASE_WAIT_MS, false); + if (retval < 0) + return retval; + + TPD_DEBUG("%s: Idle status detected\n", + __func__); + + return 0; +} + +static int fwu_erase_guest_code(void) +{ + int retval; + + retval = fwu_write_f34_command(CMD_ERASE_GUEST_CODE); + if (retval < 0) + return retval; + + TPD_DEBUG("%s: Erase command written\n", + __func__); + + retval = fwu_wait_for_idle(ERASE_WAIT_MS, false); + if (retval < 0) + return retval; + + TPD_DEBUG("%s: Idle status detected\n", + __func__); + + return 0; +} + +static int fwu_erase_all(void) +{ + int retval; + + if (fwu->bl_version == BL_V7) { + retval = fwu_write_f34_command(CMD_ERASE_UI_FIRMWARE); + if (retval < 0) + return retval; + + TPD_DEBUG("%s: Erase command written\n", + __func__); + + retval = fwu_wait_for_idle(ERASE_WAIT_MS, false); + if (retval < 0) + return retval; + + TPD_DEBUG("%s: Idle status detected\n", + __func__); + + fwu->config_area = UI_CONFIG_AREA; + retval = fwu_erase_configuration(); + if (retval < 0) + return retval; + } else { + retval = fwu_write_f34_command(CMD_ERASE_ALL); + if (retval < 0) + return retval; + + TPD_DEBUG("%s: Erase all command written\n", + __func__); + + retval = fwu_wait_for_idle(ERASE_WAIT_MS, false); + if (!(fwu->bl_version == BL_V8 && + fwu->flash_status == BAD_PARTITION_TABLE)) { + if (retval < 0) + return retval; + } + + TPD_DEBUG("%s: Idle status detected\n", + __func__); + + if (fwu->bl_version == BL_V8) + return 0; + } + + if (fwu->flash_properties.has_disp_config) { + fwu->config_area = DP_CONFIG_AREA; + retval = fwu_erase_configuration(); + if (retval < 0) + return retval; + } + + if (fwu->has_guest_code) { + retval = fwu_erase_guest_code(); + if (retval < 0) + return retval; + } + + return 0; +} + +static int fwu_write_firmware(void) +{ + unsigned short firmware_block_count; + + firmware_block_count = fwu->img.ui_firmware.size / fwu->block_size; + + return fwu_write_f34_blocks((unsigned char *)fwu->img.ui_firmware.data, + firmware_block_count, CMD_WRITE_FW); +} + +static int fwu_write_bootloader(void) +{ + int retval; + unsigned short bootloader_block_count; + + bootloader_block_count = fwu->img.bl_image.size / fwu->block_size; + + fwu->write_bootloader = true; + retval = fwu_write_f34_blocks((unsigned char *)fwu->img.bl_image.data, + bootloader_block_count, CMD_WRITE_BOOTLOADER); + fwu->write_bootloader = false; + + return retval; +} + +static int fwu_write_utility_parameter(void) +{ + int retval; + unsigned char ii; + unsigned char checksum_array[4]; + unsigned char *pbuf; + unsigned short remaining_size; + unsigned short utility_param_size; + unsigned long checksum; + + utility_param_size = fwu->blkcount.utility_param * fwu->block_size; + retval = fwu_allocate_read_config_buf(utility_param_size); + if (retval < 0) + return retval; + memset(fwu->read_config_buf, 0x00, utility_param_size); + + pbuf = fwu->read_config_buf; + remaining_size = utility_param_size - 4; + + for (ii = 0; ii < MAX_UTILITY_PARAMS; ii++) { + if (fwu->img.utility_param_id[ii] == UNUSED) + continue; + +#ifdef F51_DISCRETE_FORCE + if (fwu->img.utility_param_id[ii] == FORCE_PARAMETER) { + if (fwu->bl_mode_device) { + TPD_ERR("%s:skipping calibration data restoration\n", + __func__); + goto image_param; + } + retval = secure_memcpy(&(pbuf[4]), + remaining_size - 4, + fwu->cal_data, + fwu->cal_data_buf_size, + fwu->cal_data_size); + if (retval < 0) { + TPD_ERR("%s:Failed to copy force calibration data\n", + __func__); + return retval; + } + pbuf[0] = FORCE_PARAMETER; + pbuf[1] = 0x00; + pbuf[2] = (4 + fwu->cal_data_size) / 2; + pbuf += (fwu->cal_data_size + 4); + remaining_size -= (fwu->cal_data_size + 4); + continue; + } +image_param: +#endif + + retval = secure_memcpy(pbuf, + remaining_size, + fwu->img.utility_param[ii].data, + fwu->img.utility_param[ii].size, + fwu->img.utility_param[ii].size); + if (retval < 0) { + TPD_ERR("%s: Failed to copy utility parameter data\n", + __func__); + return retval; + } + pbuf += fwu->img.utility_param[ii].size; + remaining_size -= fwu->img.utility_param[ii].size; + } + + calculate_checksum((unsigned short *)fwu->read_config_buf, + ((utility_param_size - 4) / 2), + &checksum); + + convert_to_little_endian(checksum_array, checksum); + + fwu->read_config_buf[utility_param_size - 4] = checksum_array[0]; + fwu->read_config_buf[utility_param_size - 3] = checksum_array[1]; + fwu->read_config_buf[utility_param_size - 2] = checksum_array[2]; + fwu->read_config_buf[utility_param_size - 1] = checksum_array[3]; + + retval = fwu_write_f34_blocks((unsigned char *)fwu->read_config_buf, + fwu->blkcount.utility_param, CMD_WRITE_UTILITY_PARAM); + if (retval < 0) + return retval; + + return 0; +} + +static int fwu_write_configuration(void) +{ + return fwu_write_f34_blocks((unsigned char *)fwu->config_data, + fwu->config_block_count, CMD_WRITE_CONFIG); +} + +static int fwu_write_ui_configuration(void) +{ + fwu->config_area = UI_CONFIG_AREA; + fwu->config_data = fwu->img.ui_config.data; + fwu->config_size = fwu->img.ui_config.size; + fwu->config_block_count = fwu->config_size / fwu->block_size; + + return fwu_write_configuration(); +} + +static int fwu_write_dp_configuration(void) +{ + fwu->config_area = DP_CONFIG_AREA; + fwu->config_data = fwu->img.dp_config.data; + fwu->config_size = fwu->img.dp_config.size; + fwu->config_block_count = fwu->config_size / fwu->block_size; + + return fwu_write_configuration(); +} + +static int fwu_write_flash_configuration(void) +{ + int retval; + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; + + fwu->config_area = FLASH_CONFIG_AREA; + fwu->config_data = fwu->img.fl_config.data; + fwu->config_size = fwu->img.fl_config.size; + fwu->config_block_count = fwu->config_size / fwu->block_size; + + if (fwu->config_block_count != fwu->blkcount.fl_config) { + TPD_ERR("%s: Flash configuration size mismatch\n", + __func__); + return -EINVAL; + } + + retval = fwu_erase_configuration(); + if (retval < 0) + return retval; + + retval = fwu_write_configuration(); + if (retval < 0) + return retval; + + rmi4_data->reset_device(fwu->client, false); + + return 0; +} + +static int fwu_write_guest_code(void) +{ + int retval; + unsigned short guest_code_block_count; + + guest_code_block_count = fwu->img.guest_code.size / fwu->block_size; + + retval = fwu_write_f34_blocks((unsigned char *)fwu->img.guest_code.data, + guest_code_block_count, CMD_WRITE_GUEST_CODE); + if (retval < 0) + return retval; + + return 0; +} + +static int fwu_write_lockdown(void) +{ + unsigned short lockdown_block_count; + + lockdown_block_count = fwu->img.lockdown.size / fwu->block_size; + + return fwu_write_f34_blocks((unsigned char *)fwu->img.lockdown.data, + lockdown_block_count, CMD_WRITE_LOCKDOWN); +} + +static int fwu_write_partition_table_v8(void) +{ + int retval; + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; + + TPD_DEBUG("%s enter\n", __func__); + fwu->config_area = FLASH_CONFIG_AREA; + fwu->config_data = fwu->img.fl_config.data; + fwu->config_size = fwu->img.fl_config.size; + fwu->config_block_count = fwu->config_size / fwu->block_size; + + if (fwu->config_block_count != fwu->blkcount.fl_config) { + TPD_ERR("%s: Flash configuration size mismatch\n", + __func__); + return -EINVAL; + } + + retval = fwu_write_configuration(); + if (retval < 0) + return retval; + TPD_ERR("%s enter 1\n ", __func__); + rmi4_data->reset_device(fwu->client, false); + + return 0; +} + +static int fwu_write_partition_table_v7(void) +{ + int retval; + unsigned short block_count; + + TPD_DEBUG("%s enter\n", __func__); + + block_count = fwu->blkcount.bl_config; + fwu->config_area = BL_CONFIG_AREA; + fwu->config_size = fwu->block_size * block_count; + + retval = fwu_allocate_read_config_buf(fwu->config_size); + if (retval < 0) + return retval; + + retval = fwu_read_f34_blocks(block_count, CMD_READ_CONFIG); + if (retval < 0) + return retval; + + retval = fwu_erase_configuration(); + if (retval < 0) + return retval; + + retval = fwu_write_flash_configuration(); + if (retval < 0) + return retval; + + fwu->config_area = BL_CONFIG_AREA; + fwu->config_data = fwu->read_config_buf; + fwu->config_size = fwu->img.bl_config.size; + fwu->config_block_count = fwu->config_size / fwu->block_size; + + retval = fwu_write_configuration(); + if (retval < 0) + return retval; + + return 0; +} + +static int fwu_write_bl_area_v7(void) +{ + int retval; + bool has_utility_param; + + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; + + TPD_DEBUG("%s enter\n ", __func__); + + has_utility_param = fwu->has_utility_param; + + if (fwu->has_utility_param) { + fwu->config_area = UPP_AREA; + retval = fwu_erase_configuration(); + if (retval < 0) + return retval; + } + + fwu->config_area = BL_CONFIG_AREA; + retval = fwu_erase_configuration(); + if (retval < 0) + return retval; + + fwu->config_area = FLASH_CONFIG_AREA; + retval = fwu_erase_configuration(); + if (retval < 0) + return retval; + + retval = fwu_erase_bootloader(); + if (retval < 0) + return retval; + + retval = fwu_write_bootloader(); + if (retval < 0) + return retval; + /*msleep(rmi4_data->hw_if->board_data->reset_delay_ms);*/ + rmi4_data->reset_device(fwu->client, false); + + fwu->config_area = FLASH_CONFIG_AREA; + fwu->config_data = fwu->img.fl_config.data; + fwu->config_size = fwu->img.fl_config.size; + fwu->config_block_count = fwu->config_size / fwu->block_size; + retval = fwu_write_configuration(); + if (retval < 0) + return retval; + rmi4_data->reset_device(fwu->client, false); + + fwu->config_area = BL_CONFIG_AREA; + fwu->config_data = fwu->img.bl_config.data; + fwu->config_size = fwu->img.bl_config.size; + fwu->config_block_count = fwu->config_size / fwu->block_size; + retval = fwu_write_configuration(); + if (retval < 0) + return retval; + + if (fwu->img.contains_utility_param) { + retval = fwu_write_utility_parameter(); + if (retval < 0) + return retval; + } + + return 0; +} + +static int fwu_do_reflash(void) +{ + int retval; + bool do_bl_update = false; + + TPD_DEBUG("%s enter\n", __func__); + if (!fwu->new_partition_table) { + retval = fwu_check_ui_firmware_size(); + if (retval < 0) + return retval; + + retval = fwu_check_ui_configuration_size(); + if (retval < 0) + return retval; + + if (fwu->flash_properties.has_disp_config && + fwu->img.contains_disp_config) { + retval = fwu_check_dp_configuration_size(); + if (retval < 0) + return retval; + } + + if (fwu->has_guest_code && fwu->img.contains_guest_code) { + retval = fwu_check_guest_code_size(); + if (retval < 0) + return retval; + } + } else if (fwu->bl_version == BL_V7) { + retval = fwu_check_bl_configuration_size(); + if (retval < 0) + return retval; + } + + if (!fwu->has_utility_param && fwu->img.contains_utility_param) { + if (fwu->bl_version == BL_V7 || fwu->bl_version == BL_V8) + do_bl_update = true; + } + + if (fwu->has_utility_param && !fwu->img.contains_utility_param) { + if (fwu->bl_version == BL_V7 || fwu->bl_version == BL_V8) + do_bl_update = true; + } + + if (!do_bl_update && fwu->incompatible_partition_tables) { + TPD_ERR("%s: Incompatible partition tables\n", + __func__); + return -EINVAL; + } else if (!do_bl_update && fwu->new_partition_table) { + if (!fwu->force_update) { + TPD_ERR("%s: Partition table mismatch\n", + __func__); + return -EINVAL; + } + } + + retval = fwu_erase_all(); + if (retval < 0) + return retval; + + if (do_bl_update) { + retval = fwu_write_bl_area_v7(); + if (retval < 0) + return retval; + TPD_ERR("%s: Bootloader area programmed\n", __func__); + } else if (fwu->bl_version == BL_V7 && fwu->new_partition_table) { + retval = fwu_write_partition_table_v7(); + if (retval < 0) + return retval; + TPD_ERR("%s: Partition table programmed\n", __func__); + } else if (fwu->bl_version == BL_V8) { + retval = fwu_write_partition_table_v8(); + if (retval < 0) + return retval; + TPD_ERR("%s: Partition table programmed\n", __func__); + } + + retval = fwu_write_firmware(); + if (retval < 0) + return retval; + TPD_ERR("%s: Firmware programmed\n", __func__); + + fwu->config_area = UI_CONFIG_AREA; + retval = fwu_write_ui_configuration(); + if (retval < 0) + return retval; + TPD_ERR("%s: Configuration programmed\n", __func__); + + if (fwu->flash_properties.has_disp_config && + fwu->img.contains_disp_config) { + retval = fwu_write_dp_configuration(); + if (retval < 0) + return retval; + TPD_ERR("%s: Display configuration programmed\n", __func__); + } + + if (fwu->has_guest_code && fwu->img.contains_guest_code) { + retval = fwu_write_guest_code(); + if (retval < 0) + return retval; + TPD_ERR("%s: Guest code programmed\n", __func__); + } + + return retval; +} + +static int fwu_do_lockdown_v7(void) +{ + int retval; + struct f34_v7_data0 status; + + TPD_DEBUG("%s enter\n", __func__); + retval = fwu_enter_flash_prog(); + if (retval < 0) + return retval; + + retval = synaptics_rmi4_reg_read(fwu->client, + fwu->f34_fd.data_base_addr + fwu->off.flash_status, + status.data, + sizeof(status.data)); + if (retval < 0) { + TPD_ERR("%s: Failed to read flash status\n", + __func__); + return retval; + } + + if (status.device_cfg_status == 2) { + TPD_ERR("%s: Device already locked down\n", + __func__); + return 0; + } + + retval = fwu_write_lockdown(); + if (retval < 0) + return retval; + + pr_notice("%s: Lockdown programmed\n", __func__); + + return retval; +} + +static int fwu_do_lockdown_v5v6(void) +{ + int retval; + + TPD_DEBUG("%s enter\n", __func__); + retval = fwu_enter_flash_prog(); + if (retval < 0) + return retval; + + retval = synaptics_rmi4_reg_read(fwu->client, + fwu->f34_fd.query_base_addr + fwu->off.properties, + fwu->flash_properties.data, + sizeof(fwu->flash_properties.data)); + if (retval < 0) { + TPD_ERR("%s: Failed to read flash properties\n", + __func__); + return retval; + } + + if (fwu->flash_properties.unlocked == 0) { + TPD_ERR("%s: Device already locked down\n", + __func__); + return 0; + } + + retval = fwu_write_lockdown(); + if (retval < 0) + return retval; + + pr_notice("%s: Lockdown programmed\n", __func__); + + return retval; +} + +#ifdef F51_DISCRETE_FORCE +static int fwu_do_restore_f51_cal_data(void) +{ + int retval; + unsigned char checksum_array[4]; + unsigned short block_count; + unsigned long checksum; + + block_count = fwu->blkcount.ui_config; + fwu->config_size = fwu->block_size * block_count; + fwu->config_area = UI_CONFIG_AREA; + + retval = fwu_allocate_read_config_buf(fwu->config_size); + if (retval < 0) + return retval; + + retval = fwu_read_f34_blocks(block_count, CMD_READ_CONFIG); + if (retval < 0) + return retval; + + retval = secure_memcpy(&fwu->read_config_buf[fwu->cal_data_off], + fwu->cal_data_size, fwu->cal_data, + fwu->cal_data_buf_size, fwu->cal_data_size); + if (retval < 0) { + TPD_ERR("%s: Failed to restore calibration data\n", + __func__); + return retval; + } + + calculate_checksum((unsigned short *)fwu->read_config_buf, + ((fwu->config_size - 4) / 2), + &checksum); + + convert_to_little_endian(checksum_array, checksum); + + fwu->read_config_buf[fwu->config_size - 4] = checksum_array[0]; + fwu->read_config_buf[fwu->config_size - 3] = checksum_array[1]; + fwu->read_config_buf[fwu->config_size - 2] = checksum_array[2]; + fwu->read_config_buf[fwu->config_size - 1] = checksum_array[3]; + + retval = fwu_enter_flash_prog(); + if (retval < 0) + return retval; + + fwu->config_area = UI_CONFIG_AREA; + fwu->config_data = fwu->read_config_buf; + fwu->config_block_count = fwu->config_size / fwu->block_size; + + retval = fwu_erase_configuration(); + if (retval < 0) + return retval; + + retval = fwu_write_configuration(); + if (retval < 0) + return retval; + + return 0; +} +#endif + +static int fwu_start_reflash(const unsigned char *fw_image) +{ + int retval = 0; + enum flash_area flash_area; + bool do_rebuild = false; + /*const struct firmware *fw_entry = NULL;*/ + unsigned char temp; + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; + + TPD_DEBUG("%s: enter\n", __func__); + if (rmi4_data->sensor_sleep) { + TPD_ERR("%s: Sensor sleeping\n", + __func__); + return -ENODEV; + } + + rmi4_data->stay_awake = true; + + /*mutex_lock(&rmi4_data->rmi4_exp_init_mutex);*/ + + TPD_ERR("%s: Start of reflash process\n", __func__); + + fwu->image = fw_image; + + #ifdef OLD_WAY_SYNA_REQ_FIRM + if (fwu->image == NULL) { + retval = secure_memcpy(fwu->image_name, MAX_IMAGE_NAME_LEN, + FW_IMAGE_NAME, sizeof(FW_IMAGE_NAME), + sizeof(FW_IMAGE_NAME)); + if (retval < 0) { + TPD_ERR("%s: Failed to copy image file name\n", + __func__); + goto exit; + } + TPD_ERR("%s: Requesting firmware image %s\n", + __func__, fwu->image_name); + + retval = request_firmware(&fw_entry, fwu->image_name, + rmi4_data->s3706_dev); + if (retval != 0) { + TPD_ERR("%s: Firmware image %s not available\n", + __func__, fwu->image_name); + retval = -EINVAL; + goto exit; + } + + TPD_ERR("%s: Firmware image size = %d\n", + __func__, (unsigned int)fw_entry->size); + + fwu->image = fw_entry->data; + } + #endif + + retval = fwu_parse_image_info(); + if (retval < 0) + goto exit; + + if (fwu->blkcount.total_count != fwu->img.blkcount.total_count) { + TPD_ERR("%s: Flash size mismatch\n", + __func__); + retval = -EINVAL; + goto exit; + } + + if (fwu->bl_version != fwu->img.bl_version) { + TPD_ERR("%s: Bootloader version mismatch\n", + __func__); + retval = -EINVAL; + goto exit; + } + + retval = fwu_read_flash_status(); + if (retval < 0) + goto exit; + + if (fwu->in_bl_mode) { + fwu->bl_mode_device = true; + TPD_ERR("%s: Device in bootloader mode\n", + __func__); + } else { + fwu->bl_mode_device = false; + } + + flash_area = fwu_go_nogo(); + + if (flash_area != NONE) { + retval = fwu_enter_flash_prog(); + if (retval < 0) { + rmi4_data->reset_device(fwu->client, false); + goto exit; + } + } +#ifdef F51_DISCRETE_FORCE + if (flash_area != NONE && !fwu->bl_mode_device) { + fwu->config_size = fwu->block_size * fwu->blkcount.ui_config; + fwu->config_area = UI_CONFIG_AREA; + + retval = fwu_allocate_read_config_buf(fwu->config_size); + if (retval < 0) { + rmi4_data->reset_device(fwu->client, false); + goto exit; + } + + retval = fwu_read_f34_blocks(fwu->blkcount.ui_config, + CMD_READ_CONFIG); + if (retval < 0) { + rmi4_data->reset_device(fwu->client, false); + goto exit; + } + + retval = secure_memcpy(fwu->cal_data, fwu->cal_data_buf_size, + &fwu->read_config_buf[fwu->cal_data_off], + fwu->cal_data_size, fwu->cal_data_size); + if (retval < 0) { + TPD_ERR("%s: Failed to save calibration data\n", + __func__); + rmi4_data->reset_device(fwu->client, false); + goto exit; + } + } +#endif + + switch (flash_area) { + case UI_FIRMWARE: + do_rebuild = true; + retval = fwu_do_reflash(); +#ifdef F51_DISCRETE_FORCE + if (retval < 0) + break; + + if (fwu->has_utility_param || fwu->img.contains_utility_param) + break; + + rmi4_data->reset_device(fwu->client, false); + + if (fwu->bl_mode_device || fwu->in_bl_mode) { + TPD_ERR("%s:bl mode skip calibration data restoration\n", + __func__); + break; + } + + retval = fwu_do_restore_f51_cal_data(); +#endif + break; + case UI_CONFIG: + do_rebuild = true; + retval = fwu_check_ui_configuration_size(); + if (retval < 0) + break; + fwu->config_area = UI_CONFIG_AREA; + retval = fwu_erase_configuration(); + if (retval < 0) + break; + retval = fwu_write_ui_configuration(); +#ifdef F51_DISCRETE_FORCE + if (retval < 0) + break; + + if (fwu->has_utility_param) + break; + + retval = fwu_do_restore_f51_cal_data(); +#endif + break; + case NONE: + default: + break; + } + + if (retval < 0) { + do_rebuild = false; + rmi4_data->reset_device(fwu->client, false); + TPD_ERR("%s: Failed to do reflash\n", + __func__); + goto exit; + } + + if (fwu->do_lockdown && (fwu->img.lockdown.data != NULL)) { + switch (fwu->bl_version) { + case BL_V5: + case BL_V6: + retval = fwu_do_lockdown_v5v6(); + if (retval < 0) { + TPD_ERR("%s: Failed to do lockdown\n", + __func__); + } + rmi4_data->reset_device(fwu->client, false); + break; + case BL_V7: + case BL_V8: + retval = fwu_do_lockdown_v7(); + if (retval < 0) { + TPD_ERR("%s: Failed to do lockdown\n", + __func__); + } + rmi4_data->reset_device(fwu->client, false); + break; + default: + break; + } + } + +exit: + #ifdef OLD_WAY_SYNA_REQ_FIRM + if (fw_entry) + release_firmware(fw_entry); + #endif + /*if (do_rebuild)*/ + rmi4_data->reset_device(fwu->client, true); + temp = 0x01; + synaptics_rmi4_reg_write(fwu->client, + fwu->bl_reset_add, &temp, 1);/*reset tp*/ + + TPD_ERR("%s: End of reflash process\n", __func__); + + /*mutex_unlock(&rmi4_data->rmi4_exp_init_mutex);*/ + + rmi4_data->stay_awake = false; + + return retval; +} + +static int fwu_recovery_check_status(void) +{ + int retval; + unsigned char data_base; + unsigned char status; + + data_base = fwu->f35_fd.data_base_addr; + + retval = synaptics_rmi4_reg_read(fwu->client, + data_base + F35_ERROR_CODE_OFFSET, + &status, + 1); + if (retval < 0) { + TPD_ERR("%s: Failed to read status\n", + __func__); + return retval; + } + + status = status & MASK_5BIT; + + if (status != 0x00) { + TPD_ERR("%s: Recovery mode status = %d\n", + __func__, status); + return -EINVAL; + } + + return 0; +} + +static int fwu_recovery_erase_completion(void) +{ + int retval; + unsigned char data_base; + unsigned char command; + unsigned char status; + unsigned int timeout = F35_ERASE_ALL_WAIT_MS / 20; + + data_base = fwu->f35_fd.data_base_addr; + TPD_DEBUG("%s enter\n", __func__); + do { + command = 0x01; + retval = synaptics_rmi4_reg_write(fwu->client, + fwu->f35_fd.cmd_base_addr, + &command, + sizeof(command)); + if (retval < 0) { + TPD_ERR("%s: Failed to issue command\n", + __func__); + return retval; + } + + do { + retval = synaptics_rmi4_reg_read(fwu->client, + fwu->f35_fd.cmd_base_addr, + &command, + sizeof(command)); + if (retval < 0) { + TPD_ERR("%s: Failed to read command status\n", + __func__); + return retval; + } + + if ((command & 0x01) == 0x00) + break; + + msleep(20); + timeout--; + } while (timeout > 0); + + if (timeout == 0) + goto exit; + + retval = synaptics_rmi4_reg_read(fwu->client, + data_base + F35_FLASH_STATUS_OFFSET, + &status, + sizeof(status)); + if (retval < 0) { + TPD_ERR("%s: Failed to read flash status\n", + __func__); + return retval; + } + + if ((status & 0x01) == 0x00) + break; + + msleep(20); + timeout--; + } while (timeout > 0); + +exit: + if (timeout == 0) { + TPD_ERR("%s: Timed out waiting for flash erase completion\n", + __func__); + return -ETIMEDOUT; + } + + return 0; +} + +static int fwu_recovery_erase_all(void) +{ + int retval; + unsigned char ctrl_base; + unsigned char command = CMD_F35_ERASE_ALL; + + TPD_DEBUG("%s enter\n", __func__); + ctrl_base = fwu->f35_fd.ctrl_base_addr; + + retval = synaptics_rmi4_reg_write(fwu->client, + ctrl_base + F35_CHUNK_COMMAND_OFFSET, + &command, + sizeof(command)); + if (retval < 0) { + TPD_ERR("%s: Failed to issue erase all command\n", + __func__); + return retval; + } + + if (fwu->f35_fd.cmd_base_addr) { + retval = fwu_recovery_erase_completion(); + if (retval < 0) + return retval; + } else { + msleep(F35_ERASE_ALL_WAIT_MS); + } + + retval = fwu_recovery_check_status(); + if (retval < 0) + return retval; + + return 0; +} + +static int fwu_recovery_write_chunk(void) +{ + int retval; + unsigned char ctrl_base; + unsigned char chunk_number[] = {0, 0}; + unsigned char chunk_spare; + unsigned char chunk_size; + unsigned char buf[F35_CHUNK_SIZE + 1]; + unsigned short chunk; + unsigned short chunk_total; + unsigned short bytes_written = 0; + unsigned char *chunk_ptr = (unsigned char *)fwu->image; + + ctrl_base = fwu->f35_fd.ctrl_base_addr; + + retval = synaptics_rmi4_reg_write(fwu->client, + ctrl_base + F35_CHUNK_NUM_LSB_OFFSET, + chunk_number, + sizeof(chunk_number)); + if (retval < 0) { + TPD_ERR("%s: Failed to write chunk number\n", + __func__); + return retval; + } + + buf[sizeof(buf) - 1] = CMD_F35_WRITE_CHUNK; + + chunk_total = fwu->image_size / F35_CHUNK_SIZE; + chunk_spare = fwu->image_size % F35_CHUNK_SIZE; + if (chunk_spare) + chunk_total++; + + for (chunk = 0; chunk < chunk_total; chunk++) { + if (chunk_spare && chunk == chunk_total - 1) + chunk_size = chunk_spare; + else + chunk_size = F35_CHUNK_SIZE; + + memset(buf, 0x00, F35_CHUNK_SIZE); + secure_memcpy(buf, sizeof(buf), chunk_ptr, + fwu->image_size - bytes_written, + chunk_size); + + retval = synaptics_rmi4_reg_write(fwu->client, + ctrl_base + F35_CHUNK_DATA_OFFSET, + buf, + sizeof(buf)); + if (retval < 0) { + TPD_ERR("%s: Failed to write chunk data (chunk %d)\n", + __func__, chunk); + return retval; + } + chunk_ptr += chunk_size; + bytes_written += chunk_size; + } + + retval = fwu_recovery_check_status(); + if (retval < 0) { + TPD_ERR("%s: Failed to write chunk data\n", + __func__); + return retval; + } + + return 0; +} + +static int fwu_recovery_reset(void) +{ + int retval; + unsigned char ctrl_base; + unsigned char command = CMD_F35_RESET; + + ctrl_base = fwu->f35_fd.ctrl_base_addr; + + retval = synaptics_rmi4_reg_write(fwu->client, + ctrl_base + F35_CHUNK_COMMAND_OFFSET, + &command, + sizeof(command)); + if (retval < 0) { + TPD_ERR("%s: Failed to issue reset command\n", + __func__); + return retval; + } + + msleep(F35_RESET_WAIT_MS); + + return 0; +} + +static int fwu_start_recovery(void) +{ + int retval; + const struct firmware *fw_entry = NULL; + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; + + TPD_DEBUG("%s enter", __func__); + if (rmi4_data->sensor_sleep) { + TPD_ERR("%s: Sensor sleeping\n", + __func__); + return -ENODEV; + } + + rmi4_data->stay_awake = true; + + /*mutex_lock(&rmi4_data->rmi4_exp_init_mutex);*/ + + pr_notice("%s: Start of recovery process\n", __func__); + + if (fwu->image == NULL) { + retval = secure_memcpy(fwu->image_name, MAX_IMAGE_NAME_LEN, + FW_IHEX_NAME, sizeof(FW_IHEX_NAME), + sizeof(FW_IHEX_NAME)); + if (retval < 0) { + TPD_ERR("%s: Failed to copy ihex file name\n", + __func__); + goto exit; + } + TPD_ERR("%s: Requesting firmware ihex %s\n", + __func__, fwu->image_name); + + retval = request_firmware(&fw_entry, fwu->image_name, + rmi4_data->pdev->dev.parent); + if (retval != 0) { + TPD_ERR("%s: Firmware ihex %s not available\n", + __func__, fwu->image_name); + retval = -EINVAL; + goto exit; + } + + TPD_ERR("%s: Firmware image size = %d\n", + __func__, (unsigned int)fw_entry->size); + + fwu->image = fw_entry->data; + fwu->image_size = fw_entry->size; + } + + /*retval = rmi4_data->irq_enable(rmi4_data, false, false);*/ + if (retval < 0) { + TPD_ERR("%s: Failed to disable interrupt\n", + __func__); + goto exit; + } + + retval = fwu_recovery_erase_all(); + if (retval < 0) { + TPD_ERR("%s: Failed to do erase all in recovery mode\n", + __func__); + goto exit; + } + + pr_notice("%s: External flash erased\n", __func__); + + retval = fwu_recovery_write_chunk(); + if (retval < 0) { + TPD_ERR("%s: Failed to write chunk data in recovery mode\n", + __func__); + goto exit; + } + + pr_notice("%s: Chunk data programmed\n", __func__); + + retval = fwu_recovery_reset(); + if (retval < 0) { + TPD_ERR("%s: Failed to reset device in recovery mode\n", + __func__); + goto exit; + } + + pr_notice("%s: Recovery mode reset issued\n", __func__); + + rmi4_data->reset_device(fwu->client, true); + + retval = 0; + +exit: + if (fw_entry) + release_firmware(fw_entry); + + pr_notice("%s: End of recovery process\n", __func__); + + /*mutex_unlock(&rmi4_data->rmi4_exp_init_mutex);*/ + + rmi4_data->stay_awake = false; + + return retval; +} + +int synaptics_fw_updater(const unsigned char *fw_data, + const unsigned char *fw_image) +{ + int retval; + + TPD_DEBUG("%s enter\n", __func__); + if (!fwu) + return -ENODEV; + + if (!fwu->initialized) + return -ENODEV; + + if (fwu->in_ub_mode) { + fwu->image = NULL; + retval = fwu_start_recovery(); + if (retval < 0) + return retval; + } + + fwu->image = fw_data; + + retval = fwu_start_reflash(fw_image); + + fwu->image = NULL; + + return retval; +} +EXPORT_SYMBOL(synaptics_fw_updater); + +static int fwu_startup_fw_update_work(const unsigned char *fw_image) +{ + int retval; + +#ifdef WAIT_FOR_FB_READY + unsigned int timeout; + struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; +#endif + +#ifdef WAIT_FOR_FB_READY + timeout = FB_READY_TIMEOUT_S * 1000 / FB_READY_WAIT_MS + 1; + + while (!rmi4_data->fb_ready) { + msleep(FB_READY_WAIT_MS); + timeout--; + if (timeout == 0) { + TPD_ERR("%s: Timed out waiting for FB ready\n", + __func__); + return -EINVAL; + } + } +#endif + + retval = synaptics_fw_updater(NULL, fw_image); + + return retval; +} + +int synaptics_rmi4_fwu_init(struct synaptics_rmi4_data *rmi4_data, + const unsigned char *fw_image, struct i2c_client *client) +{ + int retval; + /*unsigned char attr_count;*/ + struct pdt_properties pdt_props; + + if (!fw_image || !rmi4_data || !client) { + TPD_ERR("%s: fw_image rmi4_data client is null\n", __func__); + retval = -ENOMEM; + goto exit; + } + + fwu = kzalloc(sizeof(*fwu), GFP_KERNEL); + if (!fwu) { + TPD_ERR("%s: Failed to alloc mem for fwu\n", __func__); + retval = -ENOMEM; + goto exit; + } + fwu->image_name = kzalloc(MAX_IMAGE_NAME_LEN, GFP_KERNEL); + if (!fwu->image_name) { + TPD_ERR("%s: Failed to alloc mem for image name\n", + __func__); + retval = -ENOMEM; + goto exit_free_fwu; + } + + fwu->rmi4_data = rmi4_data; + fwu->client = client; + retval = synaptics_rmi4_reg_read(fwu->client, + PDT_PROPS, + pdt_props.data, + sizeof(pdt_props.data)); + if (retval < 0) { + TPD_ERR("%s: Failed to read PDT properties, assuming 0x00\n", + __func__); + } else if (pdt_props.has_bsr) { + TPD_ERR("%s: Reflash for LTS not currently supported\n", + __func__); + retval = -ENODEV; + goto exit_free_mem; + } + retval = fwu_scan_pdt(); + if (retval < 0) + goto exit_free_mem; + + if (!fwu->in_ub_mode) { + retval = fwu_read_f34_queries(); + if (retval < 0) + goto exit_free_mem; + + retval = fwu_get_device_config_id(); + if (retval < 0) { + TPD_ERR("%s: Failed to read device config ID\n", + __func__); + goto exit_free_mem; + } + } + + fwu->force_update = FORCE_UPDATE; + fwu->do_lockdown = DO_LOCKDOWN; + fwu->initialized = true; + + retval = fwu_startup_fw_update_work(fw_image); +#ifdef F51_DISCRETE_FORCE + fwu_read_flash_status(); + if (!fwu->in_bl_mode) { + retval = fwu_f51_force_data_init(); + if (retval < 0) + goto exit_free_mem; + } +#endif + + return retval; + +exit_free_mem: + kfree(fwu->image_name); + +exit_free_fwu: + kfree(fwu); + fwu = NULL; + +exit: + return retval; +} + diff --git a/drivers/input/touchscreen/synaptics_redremote.h b/drivers/input/touchscreen/synaptics_redremote.h new file mode 100644 index 000000000000..57428a319d47 --- /dev/null +++ b/drivers/input/touchscreen/synaptics_redremote.h @@ -0,0 +1,15 @@ +#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 \ No newline at end of file diff --git a/drivers/input/touchscreen/synaptics_s3320_redremote.c b/drivers/input/touchscreen/synaptics_s3320_redremote.c new file mode 100644 index 000000000000..ad4df62c2463 --- /dev/null +++ b/drivers/input/touchscreen/synaptics_s3320_redremote.c @@ -0,0 +1,984 @@ +/* + * Synaptics DSX touchscreen driver + * + * Copyright (C) 2012 Synaptics Incorporated + * + * Copyright (C) 2012 Alexandra Chin + * Copyright (C) 2012 Scott Lin + * + * 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 "synaptics_redremote.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[2]; + struct i2c_msg msg[] = { + { + .addr = i2c_client->addr, + .flags = 0, + .len = 2, + .buf = buf, + } + }; + buf[0] = 0xff; + buf[1] = ((address >> 8) & 0xFF); + + for (retry = 0; retry < 2; retry++) { + if (i2c_transfer(i2c_client->adapter, msg, 1) == 1) { + break; + } + msleep(5); + } + + if (retry == 2) { + return -EIO; + } + + 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[2]; + struct i2c_msg msg[] = { + { + .addr = i2c_client->addr, + .flags = 0, + .len = 2, + .buf = buf, + } + }; + buf[0] = 0xff; + buf[1] = 0x00; + + for (retry = 0; retry < 2; retry++) { + if (i2c_transfer(i2c_client->adapter, msg, 1) == 1) { + break; + } + msleep(5); + } + + if (retry == 2) { + return -EIO; + } + + return 0; +} + + +int remote_rmi4_i2c_read(unsigned short addr, unsigned char *data, unsigned short length) +{ + int retval; + unsigned char retry; + unsigned char buf; + 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 = data, + }, + }; + + buf = addr & 0xff; + + 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(5); + } + + if (retry == 2) { + retval = -EIO; + } + +exit: + 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[length + 1]; + 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, + } + }; + + + 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(5); + } + msleep(10); + if (retry == 2) { + retval = -EIO; + } + +exit: + remote_rmit_put_page(); + + 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; + //printk("synap %s\n",__func__); + 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[count + 1]; + struct rmidev_data *dev_data = filp->private_data; + //printk("synap %s\n",__func__); + 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; + + 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); + + 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[count + 1]; + struct rmidev_data *dev_data = filp->private_data; + printk("synap %s\n",__func__); + + 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; + + if (copy_from_user(tmpbuf, buf, count)) + return -EFAULT; + + 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); + + 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(); + + printk("synap %s\n",__func__); + 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); + printk("synap %s\n",__func__); + + if (!dev_data) + return -EACCES; + + + 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__); + + 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); + + if (!dev_data) + return -EACCES; + + 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__); + + 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) + { + printk("%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) + { + printk("%s:pdata is null\n",__func__); + return -1; + } + if(rmidev) + { + printk("%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); + } else { + retval = alloc_chrdev_region(&dev_no, 1, 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)) { + pr_err("%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"); +*/ + From a9e6a342bb65446a5f28ce347e5fa7882554d562 Mon Sep 17 00:00:00 2001 From: LuK1337 Date: Thu, 7 Nov 2019 20:02:29 +0100 Subject: [PATCH 253/356] oneplus: Import OnePlus specific drivers Change-Id: I49a7392d905e98dfb9ee38a5d95cfe002374dcf8 --- drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/oneplus/Kconfig | 3 + drivers/oneplus/Makefile | 3 + drivers/oneplus/coretech/Kconfig | 35 + drivers/oneplus/coretech/Makefile | 8 + drivers/oneplus/coretech/adj_chain/Makefile | 1 + .../oneplus/coretech/adj_chain/adj_chain.c | 86 + drivers/oneplus/coretech/coretech_helper.c | 22 + drivers/oneplus/coretech/coretech_helper.h | 6 + drivers/oneplus/coretech/houston/Makefile | 1 + drivers/oneplus/coretech/houston/houston.c | 467 ++ drivers/oneplus/coretech/memplus/Makefile | 1 + drivers/oneplus/coretech/memplus/memplus.h | 22 + .../oneplus/coretech/memplus/memplus_core.c | 871 +++ .../oneplus/coretech/memplus/memplus_helper.c | 61 + drivers/oneplus/coretech/smartboost/Makefile | 1 + .../oneplus/coretech/smartboost/core/Makefile | 1 + .../smartboost/core/smartboost_core.c | 763 +++ .../coretech/smartboost/smartboost_helper.c | 38 + drivers/oneplus/coretech/uxcore/Makefile | 1 + drivers/oneplus/coretech/uxcore/core/Kconfig | 0 drivers/oneplus/coretech/uxcore/core/Makefile | 3 + .../coretech/uxcore/core/opchain_core.c | 412 ++ .../coretech/uxcore/core/opchain_core.h | 8 + .../coretech/uxcore/core/opchain_proxy.c | 99 + .../coretech/uxcore/core/opchain_proxy.h | 9 + .../core/opchain_struct_offset_helper.c | 64 + .../core/opchain_struct_offset_helper.h | 68 + .../oneplus/coretech/uxcore/opchain_define.h | 56 + .../oneplus/coretech/uxcore/opchain_helper.c | 152 + .../oneplus/coretech/uxcore/opchain_helper.h | 40 + drivers/oneplus/drivers/Kconfig | 26 + drivers/oneplus/drivers/Makefile | 7 + drivers/oneplus/drivers/boot_mode/Makefile | 1 + drivers/oneplus/drivers/boot_mode/boot_mode.c | 77 + drivers/oneplus/drivers/debugdriver/Makefile | 1 + .../oneplus/drivers/debugdriver/debugdriver.c | 420 ++ .../oneplus/drivers/input/fingerprint/Kconfig | 27 + .../drivers/input/fingerprint/Makefile | 5 + .../fingerprint/fingerprint_detect/Makefile | 1 + .../fingerprint_detect/fingerprint_detect.c | 318 + .../fingerprint_detect/fingerprint_detect.h | 18 + .../drivers/input/fingerprint/fpc/Makefile | 1 + .../input/fingerprint/fpc/fpc1020_tee.c | 559 ++ .../drivers/input/fingerprint/goodix/Makefile | 1 + .../drivers/input/fingerprint/goodix/gf_spi.c | 1101 ++++ .../drivers/input/fingerprint/goodix/gf_spi.h | 185 + .../input/fingerprint/goodix/netlink.c | 100 + .../input/fingerprint/goodix/platform.c | 202 + .../drivers/input/fingerprint/silead/Makefile | 3 + .../input/fingerprint/silead/silead_fp.h | 240 + .../fingerprint/silead/silead_fp_platform.c | 1555 +++++ .../input/fingerprint/silead/silead_fp_qcom.c | 606 ++ .../input/fingerprint/silead/silead_fp_qcom.h | 48 + drivers/oneplus/drivers/oem_debug/Makefile | 1 + .../drivers/oem_debug/oem_force_dump.c | 212 + drivers/oneplus/drivers/oem_trace/Makefile | 1 + drivers/oneplus/drivers/oem_trace/oem_trace.c | 544 ++ drivers/oneplus/drivers/oem_trace/oem_trace.h | 10 + .../oneplus/drivers/param_read_write/Makefile | 1 + .../param_read_write/param_read_write.c | 348 ++ drivers/oneplus/drivers/sysrq/Makefile | 1 + drivers/oneplus/drivers/sysrq/sysrq_x.c | 35 + drivers/oneplus/fs/Kconfig | 2 + drivers/oneplus/fs/Makefile | 2 + drivers/oneplus/fs/exfat/Kconfig | 39 + drivers/oneplus/fs/exfat/LICENSE | 339 ++ drivers/oneplus/fs/exfat/Makefile | 54 + drivers/oneplus/fs/exfat/README.md | 98 + drivers/oneplus/fs/exfat/dkms.conf | 7 + drivers/oneplus/fs/exfat/exfat-km.mk | 11 + drivers/oneplus/fs/exfat/exfat_api.c | 528 ++ drivers/oneplus/fs/exfat/exfat_api.h | 206 + drivers/oneplus/fs/exfat/exfat_bitmap.c | 63 + drivers/oneplus/fs/exfat/exfat_bitmap.h | 55 + drivers/oneplus/fs/exfat/exfat_blkdev.c | 197 + drivers/oneplus/fs/exfat/exfat_blkdev.h | 73 + drivers/oneplus/fs/exfat/exfat_cache.c | 784 +++ drivers/oneplus/fs/exfat/exfat_cache.h | 85 + drivers/oneplus/fs/exfat/exfat_config.h | 69 + drivers/oneplus/fs/exfat/exfat_core.c | 5138 +++++++++++++++++ drivers/oneplus/fs/exfat/exfat_core.h | 671 +++ drivers/oneplus/fs/exfat/exfat_data.c | 77 + drivers/oneplus/fs/exfat/exfat_data.h | 58 + drivers/oneplus/fs/exfat/exfat_nls.c | 448 ++ drivers/oneplus/fs/exfat/exfat_nls.h | 91 + drivers/oneplus/fs/exfat/exfat_oal.c | 196 + drivers/oneplus/fs/exfat/exfat_oal.h | 74 + drivers/oneplus/fs/exfat/exfat_super.c | 2697 +++++++++ drivers/oneplus/fs/exfat/exfat_super.h | 171 + drivers/oneplus/fs/exfat/exfat_upcase.c | 405 ++ drivers/oneplus/fs/exfat/exfat_version.h | 19 + drivers/oneplus/fs/proc/Kconfig | 5 + drivers/oneplus/fs/proc/Makefile | 2 + drivers/oneplus/fs/proc/adj_chain_stat.c | 89 + drivers/oneplus/fs/proc/fg_uid.c | 125 + drivers/oneplus/fs/proc/fg_uid.h | 30 + include/linux/adj_chain.h | 46 + include/linux/oem_force_dump.h | 16 + include/linux/oneplus/boot_mode.h | 16 + include/linux/param_rw.h | 36 + include/oneplus/memplus/memplus_helper.h | 92 + .../oneplus/smartboost/smartboost_helper.h | 81 + 104 files changed, 23155 insertions(+) create mode 100755 drivers/oneplus/Kconfig create mode 100755 drivers/oneplus/Makefile create mode 100644 drivers/oneplus/coretech/Kconfig create mode 100755 drivers/oneplus/coretech/Makefile create mode 100644 drivers/oneplus/coretech/adj_chain/Makefile create mode 100644 drivers/oneplus/coretech/adj_chain/adj_chain.c create mode 100644 drivers/oneplus/coretech/coretech_helper.c create mode 100644 drivers/oneplus/coretech/coretech_helper.h create mode 100644 drivers/oneplus/coretech/houston/Makefile create mode 100644 drivers/oneplus/coretech/houston/houston.c create mode 100644 drivers/oneplus/coretech/memplus/Makefile create mode 100644 drivers/oneplus/coretech/memplus/memplus.h create mode 100644 drivers/oneplus/coretech/memplus/memplus_core.c create mode 100644 drivers/oneplus/coretech/memplus/memplus_helper.c create mode 100644 drivers/oneplus/coretech/smartboost/Makefile create mode 100644 drivers/oneplus/coretech/smartboost/core/Makefile create mode 100644 drivers/oneplus/coretech/smartboost/core/smartboost_core.c create mode 100644 drivers/oneplus/coretech/smartboost/smartboost_helper.c create mode 100755 drivers/oneplus/coretech/uxcore/Makefile create mode 100755 drivers/oneplus/coretech/uxcore/core/Kconfig create mode 100755 drivers/oneplus/coretech/uxcore/core/Makefile create mode 100644 drivers/oneplus/coretech/uxcore/core/opchain_core.c create mode 100755 drivers/oneplus/coretech/uxcore/core/opchain_core.h create mode 100644 drivers/oneplus/coretech/uxcore/core/opchain_proxy.c create mode 100755 drivers/oneplus/coretech/uxcore/core/opchain_proxy.h create mode 100755 drivers/oneplus/coretech/uxcore/core/opchain_struct_offset_helper.c create mode 100755 drivers/oneplus/coretech/uxcore/core/opchain_struct_offset_helper.h create mode 100755 drivers/oneplus/coretech/uxcore/opchain_define.h create mode 100755 drivers/oneplus/coretech/uxcore/opchain_helper.c create mode 100755 drivers/oneplus/coretech/uxcore/opchain_helper.h create mode 100644 drivers/oneplus/drivers/Kconfig create mode 100644 drivers/oneplus/drivers/Makefile create mode 100644 drivers/oneplus/drivers/boot_mode/Makefile create mode 100644 drivers/oneplus/drivers/boot_mode/boot_mode.c create mode 100644 drivers/oneplus/drivers/debugdriver/Makefile create mode 100644 drivers/oneplus/drivers/debugdriver/debugdriver.c create mode 100755 drivers/oneplus/drivers/input/fingerprint/Kconfig create mode 100755 drivers/oneplus/drivers/input/fingerprint/Makefile create mode 100644 drivers/oneplus/drivers/input/fingerprint/fingerprint_detect/Makefile create mode 100755 drivers/oneplus/drivers/input/fingerprint/fingerprint_detect/fingerprint_detect.c create mode 100644 drivers/oneplus/drivers/input/fingerprint/fingerprint_detect/fingerprint_detect.h create mode 100644 drivers/oneplus/drivers/input/fingerprint/fpc/Makefile create mode 100644 drivers/oneplus/drivers/input/fingerprint/fpc/fpc1020_tee.c create mode 100644 drivers/oneplus/drivers/input/fingerprint/goodix/Makefile create mode 100644 drivers/oneplus/drivers/input/fingerprint/goodix/gf_spi.c create mode 100644 drivers/oneplus/drivers/input/fingerprint/goodix/gf_spi.h create mode 100644 drivers/oneplus/drivers/input/fingerprint/goodix/netlink.c create mode 100644 drivers/oneplus/drivers/input/fingerprint/goodix/platform.c create mode 100755 drivers/oneplus/drivers/input/fingerprint/silead/Makefile create mode 100755 drivers/oneplus/drivers/input/fingerprint/silead/silead_fp.h create mode 100755 drivers/oneplus/drivers/input/fingerprint/silead/silead_fp_platform.c create mode 100755 drivers/oneplus/drivers/input/fingerprint/silead/silead_fp_qcom.c create mode 100755 drivers/oneplus/drivers/input/fingerprint/silead/silead_fp_qcom.h create mode 100755 drivers/oneplus/drivers/oem_debug/Makefile create mode 100644 drivers/oneplus/drivers/oem_debug/oem_force_dump.c create mode 100644 drivers/oneplus/drivers/oem_trace/Makefile create mode 100755 drivers/oneplus/drivers/oem_trace/oem_trace.c create mode 100755 drivers/oneplus/drivers/oem_trace/oem_trace.h create mode 100644 drivers/oneplus/drivers/param_read_write/Makefile create mode 100644 drivers/oneplus/drivers/param_read_write/param_read_write.c create mode 100644 drivers/oneplus/drivers/sysrq/Makefile create mode 100755 drivers/oneplus/drivers/sysrq/sysrq_x.c create mode 100644 drivers/oneplus/fs/Kconfig create mode 100644 drivers/oneplus/fs/Makefile create mode 100644 drivers/oneplus/fs/exfat/Kconfig create mode 100644 drivers/oneplus/fs/exfat/LICENSE create mode 100644 drivers/oneplus/fs/exfat/Makefile create mode 100644 drivers/oneplus/fs/exfat/README.md create mode 100644 drivers/oneplus/fs/exfat/dkms.conf create mode 100644 drivers/oneplus/fs/exfat/exfat-km.mk create mode 100644 drivers/oneplus/fs/exfat/exfat_api.c create mode 100644 drivers/oneplus/fs/exfat/exfat_api.h create mode 100644 drivers/oneplus/fs/exfat/exfat_bitmap.c create mode 100644 drivers/oneplus/fs/exfat/exfat_bitmap.h create mode 100644 drivers/oneplus/fs/exfat/exfat_blkdev.c create mode 100644 drivers/oneplus/fs/exfat/exfat_blkdev.h create mode 100644 drivers/oneplus/fs/exfat/exfat_cache.c create mode 100644 drivers/oneplus/fs/exfat/exfat_cache.h create mode 100644 drivers/oneplus/fs/exfat/exfat_config.h create mode 100644 drivers/oneplus/fs/exfat/exfat_core.c create mode 100644 drivers/oneplus/fs/exfat/exfat_core.h create mode 100644 drivers/oneplus/fs/exfat/exfat_data.c create mode 100644 drivers/oneplus/fs/exfat/exfat_data.h create mode 100644 drivers/oneplus/fs/exfat/exfat_nls.c create mode 100644 drivers/oneplus/fs/exfat/exfat_nls.h create mode 100644 drivers/oneplus/fs/exfat/exfat_oal.c create mode 100644 drivers/oneplus/fs/exfat/exfat_oal.h create mode 100644 drivers/oneplus/fs/exfat/exfat_super.c create mode 100644 drivers/oneplus/fs/exfat/exfat_super.h create mode 100644 drivers/oneplus/fs/exfat/exfat_upcase.c create mode 100644 drivers/oneplus/fs/exfat/exfat_version.h create mode 100644 drivers/oneplus/fs/proc/Kconfig create mode 100644 drivers/oneplus/fs/proc/Makefile create mode 100644 drivers/oneplus/fs/proc/adj_chain_stat.c create mode 100644 drivers/oneplus/fs/proc/fg_uid.c create mode 100644 drivers/oneplus/fs/proc/fg_uid.h create mode 100644 include/linux/adj_chain.h create mode 100644 include/linux/oem_force_dump.h create mode 100644 include/linux/oneplus/boot_mode.h create mode 100644 include/linux/param_rw.h create mode 100644 include/oneplus/memplus/memplus_helper.h create mode 100644 include/oneplus/smartboost/smartboost_helper.h diff --git a/drivers/Kconfig b/drivers/Kconfig index e0866eda8bbd..3918ba782a80 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -232,4 +232,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..0670ba8ab248 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/oneplus/Kconfig b/drivers/oneplus/Kconfig new file mode 100755 index 000000000000..6063218df409 --- /dev/null +++ b/drivers/oneplus/Kconfig @@ -0,0 +1,3 @@ +source "drivers/oneplus/coretech/Kconfig" +source "drivers/oneplus/drivers/Kconfig" +source "drivers/oneplus/fs/Kconfig" diff --git a/drivers/oneplus/Makefile b/drivers/oneplus/Makefile new file mode 100755 index 000000000000..1b9a785237be --- /dev/null +++ b/drivers/oneplus/Makefile @@ -0,0 +1,3 @@ +obj-y += coretech/ +obj-y += drivers/ +obj-y += fs/ diff --git a/drivers/oneplus/coretech/Kconfig b/drivers/oneplus/coretech/Kconfig new file mode 100644 index 000000000000..1f61087e021d --- /dev/null +++ b/drivers/oneplus/coretech/Kconfig @@ -0,0 +1,35 @@ +config OPCHAIN + default n + bool "Oneplus CoreTech helper, used for opchain module" + +config DEFRAG_HELPER + default n + bool "Oneplus CoreTech helper, used for defrag module" + +config CRPL_HELPER + default n + bool "Oneplus CoreTech helper, used for crpl module" + +config ADJ_CHAIN + default n + bool "Chain task adj for victim select" + help + To chain task adj for any purpose + +config HOUSTON + default n + bool "houston rocket play your temperature guard" + help + Realtime temperature monitor + +config MEMPLUS + default n + bool "memory+ feature" + help + Memory+ feature + +config SMART_BOOST + bool "support smart boost feature" + default n + help + Smart Boost feature diff --git a/drivers/oneplus/coretech/Makefile b/drivers/oneplus/coretech/Makefile new file mode 100755 index 000000000000..d1c172f25c8f --- /dev/null +++ b/drivers/oneplus/coretech/Makefile @@ -0,0 +1,8 @@ +obj-y += coretech_helper.o +obj-$(CONFIG_ADJ_CHAIN) += adj_chain/ +obj-$(CONFIG_CRPL) += crpl/ +obj-$(CONFIG_DEFRAG_HELPER) += defrag/ +obj-$(CONFIG_HOUSTON) += houston/ +obj-$(CONFIG_MEMPLUS) += memplus/ +obj-$(CONFIG_OPCHAIN) += uxcore/ uxcore/core/ +obj-$(CONFIG_SMART_BOOST) += smartboost/ smartboost/core/ diff --git a/drivers/oneplus/coretech/adj_chain/Makefile b/drivers/oneplus/coretech/adj_chain/Makefile new file mode 100644 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 100644 index 000000000000..2ed5341a071e --- /dev/null +++ b/drivers/oneplus/coretech/adj_chain/adj_chain.c @@ -0,0 +1,86 @@ +#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/coretech_helper.c b/drivers/oneplus/coretech/coretech_helper.c new file mode 100644 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 100644 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/houston/Makefile b/drivers/oneplus/coretech/houston/Makefile new file mode 100644 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 100644 index 000000000000..f3f5cfe35bb2 --- /dev/null +++ b/drivers/oneplus/coretech/houston/houston.c @@ -0,0 +1,467 @@ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define HT_POLLING_MIN_INTERVAL (100) +#define HT_REPORT_PERIOD_MAX (18000) + +/* customize your monitor */ +enum { + HT_CLUS_FREQ_0_MIN, + HT_CLUS_FREQ_0_CUR, + HT_CLUS_FREQ_0_MAX, + HT_CLUS_FREQ_1_MIN, + HT_CLUS_FREQ_1_CUR, + HT_CLUS_FREQ_1_MAX, + HT_BAT_VOLT_NOW, + HT_BAT_CURR_NOW, + HT_CPU_0, + HT_CPU_1, + HT_CPU_2, + HT_CPU_3, + HT_CPU_4, + HT_CPU_5, + HT_CPU_6, + HT_CPU_7, + HT_SEN_0, + HT_SEN_1, + HT_SEN_2, + HT_MONITOR_SIZE +}; + +const char *ht_monitor_case[HT_MONITOR_SIZE] = { + "clus_0_min", + "clus_0_cur", + "clus_0_max", + "clus_1_min", + "clus_1_cur", + "clus_1_max", + "voltage_now", + "current_now", + "cpu0-silver-usr", + "cpu1-silver-usr", + "cpu2-silver-usr", + "cpu3-silver-usr", + "cpu0-gold-usr", + "cpu1-gold-usr", + "cpu2-gold-usr", + "cpu3-gold-usr", + "xo-therm-adc", + "msm-therm-adc", + "quiet-therm-adc" +}; + +static unsigned int ht_all_mask; + +static unsigned int report_period = 600; +module_param_named(period, report_period, uint, 0644); + +static unsigned int filter_mask = 0; +module_param_named(filter_mask, filter_mask, uint, 0644); + +static unsigned int disable_mask = 0; +module_param_named(disable_mask, disable_mask, uint, 0644); + +/* div should not be 0, check before assign */ +static unsigned int report_div[HT_MONITOR_SIZE]; +module_param_array_named(div, report_div, uint, NULL, 0644); + +static unsigned int sample_period = 3000; + +static int ht_sample_period_store(const char *buf, const struct kernel_param *kp) +{ + unsigned int val; + + if (sscanf(buf, "%u\n", &val) <= 0) + return -EINVAL; + + if (val < HT_POLLING_MIN_INTERVAL) { + pr_err("Not allowed to polling too fast\n"); + return -EINVAL; + } + + sample_period = val; + + return 0; +} + +static int ht_sample_period_show(char *buf, const struct kernel_param *kp) +{ + return snprintf(buf, PAGE_SIZE, "%u\n", sample_period); +} + +static struct kernel_param_ops ht_sample_period_ops = { + .set = ht_sample_period_store, + .get = ht_sample_period_show, +}; +module_param_cb(sample_period, &ht_sample_period_ops, NULL, 0644); + +/* NOTE better not use this directly */ +int sidx; +int smps[HT_REPORT_PERIOD_MAX][HT_MONITOR_SIZE]; // samples + +/* TODO set ht_tzd_idx to atomic */ +static int ht_tzd_idx = HT_CPU_0; +static bool __read_mostly keep_alive = false; +static bool __read_mostly ht_reporting = false; + +struct track { + struct thermal_zone_device *tzd; + int slope; + int offset; + bool disabled; +}; + +struct ht_rocket { + struct power_supply *psy; + struct track trk[HT_MONITOR_SIZE]; + struct task_struct *monitor_thread; + struct task_struct *stable_thread; + bool running; +} rocket; + +static inline int ht_next_sample_idx(void) +{ + ++sidx; + sidx %= HT_REPORT_PERIOD_MAX; + return sidx; +} + +static inline void ht_set_all_mask(void) +{ + int i; + for (i = 0; i < HT_MONITOR_SIZE; ++i) + ht_all_mask |= (1 << i); +} + +static inline bool ht_is_all_disabled(unsigned int mask) +{ + return ht_all_mask == mask; +} + +static inline bool ht_is_all_filter(unsigned int 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; +} + +void ht_register_thermal_zone_device(struct thermal_zone_device *tzd) +{ + int idx; + + /* tzd is guaranteed has value */ + pr_info("tzd: %s id: %d\n", tzd->type, tzd->id); + + if (!tzd->type) + return; + + idx = ht_mapping_tags(tzd->type); + + if (idx == HT_MONITOR_SIZE) + return; + + if (ht_tzd_idx < HT_MONITOR_SIZE) { + ++ht_tzd_idx; + rocket.trk[idx].tzd = tzd; + } +} + +void ht_register_power_supply(struct power_supply *psy) +{ + if (!psy) + return; + + pr_info("ht power supply list %s\n", psy->desc->name); + if (!strcmp(psy->desc->name, "battery")) { + rocket.psy = psy; + pr_info("ht power supply registed %s\n", psy->desc->name); + } +} + +#define SILVER_CLUS_IDX 0 +#define GOLDEN_CLUS_IDX 4 +static void ht_collect_resources(void) +{ + int temp, i, idx = ht_next_sample_idx(), ret; + unsigned int d_mask = disable_mask; + struct thermal_zone_device* tzd; + struct cpufreq_policy *pol_0, *pol_1, *pol; + union power_supply_propval prop = {0, }; + + if (ht_is_all_disabled(d_mask)) + return; + + /* temperature part */ + for (i = HT_CPU_0; i < ht_tzd_idx; ++i) { + if (d_mask & (1 << i)) { + smps[idx][i] = 0; + continue; + } + + temp = -1; + tzd = rocket.trk[i].tzd; + if (likely(tzd)) { + ret = thermal_zone_get_temp(tzd, &temp); + if (ret) { + if (ret != -EAGAIN) + pr_debug("failed to read out thermal zone with idx %d\n", i); + temp = -1; + } + } + smps[idx][i] = temp; + } + + /* cpufreq part */ + pol_0 = cpufreq_cpu_get(SILVER_CLUS_IDX); + pol_1 = cpufreq_cpu_get(GOLDEN_CLUS_IDX); + for (i = 0; i < HT_BAT_VOLT_NOW; ++i) { + if (d_mask & (1 << i)) { + smps[idx][i] = 0; + continue; + } + + pol = (i < HT_CLUS_FREQ_1_MIN)? pol_0: pol_1; + if (likely(pol)) { + switch(i) { + case HT_CLUS_FREQ_0_MIN: + case HT_CLUS_FREQ_1_MIN: + smps[idx][i] = pol->min; break; + case HT_CLUS_FREQ_0_CUR: + case HT_CLUS_FREQ_1_CUR: + smps[idx][i] = pol->cur; break; + case HT_CLUS_FREQ_0_MAX: + case HT_CLUS_FREQ_1_MAX: + smps[idx][i] = pol->max; break; + default: + smps[idx][i] = 0; + } + } else { + pr_debug("failed to read cpufreq with idx %d\n", i); + smps[idx][i] = 0; + } + } + if (pol_0) cpufreq_cpu_put(pol_0); + if (pol_1) cpufreq_cpu_put(pol_1); + + /* battery part */ + ret = power_supply_get_property(rocket.psy, POWER_SUPPLY_PROP_VOLTAGE_NOW, &prop); + smps[idx][HT_BAT_VOLT_NOW] = ret >= 0? prop.intval: 0; + ret = power_supply_get_property(rocket.psy, POWER_SUPPLY_PROP_CURRENT_NOW, &prop); + smps[idx][HT_BAT_CURR_NOW] = ret >= 0? prop.intval: 0; +} + +static inline void ht_wake_up(void) +{ + wake_up_process(rocket.monitor_thread); + wake_up_process(rocket.stable_thread); +} + +/* main thread for monitor */ +static int ht_monitor(void *arg) +{ + bool not_stable = false; + while (likely(keep_alive)) { + /* reset for every time evaluation */ + not_stable = false; + + if (!rocket.running) { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule(); + continue; + } + + if (likely(!pm_freezing)) + ht_collect_resources(); + + /* check tsens data to make decision */ + if (not_stable) { + pr_err("wakeup stable_thread\n"); + wake_up_process(rocket.stable_thread); + } + msleep(sample_period); + } + + return 0; +} + +/* try to stable something, maybe temperature or ...? */ +static int ht_stable(void *arg) +{ + while (likely(keep_alive)) { + if (!rocket.running) { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule(); + continue; + } + + /* TODO put some thoughts please */ + + set_current_state(TASK_UNINTERRUPTIBLE); + schedule(); + } + + return 0; +} + +static int ht_registed_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_tzd_idx; ++i) { + tzd = rocket.trk[i].tzd; + 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]); + } + + return offset; +} + +static struct kernel_param_ops ht_registed_ops = { + .get = ht_registed_show, +}; +module_param_cb(ht_registed, &ht_registed_ops, NULL, 0644); + +static int ht_reset_show(char *buf, const struct kernel_param *kp) +{ + memset(smps, 0, sizeof(int) * HT_REPORT_PERIOD_MAX * HT_MONITOR_SIZE); + return snprintf(buf, PAGE_SIZE, "sample data reset\n"); +} + +static struct kernel_param_ops ht_reset_ops = { + .get = ht_reset_show, +}; +module_param_cb(reset, &ht_reset_ops, NULL, 0644); + +static int ht_report_proc_show(struct seq_file *m, void *v) +{ + unsigned int i, cnt = 0, j; + unsigned int f_mask = filter_mask, d_mask = disable_mask; + unsigned int report_cnt = 0; + struct thermal_zone_device* tzd; + + report_cnt = report_period; + + /* cap max */ + if (unlikely(report_cnt > HT_REPORT_PERIOD_MAX)) + report_cnt = HT_REPORT_PERIOD_MAX; + + if (!report_cnt) + return 0; + + ht_reporting = true; + + if (ht_is_all_filter(f_mask) || ht_is_all_disabled(d_mask)) + goto out; + + /* mark */ + for (i = 0; i < ht_tzd_idx; ++i) { + if (f_mask & (1 << i) || d_mask & (1 << i)) + continue; + tzd = rocket.trk[i].tzd; + if (tzd) + seq_printf(m, "%s\t", tzd->type); + else if (i < HT_CPU_0) + seq_printf(m, "%s\t", ht_monitor_case[i]); + } + seq_printf(m, "\n"); + + /* fill gap */ + i = sidx + HT_REPORT_PERIOD_MAX - report_cnt + 1; + + /* value */ + for (; cnt < report_cnt; ++cnt, ++i) { + i %= HT_REPORT_PERIOD_MAX; + + for (j = 0; j < HT_MONITOR_SIZE; ++j) { + if (f_mask & (1 << j) || d_mask & (1 << j)) + continue; + + seq_printf(m, "%d\t", smps[i][j]/ (report_div[j]? report_div[j]: 1)); + } + seq_printf(m, "\n"); + } + +out: + ht_reporting = false; + 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, +}; + +static int ht_init(void) +{ + int i; + + for (i = 0; i < HT_MONITOR_SIZE; ++i) + report_div[i] = (i >= HT_CPU_0)? 100: 1; + + ht_set_all_mask(); + + /* default disabled, enable while you need it */ + disable_mask = ht_all_mask; + + rocket.monitor_thread = kthread_create(ht_monitor, NULL, "ht_rocket"); + if (IS_ERR(rocket.monitor_thread)) { + pr_err("Can't create ht monitor thread\n"); + goto out; + } + + rocket.stable_thread = kthread_create(ht_stable, NULL, "ht_stable"); + if (IS_ERR(rocket.stable_thread)) { + pr_err("Can't create ht stable thread\n"); + wake_up_process(rocket.monitor_thread); + goto out; + } + + keep_alive = true; + rocket.running = true; + ht_wake_up(); + proc_create("ht_report", S_IFREG | 0400, NULL, &ht_report_proc_fops); + + return 0; +out: + return -EINVAL; +} + +pure_initcall(ht_init); +MODULE_AUTHOR("tedlin "); +MODULE_DESCRIPTION("Oneplus Houston"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/oneplus/coretech/memplus/Makefile b/drivers/oneplus/coretech/memplus/Makefile new file mode 100644 index 000000000000..83b47d521522 --- /dev/null +++ b/drivers/oneplus/coretech/memplus/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_MEMPLUS) += memplus_core.o memplus_helper.o diff --git a/drivers/oneplus/coretech/memplus/memplus.h b/drivers/oneplus/coretech/memplus/memplus.h new file mode 100644 index 000000000000..bce7bc299fcd --- /dev/null +++ b/drivers/oneplus/coretech/memplus/memplus.h @@ -0,0 +1,22 @@ +#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, +}; + +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/memplus_core.c b/drivers/oneplus/coretech/memplus/memplus_core.c new file mode 100644 index 000000000000..cef5eba4f9f4 --- /dev/null +++ b/drivers/oneplus/coretech/memplus/memplus_core.c @@ -0,0 +1,871 @@ +#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 "memplus.h" + +#define PF_NO_TAIL(page, enforce) ({ \ + VM_BUG_ON_PGFLAGS(enforce && PageTail(page), page); \ + compound_head(page);}) + +#define RD_SIZE 128 +#define DEBUG_TIME_INFO 0 +#define FEAT_RECLAIM_LIMIT 0 +struct reclaim_stat { + unsigned nr_dirty; + unsigned nr_unqueued_dirty; + unsigned nr_congested; + unsigned nr_writeback; + unsigned nr_immediate; + unsigned nr_activate; + unsigned nr_ref_keep; + unsigned nr_unmap_fail; +}; + +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); + +/* -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); +extern bool enough_swap_size(unsigned long req_size, int swap_bdv); + +bool ctech_current_is_swapind(void) { + 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_FAST) + ret = true; + spin_unlock(&p->lock); +out: + 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 fault_env *fe, pte_t orig_pte); +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 fault_env 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, pte); + 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); + 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); + /* swapin kicked in, don't reclaim within 2 secs */ + task->signal->reclaim_timeout = jiffies + 2*HZ; + + if (task->signal->swapin_should_readahead_m == RECLAIM_QUEUE) { + task->signal->swapin_should_readahead_m = RECLAIM_STANDBY; + } else if (task->signal->swapin_should_readahead_m == RECLAIM_DONE) { + 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; + + 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; + + 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) + reclaimed = swapout_to_disk(&page_list, vma); + else if (reclaim_type == TYPE_FREQUENT) + 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 + + spin_lock(&task->signal->reclaim_state_lock); + + /*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); + + /* if available swap is less than 4MB, quit early */ + if (!enough_swap_size(1024, task->signal->memplus_type)) + 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; + + rp.nr_to_reclaim = INT_MAX; + rp.nr_reclaimed = 0; + rp.nr_scanned = 0; + + /* 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 (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 0; +} + +//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; +} + +void memplus_stop(void) +{ + if (reclaimd_tsk) { + kthread_stop(reclaimd_tsk); + reclaimd_tsk = NULL; + } + if (swapind_tsk) { + kthread_stop(swapind_tsk); + swapind_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; + + 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 (sched_setscheduler_nocheck(swapind_tsk, SCHED_FIFO, ¶m)) { + // pr_warn("%s: failed to set SCHED_FIFO\n", __func__); + //} + } + + 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; + + register_cb_set(&set); + return 0; +} + +unsigned long memplus_scan(void) +{ + struct pagevec pvec; + pgoff_t index = 0, indices[PAGEVEC_SIZE]; + int i, iso_count = 0; + struct address_space *spaces; + struct swap_info_struct *sis, *next; + 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_head, avail_list) { + spaces = &swapper_spaces[sis->type]; + if (!spaces) + continue; + + index = 0; + pagevec_init(&pvec, 0); + while (pagevec_lookup_entries(&pvec, spaces, 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; + + if (sscanf(buf, "%u\n", &val) <= 0) + return -EINVAL; + + if (val == 1) { + freed = memplus_scan(); + pr_info("memory_plus_test_worstcase_store: freed = %ld\n", freed); + } + + return 0; +} + +static struct kernel_param_ops memory_plus_test_worstcase_ops = { + .set = memory_plus_test_worstcase_store, +}; + +module_param_cb(memory_plus_test_worstcase, &memory_plus_test_worstcase_ops, NULL, 0200); + +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_init(memplus_init) diff --git a/drivers/oneplus/coretech/memplus/memplus_helper.c b/drivers/oneplus/coretech/memplus/memplus_helper.c new file mode 100644 index 000000000000..886126e9951a --- /dev/null +++ b/drivers/oneplus/coretech/memplus/memplus_helper.c @@ -0,0 +1,61 @@ +#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 register_cb_set(struct memplus_cb_set *set) +{ + cb_set = *set; +} + +#undef PF_NO_TAIL diff --git a/drivers/oneplus/coretech/smartboost/Makefile b/drivers/oneplus/coretech/smartboost/Makefile new file mode 100644 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 100644 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 100644 index 000000000000..8281a4f6059d --- /dev/null +++ b/drivers/oneplus/coretech/smartboost/core/smartboost_core.c @@ -0,0 +1,763 @@ +#include +#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]; +#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; +}; + +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_page_state(NR_ZONE_UID_LRU); +} + +static int suitable_reclaim_check(struct lruvec *lruvec) +{ + unsigned long active = global_page_state(NR_ZONE_ACTIVE_FILE); + unsigned long inactive = global_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:%lu\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 struct cgroup_subsys_state * +task_get_css_noretry(struct task_struct *task, int subsys_id) +{ + struct cgroup_subsys_state *css; + + rcu_read_lock(); + css = task_css(task, subsys_id); + + if (unlikely(!css_tryget_online(css))) { + rcu_read_unlock(); + return NULL; + } + rcu_read_unlock(); + return css; +} + +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) { + struct cgroup_subsys_state *pos; + struct css_task_iter it; + struct task_struct *tsk; + struct cgroup_subsys_state *parent; + struct cgroup_subsys_state *css; + + css = task_get_css_noretry(task, cpuacct_cgrp_id); + if (css) { + parent = css->parent; + rcu_read_lock(); + css_for_each_child(pos, parent) { + css_task_iter_start(&pos->cgroup->self, &it); + while ((tsk = css_task_iter_next(&it))) + tsk->hot_count = 0; + css_task_iter_end(&it); + } + rcu_read_unlock(); + } + 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_init(smartboost_init) + diff --git a/drivers/oneplus/coretech/smartboost/smartboost_helper.c b/drivers/oneplus/coretech/smartboost/smartboost_helper.c new file mode 100644 index 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/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..e69de29bb2d1 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 100644 index 000000000000..5411ec4f1aa2 --- /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 "../drivers/oneplus/coretech/uxcore/opchain_define.h" +#include "opchain_proxy.h" +#include "opchain_struct_offset_helper.h" +#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 + +static inline bool ctech_is_major_utask(int pid, u32 tag) +{ + return (CHAIN_REP((tag % UX_TOTAL_ENTRIES), 0) == pid); +} + +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) && + !(ctech_is_major_utask(TASK_PID_R(t), tag) && + (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 void 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 (chain_on && !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 (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); + } + */ + } +} + +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 100644 index 000000000000..e5fe88e95b6a --- /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 "../drivers/oneplus/coretech/uxcore/opchain_define.h" +#include "opchain_core.h" +#include "../drivers/oneplus/coretech/uxcore/opchain_helper.h" + +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 = 1; +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_define.h b/drivers/oneplus/coretech/uxcore/opchain_define.h new file mode 100755 index 000000000000..0205b0e99e82 --- /dev/null +++ b/drivers/oneplus/coretech/uxcore/opchain_define.h @@ -0,0 +1,56 @@ +/* + * 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_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); + void (*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/coretech/uxcore/opchain_helper.c b/drivers/oneplus/coretech/uxcore/opchain_helper.c new file mode 100755 index 000000000000..60a581ca0e24 --- /dev/null +++ b/drivers/oneplus/coretech/uxcore/opchain_helper.c @@ -0,0 +1,152 @@ +/* + * 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 "opchain_define.h" +#include "../drivers/oneplus/coretech/uxcore/core/opchain_proxy.h" + +#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); + +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) + uxcore_api.opc_binder_pass_t((void *)t_rq(current), (void *)current, data_size, data, send); +} +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; +} +EXPORT_SYMBOL(opc_exit_module); diff --git a/drivers/oneplus/coretech/uxcore/opchain_helper.h b/drivers/oneplus/coretech/uxcore/opchain_helper.h new file mode 100755 index 000000000000..f31a6d2091dd --- /dev/null +++ b/drivers/oneplus/coretech/uxcore/opchain_helper.h @@ -0,0 +1,40 @@ +#ifndef _LINUX_OPCHAIN_HELPER_H +#define _LINUX_OPCHAIN_HELPER_H +#include "opchain_define.h" + +#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); +extern unsigned int *opc_boost_tl; +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); +#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; } +#endif +#endif diff --git a/drivers/oneplus/drivers/Kconfig b/drivers/oneplus/drivers/Kconfig new file mode 100644 index 000000000000..d9db3bed32c0 --- /dev/null +++ b/drivers/oneplus/drivers/Kconfig @@ -0,0 +1,26 @@ +config OEM_DEBUG_SUPPORT + default y + bool + +config OEM_SYSRQ_X + default y + depends on OEM_DEBUG_SUPPORT + bool "echo x > /proc/sysrq-trigger to get init process stacktrace" + +config OEM_TRACE_SUPPORT + default y + depends on OEM_DEBUG_SUPPORT + bool "OEM debug function, enable it will register the device, which under /dev/otracer." + +config OEM_FORCE_DUMP + default y + bool "OEM force dump function, it will enable goto the force dump" + +config PARAM_READ_WRITE + bool "Param partition read/write support" + default y + help + if you want to read/write the param partition in kernel, + then you must say Y here. + +source "drivers/oneplus/drivers/input/fingerprint/Kconfig" diff --git a/drivers/oneplus/drivers/Makefile b/drivers/oneplus/drivers/Makefile new file mode 100644 index 000000000000..2c75f051edbb --- /dev/null +++ b/drivers/oneplus/drivers/Makefile @@ -0,0 +1,7 @@ +obj-y += boot_mode/ +obj-y += debugdriver/ +obj-y += input/fingerprint/ +obj-y += oem_debug/ +obj-y += oem_trace/ +obj-y += param_read_write/ +obj-y += sysrq/ diff --git a/drivers/oneplus/drivers/boot_mode/Makefile b/drivers/oneplus/drivers/boot_mode/Makefile new file mode 100644 index 000000000000..d4708a023dbe --- /dev/null +++ b/drivers/oneplus/drivers/boot_mode/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_OEM_DEBUG_SUPPORT) += boot_mode.o diff --git a/drivers/oneplus/drivers/boot_mode/boot_mode.c b/drivers/oneplus/drivers/boot_mode/boot_mode.c new file mode 100644 index 000000000000..1c58341e1c6e --- /dev/null +++ b/drivers/oneplus/drivers/boot_mode/boot_mode.c @@ -0,0 +1,77 @@ +#include +#include +#include + +static enum oem_boot_mode boot_mode = MSM_BOOT_MODE__NORMAL; + +char *enum_ftm_mode[] = {"normal", + "fastboot", + "recovery", + "aging", + "ftm_at", + "ftm_rf", + "ftm_wlan", + "ftm_mos", + "charge" +}; + +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_wlan", 8) == 0) + boot_mode = MSM_BOOT_MODE__WLAN; + else if (strncmp(str, "ftm_mos", 7) == 0) + boot_mode = MSM_BOOT_MODE__MOS; + 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); + diff --git a/drivers/oneplus/drivers/debugdriver/Makefile b/drivers/oneplus/drivers/debugdriver/Makefile new file mode 100644 index 000000000000..2d8317eb850c --- /dev/null +++ b/drivers/oneplus/drivers/debugdriver/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_DEBUG_DRIVER) += debugdriver.o diff --git a/drivers/oneplus/drivers/debugdriver/debugdriver.c b/drivers/oneplus/drivers/debugdriver/debugdriver.c new file mode 100644 index 000000000000..d2cb39266f75 --- /dev/null +++ b/drivers/oneplus/drivers/debugdriver/debugdriver.c @@ -0,0 +1,420 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019 op, Inc. + * Author: Siba Prasad + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAXLEN 255 + +static int sys_value; +struct mutex sys_mutex1; +spinlock_t sys_spinlock; +unsigned long global_mutex; +unsigned long global_spinlock; + +dev_t dev; +static struct class *dev_class; +static struct cdev sys_cdev; +struct kobject *kobj_ref; +uint8_t *kernel_buffer; + +static int __init sysdriver_init(void); +static void __exit sysdriver_exit(void); + +static struct task_struct *sys_thread1; +static struct task_struct *sys_thread2; +static struct task_struct *sys_thread3; +static struct task_struct *sys_thread4; + +/*************** Driver Functions **********************/ +static int sysdebug_open(struct inode *inode, struct file *file); +static int sysdebug_release(struct inode *inode, struct file *file); +static ssize_t sysdebug_read(struct file *filp, char __user *buf, + size_t len, loff_t *off); +static ssize_t sysdebug_write(struct file *filp, const char *buf, + size_t len, loff_t *off); + +/*************** Sysfs Functions **********************/ +static ssize_t sysfs_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf); +static ssize_t sysfs_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count); + +static int sys_null(void); +static int sys_stackoverflow(void); +static int sys_bufoverflow(void); +static int sys_free(void); +static int sys_doublefree(void); +static int sys_mutexlock(void); +static int sys_spin(void); + +static int thread_function1(void *data); +static int thread_function2(void *data); +static int thread_function3(void *data); +static int thread_function4(void *data); + +static struct kobj_attribute sysvalue_attr = __ATTR(sys_value, 0660, + sysfs_show, sysfs_store); + +static int thread_function1(void *data) +{ + while (!kthread_should_stop()) { + mutex_lock(&sys_mutex1); + global_mutex++; + pr_info("In Thread Function1 %lu\n", global_mutex); + mutex_unlock(&sys_mutex1); + msleep(1000); + } + do_exit(0); +} + +static int thread_function2(void *data) +{ + while (!kthread_should_stop()) { + mutex_lock(&sys_mutex1); + global_mutex++; + pr_info("In Thread Function2 %lu\n", global_mutex); + mutex_lock(&sys_mutex1); + mutex_unlock(&sys_mutex1); + msleep(1000); + } + do_exit(0); +} + +static int thread_function3(void *data) +{ + while (!kthread_should_stop()) { + spin_lock(&sys_spinlock); + global_spinlock++; + pr_info("In Thread Function3 %lu\n", global_spinlock); + spin_lock(&sys_spinlock); + spin_unlock(&sys_spinlock); + } + do_exit(0); +} + +static int thread_function4(void *data) +{ + while (!kthread_should_stop()) { + spin_lock(&sys_spinlock); + global_spinlock++; + pr_info("In Thread Function4 %lu\n", global_spinlock); + spin_unlock(&sys_spinlock); + } + do_exit(0); +} + +static const struct file_operations fops = { + .owner = THIS_MODULE, + .read = sysdebug_read, + .write = sysdebug_write, + .open = sysdebug_open, + .release = sysdebug_release, +}; + +/* Creata a group of attributes helps to create and destroy them all at once */ +static struct attribute *attrs[] = { + &sysvalue_attr.attr, + NULL, /* need to NULL terminate the list of attributes */ +}; + +/* + * By specifying a name, a subdirectory will be created for the + * attributes with the directory being the name of the attribute group. + */ +static struct attribute_group attr_group = { + .attrs = attrs, +}; + +static ssize_t sysfs_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + pr_info("Sysfs- Read!!!\n"); + return snprintf(buf, MAXLEN, "%d\nChoose BUG:\n" + "1 = Null pointer dereference\n2 = Stack overflow\n" + "3 = Use-after-free\n4 = Double free\n" + "5 = Buffer overflow\n6 = Mutex lock\n" + "7 = Spinlock\n", sys_value); +} + +static ssize_t sysfs_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count) +{ + int ret = 0; + + pr_info("Sysfs- Write!!!\n"); + ret = sscanf(buf, "%d\n", &sys_value); + + if (ret != 1) + return -EINVAL; + + if (sys_value < 0) { + pr_err("Value is not valid...\n"); + return -EINVAL; + } else if (sys_value == 1) { + pr_info("Calling Null pointer error...\n"); + sys_null(); + } else if (sys_value == 2) { + pr_info("Calling Stack Overflow error...\n"); + sys_stackoverflow(); + } else if (sys_value == 3) { + pr_info("Calling Use-after-free error...\n"); + sys_free(); + } else if (sys_value == 4) { + pr_info("Calling Double free error...\n"); + sys_doublefree(); + } else if (sys_value == 5) { + pr_info("Calling Buffer Overflow error...\n"); + sys_bufoverflow(); + } else if (sys_value == 6) { + pr_info("Calling Mutex lock error...\n"); + sys_mutexlock(); + } else if (sys_value == 7) { + pr_info("Calling Spinlock error...\n"); + sys_spin(); + } else { + return count; + } + return count; +} + +static int sys_null(void) +{ + struct inode { + int i_ino; + }; + + struct inode *p = NULL; + + pr_info("Inside NULL function\n"); + p->i_ino = 1; + return 0; +} + +static void fun(int x) +{ + pr_info("Inside Fun_Overflow function\n"); + + if (x == 1) + return; + x = 6; + fun(x); +} + +static int sys_stackoverflow(void) +{ + int x = 5; + + pr_info("Inside Stack Overflow function\n"); + fun(x); + return 0; +} + +static int sys_bufoverflow(void) +{ + char *ptr = kmalloc(100, GFP_KERNEL); + + pr_info("Inside buffer overflow function\n"); + pr_info("slub_debug catches buffer overflow\n"); + memset(ptr, 'x', 300); + kfree(ptr); + return 0; +} + +static int sys_free(void) +{ + char *ptr = kmalloc(100, GFP_KERNEL); + + pr_info("Inside use-after-free function\n"); + kfree(ptr); + pr_info("slub_debug catches use after free\n"); + memset(ptr, 'c', 100); + return 0; +} + +static int sys_doublefree(void) +{ + char *ptr = kmalloc(100, GFP_KERNEL); + + pr_info("Inside double free function\n"); + kfree(ptr); + pr_info("slub_debug catches double free\n"); + kfree(ptr); + return 0; +} + +static int sys_mutexlock(void) +{ + /* Creating Thread 1 */ + sys_thread1 = kthread_run(thread_function1, NULL, "sys Thread1"); + + if (sys_thread1) { + pr_info("Kthread1 Created Successfully...\n"); + } else { + pr_err("Cannot create kthread1\n"); + return 0; + } + + /* Creating Thread 2 */ + sys_thread2 = kthread_run(thread_function2, NULL, "sys Thread2"); + + if (sys_thread2) { + pr_info("Kthread2 Created Successfully...\n"); + } else { + pr_err("Cannot create kthread2\n"); + return 0; + } + return 0; +} + +static int sys_spin(void) +{ + /* Creating Thread 3 */ + sys_thread3 = kthread_run(thread_function3, NULL, "sys Thread3"); + + if (sys_thread3) { + pr_info("Kthread3 Created Successfully...\n"); + } else { + pr_err("Cannot create kthread3\n"); + return 0; + } + + /* Creating Thread 4 */ + sys_thread4 = kthread_run(thread_function4, NULL, "sys Thread4"); + + if (sys_thread4) { + pr_info("Kthread4 Created Successfully...\n"); + } else { + pr_err("Cannot create kthread4\n"); + return 0; + } + return 0; +} + +static int sysdebug_open(struct inode *inode, struct file *file) +{ + pr_info("Device File Opened...!!!\n"); + return 0; +} + +static int sysdebug_release(struct inode *inode, struct file *file) +{ + pr_info("Device File Closed...!!!\n"); + return 0; +} + +static ssize_t sysdebug_read(struct file *filp, char __user *buf, + size_t len, loff_t *off) +{ + pr_info("Read function\n"); + return 0; +} +static ssize_t sysdebug_write(struct file *filp, const char __user *buf, + size_t len, loff_t *off) +{ + pr_info("Write Function\n"); + return len; +} + +static int __init sysdriver_init(void) +{ + /*Allocating Major number*/ + int err = alloc_chrdev_region(&dev, 0, 1, "debugmaj_Dev"); + + if (err < 0) { + pr_err("Cannot allocate major number\n"); + return err; + } + pr_info("Major = %d Minor = %d\n", MAJOR(dev), MINOR(dev)); + + /*Creating cdev structure*/ + cdev_init(&sys_cdev, &fops); + + /*Adding character device to the system*/ + if ((cdev_add(&sys_cdev, dev, 1)) < 0) { + pr_err("Cannot add the device to the system\n"); + goto remove_class; + } + + /*Creating struct class*/ + dev_class = class_create(THIS_MODULE, "debug_class"); + if (dev_class == NULL) { + pr_err("Cannot create the struct class\n"); + goto remove_class; + } + + /*Creating device*/ + if ((device_create(dev_class, NULL, dev, NULL, "debug_device")) + == NULL) { + pr_err("Cannot create the Device 1\n"); + goto remove_device; + } + + /*Creating a directory in /sys/kernel/ */ + kobj_ref = kobject_create_and_add("debug_sysfs", kernel_kobj); + if (!kobj_ref) + return -ENOMEM; + + /*Creating sysfs file for my_value*/ + if (sysfs_create_group(kobj_ref, &attr_group)) { + pr_err("Cannot create sysfs file......\n"); + goto remove_sysfs; + } + + spin_lock_init(&sys_spinlock); + mutex_init(&sys_mutex1); + pr_info("Debug Driver Insert...Done!!!\n"); + return 0; + +remove_sysfs: + kobject_put(kobj_ref); + sysfs_remove_group(kernel_kobj, &attr_group); +remove_device: + class_destroy(dev_class); +remove_class: + unregister_chrdev_region(dev, 1); + cdev_del(&sys_cdev); + return -EINVAL; +} + +void __exit sysdriver_exit(void) +{ + kthread_stop(sys_thread1); + kthread_stop(sys_thread2); + kthread_stop(sys_thread3); + kthread_stop(sys_thread4); + kobject_put(kobj_ref); + sysfs_remove_group(kernel_kobj, &attr_group); + device_destroy(dev_class, dev); + class_destroy(dev_class); + cdev_del(&sys_cdev); + unregister_chrdev_region(dev, 1); + pr_info("Debug Driver Remove...Done!!!\n"); +} + +module_init(sysdriver_init); +module_exit(sysdriver_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Siba Prasad"); +MODULE_DESCRIPTION("Debug driver using sysfs entry"); diff --git a/drivers/oneplus/drivers/input/fingerprint/Kconfig b/drivers/oneplus/drivers/input/fingerprint/Kconfig new file mode 100755 index 000000000000..2c5ebec52b07 --- /dev/null +++ b/drivers/oneplus/drivers/input/fingerprint/Kconfig @@ -0,0 +1,27 @@ +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_FPC + tristate "fpc fingerprint sensor support" + depends on SPI_MASTER + +config FINGERPRINT_GOODIX + tristate "goodix fingerprint sensor support" + depends on SPI_MASTER + +config FINGERPRINT_SILEAD + tristate "silead fingerprint sensor support" + depends on SPI_MASTER +endif diff --git a/drivers/oneplus/drivers/input/fingerprint/Makefile b/drivers/oneplus/drivers/input/fingerprint/Makefile new file mode 100755 index 000000000000..1489636478fb --- /dev/null +++ b/drivers/oneplus/drivers/input/fingerprint/Makefile @@ -0,0 +1,5 @@ +#fingerprint_detect should before fpc1022 +obj-$(CONFIG_FINGERPRINT_DETECT) += fingerprint_detect/ +obj-$(CONFIG_FINGERPRINT_FPC) += fpc/ +obj-$(CONFIG_FINGERPRINT_GOODIX) += goodix/ +obj-$(CONFIG_FINGERPRINT_SILEAD) += silead/ diff --git a/drivers/oneplus/drivers/input/fingerprint/fingerprint_detect/Makefile b/drivers/oneplus/drivers/input/fingerprint/fingerprint_detect/Makefile new file mode 100644 index 000000000000..c9846540e94f --- /dev/null +++ b/drivers/oneplus/drivers/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/drivers/input/fingerprint/fingerprint_detect/fingerprint_detect.c b/drivers/oneplus/drivers/input/fingerprint/fingerprint_detect/fingerprint_detect.c new file mode 100755 index 000000000000..592f14a0bb53 --- /dev/null +++ b/drivers/oneplus/drivers/input/fingerprint/fingerprint_detect/fingerprint_detect.c @@ -0,0 +1,318 @@ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fingerprint_detect.h" +int fp_version; + +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 DEVICE_ATTR(sensor_version, S_IRUSR, sensor_version_get, NULL); + +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_en_init = + pinctrl_lookup_state(fp_dev->fp_pinctrl, "fp_id_init"); + if (IS_ERR_OR_NULL(fp_dev->id_en_init)) { + dev_err(dev, "Cannot get en active pinstate\n"); + ret = PTR_ERR(fp_dev->id_en_init); + goto err; + } + + ret = pinctrl_select_state(fp_dev->fp_pinctrl, + fp_dev->id_en_init); + if (ret) { + dev_err(dev, "can not set %s pins\n", "id_en_init"); + goto err; + } + +err: + fp_dev->fp_pinctrl = NULL; + fp_dev->id_en_init = NULL; + return ret; +} + +int fp_pinctrl_id(struct fingerprint_detect_data *fp_dev, int en) +{ + 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; + } + + if (en == 1) { + fp_dev->id_state_up = + pinctrl_lookup_state(fp_dev->fp_pinctrl, "fp_id_up"); + if (IS_ERR_OR_NULL(fp_dev->id_state_up)) { + dev_err(dev, "Cannot fp_id_up pinstate\n"); + ret = PTR_ERR(fp_dev->id_state_up); + goto err; + } + ret = pinctrl_select_state(fp_dev->fp_pinctrl, + fp_dev->id_state_up); + if (ret) { + dev_err(dev, "can not set %s pins\n", "fp_id_up"); + goto err; + } + } else { + fp_dev->id_state_down = + pinctrl_lookup_state(fp_dev->fp_pinctrl, "fp_id_down"); + if (IS_ERR_OR_NULL(fp_dev->id_state_down)) { + dev_err(dev, "Cannot get fp_id_down pinstate\n"); + ret = PTR_ERR(fp_dev->id_state_down); + goto err; + } + ret = pinctrl_select_state(fp_dev->fp_pinctrl, + fp_dev->id_state_down); + if (ret) { + dev_err(dev, "can not set %s pins\n", "fp_id_down"); + goto err; + } + } + +err: + fp_dev->fp_pinctrl = NULL; + fp_dev->id_state_up = NULL; + fp_dev->id_state_down = NULL; + return ret; +} + +static int fingerprint_detect_probe(struct platform_device *pdev) +{ + int id0 = 0, id1 = 0, id2 = 0; + int rc = 0; + int i; + 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; + } + if (of_property_read_bool(fp_detect->dev->of_node, "oem,enchilada")) + fp_detect->project_version = 0x02; + else if (of_property_read_bool(fp_detect->dev->of_node, "oem,fajta")) + fp_detect->project_version = 0x03; + else + fp_detect->project_version = 0x01; + + if (fp_detect->project_version < 0x03) { + 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); + } + + if (fp_detect->project_version < 0x03) { + 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 = fingerprint_detect_request_named_gpio(fp_detect, + "fp-gpio-id2", &fp_detect->id2_gpio); + if (gpio_is_valid(fp_detect->id2_gpio)) { + dev_err(dev, "%s: gpio_is_valid(fp_detect->id2_gpio=%d)\n", + __func__, fp_detect->id2_gpio); + } + } + rc = sysfs_create_group(&dev->kobj, &attribute_group); + if (rc) { + dev_err(dev, "could not create sysfs\n"); + goto exit; + } + + /** + * ID0(GPIO91) ID1(GPIO92) ID1(GPIO95) + * fpc1245 + * O-film 1 1 1 + * Primax 1 0 0 + * truly 0 0 1 + * + + * goodix 1 1 0 + * Primax 0 0 0 + * truly 0 1 1 + *fingerchip/ + * qtech 0 1 0 + * Goodix 1 0 1 + */ + + for (i = 1; i < 4; i++) { + usleep_range(5000, 10000); + rc = fp_pinctrl_id(fp_detect, i%2); + if (rc) + goto exit; + id0 = gpio_get_value(fp_detect->id0_gpio); + if (fp_detect->project_version < 0x03) { + id1 = gpio_get_value(fp_detect->id1_gpio); + id2 = gpio_get_value(fp_detect->id2_gpio); + } + pr_info("%s: %d%d%d\n", __func__, id0, id1, id2); + } + + if (fp_detect->project_version < 0x03) { + if (id0 && id1 && id2) { + push_component_info(FINGERPRINTS, + "fpc1228", "FPC"); + fp_detect->sensor_version = 0x01; + } else if (id0 && !id1 && !id2) { + push_component_info(FINGERPRINTS, + "fpc1245", "FPC(Primax)"); + fp_detect->sensor_version = 0x01; + } else if (!id0 && !id1 && id2) { + push_component_info(FINGERPRINTS, "gf5228", "goodix"); + fp_detect->sensor_version = 0x03; + } else if (id0 && id1 && !id2) { + if (fp_detect->project_version == 0x02) { + push_component_info(FINGERPRINTS, + "goodix5228", "goodix"); + fp_detect->sensor_version = 0x03; + } else { + push_component_info(FINGERPRINTS, + "goodix5228", "goodix"); + fp_detect->sensor_version = 0x03; + } + } else if (!id0 && !id1 && !id2) { + push_component_info(FINGERPRINTS, + "fpc1263", "FPC(Primax)"); + fp_detect->sensor_version = 0x02; + } else if (!id0 && id1 && id2) { + if (fp_detect->project_version == 0x02) { + push_component_info(FINGERPRINTS, + "gfp5288", "Goodix"); + fp_detect->sensor_version = 0x03; + } else { + push_component_info(FINGERPRINTS, + "fpc1263", "FPC(truly)"); + fp_detect->sensor_version = 0x02; + } + } else if (!id0 && id1 && !id2) { + push_component_info(FINGERPRINTS, + "fpc1263", "FPC(f/p)"); + fp_detect->sensor_version = 0x02; + } else if (id0 && !id1 && id2) { + push_component_info(FINGERPRINTS, "gfp5288", "Goodix"); + fp_detect->sensor_version = 0x03; + } else { + push_component_info(FINGERPRINTS, "goodix", "goodix"); + } + } else { + if (id0) { + push_component_info(FINGERPRINTS, + "goodix9508", "goodix"); + fp_detect->sensor_version = 0x04; + } else { + push_component_info(FINGERPRINTS, + "sileadgsl7000", "silead"); + fp_detect->sensor_version = 0x05; + } + } + fp_version = fp_detect->sensor_version; + dev_info(dev, "%s: ok\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/drivers/input/fingerprint/fingerprint_detect/fingerprint_detect.h b/drivers/oneplus/drivers/input/fingerprint/fingerprint_detect/fingerprint_detect.h new file mode 100644 index 000000000000..2775e09a7d12 --- /dev/null +++ b/drivers/oneplus/drivers/input/fingerprint/fingerprint_detect/fingerprint_detect.h @@ -0,0 +1,18 @@ +#ifndef __FINGERPRINT_DETETC_H_ +#define __FINGERPRINT_DETETC_H_ + +struct fingerprint_detect_data { + struct device *dev; + int id0_gpio; + int id1_gpio; + int id2_gpio; + struct pinctrl *fp_pinctrl; + struct pinctrl_state *id_en_init; + struct pinctrl_state *id_state_up; + struct pinctrl_state *id_state_down; + int sensor_version; + int project_version; +}; +extern int fp_version; +#endif + diff --git a/drivers/oneplus/drivers/input/fingerprint/fpc/Makefile b/drivers/oneplus/drivers/input/fingerprint/fpc/Makefile new file mode 100644 index 000000000000..43c12d18eb3e --- /dev/null +++ b/drivers/oneplus/drivers/input/fingerprint/fpc/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_FINGERPRINT_FPC) += fpc1020_tee.o diff --git a/drivers/oneplus/drivers/input/fingerprint/fpc/fpc1020_tee.c b/drivers/oneplus/drivers/input/fingerprint/fpc/fpc1020_tee.c new file mode 100644 index 000000000000..de61f1ba141d --- /dev/null +++ b/drivers/oneplus/drivers/input/fingerprint/fpc/fpc1020_tee.c @@ -0,0 +1,559 @@ +/* + * FPC1020 Fingerprint sensor device driver + * + * This driver will control the platform resources that the FPC fingerprint + * sensor needs to operate. The major things are probing the sensor to check + * that it is actually connected and let the Kernel know this and with that also + * enabling and disabling of regulators, controlling GPIOs such as sensor reset + * line, sensor IRQ line. + * + * The driver will expose most of its available functionality in sysfs which + * enables dynamic control of these features from eg. a user space process. + * + * The sensor's IRQ events will be pushed to Kernel's event handling system and + * are exposed in the drivers event node. + * + * This driver will NOT send any commands to the sensor it only controls the + * electrical parts. + * + * + * Copyright (c) 2015 Fingerprint Cards AB + * + * 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 "../fingerprint_detect/fingerprint_detect.h" + +#define FPC_TTW_HOLD_TIME 1000 + +#define RESET_LOW_SLEEP_MIN_US 5000 +#define RESET_LOW_SLEEP_MAX_US (RESET_LOW_SLEEP_MIN_US + 100) +#define RESET_HIGH_SLEEP1_MIN_US 100 +#define RESET_HIGH_SLEEP1_MAX_US (RESET_HIGH_SLEEP1_MIN_US + 100) +#define RESET_HIGH_SLEEP2_MIN_US 5000 +#define RESET_HIGH_SLEEP2_MAX_US (RESET_HIGH_SLEEP2_MIN_US + 100) +#define PWR_ON_SLEEP_MIN_US 100 +#define PWR_ON_SLEEP_MAX_US (PWR_ON_SLEEP_MIN_US + 900) + +#define NUM_PARAMS_REG_ENABLE_SET 2 + +static const char * const pctl_names[] = { + "fp_reset_low", + "fp_reset_high", + //"fpc1020_irq_active", +}; + +struct vreg_config { + char *name; + unsigned long vmin; + unsigned long vmax; + int ua_load; +}; + +static const struct vreg_config const vreg_conf[] = { + { "vdd_ana", 1800000UL, 1800000UL, 6000, }, + { "vcc_spi", 1800000UL, 1800000UL, 10, }, + { "vdd_io", 1800000UL, 1800000UL, 6000, }, +}; + +struct fpc1020_data { + struct device *dev; + + struct pinctrl *fingerprint_pinctrl; + struct pinctrl_state *pinctrl_state[ARRAY_SIZE(pctl_names)]; + struct regulator *vreg[ARRAY_SIZE(vreg_conf)]; + + struct wakeup_source ttw_wl; + int irq_gpio; + int rst_gpio; + struct mutex lock; /* To set/get exported values in sysfs */ + bool prepared; + atomic_t wakeup_enabled; /* Used both in ISR and non-ISR */ + struct input_dev *input_dev; +}; + +/** + * sysfs node for controlling clocks. + * + * This is disabled in platform variant of this driver but kept for + * backwards compatibility. Only prints a debug print that it is + * disabled. + */ +static ssize_t clk_enable_set(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + dev_dbg(dev, + "clk_enable sysfs node not enabled in platform driver\n"); + + return count; +} +static DEVICE_ATTR(clk_enable, S_IWUSR, NULL, clk_enable_set); + +/** + * Will try to select the set of pins (GPIOS) defined in a pin control node of + * the device tree named @p name. + * + * The node can contain several eg. GPIOs that is controlled when selecting it. + * The node may activate or deactivate the pins it contains, the action is + * defined in the device tree node itself and not here. The states used + * internally is fetched at probe time. + * + * @see pctl_names + * @see fpc1020_probe + */ +static int select_pin_ctl(struct fpc1020_data *fpc1020, const char *name) +{ + size_t i; + int rc; + struct device *dev = fpc1020->dev; + + for (i = 0; i < ARRAY_SIZE(fpc1020->pinctrl_state); i++) { + const char *n = pctl_names[i]; + + if (!strncmp(n, name, strlen(n))) { + rc = pinctrl_select_state(fpc1020->fingerprint_pinctrl, + fpc1020->pinctrl_state[i]); + if (rc) + dev_err(dev, "cannot select '%s'\n", name); + else + dev_dbg(dev, "Selected '%s'\n", name); + goto exit; + } + } + + rc = -EINVAL; + dev_err(dev, "%s:'%s' not found\n", __func__, name); + +exit: + return rc; +} + +static ssize_t pinctl_set(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct fpc1020_data *fpc1020 = dev_get_drvdata(dev); + int rc; + + mutex_lock(&fpc1020->lock); + rc = select_pin_ctl(fpc1020, buf); + mutex_unlock(&fpc1020->lock); + + return rc ? rc : count; +} +static DEVICE_ATTR(pinctl_set, S_IWUSR, NULL, pinctl_set); + +static int hw_reset(struct fpc1020_data *fpc1020) +{ + int irq_gpio; + struct device *dev = fpc1020->dev; + int rc = select_pin_ctl(fpc1020, "fp_reset_high"); + + if (rc) + goto exit; + usleep_range(RESET_HIGH_SLEEP1_MIN_US, RESET_HIGH_SLEEP1_MAX_US); + + rc = select_pin_ctl(fpc1020, "fp_reset_low"); + if (rc) + goto exit; + usleep_range(RESET_LOW_SLEEP_MIN_US, RESET_LOW_SLEEP_MAX_US); + + rc = select_pin_ctl(fpc1020, "fp_reset_high"); + if (rc) + goto exit; + usleep_range(RESET_HIGH_SLEEP2_MIN_US, RESET_HIGH_SLEEP2_MAX_US); + + irq_gpio = gpio_get_value(fpc1020->irq_gpio); + dev_info(dev, "IRQ after reset %d\n", irq_gpio); + +exit: + return rc; +} + +static ssize_t hw_reset_set(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int rc; + struct fpc1020_data *fpc1020 = dev_get_drvdata(dev); + + if (!strncmp(buf, "reset", strlen("reset"))) { + mutex_lock(&fpc1020->lock); + rc = hw_reset(fpc1020); + mutex_unlock(&fpc1020->lock); + } else { + return -EINVAL; + } + + return rc ? rc : count; +} +static DEVICE_ATTR(hw_reset, S_IWUSR, NULL, hw_reset_set); + +/** + * sysfs node for controlling whether the driver is allowed + * to wake up the platform on interrupt. + */ +static ssize_t wakeup_enable_set(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct fpc1020_data *fpc1020 = dev_get_drvdata(dev); + ssize_t ret = count; + + mutex_lock(&fpc1020->lock); + if (!strncmp(buf, "enable", strlen("enable"))) + atomic_set(&fpc1020->wakeup_enabled, 1); + else if (!strncmp(buf, "disable", strlen("disable"))) + atomic_set(&fpc1020->wakeup_enabled, 0); + else + ret = -EINVAL; + mutex_unlock(&fpc1020->lock); + + return ret; +} +static DEVICE_ATTR(wakeup_enable, S_IWUSR, NULL, wakeup_enable_set); + +/** + * sysf node to check the interrupt status of the sensor, the interrupt + * handler should perform sysf_notify to allow userland to poll the node. + */ +static ssize_t irq_get(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct fpc1020_data *fpc1020 = dev_get_drvdata(dev); + int irq = gpio_get_value(fpc1020->irq_gpio); + + return scnprintf(buf, PAGE_SIZE, "%i\n", irq); +} + +/** + * writing to the irq node will just drop a printk message + * and return success, used for latency measurement. + */ +static ssize_t irq_ack(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fpc1020_data *fpc1020 = dev_get_drvdata(dev); + + dev_dbg(fpc1020->dev, "%s\n", __func__); + + return count; +} +static DEVICE_ATTR(irq, S_IRUSR | S_IWUSR, irq_get, irq_ack); + + +static ssize_t report_key_set(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct input_event *ev = (struct input_event *)buf; + struct fpc1020_data *fpc1020 = dev_get_drvdata(dev); + + input_event(fpc1020->input_dev, ev->type, ev->code, ev->value); + return count; +} +static DEVICE_ATTR(report_key, S_IWUSR, NULL, report_key_set); + + +static struct attribute *attributes[] = { + &dev_attr_pinctl_set.attr, + &dev_attr_hw_reset.attr, + &dev_attr_wakeup_enable.attr, + &dev_attr_clk_enable.attr, + &dev_attr_irq.attr, + &dev_attr_report_key.attr, + NULL +}; + +static const struct attribute_group attribute_group = { + .attrs = attributes, +}; + +int fpc1020_input_init(struct fpc1020_data *fpc1020) +{ + int error = 0; + + + dev_dbg(fpc1020->dev, "%s\n", __func__); + + fpc1020->input_dev = input_allocate_device(); + + if (!fpc1020->input_dev) { + dev_err(fpc1020->dev, "Input_allocate_device failed.\n"); + error = -ENOMEM; + } + + if (!error) { + fpc1020->input_dev->name = "fpc1020"; + + /* Set event bits according to what events we are generating */ + set_bit(EV_KEY, fpc1020->input_dev->evbit); + set_bit(EV_SYN, fpc1020->input_dev->evbit); + set_bit(EV_ABS, fpc1020->input_dev->evbit); + + set_bit(KEY_POWER, fpc1020->input_dev->keybit); + set_bit(KEY_F2, fpc1020->input_dev->keybit); + set_bit(KEY_HOME, fpc1020->input_dev->keybit); + /* + set_bit(BTN_A, fpc1020->input_dev->keybit); + set_bit(BTN_C, fpc1020->input_dev->keybit); + */ + set_bit(BTN_B, fpc1020->input_dev->keybit); + set_bit(ABS_Z, fpc1020->input_dev->keybit); + set_bit(KEY_UP, fpc1020->input_dev->keybit); + set_bit(KEY_DOWN, fpc1020->input_dev->keybit); + /* + set_bit(KEY_LEFT, fpc1020->input_dev->keybit); + set_bit(KEY_RIGHT, fpc1020->input_dev->keybit); + */ + + /* Register the input device */ + error = input_register_device(fpc1020->input_dev); + + + if (error) { + dev_err(fpc1020->dev, "Input_register_device failed.\n"); + input_free_device(fpc1020->input_dev); + fpc1020->input_dev = NULL; + } + } + + return error; +} + + +static irqreturn_t fpc1020_irq_handler(int irq, void *handle) +{ + struct fpc1020_data *fpc1020 = handle; + + dev_dbg(fpc1020->dev, "%s\n", __func__); + + if (atomic_read(&fpc1020->wakeup_enabled)) { + __pm_wakeup_event(&fpc1020->ttw_wl, FPC_TTW_HOLD_TIME); + } + + sysfs_notify(&fpc1020->dev->kobj, NULL, dev_attr_irq.attr.name); + + return IRQ_HANDLED; +} + +static int fpc1020_request_named_gpio(struct fpc1020_data *fpc1020, + const char *label, int *gpio) +{ + struct device *dev = fpc1020->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); + 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_dbg(dev, "%s %d\n", label, *gpio); + + return 0; +} + +static int fpc1020_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + int rc = 0; + size_t i; + int irqf; + struct device_node *np; + struct fpc1020_data *fpc1020; + + pr_info("%s: fp version %x\n", __func__, fp_version); + if ((fp_version != 0x01) && (fp_version != 0x02)) + return 0; + + np = dev->of_node; + fpc1020 = devm_kzalloc(dev, sizeof(*fpc1020), + GFP_KERNEL); + + if (!fpc1020) { + dev_err(dev, + "failed to allocate memory for struct fpc1020_data\n"); + rc = -ENOMEM; + goto exit; + } + + fpc1020->dev = dev; + platform_set_drvdata(pdev, fpc1020); + + if (!np) { + dev_err(dev, "no of node found\n"); + rc = -EINVAL; + goto exit; + } + + rc = fpc1020_request_named_gpio(fpc1020, "fpc,irq-gpio", + &fpc1020->irq_gpio); + if (rc) + goto exit; + rc = fpc1020_request_named_gpio(fpc1020, "fpc,reset-gpio", + &fpc1020->rst_gpio); + if (rc) + goto exit; + + fpc1020->fingerprint_pinctrl = devm_pinctrl_get(dev); + if (IS_ERR(fpc1020->fingerprint_pinctrl)) { + if (PTR_ERR(fpc1020->fingerprint_pinctrl) == -EPROBE_DEFER) { + dev_info(dev, "pinctrl not ready\n"); + rc = -EPROBE_DEFER; + goto exit; + } + dev_err(dev, "Target does not use pinctrl\n"); + fpc1020->fingerprint_pinctrl = NULL; + rc = -EINVAL; + goto exit; + } + + for (i = 0; i < ARRAY_SIZE(fpc1020->pinctrl_state); i++) { + const char *n = pctl_names[i]; + struct pinctrl_state *state = + pinctrl_lookup_state(fpc1020->fingerprint_pinctrl, n); + if (IS_ERR(state)) { + dev_err(dev, "cannot find '%s'\n", n); + rc = -EINVAL; + goto exit; + } + dev_info(dev, "found pin control %s\n", n); + fpc1020->pinctrl_state[i] = state; + } + + rc = select_pin_ctl(fpc1020, "fp_reset_low"); + if (rc) + goto exit; + + //rc = select_pin_ctl(fpc1020, "fpc1020_irq_active"); + //if (rc) + // goto exit; + + rc = gpio_direction_input(fpc1020->irq_gpio); + + if (rc) { + dev_err(fpc1020->dev, + "gpio_direction_input (irq) failed.\n"); + goto exit; + } + + + atomic_set(&fpc1020->wakeup_enabled, 0); + + irqf = IRQF_TRIGGER_RISING | IRQF_ONESHOT; + if (of_property_read_bool(dev->of_node, "fpc,enable-wakeup")) { + irqf |= IRQF_NO_SUSPEND; + device_init_wakeup(dev, 1); + } + + mutex_init(&fpc1020->lock); + rc = devm_request_threaded_irq(dev, gpio_to_irq(fpc1020->irq_gpio), + NULL, fpc1020_irq_handler, irqf, + dev_name(dev), fpc1020); + if (rc) { + dev_err(dev, "could not request irq %d\n", + gpio_to_irq(fpc1020->irq_gpio)); + goto exit; + } + + dev_dbg(dev, "requested irq %d\n", gpio_to_irq(fpc1020->irq_gpio)); + + /* Request that the interrupt should be wakeable */ + enable_irq_wake(gpio_to_irq(fpc1020->irq_gpio)); + + wakeup_source_init(&fpc1020->ttw_wl, "fpc_ttw_wl"); + + rc = fpc1020_input_init(fpc1020); + if (rc){ + dev_err(dev, "could not init fpc1020 input device\n"); + goto exit; + } + + rc = sysfs_create_group(&dev->kobj, &attribute_group); + if (rc) { + dev_err(dev, "could not create sysfs\n"); + goto exit; + } + + rc = hw_reset(fpc1020); + + dev_info(dev, "%s: ok\n", __func__); + +exit: + return rc; +} + +static int fpc1020_remove(struct platform_device *pdev) +{ + struct fpc1020_data *fpc1020 = platform_get_drvdata(pdev); + + sysfs_remove_group(&pdev->dev.kobj, &attribute_group); + mutex_destroy(&fpc1020->lock); + wakeup_source_trash(&fpc1020->ttw_wl); + dev_info(&pdev->dev, "%s\n", __func__); + + return 0; +} + +static struct of_device_id fpc1020_of_match[] = { + { .compatible = "fpc,fpc1020", }, + {} +}; +MODULE_DEVICE_TABLE(of, fpc1020_of_match); + +static struct platform_driver fpc1020_driver = { + .driver = { + .name = "fpc1020", + .owner = THIS_MODULE, + .of_match_table = fpc1020_of_match, + }, + .probe = fpc1020_probe, + .remove = fpc1020_remove, +}; + +static int __init fpc1020_init(void) +{ + int rc = platform_driver_register(&fpc1020_driver); + + if (!rc) + pr_info("%s OK\n", __func__); + else + pr_err("%s %d\n", __func__, rc); + + return rc; +} + +static void __exit fpc1020_exit(void) +{ + pr_info("%s\n", __func__); + platform_driver_unregister(&fpc1020_driver); +} + +module_init(fpc1020_init); +module_exit(fpc1020_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Aleksej Makarov"); +MODULE_AUTHOR("Henrik Tillman "); +MODULE_DESCRIPTION("FPC1020 Fingerprint sensor device driver."); diff --git a/drivers/oneplus/drivers/input/fingerprint/goodix/Makefile b/drivers/oneplus/drivers/input/fingerprint/goodix/Makefile new file mode 100644 index 000000000000..9faa4a643604 --- /dev/null +++ b/drivers/oneplus/drivers/input/fingerprint/goodix/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_FINGERPRINT_GOODIX) += gf_spi.o platform.o netlink.o diff --git a/drivers/oneplus/drivers/input/fingerprint/goodix/gf_spi.c b/drivers/oneplus/drivers/input/fingerprint/goodix/gf_spi.c new file mode 100644 index 000000000000..fcf8bc175649 --- /dev/null +++ b/drivers/oneplus/drivers/input/fingerprint/goodix/gf_spi.c @@ -0,0 +1,1101 @@ +/* + * 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 "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; + +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, +}; + +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_info("[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 msm_drm_notifier *evdata = data; + unsigned int blank; + char msg = 0; + + if (val != MSM_DRM_EARLY_EVENT_BLANK && + val != MSM_DRM_ONSCREENFINGERPRINT_EVENT) + return 0; + + if (evdata->id != MSM_DRM_PRIMARY_DISPLAY) + return 0; + + pr_info("[info] %s go to the msm_drm_notifier_callback value = %d\n", + __func__, (int)val); + blank = *(int *)(evdata->data); + if (val == MSM_DRM_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 == + MSM_DRM_EARLY_EVENT_BLANK && gf_dev) { + blank = *(int *)(evdata->data); + switch (blank) { + case MSM_DRM_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 + } + gf_dev->screen_state = 0; + sysfs_notify(&gf_dev->spi->dev.kobj, + NULL, dev_attr_screen_state.attr.name); + break; + case MSM_DRM_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 + } + 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->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 + */ + wakeup_source_init(&fp_wakelock, "fp_wakelock"); + status = irq_setup(gf_dev); + if (status) + goto err_irq; + + status = gf_pinctrl_init(gf_dev); + if (status) + goto err_irq; + if (get_boot_mode() != MSM_BOOT_MODE__FACTORY) { + 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 = 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; + } + } + 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); +#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_trash(&fp_wakelock); + +#if defined(CONFIG_FB) + fb_unregister_client(&gf_dev->notifier); +#elif defined(CONFIG_MSM_RDM_NOTIFY) + if (msm_drm_unregister_client(&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)) + 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; +} +module_init(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/drivers/input/fingerprint/goodix/gf_spi.h b/drivers/oneplus/drivers/input/fingerprint/goodix/gf_spi.h new file mode 100644 index 000000000000..4b0d762a5f38 --- /dev/null +++ b/drivers/oneplus/drivers/input/fingerprint/goodix/gf_spi.h @@ -0,0 +1,185 @@ +/* + * 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 +}; + +#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_3v2; + 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); +int netlink_init(void); +void netlink_exit(void); +extern int gf_opticalfp_irq_handler(int event); +#endif /*__GF_SPI_H*/ diff --git a/drivers/oneplus/drivers/input/fingerprint/goodix/netlink.c b/drivers/oneplus/drivers/input/fingerprint/goodix/netlink.c new file mode 100644 index 000000000000..112536dfce09 --- /dev/null +++ b/drivers/oneplus/drivers/input/fingerprint/goodix/netlink.c @@ -0,0 +1,100 @@ +/* + * 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 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/drivers/input/fingerprint/goodix/platform.c b/drivers/oneplus/drivers/input/fingerprint/goodix/platform.c new file mode 100644 index 000000000000..9992fc89c42e --- /dev/null +++ b/drivers/oneplus/drivers/input/fingerprint/goodix/platform.c @@ -0,0 +1,202 @@ +/* + * platform indepent driver interface + * + * Coypritht (c) 2017 Goodix + */ +#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 + +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); + +/***********power regulator_get****************/ + gf_dev->vdd_3v2 = regulator_get(dev, "vdd-3v2"); + if (IS_ERR(gf_dev->vdd_3v2)) { + rc = PTR_ERR(gf_dev->vdd_3v2); + pr_err("Regulator get failed vdd rc=%d\n", rc); + } + + + rc = of_property_read_u32_array(np, "vdd-voltage", voltage_supply, 2); + if (rc < 0) + pr_err("%s: Failed to get regulator vdd voltage\n", __func__); + + gf_dev->regulator_vdd_vmin = voltage_supply[0]; + gf_dev->regulator_vdd_vmax = voltage_supply[1]; + + rc = regulator_set_voltage(gf_dev->vdd_3v2, + gf_dev->regulator_vdd_vmin, gf_dev->regulator_vdd_vmax); + if (rc < 0) + pr_err("%s:00Failed to set regulator voltage vdd\n", __func__); + + + rc = of_property_read_u32(np, "vdd-current", + ¤t_supply); + if (rc < 0) + pr_err("%s: Failed to get regulator vdd current\n", __func__); + + gf_dev->regulator_vdd_current = current_supply; + + rc = regulator_set_load(gf_dev->vdd_3v2, + gf_dev->regulator_vdd_current); + if (rc < 0) + pr_err("%s: Failed to set regulator current vdd\n", __func__); + + + rc = regulator_enable(gf_dev->vdd_3v2); + if (rc) + pr_err("Regulator vdd enable failed rc=%d\n", rc); + + if (get_boot_mode() == MSM_BOOT_MODE__FACTORY) + { + rc = regulator_disable(gf_dev->vdd_3v2); + if (rc) + pr_err("Regulator vdd disable failed rc=%d\n", rc); + } + + return rc; + +err_irq: + devm_gpio_free(dev, gf_dev->reset_gpio); +err_reset: + 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; + + pr_info("---- power on ok ----\n"); + + return rc; +} + +int gf_power_off(struct gf_dev* gf_dev) +{ + int rc = 0; + + 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/drivers/input/fingerprint/silead/Makefile b/drivers/oneplus/drivers/input/fingerprint/silead/Makefile new file mode 100755 index 000000000000..326ea620a159 --- /dev/null +++ b/drivers/oneplus/drivers/input/fingerprint/silead/Makefile @@ -0,0 +1,3 @@ +ccflags-$(CONFIG_FINGERPRINT_SILEAD) += -DBSP_SIL_PLAT_QCOM +ccflags-$(CONFIG_FINGERPRINT_SILEAD) += -DBSP_SIL_POWER_SUPPLY_REGULATOR +obj-$(CONFIG_FINGERPRINT_SILEAD) += silead_fp_platform.o \ No newline at end of file diff --git a/drivers/oneplus/drivers/input/fingerprint/silead/silead_fp.h b/drivers/oneplus/drivers/input/fingerprint/silead/silead_fp.h new file mode 100755 index 000000000000..16b86b8fed89 --- /dev/null +++ b/drivers/oneplus/drivers/input/fingerprint/silead/silead_fp.h @@ -0,0 +1,240 @@ +/* + * @file silead_fp.h + * @brief Contains silead_fp device head file. + * + * + * Copyright 2016-2018 Slead Inc. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + * + * ------------------- Revision History ------------------------------ + * + * Bill Yu 2018/5/2 0.1.0 Init version + * Bill Yu 2018/5/28 0.1.1 Disable netlink if netlink id = 0 + * Bill Yu 2018/6/1 0.1.2 Support wakelock + * Bill Yu 2018/6/5 0.1.3 Support chip enter power down + * Bill Yu 2018/6/7 0.1.4 Support create proc node + * + */ + +#ifndef __SILEAD_FP_H__ +#define __SILEAD_FP_H__ + +#ifndef _LINUX_WAKELOCK_H +enum { + WAKE_LOCK_SUSPEND, /* Prevent suspend */ + WAKE_LOCK_TYPE_COUNT +}; + +struct wake_lock { + struct wakeup_source ws; +}; + +static inline void wake_lock_init(struct wake_lock *lock, int type, + const char *name) +{ + wakeup_source_init(&lock->ws, name); +} + +static inline void wake_lock_destroy(struct wake_lock *lock) +{ + wakeup_source_trash(&lock->ws); +} + +static inline void wake_lock(struct wake_lock *lock) +{ + __pm_stay_awake(&lock->ws); +} + +static inline void wake_lock_timeout(struct wake_lock *lock, long timeout) +{ + __pm_wakeup_event(&lock->ws, jiffies_to_msecs(timeout)); +} + +static inline void wake_unlock(struct wake_lock *lock) +{ + __pm_relax(&lock->ws); +} +#endif /* _LINUX_WAKELOCK_H */ + +enum _pwdn_mode_t { + SIFP_PWDN_NONE = 0, + SIFP_PWDN_POWEROFF = 1, /* shutdown the avdd power supply */ + SIFP_PWDN_FLASH = 2, /* shutdown avdd 200ms for H/W full reset */ + SIFP_PWDN_MAX, +}; +enum _netlink_cmd_t { + SIFP_NETLINK_START = 0, + SIFP_NETLINK_IRQ = 1, + SIFP_NETLINK_SCR_OFF, + SIFP_NETLINK_SCR_ON, + SIFP_NETLINK_CONNECT, + SIFP_NETLINK_DISCONNECT, + SIFP_NETLINK_UI_READY, + SIFP_NETLINK_TP_TOUCHDOWN, + SIFP_NETLINK_TP_TOUCHUP, + SIFP_NETLINK_MAX, +}; + +enum _fp_nav_key_v_t { + NAV_KEY_UNKNOWN = 0, + NAV_KEY_START = 1, + NAV_KEY_UP = NAV_KEY_START, + NAV_KEY_DOWN, + NAV_KEY_RIGHT, + NAV_KEY_LEFT, + NAV_KEY_CLICK, + NAV_KEY_DCLICK, + NAV_KEY_LONGPRESS, + NAV_KEY_CLICK_DOWN, + NAV_KEY_CLICK_UP, + NAV_KEY_MAX, + NAV_KEY_WAITMORE = 1000, +}; + +#define IS_KEY_VALID(k) ((k) > NAV_KEY_UNKNOWN && (k) < NAV_KEY_MAX) + +enum _fp_nav_key_f_t { + NAV_KEY_FLAG_UP = 0, + NAV_KEY_FLAG_DOWN, + NAV_KEY_FLAG_CLICK, +}; + +struct fp_dev_key_t { + int value; + uint32_t flag; /* key down = 1, key up = 0, key down+up = 2 */ +}; + +#define DEVNAME_LEN 16 +struct fp_dev_init_t { + uint8_t mode; + uint8_t bits; + uint16_t delay; + uint32_t speed; + char dev[DEVNAME_LEN]; + uint8_t nl_id; + uint8_t dev_id; + uint16_t reserve; + uint32_t reg; + char ta[DEVNAME_LEN]; +}; + +struct fp_underscreen_info { + uint8_t touch_state; + uint8_t area_rate; + uint16_t x; + uint16_t y; +}; + +struct fp_dev_debug_t { + uint8_t cmd[4]; +}; + +struct fp_dev_kmap_t { + uint16_t k[NAV_KEY_MAX-NAV_KEY_START]; /* Up/Down/Right/Left/Click/Double Click/Longpress */ +}; + +#define PROC_VND_ID_LEN 32 + +#define SIFP_IOC_MAGIC 's' + +#define SIFP_IOC_RESET _IOW(SIFP_IOC_MAGIC, 10, u8) + +#define SIFP_IOC_ENABLE_IRQ _IO(SIFP_IOC_MAGIC, 11) +#define SIFP_IOC_DISABLE_IRQ _IO(SIFP_IOC_MAGIC, 12) +#define SIFP_IOC_WAIT_IRQ _IOR(SIFP_IOC_MAGIC, 13, u8) +#define SIFP_IOC_CLR_IRQ _IO(SIFP_IOC_MAGIC, 14) +//#define SPFP_IOC_EXIT _IOR(SIFP_IOC_MAGIC, 1, u8) + +#define SIFP_IOC_KEY_EVENT _IOW(SIFP_IOC_MAGIC, 15, struct fp_dev_key_t) +#define SIFP_IOC_INIT _IOR(SIFP_IOC_MAGIC, 16, struct fp_dev_init_t) +#define SIFP_IOC_DEINIT _IO(SIFP_IOC_MAGIC, 17) +#define SIFP_IOC_IRQ_STATUS _IOR(SIFP_IOC_MAGIC, 18, u8) +#define SIFP_IOC_DEBUG _IOR(SIFP_IOC_MAGIC, 19, struct fp_dev_debug_t) +#define SIFP_IOC_SCR_STATUS _IOR(SIFP_IOC_MAGIC, 20, u8) +#define SIFP_IOC_GET_VER _IOR(SIFP_IOC_MAGIC, 21, char[10]) +#define SIFP_IOC_SET_KMAP _IOW(SIFP_IOC_MAGIC, 22, uint16_t[7]) +#define SIFP_IOC_ACQ_SPI _IO(SIFP_IOC_MAGIC, 23) +#define SIFP_IOC_RLS_SPI _IO(SIFP_IOC_MAGIC, 24) +#define SIFP_IOC_PKG_SIZE _IOR(SIFP_IOC_MAGIC, 25, u8) +#define SIFP_IOC_DBG_LEVEL _IOWR(SIFP_IOC_MAGIC,26, u8) +#define SIFP_IOC_WAKELOCK _IOW(SIFP_IOC_MAGIC, 27, u8) +#define SIFP_IOC_PWDN _IOW(SIFP_IOC_MAGIC, 28, u8) +#define SIFP_IOC_PROC_NODE _IOW(SIFP_IOC_MAGIC, 29, char[PROC_VND_ID_LEN]) +#define SIFP_IOC_GET_TP_TOUCH_INFO _IOR(SIFP_IOC_MAGIC, 30, struct fp_underscreen_info) +#define SIFP_IOC_SET_TP_MSG_REPORT_MODE _IOW(SIFP_IOC_MAGIC, 31, u8) + +#define SIFP_IOC_REPORT_KEY _IOW(SIFP_IOC_MAGIC, 32, uint8_t) + +#define RESET_TIME 1 /* Default chip reset wait time(ms) */ +#define RESET_TIME_MULTIPLE 1 /* Multiple for reset time multiple*wait_time */ +#define SIFP_NETLINK_ROUTE 30 +#define NL_MSG_LEN 16 + +//#define PROC_DIR "fp" /* if defined, create node under /proc/fp/xxx */ +//#define PROC_NODE "fp_id" /* proc node name */ //remove by chenran + +#if (SIFP_NETLINK_ROUTE > 0) + #define BSP_SIL_NETLINK +#endif + +#if !defined(BSP_SIL_PLAT_MTK) && !defined(BSP_SIL_PLAT_QCOM) + #define BSP_SIL_PLAT_COMM +#endif /* ! BSP_SIL_PLAT_MTK & ! BSP_SIL_PLAT_QCOM */ + +/* Todo: enable correct power supply mode */ +#if !defined(BSP_SIL_POWER_SUPPLY_REGULATOR) +#define BSP_SIL_POWER_SUPPLY_REGULATOR +//#define BSP_SIL_POWER_SUPPLY_PINCTRL +//#define BSP_SIL_POWER_SUPPLY_GPIO +#endif + +/* AVDD voltage range 2.8v ~ 3.3v */ +#define AVDD_MAX 3000000 +#define AVDD_MIN 3000000 + +/* VDDIO voltage range 1.8v ~ AVDD */ +#define VDDIO_MAX 1800000 +#define VDDIO_MIN 1800000 + +#define CURRENT 50000 + +#if defined(BSP_SIL_POWER_SUPPLY_REGULATOR) && defined(BSP_SIL_POWER_SUPPLY_PINCTRL) || defined(BSP_SIL_POWER_SUPPLY_REGULATOR) && defined(BSP_SIL_POWER_SUPPLY_GPIO) || defined(BSP_SIL_POWER_SUPPLY_GPIO) && defined(BSP_SIL_POWER_SUPPLY_PINCTRL) + #error "Don't define multiple power supply mode!" +#endif + +#ifdef BSP_SIL_PLAT_MTK + #include "silead_fp_mtk.h" + #define PLAT_H "silead_fp_mtk.c" + + #define DEVICE "/dev/spidev1.0" + //#define BSP_SIL_IRQ_CONFIRM + #define PKG_SIZE 1 +#elif defined(BSP_SIL_PLAT_QCOM) + #define QSEE_V4 /* Enable it if QSEE v4 or higher */ + #include "silead_fp_qcom.h" + #define PLAT_H "silead_fp_qcom.c" + + #define DEVICE "/dev/spidev0.0" + #define BSP_SIL_IRQ_CONFIRM + #define PKG_SIZE 4 + #define TANAME "sileadta" +#else + #include "silead_fp_comm.h" + #define PLAT_H "silead_fp_comm.c" + + #define DEVICE "/dev/spidev0.0" + #define BSP_SIL_IRQ_CONFIRM + #define PKG_SIZE 4 + #define TANAME "" +#endif /* BSP_SIL_PLAT_XXX */ + +extern int opticalfp_irq_handler(struct fp_underscreen_info* tp_info); +#endif /* __SILEAD_FP_H__ */ + +/* End of file silead_fp.h */ diff --git a/drivers/oneplus/drivers/input/fingerprint/silead/silead_fp_platform.c b/drivers/oneplus/drivers/input/fingerprint/silead/silead_fp_platform.c new file mode 100755 index 000000000000..c70e2cc0ca3f --- /dev/null +++ b/drivers/oneplus/drivers/input/fingerprint/silead/silead_fp_platform.c @@ -0,0 +1,1555 @@ +/************************************************************************************ + * @file silead_fp_platform.c + * @brief Contains silead_fp device implementation. + * + * + * Copyright 2016-2018 Slead Inc. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + * + * ------------------- Revision History ------------------------------ + * + * Bill Yu 2018/4/2 0.1.6 Init version + * Bill Yu 2018/5/2 0.1.7 Fix compile error for some platform + * Bill Yu 2018/5/20 0.1.8 Default wait 3ms after reset + * Bill Yu 2018/5/28 0.1.9 Support poll/read if netlink id = 0 + * Bill Yu 2018/6/1 0.2.0 Support wakelock + * Bill Yu 2018/6/5 0.2.1 Support chip enter power down + * Bill Yu 2018/6/7 0.2.2 Support create proc node + * + * 2018/06/24 add fix for coverity 63621 63600 + * 2018/06/26 add silead power_on and power_offf for deep_sleep + * 2018/06/30 add for modify kernel warning (power on) + * 2018/07/07 add for tp irq and lcd notify + * 2018/07/21 add for get tp info + ***********************************************************************************/ +#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, 5, 0)) +#include +#endif +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#else +#include +#endif + +#include "silead_fp.h" +#include +#include +#include "../fingerprint_detect/fingerprint_detect.h" +#include "../drivers/gpu/drm/msm/sde/sde_trace.h" + +#define FP_DEV_NAME "silead_fp" +#define FP_DEV_MAJOR 0 /* assigned */ + +#define FP_CLASS_NAME "silead_fp" +#define FP_INPUT_NAME "fp-keys" + +#define FP_DEV_VERSION "v0.2.3" +#define LOG_TAG "[+silead_fp-] " + +#define BSP_SIL_IRQ_ASYNC /* IRQ use asynchrous mode. */ +static struct silfp_data *optical_fp; +static struct fp_underscreen_info fp_tpinfo; +static unsigned int lasttouchmode = 0; + +#ifndef BSP_SIL_NETLINK +struct silfp_msg_list { + unsigned char msg; + struct list_head list; +}; +#endif /* !BSP_SIL_NETLINK */ + +struct silfp_data { + dev_t devt; + struct cdev cdev; + spinlock_t spi_lock; + struct platform_device *spi; + struct list_head device_entry; + + unsigned users; + + struct device *dev; + int ref; + + struct input_dev *input; + + spinlock_t irq_lock; + int int_port; + int irq; + s32 irq_is_disable; + int irq_ignore; + s32 power_is_off; + int rst_port; + struct work_struct work; + struct completion done; + struct wake_lock wakelock; + struct wake_lock wakelock_hal; + +#ifdef BSP_SIL_NETLINK + /* for netlink use */ + struct sock *nl_sk; +#else + spinlock_t read_lock; + wait_queue_head_t read_queue; + struct list_head msg_q; +#endif + struct fp_dev_kmap_t keymap_cust; + + int scr_off; +#ifdef CONFIG_HAS_EARLYSUSPEND + struct early_suspend es; +#else + struct notifier_block msm_drm_notif; +#endif /* CONFIG_HAS_EARLYSUSPEND */ + + /* for power supply */ +#ifdef BSP_SIL_POWER_SUPPLY_REGULATOR + struct regulator *avdd_ldo; + struct regulator *vddio_ldo; +#endif /* BSP_SIL_POWER_SUPPLY_REGULATOR */ +#ifdef BSP_SIL_POWER_SUPPLY_GPIO + int avdd_port; + int vddio_port; +#endif /* BSP_SIL_POWER_SUPPLY_GPIO */ +#ifdef PROC_NODE + struct proc_dir_entry *proc_root; + struct proc_dir_entry *proc_entry; +#endif /* PROC_NODE */ + + /* for spi enable/disable */ + atomic_t spionoff_count; + + struct fp_plat_t pin; + + atomic_t init; + struct pinctrl *sl_pinctrl; + struct pinctrl_state *gpio_state_enable; +}; + +typedef enum _fp_spi_speet_t { + SPEED_1M=1*1000*1000, + SPEED_LOW = SPEED_1M, + SPEED_5M=5*1000*1000, + SPEED_MEDIUM = SPEED_5M, + SPEED_8M=8*1000*1000, + SPEED_9M=9*1000*1000, + SPEED_HIGH=SPEED_8M, + SPEED_10M=10*1000*1000, +} fp_spi_speet_t ; + +static struct fp_dev_init_t silfp_dev_init_d = { + .mode = 0, + .bits = 8, + .speed = SPEED_HIGH, + .delay = 100, + .dev = DEVICE, + .nl_id = SIFP_NETLINK_ROUTE, + .dev_id = 0, +}; + +/* on some platform, home key has been redefine to KEY_HOMEPAGE! */ +/* double check the define on customer board!!! + out/target/product/.../system/usr/keylayout/Generic.kl + kernel/include/uapi/linux/input.h + + KEY_HOMEPAGE + KEY_HOME + KEY_MENU + KEY_BACK + KEY_POWER + KEY_CAMERA + KEY_VOLUMEUP + KEY_VOLUMEDOWN */ + +typedef struct _key_map { + int key_orig; + int key_new; +} nav_keymap_t; + +static nav_keymap_t keymap[] = { + { NAV_KEY_UP, KEY_UP, }, /* KEY_RESERVED, ignore this key */ + { NAV_KEY_DOWN, KEY_DOWN, }, + { NAV_KEY_RIGHT, KEY_RIGHT, }, + { NAV_KEY_LEFT, KEY_LEFT, }, + { NAV_KEY_CLICK, KEY_HOMEPAGE, }, + { NAV_KEY_DCLICK, KEY_HOMEPAGE, }, + { NAV_KEY_LONGPRESS,KEY_HOMEPAGE, }, +}; + +static LIST_HEAD(device_list); +static DEFINE_MUTEX(device_list_lock); + +#ifdef BSP_SIL_NETLINK +static int pid; +#endif /* BSP_SIL_NETLINK */ + +#ifdef PROC_NODE +static char vendor_name[PROC_VND_ID_LEN]; +#endif /* PROC_NODE */ + + +struct class *silfp_class; + +static struct workqueue_struct *silfp_wq; + +static void silfp_hw_reset(struct silfp_data *fp_dev, u8 delay); +static void silfp_irq_disable(struct silfp_data *fp_dev); +static void silfp_irq_enable(struct silfp_data *fp_dev); +static int silfp_wait_irq(struct silfp_data *fp_dev); +static int silfp_irq_status(struct silfp_data *fp_dev); +static int silfp_resource_init(struct silfp_data *fp_dev, struct fp_dev_init_t *dev_info); +static int silfp_resource_deinit(struct silfp_data *fp_dev); +static void silfp_power_deinit(struct silfp_data *fp_dev); +static void silfp_pwdn(struct silfp_data *fp_dev, u8 flag_avdd); +static void silfp_hw_poweron(struct silfp_data *fp_dev); + +/* -------------------------------------------------------------------- */ +/* debug settings */ +/* -------------------------------------------------------------------- */ +typedef enum { + ERR_LOG=0, + DBG_LOG, + INFO_LOG, + ALL_LOG, +} fp_debug_level_t; + +/* debug log level */ +static fp_debug_level_t debug_level = DBG_LOG; + +#define LOG_MSG_DEBUG(level, fmt, args...) do { \ + if (debug_level >= level) {\ + pr_warn(LOG_TAG fmt, ##args); \ + } \ + } while (0) + +#include PLAT_H + +/* -------------------------------------------------------------------- */ +/* netlink functions */ +/* -------------------------------------------------------------------- */ +#ifdef BSP_SIL_NETLINK +static void silfp_netlink_send(struct silfp_data *fp_dev, const int cmd) +{ + struct nlmsghdr *nlh = NULL; + struct sk_buff *skb = NULL; + int ret; + + LOG_MSG_DEBUG(INFO_LOG, "[%s] send cmd %d\n", __func__, cmd); + if ( !fp_dev->nl_sk) { + LOG_MSG_DEBUG(ERR_LOG, "[%s] invalid socket\n", __func__); + return; + } + + if (! pid) { + LOG_MSG_DEBUG(ERR_LOG, "[%s] invalid PID\n", __func__); + return; + } + + /*alloc data buffer for sending to native*/ + /*malloc data space at least 1500 bytes, which is ethernet data length*/ + skb = alloc_skb(NL_MSG_LEN, GFP_ATOMIC); + if (skb == NULL) { + return; + } + + nlh = nlmsg_put(skb, 0, 0, 0, NL_MSG_LEN, 0); + if (!nlh) { + LOG_MSG_DEBUG(ERR_LOG, "[%s] nlmsg_put() failed\n", __func__); + kfree_skb(skb); + return; + } + + NETLINK_CB(skb).portid = 0; + NETLINK_CB(skb).dst_group = 0; + + *(char *)NLMSG_DATA(nlh) = cmd; + ret = netlink_unicast(fp_dev->nl_sk, skb, pid, MSG_DONTWAIT); + if (ret == 0) { + LOG_MSG_DEBUG(ERR_LOG, "[%s] send failed\n", __func__); + kfree_skb(skb); + return; + } + + LOG_MSG_DEBUG(INFO_LOG, "[%s] sent, len=%d\n", __func__, ret); +} + +static void silfp_netlink_recv(struct sk_buff *__skb) +{ + struct sk_buff *skb = NULL; + struct nlmsghdr *nlh = NULL; + char str[128]; + + skb = skb_get(__skb); + if (!skb ) { + LOG_MSG_DEBUG(ERR_LOG, "[%s] skb NULL\n", __func__); + return; + } + + /* presume there is 5byte payload at leaset */ + if (skb->len >= NLMSG_SPACE(0)) { + nlh = nlmsg_hdr(skb); + memcpy(str, NLMSG_DATA(nlh), sizeof(str)); + pid = nlh->nlmsg_pid; + LOG_MSG_DEBUG(INFO_LOG, "[%s] PID=%d, msg=%s\n", __func__, pid, str); + } else { + LOG_MSG_DEBUG(ERR_LOG, "[%s] data len incorrect\n", __func__); + } + + kfree_skb(skb); +} + +static int silfp_netlink_init(struct silfp_data *fp_dev) +{ + struct netlink_kernel_cfg cfg; + + memset(&cfg, 0, sizeof(struct netlink_kernel_cfg)); + cfg.input = silfp_netlink_recv; + + fp_dev->nl_sk = netlink_kernel_create(&init_net, SIFP_NETLINK_ROUTE, &cfg); + if (fp_dev->nl_sk == NULL) { + LOG_MSG_DEBUG(ERR_LOG, "[%s] netlink create failed\n", __func__); + return -1; + } + + LOG_MSG_DEBUG(INFO_LOG, "[%s] netlink create success\n", __func__); + return 0; +} + +static int silfp_netlink_destroy(struct silfp_data *fp_dev) +{ + if (fp_dev->nl_sk != NULL) { + netlink_kernel_release(fp_dev->nl_sk); + fp_dev->nl_sk = NULL; + return 0; + } + + LOG_MSG_DEBUG(ERR_LOG, "[%s] no netlink socket\n", __func__); + return -1; +} +#else +static void silfp_netlink_send(struct silfp_data *fp_dev, const int cmd) +{ + unsigned long flags; + struct silfp_msg_list *list; + + list = kzalloc(sizeof(*list), GFP_ATOMIC); + if (!list) { + return; + } + + list->msg = (unsigned char)cmd; + + LOG_MSG_DEBUG(INFO_LOG, "silfp_poll cmd %d\n", cmd); + spin_lock_irqsave(&fp_dev->read_lock, flags); + list_add_tail(&list->list, &fp_dev->msg_q); + spin_unlock_irqrestore(&fp_dev->read_lock, flags); + + wake_up_interruptible(&fp_dev->read_queue); +} + +static int silfp_netlink_init(struct silfp_data *fp_dev) +{ + spin_lock_init(&fp_dev->read_lock); + init_waitqueue_head(&fp_dev->read_queue); + INIT_LIST_HEAD(&fp_dev->msg_q); + + return 0; +} + +static int silfp_netlink_destroy(struct silfp_data *fp_dev) +{ + struct silfp_msg_list *list, *next; + unsigned long flags; + + if (fp_dev && (&fp_dev->msg_q)) { + spin_lock_irqsave(&fp_dev->read_lock, flags); + list_for_each_entry_safe(list, next, &fp_dev->msg_q, list) { + list_del(&list->list); + kfree(list); + } + spin_unlock_irqrestore(&fp_dev->read_lock, flags); + } + return 0; +} + +static unsigned int silfp_poll(struct file *fd, poll_table *wait) +{ + struct silfp_data *fp_dev; + unsigned int mask = 0; + + if (!fd) { + return -EINVAL; + } + + fp_dev = fd->private_data; + poll_wait(fd, &fp_dev->read_queue, wait); + + if(!list_empty(&fp_dev->msg_q)) { + mask |= POLLIN | POLLRDNORM; + } + + return mask; +} + +static ssize_t silfp_read(struct file *fd, char __user *buf, size_t len,loff_t *ptr) +{ + struct silfp_data *fp_dev; + struct silfp_msg_list *list; + unsigned long flags; + int32_t msglen = sizeof(char); + + if (!fd || !buf || (len < msglen)) { + return -EINVAL; + } + + fp_dev = fd->private_data; + if (!&fp_dev->msg_q) { + return -EINVAL; + } + + spin_lock_irqsave(&fp_dev->read_lock, flags); + while(list_empty(&fp_dev->msg_q)) { + spin_unlock_irqrestore(&fp_dev->read_lock, flags); + if (wait_event_interruptible(fp_dev->read_queue, !list_empty(&fp_dev->msg_q))) { + return -EINVAL; + } + spin_lock_irqsave(&fp_dev->read_lock, flags); + } + /* pick the first one */ + list = list_first_entry(&fp_dev->msg_q, + struct silfp_msg_list, list); + spin_unlock_irqrestore(&fp_dev->read_lock, flags); + + if (!list) { + return -EFAULT; + } + + if (copy_to_user(buf, &list->msg, msglen)) { + LOG_MSG_DEBUG(ERR_LOG, "copy_to fail\n"); + msglen = -EFAULT; + } else { + LOG_MSG_DEBUG(INFO_LOG, "[%s] %d\n", __func__, list->msg); + } + spin_lock_irqsave(&fp_dev->read_lock, flags); + list_del(&list->list); + kfree(list); + spin_unlock_irqrestore(&fp_dev->read_lock, flags); + + return msglen; +} +#endif /* BSP_SIL_NETLINK */ + +/*liuyan 2017/12/7 add for detect screen state*/ +static ssize_t screen_state_get(struct device *device, + struct device_attribute *attribute, + char *buffer) +{ + struct silfp_data *fp_dev = dev_get_drvdata(device); + + return scnprintf(buffer, PAGE_SIZE, "%i\n", !fp_dev->scr_off); +} + +static DEVICE_ATTR(screen_state, 0400, screen_state_get, NULL); + +static struct attribute *sl_attributes[] = { + &dev_attr_screen_state.attr, + NULL +}; + +static const struct attribute_group sl_attribute_group = { + .attrs = sl_attributes, +}; + + +#ifdef CONFIG_HAS_EARLYSUSPEND +static void silfp_early_suspend(struct early_suspend *es) +{ + struct silfp_data *fp_dev = container_of(es, struct silfp_data, es); + + LOG_MSG_DEBUG(INFO_LOG, "[%s] enter\n", __func__); + fp_dev->scr_off = 1; + silfp_netlink_send(fp_dev, SIFP_NETLINK_SCR_OFF); +} + +static void silfp_late_resume(struct early_suspend *es) +{ + struct silfp_data *fp_dev = container_of(es, struct silfp_data, es); + + LOG_MSG_DEBUG(INFO_LOG, "[%s] enter\n", __func__); + fp_dev->scr_off = 0; + silfp_netlink_send(fp_dev, SIFP_NETLINK_SCR_ON); +} +#else +static int silfp_fb_callback(struct notifier_block *notif, + unsigned long event, void *data) +{ + struct silfp_data *fp_dev = container_of(notif, struct silfp_data, msm_drm_notif); + struct msm_drm_notifier *evdata = data; + unsigned int blank; + int retval = 0; + + /* If we aren't interested in this event, skip it immediately ... */ + if (event == MSM_DRM_EARLY_EVENT_BLANK || event == MSM_DRM_ONSCREENFINGERPRINT_EVENT){ + + + if (evdata->id != MSM_DRM_PRIMARY_DISPLAY) + return 0; + + + + + blank = *(int *)evdata->data; + //printk(KERN_ERR"GZM FP1 blank = %d\n",blank); + //printk(KERN_ERR"GZM FP1 event = %ld\n",event); + //printk(KERN_ERR"GZM FP1 evdata->id = %d\n",evdata->id); + + if (event == MSM_DRM_ONSCREENFINGERPRINT_EVENT ) { + LOG_MSG_DEBUG(INFO_LOG, "[%s] UI ready enter\n", __func__); + //printk(KERN_ERR"GZM FP2 blank =%d\n",blank); + + switch (blank) { + case 0: + LOG_MSG_DEBUG(INFO_LOG, "[%s] UI disappear\n", __func__); + //printk(KERN_ERR"GZM FP3\n"); + //silfp_netlink_send(fp_dev, SIFP_NETLINK_UI_OFF);//SIFP_NETLINK_UI_OFF donothing now + break; + case 1: + //printk(KERN_ERR"GZM FP4\n"); + LOG_MSG_DEBUG(INFO_LOG, "[%s] UI ready \n", __func__); + SDE_ATRACE_BEGIN("fb_ui_ready"); + silfp_netlink_send(fp_dev, SIFP_NETLINK_UI_READY); + SDE_ATRACE_END("fb_ui_ready"); + break; + default: + LOG_MSG_DEBUG(INFO_LOG, "[%s] Unknown MSM_DRM_ONSCREENFINGERPRINT_EVENT\n", __func__); + break; + } + return retval; + } + LOG_MSG_DEBUG(INFO_LOG, "[%s] enter, blank=0x%x\n", __func__, blank); + + switch (blank) { + case MSM_DRM_BLANK_UNBLANK: + LOG_MSG_DEBUG(INFO_LOG, "[%s] LCD ON\n", __func__); + fp_dev->scr_off = 0; + silfp_netlink_send(fp_dev, SIFP_NETLINK_SCR_ON); + sysfs_notify(&fp_dev->spi->dev.kobj, + NULL, dev_attr_screen_state.attr.name); + break; + + case MSM_DRM_BLANK_POWERDOWN: + LOG_MSG_DEBUG(INFO_LOG, "[%s] LCD OFF\n", __func__); + fp_dev->scr_off = 1; + silfp_netlink_send(fp_dev, SIFP_NETLINK_SCR_OFF); + sysfs_notify(&fp_dev->spi->dev.kobj, + NULL, dev_attr_screen_state.attr.name); + break; + + default: + LOG_MSG_DEBUG(INFO_LOG, "[%s] Unknown notifier\n", __func__); + break; + } + return retval; + } + else + return 0; +} +#endif /* CONFIG_HAS_EARLYSUSPEND */ + +/* -------------------------------------------------------------------- */ +/* IRQ related functions */ +/* -------------------------------------------------------------------- */ +static void silfp_irq_disable(struct silfp_data *fp_dev) +{ + unsigned long irqflags; + + spin_lock_irqsave(&fp_dev->irq_lock, irqflags); + if (!fp_dev->irq_is_disable) { + fp_dev->irq_is_disable = 1; + disable_irq_nosync(fp_dev->irq); + LOG_MSG_DEBUG(INFO_LOG, "[%s] irq disabled\n", __func__); + } + spin_unlock_irqrestore(&fp_dev->irq_lock, irqflags); +} + +static void silfp_irq_enable(struct silfp_data *fp_dev) +{ + unsigned long irqflags = 0; + + spin_lock_irqsave(&fp_dev->irq_lock, irqflags); + if (fp_dev->irq_is_disable) { + enable_irq(fp_dev->irq); + fp_dev->irq_is_disable = 0; + reinit_completion(&fp_dev->done); + LOG_MSG_DEBUG(INFO_LOG, "[%s] irq enabled\n", __func__); + } + spin_unlock_irqrestore(&fp_dev->irq_lock, irqflags); +} + +static int silfp_wait_irq(struct silfp_data *fp_dev) +{ + // this function is obsolete, for test purpose only. + wait_for_completion(&fp_dev->done); + //return wait_for_completion_timeout(&fp_dev->done, msecs_to_jiffies(3000)); + return 1; +} + +static int silfp_irq_status(struct silfp_data *fp_dev) +{ + // this function is obsolete, for test purpose only. + if (fp_dev->int_port) { + return gpio_get_value(fp_dev->int_port); + } + return -1; +} + +static irqreturn_t silfp_irq_handler(int irq, void *dev_id) +{ + struct silfp_data *fp_dev = (struct silfp_data *)dev_id; + + if (fp_dev->irq_ignore) { + return IRQ_HANDLED; + } + +#ifdef BSP_SIL_IRQ_CONFIRM + if (gpio_get_value(fp_dev->int_port)) { +#else + if (true) { +#endif /* BSP_SIL_IRQ_CONFIRM */ + wake_lock_timeout(&fp_dev->wakelock, 10*HZ); /* set a little long for a poor MCU */ +#ifdef BSP_SIL_IRQ_ASYNC + queue_work(silfp_wq, &fp_dev->work); +#else + silfp_netlink_send(fp_dev, SIFP_NETLINK_IRQ); +#endif /* BSP_SIL_IRQ_ASYNC */ + complete(&fp_dev->done); + } else { + LOG_MSG_DEBUG(INFO_LOG, "[%s] irq ignore\n", __func__); + } + + return IRQ_HANDLED; +} + +int opticalfp_irq_handler(struct fp_underscreen_info* tp_info) +{ + + // wake_lock_timeout(&fp_dev->wakelock, 10*HZ); /* set a little long for a poor MCU */ + + //silfp_netlink_send(fp_dev, SIFP_NETLINK_IRQ); + //static unsigned int lasttouchmode = 0; + + if (optical_fp == NULL) + return 0; + fp_tpinfo = *tp_info; + LOG_MSG_DEBUG(INFO_LOG, "fp_tpinfo %d, %d, %d, %d \n" , + fp_tpinfo.touch_state, fp_tpinfo.area_rate, fp_tpinfo.x, fp_tpinfo.y); + + //complete(&fp_dev->done); + LOG_MSG_DEBUG(INFO_LOG, "[%s] touchmode = %d, lasttouchmode =%d \n", __func__, tp_info->touch_state, lasttouchmode); + if(tp_info->touch_state== lasttouchmode){ + return 0; + } + if(1 == tp_info->touch_state){ + silfp_netlink_send(optical_fp, SIFP_NETLINK_TP_TOUCHDOWN); + lasttouchmode = tp_info->touch_state; + }else{ + silfp_netlink_send(optical_fp, SIFP_NETLINK_TP_TOUCHUP); + lasttouchmode = tp_info->touch_state; + } + + wake_lock_timeout(&optical_fp->wakelock, 10*HZ); + + return 0; +} + +EXPORT_SYMBOL(opticalfp_irq_handler); + +static void silfp_work_func(struct work_struct *work) +{ + struct silfp_data *fp_dev = container_of(work, struct silfp_data, work); + + LOG_MSG_DEBUG(INFO_LOG, "[%s] running\n", __func__); + silfp_netlink_send(fp_dev, SIFP_NETLINK_IRQ); +} + +/* -------------------------------------------------------------------- */ +/* key event functions */ +/* -------------------------------------------------------------------- */ +static int silfp_keyevent(struct silfp_data *fp_dev, struct fp_dev_key_t *pkey) +{ + int ret = -EFAULT; + int i; + + //LOG_MSG_DEBUG(INFO_LOG, "[%s] key %d, flag %d\n", __func__,pkey->value,pkey->flag); + if (!fp_dev->input) { + LOG_MSG_DEBUG(INFO_LOG, "[%s] invalid input device\n",__func__); + return -1; + } + if ( IS_KEY_VALID(pkey->value) ) { + /* Translate Click Down/Up key to Click key. */ + switch( pkey->value ) { + case NAV_KEY_CLICK_DOWN: + pkey->value = NAV_KEY_CLICK; + pkey->flag = NAV_KEY_FLAG_DOWN; + break; + case NAV_KEY_CLICK_UP: + pkey->value = NAV_KEY_CLICK; + pkey->flag = NAV_KEY_FLAG_UP; + break; + default: + break; + } + + /* Check the custom define keymap */ + if ( fp_dev->keymap_cust.k[pkey->value - NAV_KEY_START] ) { + LOG_MSG_DEBUG(INFO_LOG, "[%s] custom-key %d\n", __func__,fp_dev->keymap_cust.k[pkey->value - NAV_KEY_START]); + if ( KEY_RESERVED != fp_dev->keymap_cust.k[pkey->value - NAV_KEY_START] ) { + if ( NAV_KEY_FLAG_CLICK == pkey->flag ) { + input_report_key(fp_dev->input, fp_dev->keymap_cust.k[pkey->value - NAV_KEY_START], NAV_KEY_FLAG_DOWN); + input_sync(fp_dev->input); + input_report_key(fp_dev->input, fp_dev->keymap_cust.k[pkey->value - NAV_KEY_START], NAV_KEY_FLAG_UP); + input_sync(fp_dev->input); + } else { + input_report_key(fp_dev->input, fp_dev->keymap_cust.k[pkey->value - NAV_KEY_START], pkey->flag); + input_sync(fp_dev->input); + } + } else { + // Here means this key is not set, simply ignore it. + } + ret = 0; + } + } + + for ( i = 0; ret && i < ARRAY_SIZE(keymap); i++ ) { + if ( keymap[i].key_orig == pkey->value ) { + LOG_MSG_DEBUG(INFO_LOG, "[%s] key %d\n", __func__,keymap[i].key_new); + if ( KEY_RESERVED != keymap[i].key_new ) { + if ( NAV_KEY_FLAG_CLICK == pkey->flag ) { + input_report_key(fp_dev->input, keymap[i].key_new, NAV_KEY_FLAG_DOWN); + input_sync(fp_dev->input); + input_report_key(fp_dev->input, keymap[i].key_new, NAV_KEY_FLAG_UP); + input_sync(fp_dev->input); + } else { + input_report_key(fp_dev->input, keymap[i].key_new, pkey->flag); + input_sync(fp_dev->input); + } + } else { + // Here means this key is not set, simply ignore it. + } + ret = 0; + } + } + + if ( ret ) { + LOG_MSG_DEBUG(INFO_LOG, "[%s] unregister custom-key %d\n", __func__,pkey->value); + input_report_key(fp_dev->input, pkey->value, pkey->flag); + input_sync(fp_dev->input); + ret = 0; + } + return ret; +} + +/* -------------------------------------------------------------------- */ +/* proc node functions */ +/* -------------------------------------------------------------------- */ +#ifdef PROC_NODE +static int silfp_proc_show(struct seq_file *m, void *v) +{ + seq_printf(m, "%s\n", vendor_name); + return 0; +} + +static int silfp_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, silfp_proc_show, NULL); +} + +static const struct file_operations silfp_proc_fops = { + .owner = THIS_MODULE, + .read = seq_read, + .open = silfp_proc_open, + .release = single_release, +}; + +static int silfp_proc_create_node(struct silfp_data *fp_dev) +{ + if (fp_dev->proc_entry == NULL) { + fp_dev->proc_root = NULL; +#ifdef PROC_DIR + fp_dev->proc_root = proc_mkdir(PROC_DIR, NULL); + if (fp_dev->proc_root == NULL) { + LOG_MSG_DEBUG(ERR_LOG, "Create dir %s under /proc error!\n", PROC_DIR); + goto err_out; + } +#endif /* PROC_DIR */ + fp_dev->proc_entry = proc_create(PROC_NODE, 0666, fp_dev->proc_root, &silfp_proc_fops); + if (fp_dev->proc_entry == NULL) { + LOG_MSG_DEBUG(ERR_LOG, "Create entry %s under /proc/ error!\n", PROC_NODE); + goto err_out1; + } + } + + return 0; + +err_out1: + remove_proc_entry(PROC_NODE, fp_dev->proc_root); +#ifdef PROC_DIR + remove_proc_entry(PROC_DIR, NULL); +err_out: +#endif /* PROC_DIR */ + fp_dev->proc_root = NULL; + fp_dev->proc_entry = NULL; + return -ENOMEM; +} + +static int silfp_proc_init(struct silfp_data *fp_dev) +{ + if (fp_dev) { + fp_dev->proc_root = NULL; + fp_dev->proc_entry = NULL; + } + return 0; + +} + +static void silfp_proc_deinit(struct silfp_data *fp_dev) +{ + if (fp_dev) { + if (fp_dev->proc_entry) { + remove_proc_entry(PROC_NODE, fp_dev->proc_root); + } +#ifdef PROC_DIR + if (fp_dev->proc_root) { + remove_proc_entry(PROC_DIR, NULL); + } +#endif /* PROC_DIR */ + fp_dev->proc_root = NULL; + fp_dev->proc_entry = NULL; + } +} +#endif /* PROC_NODE */ + +/* -------------------------------------------------------------------- */ +/* init/deinit functions */ +/* -------------------------------------------------------------------- */ +static int silfp_input_init(struct silfp_data *fp_dev) +{ + int i, status = 0; + + /*register device within input system.*/ + fp_dev->input = input_allocate_device(); + if (!fp_dev->input) { + LOG_MSG_DEBUG(ERR_LOG, "[%s] input_allocate_device() fail!\n", __func__); + status = -ENOMEM; + return status; + } + + __set_bit(EV_KEY, fp_dev->input->evbit); + //__set_bit(KEY_Q, fp_dev->input->keybit); // it will cause Android think this is a physical keyboard. + __set_bit(KEY_HOME, fp_dev->input->keybit); + __set_bit(KEY_HOMEPAGE, fp_dev->input->keybit); + + __set_bit(KEY_MENU, fp_dev->input->keybit); + __set_bit(KEY_BACK, fp_dev->input->keybit); + __set_bit(KEY_CAMERA, fp_dev->input->keybit); + + __set_bit(KEY_F2, fp_dev->input->keybit); + + for ( i = 0; i < ARRAY_SIZE(keymap); i++ ) { + if ( keymap[i].key_new != KEY_RESERVED ) { + __set_bit(keymap[i].key_new, fp_dev->input->keybit); + } + } + + for ( i = 0; i < ARRAY_SIZE(fp_dev->keymap_cust.k); i++ ) { + if (fp_dev->keymap_cust.k[i] && (fp_dev->keymap_cust.k[i] != KEY_RESERVED)) { + __set_bit(fp_dev->keymap_cust.k[i], fp_dev->input->keybit); + } + } + + fp_dev->input->name = FP_INPUT_NAME; + if (input_register_device(fp_dev->input)) { + LOG_MSG_DEBUG(ERR_LOG, "[%s] input_register_device() fail!\n", __func__); + input_free_device(fp_dev->input); + fp_dev->input = NULL; + status = -ENODEV; + } + return status; +} + +static int silfp_input_deinit(struct silfp_data *fp_dev) +{ + if (fp_dev->input) { + input_unregister_device(fp_dev->input); + fp_dev->input = NULL; + } + return 0; +} + +static int silfp_input_reinit(struct silfp_data *fp_dev) +{ + if (fp_dev->input) { + silfp_input_deinit(fp_dev); + } + return silfp_input_init(fp_dev); +} + +static int silfp_init(struct silfp_data *fp_dev) +{ + int status = 0; + + LOG_MSG_DEBUG(INFO_LOG, "[%s] enter\n", __func__); + init_completion(&fp_dev->done); + spin_lock_init(&fp_dev->irq_lock); + INIT_WORK(&fp_dev->work, silfp_work_func); + + /* netlink interface init */ + status = silfp_netlink_init(fp_dev); + if (status == -1) { + return status; + } + +#if defined(CONFIG_HAS_EARLYSUSPEND) + LOG_MSG_DEBUG(INFO_LOG, "[%s] register_early_suspend\n", __func__); + fp_dev->es.level = (EARLY_SUSPEND_LEVEL_DISABLE_FB - 1); + fp_dev->es.suspend = silfp_early_suspend; + fp_dev->es.resume = silfp_late_resume; + register_early_suspend(&fp_dev->es); +#else + fp_dev->msm_drm_notif.notifier_call = silfp_fb_callback; + status = msm_drm_register_client(&fp_dev->msm_drm_notif); + if (status) + LOG_MSG_DEBUG(INFO_LOG,"Unable to register msm_drm_notifier: %d\n", status); + else + LOG_MSG_DEBUG(INFO_LOG,"register msm_drm_notifier: %d\n", status); +#endif /* CONFIG_HAS_EARLYSUSPEND */ + + atomic_set(&fp_dev->spionoff_count,0); + + return status; +} + +static int silfp_resource_deinit(struct silfp_data *fp_dev) +{ + LOG_MSG_DEBUG(INFO_LOG, "[%s] enter\n", __func__); + + if (atomic_read(&fp_dev->init)) { + atomic_dec(&fp_dev->init); + + if (!atomic_read(&fp_dev->init)) { + LOG_MSG_DEBUG(INFO_LOG, "[%s] no more users, free GPIOs\n", __func__); + silfp_irq_disable(fp_dev); + free_irq(fp_dev->irq, fp_dev); + + gpio_direction_input(fp_dev->int_port); +#if !defined(BSP_SIL_PLAT_MTK) + gpio_free(fp_dev->int_port); + if (fp_dev->rst_port > 0 ) { + gpio_free(fp_dev->rst_port); + } +#endif /* !BSP_SIL_PLAT_MTK */ + fp_dev->int_port = 0; + fp_dev->rst_port = 0; + + silfp_input_deinit(fp_dev); + silfp_power_deinit(fp_dev); +#ifdef PROC_NODE + silfp_proc_deinit(fp_dev); +#endif /* PROC_NODE */ + } + silfp_netlink_send(fp_dev, SIFP_NETLINK_DISCONNECT); + } + return 0; +} + +static void silfp_exit(struct silfp_data *fp_dev) +{ + LOG_MSG_DEBUG(INFO_LOG, "[%s] enter\n", __func__); + +#ifdef CONFIG_HAS_EARLYSUSPEND + if (fp_dev->es.suspend) { + unregister_early_suspend(&fp_dev->es); + } +#else + if (msm_drm_unregister_client(&fp_dev->msm_drm_notif)) + pr_err("Error occurred while unregistering msm_drm_notifier.\n"); +#endif /* CONFIG_HAS_EARLYSUSPEND */ + + silfp_set_spi(fp_dev, false); /* release SPI resources */ + + if (silfp_wq) { + destroy_workqueue(silfp_wq); + silfp_wq = NULL; + } + silfp_netlink_destroy(fp_dev); +#ifdef PROC_NODE + silfp_proc_deinit(fp_dev); +#endif /* PROC_NODE */ +} + +static void silfp_wakelock_ctl(struct silfp_data *fp_dev, unsigned char lock) +{ + if (lock) { + wake_lock_timeout(&fp_dev->wakelock_hal, 10*HZ); + } else { + wake_unlock(&fp_dev->wakelock_hal); + } +} +/*-------------------------------------------------------------------------*/ + +static long +silfp_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + int err = 0; + int retval = 0; + struct silfp_data *fp_dev; + struct fp_dev_key_t key; + + /* Check type and command number */ + if (_IOC_TYPE(cmd) != SIFP_IOC_MAGIC) + return -ENOTTY; + + /* Check access direction once here; don't repeat below. + * IOC_DIR is from the user perspective, while access_ok is + * from the kernel perspective; so they look reversed. + */ + if (_IOC_DIR(cmd) & _IOC_READ) { + err = !access_ok(VERIFY_WRITE, + (void __user *)arg, _IOC_SIZE(cmd)); + } + if (err == 0 && _IOC_DIR(cmd) & _IOC_WRITE) { + err = !access_ok(VERIFY_READ, + (void __user *)arg, _IOC_SIZE(cmd)); + } + if (err) { + return -EFAULT; + } + + /* guard against device removal before, or while, + * we issue this ioctl. + */ + fp_dev = filp->private_data; + + switch (cmd) { + case SIFP_IOC_INIT: + silfp_resource_init(fp_dev,&silfp_dev_init_d); + if (copy_to_user((void __user *)arg, (void *)&silfp_dev_init_d, sizeof(struct fp_dev_init_t))) { + retval = -EFAULT; + } + + break; + case SIFP_IOC_DEINIT: + silfp_resource_deinit(fp_dev); + break; + + case SIFP_IOC_RESET: { + unsigned char delay = RESET_TIME; + LOG_MSG_DEBUG(INFO_LOG, "[%s] chip reset\n", __func__); + if (arg) { + if (copy_from_user(&delay, (void __user *)arg, sizeof(char))) { + retval = -EFAULT; + break; + } + } + + if (fp_dev->power_is_off) { + silfp_hw_poweron(fp_dev); + mdelay(5); + } + fp_dev->irq_ignore = 1; + if (fp_dev->irq_is_disable) { + silfp_irq_enable(fp_dev); + silfp_hw_reset(fp_dev, delay); + silfp_irq_disable(fp_dev); + } else { + silfp_hw_reset(fp_dev, delay); + } + fp_dev->irq_ignore = 0; + } + break; + + case SIFP_IOC_ENABLE_IRQ: + LOG_MSG_DEBUG(INFO_LOG, "[%s] enable irq\n", __func__); + silfp_irq_enable(fp_dev); + break; + + case SIFP_IOC_DISABLE_IRQ: + LOG_MSG_DEBUG(INFO_LOG, "[%s] disable irq\n", __func__); + silfp_irq_disable(fp_dev); + break; + + case SIFP_IOC_CLR_IRQ: + LOG_MSG_DEBUG(INFO_LOG, "[%s] clear irq\n", __func__); + reinit_completion(&fp_dev->done); + break; + + case SIFP_IOC_WAIT_IRQ: + LOG_MSG_DEBUG(INFO_LOG, "[%s] wait irq\n", __func__); + retval = __put_user(silfp_wait_irq(fp_dev)?1:0, (__u8 __user *)arg); + break; + + case SIFP_IOC_IRQ_STATUS: + LOG_MSG_DEBUG(INFO_LOG, "[%s] irq status\n", __func__); + retval = __put_user((char)silfp_irq_status(fp_dev), (__u8 __user *)arg); + break; + + case SIFP_IOC_KEY_EVENT: + if (copy_from_user(&key, (struct fp_dev_key_t *)arg, sizeof(struct fp_dev_key_t))) { + LOG_MSG_DEBUG(ERR_LOG, "[%s] copy key fail?\n",__func__); + retval = -EFAULT; + } else { + retval = silfp_keyevent(fp_dev,&key); + } + break; + + case SIFP_IOC_SCR_STATUS: + if (arg) { + LOG_MSG_DEBUG(INFO_LOG, "[IOC_SCR_STATUS] put v = %d\n",(u8)(!fp_dev->scr_off)); + retval = __put_user((u8)(!fp_dev->scr_off), (__u8 __user *)arg); + } else { + LOG_MSG_DEBUG(INFO_LOG, "[IOC_SCR_STATUS] send v = %d\n",(u8)(!fp_dev->scr_off)); + silfp_netlink_send(fp_dev, fp_dev->scr_off?SIFP_NETLINK_SCR_OFF:SIFP_NETLINK_SCR_ON); + } + break; + + case SIFP_IOC_GET_VER: + if ( copy_to_user((void __user *)arg, (void *)FP_DEV_VERSION, sizeof(char)*7)) { + LOG_MSG_DEBUG(ERR_LOG, "[IOC_GET_VER] copy_to fail\n"); + retval = -EFAULT; + } + break; + + case SIFP_IOC_SET_KMAP: + if (!arg) { + retval = -EFAULT; + break; + } + if (copy_from_user(&fp_dev->keymap_cust.k, (void __user *)arg, sizeof(struct fp_dev_kmap_t))) { + LOG_MSG_DEBUG(ERR_LOG, "[IOC_SET_KMAP] copy_from fail\n"); + retval = -EFAULT; + break; + } + + if (silfp_input_reinit(fp_dev)) { + retval = -EFAULT; + } + break; + + case SIFP_IOC_ACQ_SPI: + LOG_MSG_DEBUG(INFO_LOG, "[%s] acq spi\n", __func__); + retval = silfp_set_spi(fp_dev,true); + break; + + case SIFP_IOC_RLS_SPI: + LOG_MSG_DEBUG(INFO_LOG, "[%s] release spi\n", __func__); + retval = silfp_set_spi(fp_dev,false); + break; + + case SIFP_IOC_PKG_SIZE: + if (arg) { + LOG_MSG_DEBUG(DBG_LOG, "[IOC_PKG_SIZE] %d\n",(u8)(PKG_SIZE)); + retval = __put_user((u8)(PKG_SIZE), (__u8 __user *)arg); + } + break; + + case SIFP_IOC_DBG_LEVEL: + if (arg) { + unsigned char level = 0; + if (copy_from_user(&level, (void __user *)arg, sizeof(char)) || level > (uint8_t)ALL_LOG ) { + retval = -EFAULT; + break; + } + LOG_MSG_DEBUG(ERR_LOG, "debug level %d-->%d\n",debug_level,level); + retval = __put_user((u8)(debug_level), (__u8 __user *)arg); + debug_level = (fp_debug_level_t)level; + } + break; + + case SIFP_IOC_WAKELOCK: + if (arg) { + unsigned char lock = 0; + if (copy_from_user(&lock, (void __user *)arg, sizeof(char))) { + LOG_MSG_DEBUG(ERR_LOG, "[SIFP_IOC_WAKELOCK] copy_from fail\n"); + retval = -EFAULT; + break; + } + silfp_wakelock_ctl(fp_dev, lock); + } + break; + + case SIFP_IOC_PWDN: + if (arg) { + unsigned char flag_avdd = 0; + if (copy_from_user(&flag_avdd, (void __user *)arg, sizeof(char))) { + LOG_MSG_DEBUG(ERR_LOG, "[SIFP_IOC_PWDN] copy_from fail\n"); + retval = -EFAULT; + break; + } + silfp_pwdn(fp_dev, flag_avdd); + } else { + silfp_pwdn(fp_dev, SIFP_PWDN_NONE); + } + + break; + +#ifdef PROC_NODE + case SIFP_IOC_PROC_NODE: + if (arg) { + if (copy_from_user(vendor_name, (void __user *)arg, PROC_VND_ID_LEN)) { + LOG_MSG_DEBUG(ERR_LOG, "[SIFP_IOC_PROC_NODE] copy_from fail\n"); + retval = -EFAULT; + break; + } + retval = silfp_proc_create_node(fp_dev); + } + break; +#endif /* PROC_NODE */ + + case SIFP_IOC_GET_TP_TOUCH_INFO: + LOG_MSG_DEBUG(ERR_LOG, "[SIFP_IOC_GET_TP_TOUCH_INFO]enter\n"); + if (arg) { + if (copy_to_user((void __user *)arg, (void *)&fp_tpinfo, sizeof(fp_tpinfo))) { + LOG_MSG_DEBUG(ERR_LOG, "[SIFP_IOC_GET_TP_TOUCH_INFO] copy_to fail\n"); + retval = -EFAULT; + } + } + break; + case SIFP_IOC_SET_TP_MSG_REPORT_MODE: + LOG_MSG_DEBUG(INFO_LOG, "[SET_TP_MSG_REPORT_MODE]enter,arg =%d,lasttouchmode=%d\n", (int)arg, (int)lasttouchmode); + if(1 == lasttouchmode) { + lasttouchmode = arg;//arg =0 + LOG_MSG_DEBUG(INFO_LOG, " success lasttouchmode = %d\n", lasttouchmode); + } else { + LOG_MSG_DEBUG(ERR_LOG, "arg null,or mode is 0, do nothing!\n"); + } + break; + + case SIFP_IOC_REPORT_KEY: + LOG_MSG_DEBUG(INFO_LOG, "[SIFP_IOC_REPORT_KEY]enter,arg =%d\n", (int)arg); + input_report_key(fp_dev->input, KEY_F2, 1); + input_sync(fp_dev->input); + input_report_key(fp_dev->input, KEY_F2, 0); + input_sync(fp_dev->input); + break; + default: + retval = -ENOTTY; + break; + } + + return retval; +} + +#ifdef CONFIG_COMPAT +static long +silfp_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + return silfp_ioctl(filp, cmd, (unsigned long)compat_ptr(arg)); +} +#else +#define silfp_compat_ioctl NULL +#endif /* CONFIG_COMPAT */ + +static int silfp_open(struct inode *inode, struct file *filp) +{ + struct silfp_data *fp_dev; + int status = -ENXIO; + + mutex_lock(&device_list_lock); + + list_for_each_entry(fp_dev, &device_list, device_entry) { + if (fp_dev->devt == inode->i_rdev) { + status = 0; + break; + } + } + if (status == 0) { + fp_dev->users++; + filp->private_data = fp_dev; + nonseekable_open(inode, filp); + } else { + LOG_MSG_DEBUG(ERR_LOG, "silfp: nothing for minor %d\n", iminor(inode)); + } + + mutex_unlock(&device_list_lock); + + return status; +} + +static int silfp_release(struct inode *inode, struct file *filp) +{ + struct silfp_data *fp_dev; + int status = 0; + + mutex_lock(&device_list_lock); + fp_dev = filp->private_data; + filp->private_data = NULL; + + /* last close? */ + fp_dev->users--; + if (!fp_dev->users) { + int dofree = 0; + + if (dofree) + kfree(fp_dev); + } + mutex_unlock(&device_list_lock); + + return status; +} + +static const struct file_operations silfp_dev_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 = silfp_ioctl, + .compat_ioctl = silfp_compat_ioctl, + .open = silfp_open, + .release = silfp_release, +#ifndef BSP_SIL_NETLINK + .read = silfp_read, + .poll = silfp_poll, +#endif /* !BSP_SIL_NETLINK */ +}; + +/*-------------------------------------------------------------------------*/ + +/* The main reason to have this class is to make mdev/udev create the + * /dev/spidevB.C character device nodes exposing our userspace API. + * It also simplifies memory management. + */ + +/*-------------------------------------------------------------------------*/ + +static int silfp_probe(struct platform_device *spi) +{ + struct silfp_data *fp_dev; + int status = 0; + //unsigned long minor; + + LOG_MSG_DEBUG(INFO_LOG, "[%s] enter.\n", __func__); + + LOG_MSG_DEBUG(INFO_LOG, "[%s] find silfp fingerprint.\n", __func__); + + /* Allocate driver data */ + fp_dev = kzalloc(sizeof(*fp_dev), GFP_KERNEL); + if (!fp_dev) { + return -ENOMEM; + } + + /* Initialize the driver data */ + fp_dev->spi = spi; + spin_lock_init(&fp_dev->spi_lock); + + wake_lock_init(&fp_dev->wakelock,WAKE_LOCK_SUSPEND,"silfp_wakelock"); + wake_lock_init(&fp_dev->wakelock_hal,WAKE_LOCK_SUSPEND,"silfp_wakelock_hal"); + INIT_LIST_HEAD(&fp_dev->device_entry); + + /* If we can allocate a minor number, hook up this device. + * Reusing minors is fine so long as udev or mdev is working. + */ + + if (FP_DEV_MAJOR > 0) { + fp_dev->devt = MKDEV(FP_DEV_MAJOR, fp_dev->ref++); + status = register_chrdev_region(fp_dev->devt, 1, FP_DEV_NAME); + } else { + status = alloc_chrdev_region(&fp_dev->devt, fp_dev->ref++, 1, FP_DEV_NAME); + } + if (status < 0) { + LOG_MSG_DEBUG(ERR_LOG, "[%s] request devt fail, ret=%d.\n", __func__, status); + goto err_devt; + } else { + LOG_MSG_DEBUG(INFO_LOG, "[%s], major=%d, minor=%d\n", __func__, MAJOR(fp_dev->devt), MINOR(fp_dev->devt)); + } + + fp_dev->dev = device_create(silfp_class, &fp_dev->spi->dev, fp_dev->devt, fp_dev, FP_DEV_NAME); + if (IS_ERR(fp_dev->dev)) { + LOG_MSG_DEBUG(ERR_LOG, "[%s] device_create() fail.\n", __func__); + status = -ENODEV; + goto err_dev; + } else { + mutex_lock(&device_list_lock); + list_add(&fp_dev->device_entry, &device_list); + mutex_unlock(&device_list_lock); + LOG_MSG_DEBUG(INFO_LOG, "[%s] device create success.\n", __func__); + } + + cdev_init(&fp_dev->cdev, &silfp_dev_fops); + fp_dev->cdev.owner = THIS_MODULE; + status = cdev_add(&fp_dev->cdev, fp_dev->devt, 1); + if (status) { + LOG_MSG_DEBUG(ERR_LOG, "[%s] cdev_add() fail, ret=%d.\n", __func__, status); + goto err_cdev; + } + + atomic_set(&fp_dev->init,0); + status = silfp_init(fp_dev); + if (status) { + LOG_MSG_DEBUG(ERR_LOG, "[%s] silfp_init fail ret=%d.\n", __func__, status); + goto err_cdev; + } +#ifdef PROC_NODE + silfp_proc_init(fp_dev); +#endif /* PROC_NODE */ + platform_set_drvdata(spi, fp_dev); + optical_fp = fp_dev; + + status = sysfs_create_group(&spi->dev.kobj, + &sl_attribute_group); + if (status) + pr_err("%s:could not create sysfs\n", __func__); + return status; + +err_cdev: + list_del(&fp_dev->device_entry); + +err_dev: + unregister_chrdev_region(fp_dev->devt, 1); + +err_devt: + platform_set_drvdata(spi, NULL); + fp_dev->spi = NULL; + kfree(fp_dev); + fp_dev = NULL; + + return status; +} + +static int silfp_remove(struct platform_device *spi) +{ + struct silfp_data *fp_dev = platform_get_drvdata(spi); + + wake_lock_destroy(&fp_dev->wakelock); + wake_lock_destroy(&fp_dev->wakelock_hal); + /* make sure ops on existing fds can abort cleanly */ + spin_lock_irq(&fp_dev->spi_lock); + fp_dev->spi = NULL; + spin_unlock_irq(&fp_dev->spi_lock); + + silfp_exit(fp_dev); + /* prevent new opens */ + mutex_lock(&device_list_lock); + list_del(&fp_dev->device_entry); + device_destroy(silfp_class, fp_dev->devt); + if (fp_dev->users == 0) + kfree(fp_dev); + mutex_unlock(&device_list_lock); + + return 0; +} + +static const struct of_device_id sildev_dt_ids[] = { + { .compatible = "sil,silead_fp" }, + { .compatible = "sil,silead-fp" }, + { .compatible = "sil,fingerprint" }, + { .compatible = "sil,silead_fp-pins" }, + {}, +}; + +MODULE_DEVICE_TABLE(of, sildev_dt_ids); + +static struct platform_driver silfp_driver = { + .driver = { + .name = "silead_fp", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(sildev_dt_ids), + }, + .probe = silfp_probe, + .remove = silfp_remove, + + /* NOTE: suspend/resume methods are not necessary here. + * We don't do anything except pass the requests to/from + * the underlying controller. The refrigerator handles + * most issues; the controller driver handles the rest. + */ +}; + +/*-------------------------------------------------------------------------*/ + +static int __init silfp_dev_init(void) +{ + int status = 0; + + LOG_MSG_DEBUG(ERR_LOG, "SILEAD_FP Driver, Version: %s.\n", FP_DEV_VERSION); + /* 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 != 0x05)) + return 0; + status = register_chrdev(FP_DEV_MAJOR, "sil", &silfp_dev_fops); + if (status < 0) { + return status; + } + + silfp_class = class_create(THIS_MODULE, "silead_fp"); + if (IS_ERR(silfp_class)) { + unregister_chrdev(FP_DEV_MAJOR, silfp_driver.driver.name); + return PTR_ERR(silfp_class); + } + + status = platform_driver_register(&silfp_driver); + if (status < 0) { + class_destroy(silfp_class); + unregister_chrdev(FP_DEV_MAJOR, silfp_driver.driver.name); + LOG_MSG_DEBUG(ERR_LOG, "[%s] spi_register_driver fail ret=%d.\n", __func__, status); + return status; + } + silfp_wq = create_singlethread_workqueue("silfp_wq"); + return status; +} +module_init(silfp_dev_init); + +static void __exit silfp_dev_exit(void) +{ + platform_driver_unregister(&silfp_driver); + class_destroy(silfp_class); + unregister_chrdev(FP_DEV_MAJOR, silfp_driver.driver.name); +} + +module_exit(silfp_dev_exit); + +MODULE_AUTHOR("Bill Yu "); +MODULE_DESCRIPTION("Silead Fingerprint driver for GSL61XX/GSL62XX series."); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("sil:silead_fp"); diff --git a/drivers/oneplus/drivers/input/fingerprint/silead/silead_fp_qcom.c b/drivers/oneplus/drivers/input/fingerprint/silead/silead_fp_qcom.c new file mode 100755 index 000000000000..78880057d8c9 --- /dev/null +++ b/drivers/oneplus/drivers/input/fingerprint/silead/silead_fp_qcom.c @@ -0,0 +1,606 @@ +/* + * @file silead_fp_qcom.c + * @brief Contains silead_fp device implements for Qualcomm platform. + * + * + * Copyright 2016-2018 Slead Inc. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + * + * ------------------- Revision History ------------------------------ + * + * Bill Yu 2018/5/2 0.1.0 Init version + * Bill Yu 2018/5/20 0.1.1 Default wait 3ms after reset + * Bill Yu 2018/6/5 0.1.2 Support chip enter power down + * + */ + +#ifdef BSP_SIL_PLAT_QCOM + +#ifndef __SILEAD_FP_QCOM__ +#define __SILEAD_FP_QCOM__ + +#include + +#ifndef INIT_COMPLETION +#define INIT_COMPLETION(x) ((x).done = 0) +#endif /* INIT_COMPLETION */ +/* Qualcomm MNC platform, need define this. */ +#define reinit_completion(x) INIT_COMPLETION(*(x)) + +#define SPI_PINCTRL_STATE_DEFAULT "spi_default" +#define SPI_PINCTRL_STATE_SLEEP "spi_sleep" + +static irqreturn_t silfp_irq_handler(int irq, void *dev_id); +static void silfp_work_func(struct work_struct *work); +static int silfp_input_init(struct silfp_data *fp_dev); + +int sl_pinctrl_init(struct silfp_data *fp_dev) +{ + int ret = 0; + struct device *dev = &fp_dev->spi->dev; + + fp_dev->sl_pinctrl = devm_pinctrl_get(dev); + if (IS_ERR_OR_NULL(fp_dev->sl_pinctrl)) { + dev_err(dev, "Target does not use pinctrl\n"); + ret = PTR_ERR(fp_dev->sl_pinctrl); + goto err; + } + + fp_dev->gpio_state_enable = + pinctrl_lookup_state(fp_dev->sl_pinctrl, "fp_en_init"); + if (IS_ERR_OR_NULL(fp_dev->gpio_state_enable)) { + dev_err(dev, "Cannot get active pinstate\n"); + ret = PTR_ERR(fp_dev->gpio_state_enable); + goto err; + } + + ret = pinctrl_select_state(fp_dev->sl_pinctrl, + fp_dev->gpio_state_enable); + if (ret) { + pr_err("can not set %s pins\n", "fp_en_init"); + goto err; + } + + return 0; +err: + fp_dev->sl_pinctrl = NULL; + fp_dev->gpio_state_enable = NULL; + return ret; +} + +/* -------------------------------------------------------------------- */ +/* power supply */ +/* -------------------------------------------------------------------- */ +static void silfp_hw_poweron(struct silfp_data *fp_dev) +{ + int err = 0; + LOG_MSG_DEBUG(INFO_LOG, "[%s] enter.\n", __func__); + +#ifdef BSP_SIL_POWER_SUPPLY_REGULATOR + /* Power control by Regulators(LDO) */ + if ( fp_dev->avdd_ldo ) { + err = regulator_set_voltage(fp_dev->avdd_ldo, + AVDD_MIN, AVDD_MAX); /*set 2.8v*/ + err = regulator_set_load(fp_dev->avdd_ldo, CURRENT); + if (err < 0) + LOG_MSG_DEBUG(INFO_LOG, + "poweron: vreg mode(err:%d)\n", err); + err = regulator_enable(fp_dev->avdd_ldo); /*enable regulator*/ + //pmic_set_register_value(PMIC_RG_VCAMA_CAL,0x0A); + } + if (fp_dev->vddio_ldo) { + err = regulator_set_voltage(fp_dev->vddio_ldo, + VDDIO_MIN, VDDIO_MAX); /*set 1.8v*/ + err = regulator_set_load(fp_dev->vddio_ldo, 200000);//100ma + if (err < 0) + LOG_MSG_DEBUG(INFO_LOG, + "poweron: vreg mode(err:%d)\n", err); + err = regulator_enable(fp_dev->vddio_ldo); /*enable regulator*/ + //pmic_set_register_value(PMIC_RG_VCAMA_CAL,0x0A); + } +#endif /* BSP_SIL_POWER_SUPPLY_REGULATOR */ + +#ifdef BSP_SIL_POWER_SUPPLY_PINCTRL + /* Power control by GPIOs */ + if ( fp_dev->pin.pins_avdd_h ) { + err = pinctrl_select_state(fp_dev->pin.pinctrl, fp_dev->pin.pins_avdd_h); + } + if ( fp_dev->pin.pins_vddio_h ) { + err = pinctrl_select_state(fp_dev->pin.pinctrl, fp_dev->pin.pins_vddio_h); + } +#endif /* BSP_SIL_POWER_SUPPLY_PINCTRL */ + +#ifdef BSP_SIL_POWER_SUPPLY_GPIO + if ( fp_dev->avdd_port > 0 ) { + err = gpio_direction_output(fp_dev->avdd_port, 1); + } + if ( fp_dev->vddio_port > 0 ) { + err = gpio_direction_output(fp_dev->vddio_port, 1); + } +#endif /* BSP_SIL_POWER_SUPPLY_GPIO */ + fp_dev->power_is_off = 0; + LOG_MSG_DEBUG(INFO_LOG, "%s: power supply ret:%d \n", __func__, err); +} + +static void silfp_hw_poweroff(struct silfp_data *fp_dev) +{ + int err = 0; + + LOG_MSG_DEBUG(INFO_LOG, "[%s] enter.\n", __func__); +#ifdef BSP_SIL_POWER_SUPPLY_REGULATOR + /* Power control by Regulators(LDO) */ + if ((fp_dev->power_is_off == 0) && + fp_dev->avdd_ldo && + (regulator_is_enabled(fp_dev->avdd_ldo) > 0)) { + regulator_disable(fp_dev->avdd_ldo); /*disable regulator*/ + err = regulator_set_load(fp_dev->avdd_ldo, 0); + if (err < 0) + LOG_MSG_DEBUG(INFO_LOG, + "poweroff: vreg mode(err:%d)\n", err); + } + if ((fp_dev->power_is_off == 0) && + fp_dev->vddio_ldo && + (regulator_is_enabled(fp_dev->vddio_ldo) > 0)) { + regulator_disable(fp_dev->vddio_ldo); /*disable regulator*/ + err = regulator_set_load(fp_dev->vddio_ldo, 0); + if (err < 0) + LOG_MSG_DEBUG(INFO_LOG, + "poweroff: vreg mode(err:%d)\n", err); + } +#endif /* BSP_SIL_POWER_SUPPLY_REGULATOR */ + +#ifdef BSP_SIL_POWER_SUPPLY_PINCTRL + /* Power control by GPIOs */ + //fp_dev->pin.pins_avdd_h = NULL; + //fp_dev->pin.pins_vddio_h = NULL; +#endif /* BSP_SIL_POWER_SUPPLY_PINCTRL */ + +#ifdef BSP_SIL_POWER_SUPPLY_GPIO + if ( fp_dev->avdd_port > 0 ) { + gpio_direction_output(fp_dev->avdd_port, 0); + } + if ( fp_dev->vddio_port > 0 ) { + gpio_direction_output(fp_dev->vddio_port, 0); + } +#endif /* BSP_SIL_POWER_SUPPLY_GPIO */ + fp_dev->power_is_off = 1; +} + +static void silfp_power_deinit(struct silfp_data *fp_dev) +{ + int err = 0; + + LOG_MSG_DEBUG(INFO_LOG, "[%s] enter.\n", __func__); +#ifdef BSP_SIL_POWER_SUPPLY_REGULATOR + /* Power control by Regulators(LDO) */ + if (fp_dev->avdd_ldo) { + regulator_disable(fp_dev->avdd_ldo); /*disable regulator*/ + err = regulator_set_load(fp_dev->avdd_ldo, 0); + if (err < 0) + LOG_MSG_DEBUG(INFO_LOG, + "deinit: vreg mode(err:%d)\n", err); + regulator_put(fp_dev->avdd_ldo); + fp_dev->avdd_ldo = NULL; + } + if (fp_dev->vddio_ldo) { + regulator_disable(fp_dev->vddio_ldo); /*disable regulator*/ + err = regulator_set_load(fp_dev->vddio_ldo, 0); + if (err < 0) + LOG_MSG_DEBUG(INFO_LOG, + "deinit: Failed vreg mode(err:%d)\n", err); + regulator_put(fp_dev->vddio_ldo); + fp_dev->vddio_ldo = NULL; + } +#endif /* BSP_SIL_POWER_SUPPLY_REGULATOR */ + +#ifdef BSP_SIL_POWER_SUPPLY_PINCTRL + /* Power control by GPIOs */ + fp_dev->pin.pins_avdd_h = NULL; + fp_dev->pin.pins_vddio_h = NULL; +#endif /* BSP_SIL_POWER_SUPPLY_PINCTRL */ + +#ifdef BSP_SIL_POWER_SUPPLY_GPIO + if ( fp_dev->avdd_port > 0 ) { + gpio_direction_output(fp_dev->avdd_port, 0); + gpio_free(fp_dev->avdd_port); + fp_dev->avdd_port = 0; + } + if ( fp_dev->vddio_port > 0 ) { + gpio_direction_output(fp_dev->vddio_port, 0); + gpio_free(fp_dev->vddio_port); + fp_dev->vddio_port = 0; + } +#endif /* BSP_SIL_POWER_SUPPLY_GPIO */ +} + +/* -------------------------------------------------------------------- */ +/* hardware reset */ +/* -------------------------------------------------------------------- */ +static void silfp_hw_reset(struct silfp_data *fp_dev, u8 delay) +{ + LOG_MSG_DEBUG(INFO_LOG, + "[%s] enter, port=%d\n", __func__, fp_dev->rst_port); + + if (fp_dev->rst_port > 0) { + gpio_direction_output(fp_dev->rst_port, 0); + mdelay((delay?delay:1)*RESET_TIME_MULTIPLE); + gpio_direction_output(fp_dev->rst_port, 1); + + mdelay((delay?delay:1)*RESET_TIME_MULTIPLE); + } +} + +/* -------------------------------------------------------------------- */ +/* power down */ +/* -------------------------------------------------------------------- */ +static void silfp_pwdn(struct silfp_data *fp_dev, u8 flag_avdd) +{ + LOG_MSG_DEBUG(INFO_LOG, "[%s] enter, port=%d\n", __func__, fp_dev->rst_port); + + if (SIFP_PWDN_FLASH == flag_avdd) { + silfp_hw_poweroff(fp_dev); + msleep(200*RESET_TIME_MULTIPLE); + silfp_hw_poweron(fp_dev); + } + if ( fp_dev->rst_port > 0 ) { + gpio_direction_output(fp_dev->rst_port, 0); + } + + if (SIFP_PWDN_POWEROFF == flag_avdd) { + silfp_hw_poweroff(fp_dev); + } +} + +/* -------------------------------------------------------------------- */ +/* init/deinit functions */ +/* -------------------------------------------------------------------- */ +static int silfp_parse_dts(struct silfp_data* fp_dev) +{ + int ret; +#ifndef QSEE_V4 + /* Get the pinctrl node */ + fp_dev->pin.pinctrl = devm_pinctrl_get(&fp_dev->spi->dev); + if (IS_ERR_OR_NULL(fp_dev->pin.pinctrl)) { + LOG_MSG_DEBUG(ERR_LOG, "%s: Failed to get pinctrl\n", __func__); + return PTR_ERR(fp_dev->pin.pinctrl); + } + + /* Get the active setting */ + fp_dev->pin.active = pinctrl_lookup_state(fp_dev->pin.pinctrl, SPI_PINCTRL_STATE_DEFAULT); + if (IS_ERR_OR_NULL(fp_dev->pin.active)) { + fp_dev->pin.active = NULL; + fp_dev->pin.pinctrl = NULL; + LOG_MSG_DEBUG(ERR_LOG, "%s: Failed to get pinctrl state active\n",__func__); + return PTR_ERR(fp_dev->pin.active); + } + + /* Get power settings */ +#ifdef BSP_SIL_POWER_SUPPLY_PINCTRL + fp_dev->pin.pins_avdd_h = pinctrl_lookup_state(fp_dev->pin.pinctrl, "avdd-enable"); + if (IS_ERR_OR_NULL(fp_dev->pin.pins_avdd_h)) { + fp_dev->pin.pins_avdd_h = NULL; + LOG_MSG_DEBUG(ERR_LOG, "%s can't find silfp avdd-enable\n", __func__); + // Ignore error + } + + fp_dev->pin.pins_vddio_h = pinctrl_lookup_state(fp_dev->pin.pinctrl, "vddio-enable"); + if (IS_ERR_OR_NULL(fp_dev->pin.pins_vddio_h)) { + fp_dev->pin.pins_vddio_h = NULL; + LOG_MSG_DEBUG(ERR_LOG, "%s can't find silfp vddio-enable\n", __func__); + // Ignore error + } +#endif /* BSP_SIL_POWER_SUPPLY_PINCTRL */ +#endif /* QSEE_V4 */ + +#ifdef BSP_SIL_POWER_SUPPLY_REGULATOR + // Todo: use correct settings. + fp_dev->avdd_ldo = regulator_get(&fp_dev->spi->dev, "avdd"); + // fp_dev->vddio_ldo= regulator_get(&fp_dev->spi->dev, "vddio"); +#endif /* BSP_SIL_POWER_SUPPLY_REGULATOR */ + +#ifndef QSEE_V4 + /* Get sleep settings */ + fp_dev->pin.sleep = pinctrl_lookup_state(fp_dev->pin.pinctrl, SPI_PINCTRL_STATE_SLEEP); + if (IS_ERR_OR_NULL(fp_dev->pin.sleep)) { + fp_dev->pin.active = NULL; + fp_dev->pin.pinctrl = NULL; + LOG_MSG_DEBUG(ERR_LOG, "%s: Failed to get pinctrl state sleep\n",__func__); + return PTR_ERR(fp_dev->pin.sleep); + } + + /* Get iface_clk info */ + fp_dev->pin.iface_clk = clk_get(&fp_dev->spi->dev, "iface_clk"); + if (IS_ERR(fp_dev->pin.iface_clk)) { + fp_dev->pin.active = NULL; + fp_dev->pin.pinctrl = NULL; + LOG_MSG_DEBUG(ERR_LOG, "%s: Failed to get iface_clk %ld\n", __func__, PTR_ERR(fp_dev->pin.iface_clk)); + return PTR_ERR(fp_dev->pin.iface_clk); + } + + /* Get core_clk info */ + fp_dev->pin.core_clk = clk_get(&fp_dev->spi->dev, "core_clk"); + if (IS_ERR(fp_dev->pin.core_clk)) { + fp_dev->pin.active = NULL; + fp_dev->pin.pinctrl = NULL; + LOG_MSG_DEBUG(ERR_LOG, "%s: Failed to get core_clk %p\n", __func__, fp_dev->pin.core_clk); + return PTR_ERR(fp_dev->pin.core_clk); + } +#else + /* Get the SPI Max speed */ + ret = of_property_read_u32(fp_dev->spi->dev.of_node,"spi-max-frequency", &fp_dev->pin.max_speed_hz); + if (ret) { + fp_dev->pin.max_speed_hz = 0; + LOG_MSG_DEBUG(ERR_LOG, "Error getting spi max speed\n"); + } +#endif /* QSEE_V4 */ + + /* Get the QUP ID (#1-12) */ + ret = of_property_read_u32(fp_dev->spi->dev.of_node,"qcom,qup-id", &fp_dev->pin.qup_id); + if (ret) { + fp_dev->pin.qup_id = 0; + LOG_MSG_DEBUG(ERR_LOG, "Error getting qup_id\n"); + } + + LOG_MSG_DEBUG(INFO_LOG, "[%s] done (%d).\n",__func__,ret); + /* + Grab SPI master lock for exclusive access + call spi_bus_unlock to unlock the lock. + */ + //spi_bus_lock(fp_dev->spi->master); + return ret; +} + +#ifndef QSEE_V4 +static int spi_set_pinctrl(struct silfp_data* fp_dev, bool active) +{ + int ret = -1; + + if ( IS_ERR_OR_NULL(fp_dev->pin.pinctrl) || IS_ERR_OR_NULL(fp_dev->pin.active)) { + LOG_MSG_DEBUG(ERR_LOG, "%s: not support\n", __func__); + return ret; + } + if (active) { /* Change to active settings */ + ret = pinctrl_select_state(fp_dev->pin.pinctrl, fp_dev->pin.active); + } else { + ret = pinctrl_select_state(fp_dev->pin.pinctrl, fp_dev->pin.sleep); + } + + LOG_MSG_DEBUG(INFO_LOG, "%s: pinctrl_select_state ret:%d Setting:%d\n", __func__, ret, active); + return ret; +} + +static int spi_set_clks(struct silfp_data* fp_dev, bool enable) +{ + int ret = -1; + int clk = 19200000; + + if ( IS_ERR_OR_NULL(fp_dev->pin.pinctrl) || IS_ERR_OR_NULL(fp_dev->pin.active)) { + LOG_MSG_DEBUG(INFO_LOG, "%s: not support\n", __func__); + return ret; + } + if (enable) { + /* Enable the spi clocks */ + ret = clk_set_rate(fp_dev->pin.core_clk, fp_dev->spi->max_speed_hz); + if (ret) { + while ( clk > fp_dev->spi->max_speed_hz ) { + clk >>= 1; + } + if ( clk < 4800000 ) { + clk = 4800000; + } + ret = clk_set_rate(fp_dev->pin.core_clk, clk); + if ( ret ) { + LOG_MSG_DEBUG(ERR_LOG, "%s: Error setting clk_rate:%d, ret=%d\n",__func__, clk,ret); + } else { + fp_dev->spi->max_speed_hz = clk; + } + } + ret = clk_prepare_enable(fp_dev->pin.core_clk); + if (ret) { + LOG_MSG_DEBUG(ERR_LOG, "%s: Error enabling core clk, ret=%d\n",__func__,ret); + } + ret = clk_prepare_enable(fp_dev->pin.iface_clk); + if (ret) { + LOG_MSG_DEBUG(ERR_LOG, "%s: Error enabling iface clk, ret=%d\n",__func__,ret); + } + } else { + /* Disable the clocks */ + clk_disable_unprepare(fp_dev->pin.iface_clk); + clk_disable_unprepare(fp_dev->pin.core_clk); + ret = 0; + } + + LOG_MSG_DEBUG(DBG_LOG, "[%s] done (%d), speed = %d.\n",__func__,ret,fp_dev->spi->max_speed_hz ); + return ret; +} + +static int spi_set_fabric(struct silfp_data* fp_dev, bool active) +{ + int ret; + struct spi_master *master = fp_dev->spi->master; + + if (active) { + ret = master->prepare_transfer_hardware(master); + } else { + ret = master->unprepare_transfer_hardware(master); + } + LOG_MSG_DEBUG(DBG_LOG, "[%s] done (%d).\n",__func__,ret); + return ret; +} +#endif /* !QSEE_V4 */ + +static int silfp_set_spi(struct silfp_data *fp_dev, bool enable) +{ + int ret = -ENOENT; +#ifndef QSEE_V4 + if ( IS_ERR_OR_NULL(fp_dev->pin.pinctrl) || IS_ERR_OR_NULL(fp_dev->pin.active) || !fp_dev->pin.qup_id ) { + LOG_MSG_DEBUG(ERR_LOG, "%s: not support!\n", __func__); + return ret; + } + + if ( enable && !atomic_read(&fp_dev->spionoff_count) ) { + atomic_inc(&fp_dev->spionoff_count); + ret = spi_set_pinctrl(fp_dev, enable); + ret |= spi_set_fabric(fp_dev, enable); + ret |= spi_set_clks(fp_dev, enable); + } else if (atomic_read(&fp_dev->spionoff_count)) { + atomic_dec(&fp_dev->spionoff_count); + //spi_change_pipe_owner(false); + ret = spi_set_clks(fp_dev, enable); + ret |= spi_set_fabric(fp_dev, enable); + ret |= spi_set_pinctrl(fp_dev, enable); + } +#else + LOG_MSG_DEBUG(ERR_LOG, "%s: qsee4 no needed!\n", __func__); +#endif /* !QSEE_V4 */ + return ret; +} + +static int silfp_resource_init(struct silfp_data *fp_dev, struct fp_dev_init_t *dev_info) +{ + int status = 0; + int ret; + + if (atomic_read(&fp_dev->init)) { + atomic_inc(&fp_dev->init); + LOG_MSG_DEBUG(DBG_LOG, "[%s] dev already init(%d).\n",__func__,atomic_read(&fp_dev->init)); + return status; + } + + silfp_parse_dts(fp_dev); +#ifdef BSP_SIL_POWER_SUPPLY_GPIO + fp_dev->avdd_port = of_get_named_gpio(fp_dev->spi->dev.of_node, "avdd-gpios", 0); + fp_dev->vddio_port = of_get_named_gpio(fp_dev->spi->dev.of_node, "vddio-gpios", 0); + if (fp_dev->avdd_port > 0 ) { + gpio_free(fp_dev->avdd_port); + ret = gpio_request(fp_dev->avdd_port, "SILFP_AVDD_PIN"); + if (ret < 0) { + LOG_MSG_DEBUG(ERR_LOG, "[%s] Failed to request GPIO=%d, ret=%d",__func__,(s32)fp_dev->avdd_port, ret); + status = -ENODEV; + goto err_avdd; + } + } + + if (fp_dev->vddio_port > 0 ) { + gpio_free(fp_dev->vddio_port); + ret = gpio_request(fp_dev->vddio_port, "SILFP_VDDIO_PIN"); + if (ret < 0) { + LOG_MSG_DEBUG(ERR_LOG, "[%s] Failed to request GPIO=%d, ret=%d",__func__,(s32)fp_dev->vddio_port, ret); + status = -ENODEV; + goto err_vddio; + } + } +#endif /* BSP_SIL_POWER_SUPPLY_GPIO */ + silfp_hw_poweron(fp_dev); + fp_dev->int_port = of_get_named_gpio(fp_dev->spi->dev.of_node, "irq-gpios", 0); + fp_dev->rst_port = of_get_named_gpio(fp_dev->spi->dev.of_node, "rst-gpios", 0); + LOG_MSG_DEBUG(INFO_LOG, "[%s] int_port %d, rst_port %d.\n",__func__,fp_dev->int_port,fp_dev->rst_port); + if (fp_dev->int_port > 0 ) { + gpio_free(fp_dev->int_port); + } + + if (fp_dev->rst_port > 0 ) { + gpio_free(fp_dev->rst_port); + } + + ret = gpio_request(fp_dev->int_port, "SILFP_INT_IRQ"); + if (ret < 0) { + LOG_MSG_DEBUG(ERR_LOG, "[%s] Failed to request GPIO=%d, ret=%d",__func__,(s32)fp_dev->int_port, ret); + status = -ENODEV; + goto err; + } else { + gpio_direction_input(fp_dev->int_port); + fp_dev->irq = gpio_to_irq(fp_dev->int_port); + fp_dev->irq_is_disable = 0; + + ret = request_irq(fp_dev->irq, + silfp_irq_handler, + IRQ_TYPE_EDGE_RISING, //IRQ_TYPE_LEVEL_HIGH, //irq_table[ts->int_trigger_type], + "silfp", + fp_dev); + if ( ret < 0 ) { + LOG_MSG_DEBUG(ERR_LOG, "[%s] Filed to request_irq (%d), ert=%d",__func__,fp_dev->irq, ret); + status = -ENODEV; + goto err_irq; + } else { + LOG_MSG_DEBUG(INFO_LOG,"[%s] Enable_irq_wake.\n",__func__); + enable_irq_wake(fp_dev->irq); + silfp_irq_disable(fp_dev); + } + } + + if (fp_dev->rst_port > 0 ) { + ret = gpio_request(fp_dev->rst_port, "SILFP_RST_PIN"); + if (ret < 0) { + LOG_MSG_DEBUG(ERR_LOG, "[%s] Failed to request GPIO=%d, ret=%d",__func__,(s32)fp_dev->rst_port, ret); + status = -ENODEV; + goto err_rst; + } else { + gpio_direction_output(fp_dev->rst_port, 0); + } + } + + if (!ret) { + if (silfp_input_init(fp_dev)) { + goto err_input; + } + atomic_set(&fp_dev->init,1); + } + dev_info->reserve = PKG_SIZE; + dev_info->reserve <<= 12; +#ifdef QSEE_V4 + if (fp_dev->pin.max_speed_hz) { + dev_info->speed = fp_dev->pin.max_speed_hz; + } +#endif /* QSEE_V4 */ + + if (dev_info && fp_dev->pin.qup_id && (fp_dev->pin.qup_id < 16)) { + dev_info->dev_id = fp_dev->pin.qup_id; + strncpy(dev_info->ta,TANAME,sizeof(dev_info->ta)); + } + status = sl_pinctrl_init(fp_dev); + if (status < 0) + LOG_MSG_DEBUG(ERR_LOG, "[%s] Failed init gpio %d", + __func__, status); + return status; + +err_input: + if (fp_dev->rst_port > 0 ) { + gpio_free(fp_dev->rst_port); + } + +err_rst: + free_irq(fp_dev->irq, fp_dev); + gpio_direction_input(fp_dev->int_port); + +err_irq: + gpio_free(fp_dev->int_port); + +#ifdef BSP_SIL_POWER_SUPPLY_GPIO + gpio_free(fp_dev->vddio_port); +err_vddio: + gpio_free(fp_dev->avdd_port); + +err_avdd: + fp_dev->avdd_port = 0; + fp_dev->vddio_port = 0; +#endif /* BSP_SIL_POWER_SUPPLY_GPIO */ + +err: + fp_dev->int_port = 0; + fp_dev->rst_port = 0; + + return status; +} + +#endif /* __SILEAD_FP_QCOM__ */ + +#endif /* BSP_SIL_PLAT_QCOM */ + +/* End of file spilead_fp_qcom.c */ diff --git a/drivers/oneplus/drivers/input/fingerprint/silead/silead_fp_qcom.h b/drivers/oneplus/drivers/input/fingerprint/silead/silead_fp_qcom.h new file mode 100755 index 000000000000..c1e02f0a1bf3 --- /dev/null +++ b/drivers/oneplus/drivers/input/fingerprint/silead/silead_fp_qcom.h @@ -0,0 +1,48 @@ +/* + * @file silead_fp_qcom.h + * @brief Contains silead_fp Qualcomm platform specific head file. + * + * + * Copyright 2016-2018 Slead Inc. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + * + * ------------------- Revision History ------------------------------ + * + * Bill Yu 2018/5/2 0.1.0 Init version + * + */ + +#ifndef __SILEAD_FP_QCOM_H__ +#define __SILEAD_FP_QCOM_H__ + +#include +#include +#include + +struct fp_plat_t { + u32 qup_id; +#ifdef QSEE_V4 + u32 max_speed_hz; +#else + /* pinctrl info */ + struct pinctrl *pinctrl; + struct pinctrl_state *active; + struct pinctrl_state *sleep; +#ifdef BSP_SIL_POWER_SUPPLY_PINCTRL + struct pinctrl_state *pins_avdd_h, *pins_vddio_h; +#endif /* BSP_SIL_POWER_SUPPLY_PINCTRL */ + /* clock info */ + struct clk *core_clk; + struct clk *iface_clk; +#endif /* QSEE_V4 */ +}; + +#endif /* __SILEAD_FP_QCOM_H__ */ + +/* End of file silead_fp_qcom.h */ diff --git a/drivers/oneplus/drivers/oem_debug/Makefile b/drivers/oneplus/drivers/oem_debug/Makefile new file mode 100755 index 000000000000..0a8b0fff6d59 --- /dev/null +++ b/drivers/oneplus/drivers/oem_debug/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_OEM_FORCE_DUMP) += oem_force_dump.o diff --git a/drivers/oneplus/drivers/oem_debug/oem_force_dump.c b/drivers/oneplus/drivers/oem_debug/oem_force_dump.c new file mode 100644 index 000000000000..36ac1a7f8157 --- /dev/null +++ b/drivers/oneplus/drivers/oem_debug/oem_force_dump.c @@ -0,0 +1,212 @@ +/* + * 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 + +struct sock *nl_sk; +static int fd = -1; +static struct workqueue_struct *smg_workwq; +static struct work_struct smg_work; + +#define MAX_MSGSIZE 1024 +static int message_state = -1; + + +/* + * 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_VOLUMEDOWN && !value) { + message_state = 2; + queue_work(smg_workwq, &smg_work); + state = NONE; + } else + state = NONE; + break; + } +} + +static void send_msg_worker(struct work_struct *work) +{ + if (message_state == 1) + send_msg("Enable DEBUG!"); + else if (message_state == 2) { + pr_info("force oem serial\n"); + msm_serial_oem_init(); + send_msg("ENABLE_OEM_FORCE_SERIAL"); + } + message_state = 0; +} + +void send_msg(char *message) +{ + struct sk_buff *skb; + struct nlmsghdr *nlh; + int len = NLMSG_SPACE(MAX_MSGSIZE); + + 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/drivers/oem_trace/Makefile b/drivers/oneplus/drivers/oem_trace/Makefile new file mode 100644 index 000000000000..74399025931a --- /dev/null +++ b/drivers/oneplus/drivers/oem_trace/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_OEM_TRACE_SUPPORT) += oem_trace.o diff --git a/drivers/oneplus/drivers/oem_trace/oem_trace.c b/drivers/oneplus/drivers/oem_trace/oem_trace.c new file mode 100755 index 000000000000..19ffdc458d1d --- /dev/null +++ b/drivers/oneplus/drivers/oem_trace/oem_trace.c @@ -0,0 +1,544 @@ +/* + * Copyright (C) 2010 op, Inc. + * Author: Andy + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/*#include */ +#include + +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_CMA +#include +#endif + +#include "oem_trace.h" + + +#define IOCTL_OTRACER_TEST (1<<0) +#define IOCTL_OTRACER_STACK (1<<1) +#define IOCTL_OTRACER_MEMINFO (1<<2) +#define IOCTL_OTRACER_TASKINFO (1<<3) +#define IOCTL_OTRACER_ALLINFO (1<<4) +#define IOCTL_OTRACER_TOLCD (1<<5) + +#define IOCTL_OTRACER_PANIC (1<<12) + +struct vmalloc_info { + unsigned long used; + unsigned long largest_chunk; +}; + + +void backtrace_test_saved(void) +{ + struct stack_trace trace; + unsigned long entries[8]; + + pr_info("\nThe following trace is a kernel self test and not a bug!\n"); + + trace.nr_entries = 0; + trace.max_entries = ARRAY_SIZE(entries); + trace.entries = entries; + trace.skip = 0; + + pr_info("Testing a dump_stack.\n"); + dump_stack(); + pr_info("Testing a print_stack_trace.\n"); + print_stack_trace(&trace, 0); +} + +void tasks_mem_get( +struct mm_struct *mm, unsigned long *vsize, unsigned long *vrss) +{ + unsigned long hiwater_vm, total_vm, hiwater_rss, total_rss; + + hiwater_vm = total_vm = mm->total_vm; + if (hiwater_vm < mm->hiwater_vm) + hiwater_vm = mm->hiwater_vm; + hiwater_rss = total_rss = get_mm_rss(mm); + if (hiwater_rss < mm->hiwater_rss) + hiwater_rss = mm->hiwater_rss; + + *vsize = total_vm << (PAGE_SHIFT-10); + *vrss = total_rss << (PAGE_SHIFT-10); +} + +static char *task_state_array[] = { + "R-0", /* 0 (running) */ + "S-1", /* 1 (sleeping) */ + "D-2", /* 2 (disk sleep) */ + "T-4", /* 4 (stopped) */ + "T-8", /* 8 (tracing stop) */ + "Z-F", /* 16 (zombie) */ + "X-" /* 32 (dead) */ +}; + +static inline const char *get_task_state(struct task_struct *tsk) +{ + unsigned int state = (tsk->state & TASK_REPORT) | tsk->exit_state; + char **p = &task_state_array[0]; + + while (state) { + p++; + state >>= 1; + } + return *p; +} + +void tasks_test_saved(void) +{ + struct task_struct *p; + struct cred *cred = NULL; + struct mm_struct *mm; + unsigned long vsize = 0, vrss = 0; + + pr_info("\nThe following trace is a kernel tasks test and not a bug!\n"); + + pr_info("USER\tPID\tVSIZE\tRSS\tSTATE\tNAME\n"); + write_lock_irq(&tasklist_lock); + for_each_process(p) { + + cred = (struct cred *)get_cred((struct cred *) __task_cred(p)); + + vsize = 0; + vrss = 0; + mm = get_task_mm(p); + + if (mm) + tasks_mem_get(mm, &vsize, &vrss); + + pr_info("%u\t%d\t%ld\t%ld\t%s\t%s\n", + (cred->uid).val, + task_pid_nr(p), + vsize, + vrss, + get_task_state(p), + p->comm); + } + write_unlock_irq(&tasklist_lock); +} + +void meminfo_test_saved(void) +{ +struct sysinfo i; + unsigned long committed; + unsigned long allowed; + long cached; + unsigned long pages[NR_LRU_LISTS]; + int lru; + +/* + * display in kilobytes. + */ +#define K(x) ((x) << (PAGE_SHIFT - 10)) + si_meminfo(&i); + si_swapinfo(&i); + committed = percpu_counter_read_positive(&vm_committed_as); + allowed = ((totalram_pages - hugetlb_total_pages()) + * sysctl_overcommit_ratio / 100) + total_swap_pages; + + cached = global_page_state(NR_FILE_PAGES) - + total_swapcache_pages() - i.bufferram; + if (cached < 0) + cached = 0; + + + for (lru = LRU_BASE; lru < NR_LRU_LISTS; lru++) + pages[lru] = global_page_state(NR_LRU_BASE + lru); + + /* + * Tagged format, for easy grepping and expansion. + */ + pr_info("Meminfo:\n" + "MemTotal: %8lu kB\n" + "MemFree: %8lu kB\n" + "Buffers: %8lu kB\n" + "Cached: %8lu kB\n" + "SwapCached: %8lu kB\n" + "Active: %8lu kB\n" + "Inactive: %8lu kB\n" + "Active(anon): %8lu kB\n" + "Inactive(anon): %8lu kB\n" + "Active(file): %8lu kB\n" + "Inactive(file): %8lu kB\n" + "Unevictable: %8lu kB\n" + "Mlocked: %8lu kB\n" +#ifdef CONFIG_HIGHMEM + "HighTotal: %8lu kB\n" + "HighFree: %8lu kB\n" + "LowTotal: %8lu kB\n" + "LowFree: %8lu kB\n" +#endif +#ifndef CONFIG_MMU + "MmapCopy: %8lu kB\n" +#endif + "SwapTotal: %8lu kB\n" + "SwapFree: %8lu kB\n" + "Dirty: %8lu kB\n" + "Writeback: %8lu kB\n" + "AnonPages: %8lu kB\n" + "Mapped: %8lu kB\n" + "Shmem: %8lu kB\n" + "Slab: %8lu kB\n" + "SReclaimable: %8lu kB\n" + "SUnreclaim: %8lu kB\n" + "KernelStack: %8lu kB\n" + "PageTables: %8lu kB\n" +#ifdef CONFIG_QUICKLIST + "Quicklists: %8lu kB\n" +#endif + "NFS_Unstable: %8lu kB\n" + "Bounce: %8lu kB\n" + "WritebackTmp: %8lu kB\n" + "CommitLimit: %8lu kB\n" + "Committed_AS: %8lu kB\n" + "VmallocTotal: %8lu kB\n" + "VmallocUsed: %8lu kB\n" + "VmallocChunk: %8lu kB\n" +#ifdef CONFIG_MEMORY_FAILURE + "HardwareCorrupted: %5lu kB\n" +#endif +#ifdef CONFIG_TRANSPARENT_HUGEPAGE + "AnonHugePages: %8lu kB\n" +#endif +#ifdef CONFIG_CMA + "CmaTotal: %8lu kB\n" + "CmaFree: %8lu kB\n" +#endif + , + K(i.totalram), + K(i.freeram), + K(i.bufferram), + K(cached), + K(total_swapcache_pages()), + K(pages[LRU_ACTIVE_ANON] + pages[LRU_ACTIVE_FILE]), + K(pages[LRU_INACTIVE_ANON] + pages[LRU_INACTIVE_FILE]), + K(pages[LRU_ACTIVE_ANON]), + K(pages[LRU_INACTIVE_ANON]), + K(pages[LRU_ACTIVE_FILE]), + K(pages[LRU_INACTIVE_FILE]), + K(pages[LRU_UNEVICTABLE]), + K(global_page_state(NR_MLOCK)), +#ifdef CONFIG_HIGHMEM + K(i.totalhigh), + K(i.freehigh), + K(i.totalram-i.totalhigh), + K(i.freeram-i.freehigh), +#endif +#ifndef CONFIG_MMU + K((unsigned long) atomic_long_read(&mmap_pages_allocated)), +#endif + K(i.totalswap), + K(i.freeswap), + K(global_page_state(NR_FILE_DIRTY)), + K(global_page_state(NR_WRITEBACK)), +#ifdef CONFIG_TRANSPARENT_HUGEPAGE + K(global_page_state(NR_PAGETABLE) + + global_page_state(NR_ANON_TRANSPARENT_HUGEPAGES) * + HPAGE_PMD_NR), +#else + K(global_page_state(NR_PAGETABLE)), +#endif + K(global_page_state(NR_FILE_MAPPED)), + K(global_page_state(NR_SHMEM)), + K(global_page_state(NR_SLAB_RECLAIMABLE) + + global_page_state(NR_SLAB_UNRECLAIMABLE)), + K(global_page_state(NR_SLAB_RECLAIMABLE)), + K(global_page_state(NR_SLAB_UNRECLAIMABLE)), + global_page_state(NR_KERNEL_STACK_KB) * THREAD_SIZE / 1024, + K(global_page_state(NR_PAGETABLE)), +#ifdef CONFIG_QUICKLIST + K(quicklist_total_size()), +#endif + K(global_page_state(NR_UNSTABLE_NFS)), + K(global_page_state(NR_BOUNCE)), + K(global_page_state(NR_WRITEBACK_TEMP)), + K(allowed), + K(committed), + (unsigned long)VMALLOC_TOTAL >> 10, + 0ul, /* used to be vmalloc 'used'*/ + 0ul /* used to be vmalloc 'largest_chunk'*/ +#ifdef CONFIG_MEMORY_FAILURE + , atomic_long_read(&num_poisoned_pages) << (PAGE_SHIFT - 10) +#endif +#ifdef CONFIG_TRANSPARENT_HUGEPAGE + , K(global_page_state(NR_ANON_TRANSPARENT_HUGEPAGES) * + HPAGE_PMD_NR) +#endif +#ifdef CONFIG_CMA + , K(totalcma_pages) + , K(global_page_state(NR_FREE_CMA_PAGES)) +#endif + ); +#undef K +} + +int oem_con_write(const unsigned char *buf, int count) +{ + return 0; +} + +void console_activate(void) +{ +} + + +static ssize_t otracer_read(struct file *filp, char __user *buf, + size_t size, loff_t *offp) +{ + pr_info("otracer_read: initialized\n"); + return 0; +} + + +static int otrace_on = -1; + + +bool is_otrace_on(void) +{ + return !!otrace_on; +} +static ssize_t otracer_write(struct file *filp, const char __user *buf, + size_t count, loff_t *offp) +{ + char *kbuf = NULL; + + if (!is_otrace_on()) + return count; + + pr_info("otracer_write\n"); + kbuf = kzalloc(PAGE_SIZE, GFP_KERNEL); + + if (kbuf == NULL) + goto end; + + if (!count) + goto free_buf; + + if (copy_from_user(kbuf, buf, ((count > PAGE_SIZE)?PAGE_SIZE:count))) + goto free_buf; + + oem_con_write(kbuf, ((count > PAGE_SIZE)?PAGE_SIZE:count)); + kfree(kbuf); + + return count; +free_buf: + kfree(kbuf); +end: + pr_info("otracer_write fail!\n"); + return -EFAULT; +} + +static long otracer_ioctl(struct file *filp, + unsigned int cmd, unsigned long arg) +{ + unsigned int cmdv = cmd; + int i; + + cmdv = cmd; + + pr_info("otracer_ioctl: initialized. cmd=0x%x\n", cmd); + + /* + * mwalker give a chance to change reboot + * result to android for android framework. + */ + if (cmd == IOCTL_TRACE_UPDATE_REBOOTFLAG) { + pr_info("android update reboot flag\n"); + goto end; + } + + for (i = 0; i < 16; i++) { + if (cmdv == 0) + break; + + if (cmdv & IOCTL_OTRACER_TOLCD) + cmdv &= (~IOCTL_OTRACER_TOLCD); + + if (cmdv & IOCTL_OTRACER_STACK) { + backtrace_test_saved(); + cmdv &= (~IOCTL_OTRACER_STACK); + } + if (cmdv & IOCTL_OTRACER_MEMINFO) { + meminfo_test_saved(); + cmdv &= (~IOCTL_OTRACER_MEMINFO); + } + if (cmdv & IOCTL_OTRACER_TASKINFO) { + tasks_test_saved(); + cmdv &= (~IOCTL_OTRACER_TASKINFO); + } + if (cmdv & IOCTL_OTRACER_ALLINFO) { + backtrace_test_saved(); + meminfo_test_saved(); + tasks_test_saved(); + cmdv &= (~IOCTL_OTRACER_ALLINFO); + } + if (cmdv & IOCTL_OTRACER_PANIC) { + pr_info("ioctl panic reboot\n"); + panic("android"); + cmdv &= (~IOCTL_OTRACER_PANIC); + } + } +end: + return 0; +} +static int otracer_open(struct inode *inode, struct file *file) +{ + pr_info("%s\n", __func__); + return nonseekable_open(inode, file); +} +static int otracer_close(struct inode *inode, struct file *file) +{ + pr_info("%s\n", __func__); + return 0; +} +static const struct file_operations otracer_fops = { + .owner = THIS_MODULE, + .open = otracer_open, + .release = otracer_close, + .read = otracer_read, + .write = otracer_write, + .unlocked_ioctl = otracer_ioctl, +}; + +static struct miscdevice otracer_misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = "otracer", + .fops = &otracer_fops, +}; +static int otrace_proc_show(struct seq_file *m, void *v) +{ + seq_printf(m, "\notrace_on:%d\n", is_otrace_on()); + return 0; +} +static int otrace_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, otrace_proc_show, NULL); +} +static ssize_t otrace_proc_write(struct file *file, const char __user *buffer, + size_t count, loff_t *pos) +{ + unsigned char *lbuf; + size_t local_count; + unsigned long val; + ssize_t ret; + + if (count <= 0) + return 0; + +#define LBUFSIZE 1200UL + lbuf = kmalloc(LBUFSIZE, GFP_KERNEL); + if (!lbuf) + return 0; + + local_count = (LBUFSIZE - 1) > count?count:(LBUFSIZE - 1); + if (copy_from_user(lbuf, buffer, local_count) != 0) { + kfree(lbuf); + return -EFAULT; + } + + ret = kstrtoul(lbuf, 10, &val); + if (ret) { + kfree(lbuf); + return ret; + } + + if (val == 7978) + otrace_on = 1; + else + otrace_on = 0; + + pr_info("val:%ld, otrace_on:%d\n", val, otrace_on); + + kfree(lbuf); + return count; +} + + + +static const struct file_operations otrace_proc_fops = { + .owner = THIS_MODULE, + .open = otrace_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = otrace_proc_write, +}; + +static struct proc_dir_entry *otrace_entry; +static int __init otracer_init(void) +{ + int ret; + + ret = misc_register(&otracer_misc); + if (unlikely(ret)) { + pr_err("otracer: failed to register misc device!\n"); + return ret; + } + + /* Set up the proc file system */ + otrace_entry = proc_create("otrace_on", 0644, NULL, &otrace_proc_fops); + if (!otrace_entry) { + ret = -ENOMEM; + goto out_misc; + } + + pr_info("otracer: initialized\n"); + + return 0; +out_misc: + misc_deregister(&otracer_misc); + return ret; +} + +static void __exit otracer_exit(void) +{ + + remove_proc_entry("otrace_on", NULL); + + misc_deregister(&otracer_misc); + + pr_info("otracer: exit\n"); +} + +module_init(otracer_init); +module_exit(otracer_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("oem tracer"); +MODULE_AUTHOR("Andy"); + + diff --git a/drivers/oneplus/drivers/oem_trace/oem_trace.h b/drivers/oneplus/drivers/oem_trace/oem_trace.h new file mode 100755 index 000000000000..d7105943d746 --- /dev/null +++ b/drivers/oneplus/drivers/oem_trace/oem_trace.h @@ -0,0 +1,10 @@ +/*add by jiachenghui for support oem trace,2015/05/09*/ +#ifndef _OEM_TRACE_H +#define _OEM_TRACE_H + +#include + +#define IOCTL_TRACE_UPDATE_REBOOTFLAG _IO('t', 3) + + +#endif diff --git a/drivers/oneplus/drivers/param_read_write/Makefile b/drivers/oneplus/drivers/param_read_write/Makefile new file mode 100644 index 000000000000..0c099c5b06e8 --- /dev/null +++ b/drivers/oneplus/drivers/param_read_write/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_PARAM_READ_WRITE) += param_read_write.o diff --git a/drivers/oneplus/drivers/param_read_write/param_read_write.c b/drivers/oneplus/drivers/param_read_write/param_read_write.c new file mode 100644 index 000000000000..9e2cd569ced8 --- /dev/null +++ b/drivers/oneplus/drivers/param_read_write/param_read_write.c @@ -0,0 +1,348 @@ +/* + * 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 + +#define DISABLE_PARAM_DEBUG_LOG + +#define PARAM_PARTITION "/dev/block/bootdevice/by-name/param" +#define READ_CHUNK_MAX_SIZE (1024) +#define WRITE_CHUNK_MAX_SIZE (1024) +static uint default_param_data_dump_size= DEFAULT_PARAM_DUMP_SIZE; + +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; +int restart_08_count; +int restart_other_count; + +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); + +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); + + #ifndef DISABLE_PARAM_DEBUG_LOG + pr_info("%s[%d] sid_index = %d offset = %d buf = %p length = %d\n", + __func__, __LINE__, sid_index, offset, buf, length); + #endif + + 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 int param_get_restart_08_count(char *val, const struct kernel_param *kp) +{ + int cnt; + + 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, 0664); + +static int param_get_restart_other_count(char *val, + const struct kernel_param *kp) +{ + int cnt; + + 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, 0664); + +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_init(void) +{ + int i; + int ret = 0; + + 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); + for (i = 0; i < NUM_PARAM_PLAINTEXT_SEGMENT; i++) { + break;//do not dump param + printk("===dump chunk %d===\n", i); + print_hex_dump (KERN_ERR, "",DUMP_PREFIX_OFFSET,16, 4, + param_ram_zone.buffer +1024*i, default_param_data_dump_size,1); + } + + param_init_done= 1; + + if (misc_register(¶m_misc)) + pr_err("misc_register failure %d\n", ret); + return ret; +} +device_initcall(param_init); diff --git a/drivers/oneplus/drivers/sysrq/Makefile b/drivers/oneplus/drivers/sysrq/Makefile new file mode 100644 index 000000000000..84ab8e66944a --- /dev/null +++ b/drivers/oneplus/drivers/sysrq/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_OEM_DEBUG_SUPPORT) += sysrq_x.o diff --git a/drivers/oneplus/drivers/sysrq/sysrq_x.c b/drivers/oneplus/drivers/sysrq/sysrq_x.c new file mode 100755 index 000000000000..77b5858a44f4 --- /dev/null +++ b/drivers/oneplus/drivers/sysrq/sysrq_x.c @@ -0,0 +1,35 @@ +#include +#include +#include +#include +#include + + +static void sysrq_handle_init_state(int key) +{ + struct task_struct *p = NULL; + + rcu_read_lock(); + for_each_process(p) { + if (p->pid == 1) { + sched_show_task(p); + break; + } + } + rcu_read_unlock(); +} + +static struct sysrq_key_op sysrq_init_state_op = { + .handler = sysrq_handle_init_state, + .help_msg = "show-init-state(x)", + .action_msg = "Show init process state", + .enable_mask = SYSRQ_ENABLE_DUMP, +}; + +static int __init op_sysrq_init(void) +{ + return register_sysrq_key('x', &sysrq_init_state_op); +} + +module_init(op_sysrq_init); + diff --git a/drivers/oneplus/fs/Kconfig b/drivers/oneplus/fs/Kconfig new file mode 100644 index 000000000000..d422a8e412bf --- /dev/null +++ b/drivers/oneplus/fs/Kconfig @@ -0,0 +1,2 @@ +source "drivers/oneplus/fs/exfat/Kconfig" +source "drivers/oneplus/fs/proc/Kconfig" diff --git a/drivers/oneplus/fs/Makefile b/drivers/oneplus/fs/Makefile new file mode 100644 index 000000000000..294d62be4122 --- /dev/null +++ b/drivers/oneplus/fs/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_EXFAT_FS) += exfat/ +obj-$(CONFIG_PROC_FS) += proc/ diff --git a/drivers/oneplus/fs/exfat/Kconfig b/drivers/oneplus/fs/exfat/Kconfig new file mode 100644 index 000000000000..78b32aa2ca19 --- /dev/null +++ b/drivers/oneplus/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/drivers/oneplus/fs/exfat/LICENSE b/drivers/oneplus/fs/exfat/LICENSE new file mode 100644 index 000000000000..d159169d1050 --- /dev/null +++ b/drivers/oneplus/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/drivers/oneplus/fs/exfat/Makefile b/drivers/oneplus/fs/exfat/Makefile new file mode 100644 index 000000000000..711ed87f991b --- /dev/null +++ b/drivers/oneplus/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/drivers/oneplus/fs/exfat/README.md b/drivers/oneplus/fs/exfat/README.md new file mode 100644 index 000000000000..feab40038352 --- /dev/null +++ b/drivers/oneplus/fs/exfat/README.md @@ -0,0 +1,98 @@ +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! + + +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.8 (or whatever version number declared on dkms.conf is) + sudo dkms add -m exfat -v 1.2.8 + +Build and load the module: + + sudo dkms build -m exfat -v 1.2.8 + sudo dkms install -m exfat -v 1.2.8 + +Now you have a proper dkms module that will work for a long time... hopefully. + + + +Free Software for the Free Minds! +================================= diff --git a/drivers/oneplus/fs/exfat/dkms.conf b/drivers/oneplus/fs/exfat/dkms.conf new file mode 100644 index 000000000000..d873c0aef4fa --- /dev/null +++ b/drivers/oneplus/fs/exfat/dkms.conf @@ -0,0 +1,7 @@ +PACKAGE_NAME="exfat" +PACKAGE_VERSION="1.2.8" +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/drivers/oneplus/fs/exfat/exfat-km.mk b/drivers/oneplus/fs/exfat/exfat-km.mk new file mode 100644 index 000000000000..4e3ef07b36ec --- /dev/null +++ b/drivers/oneplus/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/drivers/oneplus/fs/exfat/exfat_api.c b/drivers/oneplus/fs/exfat/exfat_api.c new file mode 100644 index 000000000000..32b29f0dd8d9 --- /dev/null +++ b/drivers/oneplus/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/drivers/oneplus/fs/exfat/exfat_api.h b/drivers/oneplus/fs/exfat/exfat_api.h new file mode 100644 index 000000000000..84bdf612a1e6 --- /dev/null +++ b/drivers/oneplus/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/drivers/oneplus/fs/exfat/exfat_bitmap.c b/drivers/oneplus/fs/exfat/exfat_bitmap.c new file mode 100644 index 000000000000..b0672dd073fc --- /dev/null +++ b/drivers/oneplus/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/drivers/oneplus/fs/exfat/exfat_bitmap.h b/drivers/oneplus/fs/exfat/exfat_bitmap.h new file mode 100644 index 000000000000..4f482c7b28cc --- /dev/null +++ b/drivers/oneplus/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/drivers/oneplus/fs/exfat/exfat_blkdev.c b/drivers/oneplus/fs/exfat/exfat_blkdev.c new file mode 100644 index 000000000000..eaccfd84e9f9 --- /dev/null +++ b/drivers/oneplus/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/drivers/oneplus/fs/exfat/exfat_blkdev.h b/drivers/oneplus/fs/exfat/exfat_blkdev.h new file mode 100644 index 000000000000..3363b591caeb --- /dev/null +++ b/drivers/oneplus/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/drivers/oneplus/fs/exfat/exfat_cache.c b/drivers/oneplus/fs/exfat/exfat_cache.c new file mode 100644 index 000000000000..4130102e3739 --- /dev/null +++ b/drivers/oneplus/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/drivers/oneplus/fs/exfat/exfat_cache.h b/drivers/oneplus/fs/exfat/exfat_cache.h new file mode 100644 index 000000000000..540e31681d04 --- /dev/null +++ b/drivers/oneplus/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/drivers/oneplus/fs/exfat/exfat_config.h b/drivers/oneplus/fs/exfat/exfat_config.h new file mode 100644 index 000000000000..33c6525e449b --- /dev/null +++ b/drivers/oneplus/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/drivers/oneplus/fs/exfat/exfat_core.c b/drivers/oneplus/fs/exfat/exfat_core.c new file mode 100644 index 000000000000..143b72155ef9 --- /dev/null +++ b/drivers/oneplus/fs/exfat/exfat_core.c @@ -0,0 +1,5138 @@ +/* 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"); + else if ((opts->errors == EXFAT_ERRORS_RO) && !(sb->s_flags & MS_RDONLY)) { + sb->s_flags |= MS_RDONLY; + 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/drivers/oneplus/fs/exfat/exfat_core.h b/drivers/oneplus/fs/exfat/exfat_core.h new file mode 100644 index 000000000000..52d05c7007d3 --- /dev/null +++ b/drivers/oneplus/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/drivers/oneplus/fs/exfat/exfat_data.c b/drivers/oneplus/fs/exfat/exfat_data.c new file mode 100644 index 000000000000..65da07aff547 --- /dev/null +++ b/drivers/oneplus/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/drivers/oneplus/fs/exfat/exfat_data.h b/drivers/oneplus/fs/exfat/exfat_data.h new file mode 100644 index 000000000000..53b0e39397fa --- /dev/null +++ b/drivers/oneplus/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/drivers/oneplus/fs/exfat/exfat_nls.c b/drivers/oneplus/fs/exfat/exfat_nls.c new file mode 100644 index 000000000000..a48b3d05a7c4 --- /dev/null +++ b/drivers/oneplus/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/drivers/oneplus/fs/exfat/exfat_nls.h b/drivers/oneplus/fs/exfat/exfat_nls.h new file mode 100644 index 000000000000..bc516d762e90 --- /dev/null +++ b/drivers/oneplus/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/drivers/oneplus/fs/exfat/exfat_oal.c b/drivers/oneplus/fs/exfat/exfat_oal.c new file mode 100644 index 000000000000..743544244ca8 --- /dev/null +++ b/drivers/oneplus/fs/exfat/exfat_oal.c @@ -0,0 +1,196 @@ +/* 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) +{ + struct timespec ts; + time_t second, day, leap_day, month, year; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,8,0) + ts = CURRENT_TIME_SEC; +#else + ktime_get_real_ts(&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/drivers/oneplus/fs/exfat/exfat_oal.h b/drivers/oneplus/fs/exfat/exfat_oal.h new file mode 100644 index 000000000000..b6dd7897ab6e --- /dev/null +++ b/drivers/oneplus/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/drivers/oneplus/fs/exfat/exfat_super.c b/drivers/oneplus/fs/exfat/exfat_super.c new file mode 100644 index 000000000000..ab828c37468e --- /dev/null +++ b/drivers/oneplus/fs/exfat/exfat_super.c @@ -0,0 +1,2697 @@ +/* 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 +#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,8,0) +#define current_time(x) (CURRENT_TIME_SEC) +#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 *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 *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; + } + dir->i_version++; + 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; + } + inode->i_version++; + 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 = dentry->d_parent->d_inode->i_version; + 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 = dentry->d_parent->d_inode->i_version; +#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 = dentry->d_parent->d_inode->i_version; + } +#else + dentry = d_splice_alias(inode, dentry); + if (dentry) + dentry->d_time = dentry->d_parent->d_inode->i_version; +#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; + } + dir->i_version++; + 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; + } + + dir->i_version++; + 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; + } + inode->i_version++; + 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 = dentry->d_parent->d_inode->i_version; + 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; + } + dir->i_version++; + 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; + } + inode->i_version++; + 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 = dentry->d_parent->d_inode->i_version; + 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; + } + dir->i_version++; + 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; + } + new_dir->i_version++; + 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); + } + + old_dir->i_version++; + 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; + inode->i_version++; + 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); + inode->i_version = 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 (!(sb->s_flags & MS_RDONLY)) + 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) +{ + *flags |= MS_NODIRATIME; + 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; + inode->i_version++; + 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; + sb->s_flags |= MS_NODIRATIME; + 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; + root_inode->i_version = 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/drivers/oneplus/fs/exfat/exfat_super.h b/drivers/oneplus/fs/exfat/exfat_super.h new file mode 100644 index 000000000000..916811e3d31e --- /dev/null +++ b/drivers/oneplus/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/drivers/oneplus/fs/exfat/exfat_upcase.c b/drivers/oneplus/fs/exfat/exfat_upcase.c new file mode 100644 index 000000000000..3807f37caacb --- /dev/null +++ b/drivers/oneplus/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/drivers/oneplus/fs/exfat/exfat_version.h b/drivers/oneplus/fs/exfat/exfat_version.h new file mode 100644 index 000000000000..a93fa46be04e --- /dev/null +++ b/drivers/oneplus/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.9" diff --git a/drivers/oneplus/fs/proc/Kconfig b/drivers/oneplus/fs/proc/Kconfig new file mode 100644 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 100644 index 000000000000..c4b7aed55832 --- /dev/null +++ b/drivers/oneplus/fs/proc/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_ADJ_CHAIN) += adj_chain_stat.o +obj-$(CONFIG_ONEPLUS_FG_OPT) += fg_uid.o diff --git a/drivers/oneplus/fs/proc/adj_chain_stat.c b/drivers/oneplus/fs/proc/adj_chain_stat.c new file mode 100644 index 000000000000..18916313a5e5 --- /dev/null +++ b/drivers/oneplus/fs/proc/adj_chain_stat.c @@ -0,0 +1,89 @@ +#include +#include +#include +#include +#include +#include + +static int adj_chain_proc_show(struct seq_file *m, void *v) +{ + struct task_struct *tsk, *p; + int i = 0; + int tasksize = 0; + rcu_read_lock(); + read_lock_irq(&tasklist_lock); + while (i <= adj_chain_hist_high) { + if (!list_empty(&adj_chain[i])) { + list_for_each_entry_rcu(tsk, &adj_chain[i], adj_chain_tasks) { + tasksize = 0; + p = find_lock_task_mm(tsk); + if (!p) + goto just_print; + tasksize = get_mm_rss(p->mm); + task_unlock(p); +just_print: + seq_printf(m, "%d tsk: %s, %d, adj %d, size %d\n", + __adjr(i), tsk->comm, tsk->pid, tsk->signal->oom_score_adj, tasksize); + } + } + ++i; + } + read_unlock_irq(&tasklist_lock); + rcu_read_unlock(); + seq_printf(m, "adj chain hist high: %d\n", __adjr(adj_chain_hist_high)); + return 0; +} + +static int adj_chain_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, adj_chain_proc_show, NULL); +} + +static const struct file_operations adj_chain_proc_fops = { + .open= adj_chain_proc_open, + .read= seq_read, + .llseek= seq_lseek, + .release= single_release, +}; + +static int adj_chain_verify_proc_show(struct seq_file *m, void *v) +{ + struct task_struct *tsk, *p; + int tasksize = 0; + rcu_read_lock(); + for_each_process(tsk) { + if (tsk) { + tasksize = 0; + p = find_lock_task_mm(tsk); + if (!p) + goto just_print; + tasksize = get_mm_rss(p->mm); + task_unlock(p); +just_print: + seq_printf(m, "tsk: %s, %d, adj %d, size %d\n", + tsk->comm, tsk->pid, tsk->signal->oom_score_adj, tasksize); + } + } + rcu_read_unlock(); + return 0; +} + +static int adj_chain_verify_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, adj_chain_verify_proc_show, NULL); +} + +static const struct file_operations adj_chain_verify_proc_fops = { + .open= adj_chain_verify_proc_open, + .read= seq_read, + .llseek= seq_lseek, + .release= single_release, +}; + +static int __init proc_adj_chain_init(void) +{ + proc_create("adj_chain_stat", S_IFREG | 0400, NULL, &adj_chain_proc_fops); + proc_create("adj_chain_verify", S_IFREG| 0400, NULL, &adj_chain_verify_proc_fops); + return 0; +} +fs_initcall(proc_adj_chain_init); diff --git a/drivers/oneplus/fs/proc/fg_uid.c b/drivers/oneplus/fs/proc/fg_uid.c new file mode 100644 index 000000000000..975ed0d7c9e1 --- /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 "../fs/proc/internal.h" +#include "fg_uid.h" + +#define FG_RW 0666 + +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; + long r; + 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; + } + err = kstrtol(buffer, 0, &r); + fginfo.fg_uids = r; + fginfo.fg_num = 1; +out: + return err < 0 ? err : count; +} + +static const struct file_operations proc_fg_uids_operations = { + .open = fg_uids_open, + .read = seq_read, + .write = fg_uids_write, + .llseek = seq_lseek, + .release = single_release, +}; + +static void uids_proc_fs_init(struct proc_dir_entry *p_parent) +{ + struct proc_dir_entry *p_temp; + + if (!p_parent) + goto out_p_temp; + + p_temp = proc_create(FS_FG_UIDS, FG_RW, + p_parent, &proc_fg_uids_operations); + if (!p_temp) + goto out_p_temp; + +out_p_temp: + return; +} + +static int __init fg_uids_init(void) +{ + struct proc_dir_entry *p_parent; + + p_parent = proc_mkdir(FS_FG_INFO_PATH, fg_dir); + if (!p_parent) + return -ENOMEM; + uids_proc_fs_init(p_parent); + return 0; +} + +static void __exit fg_uids_exit(void) +{ + if (!fg_dir) + return; + + remove_proc_entry(FS_FG_UIDS, fg_dir); +} + +module_init(fg_uids_init); +module_exit(fg_uids_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jared Wu "); +MODULE_DESCRIPTION("optimize foreground process to promote performance"); diff --git a/drivers/oneplus/fs/proc/fg_uid.h b/drivers/oneplus/fs/proc/fg_uid.h new file mode 100644 index 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/include/linux/adj_chain.h b/include/linux/adj_chain.h new file mode 100644 index 000000000000..f0579c0cdc11 --- /dev/null +++ b/include/linux/adj_chain.h @@ -0,0 +1,46 @@ +#ifndef _LINUX_ADJ_CHAIN_H +#define _LINUX_ADJ_CHAIN_H + +#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/include/linux/oem_force_dump.h b/include/linux/oem_force_dump.h new file mode 100644 index 000000000000..4dee0ebd619b --- /dev/null +++ b/include/linux/oem_force_dump.h @@ -0,0 +1,16 @@ +/* + * 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 + +extern void oem_check_force_dump_key(unsigned int code, int value); +extern int oem_get_download_mode(void); +void send_msg(char *message); +int msm_serial_oem_init(void); +#endif diff --git a/include/linux/oneplus/boot_mode.h b/include/linux/oneplus/boot_mode.h new file mode 100644 index 000000000000..f595f407cb04 --- /dev/null +++ b/include/linux/oneplus/boot_mode.h @@ -0,0 +1,16 @@ +#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__WLAN, + MSM_BOOT_MODE__MOS, + MSM_BOOT_MODE__CHARGE, +}; +enum oem_boot_mode get_boot_mode(void); +#endif diff --git a/include/linux/param_rw.h b/include/linux/param_rw.h new file mode 100644 index 000000000000..cb3978255fca --- /dev/null +++ b/include/linux/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/include/oneplus/memplus/memplus_helper.h b/include/oneplus/memplus/memplus_helper.h new file mode 100644 index 000000000000..7fdd83fd363b --- /dev/null +++ b/include/oneplus/memplus/memplus_helper.h @@ -0,0 +1,92 @@ +#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 *); + void (*memplus_move_anon_to_swapcache_lru_cb)(struct page *); + void (*memplus_state_check_cb)(bool, int, + struct task_struct *, int, int); + bool (*memplus_check_isolate_page_cb)(struct 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); + +#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, + +#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 + + +#endif +#endif /* _MEMORY_PLUS_H */ diff --git a/include/oneplus/smartboost/smartboost_helper.h b/include/oneplus/smartboost/smartboost_helper.h new file mode 100644 index 000000000000..81716f1973e5 --- /dev/null +++ b/include/oneplus/smartboost/smartboost_helper.h @@ -0,0 +1,81 @@ +#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 get_max_minfree(void); +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_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(condition, p) \ + do { \ + } while (0) + +#define UID_LRU_SIZE 0L +#define ZONE_UID_LRU_SIZE(z) 0L +#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 From eb3922e1fe9fe215bf07839b86bacbf24b93b1f2 Mon Sep 17 00:00:00 2001 From: Luca Stefani Date: Thu, 13 Sep 2018 13:10:12 +0200 Subject: [PATCH 254/356] drivers: power: Import OnePlus drivers * bq27541 and oneplus_fastchg ( aka dash ) * Also import relative changes to QPNP SMB Battery Charger EdwinMoq: Adapt for 4.19 Change-Id: I07a5e518d16e5d4f679b9aeb542b8a56dbb81dde --- drivers/power/supply/power_supply.h | 6 + drivers/power/supply/power_supply_core.c | 2 + drivers/power/supply/power_supply_sysfs.c | 34 +- drivers/power/supply/qcom/Kconfig | 27 + drivers/power/supply/qcom/Makefile | 3 + drivers/power/supply/qcom/battery.c | 4 + .../power/supply/qcom/bq27541_fuelgauger.c | 2160 ++++++++++ drivers/power/supply/qcom/fg-core.h | 3 + drivers/power/supply/qcom/fg-util.c | 33 +- drivers/power/supply/qcom/oneplus_fastchg.c | 1635 ++++++++ drivers/power/supply/qcom/op_charge.h | 691 ++++ drivers/power/supply/qcom/op_dash_adapter.c | 599 +++ drivers/power/supply/qcom/op_dash_adapter.h | 223 + drivers/power/supply/qcom/qg-reg.h | 1 - drivers/power/supply/qcom/qg-sdam.c | 22 - drivers/power/supply/qcom/qg-sdam.h | 4 - drivers/power/supply/qcom/qpnp-fg-gen3.c | 167 +- drivers/power/supply/qcom/qpnp-qg.c | 41 - drivers/power/supply/qcom/qpnp-smb2.c | 588 ++- drivers/power/supply/qcom/smb-lib.c | 3588 ++++++++++++++++- drivers/power/supply/qcom/smb-lib.h | 178 +- include/linux/power/oem_external_fg.h | 138 + include/linux/power_supply.h | 23 + 23 files changed, 9859 insertions(+), 311 deletions(-) create mode 100755 drivers/power/supply/qcom/bq27541_fuelgauger.c create mode 100755 drivers/power/supply/qcom/oneplus_fastchg.c create mode 100644 drivers/power/supply/qcom/op_charge.h create mode 100644 drivers/power/supply/qcom/op_dash_adapter.c create mode 100644 drivers/power/supply/qcom/op_dash_adapter.h create mode 100644 include/linux/power/oem_external_fg.h diff --git a/drivers/power/supply/power_supply.h b/drivers/power/supply/power_supply.h index cc439fd89d8d..4f7be680fc26 100644 --- a/drivers/power/supply/power_supply.h +++ b/drivers/power/supply/power_supply.h @@ -26,6 +26,12 @@ static inline void power_supply_init_attrs(struct device_type *dev_type) {} #endif /* CONFIG_SYSFS */ +#if defined(CONFIG_HOUSTON) +extern void ht_register_power_supply(struct power_supply *psy); +#else +static inline void ht_register_power_supply(struct power_supply *psy) {} +#endif /* CONFIG_HOUSTON */ + #ifdef CONFIG_LEDS_TRIGGERS extern void power_supply_update_leds(struct power_supply *psy); diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c index 2963570da602..bed25384c07d 100644 --- a/drivers/power/supply/power_supply_core.c +++ b/drivers/power/supply/power_supply_core.c @@ -949,6 +949,8 @@ __power_supply_register(struct device *parent, &psy->deferred_register_work, POWER_SUPPLY_DEFERRED_REGISTER_TIME); + ht_register_power_supply(psy); + return psy; create_triggers_failed: diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c index 7a5a8177723a..01ab8b04c998 100644 --- a/drivers/power/supply/power_supply_sysfs.c +++ b/drivers/power/supply/power_supply_sysfs.c @@ -46,7 +46,13 @@ static const char * const power_supply_type_text[] = { "USB_PD", "USB_PD_DRP", "BrickID", "USB_HVDCP", "USB_HVDCP_3", "USB_HVDCP_3P5", "Wireless", "USB_FLOAT", "BMS", "Parallel", "Main", "USB_C_UFP", "USB_C_DFP", - "Charge_Pump", +/* david.liu@bsp, 20171023 Battery & Charging porting */ + "Charge_Pump", "DASH" +}; + +/* david.liu@bsp, 20171023 Battery & Charging porting */ +static const char * const cc_orientation_text[] = { + "Unknown", "cc1", "cc2" }; static const char * const power_supply_usb_type_text[] = { @@ -202,6 +208,11 @@ static ssize_t power_supply_show_property(struct device *dev, ret = sprintf(buf, "%s\n", power_supply_usbc_pr_text[value.intval]); break; +/* david.liu@bsp, 20171023 Battery & Charging porting */ + case POWER_SUPPLY_PROP_OEM_TYPEC_CC_ORIENTATION: + ret = snprintf(buf, sizeof(buf), "%s\n", + cc_orientation_text[value.intval]); + break; case POWER_SUPPLY_PROP_TYPEC_SRC_RP: ret = sprintf(buf, "%s\n", power_supply_typec_src_rp_text[value.intval]); @@ -283,6 +294,27 @@ 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), +/* david.liu@bsp, 20171023 Battery & Charging porting */ + POWER_SUPPLY_ATTR(set_allow_read_extern_fg_iic), + POWER_SUPPLY_ATTR(cc_to_cv_point), + POWER_SUPPLY_ATTR(chg_protect_status), + POWER_SUPPLY_ATTR(fastchg_status), + 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(connect_disable), + POWER_SUPPLY_ATTR(connecter_temp), + POWER_SUPPLY_ATTR(bq_soc), + POWER_SUPPLY_ATTR(oem_cc_orientation), POWER_SUPPLY_ATTR(charge_type), POWER_SUPPLY_ATTR(health), POWER_SUPPLY_ATTR(present), diff --git a/drivers/power/supply/qcom/Kconfig b/drivers/power/supply/qcom/Kconfig index b6671064abcc..42495697f357 100644 --- a/drivers/power/supply/qcom/Kconfig +++ b/drivers/power/supply/qcom/Kconfig @@ -184,4 +184,31 @@ config SMB1398_CHARGER wireless charger receiver and provide the input for downstream chargers. +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 VOOC charge and state of charge of battery connected to + the battery. The state of charge is reported through a battery power + supply property + endmenu diff --git a/drivers/power/supply/qcom/Makefile b/drivers/power/supply/qcom/Makefile index dac497096c5a..432c6e19228a 100644 --- a/drivers/power/supply/qcom/Makefile +++ b/drivers/power/supply/qcom/Makefile @@ -16,3 +16,6 @@ obj-$(CONFIG_SMB1398_CHARGER) += smb1398-charger.o pmic-voter.o obj-$(CONFIG_QPNP_SMBLITE) += step-chg-jeita.o battery.o qpnp-smblite.o smblite-lib.o pmic-voter.o storm-watch.o schgm-flashlite.o obj-$(CONFIG_QPNP_VM_BMS) += qpnp-vm-bms.o batterydata-lib.o batterydata-interface.o obj-$(CONFIG_QPNP_LINEAR_CHARGER) += qpnp-linear-charger.o +obj-$(CONFIG_FG_BQ27541) += bq27541_fuelgauger.o +obj-$(CONFIG_ONEPLUS_FASTCHG) += oneplus_fastchg.o op_dash_adapter.o +obj-$(CONFIG_QPNP_QG) += qpnp-qg.o pmic-voter.o qg-util.o qg-soc.o qg-sdam.o qg-battery-profile.o qg-profile-lib.o fg-alg.o diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c index caad31163fbf..efd5e0123b32 100644 --- a/drivers/power/supply/qcom/battery.c +++ b/drivers/power/supply/qcom/battery.c @@ -952,6 +952,8 @@ 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,6 +1223,7 @@ static int pl_fv_vote_callback(struct votable *votable, void *data, return 0; pval.intval = fv_uv; + pr_info("fv_uv=%d\n", fv_uv); rc = power_supply_set_property(chip->main_psy, POWER_SUPPLY_PROP_VOLTAGE_MAX, &pval); @@ -1326,6 +1329,7 @@ static int usb_icl_vote_callback(struct votable *votable, void *data, POWER_SUPPLY_PROP_CURRENT_MAX, &pval); } + pr_info("total_icl_ua=%d\n", icl_ua); /* set the effective ICL */ pval.intval = icl_ua; diff --git a/drivers/power/supply/qcom/bq27541_fuelgauger.c b/drivers/power/supply/qcom/bq27541_fuelgauger.c new file mode 100755 index 000000000000..c914c2255522 --- /dev/null +++ b/drivers/power/supply/qcom/bq27541_fuelgauger.c @@ -0,0 +1,2160 @@ +/* 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 +#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_OVER_TEMP 0x40 +#define BQ27411_REG_GET_OVER_TEMP_EN 0x0002 + +#define CONTROL_CMD 0x00 +#define CONTROL_STATUS 0x00 +#define SEAL_POLLING_RETRY_LIMIT SEAL_POLLING_RETRY_LIMIT_2 +#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 0x3e +#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 600 + + +/* 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 BQ27411_OVER_TEMP 0x6c02 +#define BQ27411_MCL_DF 0xBD + + +#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 health_pre; + int get_over_temp; + 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; + bool lcd_is_off; + bool allow_reading; + bool fastchg_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 + /* david.liu@bsp, 20161004 Add BQ27411 support */ + int device_type; + struct cmd_address cmd_addr; + bool modify_soc_smooth; + bool already_modify_smooth; + bool is_mcl_verion; + bool df_ver_match; +#endif +}; + +/*add by yangrujin@bsp 2016/3/16, reduce bq resume time*/ + +#include + +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 +); + +int SEAL_POLLING_RETRY_LIMIT_2; + +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 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 bool check_df_version(struct bq27541_device_info *di) +{ + int df; + bool ret; + + if (di->device_type == DEVICE_BQ27541) + return true; + bq27541_cntl_cmd(di, BQ27541_SUBCMD_DF_CSUM); + udelay(66); + bq27541_read(BQ27541_REG_CNTL, &df, 0, di); + pr_info("DEVICE DF:%d\n", df); + if (df == BQ27411_MCL_DF) + ret = true; + else + ret = false; + return ret; +} + +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 30 +#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; +} + +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) + charging_status = 1; + else + charging_status = 0; + + if (charging_status ^ charging_status_pre) { + if (charging_status_pre) { + get_current_time(&soc_current_time); + di->soc_store_time = + soc_current_time - di->soc_pre_time; + } + + get_current_time(&di->soc_pre_time); + if (!charging_status_pre && di->soc_store_time) + di->soc_pre_time -= di->soc_store_time; + charging_status_pre = charging_status; + di->saltate_counter = 0; + } + + get_current_time(&soc_current_time); + time_last = soc_current_time - di->soc_pre_time; + if (charging_status) { /* is charging */ + if (ret.intval == POWER_SUPPLY_STATUS_FULL) { + soc_calib = di->soc_pre; + if (di->soc_pre < 100 + && (temp_region == BATT_TEMP_LITTLE_COOL + || temp_region == BATT_TEMP_NORMAL + || temp_region == BATT_TEMP_PRE_NORMAL + || temp_region == BATT_TEMP_COOL)) { + if (time_last > TWENTY_SECS) + soc_calib = di->soc_pre + 1; + } + } else { + if (soc - di->soc_pre > 0) { + di->saltate_counter++; + if ((bq27541_di->fastchg_started + && time_last < 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); + /* 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) > 3400) + 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 (di->allow_reading) { +#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; + } + } + + 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_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->device_type == DEVICE_BQ27541) + return true; + if (bq27541_di->df_ver_match) + return true; + if (bq27541_di->get_over_temp == BQ27411_OVER_TEMP + && bq27541_di->is_mcl_verion) + return true; + else if (bq27541_di->get_over_temp != BQ27411_OVER_TEMP + && !bq27541_di->is_mcl_verion) + return true; + else + return false; +} +static int bq_get_over_temp(struct bq27541_device_info *di) +{ + int flags; + int ret; + + ret = bq27541_i2c_txsubcmd(BQ27411_DATA_CLASS_ACCESS, + BQ27411_REG_GET_OVER_TEMP_EN, bq27541_di); + if (ret < 0) + pr_err("error w register %02x ret = %d\n", + BQ27411_DATA_CLASS_ACCESS, ret); + ret = bq27541_read(BQ27411_REG_OVER_TEMP, + &flags, 0, bq27541_di); + if (ret < 0) { + pr_err("error reading register %02x ret = %d\n", + BQ27411_REG_OVER_TEMP, ret); + } + pr_info("BQ27411 OVER_TEMP:0x%x\n",flags); + return flags; +} + + +#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->df_ver_match + || bq27541_di->already_modify_smooth) { + 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 true; +} + +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 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_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, +}; +#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(); + pr_debug("battery remain capacity:%d\n", + bq27541_get_batt_health()); + 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_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"); + 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); + 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); + +#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"); + di->df_ver_match = check_df_version(di); + } 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_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"); + di->is_mcl_verion = of_property_read_bool(node, + "op,mcl_verion"); + pr_info("di->is_mcl_verion=%d\n", di->is_mcl_verion); +} +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); + + if (get_boot_mode() == MSM_BOOT_MODE__RECOVERY) + SEAL_POLLING_RETRY_LIMIT_2 = 10; + else + SEAL_POLLING_RETRY_LIMIT_2 = 100; + + 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_err("%s begin\n", __func__); + if (sealed()) { + if (!unseal(BQ27411_UNSEAL_KEY)) + return; + msleep(50); + } + if (di->is_mcl_verion && !di->df_ver_match) + di->get_over_temp = bq_get_over_temp(di); +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_err("%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; + + wakeup_source_init(&di->update_soc_wake_lock, "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/power/supply/qcom/fg-core.h b/drivers/power/supply/qcom/fg-core.h index 7e3de38af9b5..9ed74859820f 100644 --- a/drivers/power/supply/qcom/fg-core.h +++ b/drivers/power/supply/qcom/fg-core.h @@ -477,6 +477,8 @@ struct fg_dev { bool profile_available; enum prof_load_status profile_load_status; bool battery_missing; +/* david.liu@bsp, 20171023 Battery & Charging porting */ + bool use_external_fg; bool fg_restarting; bool charge_full; bool recharge_soc_adjusted; @@ -528,6 +530,7 @@ struct fg_dbgfs { u32 addr; }; +static struct external_battery_gauge *external_fg; extern int fg_decode_voltage_24b(struct fg_sram_param *sp, enum fg_sram_param_id id, int val); extern int fg_decode_voltage_15b(struct fg_sram_param *sp, diff --git a/drivers/power/supply/qcom/fg-util.c b/drivers/power/supply/qcom/fg-util.c index 0d152d57258e..a8cdce3e6221 100644 --- a/drivers/power/supply/qcom/fg-util.c +++ b/drivers/power/supply/qcom/fg-util.c @@ -378,6 +378,7 @@ bool is_input_present(struct fg_dev *fg) return is_usb_present(fg) || is_dc_present(fg); } +/* Yangfb@bsp, 20170109 set Ibat 500mA by default */ void fg_notify_charger(struct fg_dev *fg) { union power_supply_propval prop = {0, }; @@ -389,27 +390,21 @@ void fg_notify_charger(struct fg_dev *fg) if (!fg->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 = 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; } - 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(fg->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; } } diff --git a/drivers/power/supply/qcom/oneplus_fastchg.c b/drivers/power/supply/qcom/oneplus_fastchg.c new file mode 100755 index 000000000000..022edd1b262d --- /dev/null +++ b/drivers/power/supply/qcom/oneplus_fastchg.c @@ -0,0 +1,1635 @@ +/**************************************************** + **Description:fastchg update firmware and driver + *****************************************************/ +#define pr_fmt(fmt) "FASTCHG: %s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BYTE_OFFSET 2 +#define BYTES_TO_WRITE 16 + +#define READ_COUNT 192 +#define FW_CHECK_FAIL 0 +#define FW_CHECK_SUCCESS 1 + +#define SHOW_FW_VERSION_DELAY_MS 18000 +static struct pm_qos_request big_cpu_update_freq; + +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 irq_enabled; + bool fast_chg_allow; + bool firmware_already_updated; + bool n76e_present; + bool is_mcl_verion; + 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[12]; + char manu_name[12]; +}; + +struct fastchg_device_info *fastchg_di; + +static unsigned char *dashchg_firmware_data; +static struct i2c_client *mcu_client; + + +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 = sprintf(page, "%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"); +} + +//for mcu_data irq delay issue 2017.10.14@Infi +extern void msm_cpuidle_set_sleep_disable(bool disable); + +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); + /* @bsp 2018/09/05 FAT-4556 fix the audio heaset pop + * issue when shutdown + */ + if (audio_adapter_flag) { + usleep_range(10000, 10001); + gpio_direction_output(fastchg_di->mcu_en_gpio, 0); + pr_info("mcu reset ahead when audio adaptor present!\n"); + } + } +} + +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[i]); + 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); + 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); + 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 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_enhache_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_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_enhache = clean_enhache_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 switch_mode_to_normal(void) +{ + usb_sw_gpio_set(0); + mcu_en_gpio_set(1); + msm_cpuidle_set_sleep_disable(false); +} + +static void update_fast_chg_started(void) +{ + if (bq27541_data && bq27541_data->fast_chg_started_status) + bq27541_data->fast_chg_started_status( + fastchg_di->fast_chg_started); +} + +static void request_mcu_irq(struct fastchg_device_info *di) +{ + int retval; + + opchg_set_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(unsigned long data) +{ + struct fastchg_device_info *di = (struct fastchg_device_info *)data; + + 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; + + /* 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 REJECT_DATA 0x11 +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 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); + /*pm_qos_update_request(&big_cpu_update_freq, MIN_CPUFREQ);*/ + + 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(di, REJECT_DATA); + } else if (arg == DASH_NOTIFY_FAST_PRESENT + 3) { + notify_check_usb_suspend(false, false); + dash_write(di, ALLOW_DATA); + di->fast_chg_started = true; + msm_cpuidle_set_sleep_disable(true); + } + break; + case DASH_NOTIFY_FAST_ABSENT: + if (arg == DASH_NOTIFY_FAST_ABSENT + 1) { + bq27541_data->set_allow_reading(true); + di->fast_chg_started = false; + di->fast_chg_allow = false; + di->fast_switch_to_normal = false; + di->fast_normal_to_warm = false; + di->fast_chg_ing = false; + di->dash_enhance = 0; + pr_err("fastchg stop unexpectly, switch off fastchg\n"); + switch_mode_to_normal(); + del_timer(&di->watchdog); + dash_write(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)); + dash_write(di, ALLOW_DATA); + } + break; + case DASH_NOTIFY_BTB_TEMP_OVER: + mod_timer(&di->watchdog, + jiffies + msecs_to_jiffies(15000)); + dash_write(di, ALLOW_DATA); + break; + case DASH_NOTIFY_UPDATE_ADAPTER_INFO: + di->dash_enhance = arg; + 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; + 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; + 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(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; + 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; + 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"); + 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 exist\n"); + } else { + pr_info("n76e not exist\n"); + } + +} + +static void check_enhance_support(struct fastchg_device_info *di) +{ + if (di->is_mcl_verion) { + init_enhance_dash_exist_node(); + pr_info("enhance dash exist\n"); + } else { + pr_info("enhance dash not exist\n"); + } + +} + + +/* @bsp 2018/09/05 FAT-4556 fix the audio heaset pop issue when shutdown*/ +static int set_mcu_reset_ahead(const char *val, const struct kernel_param *kp) +{ + unsigned long reset_value = 0; + int ret = 0; + + if (!audio_adapter_flag) { + pr_info("audio_adapter_flag = %d,return!\n", + audio_adapter_flag); + return 0; + } + + ret = kstrtoul(val, 10, &reset_value); + if (ret) + return ret; + + if (!reset_value) { + fastchg_di->mcu_reset_ahead = 0; + return 0; + } + + if (reset_value) { + pr_info("reset_value:%lu\n", + reset_value); + mcu_en_reset(); + fastchg_di->mcu_reset_ahead = reset_value; + } + + return 0; +} + +static int get_mcu_reset_status(char *buffer, const struct kernel_param *kp) +{ + int cnt = 0; + + cnt = snprintf(buffer, sizeof(char), "%d", + fastchg_di->mcu_reset_ahead); + pr_debug("mcu reset ahead status:%d\n", + fastchg_di->mcu_reset_ahead); + + return cnt; +} + +module_param_call(mcu_reset, set_mcu_reset_ahead, + get_mcu_reset_status, NULL, 0644); + +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); + wakeup_source_init(&di->fastchg_wake_lock, "fastcg_wake_lock"); + wakeup_source_init(&di->fastchg_update_fireware_lock, + "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); + /*pm_qos_add_request(&big_cpu_update_freq, + PM_QOS_C1_CPUFREQ_MIN, MIN_CPUFREQ);*/ + + init_timer(&di->watchdog); + di->watchdog.data = (unsigned long)di; + di->watchdog.function = di_watchdog; + + 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); + fastcharge_information_register(&fastcharge_information); + pr_info("dash_probe success\n"); + + return 0; + +err_misc_register_failed: + pm_qos_remove_request(&big_cpu_update_freq); +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); + /* @bsp 2018/09/05 FAT-4556 fix the audio heaset pop + * issue when shutdown + */ + if (audio_adapter_flag && fastchg_di->mcu_reset_ahead) + return; + 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/power/supply/qcom/op_charge.h b/drivers/power/supply/qcom/op_charge.h new file mode 100644 index 000000000000..c0501968b97a --- /dev/null +++ b/drivers/power/supply/qcom/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[] = { + 1774, + 1773, + 1771, + 1769, + 1767, + 1764, + 1762, + 1759, + 1757, + 1754, + 1751, + 1747, + 1744, + 1740, + 1737, + 1733, + 1728, + 1724, + 1719, + 1714, + 1709, + 1704, + 1698, + 1692, + 1686, + 1679, + 1672, + 1665, + 1658, + 1650, + 1642, + 1633, + 1624, + 1615, + 1605, + 1595, + 1585, + 1574, + 1563, + 1552, + 1540, + 1527, + 1515, + 1501, + 1488, + 1474, + 1460, + 1445, + 1430, + 1414, + 1399, + 1382, + 1366, + 1349, + 1332, + 1314, + 1296, + 1278, + 1260, + 1241, + 1222, + 1203, + 1184, + 1164, + 1144, + 1125, + 1105, + 1084, + 1064, + 1044, + 1024, + 1004, + 983, + 963, + 943, + 923, + 903, + 883, + 863, + 843, + 824, + 804, + 785, + 766, + 748, + 729, + 711, + 693, + 675, + 658, + 641, + 624, + 607, + 591, + 575, + 559, + 544, + 529, + 514, + 500, + 486, + 472, + 459, + 446, + 433, + 421, + 408, + 397, + 385, + 374, + 363, + 352, + 342, + 332, + 322, + 313, + 303, + 294, + 286, + 278, + 269, + 261, + 254, + 246, + 239, + 232, + 225, + 218, + 212, + 206, + 200, + 194, + 188, + 182, + 177, + 172, + 167, + 162, + 157, + 153, + 148, + 144, + 140, + 136, + 132, + 128, + 125, + 121, + 118, + 114, + 111, + 108, + 105, + 102, + 99, + 96, + 94, + 91, + 89, + 86, + 84, + 82, + 79, + 77, + 75, + 73, +}; + +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/power/supply/qcom/op_dash_adapter.c b/drivers/power/supply/qcom/op_dash_adapter.c new file mode 100644 index 000000000000..9d7a468837c6 --- /dev/null +++ b/drivers/power/supply/qcom/op_dash_adapter.c @@ -0,0 +1,599 @@ +#include +#include +#include +#include +#include +#include "op_dash_adapter.h" +/* add for dash adapter update */ +#include + +static struct op_adapter_chip *the_chip; + +#define DEFALUT_TX_VALUE 0xFF +static void dash_uart_gpio_set_value(struct op_adapter_chip *chip, + unsigned long pin, bool value) +{ + if (chip->tx_invalid_val != value) { + gpio_set_value(pin, value); + chip->tx_invalid_val = value; + } +} + +#define update_cycle 998 +#define LOG_COUNT 30 +int rx_time[LOG_COUNT]; +int tx_time[LOG_COUNT]; +void print_oem(void) +{ + int i; + + for (i = 0; i < LOG_COUNT - 1; i++) + pr_info("rx=%d, tx=%d\n", rx_time[i], tx_time[i]); +} + +static int dash_uart_gpio_get_value(unsigned long pin) +{ + return gpio_get_value(pin); +} + +void oem_delay(struct op_adapter_chip *chip, cycles_t begin_time) +{ + cycles_t time, curl_time; + + if (chip->timer_delay == 52) { + do { + curl_time = get_cycles(); + time = curl_time - begin_time; + } while (time < update_cycle); + } else if (chip->timer_delay == 78) { + do { + curl_time = get_cycles(); + time = curl_time - begin_time; + } while (time < update_cycle * 3 / 2); + } else if (chip->timer_delay == 25) { + do { + curl_time = get_cycles(); + time = curl_time - begin_time; + } while (time < update_cycle / 2); + } else if (chip->timer_delay == 2) { + do { + curl_time = get_cycles(); + time = curl_time - begin_time; + } while (time < 30); + } else { + udelay(chip->timer_delay); + } +} + +static void dash_uart_tx_bit( + struct op_adapter_chip *chip, unsigned char tx_data) +{ + static unsigned char tx_bit = BIT_START; + + switch (tx_bit) { + case BIT_START: + chip->tx_byte_over = false; + dash_uart_gpio_set_value( + chip, chip->uart_tx_gpio, 0); + tx_bit = BIT_0; + break; + case BIT_0: + case BIT_1: + case BIT_2: + case BIT_3: + case BIT_4: + case BIT_5: + case BIT_6: + case BIT_7: + if (tx_data & (1 << tx_bit)) + dash_uart_gpio_set_value( + chip, chip->uart_tx_gpio, 1); + else + dash_uart_gpio_set_value( + chip, chip->uart_tx_gpio, 0); + tx_bit++; + break; + case BIT_STOP: + case BIT_IDLE: + dash_uart_gpio_set_value(chip, chip->uart_tx_gpio, 1); + tx_bit = BIT_START; + chip->tx_byte_over = true; + break; + default: + break; + } +} + +static int dash_uart_rx_bit(struct op_adapter_chip *chip) +{ + static unsigned char rx_bit = BIT_IDLE, rx_val; + + switch (rx_bit) { + case BIT_IDLE: + chip->rx_byte_over = false; + if (!dash_uart_gpio_get_value(chip->uart_rx_gpio)) { + rx_bit = BIT_0; + chip->timer_delay = 78; /* 1.5 cycle */ + } else { + chip->timer_delay = 2; /* 0.02 cycle */ + } + break; + case BIT_0: + case BIT_1: + case BIT_2: + case BIT_3: + case BIT_4: + case BIT_5: + case BIT_6: + case BIT_7: + chip->timer_delay = 52; /* 1 cycle */ + if (dash_uart_gpio_get_value(chip->uart_rx_gpio)) + rx_val |= (1 << rx_bit); + else + rx_val &= ~(1 << rx_bit); + rx_bit++; + break; + case BIT_STOP: + rx_bit = BIT_IDLE; + chip->rx_byte_over = true; + break; + default: + break; + } + + return rx_val; +} + +static void dash_uart_tx_byte( + struct op_adapter_chip *chip, unsigned char tx_data) +{ + cycles_t time, curl_time, begin_time; + int i = 0; + + chip->timer_delay = 52; + while (1) { + begin_time = get_cycles(); + mb();/*need const tx*/ + dash_uart_tx_bit(chip, tx_data); + curl_time = get_cycles(); + time = curl_time - begin_time; + tx_time[i++] = time; + + if (i > LOG_COUNT - 1) + i = 0; + + oem_delay(chip, begin_time); + if (chip->tx_byte_over) { + chip->timer_delay = 25; + break; + } + } +} + +static unsigned char dash_uart_rx_byte( + struct op_adapter_chip *chip, unsigned int cmd) +{ + unsigned char rx_val = 0; + unsigned int count = 0; + unsigned int max_count = 0; + cycles_t time, curl_time, begin_time; + int i = 0; + + if (cmd == Read_Addr_Line_Cmd) + max_count = Read_Addr_Line_Cmd_Count; + else if (cmd == Write_Addr_Line_Cmd) + max_count = Write_Addr_Line_Cmd_Count; + else if (cmd == Erase_Addr_Line_Cmd) + max_count = Erase_Addr_Line_Cmd_Count; + else if (cmd == Read_All_Cmd) + max_count = Read_All_Cmd_Count; + else if (cmd == Erase_All_Cmd) + max_count = Erase_All_Cmd_Count; + else if (cmd == Boot_Over_Cmd) + max_count = Boot_Over_Cmd_Count; + else + max_count = Other_Cmd_count; + + chip->rx_timeout = false; + chip->timer_delay = 25; + while (1) { + begin_time = get_cycles(); + mb();/*need a const rx*/ + rx_val = dash_uart_rx_bit(chip); + curl_time = get_cycles(); + time = curl_time - begin_time; + rx_time[i++] = time; + + if (i > LOG_COUNT - 1) + i = 0; + + oem_delay(chip, begin_time); + if (chip->rx_byte_over) + return rx_val; + if (count > max_count) { + chip->rx_timeout = true; + return 0x00; + } + count++; + } +} + +static void dash_uart_irq_fiq_enable(bool enable) +{ + if (enable) { + preempt_enable(); + local_fiq_enable(); + local_irq_enable(); + } else { + local_irq_disable(); + local_fiq_disable(); + preempt_disable(); + } +} + +static int dash_uart_write_some_addr( + struct op_adapter_chip *chip, u8 *fw_buf, int length) +{ + unsigned int write_addr = 0, i = 0, fw_count = 0; + unsigned char rx_val = 0; + + while (1) { + /* tx: 0xF5 */ + dash_uart_irq_fiq_enable(false); + dash_uart_tx_byte(chip, (Write_Addr_Line_Cmd >> 8) & 0xff); + /* tx: 0x02 */ + dash_uart_tx_byte(chip, Write_Addr_Line_Cmd & 0xff); + /* count:16 bytes */ + dash_uart_tx_byte(chip, 16); + + /* addr: 2 byte */ + if (write_addr == 0) + write_addr = + (fw_buf[fw_count + 1] << 8) + | fw_buf[fw_count]; + dash_uart_tx_byte(chip, (write_addr >> 8) & 0xff); + dash_uart_tx_byte(chip, write_addr & 0xff); + + if (!(write_addr % 0x20)) + fw_count += 2; + + /* data: 16 bytes */ + for (i = 0; i < 16; i++) { + dash_uart_tx_byte(chip, fw_buf[fw_count]); + fw_count++; + + if (i == 15) + rx_val = dash_uart_rx_byte( + chip, Write_Addr_Line_Cmd); + } + + dash_uart_irq_fiq_enable(true); + write_addr += 16; + if (rx_val != UART_ACK || chip->rx_timeout) { + pr_err("%s err,write_addr:0x%x,chip->rx_timeout:%d,rx_val=%d\n", + __func__, write_addr, + chip->rx_timeout, rx_val); + return -EINVAL; + } + if (fw_count >= length) + return 0; + } +} + +#define STM8S_ADAPTER_FIRST_ADDR 0x8C00 +#define STM8S_ADAPTER_LAST_ADDR 0x9FEF +#define HALF_ONE_LINE 16 + +static bool dash_uart_read_addr_line_and_check( + struct op_adapter_chip *chip, unsigned int addr) +{ + unsigned char fw_check_buf[20] = {0x00}; + int i = 0; + static int fw_line; + bool check_result = false; + int addr_check_err = 0; + + if (addr == STM8S_ADAPTER_FIRST_ADDR) + fw_line = 0; + + /* Tx_Read_Addr_Line */ + /* tx:0xF5 */ + dash_uart_irq_fiq_enable(false); + dash_uart_tx_byte(chip, (Read_Addr_Line_Cmd >> 8) & 0xff); + /* tx:0x01 */ + dash_uart_tx_byte(chip, Read_Addr_Line_Cmd & 0xff); + /* tx:0x9F */ + dash_uart_tx_byte(chip, (addr >> 8) & 0xff); + /* tx:0xF0 */ + dash_uart_tx_byte(chip, addr & 0xff); + + fw_check_buf[0] = dash_uart_rx_byte(chip, Read_Addr_Line_Cmd); + if (chip->rx_timeout) + goto read_addr_line_err; + + fw_check_buf[1] = dash_uart_rx_byte(chip, Read_Addr_Line_Cmd); + if (chip->rx_timeout) + goto read_addr_line_err; + + if (addr != ((fw_check_buf[0] << 8) | fw_check_buf[1])) { + addr_check_err = 1; + goto read_addr_line_err; + } + + for (i = 0; i < 16; i++) { + fw_check_buf[i + 2] = + dash_uart_rx_byte(chip, Read_Addr_Line_Cmd); + if (chip->rx_timeout) + goto read_addr_line_err; + } + + if (!(addr % 0x20)) { + if (addr == ((adapter_stm8s_firmware_data[fw_line * 34 + 1] + << 8) + | (adapter_stm8s_firmware_data[fw_line * 34]))) { + for (i = 0; i < 16; i++) { + if (fw_check_buf[i + 2] + != adapter_stm8s_firmware_data[ + fw_line * 34 + 2 + i]) + goto read_addr_line_err; + } + } + } else { + if ((addr - 16) == + ((adapter_stm8s_firmware_data[fw_line * 34 + 1] << 8) + | (adapter_stm8s_firmware_data[fw_line * 34]))) { + for (i = 0; i < 16; i++) { + if (fw_check_buf[i + 2] + != adapter_stm8s_firmware_data[ + fw_line * 34 + + 2 + HALF_ONE_LINE + i]) + goto read_addr_line_err; + } + } + fw_line++; + } + check_result = true; + +read_addr_line_err: + dash_uart_irq_fiq_enable(true); + if (addr_check_err) { + pr_err("%s addr:0x%x,buf[0]:0x%x,buf[1]:0x%x\n", + __func__, addr, fw_check_buf[0], fw_check_buf[1]); + } + if (!check_result) { + pr_err("%s fw_check err,addr:0x%x,check_buf[%d]:0x%x != fw_data[%d]:0x%x\n", + __func__, addr, i + 2, fw_check_buf[i + 2], + (fw_line * 34 + 2 + i), + adapter_stm8s_firmware_data[fw_line * 34 + 2 + i]); + for (i = 0; i < 16; i++) + pr_err("fw_check_buf[%d]=0x%x\n", + i+2, fw_check_buf[i + 2]); + } + return check_result; +} + +static int dash_uart_read_front_addr_and_check(struct op_adapter_chip *chip) +{ + unsigned int read_addr = STM8S_ADAPTER_FIRST_ADDR; + bool result = false; + + while (read_addr < STM8S_ADAPTER_LAST_ADDR) { + result = dash_uart_read_addr_line_and_check(chip, read_addr); + read_addr = read_addr + 16; + if ((!result) || chip->rx_timeout) { + pr_err("%s result:%d,chip->rx_timeout:%d\n", + __func__, result, chip->rx_timeout); + return -EINVAL; + } + } + return 0; +} + +static bool +dash_adapter_update_handle( + struct op_adapter_chip *chip, + unsigned long tx_pin, unsigned long rx_pin) +{ + unsigned char rx_val = 0; + int rx_last_line_count = 0; + unsigned char rx_last_line[18] = {0x0}; + int rc = 0; + + pr_err("%s v1 begin\n", __func__); + chip->uart_tx_gpio = tx_pin; + chip->uart_rx_gpio = rx_pin; + chip->adapter_update_ing = true; + chip->tx_invalid_val = DEFALUT_TX_VALUE; + chip->rx_timeout = false; + + /* step1: Tx_Erase_Addr_Line */ + /* tx:0xF5 */ + dash_uart_irq_fiq_enable(false); + dash_uart_tx_byte(chip, (Erase_Addr_Line_Cmd >> 8) & 0xff); + dash_uart_irq_fiq_enable(true); + + /* tx:0x03 */ + dash_uart_irq_fiq_enable(false); + dash_uart_tx_byte(chip, Erase_Addr_Line_Cmd & 0xff); + dash_uart_irq_fiq_enable(true); + + /* tx:0x9F */ + dash_uart_irq_fiq_enable(false); + dash_uart_tx_byte(chip, (Last_Line_Addr >> 8) & 0xff); + dash_uart_irq_fiq_enable(true); + + /* tx:0xF0 */ + dash_uart_irq_fiq_enable(false); + dash_uart_tx_byte(chip, Last_Line_Addr & 0xff); + rx_val = dash_uart_rx_byte(chip, Erase_Addr_Line_Cmd); + dash_uart_irq_fiq_enable(true); + if (rx_val != UART_ACK || chip->rx_timeout) { + pr_err("%s Tx_Erase_Addr_Line err,chip->rx_timeout:%d, rx_val:0x%x\n", + __func__, chip->rx_timeout, rx_val); + goto update_err; + } + /* Step2: Tx_Read_Addr_Line */ + /* tx:0xF5 */ + dash_uart_irq_fiq_enable(false); + dash_uart_tx_byte(chip, (Read_Addr_Line_Cmd >> 8) & 0xff); + dash_uart_irq_fiq_enable(true); + + /* tx:0x01 */ + dash_uart_irq_fiq_enable(false); + dash_uart_tx_byte(chip, Read_Addr_Line_Cmd & 0xff); + dash_uart_irq_fiq_enable(true); + + /* tx:0x9F */ + dash_uart_irq_fiq_enable(false); + dash_uart_tx_byte(chip, (Last_Line_Addr >> 8) & 0xff); + dash_uart_irq_fiq_enable(true); + + /* tx:0xF0 */ + dash_uart_irq_fiq_enable(false); + dash_uart_tx_byte(chip, Last_Line_Addr & 0xff); + for (rx_last_line_count = 0; + rx_last_line_count < 18; rx_last_line_count++) { + rx_last_line[rx_last_line_count] + = dash_uart_rx_byte(chip, Read_Addr_Line_Cmd); + if (chip->rx_timeout) + break; + } + + dash_uart_irq_fiq_enable(true); + if ((rx_last_line[FW_EXIST_LOW] == 0x55 && + rx_last_line[FW_EXIST_HIGH] == 0x34) + || chip->rx_timeout) { + pr_err("%s Tx_Read_Addr_Line err,chip->rx_timeout:%d\n", + __func__, chip->rx_timeout); + goto update_err; + } + + /* Step3: Tx_Erase_All */ + /* tx:0xF5 */ + dash_uart_irq_fiq_enable(false); + dash_uart_tx_byte(chip, (Erase_All_Cmd >> 8) & 0xff); + dash_uart_irq_fiq_enable(true); + + /* tx:0x05 */ + dash_uart_irq_fiq_enable(false); + dash_uart_tx_byte(chip, Erase_All_Cmd & 0xff); + rx_val = dash_uart_rx_byte(chip, Erase_All_Cmd); + dash_uart_irq_fiq_enable(true); + if (rx_val != UART_ACK || chip->rx_timeout) { + pr_err("%s Tx_Erase_All err,chip->rx_timeout:%d\n", + __func__, chip->rx_timeout); + goto update_err; + } + + /* Step4: Tx_Write_Addr_Line */ + rc = dash_uart_write_some_addr(chip, &adapter_stm8s_firmware_data[0], + (sizeof(adapter_stm8s_firmware_data) - 34)); + if (rc) { + pr_err("%s Tx_Write_Addr_Line err\n", __func__); + goto update_err; + } + + /* Step5: Tx_Read_All */ + rc = dash_uart_read_front_addr_and_check(chip); + if (rc) { + pr_err("%s Tx_Read_All err\n", __func__); + goto update_err; + } + + /* Step6: write the last line */ + rc = dash_uart_write_some_addr(chip, + &adapter_stm8s_firmware_data[ + sizeof(adapter_stm8s_firmware_data) - 34], + 34); + if (rc) { + pr_err("%s write the last line err\n", __func__); + goto update_err; + } + + /* Step7: Tx_Boot_Over */ + /* tx:0xF5 */ + dash_uart_irq_fiq_enable(false); + dash_uart_tx_byte(chip, (Boot_Over_Cmd >> 8) & 0xff); + dash_uart_irq_fiq_enable(true); + + /* tx:0x06 */ + dash_uart_irq_fiq_enable(false); + dash_uart_tx_byte(chip, Boot_Over_Cmd & 0xff); + rx_val = dash_uart_rx_byte(chip, Boot_Over_Cmd); + dash_uart_irq_fiq_enable(true); + if (rx_val != UART_ACK || chip->rx_timeout) { + pr_err("%s Tx_Boot_Over err,chip->rx_timeout:%d\n", + __func__, chip->rx_timeout); + goto update_err; + } + chip->rx_timeout = false; + chip->adapter_update_ing = false; + pr_err("%s success\n", __func__); + return true; + +update_err: + chip->rx_timeout = false; + chip->adapter_update_ing = false; + print_oem(); + pr_err("%s err\n", __func__); + return false; +} + +bool dash_adapter_update_is_tx_gpio(unsigned int gpio_num) +{ + if (!the_chip) + return false; + if (the_chip->adapter_update_ing && gpio_num == the_chip->uart_tx_gpio) + return true; + else + return false; +} + +bool dash_adapter_update_is_rx_gpio(unsigned int gpio_num) +{ + if (!the_chip) + return false; + + if (the_chip->adapter_update_ing && gpio_num == the_chip->uart_rx_gpio) + return true; + else + return false; +} + + +struct op_adapter_operations op_adapter_ops = { + .adapter_update = dash_adapter_update_handle, +}; + +static int __init dash_adapter_init(void) +{ + struct op_adapter_chip *chip = NULL; + + chip = kzalloc(sizeof(struct op_adapter_chip), GFP_KERNEL); + if (!chip) + return -EINVAL; + + chip->timer_delay = 0; + chip->tx_byte_over = false; + chip->rx_byte_over = false; + chip->rx_timeout = false; + chip->uart_tx_gpio = 0; + chip->uart_rx_gpio = 0; + chip->adapter_update_ing = false; + chip->adapter_firmware_data = adapter_stm8s_firmware_data; + chip->adapter_fw_data_count = sizeof(adapter_stm8s_firmware_data); + chip->vops = &op_adapter_ops; + op_adapter_init(chip); + the_chip = chip; + + pr_info("%s success\n", __func__); + return 0; +} + +static void __init dash_adapter_exit(void) +{ + +} + +module_init(dash_adapter_init); +module_exit(dash_adapter_exit); diff --git a/drivers/power/supply/qcom/op_dash_adapter.h b/drivers/power/supply/qcom/op_dash_adapter.h new file mode 100644 index 000000000000..09489c806f83 --- /dev/null +++ b/drivers/power/supply/qcom/op_dash_adapter.h @@ -0,0 +1,223 @@ +#ifndef _OP_DASH_ADAPTER_H_ +#define _OP_DASH_ADAPTER_H_ + +/*ap_data---->rx ap_clk---->tx*/ +#define BIT_0 0 +#define BIT_1 1 +#define BIT_2 2 +#define BIT_3 3 +#define BIT_4 4 +#define BIT_5 5 +#define BIT_6 6 +#define BIT_7 7 +#define BIT_STOP 8 +#define BIT_IDLE 9 +#define BIT_START 10 + +#define UART_NOACK 0 +#define UART_ACK 1 + +#define FW_VER_LOW 14 +#define FW_VER_HIGH 15 +#define FW_EXIST_LOW 16 +#define FW_EXIST_HIGH 17 + +#define Tx_Read_Addr_Line 0x01 +#define Tx_Write_Addr_Line 0x02 +#define Tx_Erase_Addr_Line 0x03 +#define Tx_Read_All 0x04 +#define Tx_Erase_All 0x05 +#define Tx_Boot_Over 0x06 +#define Tx_Cmd_Invalid 0xff + +#define Rx_Read_Addr_Line 0x01 +#define Rx_Write_Addr_Line 0x02 +#define Rx_Erase_Addr_Line 0x03 +#define Rx_Read_All 0x04 +#define Rx_Erase_All 0x05 +#define Rx_Boot_Over 0x06 +#define Rx_Cmd_Invalid 0xff + +#define Read_Addr_Line_Cmd 0xF501 +#define Write_Addr_Line_Cmd 0xF502 +#define Erase_Addr_Line_Cmd 0xF503 +#define Read_All_Cmd 0xF504 +#define Erase_All_Cmd 0xF505 +#define Boot_Over_Cmd 0xF506 +#define Last_Line_Addr 0x9FF0 + +#define Read_Addr_Line_Cmd_Count 2000 /*physical test: 27*/ +#define Write_Addr_Line_Cmd_Count 18000 /*physical test:8720*/ +#define Erase_Addr_Line_Cmd_Count 16000 /*physical test:7657*/ +#define Read_All_Cmd_Count 2000 /*physical test:27*/ +#define Erase_All_Cmd_Count 180000 /*physical test:86916*/ +#define Boot_Over_Cmd_Count 2000 /*physical test:34*/ +#define Other_Cmd_count 2000 + +#include +extern void op_adapter_init(struct op_adapter_chip *chip); +/*fw_ver must be 0x0b/0x0c/0x0d/0x0e/0x0f because of pic1508/stm8s*/ + +static unsigned char adapter_stm8s_firmware_data[] = { +0x00,0x8c,0x82,0x00,0x9F,0x20,0x82,0x00,0x9F,0xCF,0x82,0x00,0x9F,0xCF,0x82,0x00,0x9F,0xCF,0x82,0x00,0x9F,0xCF,0x82,0x00,0x9F,0xCF,0x82,0x00,0x9F,0xCF,0x82,0x00,0x9F,0xCF, +0x20,0x8C,0x82,0x00,0x93,0xBC,0x82,0x00,0x9F,0xCF,0x82,0x00,0x9F,0xCF,0x82,0x00,0x9F,0xCF,0x82,0x00,0x9F,0xCF,0x82,0x00,0x9F,0xCF,0x82,0x00,0x9F,0xCF,0x82,0x00,0x9F,0xCF, +0x40,0x8C,0x82,0x00,0x9F,0xCF,0x82,0x00,0x9F,0xCF,0x82,0x00,0x9F,0xCF,0x82,0x00,0x9F,0xCF,0x82,0x00,0x9F,0xCF,0x82,0x00,0x9F,0xCF,0x82,0x00,0x9F,0xCF,0x82,0x00,0x9F,0xCF, +0x60,0x8C,0x82,0x00,0x9F,0xCF,0x82,0x00,0x9F,0xCF,0x82,0x00,0x9F,0xCF,0x82,0x00,0x9F,0xCF,0x82,0x00,0x9F,0xCF,0x82,0x00,0x9F,0xCF,0x82,0x00,0x9F,0xCF,0x82,0x00,0x9F,0xCF, +0x80,0x8C,0x3B,0x00,0x08,0x3F,0x08,0x20,0x0C,0x3D,0x08,0x26,0x03,0xCD,0x93,0x70,0xA6,0x14,0xCD,0x9E,0xA4,0xB6,0x08,0xA1,0x02,0x27,0x2A,0xCD,0x9F,0xC1,0xCD,0x91,0x69,0xAE, +0xA0,0x8C,0x00,0x12,0xCD,0x91,0x2C,0xB7,0x08,0xA1,0x02,0x26,0x04,0xA6,0x01,0x20,0x14,0xA1,0x01,0x26,0x05,0xCD,0x92,0xDD,0x20,0xD6,0xA1,0x03,0x26,0xCB,0xA6,0x01,0xCD,0x92, +0xC0,0x8C,0xF6,0x20,0xCB,0x32,0x00,0x08,0x81,0xCD,0x9A,0x2A,0xCD,0x99,0xF2,0xBF,0x0A,0x90,0xBF,0x08,0xB7,0x0D,0x3F,0x0C,0xCD,0x9F,0xC1,0xB6,0x0D,0xCD,0x8D,0xAE,0xA6,0x02, +0xE0,0x8C,0xCD,0x93,0x29,0xBF,0x00,0xB3,0x0A,0x2F,0x06,0xBE,0x08,0xB3,0x00,0x2E,0x74,0xBE,0x00,0xB3,0x0A,0x2E,0x5C,0x3D,0x0D,0x27,0x49,0xA6,0x04,0xCD,0x93,0x29,0xA3,0x07, +0x00,0x8D,0x03,0x24,0x60,0xC6,0x00,0x31,0xA1,0x05,0x24,0x09,0xC6,0x00,0x31,0x4C,0xC7,0x00,0x31,0x20,0x15,0xC6,0x00,0x32,0xA1,0x0A,0x24,0x0E,0xC6,0x00,0x32,0x4C,0xC7,0x00, +0x20,0x8D,0x32,0xCD,0x92,0xDD,0x72,0x5F,0x00,0x31,0xC6,0x00,0x32,0xA1,0x0A,0x26,0x0A,0x35,0x0B,0x00,0x32,0x35,0x05,0x00,0x31,0x20,0x2A,0xC6,0x00,0x32,0xA1,0x0B,0x25,0x23, +0x40,0x8D,0x20,0x0A,0xA6,0x04,0xCD,0x93,0x29,0xA3,0x07,0x2C,0x24,0x40,0xCD,0x92,0xDD,0x20,0x12,0xBE,0x08,0xB3,0x00,0x2E,0x0C,0xB6,0x0D,0xCD,0x92,0xF6,0x20,0x05,0xA6,0x02, +0x60,0x8D,0xCD,0x9E,0xA4,0xB6,0x0C,0x4C,0xB7,0x0C,0xA6,0x02,0xCD,0x93,0x29,0xA3,0x05,0xBF,0x2F,0x14,0xC6,0x00,0x28,0xAB,0xF7,0xCD,0x93,0x1B,0xB6,0x0D,0xCD,0x8D,0xAE,0xA6, +0x80,0x8D,0x14,0xCD,0x9E,0xA4,0x20,0x06,0xB6,0x0C,0xA1,0x0A,0x25,0xD2,0xA6,0x04,0xCD,0x93,0x29,0x3D,0x0D,0x27,0x06,0x90,0xAE,0x07,0x2B,0x20,0x04,0x90,0xAE,0x07,0x4E,0xBF, +0xA0,0x8D,0x00,0x90,0xB3,0x00,0x2E,0x05,0xB6,0x0D,0xCD,0x92,0xF6,0xCC,0x9A,0x7E,0xA1,0x01,0x27,0x2F,0xA6,0x04,0xCD,0x93,0x29,0xA3,0x05,0x54,0x24,0x21,0xA6,0x02,0xCD,0x93, +0xC0,0x8D,0x29,0xA3,0x02,0x8F,0x25,0x17,0xC6,0x00,0x30,0xA1,0x46,0x24,0x08,0xC6,0x00,0x30,0x4C,0xC7,0x00,0x30,0x81,0xCD,0x8E,0xAD,0xCD,0x8D,0xE2,0x20,0xFB,0x72,0x5F,0x00, +0xE0,0x8D,0x30,0x81,0xCD,0x99,0xED,0x3B,0x00,0x0A,0x52,0x04,0x35,0x01,0x00,0x0A,0x90,0xAE,0x9F,0xCB,0x96,0x5C,0x89,0xA6,0x04,0xCD,0x9F,0x5F,0x85,0xCD,0x9F,0xC1,0xCD,0x8F, +0x00,0x8E,0x12,0x7B,0x01,0xA1,0x1D,0x26,0x12,0x7B,0x02,0xA1,0x05,0x26,0x0C,0x7B,0x03,0xA1,0x14,0x26,0x06,0x7B,0x04,0xA1,0x08,0x27,0x4B,0xCD,0x9F,0xC1,0x7B,0x01,0xA1,0x1D, +0x20,0x8E,0x27,0x13,0xCD,0x9F,0xC1,0x96,0x5C,0xCD,0x8E,0xC0,0x96,0x1C,0x00,0x02,0xBF,0x08,0x4D,0x26,0xE9,0x20,0x37,0xBE,0x08,0xCD,0x8E,0xC0,0xBE,0x08,0x5C,0xBF,0x08,0x4D, +0x40,0x8E,0x26,0x02,0x3F,0x0A,0xCD,0x8E,0xC0,0xBE,0x08,0x5C,0xBF,0x08,0x4D,0x26,0x02,0x3F,0x0A,0xCD,0x8E,0xC0,0xBE,0x08,0x5C,0xBF,0x08,0x4D,0x26,0x02,0x3F,0x0A,0x3D,0x0A, +0x60,0x8E,0x26,0x9F,0x20,0x08,0x35,0x01,0x00,0x2F,0x4F,0xCD,0x8E,0x74,0x5B,0x04,0x32,0x00,0x0A,0xCC,0x9A,0x85,0x4D,0x27,0x03,0xCD,0x8E,0xAD,0xC6,0x00,0x2F,0x26,0x03,0xCD, +0x80,0x8E,0x93,0x70,0xCD,0x9F,0xC1,0xCD,0x9F,0x9B,0x72,0x1C,0x50,0x5B,0x72,0x1D,0x50,0x5C,0x72,0x5F,0x9F,0xFC,0x72,0x5F,0x9F,0xFD,0x72,0x5F,0x9F,0xFE,0x72,0x5F,0x9F,0xFF, +0xA0,0x8E,0xCD,0x9F,0xC1,0xC6,0x50,0x5F,0xA5,0x05,0x27,0xF9,0xCC,0x93,0x70,0xA6,0x01,0xCD,0x94,0x82,0xA6,0x14,0xCD,0x9E,0xA4,0xA6,0xC8,0xCD,0x93,0x1B,0x4F,0xCC,0x95,0x1B, +0xC0,0x8E,0xCD,0x99,0xED,0x3B,0x00,0x0A,0xBF,0x08,0xC6,0x52,0x30,0xB7,0x0A,0xCD,0x9F,0xC1,0x20,0x08,0xCD,0x9F,0xC1,0xC6,0x52,0x30,0xB7,0x0A,0xB6,0x0A,0xA5,0x20,0x27,0xF2, +0xE0,0x8E,0xB6,0x0A,0xA5,0x09,0x27,0x09,0xC6,0x52,0x31,0x92,0xC7,0x08,0x4F,0x20,0x08,0xC6,0x52,0x31,0x92,0xC7,0x08,0xA6,0x01,0x32,0x00,0x0A,0xCC,0x9A,0x85,0x72,0x5F,0x52, +0x00,0x8F,0x34,0x72,0x5F,0x52,0x36,0x72,0x5F,0x52,0x33,0x72,0x5F,0x52,0x32,0x72,0x5F,0x52,0x35,0x81,0x72,0x5F,0x50,0x12,0x72,0x5F,0x50,0x13,0x35,0x02,0x50,0x11,0x72,0x19, +0x20,0x8F,0x52,0x34,0xC6,0x52,0x36,0xC7,0x52,0x36,0x35,0x01,0x52,0x33,0x35,0x34,0x52,0x32,0xC6,0x52,0x35,0xAA,0x0C,0xC7,0x52,0x35,0x81,0xCD,0x99,0xED,0xBF,0x08,0xCD,0x92, +0x40,0x8F,0x4D,0xBE,0x08,0xCD,0x92,0x33,0xA1,0x00,0x26,0x04,0x4F,0xCC,0x9A,0x85,0xBE,0x08,0x1C,0x00,0x08,0xF6,0x48,0x88,0xBE,0x08,0x1C,0x00,0x07,0xF6,0x48,0x48,0xB7,0x01, +0x60,0x8F,0x84,0xBA,0x01,0xBE,0x08,0x1C,0x00,0x09,0xFA,0x90,0x5F,0x90,0x97,0xAE,0x00,0x52,0xBF,0x00,0x93,0xCD,0x9C,0x69,0x1C,0x03,0xD4,0xCF,0x00,0x26,0xCE,0x00,0x26,0x1C, +0x80,0x8F,0xFF,0xCF,0xCF,0x00,0x24,0xCE,0x00,0x24,0xA3,0x04,0xEB,0x2F,0x06,0xAE,0x04,0xEA,0xCF,0x00,0x24,0xCE,0x00,0x26,0xA3,0x05,0x1C,0x2F,0x06,0xAE,0x05,0x1B,0xCF,0x00, +0xA0,0x8F,0x26,0xA6,0x01,0xCC,0x9A,0x85,0x72,0x5F,0x00,0x1F,0x72,0x5F,0x00,0x20,0x35,0x01,0x00,0x21,0x35,0x01,0x00,0x22,0xAE,0x00,0x1C,0xCC,0x92,0x9B,0x35,0x01,0x00,0x1F, +0xC0,0x8F,0x72,0x5F,0x00,0x20,0x72,0x5F,0x00,0x21,0x35,0x01,0x00,0x22,0xAE,0x00,0x1C,0xCC,0x92,0x9B,0xCD,0x99,0xED,0xBF,0x08,0xCD,0x92,0x4D,0xBE,0x08,0xCD,0x92,0x33,0xA1, +0xE0,0x8F,0x00,0x27,0x08,0xBE,0x08,0x1C,0x00,0x03,0x7D,0x26,0x04,0x4F,0xCC,0x9A,0x85,0xA6,0x01,0xCC,0x9A,0x85,0x72,0x5F,0x00,0x1F,0x35,0x01,0x00,0x20,0x35,0x01,0x00,0x21, +0x00,0x90,0x72,0x5F,0x00,0x22,0xAE,0x00,0x1C,0xCC,0x92,0x9B,0xCD,0x99,0xED,0xBF,0x08,0xCD,0x92,0x4D,0xBE,0x08,0xCD,0x92,0x33,0xA1,0x00,0x26,0x04,0x4F,0xCC,0x9A,0x85,0xBE, +0x20,0x90,0x08,0x1C,0x00,0x04,0x7D,0x26,0x0D,0xBE,0x08,0x1C,0x00,0x05,0x7D,0x27,0x05,0xA6,0x02,0xCC,0x9A,0x85,0xA6,0x01,0xCC,0x9A,0x85,0x35,0x01,0x00,0x1F,0x72,0x5F,0x00, +0x40,0x90,0x20,0x72,0x5F,0x00,0x21,0x72,0x5F,0x00,0x22,0xAE,0x00,0x1C,0xCC,0x92,0x9B,0xCD,0x99,0xED,0xBF,0x08,0xCD,0x92,0x4D,0xBE,0x08,0xCD,0x92,0x33,0xA1,0x00,0x27,0x15, +0x60,0x90,0xBE,0x08,0x1C,0x00,0x04,0x7D,0x26,0x0D,0xBE,0x08,0x1C,0x00,0x05,0x7D,0x27,0x05,0xA6,0x01,0xCC,0x9A,0x85,0x4F,0xCC,0x9A,0x85,0xC6,0x9F,0xFC,0xB7,0x00,0x44,0x44, +0x80,0x90,0x44,0xA4,0x01,0xC7,0x00,0x1F,0xB6,0x00,0x44,0x44,0xA4,0x01,0xC7,0x00,0x20,0xB6,0x00,0x44,0xA4,0x01,0xC7,0x00,0x21,0xB6,0x00,0xA4,0x01,0xC7,0x00,0x22,0xAE,0x00, +0xA0,0x90,0x1C,0xCC,0x92,0x9B,0xCD,0x99,0xED,0xBF,0x08,0xCD,0x92,0x4D,0xBE,0x08,0xCD,0x92,0x33,0xA1,0x00,0x26,0x05,0xA6,0x02,0xCC,0x9A,0x85,0xBE,0x08,0x1C,0x00,0x04,0xF6, +0xC0,0x90,0xC7,0x00,0x2D,0xBE,0x08,0x1C,0x00,0x03,0x7D,0x26,0x04,0x4F,0xCC,0x9A,0x85,0xBE,0x08,0x1C,0x00,0x05,0xF6,0x4E,0xA4,0xF0,0xC7,0x00,0x29,0xBE,0x08,0x1C,0x00,0x06, +0xE0,0x90,0xF6,0x48,0x48,0x48,0xCA,0x00,0x29,0xC7,0x00,0x29,0xBE,0x08,0x1C,0x00,0x07,0xF6,0x48,0x48,0xCA,0x00,0x29,0xC7,0x00,0x29,0xBE,0x08,0x1C,0x00,0x08,0xF6,0x48,0xCA, +0x00,0x91,0x00,0x29,0xC7,0x00,0x29,0xBE,0x08,0x1C,0x00,0x09,0xF6,0xCA,0x00,0x29,0xC7,0x00,0x29,0xA6,0x01,0xCC,0x9A,0x85,0x72,0x5F,0x00,0x1F,0x35,0x01,0x00,0x20,0x72,0x5F, +0x20,0x91,0x00,0x21,0x72,0x5F,0x00,0x22,0xAE,0x00,0x1C,0xCC,0x92,0x9B,0xCD,0x99,0xED,0xBF,0x08,0xCD,0x92,0x4D,0xBE,0x08,0xCD,0x92,0x33,0xA1,0x00,0x27,0x28,0xBE,0x08,0x1C, +0x40,0x91,0x00,0x04,0xF6,0x48,0xBE,0x08,0x1C,0x00,0x05,0xFA,0xA1,0x03,0x26,0x05,0xA6,0x02,0xCC,0x9A,0x85,0xA1,0x02,0x26,0x05,0xA6,0x03,0xCC,0x9A,0x85,0xA1,0x01,0x26,0x05, +0x60,0x91,0xA6,0x01,0xCC,0x9A,0x85,0x4F,0xCC,0x9A,0x85,0x72,0x5F,0x00,0x1F,0x72,0x5F,0x00,0x20,0x35,0x01,0x00,0x21,0x72,0x5F,0x00,0x22,0xAE,0x00,0x1C,0xCC,0x92,0x9B,0xCD, +0x80,0x91,0x99,0xED,0xBF,0x08,0xCD,0x92,0x4D,0xBE,0x08,0xCD,0x92,0x33,0xA1,0x00,0x26,0x03,0xCC,0x92,0x19,0xBE,0x08,0x1C,0x00,0x03,0x7D,0x27,0x7E,0xBE,0x08,0x1C,0x00,0x05, +0xA0,0x91,0xF6,0x5F,0x97,0xCD,0x9C,0xA9,0xBF,0x00,0xBE,0x08,0x1C,0x00,0x04,0xF6,0x5F,0x97,0xCD,0x9C,0xA8,0x01,0xBA,0x01,0x01,0xBA,0x00,0x01,0x90,0x93,0xBE,0x08,0x1C,0x00, +0xC0,0x91,0x06,0xF6,0x5F,0x97,0x58,0x58,0x58,0xBF,0x00,0x93,0x01,0xBA,0x01,0x01,0xBA,0x00,0x01,0x90,0x93,0xBE,0x08,0x1C,0x00,0x07,0xF6,0x5F,0x97,0x58,0x58,0xBF,0x00,0x93, +0xE0,0x91,0x01,0xBA,0x01,0x01,0xBA,0x00,0x01,0x90,0x93,0xBE,0x08,0x1C,0x00,0x08,0xF6,0x5F,0x97,0x58,0xBF,0x00,0x93,0x01,0xBA,0x01,0x01,0xBA,0x00,0x01,0x90,0xBE,0x08,0x72, +0x00,0x92,0xA9,0x00,0x09,0x90,0xF6,0x90,0x5F,0x90,0x97,0x90,0xBF,0x00,0x01,0xBA,0x01,0x02,0xCD,0x9C,0xA9,0x1C,0x0D,0x4C,0xCC,0x9A,0x85,0x5F,0xCC,0x9A,0x85,0x72,0x5F,0x00, +0x20,0x92,0x1F,0x72,0x5F,0x00,0x20,0x72,0x5F,0x00,0x21,0x35,0x01,0x00,0x22,0xAE,0x00,0x1C,0xCC,0x92,0x9B,0xF6,0xA1,0x01,0x26,0x13,0x90,0x93,0x90,0x5C,0x90,0x7D,0x26,0x0B, +0x40,0x92,0x1C,0x00,0x02,0xF6,0xA1,0x01,0x26,0x03,0xA6,0x01,0x81,0x4F,0x81,0xCD,0x9A,0x2A,0x3B,0x00,0x0C,0xBF,0x08,0xCD,0x94,0xD9,0xCD,0x9F,0x52,0x3F,0x0C,0x20,0x19,0xCD, +0x60,0x92,0x9F,0x6C,0x5F,0x41,0xB6,0x0C,0x41,0x72,0xBB,0x00,0x08,0xBF,0x0A,0xCD,0x94,0xA0,0x92,0xC7,0x0A,0xB6,0x0C,0x4C,0xB7,0x0C,0xB6,0x0C,0xA1,0x0A,0x24,0x17,0x4F,0xCD, +0x80,0x92,0x94,0xE6,0xCD,0x9F,0x45,0xA6,0x01,0xCD,0x94,0xE6,0x3D,0x0C,0x26,0xD1,0xA6,0x04,0xCD,0x9E,0xA4,0x20,0xCD,0x32,0x00,0x0C,0xCC,0x9A,0x7A,0xCD,0x99,0xED,0x3B,0x00, +0xA0,0x92,0x0A,0xBF,0x08,0xCD,0x94,0xC8,0xCD,0x94,0xF3,0xCD,0x9F,0x52,0x3F,0x0A,0x20,0x21,0x4F,0xCD,0x94,0xE6,0x5F,0x41,0xB6,0x0A,0x41,0x72,0xBB,0x00,0x08,0xF6,0xCD,0x94, +0xC0,0x92,0xAA,0xCD,0x9F,0x45,0xA6,0x01,0xCD,0x94,0xE6,0xCD,0x9F,0x6C,0xB6,0x0A,0x4C,0xB7,0x0A,0xB6,0x0A,0xA1,0x08,0x25,0xD9,0x32,0x00,0x0A,0xCC,0x9A,0x85,0xC6,0x00,0x28, +0xE0,0x92,0xA1,0xFF,0x27,0x07,0xC6,0x00,0x28,0x4C,0xC7,0x00,0x28,0xAE,0x00,0x28,0x35,0x01,0x00,0x00,0x4F,0xCC,0x9A,0x96,0x4D,0x26,0x0A,0xA6,0x04,0xCD,0x93,0x29,0xA3,0x04, +0x00,0x93,0xC7,0x25,0x17,0xC6,0x00,0x28,0x27,0x07,0xC6,0x00,0x28,0x4A,0xC7,0x00,0x28,0xAE,0x00,0x28,0x35,0x01,0x00,0x00,0x4F,0xCD,0x9A,0x96,0x81,0xC7,0x00,0x28,0xAE,0x00, +0x20,0x93,0x28,0x35,0x01,0x00,0x00,0x4F,0xCC,0x9A,0x96,0xCD,0x9A,0x2A,0xB7,0x08,0xA6,0x03,0xCD,0x93,0x59,0xBF,0x0A,0x26,0x04,0x5F,0x5C,0xBF,0x0A,0xB6,0x08,0xCD,0x93,0x59, +0x40,0x93,0xBF,0x02,0x5F,0xBF,0x00,0xBF,0x08,0xCD,0x98,0x07,0x00,0x00,0x09,0xC4,0xCD,0x9A,0x89,0xCD,0x98,0x91,0xBE,0x02,0xCC,0x9A,0x7A,0xCD,0x99,0xED,0xB7,0x08,0xCD,0x9F, +0x60,0x93,0xC1,0xB6,0x08,0xCD,0x9C,0xAE,0xBF,0x08,0xCD,0x9F,0xC1,0xBE,0x08,0xCC,0x9A,0x85,0x35,0x7F,0x50,0xD2,0x35,0x80,0x50,0xD1,0x35,0x7F,0x50,0xD2,0x81,0xCD,0x95,0x28, +0x80,0x93,0xCD,0x95,0x0E,0xCD,0x94,0xD9,0xCD,0x94,0x71,0xCD,0x94,0x8F,0xCD,0x94,0xC8,0xCD,0x94,0xF3,0xA6,0x01,0xCD,0x94,0xAA,0xA6,0x01,0xCD,0x94,0xE6,0xCD,0x94,0x53,0x35, +0xA0,0x93,0x01,0x00,0x1C,0x72,0x5F,0x00,0x1D,0x35,0x01,0x00,0x1E,0x72,0x5F,0x00,0x2A,0x72,0x5F,0x00,0x2B,0x72,0x5F,0x00,0x2D,0x72,0x5F,0x00,0x2F,0x81,0x8A,0x84,0xA4,0xBF, +0xC0,0x93,0x88,0x86,0xCD,0x9A,0x20,0xCD,0x9A,0x25,0xC6,0x00,0x2A,0xA1,0x01,0x27,0x5E,0xC6,0x00,0x2B,0x4C,0xC7,0x00,0x2B,0xC6,0x00,0x2B,0xA1,0x33,0x24,0x50,0xA6,0x02,0xCD, +0xE0,0x93,0x95,0x39,0xCD,0x95,0x04,0xB7,0x00,0xC6,0x00,0x10,0xA1,0x02,0x26,0x05,0xB6,0x00,0xC7,0x00,0x10,0x3D,0x00,0x26,0x07,0xC6,0x00,0x10,0xA1,0x01,0x27,0x0B,0xB6,0x00, +0x00,0x94,0xA1,0x01,0x26,0x0C,0xC6,0x00,0x10,0x26,0x07,0xC6,0x00,0x2C,0x4C,0xC7,0x00,0x2C,0xC6,0x00,0x2C,0xA1,0x14,0x25,0x11,0x72,0x5F,0x00,0x2C,0x35,0x02,0x00,0x10,0x35, +0x20,0x94,0x01,0x00,0x2A,0xCD,0x94,0x34,0x20,0x05,0xB6,0x00,0xC7,0x00,0x10,0xCD,0x9A,0x5C,0xCD,0x9A,0x51,0x80,0xCD,0x94,0xF3,0xA6,0x62,0xCC,0x95,0x39,0x9B,0x72,0x1B,0x50, +0x40,0x94,0x11,0x72,0x1B,0x50,0x12,0x72,0x1A,0x50,0x13,0xC6,0x50,0xA0,0xA4,0x3F,0xC7,0x50,0xA0,0x9B,0x81,0x9B,0x72,0x1B,0x50,0x11,0x72,0x1B,0x50,0x12,0x72,0x1A,0x50,0x13, +0x60,0x94,0xC6,0x50,0xA0,0xA4,0x3F,0xC7,0x50,0xA0,0x72,0x1C,0x50,0xA0,0x9A,0x81,0xCC,0x94,0xB7,0x72,0x1E,0x50,0x0C,0x72,0x1E,0x50,0x0D,0x72,0x1F,0x50,0x0E,0x72,0x1F,0x50, +0x80,0x94,0x0A,0x81,0x4D,0x27,0x05,0x72,0x16,0x50,0x0A,0x81,0x72,0x17,0x50,0x0A,0x81,0x72,0x16,0x50,0x0C,0x72,0x16,0x50,0x0D,0x72,0x17,0x50,0x0E,0x72,0x17,0x50,0x0A,0x81, +0xA0,0x94,0x72,0x0D,0x50,0x10,0x03,0xA6,0x01,0x81,0x4F,0x81,0x4D,0x27,0x05,0x72,0x1C,0x50,0x0F,0x81,0x72,0x1D,0x50,0x0F,0x81,0x72,0x1C,0x50,0x11,0x72,0x1C,0x50,0x12,0x72, +0xC0,0x94,0x1D,0x50,0x13,0x72,0x1C,0x50,0x0F,0x81,0x72,0x1C,0x50,0x11,0x72,0x1C,0x50,0x12,0x72,0x1D,0x50,0x13,0x72,0x1D,0x50,0x0F,0x81,0x72,0x1D,0x50,0x11,0x72,0x1D,0x50, +0xE0,0x94,0x12,0x72,0x1D,0x50,0x13,0x81,0x4D,0x27,0x05,0x72,0x1A,0x50,0x0F,0x81,0x72,0x1B,0x50,0x0F,0x81,0x72,0x1A,0x50,0x11,0x72,0x1A,0x50,0x12,0x72,0x1B,0x50,0x13,0x72, +0x00,0x95,0x1B,0x50,0x0F,0x81,0x72,0x0B,0x50,0x10,0x03,0xA6,0x01,0x81,0x4F,0x81,0x72,0x1B,0x50,0x11,0x72,0x1B,0x50,0x12,0x72,0x1B,0x50,0x13,0x81,0x4D,0x27,0x05,0x72,0x18, +0x20,0x95,0x50,0x0F,0x81,0x72,0x19,0x50,0x0F,0x81,0x72,0x18,0x50,0x11,0x72,0x18,0x50,0x12,0x72,0x19,0x50,0x13,0x72,0x19,0x50,0x0F,0x81,0xCD,0x99,0xED,0xB7,0x09,0x3F,0x08, +0x40,0x95,0x4F,0xB7,0x08,0xB6,0x08,0xB1,0x09,0x24,0x0B,0xCD,0x9F,0x6C,0xB6,0x08,0xAB,0x01,0xB7,0x08,0x20,0xEF,0xCC,0x9A,0x85,0xCD,0x9A,0x2A,0xCD,0x9A,0x2F,0x52,0x05,0x4F, +0x60,0x95,0x6B,0x03,0x6B,0x02,0x3F,0x0C,0x3F,0x0D,0x6B,0x01,0x3F,0x0A,0x3F,0x0B,0xCD,0x9F,0xC1,0xA6,0x28,0xCD,0x9E,0xA4,0xCD,0x8F,0xA6,0xAE,0x00,0x12,0xCD,0x8F,0x39,0xA1, +0x80,0x95,0x00,0x26,0x03,0xCD,0x93,0x70,0x4F,0xCD,0x94,0x82,0xC6,0x00,0x29,0x90,0x5F,0x90,0x97,0xAE,0x00,0x05,0xBF,0x00,0x93,0xCD,0x9C,0x69,0x1C,0x01,0x04,0x1F,0x04,0x20, +0xA0,0x95,0x10,0x0D,0x01,0x26,0x03,0xCD,0x8E,0xAD,0xA6,0x01,0x6B,0x01,0xA6,0x1E,0xCD,0x9E,0xA4,0xCD,0x9F,0xC1,0xA6,0x0F,0xCD,0x9E,0xA4,0xCD,0x92,0x1D,0xAE,0x00,0x12,0xCD, +0xC0,0x95,0x91,0x7F,0xBF,0x08,0x26,0x03,0xCC,0x97,0x01,0xA3,0x11,0x2C,0x26,0x06,0x35,0x01,0x00,0x0A,0x20,0x13,0x3D,0x0A,0x27,0x0B,0xA3,0x0D,0x9C,0x26,0x06,0x35,0x01,0x00, +0xE0,0x95,0x0B,0x20,0x04,0x3F,0x0A,0x3F,0x0B,0x3D,0x0A,0x27,0x04,0x3D,0x0B,0x26,0xB2,0x0D,0x01,0x26,0xAE,0xB6,0x0D,0xA1,0x1E,0x24,0x06,0x4C,0xB7,0x0D,0xCC,0x96,0x82,0x3F, +0x00,0x96,0x0D,0xA6,0x02,0xCD,0x93,0x29,0x1C,0xFE,0x16,0x90,0xAE,0x00,0x52,0xCD,0x9C,0x87,0xA3,0x00,0x00,0x2F,0x10,0x1C,0x00,0x07,0xBF,0x00,0x1E,0x04,0x57,0x57,0xCD,0x9C, +0x20,0x96,0x69,0xBF,0x0E,0x20,0x08,0x1E,0x04,0x57,0x72,0xFB,0x04,0xBF,0x0E,0xCD,0x9F,0x52,0xA6,0x04,0xCD,0x93,0x29,0xBF,0x02,0xAE,0x00,0x0B,0xBF,0x00,0xBE,0x02,0xCD,0x9C, +0x40,0x96,0x69,0x90,0xAE,0x00,0x0E,0xCD,0x9C,0x87,0x90,0x93,0xBE,0x02,0x58,0xBF,0x00,0x93,0x72,0xBB,0x00,0x00,0xBF,0x00,0xBE,0x0E,0x72,0xBB,0x00,0x08,0xB3,0x00,0x2E,0x20, +0x60,0x96,0xB6,0x0C,0x4C,0xB7,0x0C,0xA1,0x0B,0x25,0x19,0xCD,0x8F,0xBC,0x4F,0xCD,0x94,0xE6,0xCD,0x9F,0x52,0xA6,0x01,0xCD,0x94,0xE6,0xCD,0x9F,0x52,0xCD,0x93,0x70,0x20,0x02, +0x80,0x96,0x3F,0x0C,0xA6,0x08,0xCD,0x9E,0xA4,0x0D,0x03,0x27,0x0F,0xA6,0x01,0x90,0xAE,0x02,0xF0,0xAE,0x02,0x8E,0xCD,0x8C,0xC7,0xCC,0x95,0xB1,0x0D,0x02,0x27,0x1E,0xBE,0x08, +0xA0,0x96,0xA3,0x10,0xE1,0x2E,0x17,0xCE,0x00,0x26,0xA3,0x04,0x36,0x2E,0x2A,0xA6,0x01,0x90,0xCE,0x00,0x26,0xCE,0x00,0x24,0xCD,0x8C,0xC7,0xCC,0x95,0xB1,0xBE,0x08,0xA3,0x10, +0xC0,0x96,0xCC,0x2F,0xEA,0x1C,0xEF,0x34,0xA3,0x00,0x15,0x24,0x1B,0xA6,0x01,0x6B,0x02,0xCE,0x00,0x26,0xA3,0x04,0x36,0x2F,0xD6,0xA6,0x01,0x90,0xAE,0x04,0x36,0xAE,0x03,0xD4, +0xE0,0x96,0xCD,0x8C,0xC7,0xCC,0x95,0xB1,0xBE,0x08,0xA3,0x10,0xE1,0x2E,0x03,0xCC,0x95,0xB1,0xA6,0x01,0x6B,0x03,0x90,0xAE,0x02,0xF0,0xAE,0x02,0x8E,0xCD,0x8C,0xC7,0xCC,0x95, +0x00,0x97,0xB1,0xCD,0x93,0x70,0xCC,0x95,0xB1,0xCD,0x9A,0x2A,0xCD,0x99,0xF2,0x3B,0x00,0x0E,0x3F,0x0C,0x3F,0x0E,0x3F,0x0D,0x3F,0x0B,0x3F,0x0A,0xCD,0x9F,0x33,0xA6,0x01,0xCD, +0x20,0x97,0x94,0x82,0xA6,0xFF,0xCD,0x93,0x1B,0xA6,0x14,0xCD,0x9E,0xA4,0x4F,0xCD,0x94,0x82,0xCD,0x9F,0xC1,0xA6,0xC8,0xCD,0x9E,0xA4,0xA6,0xC8,0xCD,0x9E,0xA4,0xCD,0x9F,0xC1, +0x40,0x97,0xA6,0xC8,0xCD,0x9E,0xA4,0xA6,0xB4,0xCD,0x9E,0xA4,0xA6,0x01,0xCD,0x95,0x1B,0x20,0x0D,0xCD,0x94,0x6E,0x3F,0x0C,0x3F,0x0E,0x3F,0x0D,0x72,0x5F,0x00,0x2E,0xCD,0x9F, +0x60,0x97,0xC1,0xCD,0x8E,0xFD,0x4F,0x90,0xAE,0x03,0x10,0xAE,0x02,0x8E,0xCD,0x8C,0xC7,0xA6,0x14,0xCD,0x9E,0xA4,0xA6,0x02,0xCD,0x93,0x29,0xBF,0x08,0xA3,0x00,0x41,0x2E,0x20, +0x80,0x97,0xB6,0x0B,0x4C,0xB7,0x0B,0xA1,0x03,0x25,0x19,0x35,0x03,0x00,0x0B,0x72,0x5F,0x00,0x2B,0x72,0x5F,0x00,0x2A,0x3F,0x0A,0x72,0x5F,0x00,0x2C,0xCD,0x94,0x53,0x20,0x02, +0xA0,0x97,0x3F,0x0B,0xBE,0x08,0xA3,0x01,0x46,0x2E,0x05,0xC6,0x00,0x2A,0x27,0xA3,0x3D,0x0E,0x26,0x12,0xB6,0x0D,0xA1,0xC8,0x24,0xA6,0xCD,0x9F,0x84,0xB7,0x0E,0xB6,0x0D,0x4C, +0xC0,0x97,0xB7,0x0D,0x20,0x9A,0xC6,0x00,0x2A,0x26,0x11,0xB6,0x0C,0xA1,0x64,0x24,0x05,0x4C,0xB7,0x0C,0x20,0x8A,0x35,0x64,0x00,0x0C,0x20,0x15,0x3D,0x0A,0x26,0x11,0x35,0x01, +0xE0,0x97,0x00,0x0A,0xA6,0xC8,0xCD,0x9E,0xA4,0xA6,0xC8,0xCD,0x9E,0xA4,0xCD,0x9F,0xC1,0xCD,0x94,0x3C,0xCD,0x98,0xFE,0xA1,0x00,0x27,0x08,0xA6,0x50,0xCD,0x9E,0xA4,0xCC,0x97, +0x00,0x98,0x5E,0x32,0x00,0x0E,0xCC,0x9A,0x7E,0xCD,0x9F,0x90,0x89,0xFE,0xBF,0x04,0x85,0xEE,0x02,0xBF,0x06,0xB6,0x00,0xBE,0x06,0x42,0x9F,0xB7,0x00,0xB6,0x01,0xBE,0x05,0x42, +0x20,0x98,0x9F,0xBB,0x00,0xB7,0x00,0xB6,0x02,0xBE,0x04,0x42,0x9F,0xBB,0x00,0xB7,0x00,0xB6,0x03,0xBE,0x03,0x42,0x9F,0xBB,0x00,0xB7,0x00,0xB6,0x01,0xBE,0x06,0x42,0x3F,0x01, +0x40,0x98,0x72,0xBB,0x00,0x00,0xBF,0x00,0xB6,0x02,0xBE,0x05,0x42,0x72,0xBB,0x00,0x00,0xBF,0x00,0xB6,0x03,0xBE,0x04,0x42,0x72,0xBB,0x00,0x00,0xBF,0x00,0xB6,0x02,0xBE,0x06, +0x60,0x98,0x42,0x3F,0x02,0x72,0xBB,0x00,0x01,0xBF,0x01,0x24,0x02,0x3C,0x00,0xB6,0x03,0xBE,0x05,0x42,0x72,0xBB,0x00,0x01,0xBF,0x01,0x24,0x02,0x3C,0x00,0xB6,0x03,0xBE,0x06, +0x80,0x98,0x42,0x3F,0x03,0x72,0xBB,0x00,0x02,0xBF,0x02,0x24,0x05,0xBE,0x00,0x5C,0xBF,0x00,0x81,0xBE,0x00,0x26,0x1E,0x90,0xBE,0x04,0x26,0x0C,0xBE,0x02,0x90,0xBE,0x06,0x65, +0xA0,0x98,0xBF,0x02,0x90,0xBF,0x06,0x81,0xBF,0x04,0x45,0x02,0x06,0x45,0x03,0x07,0xBF,0x00,0xBF,0x02,0x81,0xA6,0x20,0x3D,0x00,0x26,0x0D,0xBE,0x01,0xBF,0x00,0x45,0x03,0x02, +0xC0,0x98,0x3F,0x03,0x3A,0x03,0xA0,0x08,0x5F,0x90,0x5F,0x99,0x20,0x17,0x90,0x59,0x59,0xB3,0x04,0x26,0x03,0x90,0xB3,0x06,0x25,0x0B,0x72,0xB2,0x00,0x06,0x24,0x01,0x5A,0x72, +0xE0,0x98,0xB0,0x00,0x04,0x39,0x03,0x39,0x02,0x39,0x01,0x39,0x00,0x4A,0x2A,0xDE,0xBF,0x04,0x90,0xBF,0x06,0xBE,0x00,0x53,0xBF,0x00,0xBE,0x02,0x53,0xBF,0x02,0x81,0xCD,0x9F, +0x00,0x99,0xC1,0xCD,0x91,0x16,0xAE,0x00,0x12,0xCD,0x90,0xA4,0x4D,0x26,0x1C,0xC6,0x00,0x2D,0x26,0x03,0xCC,0x99,0xEA,0xA6,0x1E,0xCD,0x9E,0xA4,0xCD,0x90,0x79,0xAE,0x00,0x12, +0x20,0x99,0xCD,0x90,0x4F,0xC7,0x00,0x2E,0xCC,0x99,0xEA,0xA1,0x01,0x27,0x03,0xCC,0x99,0xEA,0xC6,0x00,0x2E,0x27,0x23,0xA6,0x1E,0xCD,0x9E,0xA4,0xCD,0x90,0x39,0xAE,0x00,0x12, +0x40,0x99,0xCD,0x90,0x0A,0xA1,0x02,0x26,0x0B,0x35,0x01,0x00,0x2F,0xA6,0x01,0xCD,0x8E,0x74,0x20,0x06,0x4D,0x26,0x03,0xCD,0x93,0x70,0xA6,0x1E,0xCD,0x9E,0xA4,0xC6,0x00,0x29, +0x60,0x99,0xA1,0x05,0x26,0x31,0xA6,0xFF,0xCD,0x93,0x1B,0x20,0x0E,0x35,0x02,0x00,0x11,0xA6,0x50,0xCD,0x9E,0xA4,0xA6,0x01,0xCD,0x8D,0xAE,0xCD,0x9F,0xC1,0xCD,0x8F,0xF4,0xAE, +0x80,0x99,0x00,0x12,0xCD,0x8F,0xD2,0xA1,0x00,0x26,0xE2,0xC6,0x00,0x11,0xA1,0x02,0x26,0x5A,0xCD,0x93,0x70,0x20,0xE4,0xA6,0x01,0xCD,0x94,0x82,0xA6,0x0A,0xCD,0x9E,0xA4,0xA6, +0xA0,0x99,0xEB,0xCD,0x93,0x1B,0xA6,0x0A,0xCD,0x9E,0xA4,0xA6,0xDC,0xCD,0x93,0x1B,0xA6,0x0A,0xCD,0x9E,0xA4,0xA6,0xCD,0xCD,0x93,0x1B,0xA6,0x0A,0xCD,0x9E,0xA4,0xA6,0xBE,0xCD, +0xC0,0x99,0x93,0x1B,0xA6,0x0A,0xCD,0x9E,0xA4,0xA6,0xAF,0xCD,0x93,0x1B,0xA6,0x0A,0xCD,0x9E,0xA4,0xA6,0xA0,0xCD,0x93,0x1B,0xA6,0x14,0xCD,0x9E,0xA4,0xCD,0x8C,0x80,0xA1,0x00, +0xE0,0x99,0x27,0x05,0xCD,0x95,0x57,0x4F,0x81,0xCD,0x93,0x70,0xA6,0x01,0x81,0x88,0xA6,0x08,0x20,0x05,0x88,0xA6,0x0C,0x20,0x00,0x88,0x7B,0x02,0x88,0x7B,0x02,0x89,0x1E,0x06, +0x00,0x9A,0x1F,0x04,0x5F,0x97,0xFE,0x1F,0x06,0x85,0x84,0x81,0x89,0x1E,0x05,0xBF,0x08,0x20,0x07,0x89,0x1E,0x05,0xBF,0x0C,0x20,0x00,0x1E,0x03,0x1F,0x05,0x85,0x5B,0x02,0x81, +0x20,0x9A,0x88,0xA6,0x00,0x20,0x0F,0x88,0xA6,0x04,0x20,0x0A,0x88,0xA6,0x08,0x20,0x05,0x88,0xA6,0x0C,0x20,0x00,0x88,0x89,0x7B,0x04,0x88,0x7B,0x04,0x89,0x1E,0x08,0x1F,0x04, +0x40,0x9A,0x5F,0x97,0x1F,0x08,0xFE,0x1F,0x06,0x1E,0x08,0x5C,0x5C,0xFE,0x1F,0x08,0x85,0x84,0x81,0x89,0x1E,0x05,0xBF,0x00,0x1E,0x07,0xBF,0x02,0x20,0x16,0x89,0x1E,0x05,0xBF, +0x60,0x9A,0x04,0x1E,0x07,0xBF,0x06,0x20,0x0B,0x89,0x1E,0x05,0xBF,0x08,0x1E,0x07,0xBF,0x0A,0x20,0x00,0x1E,0x03,0x1F,0x07,0x85,0x5B,0x04,0x81,0xCD,0x9A,0x67,0x81,0xCD,0x9A, +0x80,0x9A,0x11,0xCD,0x9A,0x67,0x81,0xCD,0x9A,0x0A,0x81,0x45,0x08,0x04,0x45,0x09,0x05,0x45,0x0A,0x06,0x45,0x0B,0x07,0x81,0xCD,0x9A,0x2A,0xB7,0x0A,0x45,0x00,0x0B,0xBF,0x08, +0xA0,0x9A,0xCD,0x9F,0xC1,0x72,0x03,0x52,0x19,0x0B,0x72,0x12,0x52,0x11,0x72,0x02,0x52,0x11,0xFB,0x20,0xF0,0x72,0x10,0x52,0x11,0x72,0x01,0x52,0x17,0xFB,0x35,0x58,0x52,0x16, +0xC0,0x9A,0xCD,0x9F,0xC1,0x72,0x03,0x52,0x17,0xFB,0xC6,0x52,0x19,0x72,0x0F,0x52,0x17,0xFB,0xB6,0x0A,0xC7,0x52,0x16,0x3D,0x0B,0x26,0x18,0x20,0x22,0x72,0x0F,0x52,0x17,0xFB, +0xE0,0x9A,0x9D,0x92,0xC6,0x08,0xC7,0x52,0x16,0x9D,0x3D,0x0B,0x27,0x05,0xBE,0x08,0x5C,0xBF,0x08,0x45,0x0B,0x00,0xB6,0x00,0x4A,0xB7,0x0B,0x3D,0x00,0x26,0xDE,0xC6,0x52,0x17, +0x00,0x9B,0xA4,0x84,0xA1,0x84,0x26,0xF7,0x72,0x12,0x52,0x11,0x72,0x02,0x52,0x11,0xFB,0xCD,0x9F,0xC1,0xCC,0x9A,0x7A,0x52,0x10,0x90,0xAE,0x9F,0xA4,0x96,0x5C,0x89,0xA6,0x08, +0x20,0x9B,0xCD,0x9F,0x5F,0x85,0x90,0xAE,0x9F,0xAC,0x96,0x1C,0x00,0x09,0x89,0xA6,0x08,0xCD,0x9F,0x5F,0x85,0x96,0x5C,0xCD,0x9D,0x2F,0x96,0x1C,0x00,0x09,0xCD,0x9B,0x80,0x7B, +0x40,0x9B,0x01,0xA1,0x09,0x26,0x34,0x35,0x01,0x00,0x02,0x20,0x24,0x90,0x5F,0x61,0x93,0x50,0xBF,0x00,0x96,0x1C,0x00,0x09,0x72,0xBB,0x00,0x00,0x1C,0x00,0x08,0xF6,0x96,0x5C, +0x60,0x9B,0x90,0xBF,0x00,0x72,0xBB,0x00,0x00,0xF1,0x26,0x0F,0xB6,0x02,0x4C,0xB7,0x02,0xB6,0x02,0xA1,0x08,0x25,0xD6,0xA6,0x01,0x20,0x04,0xCD,0x9C,0x17,0x4F,0x5B,0x10,0x81, +0x80,0x9B,0xCD,0x9A,0x2A,0x3B,0x00,0x0C,0xBF,0x08,0xCD,0x9B,0xD5,0x9D,0x9D,0xCD,0x9D,0x67,0xA6,0xCC,0xCD,0x9D,0x9E,0xA6,0x21,0xCD,0x9F,0xB4,0xA6,0xF0,0xCD,0x9D,0x9E,0xA6, +0xA0,0x9B,0x21,0xCD,0x9F,0xB4,0xA6,0x20,0xCD,0x9D,0x9E,0xA6,0x21,0xCD,0x9F,0xB4,0x4F,0xCD,0x9D,0x9E,0x3F,0x0C,0x20,0x13,0x5F,0x41,0x72,0xBB,0x00,0x08,0xBF,0x0A,0xCD,0x9D, +0xC0,0x9B,0xFE,0x92,0xC7,0x0A,0xB6,0x0C,0x4C,0xB7,0x0C,0xB6,0x0C,0xA1,0x08,0x25,0xE7,0x32,0x00,0x0C,0xCC,0x9A,0x7A,0xCD,0x9C,0x06,0xA6,0x01,0xCD,0x9B,0xF9,0xCD,0x9F,0x6C, +0xE0,0x9B,0x4F,0xCD,0x9B,0xF9,0xCD,0x9F,0x6C,0xA6,0x4B,0xCD,0x9F,0xB4,0xCC,0x9C,0x17,0x72,0x05,0x50,0x01,0x03,0xA6,0x01,0x81,0x4F,0x81,0x4D,0x27,0x05,0x72,0x14,0x50,0x00, +0x00,0x9C,0x81,0x72,0x15,0x50,0x00,0x81,0x72,0x14,0x50,0x02,0x72,0x14,0x50,0x03,0x72,0x15,0x50,0x04,0x72,0x15,0x50,0x00,0x81,0x72,0x15,0x50,0x02,0x72,0x15,0x50,0x03,0x72, +0x20,0x9C,0x15,0x50,0x04,0x81,0xC6,0x50,0x05,0xAA,0x30,0xC7,0x50,0x05,0xC6,0x50,0x07,0xAA,0x30,0xC7,0x50,0x07,0xC6,0x50,0x08,0xA4,0xCF,0xC7,0x50,0x08,0xC6,0x50,0x09,0xAA, +0x40,0x9C,0x30,0xC7,0x50,0x09,0x35,0x08,0x52,0x12,0x35,0x28,0x52,0x1B,0x72,0x5F,0x52,0x1C,0x35,0x09,0x52,0x1D,0x35,0xA2,0x52,0x13,0x72,0x1C,0x52,0x14,0x35,0x01,0x52,0x1A, +0x60,0x9C,0x72,0x14,0x52,0x11,0x72,0x10,0x52,0x10,0x81,0x88,0x89,0x5E,0xB6,0x01,0x42,0x89,0x1E,0x03,0xB6,0x00,0x42,0x72,0xFB,0x01,0x4F,0x02,0x89,0x1E,0x05,0xB6,0x01,0x42, +0x80,0x9C,0x72,0xFB,0x01,0x5B,0x06,0x84,0x81,0x5D,0x2B,0x06,0x90,0x5D,0x2B,0x0A,0x65,0x81,0x50,0x90,0x5D,0x2B,0x07,0x65,0x50,0x81,0x90,0x50,0x20,0xF9,0x90,0x50,0x20,0xEE, +0xA0,0x9C,0x4D,0x27,0x04,0x58,0x4A,0x26,0xFC,0x81,0x58,0x58,0x58,0x58,0x58,0x81,0x3B,0x00,0x08,0xB7,0x08,0xCD,0x9E,0x85,0xB6,0x08,0xCA,0x54,0x00,0xC7,0x54,0x00,0xA6,0x32, +0xC0,0x9C,0xB7,0x00,0x4A,0x3D,0x00,0x26,0xF9,0x72,0x10,0x54,0x01,0x72,0x0F,0x54,0x00,0xFB,0x72,0x1F,0x54,0x00,0xC6,0x54,0x05,0xB7,0x00,0xC6,0x54,0x04,0x5F,0x97,0x4F,0x02, +0xE0,0x9C,0x90,0x5F,0xB6,0x00,0x61,0xBF,0x00,0x93,0x02,0xBA,0x00,0x01,0x32,0x00,0x08,0x81,0x3B,0x00,0x08,0xB7,0x08,0xCD,0x9C,0x06,0xA6,0x01,0xCD,0x9B,0xF9,0x9D,0x4F,0xCD, +0x00,0x9D,0x9B,0xF9,0x3D,0x08,0x27,0x11,0xA6,0x03,0xCD,0x9F,0xB4,0xA6,0x01,0xCD,0x9B,0xF9,0xA6,0x21,0xCD,0x9F,0xB4,0x20,0x0F,0xA6,0x21,0xCD,0x9F,0xB4,0xA6,0x01,0xCD,0x9B, +0x20,0x9D,0xF9,0xA6,0x03,0xCD,0x9F,0xB4,0xA6,0x03,0xCD,0x9F,0xB4,0x32,0x00,0x08,0x81,0xCD,0x9A,0x2A,0x3B,0x00,0x0C,0xBF,0x08,0xCD,0x9B,0xD5,0xCD,0x9D,0x67,0x9D,0x9D,0xA6, +0x40,0x9D,0x33,0xCD,0x9D,0x9E,0x3F,0x0C,0x20,0x13,0x5F,0x41,0x72,0xBB,0x00,0x08,0xBF,0x0A,0xCD,0x9D,0xFE,0x92,0xC7,0x0A,0xB6,0x0C,0x4C,0xB7,0x0C,0xB6,0x0C,0xA1,0x08,0x25, +0x60,0x9D,0xE7,0x32,0x00,0x0C,0xCC,0x9A,0x7A,0xCD,0x99,0xED,0x3B,0x00,0x0A,0xAE,0x01,0x2C,0xBF,0x08,0x3F,0x0A,0x20,0x04,0x35,0x01,0x00,0x0A,0xBE,0x08,0xA3,0x00,0x01,0x2F, +0x80,0x9D,0x12,0x3D,0x0A,0x26,0x0E,0xCD,0x9B,0xEF,0xA1,0x00,0x27,0xEA,0xBE,0x08,0x5A,0xBF,0x08,0x20,0xE7,0xCD,0x9F,0x6C,0xB6,0x0A,0x32,0x00,0x0A,0xCC,0x9A,0x85,0xCD,0x99, +0xA0,0x9D,0xED,0x3B,0x00,0x0A,0xB7,0x0A,0x35,0x01,0x00,0x09,0x3F,0x08,0x20,0x11,0xB6,0x09,0xB4,0x0A,0xCD,0x9C,0xF0,0xB6,0x09,0x48,0xB7,0x09,0xB6,0x08,0x4C,0xB7,0x08,0xB6, +0xC0,0x9D,0x08,0xA1,0x08,0x25,0xE9,0xA6,0x37,0xCD,0x9F,0xB4,0x32,0x00,0x0A,0xCC,0x9A,0x85,0x3B,0x00,0x08,0xCD,0x9C,0x17,0x9D,0x9D,0x9D,0xCD,0x9C,0x06,0x4F,0xCD,0x9B,0xF9, +0xE0,0x9D,0x9D,0xCD,0x9C,0x17,0xA6,0x03,0xCD,0x9F,0xB4,0x9D,0x9D,0xCD,0x9B,0xEF,0xB7,0x08,0xA6,0x21,0xCD,0x9F,0xB4,0xCD,0x9C,0x17,0xB6,0x08,0x32,0x00,0x08,0x81,0xCD,0x99, +0x00,0x9E,0xED,0x3F,0x09,0x3F,0x08,0x20,0x14,0xCD,0x9D,0xD0,0x5F,0x97,0xB6,0x08,0xCD,0x9C,0xA0,0x9F,0xBA,0x09,0xB7,0x09,0xB6,0x08,0x4C,0xB7,0x08,0xB6,0x08,0xA1,0x08,0x25, +0x20,0x9E,0xE6,0xB6,0x09,0xCC,0x9A,0x85,0x89,0xFE,0x90,0x93,0x85,0x5C,0x5C,0x90,0x5D,0x27,0x1C,0x89,0xFE,0xBF,0x00,0x85,0x5C,0x5C,0x89,0xFE,0xBF,0x02,0x85,0x5C,0x5C,0x51, +0x40,0x9E,0x5A,0x92,0xD6,0x00,0x92,0xD7,0x02,0x5A,0x2A,0xF7,0x51,0x20,0xD9,0x81,0x72,0x15,0x50,0x11,0x72,0x15,0x50,0x12,0x72,0x15,0x50,0x13,0x72,0x17,0x50,0x11,0x72,0x17, +0x60,0x9E,0x50,0x12,0x72,0x17,0x50,0x13,0x72,0x19,0x50,0x0C,0x72,0x19,0x50,0x0D,0x72,0x19,0x50,0x0E,0x81,0x9E,0xC2,0x00,0x21,0x00,0x12,0x00,0x00,0x9E,0x26,0x00,0x02,0x9F, +0x80,0x9E,0xDC,0x00,0x10,0x00,0x00,0x72,0x5F,0x54,0x00,0xC6,0x54,0x01,0xA4,0x8F,0xC7,0x54,0x01,0xC6,0x54,0x01,0xC7,0x54,0x01,0x72,0x13,0x54,0x01,0x72,0x16,0x54,0x02,0x72, +0xA0,0x9E,0x10,0x54,0x01,0x81,0xCD,0x99,0xED,0xB7,0x09,0x3F,0x08,0x4F,0xB7,0x08,0xB6,0x08,0xB1,0x09,0x24,0x0B,0xCD,0x9F,0x78,0xB6,0x08,0xAB,0x01,0xB7,0x08,0x20,0xEF,0xCC, +0xC0,0x9E,0x9A,0x85,0x89,0xFE,0x90,0x93,0x85,0x5C,0x5C,0x90,0x5D,0x27,0x12,0x89,0xFE,0xBF,0x00,0x85,0x5C,0x5C,0x51,0x5A,0x92,0x6F,0x00,0x5A,0x2A,0xFA,0x51,0x20,0xE3,0x81, +0xE0,0x9E,0x90,0xAE,0x9E,0x73,0x20,0x0A,0x93,0x1C,0x00,0x02,0x90,0xFE,0x90,0xFD,0x90,0x93,0x90,0xA3,0x9E,0x85,0x26,0xF0,0x81,0x35,0xCC,0x50,0xE0,0x35,0x55,0x50,0xE0,0x35, +0x00,0x9F,0x06,0x50,0xE1,0x35,0xFF,0x50,0xE2,0x35,0xAA,0x50,0xE0,0x81,0xCD,0x99,0xED,0x52,0x02,0xBF,0x08,0xBE,0x08,0x1F,0x01,0x96,0x5C,0xA6,0x01,0xCD,0x9F,0xDB,0x20,0xF3, +0x20,0x9F,0xAE,0x03,0xFF,0x94,0xCD,0x9F,0xD2,0x5D,0x27,0x03,0xCD,0x9E,0xE0,0xCD,0x97,0x07,0xCC,0x9F,0xD5,0xCD,0x9F,0xBC,0xCD,0x8E,0xFD,0xCD,0x93,0x7D,0xCD,0x9E,0x4E,0xCD, +0x40,0x9F,0x9C,0x24,0xCC,0x9E,0xF7,0xA6,0x07,0xB7,0x00,0xB6,0x00,0xAB,0xFF,0x3D,0x00,0x26,0xF6,0x81,0xA6,0x1A,0xB7,0x00,0xB6,0x00,0xAB,0xFF,0x3D,0x00,0x26,0xF6,0x81,0x88, +0x60,0x9F,0x90,0xF6,0xF7,0x5C,0x90,0x5C,0x0A,0x01,0x26,0xF6,0x84,0x81,0xAE,0x00,0xFA,0x90,0x93,0x93,0x5A,0x90,0x5D,0x26,0xF8,0x81,0xAE,0x01,0xF4,0x90,0x93,0x93,0x5A,0x90, +0x80,0x9F,0x5D,0x26,0xF8,0x81,0xCD,0x9B,0x15,0xA1,0x01,0x26,0x03,0xA6,0x01,0x81,0x4F,0x81,0x1E,0x03,0x1C,0x00,0x04,0x1F,0x03,0x1D,0x00,0x04,0x81,0x35,0x56,0x50,0x62,0x35, +0xA0,0x9F,0xAE,0x50,0x62,0x81,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xB7,0x00,0x4A,0x3D,0x00,0x26,0xF9,0x81,0x35,0x02,0x50,0xC6, +0xC0,0x9F,0x81,0x35,0xAA,0x50,0xE0,0x81,0x89,0x85,0xCD,0x9F,0x0C,0x00,0x00,0x00,0x00,0xCC,0x9F,0xD8,0x5F,0x5C,0x81,0xCC,0x9F,0xC6,0x9D,0x20,0xFD,0x81,0x02,0x01,0x00,0x00, +0xE0,0x9F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0B,0x34,0x55,0x34, +}; +#endif diff --git a/drivers/power/supply/qcom/qg-reg.h b/drivers/power/supply/qcom/qg-reg.h index f6ee0807022c..f97d8c3d1f1f 100644 --- a/drivers/power/supply/qcom/qg-reg.h +++ b/drivers/power/supply/qcom/qg-reg.h @@ -127,7 +127,6 @@ #define QG_SDAM_ESR_CHARGE_SF_OFFSET 0x72 /* 2-byte 0x72-0x73 */ #define QG_SDAM_ESR_DISCHARGE_SF_OFFSET 0x74 /* 2-byte 0x74-0x75 */ #define QG_SDAM_BATT_AGE_LEVEL_OFFSET 0x76 /* 1-byte 0x76 */ -#define QG_SDAM_MAGIC_OFFSET 0x80 /* 4-byte 0x80-0x83 */ #define QG_SDAM_FLASH_OCV_OFFSET 0x84 /* 1-byte 0x84 */ #define QG_SDAM_MAX_OFFSET 0xA4 diff --git a/drivers/power/supply/qcom/qg-sdam.c b/drivers/power/supply/qcom/qg-sdam.c index 8f48afa51fec..74e9a0edb4ba 100644 --- a/drivers/power/supply/qcom/qg-sdam.c +++ b/drivers/power/supply/qcom/qg-sdam.c @@ -86,11 +86,6 @@ static struct qg_sdam_info sdam_info[] = { .offset = QG_SDAM_BATT_AGE_LEVEL_OFFSET, .length = 1, }, - [SDAM_MAGIC] = { - .name = "SDAM_MAGIC_OFFSET", - .offset = QG_SDAM_MAGIC_OFFSET, - .length = 4, - }, [SDAM_FLASH_OCV] = { .name = "SDAM_FLASH_OCV_OFFSET", .offset = QG_SDAM_FLASH_OCV_OFFSET, @@ -250,23 +245,6 @@ int qg_sdam_write_all(u32 *sdam_data) return 0; } -int qg_sdam_clear(void) -{ - int i, rc = 0; - struct qg_sdam *chip = the_chip; - u8 data = 0; - - if (!chip) { - pr_err("Invalid sdam-chip pointer\n"); - return -EINVAL; - } - - for (i = SDAM_MIN_OFFSET; i <= SDAM_MAX_OFFSET; i++) - rc |= qg_sdam_multibyte_write(i, &data, 1); - - return rc; -} - int qg_sdam_init(struct device *dev) { int rc; diff --git a/drivers/power/supply/qcom/qg-sdam.h b/drivers/power/supply/qcom/qg-sdam.h index 77385b807f21..5222b87380b0 100644 --- a/drivers/power/supply/qcom/qg-sdam.h +++ b/drivers/power/supply/qcom/qg-sdam.h @@ -7,8 +7,6 @@ #define __QG_SDAM_H__ #define SDAM_TYPE 0x2E -#define SDAM_MIN_OFFSET 0x45 -#define SDAM_MAX_OFFSET 0xB3 enum qg_sdam_param { SDAM_VALID, @@ -23,7 +21,6 @@ enum qg_sdam_param { SDAM_ESR_DISCHARGE_DELTA, SDAM_ESR_CHARGE_SF, SDAM_ESR_DISCHARGE_SF, - SDAM_MAGIC, SDAM_BATT_AGE_LEVEL, SDAM_FLASH_OCV, SDAM_MAX, @@ -41,6 +38,5 @@ int qg_sdam_write_all(u32 *sdam_data); int qg_sdam_read_all(u32 *sdam_data); int qg_sdam_multibyte_write(u32 offset, u8 *sdam_data, u32 length); int qg_sdam_multibyte_read(u32 offset, u8 *sdam_data, u32 length); -int qg_sdam_clear(void); #endif diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c index e255a0abdbca..fe42ee05997a 100644 --- a/drivers/power/supply/qcom/qpnp-fg-gen3.c +++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c @@ -17,6 +17,8 @@ #include #include "fg-core.h" #include "fg-reg.h" +/* david.liu@bsp, 20171023 Battery & Charging porting */ +#include #define FG_GEN3_DEV_NAME "qcom,fg-gen3" @@ -156,6 +158,14 @@ #define KI_COEFF_SOC_LEVELS 3 #define BATT_THERM_NUM_COEFFS 3 +/* david.liu@bsp, 20171023 Battery & Charging porting */ +static void oem_update_cc_cv_setpoint(struct fg_dev *fg, + int cv_float_point); +static void oneplus_set_allow_read_iic(struct fg_dev *fg, + bool status); +static void oneplus_set_lcd_off_status(struct fg_dev *fg, + bool status); + static struct fg_irq_info fg_irqs[FG_GEN3_IRQ_MAX]; /* DT parameters for FG device */ @@ -486,6 +496,25 @@ static ssize_t profile_dump_store(struct device *dev, } static DEVICE_ATTR_RW(profile_dump); +/* david.liu@bsp, 20171023 Battery & Charging porting */ +void external_battery_gauge_register( + struct external_battery_gauge *batt_gauge) +{ + if (external_fg) { + external_fg = batt_gauge; + pr_err("multiple battery gauge called\n"); + } else + external_fg = batt_gauge; +} +EXPORT_SYMBOL(external_battery_gauge_register); + +void external_battery_gauge_unregister( + struct external_battery_gauge *batt_gauge) +{ + external_fg = NULL; +} +EXPORT_SYMBOL(external_battery_gauge_unregister); + static int fg_sram_dump_period_ms = 20000; static ssize_t sram_dump_period_ms_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -767,6 +796,8 @@ static int fg_batt_missing_config(struct fg_dev *fg, bool enable) return rc; } +/* david.liu@bsp, 20171023 Battery & Charging porting */ +#define OP_SW_DEFAULT_ID 200000 static int fg_get_batt_id(struct fg_dev *fg) { struct fg_gen3_chip *chip = container_of(fg, struct fg_gen3_chip, fg); @@ -791,7 +822,8 @@ static int fg_get_batt_id(struct fg_dev *fg) msleep(chip->dt.bmd_en_delay_ms); fg_dbg(fg, FG_STATUS, "batt_id: %d\n", batt_id); - fg->batt_id_ohms = batt_id; +/* Yangfb@bsp, 20170110 Add OP battery profile */ + fg->batt_id_ohms = OP_SW_DEFAULT_ID; out: ret = fg_batt_missing_config(fg, true); if (ret < 0) { @@ -947,7 +979,6 @@ static int fg_delta_bsoc_irq_en_cb(struct votable *votable, void *data, if (enable) { enable_irq(fg->irqs[BSOC_DELTA_IRQ].irq); - enable_irq_wake(fg->irqs[BSOC_DELTA_IRQ].irq); } else { disable_irq_wake(fg->irqs[BSOC_DELTA_IRQ].irq); disable_irq_nosync(fg->irqs[BSOC_DELTA_IRQ].irq); @@ -3433,6 +3464,8 @@ static int fg_update_maint_soc(struct fg_dev *fg) return rc; } +/* david.liu@bsp, 20171023 Battery & Charging porting */ +#define DEFALUT_BATT_TEMP 250 static int fg_esr_validate(struct fg_dev *fg) { struct fg_gen3_chip *chip = container_of(fg, struct fg_gen3_chip, fg); @@ -3647,25 +3680,44 @@ static int fg_psy_get_property(struct power_supply *psy, switch (psp) { case POWER_SUPPLY_PROP_CAPACITY: - rc = fg_get_prop_capacity(fg, &pval->intval); - break; - case POWER_SUPPLY_PROP_REAL_CAPACITY: - rc = fg_get_prop_real_capacity(fg, &pval->intval); +/* david.liu@bsp, 20171023 Battery & Charging porting */ + 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_CAPACITY_RAW: rc = fg_get_msoc_raw(fg, &pval->intval); break; case POWER_SUPPLY_PROP_VOLTAGE_NOW: - if (fg->battery_missing) - pval->intval = 3700000; +/* david.liu@bsp, 20171023 Battery & Charging porting */ + 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); +/* david.liu@bsp, 20171023 Battery & Charging porting */ + 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_TEMP: - rc = fg_get_battery_temp(fg, &pval->intval); +/* david.liu@bsp, 20171023 Battery & Charging porting */ + 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_average_current) { + pval->intval = external_fg->get_battery_temperature(); + } else + pval->intval = -400; break; case POWER_SUPPLY_PROP_COLD_TEMP: rc = fg_get_jeita_threshold(fg, JEITA_COLD, &pval->intval); @@ -3749,6 +3801,26 @@ static int fg_psy_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_DEBUG_BATTERY: pval->intval = is_debug_batt_id(fg); break; +/* david.liu@bsp, 20170303 Add internal FG info */ + case POWER_SUPPLY_PROP_FG_CAPACITY: + rc = fg_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; @@ -3766,6 +3838,9 @@ static int fg_psy_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_CC_STEP_SEL: pval->intval = chip->ttf.cc_step.sel; break; + case POWER_SUPPLY_PROP_REAL_CAPACITY: + rc = fg_get_prop_real_capacity(fg, &pval->intval); + break; case POWER_SUPPLY_PROP_FG_RESET_CLOCK: pval->intval = 0; break; @@ -3884,6 +3959,16 @@ static int fg_psy_set_property(struct power_supply *psy, int rc = 0; switch (psp) { +/* david.liu@bsp, 20171023 Battery & Charging porting */ + case POWER_SUPPLY_PROP_CC_TO_CV_POINT: + oem_update_cc_cv_setpoint(fg, pval->intval); + break; + case POWER_SUPPLY_PROP_SET_ALLOW_READ_EXTERN_FG_IIC: + oneplus_set_allow_read_iic(fg, pval->intval); + break; + case POWER_SUPPLY_PROP_UPDATE_LCD_IS_OFF: + oneplus_set_lcd_off_status(fg, pval->intval); + break; case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: rc = fg_set_constant_chg_voltage(fg, pval->intval); break; @@ -3983,6 +4068,8 @@ static int fg_property_is_writeable(struct power_supply *psy, case POWER_SUPPLY_PROP_COOL_TEMP: case POWER_SUPPLY_PROP_WARM_TEMP: case POWER_SUPPLY_PROP_HOT_TEMP: +/* david.liu@bsp, 20171023 Battery & Charging porting */ + case POWER_SUPPLY_PROP_SET_ALLOW_READ_EXTERN_FG_IIC: return 1; default: break; @@ -4048,7 +4135,6 @@ static int twm_notifier_cb(struct notifier_block *nb, static enum power_supply_property fg_psy_props[] = { POWER_SUPPLY_PROP_CAPACITY, - POWER_SUPPLY_PROP_REAL_CAPACITY, POWER_SUPPLY_PROP_CAPACITY_RAW, POWER_SUPPLY_PROP_TEMP, POWER_SUPPLY_PROP_COLD_TEMP, @@ -4078,6 +4164,10 @@ static enum power_supply_property fg_psy_props[] = { POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, POWER_SUPPLY_PROP_CC_STEP, POWER_SUPPLY_PROP_CC_STEP_SEL, +/* david.liu@bsp, 20171023 Battery & Charging porting */ + POWER_SUPPLY_PROP_SET_ALLOW_READ_EXTERN_FG_IIC, + POWER_SUPPLY_PROP_BQ_SOC, + POWER_SUPPLY_PROP_REAL_CAPACITY, POWER_SUPPLY_PROP_FG_RESET_CLOCK, }; @@ -4348,6 +4438,14 @@ static int fg_hw_init(struct fg_dev *fg) return rc; } +/* david.liu@bsp, 20171023 Battery & Charging porting */ + 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; + } + fg_encode(fg->sp, FG_SRAM_ESR_PULSE_THRESH, chip->dt.esr_pulse_thresh_ma, buf); rc = fg_sram_write(fg, fg->sp[FG_SRAM_ESR_PULSE_THRESH].addr_word, @@ -4366,6 +4464,14 @@ static int fg_hw_init(struct fg_dev *fg) return rc; } +/* david.liu@bsp, 20171023 Battery & Charging porting */ + 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) || chip->dt.disable_esr_pull_dn) { val = ESR_NO_PULL_DOWN; rc = fg_masked_write(fg, BATT_INFO_ESR_PULL_DN_CFG(fg), @@ -4703,7 +4809,6 @@ static struct fg_irq_info fg_irqs[FG_GEN3_IRQ_MAX] = { [MSOC_DELTA_IRQ] = { .name = "msoc-delta", .handler = fg_delta_msoc_irq_handler, - .wakeable = true, }, [BSOC_DELTA_IRQ] = { .name = "bsoc-delta", @@ -4723,7 +4828,6 @@ static struct fg_irq_info fg_irqs[FG_GEN3_IRQ_MAX] = { [BATT_TEMP_DELTA_IRQ] = { .name = "batt-temp-delta", .handler = fg_delta_batt_temp_irq_handler, - .wakeable = true, }, [BATT_MISSING_IRQ] = { .name = "batt-missing", @@ -5117,6 +5221,11 @@ static int fg_parse_dt(struct fg_gen3_chip *chip) else chip->dt.rsense_sel = (u8)temp & SOURCE_SELECT_MASK; +/* david.liu@bsp, 20171023 Battery & Charging porting */ + fg->use_external_fg = + of_property_read_bool(node, "oem,use_external_fg"); + pr_info("use_external_fg=%d\n", fg->use_external_fg); + chip->dt.jeita_thresholds[JEITA_COLD] = DEFAULT_BATT_TEMP_COLD; chip->dt.jeita_thresholds[JEITA_COOL] = DEFAULT_BATT_TEMP_COOL; chip->dt.jeita_thresholds[JEITA_WARM] = DEFAULT_BATT_TEMP_WARM; @@ -5367,6 +5476,9 @@ static void fg_cleanup(struct fg_gen3_chip *chip) cancel_work_sync(&fg->status_change_work); cancel_work_sync(&fg->esr_filter_work); cancel_delayed_work_sync(&chip->pl_enable_work); +/* david.liu@bsp, 20170314 Fix system crash */ + if (fg->fg_psy) + power_supply_unregister(fg->fg_psy); fg_unregister_interrupts(fg, chip, FG_GEN3_IRQ_MAX); alarm_try_to_cancel(&fg->esr_filter_alarm); @@ -5387,6 +5499,33 @@ static void fg_cleanup(struct fg_gen3_chip *chip) dev_set_drvdata(fg->dev, NULL); } +/* david.liu@bsp, 20171023 Battery & Charging porting */ +static void oem_update_cc_cv_setpoint( + struct fg_dev *fg, int cv_float_point) +{ + /* TODO: write CC_CV_SETPOINT_REG */ +} + +static void oneplus_set_allow_read_iic(struct fg_dev *fg, + bool status) +{ + if (fg->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 *fg, + bool status) +{ + if (fg->use_external_fg && external_fg + && external_fg->set_lcd_off_status) + external_fg->set_lcd_off_status(status); + else + pr_info("set lcd off status fail\n"); +} + static int fg_gen3_probe(struct platform_device *pdev) { struct fg_gen3_chip *chip; diff --git a/drivers/power/supply/qcom/qpnp-qg.c b/drivers/power/supply/qcom/qpnp-qg.c index 902e69f57f68..31cb23c51a9b 100644 --- a/drivers/power/supply/qcom/qpnp-qg.c +++ b/drivers/power/supply/qcom/qpnp-qg.c @@ -3420,41 +3420,6 @@ static int qg_set_wa_flags(struct qpnp_qg *chip) return 0; } -#define SDAM_MAGIC_NUMBER 0x12345678 -static int qg_sanitize_sdam(struct qpnp_qg *chip) -{ - int rc = 0; - u32 data = 0; - - rc = qg_sdam_read(SDAM_MAGIC, &data); - if (rc < 0) { - pr_err("Failed to read SDAM rc=%d\n", rc); - return rc; - } - - if (data == SDAM_MAGIC_NUMBER) { - qg_dbg(chip, QG_DEBUG_PON, "SDAM valid\n"); - } else if (data == 0) { - rc = qg_sdam_write(SDAM_MAGIC, SDAM_MAGIC_NUMBER); - if (!rc) - qg_dbg(chip, QG_DEBUG_PON, "First boot. SDAM initilized\n"); - chip->first_profile_load = true; - } else { - /* SDAM has invalid value */ - rc = qg_sdam_clear(); - if (!rc) { - pr_err("SDAM uninitialized, SDAM reset\n"); - rc = qg_sdam_write(SDAM_MAGIC, SDAM_MAGIC_NUMBER); - } - chip->first_profile_load = true; - } - - if (rc < 0) - pr_err("Failed in SDAM operation, rc=%d\n", rc); - - return rc; -} - #define ADC_CONV_DLY_512MS 0xA #define IBAT_5A_FCC_MA 4800 #define IBAT_10A_FCC_MA 9600 @@ -4787,12 +4752,6 @@ static int qpnp_qg_probe(struct platform_device *pdev) return rc; } - rc = qg_sanitize_sdam(chip); - if (rc < 0) { - pr_err("Failed to sanitize SDAM, rc=%d\n", rc); - return rc; - } - rc = qg_soc_init(chip); if (rc < 0) { pr_err("Failed to initialize SOC scaling init rc=%d\n", rc); diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c index 24e424b5d6b8..c9e86209554c 100644 --- a/drivers/power/supply/qcom/qpnp-smb2.c +++ b/drivers/power/supply/qcom/qpnp-smb2.c @@ -2,6 +2,9 @@ /* Copyright (c) 2016-2017,2019-2020, The Linux Foundation. All rights reserved. */ +/* david.liu@bsp, 20171023 Battery & Charging porting */ +#define pr_fmt(fmt) "SMB2: %s: " fmt, __func__ + #include #include #include @@ -16,11 +19,19 @@ #include #include #include +/* david.liu@bsp, 20171023 Battery & Charging porting */ +#include +#include +#include #include "smb-reg.h" #include "smb-lib.h" #include "storm-watch.h" #include +/*yangfb@bsp, 20180302,enable stm6620 sheepmode */ +#include +#include + #define SMB2_DEFAULT_WPWR_UW 8000000 static struct smb_params v1_params = { @@ -172,7 +183,37 @@ struct smb2 { bool bad_part; }; +/* david.liu@bsp, 20171023 Battery & Charging porting */ +static int smbchg_cutoff_volt_with_charger = 3240; +struct smb_charger *g_chip; +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 static int __weak_chg_icl_ua = 500000; static ssize_t weak_chg_icl_ua_show(struct device *dev, struct device_attribute @@ -258,7 +299,10 @@ static int smb2_parse_dt(struct smb2 *chip) { struct smb_charger *chg = &chip->chg; struct device_node *node = chg->dev->of_node; - int rc, byte_len; +/* david.liu@bsp, 20171023 Battery & Charging porting */ + int byte_len, rc = 0; + /*yangfb@bsp, 20180302,enable stm6620 sheepmode */ + enum of_gpio_flags flags; if (!node) { pr_err("device tree node missing\n"); @@ -268,9 +312,176 @@ static int smb2_parse_dt(struct smb2 *chip) chg->reddragon_ipc_wa = of_property_read_bool(node, "qcom,qcs605-ipc-wa"); - chg->step_chg_enabled = of_property_read_bool(node, - "qcom,step-charging-enable"); - +/* david.liu@bsp, 20171023 Battery & Charging porting */ + /* read ibatmax setting for different temp regions */ + OF_PROP_READ(node, "ibatmax-little-cold-ma", + chg->ibatmax[BATT_TEMP_LITTLE_COLD], rc, 1); + OF_PROP_READ(node, "ibatmax-cool-ma", + chg->ibatmax[BATT_TEMP_COOL], rc, 1); + OF_PROP_READ(node, "ibatmax-little-cool-ma", + chg->ibatmax[BATT_TEMP_LITTLE_COOL], rc, 1); + OF_PROP_READ(node, "ibatmax-little-cool-low_ma", + chg->temp_littel_cool_low_current, rc, 1); + if (rc < 0) + chg->temp_littel_cool_low_current = 450; + pr_info("temp_littel_cool_low_current:%d\n", + chg->temp_littel_cool_low_current); + OF_PROP_READ(node, "ibatmax-pre-normal-ma", + chg->ibatmax[BATT_TEMP_PRE_NORMAL], rc, 1); + OF_PROP_READ(node, "ibatmax-normal-ma", + chg->ibatmax[BATT_TEMP_NORMAL], rc, 1); + OF_PROP_READ(node, "ibatmax-warm-ma", + chg->ibatmax[BATT_TEMP_WARM], rc, 1); + + /* read vbatmax setting for different temp regions */ + OF_PROP_READ(node, "vbatmax-little-cold-mv", + chg->vbatmax[BATT_TEMP_LITTLE_COLD], rc, 1); + OF_PROP_READ(node, "vbatmax-cool-mv", + chg->vbatmax[BATT_TEMP_COOL], rc, 1); + OF_PROP_READ(node, "vbatmax-little-cool-mv", + chg->vbatmax[BATT_TEMP_LITTLE_COOL], rc, 1); + OF_PROP_READ(node, "vbatmax-pre-normal-mv", + chg->vbatmax[BATT_TEMP_PRE_NORMAL], rc, 1); + OF_PROP_READ(node, "vbatmax-normal-mv", + chg->vbatmax[BATT_TEMP_NORMAL], rc, 1); + OF_PROP_READ(node, "vbatmax-warm-mv", + chg->vbatmax[BATT_TEMP_WARM], rc, 1); + OF_PROP_READ(node, "little-cool-vbat-thr-mv", + chg->temp_littel_cool_voltage, rc, 1); + if (rc < 0) + chg->temp_littel_cool_voltage = 4180; + /* read vbatdet setting for different temp regions */ + OF_PROP_READ(node, "vbatdet-little-cold-mv", + chg->vbatdet[BATT_TEMP_LITTLE_COLD], rc, 1); + OF_PROP_READ(node, "vbatdet-cool-mv", + chg->vbatdet[BATT_TEMP_COOL], rc, 1); + OF_PROP_READ(node, "vbatdet-little-cool-mv", + chg->vbatdet[BATT_TEMP_LITTLE_COOL], rc, 1); + OF_PROP_READ(node, "vbatdet-pre-normal-mv", + chg->vbatdet[BATT_TEMP_PRE_NORMAL], rc, 1); + OF_PROP_READ(node, "vbatdet-normal-mv", + chg->vbatdet[BATT_TEMP_NORMAL], rc, 1); + OF_PROP_READ(node, "vbatdet-warm-mv", + chg->vbatdet[BATT_TEMP_WARM], rc, 1); + + /* read temp region settings */ + OF_PROP_READ(node, "cold-bat-decidegc", + chg->BATT_TEMP_T0, rc, 1); + chg->BATT_TEMP_T0 = 0 - chg->BATT_TEMP_T0; + OF_PROP_READ(node, "little-cold-bat-decidegc", + chg->BATT_TEMP_T1, rc, 1); + OF_PROP_READ(node, "cool-bat-decidegc", + chg->BATT_TEMP_T2, rc, 1); + OF_PROP_READ(node, "little-cool-bat-decidegc", + chg->BATT_TEMP_T3, rc, 1); + OF_PROP_READ(node, "pre-normal-bat-decidegc", + chg->BATT_TEMP_T4, rc, 1); + OF_PROP_READ(node, "warm-bat-decidegc", + chg->BATT_TEMP_T5, rc, 1); + OF_PROP_READ(node, "hot-bat-decidegc", + chg->BATT_TEMP_T6, rc, 1); + /*read ffc param*/ + OF_PROP_READ(node, "ffc-pre-normal-decidegc", + chg->FFC_TEMP_T1, rc, 1); + OF_PROP_READ(node, "ffc-normal-decidegc", + chg->FFC_TEMP_T2, rc, 1); + OF_PROP_READ(node, "ffc-warm-decidegc", + chg->FFC_TEMP_T3, rc, 1); + OF_PROP_READ(node, "ffc-normal-fcc-ma", + chg->FFC_NOR_FCC, rc, 1); + OF_PROP_READ(node, "ffc-warm-fcc-ma", + chg->FFC_WARM_FCC, rc, 1); + OF_PROP_READ(node, "ffc-normal-cutoff-ma", + chg->FFC_NORMAL_CUTOFF, rc, 1); + OF_PROP_READ(node, "ffc-warm-cutoff-ma", + chg->FFC_WARM_CUTOFF, rc, 1); + OF_PROP_READ(node, "ffc-full-vbat-mv", + chg->FFC_VBAT_FULL, rc, 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); +/*yangfb@bsp, 20181023 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, rc, 1); + if (rc < 0) + chg->OTG_LOW_BAT = -EINVAL; + OF_PROP_READ(node, "otg-low-bat-icl-thr", + chg->OTG_LOW_BAT_ICL, rc, 1); + if (rc < 0) + chg->OTG_LOW_BAT_ICL = -EINVAL; + OF_PROP_READ(node, "otg-normal-bat-icl-thr", + chg->OTG_NORMAL_BAT_ICL, rc, 1); + if (rc < 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); + pr_info("q1:%d,q2:%d,q3:%d,NORMAL_CUTOFF:%d,warm:%d,FULL=%d\n", + chg->FFC_TEMP_T1, + chg->FFC_TEMP_T2, + chg->FFC_TEMP_T3, + chg->FFC_NORMAL_CUTOFF, + chg->FFC_WARM_CUTOFF, + chg->FFC_VBAT_FULL); + chg->plug_irq = of_get_named_gpio_flags(node, + "op,usb-check", 0, &flags); + chg->vbus_ctrl = of_get_named_gpio_flags(node, + "op,vbus-ctrl-gpio", 0, &flags); + /* read other settings */ + OF_PROP_READ(node, "qcom,cutoff-voltage-with-charger", + smbchg_cutoff_volt_with_charger, rc, 1); + chg->chg_enabled = !(of_property_read_bool(node, + "qcom,charging-disabled")); + + chg->pd_disabled = of_property_read_bool(node, + "disable-pd"); + 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); + + 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); + /* disable step_chg */ + chg->step_chg_enabled = false; chg->sw_jeita_enabled = of_property_read_bool(node, "qcom,sw-jeita-enable"); @@ -413,6 +624,10 @@ static enum power_supply_property smb2_usb_props[] = { POWER_SUPPLY_PROP_TYPEC_MODE, POWER_SUPPLY_PROP_TYPEC_POWER_ROLE, POWER_SUPPLY_PROP_TYPEC_CC_ORIENTATION, +/* david.liu@bsp, 20171023 Battery & Charging porting */ + POWER_SUPPLY_PROP_OTG_SWITCH, + POWER_SUPPLY_PROP_HW_DETECT, + POWER_SUPPLY_PROP_OEM_TYPEC_CC_ORIENTATION, POWER_SUPPLY_PROP_TYPEC_SRC_RP, POWER_SUPPLY_PROP_PD_ALLOWED, POWER_SUPPLY_PROP_PD_ACTIVE, @@ -492,6 +707,13 @@ static int smb2_usb_get_prop(struct power_supply *psy, else val->intval = chg->typec_mode; break; +/* david.liu@bsp, 20170414 Add otg switch */ + case POWER_SUPPLY_PROP_OTG_SWITCH: + val->intval = chg->otg_switch; + break; + case POWER_SUPPLY_PROP_HW_DETECT: + val->intval = chg->hw_detect; + break; case POWER_SUPPLY_PROP_TYPEC_POWER_ROLE: if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) val->intval = POWER_SUPPLY_TYPEC_PR_NONE; @@ -499,6 +721,8 @@ static int smb2_usb_get_prop(struct power_supply *psy, rc = smblib_get_prop_typec_power_role(chg, val); break; case POWER_SUPPLY_PROP_TYPEC_CC_ORIENTATION: +/* david.liu@bsp, 20171023 Battery & Charging porting */ + case POWER_SUPPLY_PROP_OEM_TYPEC_CC_ORIENTATION: if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) val->intval = 0; else @@ -578,7 +802,8 @@ static int smb2_usb_set_prop(struct power_supply *psy, int rc = 0; mutex_lock(&chg->lock); - if (!chg->typec_present) { +/* david.liu@bsp, 20170417 Fix otg switch */ + if (!chg->typec_present && psp != POWER_SUPPLY_PROP_OTG_SWITCH) { switch (psp) { case POWER_SUPPLY_PROP_MOISTURE_DETECTED: vote(chg->disable_power_role_switch, MOISTURE_VOTER, @@ -596,6 +821,11 @@ static int smb2_usb_set_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_PD_CURRENT_MAX: rc = smblib_set_prop_pd_current_max(chg, val); break; +/* david.liu@bsp, 20170414 Add otg switch */ + 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; @@ -645,6 +875,8 @@ static int smb2_usb_prop_is_writeable(struct power_supply *psy, enum power_supply_property psp) { switch (psp) { +/* david.liu@bsp, 20170414 Add otg switch */ + case POWER_SUPPLY_PROP_OTG_SWITCH: case POWER_SUPPLY_PROP_CTM_CURRENT_MAX: return 1; default: @@ -690,6 +922,7 @@ static enum power_supply_property smb2_usb_port_props[] = { POWER_SUPPLY_PROP_CURRENT_MAX, }; + static int smb2_usb_port_get_prop(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) @@ -853,10 +1086,12 @@ static int smb2_usb_main_set_prop(struct power_supply *psy, switch (psp) { case POWER_SUPPLY_PROP_VOLTAGE_MAX: - rc = smblib_set_charge_param(chg, &chg->param.fv, val->intval); + rc = smblib_set_charge_param(chg, + &chg->param.fv, val->intval); break; case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: - rc = smblib_set_charge_param(chg, &chg->param.fcc, val->intval); + rc = smblib_set_charge_param(chg, + &chg->param.fcc, val->intval); break; case POWER_SUPPLY_PROP_CURRENT_MAX: rc = smblib_set_icl_current(chg, val->intval); @@ -978,6 +1213,8 @@ static int smb2_dc_set_prop(struct power_supply *psy, (bool)val->intval, 0); break; case POWER_SUPPLY_PROP_CURRENT_MAX: +/* Yangfb@bsp support ec4016 wipower */ + pr_info("dc set icl:%d\n", val->intval); rc = smblib_set_prop_dc_current_max(chg, val); break; default: @@ -1043,6 +1280,17 @@ static enum power_supply_property smb2_batt_props[] = { POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_CHARGE_TYPE, POWER_SUPPLY_PROP_CAPACITY, +/* david.liu@bsp, 20171023 Battery & Charging porting */ + 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_CONNECT_DISABLE, + POWER_SUPPLY_PROP_CONNECTER_TEMP, POWER_SUPPLY_PROP_CHARGER_TEMP, POWER_SUPPLY_PROP_CHARGER_TEMP_MAX, POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED, @@ -1083,7 +1331,8 @@ static int smb2_batt_get_prop(struct power_supply *psy, switch (psp) { case POWER_SUPPLY_PROP_STATUS: - rc = smblib_get_prop_batt_status(chg, val); +/* david.liu@bsp, 20171023 Battery & Charging porting */ + val->intval = get_prop_batt_status(chg); break; case POWER_SUPPLY_PROP_HEALTH: rc = smblib_get_prop_batt_health(chg, val); @@ -1100,6 +1349,37 @@ static int smb2_batt_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_CAPACITY: rc = smblib_get_prop_batt_capacity(chg, val); break; +/* david.liu@bsp, 20171023 Battery & Charging porting */ + case POWER_SUPPLY_PROP_CHARGE_NOW: + rc = smblib_get_prop_usb_voltage_now(chg, val); + break; + case POWER_SUPPLY_PROP_CHG_PROTECT_STATUS: + val->intval = get_prop_chg_protect_status(chg); + break; + case POWER_SUPPLY_PROP_FASTCHG_STATUS: + val->intval = get_prop_fastchg_status(chg); + break; + case POWER_SUPPLY_CUTOFF_VOLT_WITH_CHARGER: + val->intval = smbchg_cutoff_volt_with_charger; + break; + case POWER_SUPPLY_PROP_FASTCHG_STARTING: + val->intval = op_get_fastchg_ing(chg); + break; + case POWER_SUPPLY_PROP_CHARGING_ENABLED: + val->intval = chg->chg_enabled; + break; + case POWER_SUPPLY_PROP_INPUT_CURRENT_MAX: + rc = smblib_get_prop_input_current_limited(chg, val); + break; + case POWER_SUPPLY_PROP_IS_AGING_TEST: + val->intval = chg->is_aging_test; + break; + case POWER_SUPPLY_PROP_CONNECT_DISABLE: + val->intval = chg->disconnect_vbus; + break; + case POWER_SUPPLY_PROP_CONNECTER_TEMP: + val->intval = chg->connecter_temp; + break; case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT: rc = smblib_get_prop_system_temp_level(chg, val); break; @@ -1188,8 +1468,6 @@ static int smb2_batt_get_prop(struct power_supply *psy, break; case POWER_SUPPLY_PROP_CURRENT_NOW: rc = smblib_get_prop_from_bms(chg, psp, val); - if (!rc) - val->intval *= (-1); break; case POWER_SUPPLY_PROP_FCC_STEPPER_ENABLE: val->intval = chg->fcc_stepper_enable; @@ -1224,6 +1502,53 @@ static int smb2_batt_set_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT: rc = smblib_set_prop_system_temp_level(chg, val); break; +/* david.liu@bsp, 20171023 Battery & Charging porting */ + case POWER_SUPPLY_PROP_CHECK_USB_UNPLUG: + if (chg->vbus_present && !chg->dash_present) + update_dash_unplug_status(); + break; + case POWER_SUPPLY_PROP_SWITCH_DASH: + rc = check_allow_switch_dash(chg, val); + break; + case POWER_SUPPLY_PROP_INPUT_CURRENT_MAX: + pr_info("set iusb %d uA\n", val->intval); + if (__debug_mask == PR_OP_DEBUG + || val->intval == 900000) + op_usb_icl_set(chg, 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; + break; + case POWER_SUPPLY_PROP_IS_AGING_TEST: + chg->is_aging_test = (bool)val->intval; + __debug_mask = PR_OP_DEBUG; + break; + case POWER_SUPPLY_PROP_CONNECT_DISABLE: + op_disconnect_vbus(chg, (bool)val->intval); + break; case POWER_SUPPLY_PROP_CAPACITY: rc = smblib_set_prop_batt_capacity(chg, val); break; @@ -1310,6 +1635,14 @@ static int smb2_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: +/* david.liu@bsp, 20171023 Battery & Charging porting */ + case POWER_SUPPLY_PROP_CHARGE_NOW: + case POWER_SUPPLY_PROP_TEMP: + case POWER_SUPPLY_PROP_CHG_PROTECT_STATUS: + case POWER_SUPPLY_PROP_CHARGING_ENABLED: + case POWER_SUPPLY_PROP_INPUT_CURRENT_MAX: + case POWER_SUPPLY_PROP_IS_AGING_TEST: + case POWER_SUPPLY_PROP_CONNECT_DISABLE: case POWER_SUPPLY_PROP_PARALLEL_DISABLE: case POWER_SUPPLY_PROP_DP_DM: case POWER_SUPPLY_PROP_RERUN_AICL: @@ -1514,6 +1847,33 @@ static int smb2_configure_typec(struct smb_charger *chg) "Couldn't configure Type-C interrupts rc=%d\n", rc); return rc; } +/* david.liu@bsp, 20170414 Add otg switch */ + if (chg->otg_switch) { + /* restore it back to 0xA5 */ + rc = smblib_write(chg, TM_IO_DTEST4_SEL, 0xA5); + if (rc < 0) + dev_err(chg->dev, + "Couldn't restore it back rc=%d\n", rc); + rc = smblib_masked_write(chg, + TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, + TYPEC_POWER_ROLE_CMD_MASK, 0); + } else { + /* disable PBS workaround when forcing sink mode */ + rc = smblib_write(chg, TM_IO_DTEST4_SEL, 0x0); + if (rc < 0) + dev_err(chg->dev, + "Couldn't disable PBS workaround rc=%d\n", rc); + + rc = smblib_masked_write(chg, + TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, + TYPEC_POWER_ROLE_CMD_MASK, + UFP_EN_CMD_BIT); + } + if (rc < 0) { + dev_err(chg->dev, + "Couldn't configure power role for DRP rc=%d\n", rc); + return rc; + } /* * disable Type-C factory mode and stay in Attached.SRC state when VCONN @@ -1643,7 +2003,10 @@ static int smb2_init_hw(struct smb2 *chip) &chg->default_icl_ua); if (chip->dt.usb_icl_ua < 0) chip->dt.usb_icl_ua = chg->default_icl_ua; - +/* david.liu@bsp, 20171023 Battery & Charging porting */ + pr_info("vbat_max=%d, ibat_max=%d, iusb_max=%d\n", + chg->batt_profile_fv_uv, + chg->batt_profile_fcc_ua, chip->dt.usb_icl_ua); if (chip->dt.dc_icl_ua < 0) smblib_get_charge_param(chg, &chg->param.dc_icl, &chip->dt.dc_icl_ua); @@ -1665,7 +2028,19 @@ static int smb2_init_hw(struct smb2 *chip) pr_err("Couldn't set otg soft start rc=%d\n", rc); return rc; } - +/* Yangfb@bsp support ec4016 wipower */ + /* set a AICL THR for DCIN */ + rc = smblib_write(chg, DCIN_AICL_REF_SEL_CFG_REG, 0x3); + if (rc < 0) { + pr_err("Couldn't write DCIN_AICL_REF_SEL_CFG_REG\n"); + return rc; + } + /* disable qcom wipower*/ + rc = smblib_write(chg, WI_PWR_OPTIONS_REG, 0); + if (rc < 0) { + pr_err("Couldn't disable qcom wipower\n"); + return rc; + } /* set OTG current limit */ rc = smblib_set_charge_param(chg, &chg->param.otg_cl, (chg->wa_flags & OTG_WA) ? @@ -1683,7 +2058,9 @@ static int smb2_init_hw(struct smb2 *chip) return rc; } - smblib_rerun_apsd_if_required(chg); + /* Disable APSD rerun for CDP case */ + if (!(stat & (CDP_CHARGER_BIT | SDP_CHARGER_BIT))) + smblib_rerun_apsd_if_required(chg); /* clear the ICL override if it is set */ if (smblib_icl_override(chg, false) < 0) { @@ -1692,17 +2069,21 @@ static int smb2_init_hw(struct smb2 *chip) } /* votes must be cast before configuring software control */ - /* vote 0mA on usb_icl for non battery platforms */ +/* david.liu@bsp, 20171023 Battery & Charging porting */ vote(chg->usb_icl_votable, - DEFAULT_VOTER, chip->dt.no_battery, 0); + DEFAULT_VOTER, !chg->chg_enabled, 0); vote(chg->dc_suspend_votable, - DEFAULT_VOTER, chip->dt.no_battery, 0); - vote(chg->fcc_votable, - BATT_PROFILE_VOTER, true, chg->batt_profile_fcc_ua); - vote(chg->fv_votable, - BATT_PROFILE_VOTER, true, chg->batt_profile_fv_uv); + 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); vote(chg->dc_icl_votable, DEFAULT_VOTER, true, chip->dt.dc_icl_ua); + vote(chg->hvdcp_disable_votable_indirect, PD_INACTIVE_VOTER, + true, 0); + vote(chg->hvdcp_disable_votable_indirect, VBUS_CC_SHORT_VOTER, + true, 0); vote(chg->hvdcp_disable_votable_indirect, DEFAULT_VOTER, chip->dt.hvdcp_disable, 0); vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, @@ -1711,6 +2092,25 @@ static int smb2_init_hw(struct smb2 *chip) true, 0); vote(chg->pd_disallowed_votable_indirect, PD_NOT_SUPPORTED_VOTER, chip->dt.no_pd, 0); +/* david.liu@bsp, 20171023 Battery & Charging porting */ + /* disable HVDCP */ + rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG, + HVDCP_EN_BIT, 0); + if (rc < 0) + dev_err(chg->dev, "Couldn't disable HVDCP rc=%d\n", rc); + + rc = smblib_masked_write(chg, USBIN_SOURCE_CHANGE_INTRPT_ENB_REG, + SLOW_IRQ_EN_CFG_BIT, 0); + if (rc < 0) + dev_err(chg->dev, + "Couldn't clean slow plugin irq=%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); + /* * AICL configuration: * start from min and AICL ADC disable @@ -1786,6 +2186,15 @@ static int smb2_init_hw(struct smb2 *chip) "Couldn't configure VBUS for SW control rc=%d\n", rc); return rc; } +/* xianglin modify otg current load to 1.5A */ + rc = smblib_masked_write( + chg, OTG_CURRENT_LIMIT_CFG_REG, + OTG_CURRENT_LIMIT_MASK, 0x5); + if (rc < 0) { + dev_err(chg->dev, + "Couldn't configure VBUS for SW control rc=%d\n", rc); + return rc; + } val = (ilog2(chip->dt.wd_bark_time / 16) << BARK_WDOG_TIMEOUT_SHIFT) & BARK_WDOG_TIMEOUT_MASK; @@ -1985,18 +2394,18 @@ static int smb2_post_init(struct smb2 *chip) } } } else { - /* configure power role for dual-role */ + /* yangfb@bsp, 20180124 ,for EID-1772 */ + /* configure power role for UDP-role */ rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, - TYPEC_POWER_ROLE_CMD_MASK, 0); + TYPEC_POWER_ROLE_CMD_MASK, UFP_EN_CMD_BIT); if (rc < 0) { dev_err(chg->dev, - "Couldn't configure power role for DRP rc=%d\n", + "Couldn't configure power role for UDP rc=%d\n", rc); return rc; } } - rerun_election(chg->usb_irq_enable_votable); return 0; @@ -2062,6 +2471,8 @@ static int smb2_chg_config_init(struct smb2 *chip) return -EINVAL; } +/* david.liu@bsp, 20170317 Improve coldboot time */ + pr_info("PMI8998 Revision=0x%x\n", pmic_rev_id->rev4); return 0; } @@ -2238,9 +2649,10 @@ static struct smb_irq_info smb2_irqs[] = { .name = "aicl-fail", .handler = smblib_handle_debug, }, +/* david.liu@bsp, 20171023 Battery & Charging porting */ [AICL_DONE_IRQ] = { .name = "aicl-done", - .handler = smblib_handle_debug, + .handler = smblib_handle_aicl_done, }, [HIGH_DUTY_CYCLE_IRQ] = { .name = "high-duty-cycle", @@ -2441,6 +2853,78 @@ static void smb2_create_debugfs(struct smb2 *chip) #endif +/* david.liu@bsp, 20171023 Battery & Charging porting */ +#ifdef CONFIG_PROC_FS +static ssize_t write_ship_mode(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + + if (count) { + g_chip->ship_mode = true; + pr_err(" * * * XCB * * * write_ship_mode\n"); + } + return count; +} + +static const struct file_operations proc_ship_mode_operations = { + .write = write_ship_mode, + .llseek = noop_llseek, +}; +#endif +static irqreturn_t op_usb_plugin_irq_handler(int irq, void *dev_id) +{ + schedule_work(&g_chip->otg_switch_work); + return IRQ_HANDLED; +} + +static void request_plug_irq(struct smb_charger *chip) +{ + int ret; + + if (!gpio_is_valid(chip->plug_irq)) + return; + ret = gpio_request(chip->plug_irq, "op_usb_plug"); + if (ret) { + pr_err("request failed,gpio:%d ret=%d\n", chip->plug_irq, ret); + return; + } + gpio_direction_input(chip->plug_irq); + ret = request_irq(gpio_to_irq(chip->plug_irq), + op_usb_plugin_irq_handler, + IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, + "op_usb_plug", chip); + if (ret < 0) { + pr_err("request usb_plug irq failed.\n"); + return; + } + enable_irq_wake(gpio_to_irq(chip->plug_irq)); + pr_info("request usb_plug irq success\n"); + /*connect with usb cable when reboot, give a vote 1*/ + if (!gpio_get_value(chip->plug_irq)) { + pr_info("%s:reboot time hw detect gpio low, vote 1\n", + __func__); + vote(chip->otg_toggle_votable, HW_DETECT_VOTER, 1, 0); + chip->hw_detect = 1; + 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; +} + +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 smb2_probe(struct platform_device *pdev) { struct smb2 *chip; @@ -2448,12 +2932,15 @@ static int smb2_probe(struct platform_device *pdev) int rc = 0; union power_supply_propval val; int usb_present, batt_present, batt_health, batt_charge_type; + struct msm_bus_scale_pdata *pdata; chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); if (!chip) return -ENOMEM; chg = &chip->chg; +/* david.liu@bsp, 20171023 Battery & Charging porting */ + g_chip = chg; chg->dev = &pdev->dev; chg->param = v1_params; chg->debug_mask = &__debug_mask; @@ -2493,6 +2980,14 @@ static int smb2_probe(struct platform_device *pdev) /* set driver data before resources request it */ platform_set_drvdata(pdev, chip); +/* david.liu@bsp, 20171228 Fix abnormal animation */ + op_charge_info_init(chg); + pdata = msm_bus_cl_get_pdata(pdev); + if (!pdata) + pr_err("Fail to get bus data\n"); + else + chg->bus_client = msm_bus_scale_register_client(pdata); + rc = smb2_init_vbus_regulator(chip); if (rc < 0) { pr_err("Couldn't initialize vbus regulator rc=%d\n", @@ -2613,9 +3108,23 @@ static int smb2_probe(struct platform_device *pdev) goto cleanup; } batt_charge_type = val.intval; +/* david.liu@bsp, 20171023 Battery & Charging porting */ +#ifdef CONFIG_PROC_FS + if (!proc_create("ship_mode", 0644, NULL, + &proc_ship_mode_operations)) + pr_err("Failed to register proc interface\n"); +#endif - device_init_wakeup(chg->dev, true); + if (usb_present) { + chg->boot_usb_present = true; + } + if (!usb_present && chg->vbus_present) + op_handle_usb_plugin(chg); + device_init_wakeup(chg->dev, true); + chg->probe_done = true; + request_plug_irq(chg); + requset_vbus_ctrl_gpio(chg); pr_info("QPNP SMB2 probed successfully usb:present=%d type=%d batt:present = %d health = %d charge = %d\n", usb_present, chg->real_charger_type, batt_present, batt_health, batt_charge_type); @@ -2649,11 +3158,15 @@ static int smb2_remove(struct platform_device *pdev) struct smb2 *chip = platform_get_drvdata(pdev); struct smb_charger *chg = &chip->chg; - power_supply_unregister(chg->batt_psy); - power_supply_unregister(chg->usb_psy); - power_supply_unregister(chg->usb_port_psy); - regulator_unregister(chg->vconn_vreg->rdev); - regulator_unregister(chg->vbus_vreg->rdev); +/* david.liu@bsp, 20170330 Fix system crash */ + if (chg->usb_psy) + power_supply_unregister(chg->batt_psy); + if (chg->batt_psy) + power_supply_unregister(chg->batt_psy); + if (chg->vconn_vreg && chg->vconn_vreg->rdev) + regulator_unregister(chg->vconn_vreg->rdev); + if (chg->vbus_vreg && chg->vbus_vreg->rdev) + regulator_unregister(chg->vbus_vreg->rdev); sysfs_remove_groups(&chg->dev->kobj, smb2_groups); debugfs_remove_recursive(chip->dfs_root); platform_set_drvdata(pdev, NULL); @@ -2664,6 +3177,19 @@ static void smb2_shutdown(struct platform_device *pdev) { struct smb2 *chip = platform_get_drvdata(pdev); struct smb_charger *chg = &chip->chg; +/* david.liu@bsp, 20171023 Battery & Charging porting */ +#ifdef CONFIG_PROC_FS + pr_info("smbchg_shutdown\n"); + if (chg->ship_mode) { + pr_info("smbchg_shutdown enter ship_mode\n"); + smblib_masked_write(chg, SHIP_MODE_REG, + SHIP_MODE_EN_BIT, SHIP_MODE_EN_BIT); + msleep(1000); + pr_err("after 1s\n"); + while (1) + ; + } +#endif /* disable all interrupts */ smb2_disable_interrupts(chg); diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c index 101f21fcbeb3..537d0881800a 100644 --- a/drivers/power/supply/qcom/smb-lib.c +++ b/drivers/power/supply/qcom/smb-lib.c @@ -2,6 +2,11 @@ /* Copyright (c) 2016-2020 The Linux Foundation. All rights reserved. */ +/* david.liu@bsp, 20171023 Battery & Charging porting */ +#define pr_fmt(fmt) "SMBLIB: %s: " fmt, __func__ + +#define CONFIG_MSM_RDM_NOTIFY +#undef CONFIG_FB #include #include #include @@ -17,6 +22,71 @@ #include "step-chg-jeita.h" #include "storm-watch.h" +/* david.liu@bsp, 20171023 Battery & Charging porting */ +#include +#include +#include +#include +#include +#if defined(CONFIG_FB) +#include +#include +#elif defined(CONFIG_MSM_RDM_NOTIFY) +#include +#include +#endif /*CONFIG_FB*/ +#include +#include +#include +#include "op_charge.h" + + +#define SOC_INVALID 0x7E +#define SOC_DATA_REG_0 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 + +struct smb_charger *g_chg; +struct qpnp_pon *pm_pon; +/*2018/06/14 @bsp add for support notify audio adapter switch*/ +static BLOCKING_NOTIFIER_HEAD(typec_cc_chain); +static int cc_notifier_call_chain(unsigned long val); +/* infi@bsp, 2018/08/08 add for support audio_adaptor trigger when reboot */ +bool audio_adapter_flag; +EXPORT_SYMBOL(audio_adapter_flag); + +static struct external_battery_gauge *fast_charger; +static int op_charging_en(struct smb_charger *chg, bool en); +static bool set_prop_fast_switch_to_normal_false(struct smb_charger *chg); + +static void op_battery_temp_region_set(struct smb_charger *chg, + enum temp_region_type batt_temp_region); +static void set_usb_switch(struct smb_charger *chg, bool enable); +static void op_handle_usb_removal(struct smb_charger *chg); +static bool get_prop_fast_switch_to_normal(struct smb_charger *chg); +static int get_prop_batt_temp(struct smb_charger *chg); +static int get_prop_batt_capacity(struct smb_charger *chg); +static int get_prop_batt_current_now(struct smb_charger *chg); +static int get_prop_batt_voltage_now(struct smb_charger *chg); +static int set_property_on_fg(struct smb_charger *chg, + enum power_supply_property prop, int val); +static int set_dash_charger_present(int status); +static enum temp_region_type + op_battery_temp_region_get(struct smb_charger *chg); +static int get_prop_fg_capacity(struct smb_charger *chg); +static int get_prop_fg_current_now(struct smb_charger *chg); +static int get_prop_fg_voltage_now(struct smb_charger *chg); +static void op_check_charger_collapse(struct smb_charger *chg); +static int op_set_collapse_fet(struct smb_charger *chg, bool on); +static int op_check_battery_temp(struct smb_charger *chg); +static void op_clean_enhache_status(void); + #define smblib_err(chg, fmt, ...) \ pr_err("%s: %s: " fmt, chg->name, \ __func__, ##__VA_ARGS__) \ @@ -241,7 +311,8 @@ static const struct apsd_result const smblib_apsd_results[] = { [FLOAT] = { .name = "FLOAT", .bit = FLOAT_CHARGER_BIT, - .pst = POWER_SUPPLY_TYPE_USB_FLOAT +/* yangfb@bsp, 20160926 Add dash charging */ + .pst = POWER_SUPPLY_TYPE_USB_DCP }, [HVDCP2] = { .name = "HVDCP2", @@ -267,10 +338,11 @@ static const struct apsd_result *smblib_get_apsd_result(struct smb_charger *chg) return result; } smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", apsd_stat); - - if (!(apsd_stat & APSD_DTC_STATUS_DONE_BIT)) +/* david.liu@bsp, 20171023 Battery & Charging porting */ + if (!(apsd_stat & APSD_DTC_STATUS_DONE_BIT)) { + pr_info("APSD_DTC_STATUS_DONE_BIT is 0\n"); return result; - + } rc = smblib_read(chg, APSD_RESULT_STATUS_REG, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read APSD_RESULT_STATUS rc=%d\n", @@ -386,6 +458,8 @@ int smblib_set_usb_suspend(struct smb_charger *chg, bool suspend) { int rc = 0; int irq = chg->irq_info[USBIN_ICL_CHANGE_IRQ].irq; +/* david.liu@bsp, 20171023 Battery & Charging porting */ + pr_info("suspend=%d\n", suspend); if (suspend && irq) { if (chg->usb_icl_change_irq_enabled) { @@ -413,7 +487,8 @@ int smblib_set_usb_suspend(struct smb_charger *chg, bool suspend) int smblib_set_dc_suspend(struct smb_charger *chg, bool suspend) { int rc = 0; - +/* Yangfb@bsp support ec4016 wipower */ + pr_info("%d\n", suspend); rc = smblib_masked_write(chg, DCIN_CMD_IL_REG, DCIN_SUSPEND_BIT, suspend ? DCIN_SUSPEND_BIT : 0); if (rc < 0) @@ -615,6 +690,14 @@ static const struct apsd_result *smblib_update_usb_type(struct smb_charger *chg) chg->real_charger_type = apsd_result->pst; } +/* Yangfb@bsp add to fix fastcharge test not pass */ + if (chg->dash_on) { + chg->real_charger_type = POWER_SUPPLY_TYPE_DASH; + chg->usb_psy_desc.type = POWER_SUPPLY_TYPE_DASH; + } else { + chg->usb_psy_desc.type = apsd_result->pst; + chg->real_charger_type = apsd_result->pst; + } smblib_dbg(chg, PR_MISC, "APSD=%s PD=%d\n", apsd_result->name, chg->pd_active); return apsd_result; @@ -917,6 +1000,62 @@ static int set_sdp_current(struct smb_charger *chg, int icl_ua) return rc; } +/* david.liu@bsp, 20171023 Battery & Charging porting */ +void op_bus_vote(int disable) +{ + int ret; + + if (!g_chg) + return; + + ret = msm_bus_scale_client_update_request(g_chg->bus_client, disable); + + if (ret) { + pr_err("%s: failed: bus_client_handle=0x%x, vote=%d, err=%d\n", + __func__, g_chg->bus_client, disable, ret); + } + pr_info("enable =%d\n", disable); +} + +int op_usb_icl_set(struct smb_charger *chg, int icl_ua) +{ + int rc = 0; + bool override; + + pr_info("icl_ua=%d\n", icl_ua); + + disable_irq_nosync(chg->irq_info[USBIN_ICL_CHANGE_IRQ].irq); + rc = smblib_set_charge_param(chg, &chg->param.usb_icl, + icl_ua); + if (rc < 0) { + smblib_err(chg, "Couldn't set HC ICL rc=%d\n", rc); + goto enable_icl_changed_interrupt; + } + + /* determine if override needs to be enforced */ + override = true; + /* enforce override */ + rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG, + USBIN_MODE_CHG_BIT, override ? USBIN_MODE_CHG_BIT : 0); + + rc = smblib_icl_override(chg, override); + 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; +} + static int get_sdp_current(struct smb_charger *chg, int *icl_ua) { int rc; @@ -943,7 +1082,7 @@ int smblib_set_icl_current(struct smb_charger *chg, int icl_ua) { int rc = 0; bool override; - + pr_info("icl_ua=%d\n", icl_ua); /* suspend and return if 25mA or less is requested */ if (icl_ua <= USBIN_25MA) return smblib_set_usb_suspend(chg, true); @@ -954,13 +1093,19 @@ int smblib_set_icl_current(struct smb_charger *chg, int icl_ua) /* configure current */ if (chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT && (chg->real_charger_type == POWER_SUPPLY_TYPE_USB)) { +/* david.liu@bsp, 20171023 Battery & Charging porting */ + if (chg->non_std_chg_present) { + rc = smblib_set_charge_param(chg, &chg->param.usb_icl, + icl_ua); + override = false; + } 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 enable_icl_changed_interrupt; } } else { - set_sdp_current(chg, 100000); 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); @@ -1152,6 +1297,9 @@ static int __smblib_set_prop_typec_power_role(struct smb_charger *chg, smblib_err(chg, "power role %d not supported\n", val->intval); return -EINVAL; } + /* david.liu@bsp, 20170414 Add otg switch */ + if (!chg->otg_switch) + power_role = UFP_EN_CMD_BIT; if (power_role != TYPEC_DISABLE_CMD_BIT) { if (chg->ufp_only_mode) @@ -1241,13 +1389,34 @@ static int smblib_dc_suspend_vote_callback(struct votable *votable, void *data, return smblib_set_dc_suspend(chg, (bool)suspend); } +/*infi@bsp, 2018/07/10 Add otg toggle vote optimize otg_switch set flow*/ +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_dc_icl_vote_callback(struct votable *votable, void *data, int icl_ua, const char *client) { struct smb_charger *chg = data; int rc = 0; bool suspend; - +/* Yangfb@bsp support ec4016 wipower */ + pr_info("dc icl set %d\n", icl_ua); if (icl_ua < 0) { smblib_dbg(chg, PR_MISC, "No Voter hence suspending\n"); icl_ua = 0; @@ -1291,6 +1460,8 @@ static int smblib_awake_vote_callback(struct votable *votable, void *data, { struct smb_charger *chg = data; +/* david.liu@bsp, 20171023 Battery & Charging porting */ + pr_info("set awake=%d\n", awake); if (awake) pm_stay_awake(chg->dev); else @@ -1305,6 +1476,8 @@ static int smblib_chg_disable_vote_callback(struct votable *votable, void *data, struct smb_charger *chg = data; int rc; +/* david.liu@bsp, 20171023 Battery & Charging porting */ + pr_err("set chg_disable=%d\n", chg_disable); rc = smblib_masked_write(chg, CHARGING_ENABLE_CMD_REG, CHARGING_ENABLE_CMD_BIT, chg_disable ? 0 : CHARGING_ENABLE_CMD_BIT); @@ -1968,9 +2141,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); @@ -1983,21 +2155,8 @@ int smblib_get_prop_batt_health(struct smb_charger *chg, stat); if (stat & CHARGER_ERROR_STATUS_BAT_OV_BIT) { - rc = smblib_get_prop_from_bms(chg, - POWER_SUPPLY_PROP_VOLTAGE_NOW, &pval); - if (!rc) { - /* - * If Vbatt is within 40mV above Vfloat, then don't - * treat it as overvoltage. - */ - effective_fv_uv = get_effective_result(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; - } - } +/* david.liu@bsp, 20171023 Battery & Charging porting */ + val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE; } if (stat & BAT_TEMP_STATUS_TOO_COLD_BIT) @@ -2010,8 +2169,6 @@ int smblib_get_prop_batt_health(struct smb_charger *chg, val->intval = POWER_SUPPLY_HEALTH_WARM; else val->intval = POWER_SUPPLY_HEALTH_GOOD; - -done: return rc; } @@ -2049,6 +2206,51 @@ int smblib_get_prop_input_current_limited(struct smb_charger *chg, return 0; } +int smblib_get_prop_batt_voltage_now(struct smb_charger *chg, + union power_supply_propval *val) +{ + int rc; + + if (!chg->bms_psy) + return -EINVAL; + + rc = power_supply_get_property(chg->bms_psy, + POWER_SUPPLY_PROP_VOLTAGE_NOW, val); + return rc; +} + +int smblib_get_prop_batt_current_now(struct smb_charger *chg, + union power_supply_propval *val) +{ + int rc; + + if (!chg->bms_psy) + return -EINVAL; + + rc = power_supply_get_property(chg->bms_psy, + POWER_SUPPLY_PROP_CURRENT_NOW, val); + 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; + +/* david.liu@bsp, 20171122 Fix fake battery temperature */ + 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) { @@ -2126,6 +2328,94 @@ int smblib_set_prop_input_suspend(struct smb_charger *chg, return rc; } +/* david.liu@bsp, 20171023 Battery & Charging porting */ +#define POWER_ROLE_BIT (DFP_EN_CMD_BIT | UFP_EN_CMD_BIT) +int op_set_prop_otg_switch(struct smb_charger *chg, + bool enable) +{ + int rc = 0; + u8 power_role; + u8 ctrl = 0; + bool pre_otg_switch; + int i = 0; + + pre_otg_switch = chg->otg_switch; + chg->otg_switch = enable; + + if (chg->otg_switch == pre_otg_switch) + return rc; + + pr_info("set otg_switch=%d\n", chg->otg_switch); + if (chg->otg_switch) + power_role = 0; + else + power_role = UFP_EN_CMD_BIT; + + for (i = 0; i < 10; i++) { + rc = smblib_masked_write(chg, + TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, + TYPEC_POWER_ROLE_CMD_MASK, power_role); + if (rc < 0) { + smblib_err(chg, "Couldn't write 0x%02x to 0x1368 rc=%d\n", + power_role, rc); + return rc; + } + usleep_range(30000, 31000); + ctrl = 0; + rc = smblib_read(chg, + TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, &ctrl); + if (rc < 0) { + smblib_err(chg, "Couldn't read err=%d\n", rc); + return rc; + } + if ((power_role == 0) && ((ctrl & POWER_ROLE_BIT) == 0)) + break; + if ((power_role == UFP_EN_CMD_BIT) && (ctrl & UFP_EN_CMD_BIT)) + break; + } + pr_info("retry time = %d,ctrl = %d\n", i, ctrl); + if (i == 10) + pr_err("retry time over\n"); + return rc; +} + +int smblib_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) { @@ -2217,6 +2507,10 @@ int smblib_rerun_aicl(struct smb_charger *chg) return rc; smblib_dbg(chg, PR_MISC, "re-running AICL\n"); + /*yangfb@bsp enable aicl_rerun before rerurn aicl*/ + rc = smblib_masked_write(chg, USBIN_AICL_OPTIONS_CFG_REG, + USBIN_AICL_RERUN_EN_BIT, + USBIN_AICL_RERUN_EN_BIT); rc = smblib_get_charge_param(chg, &chg->param.icl_stat, &settled_icl_ua); if (rc < 0) { @@ -2434,7 +2728,8 @@ int smblib_set_prop_dc_current_max(struct smb_charger *chg, const union power_supply_propval *val) { int rc; - +/* Yangfb@bsp support ec4016 wipower */ + pr_info("%s,%d\n", __func__, val->intval); rc = vote(chg->dc_icl_votable, USER_VOTER, true, val->intval); return rc; } @@ -2470,6 +2765,12 @@ int smblib_get_prop_usb_online(struct smb_charger *chg, return rc; } +/* david.liu@bsp, 20161122 Fix power off charging loop */ + if (chg->vbus_present) { + val->intval = true; + return rc; + } + rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n", @@ -2529,14 +2830,18 @@ int smblib_get_prop_usb_voltage_max_design(struct smb_charger *chg, int smblib_get_prop_usb_voltage_now(struct smb_charger *chg, union power_supply_propval *val) { +/* yangfb@bsp, 20161229 Vbus switch uV to mV */ + int rc = 0; if (!chg->iio.usbin_v_chan || PTR_ERR(chg->iio.usbin_v_chan) == -EPROBE_DEFER) chg->iio.usbin_v_chan = iio_channel_get(chg->dev, "usbin_v"); if (IS_ERR(chg->iio.usbin_v_chan)) return PTR_ERR(chg->iio.usbin_v_chan); - - return iio_read_channel_processed(chg->iio.usbin_v_chan, &val->intval); +/* yangfb@bsp, 20161229 Vbus switch uV to mV */ + rc = iio_read_channel_processed(chg->iio.usbin_v_chan, &val->intval); + val->intval = val->intval / 1000; + return rc; } int smblib_get_prop_usb_current_now(struct smb_charger *chg, @@ -2702,7 +3007,11 @@ int smblib_get_prop_typec_power_role(struct smb_charger *chg, int smblib_get_prop_pd_allowed(struct smb_charger *chg, union power_supply_propval *val) { - val->intval = get_effective_result(chg->pd_allowed_votable); +/* david.liu@bsp, 201710503 Fix slow SRC & SNK */ + if (chg->pd_disabled) + val->intval = 0; + else + val->intval = get_effective_result(chg->pd_allowed_votable); return 0; } @@ -2878,6 +3187,8 @@ int smblib_set_prop_sdp_current_max(struct smb_charger *chg, { int rc = 0; +/* david.liu@bsp, 20171023 Battery & Charging porting */ + pr_err("set usb current_max=%d\n", val->intval); if (!chg->pd_active) { rc = smblib_handle_usb_current(chg, val->intval); } else if (chg->system_suspend_supported) { @@ -2998,6 +3309,12 @@ static int __smblib_set_prop_pd_active(struct smb_charger *chg, bool pd_active) bool orientation, sink_attached, hvdcp; u8 stat; +/* david.liu@bsp, 20171023 Battery & Charging porting */ + rc = 0; + if (chg->pd_disabled) + return rc; + + pr_info("set pd_active=%d\n", pd_active); chg->pd_active = pd_active; if (chg->pd_active) { chg->real_charger_type = POWER_SUPPLY_TYPE_USB_PD; @@ -3251,6 +3568,9 @@ int smblib_set_prop_pd_in_hard_reset(struct smb_charger *chg, { int rc = 0; +/* david.liu@bsp, 20170202 Add pd_disabled */ + if (chg->pd_disabled) + return rc; if (chg->pd_hard_reset == val->intval) return rc; @@ -3501,6 +3821,20 @@ irqreturn_t smblib_handle_chg_state_change(int irq, void *data) } stat = stat & BATTERY_CHARGER_STATUS_MASK; +/* david.liu@bsp, 20171023 Battery & Charging porting */ + if (stat == TERMINATE_CHARGE) { + /* charge done, disable charge in software also */ + chg->chg_done = true; + pr_info("TERMINATE_CHARGE: chg_done: CAP=%d (Q:%d), VBAT=%d (Q:%d), IBAT=%d (Q:%d), BAT_TEMP=%d\n", + get_prop_batt_capacity(chg), + get_prop_fg_capacity(chg), + get_prop_batt_voltage_now(chg) / 1000, + get_prop_fg_voltage_now(chg) / 1000, + get_prop_batt_current_now(chg) / 1000, + get_prop_fg_current_now(chg) / 1000, + get_prop_batt_temp(chg)); + op_charging_en(chg, false); + } power_supply_changed(chg->batt_psy); return IRQ_HANDLED; } @@ -3552,6 +3886,12 @@ irqreturn_t smblib_handle_usbin_uv(int irq, void *data) int rc; u8 stat = 0, max_pulses = 0; +/* david.liu@bsp, 20171023 Battery & Charging porting */ + chg->dash_on = get_prop_fast_chg_started(chg); + if (chg->dash_on) { + pr_err("return directly because dash is online\n"); + return IRQ_HANDLED; + } smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name); if (!chg->irq_info[SWITCH_POWER_OK_IRQ].irq_data) return IRQ_HANDLED; @@ -3606,9 +3946,40 @@ irqreturn_t smblib_handle_usbin_uv(int irq, void *data) smblib_rerun_apsd(chg); } +/* david.liu@bsp, 20171023 Battery & Charging porting */ + smblib_err(chg, "DEBUG: RESET STORM COUNT FOR POWER_OK\n"); return IRQ_HANDLED; } +/* david.liu@bsp, 20171023 Battery & Charging porting */ +char dump_val[2048]; +static inline void op_dump_reg(struct smb_charger *chip, + u16 addr_start, u16 addr_end) +{ + u8 reg = 0; + u16 addr; + char reg_val[19]; + + memset(dump_val, 0, sizeof(dump_val)); + for (addr = addr_start; addr <= addr_end; addr++) { + memset(reg_val, 0, sizeof(reg_val)); + smblib_read(chip, addr, ®); + 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)); +} + static void smblib_micro_usb_plugin(struct smb_charger *chg, bool vbus_rising) { if (vbus_rising) { @@ -3630,6 +4001,16 @@ void smblib_usb_plugin_hard_reset_locked(struct smb_charger *chg) struct smb_irq_data *data; struct storm_watch *wdata; +/* david.liu@bsp, 20171023 Battery & Charging porting */ + bool last_vbus_present; + + last_vbus_present = chg->vbus_present; + chg->dash_on = get_prop_fast_chg_started(chg); + if (chg->dash_on) { + pr_err("return directly because dash is online\n"); + return; + } + rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read USB_INT_RT_STS rc=%d\n", rc); @@ -3679,6 +4060,17 @@ void smblib_usb_plugin_locked(struct smb_charger *chg) struct smb_irq_data *data; struct storm_watch *wdata; +/* david.liu@bsp, 20171023 Battery & Charging porting */ + union power_supply_propval vbus_val; + bool last_vbus_present; + + last_vbus_present = chg->vbus_present; + chg->dash_on = get_prop_fast_chg_started(chg); + if (chg->dash_on) { + pr_err("return directly because dash is online\n"); + return; + } + rc = smblib_read(chg, USBIN_BASE + INT_RT_STS_OFFSET, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read USB_INT_RT_STS rc=%d\n", rc); @@ -3689,6 +4081,17 @@ void smblib_usb_plugin_locked(struct smb_charger *chg) smblib_set_opt_freq_buck(chg, vbus_rising ? chg->chg_freq.freq_5V : chg->chg_freq.freq_removal); +/* david.liu@bsp, 20171023 Battery & Charging porting */ + chg->vbus_present = vbus_rising; + if (last_vbus_present != chg->vbus_present) { + if (chg->vbus_present) { + pr_info("acquire chg_wake_lock\n"); + __pm_stay_awake(&chg->chg_wake_lock); + } else { + pr_info("release chg_wake_lock\n"); + __pm_relax(&chg->chg_wake_lock); + } + } if (vbus_rising) { if (smblib_get_prop_dfp_mode(chg) != POWER_SUPPLY_TYPEC_NONE) { chg->fake_usb_insertion = true; @@ -3703,6 +4106,16 @@ void smblib_usb_plugin_locked(struct smb_charger *chg) if (chg->fcc_stepper_enable) vote(chg->fcc_votable, FCC_STEPPER_VOTER, false, 0); +/* david.liu@bsp, 20171023 Battery & Charging porting */ + if (chg->charger_collpse) { + op_set_collapse_fet(chg, 0); + chg->charger_collpse = 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)); /* Schedule work to enable parallel charger */ vote(chg->awake_votable, PL_DELAY_VOTER, true, 0); schedule_delayed_work(&chg->pl_enable_work, @@ -3738,6 +4151,9 @@ void smblib_usb_plugin_locked(struct smb_charger *chg) rc = smblib_request_dpdm(chg, false); if (rc < 0) smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc); +/* david.liu@bsp, 20171023 Battery & Charging porting */ + if (last_vbus_present != chg->vbus_present) + op_handle_usb_removal(chg); } if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) @@ -3746,6 +4162,21 @@ 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"); +/* david.liu@bsp, 20171023 Battery & Charging porting */ + if (!vbus_rising) { + rc = smblib_get_prop_usb_voltage_now(chg, &vbus_val); + if (rc < 0) { + pr_err("V fail rc=%d\n", rc); + } else { + if (vbus_val.intval > 3000) { + pr_err("unplg,Vbus=%d", + vbus_val.intval); + } + } + } + + pr_err("IRQ: %s\n", + vbus_rising ? "attached" : "detached"); } irqreturn_t smblib_handle_usb_plugin(int irq, void *data) @@ -3762,6 +4193,15 @@ irqreturn_t smblib_handle_usb_plugin(int irq, void *data) return IRQ_HANDLED; } +/* david.liu@bsp, 20171023 Battery & Charging porting */ +void op_handle_usb_plugin(struct smb_charger *chg) +{ + mutex_lock(&chg->lock); + smblib_usb_plugin_locked(chg); + smblib_usb_typec_change(chg); + mutex_unlock(&chg->lock); +} + #define USB_WEAK_INPUT_UA 1400000 #define ICL_CHANGE_DELAY_MS 1000 irqreturn_t smblib_handle_icl_change(int irq, void *data) @@ -4003,7 +4443,8 @@ static void smblib_force_legacy_icl(struct smb_charger *chg, int pst) */ if (!is_client_vote_enabled(chg->usb_icl_votable, USB_PSY_VOTER)) - vote(chg->usb_icl_votable, USB_PSY_VOTER, true, 100000); + vote(chg->usb_icl_votable, USB_PSY_VOTER, + true, USBIN_500MA + USBIN_25MA); vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, false, 0); break; case POWER_SUPPLY_TYPE_USB_CDP: @@ -4012,6 +4453,7 @@ static void smblib_force_legacy_icl(struct smb_charger *chg, int pst) case POWER_SUPPLY_TYPE_USB_DCP: typec_mode = smblib_get_prop_typec_mode(chg); rp_ua = get_rp_based_dcp_current(chg, typec_mode); +/* david.liu@bsp, 20171023 Battery & Charging porting */ vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, rp_ua); break; case POWER_SUPPLY_TYPE_USB_FLOAT: @@ -4019,7 +4461,9 @@ static void smblib_force_legacy_icl(struct smb_charger *chg, int pst) * limit ICL to 100mA, the USB driver will enumerate to check * if this is a SDP and appropriately set the current */ - vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 100000); +/* david.liu@bsp, 20171023 Battery & Charging porting */ + vote(chg->usb_icl_votable, + LEGACY_UNKNOWN_VOTER, true, DCP_CURRENT_UA); break; case POWER_SUPPLY_TYPE_USB_HVDCP: case POWER_SUPPLY_TYPE_USB_HVDCP_3: @@ -4063,16 +4507,44 @@ static void smblib_notify_usb_host(struct smb_charger *chg, bool enable) extcon_set_state_sync(chg->extcon, EXTCON_USB_HOST, enable); } +/* david.liu@bsp, 20171023 Battery & Charging porting */ +#define DEFAULT_AGAING_CHG_MA 1000 +int op_rerun_apsd(struct smb_charger *chg) +{ + union power_supply_propval val; + int rc; + + rc = smblib_get_prop_usb_present(chg, &val); + if (rc < 0) { + smblib_err(chg, "Couldn't get usb present rc = %d\n", rc); + return rc; + } + + if (!val.intval) + return 0; + /* rerun APSD */ + pr_info("OP Reruning APSD type\n"); + 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; +} + #define HVDCP_DET_MS 2500 static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising) { +/* david.liu@bsp, 20171023 Battery & Charging porting */ + int temp_region = 0, current_limit_ua = 0; const struct apsd_result *apsd_result; if (!rising) return; apsd_result = smblib_update_usb_type(chg); - if (!chg->typec_legacy_valid) smblib_force_legacy_icl(chg, apsd_result->pst); @@ -4100,6 +4572,63 @@ static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising) default: break; } +/* david.liu@bsp, 20171023 Battery & Charging porting */ + if ((apsd_result->bit) == SDP_CHARGER_BIT) + current_limit_ua = SDP_CURRENT_UA; + else if ((apsd_result->bit) == CDP_CHARGER_BIT) + current_limit_ua = CDP_CURRENT_UA; + else if ((apsd_result->bit) == DCP_CHARGER_BIT) + current_limit_ua = DCP_CURRENT_UA; + else if ((apsd_result->bit) == FLOAT_CHARGER_BIT) { + if (chg->usb_type_redet_done) + current_limit_ua = DCP_CURRENT_UA; + else + current_limit_ua = TYPEC_DEFAULT_CURRENT_UA; + } else if ((apsd_result->bit) == OCP_CHARGER_BIT) + current_limit_ua = DCP_CURRENT_UA; + + if (chg->is_aging_test) + current_limit_ua = DEFAULT_AGAING_CHG_MA*1000; + vote(chg->usb_icl_votable, + DCP_VOTER, true, current_limit_ua); + + temp_region = op_battery_temp_region_get(chg); + if (temp_region != BATT_TEMP_COLD + && temp_region != BATT_TEMP_HOT) { + op_charging_en(chg, true); + smblib_set_prop_charge_parameter_set(chg); + } + + 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(500)); + } else { + if (!chg->usb_type_redet_done) { + schedule_delayed_work(&chg->re_det_work, + msecs_to_jiffies(TIME_1000MS)); + } else { + if (chg->probe_done) { + if (apsd_result->bit == FLOAT_CHARGER_BIT) + schedule_delayed_work( + &chg->check_switch_dash_work, + msecs_to_jiffies(500)); + 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); @@ -4114,6 +4643,12 @@ irqreturn_t smblib_handle_usb_source_change(int irq, void *data) if (chg->fake_usb_insertion) return IRQ_HANDLED; +/* david.liu@bsp, 20171023 Battery & Charging porting */ + chg->dash_on = get_prop_fast_chg_started(chg); + if (chg->dash_on) { + pr_err("return directly because dash is online\n"); + return IRQ_HANDLED; + } rc = smblib_read(chg, APSD_STATUS_REG, &stat); if (rc < 0) { @@ -4121,6 +4656,8 @@ irqreturn_t smblib_handle_usb_source_change(int irq, void *data) return IRQ_HANDLED; } smblib_dbg(chg, PR_REGISTER, "APSD_STATUS = 0x%02x\n", stat); +/* david.liu@bsp, 20171023 Battery & Charging porting */ + pr_info("APSD_STATUS=0x%02x\n", stat); if ((chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) && (stat & APSD_DTC_STATUS_DONE_BIT) @@ -4335,8 +4872,14 @@ static void typec_sink_insertion(struct smb_charger *chg) } typec_mode = smblib_get_prop_typec_mode(chg); - if (typec_mode == POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER) +/*2018/06/14 @bsp add for support notify audio adapter switch*/ + if (typec_mode == POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER) { chg->is_audio_adapter = true; + audio_adapter_flag = true; + pr_info("Type-C %s detected,notify!\n", + smblib_typec_mode_name[chg->typec_mode]); + cc_notifier_call_chain(1); + } /* when a sink is inserted we should not wait on hvdcp timeout to * enable pd @@ -4388,7 +4931,8 @@ static void smblib_handle_typec_removal(struct smb_charger *chg) cancel_delayed_work_sync(&chg->hvdcp_detect_work); /* reset input current limit voters */ - vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, 100000); +/*Yangfb@bsp ,20180202,set icl 500mA after charger removed*/ + vote(chg->usb_icl_votable, LEGACY_UNKNOWN_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); @@ -4487,14 +5031,21 @@ static void smblib_handle_typec_removal(struct smb_charger *chg) smblib_err(chg, "Couldn't set USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V rc=%d\n", rc); - if (chg->is_audio_adapter) +/*2018/06/14 @bsp add for support notify audio adapter switch*/ + if (chg->is_audio_adapter) { /* wait for the audio driver to lower its en gpio */ msleep(*chg->audio_headset_drp_wait_ms); - chg->is_audio_adapter = false; + chg->is_audio_adapter = false; + audio_adapter_flag = false; + pr_info("Type-C removal, audio_adapter_present=(%d),notify!\n", + chg->is_audio_adapter); + cc_notifier_call_chain(0); + } /* enable DRP */ - val.intval = POWER_SUPPLY_TYPEC_PR_DUAL; + val.intval = chg->otg_switch ? + POWER_SUPPLY_TYPEC_PR_DUAL : POWER_SUPPLY_TYPEC_PR_SINK; rc = smblib_set_prop_typec_power_role(chg, &val); if (rc < 0) smblib_err(chg, "Couldn't enable DRP rc=%d\n", rc); @@ -4604,21 +5155,52 @@ static void smblib_handle_rp_change(struct smb_charger *chg, int typec_mode) vote(chg->usb_icl_votable, LEGACY_UNKNOWN_VOTER, true, rp_ua); } -static void smblib_handle_typec_cc_state_change(struct smb_charger *chg) +/*2018/06/14 @bsp add for support notify audio adapter switch*/ +int register_cc_notifier_client(struct notifier_block *nb) { - int typec_mode; + int ret; - if (chg->pr_swap_in_progress) - return; + ret = blocking_notifier_chain_register(&typec_cc_chain, nb); + if (ret) + pr_err("Cann't register cc notifier, ret = %d\n", ret); - typec_mode = smblib_get_prop_typec_mode(chg); - if (chg->typec_present && (typec_mode != chg->typec_mode)) - smblib_handle_rp_change(chg, typec_mode); + return ret; +} +EXPORT_SYMBOL(register_cc_notifier_client); - chg->typec_mode = typec_mode; +int unregister_cc_notifier_client(struct notifier_block *nb) +{ + int ret; - if (!chg->typec_present && chg->typec_mode != POWER_SUPPLY_TYPEC_NONE) { - chg->typec_present = true; + ret = blocking_notifier_chain_unregister(&typec_cc_chain, nb); + if (ret) + pr_err("Cann't unregister cc notifier, ret = %d\n", ret); + + return ret; +} +EXPORT_SYMBOL(unregister_cc_notifier_client); + +static int cc_notifier_call_chain(unsigned long val) +{ + return (blocking_notifier_call_chain(&typec_cc_chain, val, NULL) + == NOTIFY_BAD) ? -EINVAL : 0; +} + +static void smblib_handle_typec_cc_state_change(struct smb_charger *chg) +{ + int typec_mode; + + if (chg->pr_swap_in_progress) + return; + + typec_mode = smblib_get_prop_typec_mode(chg); + if (chg->typec_present && (typec_mode != chg->typec_mode)) + smblib_handle_rp_change(chg, typec_mode); + + chg->typec_mode = typec_mode; + + if (!chg->typec_present && chg->typec_mode != POWER_SUPPLY_TYPEC_NONE) { + chg->typec_present = true; smblib_dbg(chg, PR_MISC, "TypeC %s insertion\n", smblib_typec_mode_name[chg->typec_mode]); smblib_handle_typec_insertion(chg); @@ -4628,189 +5210,2777 @@ static void smblib_handle_typec_cc_state_change(struct smb_charger *chg) smblib_dbg(chg, PR_MISC, "TypeC removal\n"); smblib_handle_typec_removal(chg); } + /* if audio adapter connectted,do not set ICL 0*/ + if (audio_adapter_flag) { + smblib_dbg(chg, PR_INTERRUPT, "IRQ: cc-state-change; Type-C %s detected\n", + smblib_typec_mode_name[chg->typec_mode]); + return; + } + /* suspend usb if sink */ + if ((chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT) + && chg->typec_present) + vote(chg->usb_icl_votable, OTG_VOTER, true, 0); + else + vote(chg->usb_icl_votable, OTG_VOTER, false, 0); + + smblib_dbg(chg, PR_INTERRUPT, "IRQ: cc-state-change; Type-C %s detected\n", + smblib_typec_mode_name[chg->typec_mode]); +} + +void smblib_usb_typec_change(struct smb_charger *chg) +{ + int rc; + + rc = smblib_multibyte_read(chg, TYPE_C_STATUS_1_REG, + chg->typec_status, 5); + if (rc < 0) { + smblib_err(chg, "Couldn't cache USB Type-C status rc=%d\n", rc); + return; + } + + smblib_handle_typec_cc_state_change(chg); + + if (chg->typec_status[3] & TYPEC_VBUS_ERROR_STATUS_BIT) + smblib_dbg(chg, PR_INTERRUPT, "IRQ: vbus-error\n"); + + if (chg->typec_status[3] & TYPEC_VCONN_OVERCURR_STATUS_BIT) + schedule_work(&chg->vconn_oc_work); + + power_supply_changed(chg->usb_psy); +} + +irqreturn_t smblib_handle_usb_typec_change(int irq, void *data) +{ + struct smb_irq_data *irq_data = data; + struct smb_charger *chg = irq_data->parent_data; +/* david.liu@bsp, 20171023 Battery & Charging porting */ + chg->dash_on = get_prop_fast_chg_started(chg); + if (chg->dash_on) + return IRQ_HANDLED; + + if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) { + cancel_delayed_work_sync(&chg->uusb_otg_work); + vote(chg->awake_votable, OTG_DELAY_VOTER, true, 0); + smblib_dbg(chg, PR_INTERRUPT, "Scheduling OTG work\n"); + schedule_delayed_work(&chg->uusb_otg_work, + msecs_to_jiffies(chg->otg_delay_ms)); + return IRQ_HANDLED; + } + + if (chg->cc2_detach_wa_active || chg->typec_en_dis_active || + chg->try_sink_active) { + smblib_dbg(chg, PR_MISC | PR_INTERRUPT, "Ignoring since %s active\n", + chg->cc2_detach_wa_active ? + "cc2_detach_wa" : "typec_en_dis"); + return IRQ_HANDLED; + } + + if (chg->pr_swap_in_progress) { + smblib_dbg(chg, PR_INTERRUPT, + "Ignoring since pr_swap_in_progress\n"); + return IRQ_HANDLED; + } + + mutex_lock(&chg->lock); + smblib_usb_typec_change(chg); + mutex_unlock(&chg->lock); + return IRQ_HANDLED; +} + +irqreturn_t smblib_handle_dc_plugin(int irq, void *data) +{ + struct smb_irq_data *irq_data = data; + struct smb_charger *chg = irq_data->parent_data; + + power_supply_changed(chg->dc_psy); + return IRQ_HANDLED; +} + +irqreturn_t smblib_handle_high_duty_cycle(int irq, void *data) +{ + struct smb_irq_data *irq_data = data; + struct smb_charger *chg = irq_data->parent_data; + + chg->is_hdc = true; + /* + * Disable usb IRQs after the flag set and re-enable IRQs after + * the flag cleared in the delayed work queue, to avoid any IRQ + * storming during the delays + */ + if (chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq) + disable_irq_nosync(chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq); + + schedule_delayed_work(&chg->clear_hdc_work, msecs_to_jiffies(60)); + + return IRQ_HANDLED; +} + +static void smblib_bb_removal_work(struct work_struct *work) +{ + struct smb_charger *chg = container_of(work, struct smb_charger, + bb_removal_work.work); + + vote(chg->usb_icl_votable, BOOST_BACK_VOTER, false, 0); + vote(chg->awake_votable, BOOST_BACK_VOTER, false, 0); +} + +#define BOOST_BACK_UNVOTE_DELAY_MS 750 +#define BOOST_BACK_STORM_COUNT 3 +#define WEAK_CHG_STORM_COUNT 8 +irqreturn_t smblib_handle_switcher_power_ok(int irq, void *data) +{ + struct smb_irq_data *irq_data = data; + struct smb_charger *chg = irq_data->parent_data; + int rc, usb_icl; + u8 stat; +/* david.liu@bsp, 20171023 Battery & Charging porting */ + union power_supply_propval vbus_val; + + smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name); + chg->dash_on = get_prop_fast_chg_started(chg); + if (chg->dash_on) { + pr_err("return directly because dash is online\n"); + return IRQ_HANDLED; + } + + if (!(chg->wa_flags & BOOST_BACK_WA)) + return IRQ_HANDLED; + + rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat); + if (rc < 0) { + smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n", rc); + return IRQ_HANDLED; + } + + /* skip suspending input if its already suspended by some other voter */ + usb_icl = get_effective_result(chg->usb_icl_votable); + if ((stat & USE_USBIN_BIT) && usb_icl >= 0 && usb_icl <= USBIN_25MA) + return IRQ_HANDLED; + + if (stat & USE_DCIN_BIT) + return IRQ_HANDLED; + + if (is_storming(&irq_data->storm_data)) { +/* david.liu@bsp, 20171023 Battery & Charging porting */ + /*Use the setting of 0x1380 and 0x1365 is useful*/ + smblib_err(chg, "Reverse boost detected\n"); + rc = smblib_get_prop_usb_voltage_now(chg, &vbus_val); + if (rc < 0) + pr_err("fail to read usb_voltage rc=%d\n", rc); + else if (vbus_val.intval >= 2500) + pr_err("vbus_val.intval=%d\n", vbus_val.intval); + chg->revert_boost_trigger = true; + vote(chg->usb_icl_votable, BOOST_BACK_VOTER, true, 0); + schedule_delayed_work(&chg->recovery_suspend_work, + msecs_to_jiffies(TIME_100MS)); + } + + return IRQ_HANDLED; +} + +irqreturn_t smblib_handle_wdog_bark(int irq, void *data) +{ + struct smb_irq_data *irq_data = data; + struct smb_charger *chg = irq_data->parent_data; + int rc; + + smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name); + + rc = smblib_write(chg, BARK_BITE_WDOG_PET_REG, BARK_BITE_WDOG_PET_BIT); + if (rc < 0) + smblib_err(chg, "Couldn't pet the dog rc=%d\n", rc); + + if (chg->step_chg_enabled || chg->sw_jeita_enabled) + power_supply_changed(chg->batt_psy); + + return IRQ_HANDLED; +} + +/* david.liu@bsp, 20171023 Battery & Charging porting */ +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_info("AICL result=%dmA\n", settled_ua / 1000); +} +static bool is_usb_present(struct smb_charger *chg); + +static void op_dash_check_work(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct smb_charger *chg = container_of(dwork, + struct smb_charger, dash_check_work); + int soc, temp; + + chg->dash_check_count++; + if (!is_usb_present(chg)) { + chg->dash_check_count = 0; + return; + } + if (!chg->dash_present) { + chg->dash_check_count = 0; + return; + } + if (op_get_fastchg_ing(chg)) { + chg->dash_check_count = 0; + return; + } + if (chg->non_stand_chg_count < 300) { + schedule_delayed_work(&chg->dash_check_work, + msecs_to_jiffies(TIME_1000MS)); + return; + } + + chg->dash_check_count = 0; + soc = get_prop_batt_capacity(chg); + temp = get_prop_batt_temp(chg); + if (soc >= 1 && temp < 410) { + chg->re_trigr_dash_done = true; + set_usb_switch(chg, false); + set_usb_switch(chg, true); + } +} + +static int get_usb_temp(struct smb_charger *chg); + +static void op_connect_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); + + if (!chg->vbus_present) + return; + chg->connecter_temp = get_usb_temp(chg); + if (chg->connecter_temp < 68) + schedule_delayed_work(&chg->connecter_check_work, + msecs_to_jiffies(200)); + else + op_disconnect_vbus(chg, true); +} + +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 int get_property_from_fg(struct smb_charger *chg, + enum power_supply_property prop, int *val) +{ + int rc; + union power_supply_propval ret = {0, }; + + if (!chg->bms_psy) + chg->bms_psy = power_supply_get_by_name("bms"); + + if (chg->bms_psy) { + rc = power_supply_get_property(chg->bms_psy, prop, &ret); + if (rc) { + pr_err("bms psy doesn't support reading prop %d rc = %d\n", + prop, rc); + return rc; + } + *val = ret.intval; + } else { + pr_err("no bms psy found\n"); + return -EINVAL; + } + + return rc; +} + +static int set_property_on_fg(struct smb_charger *chg, + enum power_supply_property prop, int val) +{ + int rc; + union power_supply_propval ret = {0, }; + + if (!chg->bms_psy) + chg->bms_psy = power_supply_get_by_name("bms"); + + if (chg->bms_psy) { + ret.intval = val; + rc = power_supply_set_property(chg->bms_psy, prop, &ret); + if (rc) + pr_err("bms psy does not allow updating prop %d rc = %d\n", + prop, rc); + } else { + pr_err("no bms psy found\n"); + return -EINVAL; + } + + return rc; +} + +static int op_charging_en(struct smb_charger *chg, bool en) +{ + int rc; + + pr_err("enable=%d\n", en); + 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 (!fw_updated) + return false; + if (chg->usb_enum_status) + return false; + if (temp < 165 || temp > 430) { + if (temp != pre_temp) + pr_err("temp=%d is not allow to swith 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) +{ + if (!g_chg) + return; + pr_info("op_switch_normal_set\n"); + vote(g_chg->usb_icl_votable, + DCP_VOTER, true, 2000 * 1000); + vote(g_chg->fv_votable, + DEFAULT_VOTER, true, 4500 * 1000); + 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->is_aging_test) + return false; +#endif + if (g_chg) + return (g_chg->chg_done || g_chg->recharge_status); + else + return false; +} + +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_enhache_status(); + + 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->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->dash_check_count = 0; + chg->ffc_count = 0; + vote(chg->fcc_votable, + DEFAULT_VOTER, true, SDP_CURRENT_UA); + set_sdp_current(chg, USBIN_500MA); + 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; +} + +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_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; +} + +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_enhache_status(void) +{ + if (fast_charger && fast_charger->clean_enhache) + return fast_charger->clean_enhache(); + 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); +} + +static void set_prop_batt_health(struct smb_charger *chg, int batt_health) +{ + chg->batt_health = batt_health; +} + +static void set_usb_switch(struct smb_charger *chg, bool enable) +{ + int retrger_time; + + if (!fast_charger) { + pr_err("no fast_charger register found\n"); + return; + } + + if (enable) { + pr_err("switch on fastchg\n"); + 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, AICL_RERUN_VOTER, + true, DCP_CURRENT_UA); + } + 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"); + 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 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->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_chek_apsd_done_work(struct work_struct *work) +{ + struct smb_charger *chg = container_of(work, + struct smb_charger, + op_check_apsd_work.work); + union power_supply_propval vbus_val; + int rc; + const struct apsd_result *apsd_result; + + pr_debug("chg->ck_apsd_count=%d\n", chg->ck_apsd_count); + if (chg->usb_enum_status || chg->op_apsd_done) { + chg->ck_apsd_count = 0; + return; + } + rc = smblib_get_prop_usb_voltage_now(chg, &vbus_val); + if (rc < 0) { + chg->ck_apsd_count = 0; + pr_info("failed to read usb_voltage rc=%d\n", rc); + return; + } + if (vbus_val.intval < 2500) { + pr_info("vbus less 2.5v\n"); + chg->ck_apsd_count = 0; + return; + } + apsd_result = smblib_get_apsd_result(chg); + if (apsd_result->bit) { + chg->ck_apsd_count = 0; + return; + } + + if (chg->ck_apsd_count >= APSD_CHECK_COUTNT) { + pr_info("apsd done error\n"); + chg->ck_apsd_count = 0; + op_dump_regs(chg); + op_rerun_apsd(chg); + } else { + chg->ck_apsd_count++; + schedule_delayed_work(&chg->op_check_apsd_work, + msecs_to_jiffies(TIME_1000MS)); + } +} + +static void op_recovery_usb_suspend_work(struct work_struct *work) +{ + struct smb_charger *chg = container_of(work, + struct smb_charger, + recovery_suspend_work.work); + int effect_result; + + if (chg->recovery_boost_count >= BOOST_BACK_COUNT + || (!is_usb_present(chg))) { + pr_info("recovery revert boost\n"); + vote(chg->usb_icl_votable, BOOST_BACK_VOTER, false, 0); + if (is_usb_present(chg)) { + effect_result = + get_effective_result(chg->usb_icl_votable); + pr_info("effect_result=%d\n", effect_result); + if (effect_result + > DEFAULT_AGAING_CHG_MA*1000) { + vote(chg->usb_icl_votable, DCP_VOTER, + true, (effect_result - USBIN_150MA)); + smblib_rerun_aicl(chg); + } + } + 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; + + 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, soc; + 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); + soc = get_prop_batt_capacity(g_chg); + if (g_chg->boot_usb_present && !soc) + schedule_delayed_work(&g_chg->dash_check_work, + msecs_to_jiffies(2000)); + } + 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 = 0, 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 = 0, 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 = 0, rc; + + rc = get_property_from_fg(chg, POWER_SUPPLY_PROP_CURRENT_NOW, &ua); + if (rc) { + pr_err("Couldn't get current rc=%d\n", rc); + ua = DEFAULT_BATT_CURRENT_NOW; + } + + return ua; +} + +#define DEFAULT_BATT_VOLTAGE_NOW 0 +static int get_prop_batt_voltage_now(struct smb_charger *chg) +{ + int uv = 0, 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 = 0, rc; + + rc = get_property_from_fg(chg, POWER_SUPPLY_PROP_FG_VOLTAGE_NOW, &uv); + if (rc) { + pr_err("Couldn't get voltage rc=%d\n", rc); + uv = DEFAULT_BATT_VOLTAGE_NOW; + } + + return uv; +} + +int get_prop_batt_status(struct smb_charger *chg) +{ + int capacity, batt_status, rc; + enum temp_region_type temp_region; + union power_supply_propval pval = {0, }; + + temp_region = op_battery_temp_region_get(chg); + capacity = get_prop_batt_capacity(chg); + chg->dash_on = get_prop_fast_chg_started(chg); + if ((chg->chg_done || chg->recharge_status) + && (temp_region == BATT_TEMP_COOL + || temp_region == BATT_TEMP_LITTLE_COOL + || temp_region == BATT_TEMP_PRE_NORMAL + || temp_region == BATT_TEMP_NORMAL) + &&(capacity == 100)) { + return POWER_SUPPLY_STATUS_FULL; + } else if (chg->dash_on) { + return POWER_SUPPLY_STATUS_CHARGING; + } + if (chg->revert_boost_trigger && chg->vbus_present) + return POWER_SUPPLY_STATUS_CHARGING; + + rc = smblib_get_prop_batt_status(chg, &pval); + if (rc) + batt_status = 0; + else + batt_status = pval.intval; + if (batt_status == POWER_SUPPLY_STATUS_FULL + && !(chg->chg_done || chg->recharge_status)) + return POWER_SUPPLY_STATUS_CHARGING; + return batt_status; +} + +int get_charging_status(void) +{ + int rc; + union power_supply_propval pval = {0, }; + + if (!g_chg) + return POWER_SUPPLY_STATUS_DISCHARGING; + + rc = smblib_get_prop_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) +{ + pr_err("set ibatmax=%d and set vbatmax=%d\n", + ibat, vfloat); + + if (chg->ffc_status != FFC_DEFAULT) + return; + vote(chg->fcc_votable, + DEFAULT_VOTER, true, ibat * 1000); + vote(chg->fv_votable, + DEFAULT_VOTER, true, vfloat * 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; + union power_supply_propval pval; + + smblib_get_prop_batt_voltage_now(chg, &pval); + vbat_mv = pval.intval/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_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]); + op_battery_temp_region_set(chg, 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; + + 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); + + set_chg_ibat_vbat_max(chg, + chg->ibatmax[BATT_TEMP_COOL], + chg->vbatmax[BATT_TEMP_COOL]); + op_battery_temp_region_set(chg, BATT_TEMP_COOL); + + /* 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); + + 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_low_current, + chg->vbatmax[BATT_TEMP_LITTLE_COOL]); + chg->temp_littel_cool_set_current = 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 = true; + } + op_battery_temp_region_set(chg, BATT_TEMP_LITTLE_COOL); + + /* 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); + + set_chg_ibat_vbat_max(chg, + chg->ibatmax[BATT_TEMP_PRE_NORMAL], + chg->vbatmax[BATT_TEMP_PRE_NORMAL]); + op_battery_temp_region_set(chg, 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); + + set_chg_ibat_vbat_max(chg, + chg->ibatmax[BATT_TEMP_NORMAL], + chg->vbatmax[BATT_TEMP_NORMAL]); + op_battery_temp_region_set(chg, 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_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]); + op_battery_temp_region_set(chg, 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 = 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; +} + +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 + && ((CC_SOFT_TERMINATE_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_RERUN_EN_BIT, USBIN_AICL_RERUN_EN_BIT); + if (rc < 0) + dev_err(chg->dev, + "Couldn't configure AICL rc=%d\n", rc); + smblib_rerun_aicl(chg); + 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; + + pr_debug("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_rerun_aicl(chg); + } + } + } + pre_uovp_satus = uovp_satus; +} + +#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 msm_drm_notifier *evdata = data; + struct smb_charger *chip = + container_of(self, struct smb_charger, msm_drm_notifier); + int *blank; + + if (evdata->id != MSM_DRM_PRIMARY_DISPLAY) + return 0; + if (event != MSM_DRM_EARLY_EVENT_BLANK) + return 0; + + if (evdata && evdata->data && chip) { + blank = evdata->data; + if (*blank == MSM_DRM_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 == MSM_DRM_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; +} +#endif + +static void ffc_exit(struct smb_charger *chg) { + int icharging, batt_volt, temp; + + if (chg->ffc_status == FFC_DEFAULT) { + chg->ffc_count = 0; + return; + } + batt_volt = get_prop_batt_voltage_now(chg) / 1000; + icharging = get_prop_batt_current_now(chg) / 1000; + temp = get_prop_batt_temp(chg); + + if (chg->ffc_status == FFC_NOR_TAPER + || chg->ffc_status == FFC_WARM_TAPER) { + if (temp > chg->FFC_TEMP_T1 + && temp < chg->FFC_TEMP_T2) { + chg->ffc_status = FFC_NOR_TAPER; + vote(g_chg->fcc_votable, + DEFAULT_VOTER, true, chg->FFC_NOR_FCC * 1000); + } else if (temp >= chg->FFC_TEMP_T2 + && temp < chg->FFC_TEMP_T3) { + chg->ffc_status = FFC_WARM_TAPER; + vote(g_chg->fcc_votable, + DEFAULT_VOTER, true, chg->FFC_WARM_FCC * 1000); + } else { + chg->ffc_count = 0; + chg->ffc_status = FFC_IDLE; + } + } + + if (chg->ffc_status == FFC_FAST) { + if (batt_volt >= chg->FFC_VBAT_FULL) + chg->ffc_count++; + else + chg->ffc_count = 0; + if (chg->ffc_count >= 2) { + chg->ffc_count = 0; + chg->ffc_status = FFC_TAPER; + pr_info("ffc one done\n"); + } + } else if (chg->ffc_status == FFC_TAPER) { + if (temp > chg->FFC_TEMP_T1 + && temp < chg->FFC_TEMP_T2) { + chg->ffc_status = FFC_NOR_TAPER; + vote(g_chg->fcc_votable, + DEFAULT_VOTER, true, chg->FFC_NOR_FCC * 1000); + } else if (temp >= chg->FFC_TEMP_T2 + && temp < chg->FFC_TEMP_T3) { + chg->ffc_status = FFC_WARM_TAPER; + vote(g_chg->fcc_votable, + DEFAULT_VOTER, true, chg->FFC_WARM_FCC * 1000); + } else { + chg->ffc_count = 0; + chg->ffc_status = FFC_IDLE; + } + } else if (chg->ffc_status == FFC_NOR_TAPER) { + if (icharging <= (-1)*chg->FFC_NORMAL_CUTOFF + && (batt_volt >= chg->FFC_VBAT_FULL)) { + chg->ffc_count = 0; + chg->ffc_status = FFC_IDLE; + } else if (icharging > (-1)*chg->FFC_NORMAL_CUTOFF) + chg->ffc_count++; + else + chg->ffc_count = 0; + if (chg->ffc_count >= 2) { + chg->ffc_count = 0; + chg->ffc_status = FFC_IDLE; + pr_info("ffc nor taper done\n"); + } + } else if (chg->ffc_status == FFC_WARM_TAPER) { + if (icharging <= (-1)*chg->FFC_WARM_CUTOFF + && (batt_volt >= chg->FFC_VBAT_FULL)) { + chg->ffc_count = 0; + chg->ffc_status = FFC_IDLE; + } else if (icharging > (-1)*chg->FFC_WARM_CUTOFF) + chg->ffc_count++; + else + chg->ffc_count = 0; + if (chg->ffc_count >= 2) { + chg->ffc_count = 0; + chg->ffc_status = FFC_IDLE; + pr_info("ffc normal taper done\n"); + } + } else if (chg->ffc_status == FFC_IDLE) { + chg->ffc_count++; + op_charging_en(chg, false); + if (chg->ffc_count > 2) { + 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 = false; + static bool ret_hw = false; + static int vbat_counts_sw = 0; + static int vbat_counts_hw = 0; + int vbatt_full_vol_sw; + int vbatt_full_vol_hw; + 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] - 70; + else if (tbatt_status == BATT_TEMP_COOL) + vbatt_full_vol_sw = chg->vbatmax[tbatt_status] - 70; + else if (tbatt_status == BATT_TEMP_LITTLE_COOL) + vbatt_full_vol_sw = chg->vbatmax[tbatt_status] - 70; + else if (tbatt_status == BATT_TEMP_PRE_NORMAL) + vbatt_full_vol_sw = chg->vbatmax[tbatt_status] - 70; + else if (tbatt_status == BATT_TEMP_NORMAL) + vbatt_full_vol_sw = chg->vbatmax[tbatt_status] - 70; + else if (tbatt_status == BATT_TEMP_WARM) + vbatt_full_vol_sw = chg->vbatmax[tbatt_status] - 70; + else { + vbat_counts_sw = 0; + vbat_counts_hw = 0; + ret_sw = 0; + ret_hw = 0; + return false; + } + + /* use SW Vfloat to check */ + batt_volt = get_prop_batt_voltage_now(chg) / 1000; + icharging = get_prop_batt_current_now(chg) / 1000; + if (batt_volt > vbatt_full_vol_sw) { + if (icharging < 0 && (icharging * -1) <= chg->sw_iterm_ma) { + vbat_counts_sw++; + if (vbat_counts_sw > FULL_COUNTS_SW) { + 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); + 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 void trigger_check_charger(struct smb_charger *chg) +{ + chg->non_stand_chg_count = 0; + schedule_delayed_work( + &chg->non_standard_charger_check_work, + msecs_to_jiffies(TIME_1000MS)); +} + + +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; + + if (!g_chg) + return 0; + if (chg->usb_enum_status) + return 0; + + if (!is_usb_present(chg)) + return 0; + + trigger_check_charger(chg); + apsd_result = smblib_get_apsd_result(chg); + if (apsd_result->bit != SDP_CHARGER_BIT + && apsd_result->bit != CDP_CHARGER_BIT) + return 0; + + ret = kstrtoul(val, 10, &usb_sw_reset); + if (ret) + return ret; + + if (!usb_sw_reset) + return 0; + + pr_info("usb don't enum for longtime in boot\n"); + op_handle_usb_removal(chg); + + return 0; +} +module_param_call(sys_boot_complete, usb_enum_check, NULL, NULL, 0644); + +static void check_non_standard_charger_work(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct smb_charger *chg = container_of(dwork, + struct smb_charger, non_standard_charger_check_work); + + bool charger_present; + const struct apsd_result *apsd_result; + int aicl_result, rc; + + pr_debug("chg->non_stand_chg_count=%d\n", + chg->non_stand_chg_count); + + charger_present = is_usb_present(chg); + if (!charger_present) { + pr_info("chk_non_std_chger,charger_present\n"); + chg->non_stand_chg_count = 0; + return; + } + if (chg->usb_enum_status) { + pr_info("chk_non_std_chger,usb_enum_status\n"); + chg->non_stand_chg_count = 0; + return; + } + if (chg->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; + rc = smblib_rerun_aicl(chg); + 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)); + } +} - /* suspend usb if sink */ - if ((chg->typec_status[3] & UFP_DFP_MODE_STATUS_BIT) - && chg->typec_present) - vote(chg->usb_icl_votable, OTG_VOTER, true, 0); - else - vote(chg->usb_icl_votable, OTG_VOTER, false, 0); +void aging_test_check_aicl(struct smb_charger *chg) +{ + int aicl_result = 0, vbat = 0; - smblib_dbg(chg, PR_INTERRUPT, "IRQ: cc-state-change; Type-C %s detected\n", - smblib_typec_mode_name[chg->typec_mode]); + 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); + } + } } -void smblib_usb_typec_change(struct smb_charger *chg) +int plugin_update(struct smb_charger *chg) { - int rc; + int rc = 0; + char *connected_str[2] = { "USBCable=CONNECTED", NULL}; + char *disconnected_str[2] = { "USBCable=DISCONNECTED", NULL}; - rc = smblib_multibyte_read(chg, TYPE_C_STATUS_1_REG, - chg->typec_status, 5); - if (rc < 0) { - smblib_err(chg, "Couldn't cache USB Type-C status rc=%d\n", rc); + rc = kobject_uevent_env(&chg->dev->kobj, KOBJ_CHANGE, + chg->hw_detect ? connected_str : disconnected_str); + + return rc; +} + + +static void op_otg_switch(struct work_struct *work) +{ + int usb_pluged; + int rc = 0; + + if (!g_chg) return; + usb_pluged = gpio_get_value(g_chg->plug_irq) ? 0 : 1; + if (usb_pluged == g_chg->pre_cable_pluged) { + pr_info("same status,return;usb_present:%d\n", usb_pluged); + return; + } + pr_info("%s,usb_present:%d\n", __func__, usb_pluged); + if (usb_pluged) { + vote(g_chg->otg_toggle_votable, HW_DETECT_VOTER, 1, 0); + g_chg->hw_detect = 1; + } else { + vote(g_chg->otg_toggle_votable, HW_DETECT_VOTER, 0, 0); + g_chg->hw_detect = 0; } + 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; +} - smblib_handle_typec_cc_state_change(chg); +static int get_usb_temp(struct smb_charger *chg) +{ + struct qpnp_vadc_chip *vadc_dev; + struct qpnp_vadc_result result; + int ret, i; - if (chg->typec_status[3] & TYPEC_VBUS_ERROR_STATUS_BIT) - smblib_dbg(chg, PR_INTERRUPT, "IRQ: vbus-error\n"); + vadc_dev = qpnp_get_vadc(chg->dev, "usb-temp"); + if (IS_ERR(vadc_dev)) { + ret = PTR_ERR(vadc_dev); + pr_err("vadc property missing, ret=%d\n", ret); + return ret; + } + ret = qpnp_vadc_read(vadc_dev, VADC_AMUX5_GPIO_PU1, &result); + chg->connecter_voltage = (int) result.physical/1000; + 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; + } + pr_debug("connectter vol:%d,temp:%d\n", + chg->connecter_voltage, con_volt_30k[i]); + return con_temp_30k[i]; +} - if (chg->typec_status[3] & TYPEC_VCONN_OVERCURR_STATUS_BIT) - schedule_work(&chg->vconn_oc_work); +void op_disconnect_vbus(struct smb_charger *chg, bool enable) +{ - power_supply_changed(chg->usb_psy); +#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; + pr_info("usb connecter connectd!"); + return; + } + pr_info("usb connecter hot,Vbus disconnected!"); + chg->dash_on = get_prop_fast_chg_started(chg); + if (chg->dash_on) { + switch_mode_to_normal(); + op_set_fast_chg_allow(chg, false); + } + gpio_set_value(chg->vbus_ctrl, 1); + chg->disconnect_vbus = true; } -irqreturn_t smblib_handle_usb_typec_change(int irq, void *data) +void op_recovery_revert_boost(struct smb_charger *chg) { - struct smb_irq_data *irq_data = data; - struct smb_charger *chg = irq_data->parent_data; + int soc = 0, rc = 0; + union power_supply_propval vbus_val; + const struct apsd_result *apsd_result; - if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) { - cancel_delayed_work_sync(&chg->uusb_otg_work); - vote(chg->awake_votable, OTG_DELAY_VOTER, true, 0); - smblib_dbg(chg, PR_INTERRUPT, "Scheduling OTG work\n"); - schedule_delayed_work(&chg->uusb_otg_work, - msecs_to_jiffies(chg->otg_delay_ms)); - return IRQ_HANDLED; + chg->dash_on = get_prop_fast_chg_started(chg); + if (chg->dash_on) { + pr_info("return directly because dash is online\n"); + return; } - - if (chg->cc2_detach_wa_active || chg->typec_en_dis_active || - chg->try_sink_active) { - smblib_dbg(chg, PR_MISC | PR_INTERRUPT, "Ignoring since %s active\n", - chg->cc2_detach_wa_active ? - "cc2_detach_wa" : "typec_en_dis"); - return IRQ_HANDLED; + if (get_prop_batt_current_now(chg) / 1000 < 0) + return; + apsd_result = smblib_update_usb_type(chg); + if (apsd_result->bit == OCP_CHARGER_BIT) + return; + soc = get_prop_batt_capacity(chg); + if (soc < 7) + return; + 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; } + if (vbus_val.intval < 2000) + return; + pr_info("suspend usb about 1s\n"); + chg->revert_boost_trigger = true; + vote(chg->usb_icl_votable, BOOST_BACK_VOTER, true, 0); + msleep(1000); + vote(chg->usb_icl_votable, BOOST_BACK_VOTER, false, 0); + chg->revert_boost_trigger = false; +} - if (chg->pr_swap_in_progress) { - smblib_dbg(chg, PR_INTERRUPT, - "Ignoring since pr_swap_in_progress\n"); - return IRQ_HANDLED; +static void op_revert_boost_recovery_work(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct smb_charger *chg = container_of(dwork, + struct smb_charger, revertboost_recovery_work); + + op_recovery_revert_boost(chg); +} + +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; + int rc; + +/*yangfb@bsp, 20181023 icl set 1A if battery lower than 15%*/ + op_otg_icl_contrl(chg); +#ifndef CONFIG_OP_DEBUG_CHG + op_check_charge_timeout(chg); +#endif + +#ifdef CONFIG_OP_DEBUG_CHG + rc = smblib_get_prop_usb_voltage_now(chg, &vbus_val); + if (rc < 0) { + pr_err("failed to read usb_voltage rc=%d\n", rc); + vbus_val.intval = CHG_VOLTAGE_NORMAL; + } +#endif + charger_present = is_usb_present(chg); + if (!charger_present) + goto out; + /* charger present */ + power_supply_changed(chg->batt_psy); + chg->dash_on = get_prop_fast_chg_started(chg); + if (chg->dash_on) { + 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; + } + goto out; + } else { + if (chg->disable_normal_chg_for_dash) { + chg->disable_normal_chg_for_dash = false; + op_charging_en(chg, true); + } + 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_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) { + if (vbat_mv > chg->temp_littel_cool_voltage + 40 + && chg->temp_littel_cool_set_current) { + chg->is_power_changed = true; + } else if (vbat_mv < chg->temp_littel_cool_voltage - 40 + && !chg->temp_littel_cool_set_current) { + chg->is_power_changed = true; + } + } + ffc_exit(chg); + checkout_term_current(chg); + if (!chg->chg_ovp && chg->chg_done + && temp_region > BATT_TEMP_COLD + && temp_region < BATT_TEMP_HOT + && chg->vbatdet[temp_region] >= vbat_mv) { + chg->chg_done = false; + chg->recharge_pending = true; + chg->recharge_status = true; + + op_charging_en(chg, true); + pr_debug("temp_region=%d, recharge_pending\n", temp_region); + } + + if (!chg->chg_ovp && chg->battery_status == BATT_STATUS_GOOD + && !chg->time_out) { + op_check_battery_temp(chg); + } +#ifdef CONFIG_OP_DEBUG_CHG + chg->dump_count++; + if (chg->dump_count == 600) { + chg->dump_count = 0; + if ((get_prop_batt_current_now(chg) / 1000) > 0) { + op_dump_regs(chg); + aging_test_check_aicl(chg); + } } +#else + if (chg->is_aging_test) { + chg->dump_count++; + if (chg->dump_count == 600) { + chg->dump_count = 0; + if ((get_prop_batt_current_now(chg) / 1000) > 0) { + op_dump_regs(chg); + aging_test_check_aicl(chg); + } + } + } +#endif +out: + smblib_dbg(chg, PR_OP_DEBUG, "CAP=%d (Q:%d), VBAT=%d (Q:%d), IBAT=%d (Q:%d), BAT_TEMP=%d, CHG_TYPE=%d, VBUS=%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->usb_psy_desc.type, + vbus_val.intval); + /*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; + int rc = 0; - mutex_lock(&chg->lock); - smblib_usb_typec_change(chg); - mutex_unlock(&chg->lock); - return IRQ_HANDLED; + if (pm_pon && pm_pon->regmap) { + rc = regmap_read(pm_pon->regmap, addr, &temp); + if (rc >= 0) + *val = (u8)temp; + } + return rc; } -irqreturn_t smblib_handle_dc_plugin(int irq, void *data) +int op_read_backup_flag(struct smb_charger *chg) { - struct smb_irq_data *irq_data = data; - struct smb_charger *chg = irq_data->parent_data; + u8 flag = 0; + int rc = 0; - power_supply_changed(chg->dc_psy); - return IRQ_HANDLED; + rc = op_read(chg, SOC_DATA_REG_0, &flag); + if (rc) { + pr_err("failed to read PM addr[0x%x], rc=%d\n", + SOC_DATA_REG_0, rc); + return 0; + } + flag = flag & BIT(7); + return flag; } -irqreturn_t smblib_handle_high_duty_cycle(int irq, void *data) +int op_masked_write(struct smb_charger *chg, u16 addr, u8 mask, u8 val) { - struct smb_irq_data *irq_data = data; - struct smb_charger *chg = irq_data->parent_data; + int rc = 0; - chg->is_hdc = true; - /* - * Disable usb IRQs after the flag set and re-enable IRQs after - * the flag cleared in the delayed work queue, to avoid any IRQ - * storming during the delays - */ - if (chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq) - disable_irq_nosync(chg->irq_info[HIGH_DUTY_CYCLE_IRQ].irq); + if (pm_pon && pm_pon->regmap) { + mutex_lock(&chg->write_lock); + rc = regmap_update_bits(pm_pon->regmap, addr, mask, val); + mutex_unlock(&chg->write_lock); + } else { + pr_err("pm_pon is NULL\n"); + } + return rc; +} - schedule_delayed_work(&chg->clear_hdc_work, msecs_to_jiffies(60)); +void op_write_backup_flag(struct smb_charger *chg, bool bk_flag) +{ + int rc = 0; - return IRQ_HANDLED; + rc = op_masked_write(chg, SOC_DATA_REG_0, + BIT(7), bk_flag ? BIT(7):0); + if (rc) { + pr_err("failed to clean PM addr[0x%x], rc=%d\n", + SOC_DATA_REG_0, rc); + } } -static void smblib_bb_removal_work(struct work_struct *work) +static int load_data(struct smb_charger *chg) { - struct smb_charger *chg = container_of(work, struct smb_charger, - bb_removal_work.work); + u8 stored_soc = 0, flag = 0; + int rc = 0, shutdown_soc = 0; - vote(chg->usb_icl_votable, BOOST_BACK_VOTER, false, 0); - vote(chg->awake_votable, BOOST_BACK_VOTER, false, 0); + if (!chg) { + pr_err("chg is NULL !\n"); + return SOC_INVALID; + } + + flag = op_read_backup_flag(chg); + if (!flag) + return SOC_INVALID; + + rc = smblib_read(chg, 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; + } + + /* the fist time connect battery, the PM 0x88d bit7 is 0, */ + /* we do not need load this data. */ + if (flag) + shutdown_soc = (stored_soc >> 1); + /* get data from bit1~bit7 */ + else + shutdown_soc = SOC_INVALID; + + pr_info("stored_soc[0x%x], shutdown_soc[%d]\n", + stored_soc, shutdown_soc); + return shutdown_soc; } -#define BOOST_BACK_UNVOTE_DELAY_MS 750 -#define BOOST_BACK_STORM_COUNT 3 -#define WEAK_CHG_STORM_COUNT 8 -irqreturn_t smblib_handle_switcher_power_ok(int irq, void *data) +int load_soc(void) { - 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; + int soc = 0; - if (!(chg->wa_flags & BOOST_BACK_WA)) - return IRQ_HANDLED; + soc = load_data(g_chg); + if (soc == SOC_INVALID || soc < 0 || soc > 100) + return -EINVAL; + return soc; +} - rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat); - if (rc < 0) { - smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n", rc); - return IRQ_HANDLED; +static void clear_backup_soc(struct smb_charger *chg) +{ + int rc = 0; + u8 invalid_soc = SOC_INVALID; + + op_write_backup_flag(chg, false); + rc = smblib_masked_write(chg, SOC_DATA_REG_0, + BIT(7) | BIT(6) | BIT(5) | BIT(4) + | BIT(3) | BIT(2) | BIT(1), + (BIT(7) & invalid_soc) | (BIT(6) & invalid_soc) + | (BIT(5) & invalid_soc) | + (BIT(4) & invalid_soc) | (BIT(3) & invalid_soc) + | (BIT(2) & invalid_soc) | + (BIT(1) & invalid_soc)); + if (rc) + pr_err("failed to write addr[0x%x], rc=%d\n", + SOC_DATA_REG_0, rc); + if (rc) { + pr_err("failed to clean PM addr[0x%x], rc=%d\n", + SOC_DATA_REG_0, rc); } +} - /* skip suspending input if its already suspended by some other voter */ - usb_icl = get_effective_result(chg->usb_icl_votable); - if ((stat & USE_USBIN_BIT) && usb_icl >= 0 && usb_icl <= USBIN_25MA) - return IRQ_HANDLED; +void clean_backup_soc_ex(void) +{ + if (g_chg) + clear_backup_soc(g_chg); +} - if (stat & USE_DCIN_BIT) - return IRQ_HANDLED; +static void backup_soc(struct smb_charger *chg, int soc) +{ + int rc = 0; - 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)); + if (!chg || soc < 0 || soc > 100) { + pr_err("chg or soc invalid, store an invalid soc\n"); + if (chg) { + rc = smblib_masked_write(chg, SOC_DATA_REG_0, + BIT(7) | BIT(6) | BIT(5) + | BIT(4) | BIT(3) | BIT(2) | BIT(1), + BIT(7) | BIT(6) | BIT(5) + | BIT(4) | BIT(3) | BIT(2) | BIT(1)); + if (rc) + pr_err("failed to write addr[0x%x], rc=%d\n", + SOC_DATA_REG_0, rc); + op_write_backup_flag(chg, false); } + return; } - return IRQ_HANDLED; + pr_err("backup_soc[%d]\n", soc); + soc = soc*2; + rc = smblib_masked_write(chg, SOC_DATA_REG_0, + BIT(7) | BIT(6) | BIT(5)| + BIT(4) | BIT(3) | BIT(2) | BIT(1), + (BIT(7) & soc) | (BIT(6) & soc) | (BIT(5) & soc) | + (BIT(4) & soc) | (BIT(3) & soc) | (BIT(2) & soc) | + (BIT(1) & soc)); + if (rc) + pr_err("failed to write addr[0x%x], rc=%d\n", + SOC_DATA_REG_0, rc); + op_write_backup_flag(chg, true); } -irqreturn_t smblib_handle_wdog_bark(int irq, void *data) +void backup_soc_ex(int soc) { - struct smb_irq_data *irq_data = data; - struct smb_charger *chg = irq_data->parent_data; - int rc; + if (g_chg) + backup_soc(g_chg, soc); +} - smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name); +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 */ +}; - rc = smblib_write(chg, BARK_BITE_WDOG_PET_REG, BARK_BITE_WDOG_PET_BIT); - if (rc < 0) - smblib_err(chg, "Couldn't pet the dog rc=%d\n", rc); +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->step_chg_enabled || chg->sw_jeita_enabled) - power_supply_changed(chg->batt_psy); + if (chg->use_fake_protect_sts) + return chg->fake_protect_sts; - return IRQ_HANDLED; + if (!is_usb_present(chg)) + return 0; + + rc = smblib_get_prop_usb_voltage_now(chg, &vbus_val); + if (rc < 0) { + pr_err("failed to read usb_voltage rc=%d\n", rc); + vbus_val.intval = CHG_VOLTAGE_NORMAL; + } + + temp = get_prop_batt_temp(chg); + batt_present = get_prop_batt_present(chg); + temp_region = op_battery_temp_region_get(chg); + if (chg->chg_ovp && vbus_val.intval >= CHG_SOFT_OVP_MV - 100) + return PROTECT_CHG_OVP; + else if (!batt_present || BATT_REMOVE_TEMP > temp) + return PROTECT_BATT_MISSING; + else if (chg->battery_status == BATT_STATUS_BAD) + return PROTECT_BATT_OVP; + else if (true == chg->time_out) + return PROTECT_CHG_OVERTIME; + else if (temp_region == BATT_TEMP_HOT) + return PROTECT_BATT_TEMP_REGION__HOT; + else if (temp_region == BATT_TEMP_COLD) + return PROTECT_BATT_TEMP_REGION_COLD; + else if (temp_region == BATT_TEMP_LITTLE_COLD + && (chg->chg_done || chg->recharge_status)) + return PROTECT_BATT_TEMP_REGION_LITTLE_COLD; + else if (temp_region == BATT_TEMP_WARM + && (chg->chg_done || chg->recharge_status)) + return PROTECT_BATT_TEMP_REGION_WARM; + else + return 0; +} + +bool get_prop_fastchg_status(struct smb_charger *chg) +{ + int capacity = 0; + + if (chg->dash_present) + return true; + + if (chg->hvdcp_present) { + capacity = get_prop_batt_capacity(chg); + if (capacity >= 1 && capacity <= 85) + return true; + } + + return false; +} + +static struct notify_dash_event notify_unplug_event = { + .notify_event = update_dash_unplug_status, + .op_contrl = op_contrl, + .notify_dash_charger_present + = set_dash_charger_present, +}; + +void op_pm8998_regmap_register(struct qpnp_pon *pon) +{ + if (pm_pon) { + pm_pon = pon; + pr_err("multiple battery gauge called\n"); + } else { + pm_pon = pon; + } +} + +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, +}; /************** * Additional USB PSY getters/setters * that call interrupt functions @@ -5294,6 +8464,15 @@ static int smblib_create_votables(struct smb_charger *chg) return rc; } +/*infi@bsp, 2018/07/10 Add otg toggle vote optimize otg_switch set flow*/ + 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->dc_icl_votable = create_votable("DC_ICL", VOTE_MIN, smblib_dc_icl_vote_callback, chg); @@ -5408,6 +8587,9 @@ static void smblib_destroy_votables(struct smb_charger *chg) { if (chg->dc_suspend_votable) destroy_votable(chg->dc_suspend_votable); +/*infi@bsp, 2018/07/10 Add otg toggle vote optimize otg_switch set flow*/ + if (chg->otg_toggle_votable) + destroy_votable(chg->otg_toggle_votable); if (chg->usb_icl_votable) destroy_votable(chg->usb_icl_votable); if (chg->dc_icl_votable) @@ -5451,11 +8633,57 @@ int smblib_init(struct smb_charger *chg) mutex_init(&chg->lock); mutex_init(&chg->write_lock); mutex_init(&chg->otg_oc_lock); +/* david.liu@bsp, 20171023 Battery & Charging porting */ + mutex_init(&chg->sw_dash_lock); mutex_init(&chg->vconn_oc_lock); INIT_WORK(&chg->bms_update_work, bms_update_work); INIT_WORK(&chg->pl_update_work, pl_update_work); INIT_WORK(&chg->rdstd_cc2_detach_work, rdstd_cc2_detach_work); INIT_DELAYED_WORK(&chg->hvdcp_detect_work, smblib_hvdcp_detect_work); +/* david.liu@bsp, 20171023 Battery & Charging porting */ + 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->op_check_apsd_work, op_chek_apsd_done_work); + INIT_DELAYED_WORK(&chg->recovery_suspend_work, + op_recovery_usb_suspend_work); + INIT_DELAYED_WORK(&chg->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); + INIT_WORK(&chg->otg_switch_work, op_otg_switch); + INIT_DELAYED_WORK(&chg->dash_check_work, op_dash_check_work); + INIT_DELAYED_WORK(&chg->connecter_check_work, + op_connect_temp_check_work); + INIT_DELAYED_WORK(&chg->revertboost_recovery_work, + op_revert_boost_recovery_work); + schedule_delayed_work(&chg->revertboost_recovery_work, + msecs_to_jiffies(16000)); + schedule_delayed_work(&chg->heartbeat_work, + msecs_to_jiffies(HEARTBEAT_INTERVAL_MS)); + notify_dash_unplug_register(¬ify_unplug_event); + wakeup_source_init(&chg->chg_wake_lock, "chg_wake_lock"); + g_chg = chg; + + regsister_notify_usb_enumeration_status(&usb_enumeration); +#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; + + rc = msm_drm_register_client(&chg->msm_drm_notifier); + if (rc) + pr_err("Smb unable to register notifier: %d\n", rc); +#endif /*CONFIG_FB*/ INIT_DELAYED_WORK(&chg->clear_hdc_work, clear_hdc_work); INIT_WORK(&chg->otg_oc_work, smblib_otg_oc_work); INIT_WORK(&chg->vconn_oc_work, smblib_vconn_oc_work); @@ -5463,6 +8691,8 @@ int smblib_init(struct smb_charger *chg) INIT_DELAYED_WORK(&chg->icl_change_work, smblib_icl_change_work); INIT_DELAYED_WORK(&chg->pl_enable_work, smblib_pl_enable_work); INIT_WORK(&chg->legacy_detection_work, smblib_legacy_detection_work); +/* david.liu@bsp, 20171023 Battery & Charging porting */ + op_set_collapse_fet(chg, false); INIT_DELAYED_WORK(&chg->uusb_otg_work, smblib_uusb_otg_work); INIT_DELAYED_WORK(&chg->bb_removal_work, smblib_bb_removal_work); chg->fake_capacity = -EINVAL; @@ -5538,7 +8768,9 @@ int smblib_deinit(struct smb_charger *chg) cancel_work_sync(&chg->legacy_detection_work); cancel_delayed_work_sync(&chg->uusb_otg_work); cancel_delayed_work_sync(&chg->bb_removal_work); - power_supply_unreg_notifier(&chg->nb); +/* david.liu@bsp, 20170330 Fix system crash */ + if (chg->nb.notifier_call) + power_supply_unreg_notifier(&chg->nb); smblib_destroy_votables(chg); qcom_step_chg_deinit(); qcom_batt_deinit(); @@ -5552,5 +8784,7 @@ int smblib_deinit(struct smb_charger *chg) smblib_iio_deinit(chg); +/* david.liu@bsp, 20171023 Battery & Charging porting */ + notify_dash_unplug_unregister(¬ify_unplug_event); return 0; } diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h index 046e6218d4ea..580a4638190a 100644 --- a/drivers/power/supply/qcom/smb-lib.h +++ b/drivers/power/supply/qcom/smb-lib.h @@ -9,6 +9,9 @@ #include #include #include + +/* david.liu@bsp, 20171023 Battery & Charging porting */ +#include #include #include "storm-watch.h" #include "battery.h" @@ -19,10 +22,28 @@ enum print_reason { PR_MISC = BIT(2), PR_PARALLEL = BIT(3), PR_OTG = BIT(4), +/* david.liu@bsp, 20171023 Battery & Charging porting */ + PR_OP_DEBUG = BIT(5), }; +/* david.liu@bsp, 20171023 Battery & Charging porting */ +#define BATT_TYPE_FCC_VOTER "BATT_TYPE_FCC_VOTER" +#define PSY_ICL_VOTER "PSY_ICL_VOTER" +#define TEMP_REGION_MAX 9 +#define NON_STANDARD_CHARGER_CHECK_S 100 +#define TIME_1000MS 1000 +#define REDET_COUTNT 1 +#define APSD_CHECK_COUTNT 15 +#define DASH_CHECK_COUNT 40 +#define BOOST_BACK_COUNT 2 +#define TIME_200MS 200 +#define TIME_100MS 100 + +#define TIME_3S 3000 + #define DEFAULT_VOTER "DEFAULT_VOTER" #define USER_VOTER "USER_VOTER" +#define HW_DETECT_VOTER "HW_DETECT_VOTER" #define PD_VOTER "PD_VOTER" #define DCP_VOTER "DCP_VOTER" #define QC_VOTER "QC_VOTER" @@ -246,6 +267,7 @@ struct smb_charger { struct charger_param chg_param; int otg_delay_ms; int *weak_chg_icl_ua; + int ffc_count; /* locks */ struct mutex lock; @@ -253,7 +275,11 @@ struct smb_charger { struct mutex ps_change_lock; struct mutex otg_oc_lock; struct mutex vconn_oc_lock; - +/* david.liu@bsp, 20171023 Battery & Charging porting */ + struct mutex sw_dash_lock; +/*yangfb@bsp, 20180302,enable stm6620 sheepmode */ + struct pinctrl_state *pinctrl_state_default; + struct pinctrl *pinctrl; /* power supplies */ struct power_supply *batt_psy; struct power_supply *usb_psy; @@ -266,6 +292,12 @@ struct smb_charger { /* notifiers */ struct notifier_block nb; +/* david.liu@bsp, 20171023 Battery & Charging porting */ +#if defined(CONFIG_FB) + struct notifier_block fb_notif; +#elif defined(CONFIG_MSM_RDM_NOTIFY) + struct notifier_block msm_drm_notifier; +#endif /* parallel charging */ struct parallel_params pl; @@ -277,6 +309,8 @@ struct smb_charger { /* votables */ struct votable *dc_suspend_votable; +/*infi@bsp, 2018/07/10 Add otg toggle vote optimize otg_switch set flow*/ + struct votable *otg_toggle_votable; struct votable *fcc_votable; struct votable *fv_votable; struct votable *usb_icl_votable; @@ -301,6 +335,23 @@ struct smb_charger { struct work_struct rdstd_cc2_detach_work; struct delayed_work hvdcp_detect_work; struct delayed_work ps_change_timeout_work; +/* david.liu@bsp, 20171023 Battery & Charging porting */ + struct delayed_work rechk_sw_dsh_work; + struct delayed_work re_kick_work; + struct delayed_work recovery_suspend_work; + struct delayed_work check_switch_dash_work; + struct delayed_work non_standard_charger_check_work; + struct delayed_work heartbeat_work; + struct delayed_work re_det_work; + struct delayed_work op_re_set_work; + struct delayed_work op_check_apsd_work; + struct work_struct get_aicl_work; + struct delayed_work dash_check_work; + struct delayed_work revertboost_recovery_work; + struct delayed_work connecter_check_work; + struct delayed_work op_icl_set_work; + struct work_struct otg_switch_work; + struct wakeup_source chg_wake_lock; struct delayed_work clear_hdc_work; struct work_struct otg_oc_work; struct work_struct vconn_oc_work; @@ -312,6 +363,86 @@ struct smb_charger { struct delayed_work bb_removal_work; /* cached status */ +/* david.liu@bsp, 20171023 Battery & Charging porting */ + int BATT_TEMP_T0; + int BATT_TEMP_T1; + int BATT_TEMP_T2; + int BATT_TEMP_T3; + int BATT_TEMP_T4; + int BATT_TEMP_T5; + int BATT_TEMP_T6; + int 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; + 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_low_current; + int fake_chgvol; + int fake_temp; + int fake_protect_sts; + int non_stand_chg_current; + int non_stand_chg_count; + int dash_check_count; + int redet_count; + int reset_count; + int dump_count; + int ck_apsd_count; + int ck_dash_count; + int recovery_boost_count; + int op_icl_val; + int plug_irq; + int sw_iterm_ma; + int pre_cable_pluged; + int hw_detect; + bool otg_switch; + bool use_fake_chgvol; + bool use_fake_temp; + bool use_fake_protect_sts; + bool vbus_present; + bool probe_done; + 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_ovp; + bool is_power_changed; + bool recharge_pending; + bool recharge_status; + bool temp_littel_cool_set_current; + bool oem_lcd_is_on; + bool chg_enabled; + bool pd_disabled; + bool op_apsd_done; + bool re_trigr_dash_done; + bool boot_usb_present; + bool is_aging_test; + bool revert_boost_trigger; + bool check_batt_full_by_sw; + 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; int voltage_min_uv; int voltage_max_uv; int pd_active; @@ -331,6 +462,15 @@ struct smb_charger { bool otg_en; bool vconn_en; bool suspend_input_on_debug_batt; + /*yangfb@bsp, 20181023 icl set 1A if battery lower than 15%*/ + bool OTG_ICL_CTRL; + int OTG_LOW_BAT; + int OTG_LOW_BAT_ICL; + int OTG_NORMAL_BAT_ICL; + int connecter_temp; + int connecter_voltage; + int disconnect_vbus; + int vbus_ctrl; int otg_attempts; int vconn_attempts; int default_icl_ua; @@ -380,6 +520,14 @@ struct smb_charger { int die_health; }; +/* david.liu@bsp, 20171023 Battery & Charging porting */ +int smblib_set_prop_charge_parameter_set(struct smb_charger *chg); +extern void set_mcu_en_gpio_value(int value); +extern void 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); 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); @@ -455,6 +603,32 @@ int smblib_set_prop_batt_status(struct smb_charger *chg, const union power_supply_propval *val); int smblib_set_prop_system_temp_level(struct smb_charger *chg, const union power_supply_propval *val); +/* david.liu@bsp, 20171023 Battery & Charging porting */ +void op_bus_vote(int disable); +int get_prop_fast_adapter_update(struct smb_charger *chg); +void op_handle_usb_plugin(struct smb_charger *chg); +int op_rerun_apsd(struct smb_charger *chg); +irqreturn_t smblib_handle_aicl_done(int irq, void *data); +void op_charge_info_init(struct smb_charger *chg); +int update_dash_unplug_status(void); +int get_prop_batt_status(struct smb_charger *chg); +int get_prop_chg_protect_status(struct smb_charger *chg); +int op_set_prop_otg_switch(struct smb_charger *chg, + bool enalbe); +int check_allow_switch_dash(struct smb_charger *chg, + const union power_supply_propval *val); +int smblib_set_prop_chg_voltage(struct smb_charger *chg, + const union power_supply_propval *val); +int smblib_set_prop_batt_temp(struct smb_charger *chg, + const union power_supply_propval *val); +int smblib_set_prop_chg_protect_status(struct smb_charger *chg, + const union power_supply_propval *val); +bool op_get_fastchg_ing(struct smb_charger *chg); +bool get_prop_fastchg_status(struct smb_charger *chg); +int op_usb_icl_set(struct smb_charger *chg, int icl_ua); +int op_get_aicl_result(struct smb_charger *chg); +void op_disconnect_vbus(struct smb_charger *chg, bool enable); +int plugin_update(struct smb_charger *chg); int smblib_set_prop_input_current_limited(struct smb_charger *chg, const union power_supply_propval *val); @@ -551,6 +725,8 @@ int smblib_stat_sw_override_cfg(struct smb_charger *chg, bool override); void smblib_usb_typec_change(struct smb_charger *chg); int smblib_toggle_stat(struct smb_charger *chg, int reset); int smblib_force_ufp(struct smb_charger *chg); +int smblib_get_prop_batt_temp(struct smb_charger *chg, + union power_supply_propval *val); int smblib_init(struct smb_charger *chg); int smblib_deinit(struct smb_charger *chg); diff --git a/include/linux/power/oem_external_fg.h b/include/linux/power/oem_external_fg.h new file mode 100644 index 000000000000..d6163341b68b --- /dev/null +++ b/include/linux/power/oem_external_fg.h @@ -0,0 +1,138 @@ +#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_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); + /*2015/01/06 Modify for sync with KK charge standard */ + bool (*fast_chg_started)(void); + bool (*fast_switch_to_normal)(void); + int (*set_switch_to_noraml_false)(void); + int (*set_fast_chg_allow)(bool enable); + void (*clean_enhache)(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 */ +}; + +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 qpnp_pon *pon); + +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); +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 bool dash_adapter_update_is_tx_gpio(unsigned int gpio_num); +extern bool dash_adapter_update_is_rx_gpio(unsigned int gpio_num); +extern int is_hw_support_n76e(void); +/* @bsp 2018/09/05 FAT-4556 fix the audio heaset pop issue when shutdown*/ +extern bool audio_adapter_flag; + +void op_switch_normal_set(void); +#endif diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 5e95332448d5..911178903806 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -164,6 +164,27 @@ enum { enum power_supply_property { /* Properties of type `int' */ POWER_SUPPLY_PROP_STATUS = 0, +/* david.liu@bsp, 20171023 Battery & Charging porting */ + POWER_SUPPLY_PROP_SET_ALLOW_READ_EXTERN_FG_IIC, + POWER_SUPPLY_PROP_CC_TO_CV_POINT, + POWER_SUPPLY_PROP_CHG_PROTECT_STATUS, + POWER_SUPPLY_PROP_FASTCHG_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_CONNECT_DISABLE, + POWER_SUPPLY_PROP_CONNECTER_TEMP, + 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, @@ -405,6 +426,8 @@ enum power_supply_type { POWER_SUPPLY_TYPE_UFP, /* Type-C UFP */ POWER_SUPPLY_TYPE_DFP, /* Type-C DFP */ POWER_SUPPLY_TYPE_CHARGE_PUMP, /* Charge Pump */ +/* david.liu@bsp, 20171023 Battery & Charging porting */ + POWER_SUPPLY_TYPE_DASH, }; enum power_supply_usb_type { From a75bd41946f977d178a554ab22335c960e1b1cec Mon Sep 17 00:00:00 2001 From: Sam Mortimer Date: Fri, 5 Jan 2018 15:01:15 -0800 Subject: [PATCH 255/356] input: fingerprint: goodix: Add proximity_state sysfs support *) Implements sysfs proximity_state so that fp reader can be disabled by PocketMode app. *) Code fragments copied from fpc1020 driver where possible. Change-Id: If0e6fa3172e1546d989de8522b2bdd734a3840a6 --- .../drivers/input/fingerprint/goodix/gf_spi.c | 24 +++++++++++++++++++ .../drivers/input/fingerprint/goodix/gf_spi.h | 1 + 2 files changed, 25 insertions(+) diff --git a/drivers/oneplus/drivers/input/fingerprint/goodix/gf_spi.c b/drivers/oneplus/drivers/input/fingerprint/goodix/gf_spi.c index fcf8bc175649..3c9ea95f0456 100644 --- a/drivers/oneplus/drivers/input/fingerprint/goodix/gf_spi.c +++ b/drivers/oneplus/drivers/input/fingerprint/goodix/gf_spi.c @@ -652,8 +652,32 @@ static ssize_t screen_state_get(struct device *device, static DEVICE_ATTR(screen_state, 0400, screen_state_get, NULL); +static ssize_t proximity_state_set(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct gf_dev *gf_dev = dev_get_drvdata(dev); + int rc, val; + + rc = kstrtoint(buf, 10, &val); + if (rc) + return -EINVAL; + + gf_dev->proximity_state = !!val; + + if (gf_dev->proximity_state) { + gf_disable_irq(gf_dev); + } else { + gf_enable_irq(gf_dev); + } + + return count; +} + +static DEVICE_ATTR(proximity_state, S_IWUSR, NULL, proximity_state_set); + static struct attribute *gf_attributes[] = { &dev_attr_screen_state.attr, + &dev_attr_proximity_state.attr, NULL }; diff --git a/drivers/oneplus/drivers/input/fingerprint/goodix/gf_spi.h b/drivers/oneplus/drivers/input/fingerprint/goodix/gf_spi.h index 4b0d762a5f38..f5e25717818d 100644 --- a/drivers/oneplus/drivers/input/fingerprint/goodix/gf_spi.h +++ b/drivers/oneplus/drivers/input/fingerprint/goodix/gf_spi.h @@ -167,6 +167,7 @@ struct gf_dev { struct pinctrl_state *gpio_state_disable; signed enable_gpio; int screen_state; + int proximity_state; /* 0:far 1:near */ }; int gf_pinctrl_init(struct gf_dev* gf_dev); int gf_parse_dts(struct gf_dev* gf_dev); From cca6a2b0fa9805b181751e455e4abef5bdbac0ec Mon Sep 17 00:00:00 2001 From: dianlujitao Date: Fri, 6 Jul 2018 00:06:54 +0200 Subject: [PATCH 256/356] input: synaptics: s3320: Expose every possible gesture Change-Id: I967893f8fe2797cf67d34aa81040be835d030e82 --- .../touchscreen/synaptics_driver_s3320.c | 590 ++++++++---------- 1 file changed, 272 insertions(+), 318 deletions(-) diff --git a/drivers/input/touchscreen/synaptics_driver_s3320.c b/drivers/input/touchscreen/synaptics_driver_s3320.c index f927252a5fdd..9e4977bbf5d1 100644 --- a/drivers/input/touchscreen/synaptics_driver_s3320.c +++ b/drivers/input/touchscreen/synaptics_driver_s3320.c @@ -142,24 +142,7 @@ struct pm_qos_request pm_qos_req_tp; #define FINGER_UP 0x1f #define SINGLE_TAP 0x10 -#define UnkownGestrue 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 Sgestrue 14 // S -#define SingleTap 15 // single tap - -//ruanbanmao@BSP add for tp gesture 2015-05-06, begin +// Gesture bit mask #define BIT0 (0x1 << 0) #define BIT1 (0x1 << 1) #define BIT2 (0x1 << 2) @@ -168,24 +151,51 @@ struct pm_qos_request pm_qos_req_tp; #define BIT5 (0x1 << 5) #define BIT6 (0x1 << 6) #define BIT7 (0x1 << 7) +#define BIT8 (0x1 << 8) +#define BIT8 (0x1 << 8) +#define BIT9 (0x1 << 9) +#define BITA (0x1 << 10) +#define BITB (0x1 << 11) +#define BITC (0x1 << 12) +#define BITD (0x1 << 13) +#define BITE (0x1 << 14) +#define BITF (0x1 << 15) + +// Gesture flags +#define GESTURE_NONE BIT0 +#define GESTURE_DOUBLE_TAP BIT1 // double tap +#define GESTURE_DOWN_ARROW BIT2 // V +#define GESTURE_UP_ARROW BIT3 // ^ +#define GESTURE_RIGHT_ARROW BIT4 // > +#define GESTURE_LEFT_ARROW BIT5 // < +#define GESTURE_CIRCLE BIT6 // O +#define GESTURE_DOUBLE_SWIPE BIT7 // || +#define GESTURE_RIGHT_SWIPE BIT8 // -> +#define GESTURE_LEFT_SWIPE BIT9 // <- +#define GESTURE_DOWN_SWIPE BITA // |v +#define GESTURE_UP_SWIPE BITB // |^ +#define GESTURE_M BITC // M +#define GESTURE_W BITD // W +#define GESTURE_S BITE // S +#define GESTURE_SINGLE_TAP BITF // single tap + +// Gesture key codes +#define KEY_GESTURE_W 246 // W +#define KEY_GESTURE_M 247 // M +#define KEY_GESTURE_S 248 // S +#define KEY_DOUBLE_TAP KEY_WAKEUP // double tap to wake +#define KEY_GESTURE_CIRCLE 250 // draw circle to lunch camera +#define KEY_GESTURE_TWO_SWIPE 251 // swipe two finger vertically to play/pause +#define KEY_GESTURE_UP_ARROW 252 // draw up arrow to toggle flashlight +#define KEY_GESTURE_LEFT_ARROW 253 // draw left arrow for previous track +#define KEY_GESTURE_RIGHT_ARROW 254 // draw right arrow for next track +#define KEY_GESTURE_DOWN_ARROW 255 // draw down arrow to toggle flashlight +#define KEY_GESTURE_SWIPE_LEFT KEY_F5 +#define KEY_GESTURE_SWIPE_DOWN KEY_F6 +#define KEY_GESTURE_SWIPE_RIGHT KEY_F7 +#define KEY_GESTURE_SWIPE_UP KEY_F8 +#define KEY_GESTURE_SINGLE_TAP KEY_F9 -int LeftVee_gesture = 0; //">" -int RightVee_gesture = 0; //"<" -int DouSwip_gesture = 0; // "||" -int Circle_gesture = 0; // "O" -int UpVee_gesture = 0; //"V" -int DownVee_gesture = 0; //"^" -int DouTap_gesture = 0; //"double tap" - -int Left2RightSwip_gesture=0;//"(-->)" -int Right2LeftSwip_gesture=0;//"(<--)" -int Up2DownSwip_gesture =0;//"up to down |" -int Down2UpSwip_gesture =0;//"down to up |" - -int Wgestrue_gesture =0;//"(W)" -int Mgestrue_gesture =0;//"(M)" -int Sgestrue_gesture =0;//"(S)" -int Single_gesture = 0; //"(SingleTap)" int Enable_gesture =0; static int gesture_switch = 0; //ruanbanmao@BSP add for tp gesture 2015-05-06, end @@ -244,7 +254,6 @@ static struct synaptics_ts_data *ts_g = NULL; static struct workqueue_struct *synaptics_wq = NULL; static struct workqueue_struct *synaptics_report = NULL; static struct workqueue_struct *get_base_report = NULL; -static struct proc_dir_entry *prEntry_tp = NULL; #ifdef SUPPORT_GESTURE @@ -509,7 +518,7 @@ struct synaptics_ts_data { struct notifier_block msm_drm_notif; #endif /******gesture*******/ - int gesture_enable; + uint32_t gestures_enable; int in_gesture_mode; int glove_enable; int changer_connet; @@ -825,7 +834,7 @@ static int synaptics_enable_interrupt_for_gesture(struct synaptics_ts_data *ts, TPD_ERR("%s :Failed to write report buffer\n", __func__); return -1; } - gesture = UnkownGestrue; + gesture = GESTURE_NONE; return 0; } #endif @@ -1176,7 +1185,7 @@ static void synaptics_get_coordinate_point(struct synaptics_ts_data *ts) if (!memcmp(coordinate_buf_last, coordinate_buf, sizeof(coordinate_buf))) { TPD_ERR("%s reject the same gestrue[%d]\n", __func__, gesture); - gesture = UnkownGestrue; + gesture = GESTURE_NONE; } memcpy(coordinate_buf_last,coordinate_buf,sizeof(coordinate_buf)); /* strcpy(coordinate_buf_last, coordinate_buf, sizeof(coordinate_buf)); @@ -1346,7 +1355,7 @@ static int double_tap(struct synaptics_ts_data *ts) static void gesture_judge(struct synaptics_ts_data *ts) { - unsigned int keyCode = KEY_F4; + unsigned int keyCode = 0; int ret = 0, regswipe = 0; uint8_t gesture_buffer[10]; uint8_t gesture_sign = 0; @@ -1401,56 +1410,54 @@ static void gesture_judge(struct synaptics_ts_data *ts) gesture_sign = gesture_buffer[0]; if (ts->project_version == 0x03) { - if (DouTap_gesture) { - if (gesture_sign == SINGLE_TAP) { - is_double_tap = double_tap(ts); - if (is_double_tap == 1) { - gesture_sign = DTAP_DETECT; - } + if (gesture_sign == SINGLE_TAP) { + is_double_tap = double_tap(ts); + if (is_double_tap == 1) { + gesture_sign = DTAP_DETECT; } } } //detect the gesture mode switch (gesture_sign) { case DTAP_DETECT: - gesture = DouTap; + gesture = GESTURE_DOUBLE_TAP; break; case SWIPE_DETECT: if (version_is_s3508 == 2) { gesture = - (regswipe_s3706[24] == 0x41) ? Left2RightSwip : - (regswipe_s3706[24] == 0x42) ? Right2LeftSwip : - (regswipe_s3706[24] == 0x44) ? Up2DownSwip : - (regswipe_s3706[24] == 0x48) ? Down2UpSwip : - (regswipe_s3706[24] == 0x80) ? DouSwip : - UnkownGestrue; + (regswipe_s3706[24] == 0x41) ? GESTURE_RIGHT_SWIPE : + (regswipe_s3706[24] == 0x42) ? GESTURE_LEFT_SWIPE : + (regswipe_s3706[24] == 0x44) ? GESTURE_DOWN_SWIPE : + (regswipe_s3706[24] == 0x48) ? GESTURE_UP_SWIPE : + (regswipe_s3706[24] == 0x80) ? GESTURE_DOUBLE_SWIPE : + GESTURE_NONE; break; } else if (version_is_s3508 == 1) { - gesture = (regswipe == 0x41) ? Left2RightSwip : - (regswipe == 0x42) ? Right2LeftSwip : - (regswipe == 0x44) ? Up2DownSwip : - (regswipe == 0x48) ? Down2UpSwip : - (regswipe == 0x80) ? DouSwip : - UnkownGestrue; + gesture = (regswipe == 0x41) ? GESTURE_RIGHT_SWIPE : + (regswipe == 0x42) ? GESTURE_LEFT_SWIPE : + (regswipe == 0x44) ? GESTURE_DOWN_SWIPE : + (regswipe == 0x48) ? GESTURE_UP_SWIPE : + (regswipe == 0x80) ? GESTURE_DOUBLE_SWIPE : + GESTURE_NONE; break; }else{ - gesture = (regswipe == 0x41) ? Left2RightSwip : - (regswipe == 0x42) ? Right2LeftSwip : - (regswipe == 0x44) ? Up2DownSwip : - (regswipe == 0x48) ? Down2UpSwip : - (regswipe == 0x84) ? DouSwip : - UnkownGestrue; + gesture = (regswipe == 0x41) ? GESTURE_RIGHT_SWIPE : + (regswipe == 0x42) ? GESTURE_LEFT_SWIPE : + (regswipe == 0x44) ? GESTURE_DOWN_SWIPE : + (regswipe == 0x48) ? GESTURE_UP_SWIPE : + (regswipe == 0x84) ? GESTURE_DOUBLE_SWIPE : + GESTURE_NONE; break; } case CIRCLE_DETECT: - gesture = Circle; + gesture = GESTURE_CIRCLE; break; case VEE_DETECT: - gesture = (gesture_buffer[2] == 0x01) ? DownVee : - (gesture_buffer[2] == 0x02) ? UpVee : - (gesture_buffer[2] == 0x04) ? RightVee : - (gesture_buffer[2] == 0x08) ? LeftVee : - UnkownGestrue; + gesture = (gesture_buffer[2] == 0x01) ? GESTURE_UP_ARROW : + (gesture_buffer[2] == 0x02) ? GESTURE_DOWN_ARROW : + (gesture_buffer[2] == 0x04) ? GESTURE_LEFT_ARROW : + (gesture_buffer[2] == 0x08) ? GESTURE_RIGHT_ARROW : + GESTURE_NONE; break; case FINGER_DOWN: if (ts->project_version == 0x03) { @@ -1466,7 +1473,7 @@ static void gesture_judge(struct synaptics_ts_data *ts) not_getbase = 1; need_reset = 0; } - gesture = UnkownGestrue; + gesture = GESTURE_NONE; break; case FINGER_UP: if (ts->project_version == 0x03) { @@ -1480,50 +1487,80 @@ static void gesture_judge(struct synaptics_ts_data *ts) set_tp_info(ts, 0); gf_opticalfp_irq_handler(0); } - gesture = UnkownGestrue; + gesture = GESTURE_NONE; break; case SINGLE_TAP: if (ts->project_version == 0x03) { TPD_DEBUG("%s:SINGLE TAP\n", __func__); - gesture = SingleTap; + gesture = GESTURE_SINGLE_TAP; } break; case UNICODE_DETECT: - gesture = (gesture_buffer[2] == 0x77) ? Wgestrue : - (gesture_buffer[2] == 0x6d) ? Mgestrue : - (gesture_buffer[2] == 0x73) ? Sgestrue : - UnkownGestrue; + gesture = (gesture_buffer[2] == 0x77) ? GESTURE_W : + (gesture_buffer[2] == 0x6d) ? GESTURE_M : + (gesture_buffer[2] == 0x73) ? GESTURE_S : + GESTURE_NONE; break; default: - gesture = UnkownGestrue; + gesture = GESTURE_NONE; break; } - TPD_ERR("detect %s gesture\n", gesture == DouTap ? "(double tap)" : - gesture == UpVee ? "(V)" : - gesture == DownVee ? "(^)" : - gesture == LeftVee ? "(>)" : - gesture == RightVee ? "(<)" : - gesture == Circle ? "(O)" : - gesture == DouSwip ? "(||)" : - gesture == Left2RightSwip ? "(-->)" : - gesture == Right2LeftSwip ? "(<--)" : - gesture == Up2DownSwip ? "(up to down |)" : - gesture == Down2UpSwip ? "(down to up |)" : - gesture == Mgestrue ? "(M)" : - gesture == Sgestrue ? "(S)" : - gesture == Wgestrue ? "(W)" : - gesture == SingleTap ? "(single tap)" : "[unknown]"); - if ((gesture != SingleTap) && (gesture != DouTap)) + // Get key code based on registered gesture. + switch (gesture) { + case GESTURE_DOUBLE_TAP: + keyCode = KEY_DOUBLE_TAP; + break; + case GESTURE_UP_ARROW: + keyCode = KEY_GESTURE_UP_ARROW; + break; + case GESTURE_DOWN_ARROW: + keyCode = KEY_GESTURE_DOWN_ARROW; + break; + case GESTURE_LEFT_ARROW: + keyCode = KEY_GESTURE_LEFT_ARROW; + break; + case GESTURE_RIGHT_ARROW: + keyCode = KEY_GESTURE_RIGHT_ARROW; + break; + case GESTURE_CIRCLE: + keyCode = KEY_GESTURE_CIRCLE; + break; + case GESTURE_DOUBLE_SWIPE: + keyCode = KEY_GESTURE_TWO_SWIPE; + break; + case GESTURE_LEFT_SWIPE: + keyCode = KEY_GESTURE_SWIPE_LEFT; + break; + case GESTURE_RIGHT_SWIPE: + keyCode = KEY_GESTURE_SWIPE_RIGHT; + break; + case GESTURE_UP_SWIPE: + keyCode = KEY_GESTURE_SWIPE_UP; + break; + case GESTURE_DOWN_SWIPE: + keyCode = KEY_GESTURE_SWIPE_DOWN; + break; + case GESTURE_W: + keyCode = KEY_GESTURE_W; + break; + case GESTURE_M: + keyCode = KEY_GESTURE_M; + break; + case GESTURE_S: + keyCode = KEY_GESTURE_S; + break; + case GESTURE_SINGLE_TAP: + keyCode = KEY_GESTURE_SINGLE_TAP; + break; + default: + break; + } + + if ((gesture != GESTURE_SINGLE_TAP) && (gesture != GESTURE_DOUBLE_TAP)) synaptics_get_coordinate_point(ts); - TPD_DEBUG("gesture suport LeftVee:%d RightVee:%d DouSwip:%d Circle:%d UpVee:%d DouTap:%d\n",\ - LeftVee_gesture,RightVee_gesture,DouSwip_gesture,Circle_gesture,UpVee_gesture,DouTap_gesture); - if((gesture == DouTap && DouTap_gesture)||(gesture == RightVee && RightVee_gesture)\ - ||(gesture == LeftVee && LeftVee_gesture)||(gesture == UpVee && UpVee_gesture)\ - ||(gesture == Circle && Circle_gesture)||(gesture == DouSwip && DouSwip_gesture)\ - ||(gesture == Sgestrue && Sgestrue_gesture)||(gesture == Wgestrue && Wgestrue_gesture)\ - ||(gesture == Mgestrue && Mgestrue_gesture)||(gesture == SingleTap && Single_gesture)) { + if((gesture & ts->gestures_enable) != 0){ input_report_key(ts->input_dev, keyCode, 1); input_sync(ts->input_dev); input_report_key(ts->input_dev, keyCode, 0); @@ -1871,7 +1908,7 @@ static void synaptics_ts_work_func(struct work_struct *work) if( ret < 0 ) { TPDTM_DMESG("Synaptic:ret = %d\n", ret); synaptics_hard_reset(ts); - if (ts->is_suspended == 1 && ts->gesture_enable == 0) { + if (ts->is_suspended == 1 && ts->gestures_enable == 0) { touch_disable(ts); goto EXIT; } @@ -1886,7 +1923,7 @@ static void synaptics_ts_work_func(struct work_struct *work) if (status_check < 0) { TPD_ERR("synaptics_init_panel failed\n"); } - if ((ts->is_suspended == 1) && (ts->gesture_enable == 1)){ + if ((ts->is_suspended == 1) && (ts->gestures_enable != 0)){ synaptics_enable_interrupt_for_gesture(ts, 1); if (ts->project_version == 0x03) { mutex_lock(&ts->mutex); @@ -1989,68 +2026,13 @@ static ssize_t i2c_device_test_read_func(struct file *file, char __user *user_bu struct synaptics_ts_data *ts = ts_g; if(!ts_g) return ret; - TPD_DEBUG("gesture enable is: %d\n", ts->gesture_enable); + TPD_DEBUG("gesture enable is: %d\n", ts->gestures_enable); ret = sprintf(page, "%d\n", ts->i2c_device_test); ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); return ret; } #ifdef SUPPORT_GESTURE -static ssize_t tp_gesture_read_func(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) -{ - int ret = 0; - char page[PAGESIZE]; - struct synaptics_ts_data *ts = ts_g; - if(!ts) - return ret; - 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 tp_gesture_write_func(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) -{ - char buf[10]; - struct synaptics_ts_data *ts = ts_g; - if(!ts) - return count; - if( count > 3 || ts->is_suspended) - return count; - if( copy_from_user(buf, buffer, count) ){ - TPD_ERR(KERN_INFO "%s: read proc input error.\n", __func__); - return count; - } - //ruanbanmao@BSP add for tp gesture 2015-05-06, begin - TPD_ERR("%s write argc1[0x%x],argc2[0x%x]\n",__func__,buf[0],buf[1]); - - UpVee_gesture = (buf[0] & BIT0)?1:0; //"V" - DouSwip_gesture = (buf[0] & BIT1)?1:0;//"||" - LeftVee_gesture = (buf[0] & BIT3)?1:0; //">" - RightVee_gesture = (buf[0] & BIT4)?1:0;//"<" - Circle_gesture = (buf[0] & BIT6)?1:0; //"O" - DouTap_gesture = (buf[0] & BIT7)?1:0; //double tap - - Sgestrue_gesture = (buf[1] & BIT0)?1:0;//"S" - Mgestrue_gesture = (buf[1] & BIT1)?1:0; //"M" - Wgestrue_gesture = (buf[1] & BIT2)?1:0; //"W" - Single_gesture = (buf[1] & BIT3)?1:0; //"Single_gesture" - //enable gesture - Enable_gesture = (buf[1] & BIT7)?1:0; - - if (DouTap_gesture || Circle_gesture || UpVee_gesture - || LeftVee_gesture || RightVee_gesture || DouSwip_gesture - || Sgestrue_gesture || Mgestrue_gesture || Wgestrue_gesture - || Enable_gesture || Single_gesture) { - ts->gesture_enable = 1; - } - else - { - ts->gesture_enable = 0; - } - //ruanbanmao@BSP add for tp gesture 2015-05-06, end - return count; -} static ssize_t coordinate_proc_read_func(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { int ret = 0; @@ -2096,9 +2078,9 @@ static ssize_t gesture_switch_write_func(struct file *file, const char __user *p mutex_lock(&ts->mutex); ret = sscanf(buf,"%d",&write_flag); gesture_switch = write_flag; - TPD_ERR("gesture_switch:%d,suspend:%d,gesture:%d\n",gesture_switch,ts->is_suspended,ts->gesture_enable); + TPD_ERR("gesture_switch:%d,suspend:%d,gesture:%d\n",gesture_switch,ts->is_suspended,ts->gestures_enable); if (1 == gesture_switch){ - if ((ts->is_suspended == 1) && (ts->gesture_enable == 1)){ + if ((ts->is_suspended == 1) && (ts->gestures_enable != 0)){ i2c_smbus_write_byte_data(ts->client, 0xff, 0x0); synaptics_mode_change(0x80); //synaptics_enable_interrupt_for_gesture(ts, 1); @@ -2106,7 +2088,7 @@ static ssize_t gesture_switch_write_func(struct file *file, const char __user *p touch_enable(ts); } }else if(2 == gesture_switch){ - if ((ts->is_suspended == 1) && (ts->gesture_enable == 1)){ + if ((ts->is_suspended == 1) && (ts->gestures_enable != 0)){ i2c_smbus_write_byte_data(ts->client, 0xff, 0x0); synaptics_mode_change(0x81); touch_disable(ts); @@ -2122,13 +2104,6 @@ static ssize_t gesture_switch_write_func(struct file *file, const char __user *p // chenggang.li@BSP.TP modified for oem 2014-08-08 create node /******************************start****************************/ -static const struct file_operations tp_gesture_proc_fops = { - .write = tp_gesture_write_func, - .read = tp_gesture_read_func, - .open = simple_open, - .owner = THIS_MODULE, -}; - static const struct file_operations gesture_switch_proc_fops = { .write = gesture_switch_write_func, .read = gesture_switch_read_func, @@ -2142,6 +2117,52 @@ static const struct file_operations coordinate_proc_fops = { .owner = THIS_MODULE, }; #endif + +#define GESTURE_ATTR(name, flag)\ + static ssize_t name##_enable_read_func(struct file *file, char __user *user_buf, size_t count, loff_t *ppos)\ + {\ + int ret = 0;\ + char page[PAGESIZE];\ + ret = sprintf(page, "%d\n", (ts_g->gestures_enable & flag) != 0);\ + ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page));\ + return ret;\ + }\ + static ssize_t name##_enable_write_func(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos)\ + {\ + int ret, write_flag = 0;\ + char page[PAGESIZE] = {0};\ + ret = copy_from_user(page, user_buf, count);\ + ret = sscanf(page, "%d", &write_flag);\ + if (write_flag) {\ + ts_g->gestures_enable |= flag;\ + } else {\ + ts_g->gestures_enable &= ~flag;\ + }\ + return count;\ + }\ + static const struct file_operations name##_enable_proc_fops = {\ + .write = name##_enable_write_func,\ + .read = name##_enable_read_func,\ + .open = simple_open,\ + .owner = THIS_MODULE,\ + }; + +GESTURE_ATTR(single_tap, GESTURE_SINGLE_TAP); +GESTURE_ATTR(double_tap, GESTURE_DOUBLE_TAP); +GESTURE_ATTR(up_arrow, GESTURE_UP_ARROW); +GESTURE_ATTR(down_arrow, GESTURE_DOWN_ARROW); +GESTURE_ATTR(left_arrow, GESTURE_LEFT_ARROW); +GESTURE_ATTR(right_arrow, GESTURE_RIGHT_ARROW); +GESTURE_ATTR(double_swipe, GESTURE_DOUBLE_SWIPE); +GESTURE_ATTR(up_swipe, GESTURE_UP_SWIPE); +GESTURE_ATTR(down_swipe, GESTURE_DOWN_SWIPE); +GESTURE_ATTR(left_swipe, GESTURE_RIGHT_SWIPE); +GESTURE_ATTR(right_swipe, GESTURE_LEFT_SWIPE); +GESTURE_ATTR(letter_o, GESTURE_CIRCLE); +GESTURE_ATTR(letter_w, GESTURE_W); +GESTURE_ATTR(letter_m, GESTURE_M); +GESTURE_ATTR(letter_s, GESTURE_S); + static int page ,address,block; static ssize_t synap_read_address(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -3553,7 +3574,22 @@ static int synaptics_input_init(struct synaptics_ts_data *ts) set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit); set_bit(BTN_TOOL_FINGER, ts->input_dev->keybit); #ifdef SUPPORT_GESTURE - set_bit(KEY_F4 , ts->input_dev->keybit);//doulbe-tap resume + set_bit(KEY_F4, ts->input_dev->keybit); + set_bit(KEY_GESTURE_W, ts->input_dev->keybit); + set_bit(KEY_GESTURE_M, ts->input_dev->keybit); + set_bit(KEY_GESTURE_S, ts->input_dev->keybit); + set_bit(KEY_DOUBLE_TAP, ts->input_dev->keybit); + set_bit(KEY_GESTURE_CIRCLE, ts->input_dev->keybit); + set_bit(KEY_GESTURE_TWO_SWIPE, ts->input_dev->keybit); + set_bit(KEY_GESTURE_UP_ARROW, ts->input_dev->keybit); + set_bit(KEY_GESTURE_LEFT_ARROW, ts->input_dev->keybit); + set_bit(KEY_GESTURE_RIGHT_ARROW, ts->input_dev->keybit); + set_bit(KEY_GESTURE_DOWN_ARROW, ts->input_dev->keybit); + set_bit(KEY_GESTURE_SWIPE_LEFT, ts->input_dev->keybit); + set_bit(KEY_GESTURE_SWIPE_DOWN, ts->input_dev->keybit); + set_bit(KEY_GESTURE_SWIPE_RIGHT, ts->input_dev->keybit); + set_bit(KEY_GESTURE_SWIPE_UP, ts->input_dev->keybit); + set_bit(KEY_GESTURE_SINGLE_TAP, ts->input_dev->keybit); set_bit(KEY_APPSELECT, ts->input_dev->keybit); set_bit(KEY_BACK, ts->input_dev->keybit); #endif @@ -4158,7 +4194,7 @@ static ssize_t synaptics_main_reg_read_func( return ret; } -static const struct file_operations tp_main_reg = { +static const struct file_operations tp_main_reg_proc_fops = { .read = synaptics_main_reg_read_func, .open = simple_open, .owner = THIS_MODULE, @@ -4233,7 +4269,7 @@ static ssize_t tp_reset_write_func (struct file *file, const char *buffer, size_ } //chenggang.li@bsp add for 14045 -static const struct file_operations base_register_address= { +static const struct file_operations radd_proc_fops = { .write = synap_write_address, .read = synap_read_address, .open = simple_open, @@ -4242,14 +4278,14 @@ static const struct file_operations base_register_address= { //wangwenxue@BSP add for change baseline_test to "proc\touchpanel\baseline_test" begin -static const struct file_operations i2c_device_test_fops = { +static const struct file_operations i2c_device_test_proc_fops = { .read = i2c_device_test_read_func, .open = simple_open, .owner = THIS_MODULE, }; //wangwenxue@BSP add for change baseline_test to "proc\touchpanel\baseline_test" begin -static const struct file_operations tp_baseline_test_proc_fops = { +static const struct file_operations baseline_test_proc_fops = { .read = tp_baseline_test_read_func, .open = simple_open, .owner = THIS_MODULE, @@ -4334,7 +4370,7 @@ static ssize_t changer_write_func(struct file *file, const char __user *buffer, TPDTM_DMESG("%s:ts->changer_connet = %d\n",__func__,ts->changer_connet); return count; } -static const struct file_operations changer_ops = { +static const struct file_operations changer_connet_proc_fops = { .write = changer_write_func, .read = changer_read_func, .open = simple_open, @@ -4406,7 +4442,7 @@ static int tp_baseline_get(struct synaptics_ts_data *ts, bool flag) memset(delta_baseline,0,sizeof(delta_baseline)); mutex_lock(&ts->mutex); - if (ts->gesture_enable) { + if (ts->gestures_enable) { synaptics_enable_interrupt_for_gesture(ts,false); synaptics_mode_change(0x00); //change to active later getbase data @@ -4455,7 +4491,7 @@ static int tp_baseline_get(struct synaptics_ts_data *ts, bool flag) } mutex_unlock(&ts->mutex); atomic_set(&ts->is_stop, 0); - if (ts->gesture_enable) + if (ts->gestures_enable) set_doze_time(1); touch_enable(ts); #ifdef ENABLE_TPEDGE_LIMIT @@ -4575,14 +4611,14 @@ static ssize_t touch_press_status_write(struct file *file, const char __user *bu tp_baseline_get(ts,false); } else if(ret == 1) { - if (0 == ts->gesture_enable) + if (0 == ts->gestures_enable) queue_delayed_work(get_base_report, &ts->base_work,msecs_to_jiffies(120)); else queue_delayed_work(get_base_report, &ts->base_work,msecs_to_jiffies(1)); } return count; } -static const struct file_operations touch_press_status = { +static const struct file_operations touch_press_proc_fops = { .write = touch_press_status_write, .read = touch_press_status_read, .open = simple_open, @@ -4662,7 +4698,7 @@ static ssize_t limit_enable_write(struct file *file, const char __user *buffer, return count; } -static const struct file_operations proc_limit_enable = +static const struct file_operations tpedge_limit_enable_proc_fops = { .read = limit_enable_read, .write = limit_enable_write, @@ -4764,129 +4800,82 @@ static const struct file_operations key_disable_proc_fops = { .owner = THIS_MODULE, }; #endif + +#define CREATE_PROC_NODE(PARENT, NAME, MODE)\ + node = proc_create(#NAME, MODE, PARENT, &NAME##_proc_fops);\ + if (node == NULL) {\ + ret = -ENOMEM;\ + TPD_ERR("Couldn't create " #NAME " in " #PARENT "\n");\ + } + +#define CREATE_GESTURE_NODE(NAME)\ + CREATE_PROC_NODE(touchpanel, NAME##_enable, 0666) + static int init_synaptics_proc(void) { int ret = 0; - struct proc_dir_entry *prEntry_tmp = NULL; - prEntry_tp = proc_mkdir("touchpanel", NULL); - if( prEntry_tp == NULL ){ + struct proc_dir_entry *node = NULL; + struct proc_dir_entry *touchpanel = NULL; + + touchpanel = proc_mkdir("touchpanel", NULL); + if (touchpanel == NULL) { ret = -ENOMEM; TPD_ERR("Couldn't create touchpanel\n"); } + CREATE_PROC_NODE(touchpanel, coordinate, 0444); + #ifdef SUPPORT_GESTURE - prEntry_tmp = proc_create( "gesture_enable", 0666, prEntry_tp, &tp_gesture_proc_fops); - if(prEntry_tmp == NULL){ - ret = -ENOMEM; - TPD_ERR("Couldn't create gesture_enable\n"); - } - prEntry_tmp = proc_create( "gesture_switch", 0666, prEntry_tp, &gesture_switch_proc_fops); - if(prEntry_tmp == NULL){ - ret = -ENOMEM; - TPD_ERR("Couldn't create gesture_switch\n"); - } - prEntry_tmp = proc_create("coordinate", 0444, prEntry_tp, &coordinate_proc_fops); - if(prEntry_tmp == NULL){ - ret = -ENOMEM; - TPD_ERR("Couldn't create coordinate\n"); - } + CREATE_GESTURE_NODE(single_tap); + CREATE_GESTURE_NODE(double_tap); + CREATE_GESTURE_NODE(up_arrow); + CREATE_GESTURE_NODE(down_arrow); + CREATE_GESTURE_NODE(left_arrow); + CREATE_GESTURE_NODE(right_arrow); + CREATE_GESTURE_NODE(double_swipe); + CREATE_GESTURE_NODE(up_swipe); + CREATE_GESTURE_NODE(down_swipe); + CREATE_GESTURE_NODE(left_swipe); + CREATE_GESTURE_NODE(right_swipe); + CREATE_GESTURE_NODE(letter_o); + CREATE_GESTURE_NODE(letter_w); + CREATE_GESTURE_NODE(letter_m); + CREATE_GESTURE_NODE(letter_s); #endif #ifdef SUPPORT_GLOVES_MODE - prEntry_tmp = proc_create( "glove_mode_enable", 0666, prEntry_tp,&glove_mode_enable_proc_fops); - if(prEntry_tmp == NULL) { - ret = -ENOMEM; - TPD_ERR("Couldn't create glove_mode_enable\n"); - } + CREATE_PROC_NODE(touchpanel, glove_mode_enable, 0666); #endif #ifdef SUPPORT_TP_SLEEP_MODE - prEntry_tmp = proc_create("sleep_mode_enable", 0666, prEntry_tp, &sleep_mode_enable_proc_fops); - if( prEntry_tmp == NULL ){ - ret = -ENOMEM; - TPD_ERR("Couldn't create sleep_mode_enable\n"); - } + CREATE_PROC_NODE(touchpanel, sleep_mode_enable, 0666); #endif #ifdef RESET_ONESECOND - prEntry_tmp = proc_create( "tp_reset", 0666, prEntry_tp, &tp_reset_proc_fops); - if( prEntry_tmp == NULL ){ - ret = -ENOMEM; - TPD_ERR("Couldn't create tp_reset\n"); - } + CREATE_PROC_NODE(touchpanel, tp_reset, 0666); #endif + #ifdef ENABLE_TPEDGE_LIMIT - prEntry_tmp = proc_create("tpedge_limit_enable", 0666, prEntry_tp, &proc_limit_enable); - if( prEntry_tmp == NULL ){ - ret = -ENOMEM; - TPD_ERR("Couldn't create tp_limit_enable\n"); - } + CREATE_PROC_NODE(touchpanel, tpedge_limit_enable, 0666); #endif - //wangwenxue@BSP add for change baseline_test to "proc\touchpanel\baseline_test" begin - prEntry_tmp = proc_create( "baseline_test", 0666, prEntry_tp, &tp_baseline_test_proc_fops); - if(prEntry_tmp == NULL){ - ret = -ENOMEM; - TPD_ERR("Couldn't create baseline_test\n"); - } - //wangwenxue@BSP add for change baseline_test to "proc\touchpanel\baseline_test" end - //wangwenxue@BSP add for change baseline_test to "proc\touchpanel\i2c_device_test" begin - prEntry_tmp = proc_create( "i2c_device_test", 0666, prEntry_tp, &i2c_device_test_fops); - if(prEntry_tmp == NULL){ - ret = -ENOMEM; - TPD_ERR("Couldn't create i2c_device_test\n"); - } - - prEntry_tmp = proc_create( "radd", 0777, prEntry_tp, &base_register_address); - if(prEntry_tmp == NULL){ - ret = -ENOMEM; - TPD_ERR("Couldn't create radd\n"); - } - prEntry_tmp = proc_create("vendor_id", 0444, prEntry_tp, &vendor_id_proc_fops); - if(prEntry_tmp == NULL){ - ret = -ENOMEM; - TPD_ERR("Couldn't create vendor_id\n"); - } - prEntry_tmp = proc_create("changer_connet", 0666, prEntry_tp, &changer_ops); - if(prEntry_tmp == NULL){ - ret = -ENOMEM; - TPD_ERR("Couldn't create changer_connet\n"); - } + CREATE_PROC_NODE(touchpanel, baseline_test, 0666); + CREATE_PROC_NODE(touchpanel, i2c_device_test, 0666); + CREATE_PROC_NODE(touchpanel, radd, 0777); + CREATE_PROC_NODE(touchpanel, vendor_id, 0444); + CREATE_PROC_NODE(touchpanel, changer_connet, 0666); + CREATE_PROC_NODE(touchpanel, touch_press, 0666); - prEntry_tmp = proc_create("touch_press", 0666, prEntry_tp, &touch_press_status); - if(prEntry_tmp == NULL){ - ret = -ENOMEM; - TPD_ERR("Couldn't create touch_press\n"); - } #ifdef SUPPORT_TP_TOUCHKEY - prEntry_tmp = proc_create("key_switch", 0666, prEntry_tp, &key_switch_proc_fops); - if(prEntry_tmp == NULL){ - ret = -ENOMEM; - TPD_ERR("Couldn't create key_switch\n"); - } - - prEntry_tmp = proc_create("key_disable", 0666, prEntry_tp, &key_disable_proc_fops); - if(prEntry_tmp == NULL){ - ret = -ENOMEM; - TPD_ERR("Couldn't create key_disable\n"); - } + CREATE_PROC_NODE(touchpanel, key_switch, 0666); + CREATE_PROC_NODE(touchpanel, key_disable, 0666); #endif /*morgan.gu add for logkit to dump main registor*/ - prEntry_tmp = proc_create("tp_main_reg", 0444, - prEntry_tp, &tp_main_reg); - if (prEntry_tmp == NULL) { - ret = -ENOMEM; - TPD_ERR("Couldn't create tp_main_reg\n"); - } + CREATE_PROC_NODE(touchpanel, tp_main_reg, 0444); /*morgan.gu add for logkit to open more log*/ - prEntry_tmp = proc_create("tp_debug_log", 0664, - prEntry_tp, &tp_debug_log_proc_fops); - if (prEntry_tmp == NULL) { - ret = -ENOMEM; - TPD_ERR("Couldn't create tp_debug_log_proc_fops\n"); - } + CREATE_PROC_NODE(touchpanel, tp_debug_log, 0644); return ret; } @@ -6159,7 +6148,7 @@ static int synaptics_ts_suspend(struct device *dev) #endif #ifdef SUPPORT_GESTURE - if( ts->gesture_enable ){ + if( ts->gestures_enable ){ atomic_set(&ts->is_stop,0); if (mutex_trylock(&ts->mutex)){ touch_enable(ts); @@ -6199,7 +6188,7 @@ static void speedup_synaptics_resume(struct work_struct *work) /*#ifdef SUPPORT_SLEEP_POWEROFF*/ TPD_DEBUG("%s enter!\n", __func__); if (ts->support_hw_poweroff) { - if (ts->gesture_enable == 0) { + if (ts->gestures_enable == 0) { ret = tpd_power(ts, 1); if (ret < 0) TPD_ERR("%s power on err\n", __func__); @@ -6254,7 +6243,7 @@ static int synaptics_i2c_suspend(struct device *dev) struct synaptics_ts_data *ts = dev_get_drvdata(dev); TPD_DEBUG("%s: is called\n", __func__); - if (ts->gesture_enable == 1){ + if (ts->gestures_enable != 0){ /*enable gpio wake system through intterrupt*/ enable_irq_wake(ts->irq); } @@ -6263,7 +6252,7 @@ static int synaptics_i2c_suspend(struct device *dev) TPD_ERR("FW is updating while suspending"); return -1; } - if(ts->support_hw_poweroff && (ts->gesture_enable == 0)){ + if(ts->support_hw_poweroff && (ts->gestures_enable == 0)){ ret = tpd_power(ts,0); if (ret < 0) TPD_ERR("%s power off err\n",__func__); @@ -6281,7 +6270,7 @@ static int synaptics_i2c_resume(struct device *dev) TPD_DEBUG("%s is called\n", __func__); queue_delayed_work(synaptics_wq,&ts->speed_up_work, msecs_to_jiffies(1)); - if (ts->gesture_enable == 1){ + if (ts->gestures_enable != 0){ /*disable gpio wake system through intterrupt*/ disable_irq_wake(ts->irq); } @@ -6310,7 +6299,6 @@ static int fb_notifier_callback(struct notifier_block *self, unsigned long event { struct fb_event *evdata = data; int *blank; - static int gesture_flag; struct synaptics_ts_data *ts = container_of(self, struct synaptics_ts_data, fb_notif); @@ -6323,16 +6311,6 @@ static int fb_notifier_callback(struct notifier_block *self, unsigned long event if ((*blank == FB_BLANK_UNBLANK) && (event == FB_EARLY_EVENT_BLANK)) { - if (gesture_flag == 1) { - ts->gesture_enable = 0; - DouTap_gesture = 0; - synaptics_enable_interrupt_for_gesture(ts, 0); - set_doze_time(1); - gesture_flag = 0; - } else if (gesture_flag == 2) { - DouTap_gesture = 0; - gesture_flag = 0; - } if (ts->is_suspended == 1) { TPD_DEBUG("%s going TP resume start\n", __func__); @@ -6342,36 +6320,12 @@ static int fb_notifier_callback(struct notifier_block *self, unsigned long event //atomic_set(&ts->is_stop,0); TPD_DEBUG("%s going TP resume end\n", __func__); } - } else if (*blank == FB_BLANK_NORMAL) { - if (ts->gesture_enable == 0) { - DouTap_gesture = 1; - ts->gesture_enable = 1; - i2c_smbus_write_byte_data(ts->client, 0xff, 0x0); - synaptics_mode_change(0x80); - synaptics_ts_suspend(&ts->client->dev); - gesture_flag = 1; - } else if ((ts->gesture_enable == 1) && (DouTap_gesture == 0)) { - DouTap_gesture = 1; - gesture_flag = 2; - } }else if( *blank == FB_BLANK_POWERDOWN && (event == FB_EARLY_EVENT_BLANK )){ - if (gesture_flag == 1) { - ts->gesture_enable = 0; - DouTap_gesture = 0; - synaptics_enable_interrupt_for_gesture(ts, 0); - set_doze_time(1); - ts->is_suspended = 0; - gesture_flag = 0; - } else if (gesture_flag == 2) { - DouTap_gesture = 0; - ts->is_suspended = 0; - gesture_flag = 0; - } if (ts->is_suspended == 0){ TPD_DEBUG("%s : going TP suspend start\n", __func__); ts->is_suspended = 1; atomic_set(&ts->is_stop,1); - if (!(ts->gesture_enable)) + if (ts->gestures_enable == 0) touch_disable(ts); synaptics_ts_suspend(&ts->client->dev); TPD_DEBUG("%s : going TP suspend end\n", __func__); @@ -6418,7 +6372,7 @@ static int msm_drm_notifier_callback( atomic_set(&ts->is_stop, 1); cancel_delayed_work_sync(&ts->base_work); flush_workqueue(get_base_report); - if (!(ts->gesture_enable)) + if (ts->gestures_enable == 0) touch_disable(ts); synaptics_ts_suspend(&ts->client->dev); TPD_DEBUG("%s:TP suspend end\n", __func__); From 262848c9459b6bf2bf53a0d2681cd9cbf1825627 Mon Sep 17 00:00:00 2001 From: Ganesh Kumar Date: Mon, 14 Oct 2019 11:43:26 +0530 Subject: [PATCH 257/356] Tune sRGB/P3 parameters Change-Id: Ice624984d753a338fa5b7963ba666f74e0f09412 (cherry picked from commit 93f6a91981887ae3651b9b6267da4ce42d1d3f98) --- arch/arm64/boot/dts/qcom/dsi-panel-samsung_s6e3fc2x01.dtsi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-samsung_s6e3fc2x01.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-samsung_s6e3fc2x01.dtsi index e950ed3c4984..09606373fd3f 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-samsung_s6e3fc2x01.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-samsung_s6e3fc2x01.dtsi @@ -346,7 +346,7 @@ 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 02 - 39 01 00 00 00 00 16 B1 CE 01 02 1D E3 00 07 0D E9 28 FD F0 D3 0A E2 EA EA 01 FF FF F2 + 39 01 00 00 00 00 16 B1 FF 00 00 22 FF 00 03 02 FF 2A FF E5 FE 06 FF FB FF 00 F8 FF EC 39 01 00 00 00 00 03 B1 00 00 39 01 00 00 00 00 03 f0 A5 A5 ]; @@ -367,7 +367,7 @@ 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 02 - 39 01 00 00 00 00 16 B1 CE 01 02 1D E3 00 07 0D E9 28 FD F0 D3 0A E2 EA EA 01 FF FF F2 + 39 01 00 00 00 00 16 B1 D6 05 05 2C E4 15 08 09 ED 3E FF E0 F0 10 EE FB FF 1B F5 FF F0 39 01 00 00 00 00 03 B1 00 00 39 01 00 00 00 00 03 f0 A5 A5 ]; @@ -375,7 +375,7 @@ 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 02 - 39 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 F2 + 39 01 00 00 00 00 16 B1 FF 00 00 22 FF 00 09 10 EA 2A FF E2 FF 06 FF FD FF 00 F8 FF EF 39 01 00 00 00 00 03 B1 00 00 39 01 00 00 00 00 03 f0 A5 A5 ]; From d1888aa63aa60f1d8575b142fc559e39500004e2 Mon Sep 17 00:00:00 2001 From: Ganesh Kumar Date: Thu, 17 Oct 2019 15:27:05 +0530 Subject: [PATCH 258/356] Tune sRGB/P3 color mode parameters Change-Id: I84d941224c61b03a4cc6cb4a52f36e79ff88e7d9 (cherry picked from commit 21d32b9ef9b516f05bfdaaa545c3247f3e6ee17a) --- .../boot/dts/qcom/dsi-panel-samsung_s6e3fc2x01.dtsi | 12 ++++++------ .../dts/qcom/dsi-panel-samsung_sofef00_m_cmd.dtsi | 10 +++++----- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-samsung_s6e3fc2x01.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-samsung_s6e3fc2x01.dtsi index 09606373fd3f..888cf82d8a06 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-samsung_s6e3fc2x01.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-samsung_s6e3fc2x01.dtsi @@ -333,11 +333,11 @@ ]; qcom,mdss-dsi-panel-serial-num-command-state = "dsi_lp_mode"; qcom,mdss-dsi-panel-display-srgb-color-mode-on-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 02 - 39 01 00 00 00 00 16 B1 DA 05 03 15 E3 18 03 03 E9 25 FC F0 FC 09 EE FE F8 16 FF F9 F3 + 39 01 00 00 00 00 16 B1 CC 06 06 48 F8 18 01 01 D7 4F FE FD D0 12 E0 FF FB 1D FF FF FC 39 01 00 00 00 00 03 B1 00 00 39 01 00 00 00 00 03 f0 A5 A5 @@ -346,7 +346,7 @@ 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 02 - 39 01 00 00 00 00 16 B1 FF 00 00 22 FF 00 03 02 FF 2A FF E5 FE 06 FF FB FF 00 F8 FF EC + 39 01 00 00 00 00 16 B1 FF 00 00 12 F0 00 02 02 e9 19 FF FC ED 03 EC FC F9 00 FF FF FD 39 01 00 00 00 00 03 B1 00 00 39 01 00 00 00 00 03 f0 A5 A5 ]; @@ -362,12 +362,12 @@ 39 01 00 00 00 00 03 F0 5A 5A 39 01 00 00 00 00 03 B1 00 01 39 01 00 00 00 00 03 F0 A5 A5 - ]; + ]; qcom,mdss-dsi-customer-srgb-enable-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 02 - 39 01 00 00 00 00 16 B1 D6 05 05 2C E4 15 08 09 ED 3E FF E0 F0 10 EE FB FF 1B F5 FF F0 + 39 01 00 00 00 00 16 B1 CC 06 06 48 F8 18 01 01 D7 4F FE FD D0 12 E0 FF FB 1D FF FF FC 39 01 00 00 00 00 03 B1 00 00 39 01 00 00 00 00 03 f0 A5 A5 ]; @@ -375,7 +375,7 @@ 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 02 - 39 01 00 00 00 00 16 B1 FF 00 00 22 FF 00 09 10 EA 2A FF E2 FF 06 FF FD FF 00 F8 FF EF + 39 01 00 00 00 00 16 B1 FF 00 00 12 F0 00 02 02 e9 19 FF FC ED 03 EC FC F9 00 FF FF FD 39 01 00 00 00 00 03 B1 00 00 39 01 00 00 00 00 03 f0 A5 A5 ]; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-samsung_sofef00_m_cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-samsung_sofef00_m_cmd.dtsi index 77680d0f38c5..43d612154580 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-samsung_sofef00_m_cmd.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-samsung_sofef00_m_cmd.dtsi @@ -229,7 +229,7 @@ 39 01 00 00 00 00 03 f0 5A 5A 39 01 00 00 00 00 03 E2 00 85 39 01 00 00 00 00 02 B0 2C - 39 01 00 00 00 00 16 E2 CE 01 02 1D E3 00 07 0D E9 28 FD F0 D3 0A E2 EA EA 01 FF FF F2 + 39 01 00 00 00 00 16 E2 CC 06 06 48 F8 18 01 01 D7 4F FE FD D0 12 E0 FF FB 1D FF FF FC 39 01 00 00 00 00 02 b0 49 39 01 00 00 00 00 02 E2 00 39 01 00 00 00 00 02 b0 4A @@ -246,7 +246,7 @@ 39 01 00 00 00 00 03 f0 5A 5A 39 01 00 00 00 00 03 E2 00 85 39 01 00 00 00 00 02 B0 2C - 39 01 00 00 00 00 16 E2 CE 01 02 1D E3 00 07 0D E9 28 FD F0 D3 0A E2 EA EA 01 FF FF F2 + 39 01 00 00 00 00 16 E2 FF 00 00 12 F0 00 02 02 e9 19 FF FC ED 03 EC FC F9 00 FF FF FD 39 01 00 00 00 00 02 b0 49 39 01 00 00 00 00 02 E2 00 39 01 00 00 00 00 02 b0 4A @@ -285,7 +285,7 @@ 39 01 00 00 00 00 03 f0 5A 5A 39 01 00 00 00 00 03 E2 00 85 39 01 00 00 00 00 02 B0 2C - 39 01 00 00 00 00 16 E2 CE 01 02 1D E3 00 07 0D E9 28 FD F0 D3 0A E2 EA EA 01 FF FF F2 + 39 01 00 00 00 00 16 E2 CC 06 06 48 F8 18 01 01 D7 4F FE FD D0 12 E0 FF FB 1D FF FF FC 39 01 00 00 00 00 02 b0 49 39 01 00 00 00 00 02 E2 00 39 01 00 00 00 00 02 b0 4A @@ -296,13 +296,13 @@ 39 01 00 00 00 00 02 E2 00 39 01 00 00 00 00 02 b0 4D 39 01 00 00 00 00 02 E2 00 - 39 01 00 00 00 00 03 f0 A5 A5 + 39 01 00 00 00 00 03 f0 A5 A5 ]; qcom,mdss-dsi-customer-p3-enable-command = [ 39 01 00 00 00 00 03 f0 5A 5A 39 01 00 00 00 00 03 E2 00 85 39 01 00 00 00 00 02 B0 2C - 39 01 00 00 00 00 16 E2 FF 00 00 00 FF 00 00 00 FF 00 FF FF FF 00 FF FF FF 00 FF FF F2 + 39 01 00 00 00 00 16 E2 FF 00 00 12 F0 00 02 02 e9 19 FF FC ED 03 EC FC F9 00 FF FF FD 39 01 00 00 00 00 02 b0 49 39 01 00 00 00 00 02 E2 00 39 01 00 00 00 00 02 b0 4A From 33ba9d5ac9fcc4a4ced4648119677d2dbc3613c7 Mon Sep 17 00:00:00 2001 From: Depeng Shao Date: Mon, 5 Aug 2019 21:31:18 +0800 Subject: [PATCH 259/356] msm: camera_oneplus: eeprom: Release the mutex even though got error Release the mutex even though got error. Change-Id: Iaeec418ce7db4623cede6c922869c6f8c69ab595 Signed-off-by: Depeng Shao --- .../cam_sensor_module/cam_eeprom/cam_eeprom_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_eeprom/cam_eeprom_core.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_eeprom/cam_eeprom_core.c index 2158ff686229..a6fadb4c1121 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_eeprom/cam_eeprom_core.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_eeprom/cam_eeprom_core.c @@ -924,7 +924,7 @@ int32_t cam_eeprom_driver_cmd(struct cam_eeprom_ctrl_t *e_ctrl, void *arg) &eeprom_cap, sizeof(struct cam_eeprom_query_cap_t))) { CAM_ERR(CAM_EEPROM, "Failed Copy to User"); - return -EFAULT; + rc = -EFAULT; goto release_mutex; } CAM_DBG(CAM_EEPROM, "eeprom_cap: ID: %d", eeprom_cap.slot_info); From 2c161ccf5c970614d9bb43413d749fe83d27c55c Mon Sep 17 00:00:00 2001 From: "v-zhiyuan.sun" Date: Fri, 22 Nov 2019 21:25:33 +0800 Subject: [PATCH 260/356] msm: camera_oneplus: Initialize completion variable before cdm submit happens. Change-Id: Id1a1f1c7dea596bb64f7327ea138e4d877fdcd6e --- .../msm/camera_oneplus/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index f5cf1bac458e..74a7583922df 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -1611,7 +1611,7 @@ static int cam_ife_mgr_config_hw(void *hw_mgr_priv, cdm_cmd->cmd[i].len = cmd->len; } - if (cfg->request_id == 1) + if (cfg->init_packet) init_completion(&ctx->config_done_complete); CAM_DBG(CAM_ISP, "Submit to CDM"); rc = cam_cdm_submit_bls(ctx->cdm_handle, cdm_cmd); @@ -1621,7 +1621,6 @@ static int cam_ife_mgr_config_hw(void *hw_mgr_priv, } if (cfg->init_packet) { - init_completion(&ctx->config_done_complete); rc = wait_for_completion_timeout( &ctx->config_done_complete, msecs_to_jiffies(30)); From fa646d4b1fccadf87f1fc0c9038557f299b48224 Mon Sep 17 00:00:00 2001 From: Siba Prasad Date: Mon, 6 Apr 2020 10:29:54 +0530 Subject: [PATCH 261/356] msm: camera_oneplus: Add null check on context pointer Change-Id: Ied55bb99c7ac63425f47cd6beec90bdc2bf4809a --- .../media/platform/msm/camera_oneplus/cam_core/cam_context.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/msm/camera_oneplus/cam_core/cam_context.c b/drivers/media/platform/msm/camera_oneplus/cam_core/cam_context.c index 98fff4838050..2b9decf48840 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_core/cam_context.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_core/cam_context.c @@ -352,7 +352,7 @@ int cam_context_handle_start_dev(struct cam_context *ctx, { int rc = 0; - if (!ctx->state_machine) { + if (!ctx || !ctx->state_machine) { CAM_ERR(CAM_CORE, "Context is not ready"); return -EINVAL; } @@ -381,7 +381,7 @@ int cam_context_handle_stop_dev(struct cam_context *ctx, { int rc = 0; - if (!ctx->state_machine) { + if (!ctx || !ctx->state_machine) { CAM_ERR(CAM_CORE, "Context is not ready"); return -EINVAL; } From 6276b8d172c2bccab1c29f8b3e7575e7ff135a83 Mon Sep 17 00:00:00 2001 From: "roger.li" Date: Sat, 23 Nov 2019 17:20:12 +0800 Subject: [PATCH 262/356] Make natural mode color check consistent with P Change-Id: Ia20b5b45d12873056ac25fab96c81b19a54a037c --- arch/arm64/boot/dts/qcom/dsi-panel-samsung_s6e3fc2x01.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-samsung_s6e3fc2x01.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-samsung_s6e3fc2x01.dtsi index 888cf82d8a06..afed2d82f9f6 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-samsung_s6e3fc2x01.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-samsung_s6e3fc2x01.dtsi @@ -337,7 +337,7 @@ 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 02 - 39 01 00 00 00 00 16 B1 CC 06 06 48 F8 18 01 01 D7 4F FE FD D0 12 E0 FF FB 1D FF FF FC + 39 01 00 00 00 00 16 B1 A7 07 05 48 D5 14 06 09 A7 54 EB CB C1 14 C4 E8 E2 1A FF FF E0 39 01 00 00 00 00 03 B1 00 00 39 01 00 00 00 00 03 f0 A5 A5 From 6c930e297de9c78a4c476757cd95fd20b8a3311f Mon Sep 17 00:00:00 2001 From: "roger.li" Date: Wed, 27 Nov 2019 11:11:44 +0800 Subject: [PATCH 263/356] Make advance srgb mode color check consistent with P Change-Id: I423dd9b1b6b7041bc49c0c9d7f259fa407c0be60 --- arch/arm64/boot/dts/qcom/dsi-panel-samsung_s6e3fc2x01.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-samsung_s6e3fc2x01.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-samsung_s6e3fc2x01.dtsi index afed2d82f9f6..47b0ea5158c8 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-samsung_s6e3fc2x01.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-samsung_s6e3fc2x01.dtsi @@ -367,7 +367,7 @@ 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 02 - 39 01 00 00 00 00 16 B1 CC 06 06 48 F8 18 01 01 D7 4F FE FD D0 12 E0 FF FB 1D FF FF FC + 39 01 00 00 00 00 16 B1 A7 07 05 48 D5 14 06 09 A7 54 EB CB C1 14 C4 E8 E2 1A FF FF E0 39 01 00 00 00 00 03 B1 00 00 39 01 00 00 00 00 03 f0 A5 A5 ]; From e6199807d2a2ae3d7445f8bc8ada5aae415902b6 Mon Sep 17 00:00:00 2001 From: LuK1337 Date: Fri, 26 Jun 2020 12:19:50 +0200 Subject: [PATCH 264/356] input: synaptics: s3320: Don't expose single tap gesture on enchilada Change-Id: I600286c03d60a1cbfc07edc1a880aeec3c847190 --- drivers/input/touchscreen/synaptics_driver_s3320.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/input/touchscreen/synaptics_driver_s3320.c b/drivers/input/touchscreen/synaptics_driver_s3320.c index 9e4977bbf5d1..4d2d703d94c5 100644 --- a/drivers/input/touchscreen/synaptics_driver_s3320.c +++ b/drivers/input/touchscreen/synaptics_driver_s3320.c @@ -4811,7 +4811,7 @@ static const struct file_operations key_disable_proc_fops = { #define CREATE_GESTURE_NODE(NAME)\ CREATE_PROC_NODE(touchpanel, NAME##_enable, 0666) -static int init_synaptics_proc(void) +static int init_synaptics_proc(struct synaptics_ts_data *ts) { int ret = 0; struct proc_dir_entry *node = NULL; @@ -4826,7 +4826,10 @@ static int init_synaptics_proc(void) CREATE_PROC_NODE(touchpanel, coordinate, 0444); #ifdef SUPPORT_GESTURE - CREATE_GESTURE_NODE(single_tap); + // single_tap is only available on fajita + if (ts->project_version == 0x03) { + CREATE_GESTURE_NODE(single_tap); + } CREATE_GESTURE_NODE(double_tap); CREATE_GESTURE_NODE(up_arrow); CREATE_GESTURE_NODE(down_arrow); @@ -6039,7 +6042,7 @@ static int synaptics_ts_probe(struct i2c_client *client, const struct i2c_device } #endif - init_synaptics_proc(); + init_synaptics_proc(ts); TPDTM_DMESG("synaptics_ts_probe 3203: normal end\n"); bootmode = get_boot_mode(); From 9313bd61eaa4f24a7bc55cc997a57b8e17caf93c Mon Sep 17 00:00:00 2001 From: LuK1337 Date: Sat, 22 May 2021 20:31:32 +0200 Subject: [PATCH 265/356] power: qpnp-smb2: Set correct power mode for UDP-role Apparently this fixes DASH charging. Change-Id: Ic40c6ab22d9293642ba2f5873a40b95f5b3abc27 --- drivers/power/supply/qcom/qpnp-smb2.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c index c9e86209554c..cbfcf696858b 100644 --- a/drivers/power/supply/qcom/qpnp-smb2.c +++ b/drivers/power/supply/qcom/qpnp-smb2.c @@ -2373,6 +2373,15 @@ static int smb2_post_init(struct smb2 *chip) * not requested */ rerun_election(chg->usb_icl_votable); + /* yangfb@bsp, 20180124 ,for EID-1772 */ + /* configure power role for UDP-role */ + rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, + TYPEC_POWER_ROLE_CMD_MASK, UFP_EN_CMD_BIT); + if (rc < 0) { + dev_err(chg->dev, + "Couldn't configure power role for UDP rc=%d\n", rc); + return rc; + } /* Force charger in Sink Only mode */ if (chg->ufp_only_mode) { @@ -2394,14 +2403,13 @@ static int smb2_post_init(struct smb2 *chip) } } } else { - /* yangfb@bsp, 20180124 ,for EID-1772 */ - /* configure power role for UDP-role */ + /* configure power role for dual-role */ rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, - TYPEC_POWER_ROLE_CMD_MASK, UFP_EN_CMD_BIT); + TYPEC_POWER_ROLE_CMD_MASK, 0); if (rc < 0) { dev_err(chg->dev, - "Couldn't configure power role for UDP rc=%d\n", + "Couldn't configure power role for DRP rc=%d\n", rc); return rc; } From 0a32205654eeb3a51299f0a21b3d6bf5f301750a Mon Sep 17 00:00:00 2001 From: LuK1337 Date: Sun, 29 Aug 2021 00:31:58 +0200 Subject: [PATCH 266/356] drivers: qcom: project_info: Add support for newer data structure This basically adds support for reading project_info when running Android 11 firmware while preserving support for older firmware. Change-Id: Ieaaabe8affe5e09c6d316fe9f8a021083df33a3a --- drivers/soc/qcom/project_info.c | 180 ++++++++++++++++++-------------- include/linux/project_info.h | 28 +++++ 2 files changed, 128 insertions(+), 80 deletions(-) diff --git a/drivers/soc/qcom/project_info.c b/drivers/soc/qcom/project_info.c index ddf9347daf75..78bfbad63d3d 100644 --- a/drivers/soc/qcom/project_info.c +++ b/drivers/soc/qcom/project_info.c @@ -24,7 +24,8 @@ static struct component_info component_info_desc[COMPONENT_MAX]; static struct kobject *project_info_kobj; -static struct project_info *project_info_desc; +static struct project_info *project_info_desc_v1 = NULL; +static struct project_info_v2 *project_info_desc_v2 = NULL; static struct dump_info *dp_info; static struct kobject *component_info; @@ -52,6 +53,13 @@ static DEVICE_ATTR(serialno, 0444, project_info_get, NULL); static DEVICE_ATTR(feature_id, 0444, project_info_get, NULL); static DEVICE_ATTR(aboard_id, 0444, project_info_get, NULL); +#define GET_PROJECT_INFO(member) (project_info_desc_v2 ? project_info_desc_v2->member : project_info_desc_v1->member) +#define SET_PROJECT_INFO(member, value) \ + if (project_info_desc_v2) \ + project_info_desc_v2->member = value; \ + else \ + project_info_desc_v1->member = value; + void save_dump_reason_to_smem(char *info, char *function_name) { int strl = 0, strl1 = 0; @@ -108,49 +116,49 @@ static ssize_t project_info_get(struct device *dev, struct device_attribute *attr, char *buf) { - if (project_info_desc) { + if (project_info_desc_v1 || project_info_desc_v2) { if (attr == &dev_attr_project_name) return snprintf(buf, BUF_SIZE, "%s\n", - project_info_desc->project_name); + GET_PROJECT_INFO(project_name)); if (attr == &dev_attr_hw_id) return snprintf(buf, BUF_SIZE, "%d\n", - project_info_desc->hw_version); + GET_PROJECT_INFO(hw_version)); if (attr == &dev_attr_rf_id_v1) return snprintf(buf, BUF_SIZE, "%d\n", - project_info_desc->rf_v1); + GET_PROJECT_INFO(rf_v1)); if (attr == &dev_attr_rf_id_v2) return snprintf(buf, BUF_SIZE, "%d\n", - project_info_desc->rf_v2); + GET_PROJECT_INFO(rf_v2)); if (attr == &dev_attr_rf_id_v3) return snprintf(buf, BUF_SIZE, "%d\n", - project_info_desc->rf_v3); + GET_PROJECT_INFO(rf_v3)); if (attr == &dev_attr_modem) return snprintf(buf, BUF_SIZE, "%d\n", - project_info_desc->modem); + GET_PROJECT_INFO(modem)); if (attr == &dev_attr_operator_no) return snprintf(buf, BUF_SIZE, "%d\n", - project_info_desc->operator); + GET_PROJECT_INFO(operator)); if (attr == &dev_attr_ddr_manufacture_info) return snprintf(buf, BUF_SIZE, "%d\n", - project_info_desc->ddr_manufacture_info); + GET_PROJECT_INFO(ddr_manufacture_info)); if (attr == &dev_attr_ddr_row) return snprintf(buf, BUF_SIZE, "%d\n", - project_info_desc->ddr_row); + GET_PROJECT_INFO(ddr_row)); if (attr == &dev_attr_ddr_column) return snprintf(buf, BUF_SIZE, "%d\n", - project_info_desc->ddr_column); + GET_PROJECT_INFO(ddr_column)); if (attr == &dev_attr_ddr_fw_version) return snprintf(buf, BUF_SIZE, "%d\n", - project_info_desc->ddr_fw_version); + GET_PROJECT_INFO(ddr_fw_version)); if (attr == &dev_attr_ddr_reserve_info) return snprintf(buf, BUF_SIZE, "%d\n", - project_info_desc->ddr_reserve_info); + GET_PROJECT_INFO(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); + GET_PROJECT_INFO(platform_id)); if (attr == &dev_attr_serialno) return snprintf(buf, BUF_SIZE, "0x%x\n", @@ -158,11 +166,11 @@ static ssize_t project_info_get(struct device *dev, if (attr == &dev_attr_feature_id) return snprintf(buf, BUF_SIZE, "%d\n", - project_info_desc->feature_id); + GET_PROJECT_INFO(feature_id)); if (attr == &dev_attr_aboard_id) return snprintf(buf, BUF_SIZE, "%d\n", - project_info_desc->a_board_version); + GET_PROJECT_INFO(a_board_version)); } return -EINVAL; @@ -470,10 +478,10 @@ void get_ddr_manufacture_name(void) uint32 i, length; length = ARRAY_SIZE(ddr_manufacture_list); - if (project_info_desc) { + if (project_info_desc_v1 || project_info_desc_v2) { for (i = 0; i < length; i++) { if (ddr_manufacture_list[i].id == - project_info_desc->ddr_manufacture_info) { + GET_PROJECT_INFO(ddr_manufacture_info)) { snprintf(ddr_manufacture, BUF_SIZE, "%s", ddr_manufacture_list[i].name); break; @@ -487,10 +495,10 @@ void get_cpu_type(void) uint32 i, length; length = ARRAY_SIZE(cpu_list_msm); - if (project_info_desc) { + if (project_info_desc_v1 || project_info_desc_v2) { for (i = 0; i < length; i++) { if (cpu_list_msm[i].id == - project_info_desc->platform_id) { + GET_PROJECT_INFO(platform_id)) { snprintf(cpu_type, BUF_SIZE, "%s", cpu_list_msm[i].name); break; @@ -534,17 +542,23 @@ struct a_borad_version a_borad_version_string_arry_gpio[]={ uint32 get_hw_version(void) { - project_info_desc = smem_find(SMEM_PROJECT_INFO, - sizeof(struct project_info), - 0, - SMEM_ANY_HOST_FLAG); + if (strnstr(saved_command_line, "androidboot.platform_name=", strlen(saved_command_line))) + project_info_desc_v2 = smem_find(SMEM_PROJECT_INFO, + sizeof(struct project_info_v2), + 0, + SMEM_ANY_HOST_FLAG); + else + project_info_desc_v1 = smem_find(SMEM_PROJECT_INFO, + sizeof(struct project_info), + 0, + SMEM_ANY_HOST_FLAG); - if (IS_ERR_OR_NULL(project_info_desc)) + if (IS_ERR_OR_NULL(project_info_desc_v1) && IS_ERR_OR_NULL(project_info_desc_v2)) 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; + GET_PROJECT_INFO(hw_version)); + return GET_PROJECT_INFO(hw_version); } return 0; } @@ -557,130 +571,136 @@ int __init init_project_info(void) if (project_info_init_done) return 0; - project_info_desc = smem_find(SMEM_PROJECT_INFO, - sizeof(struct project_info), - 0, - SMEM_ANY_HOST_FLAG); + if (strnstr(saved_command_line, "androidboot.platform_name=", strlen(saved_command_line))) + project_info_desc_v2 = smem_find(SMEM_PROJECT_INFO, + sizeof(struct project_info_v2), + 0, + SMEM_ANY_HOST_FLAG); + else + project_info_desc_v1 = smem_find(SMEM_PROJECT_INFO, + sizeof(struct project_info), + 0, + SMEM_ANY_HOST_FLAG); - if (IS_ERR_OR_NULL(project_info_desc)) { + if (IS_ERR_OR_NULL(project_info_desc_v1) && IS_ERR_OR_NULL(project_info_desc_v2)) { pr_err("%s: get project_info failure\n", __func__); return 0; } pr_err("%s: project_name: %s hw_version: %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->rf_v1, - project_info_desc->rf_v2, - project_info_desc->rf_v3, - project_info_desc->platform_id); - - switch (project_info_desc->hw_version) { + __func__, GET_PROJECT_INFO(project_name), + GET_PROJECT_INFO(hw_version), + GET_PROJECT_INFO(rf_v1), + GET_PROJECT_INFO(rf_v2), + GET_PROJECT_INFO(rf_v3), + GET_PROJECT_INFO(platform_id)); + + switch (GET_PROJECT_INFO(hw_version)) { case 11: snprintf(mainboard_version, sizeof(mainboard_version), "%s %s", - project_info_desc->project_name, "EVB"); + GET_PROJECT_INFO(project_name), "EVB"); break; case 12: snprintf(mainboard_version, sizeof(mainboard_version), "%s %s", - project_info_desc->project_name, "T0"); + GET_PROJECT_INFO(project_name), "T0"); break; case 13: snprintf(mainboard_version, sizeof(mainboard_version), "%s %s", - project_info_desc->project_name, "T1"); + GET_PROJECT_INFO(project_name), "T1"); break; case 14: snprintf(mainboard_version, sizeof(mainboard_version), "%s %s", - project_info_desc->project_name, "EVT1"); + GET_PROJECT_INFO(project_name), "EVT1"); break; case 15: snprintf(mainboard_version, sizeof(mainboard_version), "%s %s", - project_info_desc->project_name, "EVT2"); + GET_PROJECT_INFO(project_name), "EVT2"); break; case 21: snprintf(mainboard_version, sizeof(mainboard_version), "%s %s", - project_info_desc->project_name, "DVT"); + GET_PROJECT_INFO(project_name), "DVT"); break; case 22: snprintf(mainboard_version, sizeof(mainboard_version), "%s %s", - project_info_desc->project_name, "PVT"); + GET_PROJECT_INFO(project_name), "PVT"); break; case 23: snprintf(mainboard_version, sizeof(mainboard_version), "%s %s", - project_info_desc->project_name, "PVT"); + GET_PROJECT_INFO(project_name), "PVT"); break; case 24: snprintf(mainboard_version, sizeof(mainboard_version), "%s %s", - project_info_desc->project_name, "PVT_MCU"); + GET_PROJECT_INFO(project_name), "PVT_MCU"); break; case 25: snprintf(mainboard_version, sizeof(mainboard_version), "%s %s", - project_info_desc->project_name, "DVTBACKUP"); + GET_PROJECT_INFO(project_name), "DVTBACKUP"); break; case 31: snprintf(mainboard_version, sizeof(mainboard_version), "%s %s", - project_info_desc->project_name, "EVB"); + GET_PROJECT_INFO(project_name), "EVB"); break; case 32: snprintf(mainboard_version, sizeof(mainboard_version), "%s %s", - project_info_desc->project_name, "T0"); + GET_PROJECT_INFO(project_name), "T0"); break; case 33: snprintf(mainboard_version, sizeof(mainboard_version), "%s %s", - project_info_desc->project_name, "EVT1"); + GET_PROJECT_INFO(project_name), "EVT1"); break; case 34: snprintf(mainboard_version, sizeof(mainboard_version), "%s %s", - project_info_desc->project_name, "DVT"); + GET_PROJECT_INFO(project_name), "DVT"); break; case 35: snprintf(mainboard_version, sizeof(mainboard_version), "%s %s", - project_info_desc->project_name, "2ND"); + GET_PROJECT_INFO(project_name), "2ND"); break; case 41: snprintf(mainboard_version, sizeof(mainboard_version), "%s %s", - project_info_desc->project_name, "PVT"); + GET_PROJECT_INFO(project_name), "PVT"); break; case 42: snprintf(mainboard_version, sizeof(mainboard_version), "%s %s", - project_info_desc->project_name, "PVT2nd"); + GET_PROJECT_INFO(project_name), "PVT2nd"); break; case 43: snprintf(mainboard_version, sizeof(mainboard_version), "%s %s", - project_info_desc->project_name, "PVT-1"); + GET_PROJECT_INFO(project_name), "PVT-1"); break; case 44: snprintf(mainboard_version, sizeof(mainboard_version), "%s %s", - project_info_desc->project_name, "PVTSpec"); + GET_PROJECT_INFO(project_name), "PVTSpec"); break; case 45: snprintf(mainboard_version, sizeof(mainboard_version), "%s %s", - project_info_desc->project_name, "MPSpec"); + GET_PROJECT_INFO(project_name), "MPSpec"); break; case 55: snprintf(mainboard_version, sizeof(mainboard_version), "%s %s", - project_info_desc->project_name, "DVTUSB30"); + GET_PROJECT_INFO(project_name), "DVTUSB30"); break; default: snprintf(mainboard_version, sizeof(mainboard_version), "%d", - project_info_desc->hw_version); + GET_PROJECT_INFO(hw_version)); break; } push_component_info(MAINBOARD, mainboard_version, mainboard_manufacture); - if( project_info_desc->hw_version <= 32 ) { + if( GET_PROJECT_INFO(hw_version) <= 32 ) { snprintf(Aboard_version, sizeof(Aboard_version), "%d %s", - project_info_desc->a_board_version,project_info_desc->a_board_version <=5 ? - a_borad_version_string_arry[project_info_desc->a_board_version -1].name:"Unknown"); + GET_PROJECT_INFO(a_board_version),GET_PROJECT_INFO(a_board_version) <=5 ? + a_borad_version_string_arry[GET_PROJECT_INFO(a_board_version) -1].name:"Unknown"); push_component_info(ABOARD, Aboard_version, mainboard_manufacture); pr_err("%s: Aboard_gpio(%s)\n", __func__, Aboard_version); } - snprintf(rf_version, sizeof(rf_version), " %d",project_info_desc->rf_v1); + snprintf(rf_version, sizeof(rf_version), " %d",GET_PROJECT_INFO(rf_v1)); push_component_info(RF_VERSION, rf_version, mainboard_manufacture); get_ddr_manufacture_name(); @@ -700,15 +720,15 @@ int __init init_project_info(void) ddr_size = 2; snprintf(ddr_version, sizeof(ddr_version), "size_%dG_r_%d_c_%d", - ddr_size, project_info_desc->ddr_row, - project_info_desc->ddr_column); + ddr_size, GET_PROJECT_INFO(ddr_row), + GET_PROJECT_INFO(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); + GET_PROJECT_INFO(ddr_reserve_info) == 0x05 ? "20nm" : + (GET_PROJECT_INFO(ddr_reserve_info) == 0x06 ? "18nm" : " "), + GET_PROJECT_INFO(ddr_fw_version) >> 16, + GET_PROJECT_INFO(ddr_fw_version) & 0x0000FFFF); push_component_info(DDR, ddr_version, ddr_manufacture_and_fw_verion); get_cpu_type(); @@ -766,23 +786,23 @@ static int op_aboard_read_gpio(void) if( gpio0 == 0 && gpio1 == 0 ) { - project_info_desc->a_board_version = 0 ; + SET_PROJECT_INFO(a_board_version, 0); } else if( gpio0 == 0 && gpio1 == 1 ) { - project_info_desc->a_board_version = 1 ; + SET_PROJECT_INFO(a_board_version, 1); } else if( gpio0 == 1 && gpio1 == 0 ) { - project_info_desc->a_board_version = 2 ; + SET_PROJECT_INFO(a_board_version, 2); } else { - project_info_desc->a_board_version = -1 ; + SET_PROJECT_INFO(a_board_version, -1); } snprintf(Aboard_version, sizeof(Aboard_version), "%d %s", - project_info_desc->a_board_version,project_info_desc->a_board_version <3 ? - a_borad_version_string_arry_gpio[project_info_desc->a_board_version].name:"Unknown"); + GET_PROJECT_INFO(a_board_version),GET_PROJECT_INFO(a_board_version) <3 ? + a_borad_version_string_arry_gpio[GET_PROJECT_INFO(a_board_version)].name:"Unknown"); push_component_info(ABOARD, Aboard_version, mainboard_manufacture); pr_err("%s: Aboard_gpio(%s)\n", __func__, Aboard_version); @@ -875,7 +895,7 @@ static int __init init_project(void) init_project_info(); - if( project_info_desc->hw_version > 32 ){ + if( GET_PROJECT_INFO(hw_version) > 32 ){ ret = platform_driver_register(&aboard_driver); if (ret) pr_err("aboard_driver register failed: %d\n", ret); diff --git a/include/linux/project_info.h b/include/linux/project_info.h index 670e5d07b156..cc8eb05f7e71 100644 --- a/include/linux/project_info.h +++ b/include/linux/project_info.h @@ -32,6 +32,34 @@ struct project_info { uint32 a_board_version; }; +struct project_info_v2 { + char project_name[8]; //eg, 15801 + char project_codename[20]; + char reservename[12]; + uint32 prj_version; + uint32 hw_version; //PCB number, T0, EVT + 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 ddr_type; + uint32 reserve02; /*reserve for feture use*/ + uint32 reserve03; + uint32 reserve04; + uint32 reserve05; + uint32 a_board_version; + uint32 feature_id; + uint32 ftm_uart_boot_mode; + uint32 operator; + uint32 modem; +}; + #define DUMP_REASON_SIZE 256 struct dump_info{ From 50c65894983f52ca24739173dd37f94987f5f092 Mon Sep 17 00:00:00 2001 From: LuK1337 Date: Sun, 29 Aug 2021 17:34:32 +0200 Subject: [PATCH 267/356] arm64: dts: Add oem,project-id, oem,hw-id properties to enchilada+fajita Needed to make Android R bootloader happy :^) Change-Id: I562494565a5a622c10a918e834555b4d388dfb7a --- arch/arm64/boot/dts/qcom/enchilada-mp-v2.1-overlay.dts | 2 ++ arch/arm64/boot/dts/qcom/enchilada-pvt-v2.1-backup-overlay.dts | 2 ++ arch/arm64/boot/dts/qcom/enchilada-pvt-v2.1-overlay.dts | 2 ++ arch/arm64/boot/dts/qcom/fajita-mp-v2.1-spec-overlay.dts | 2 ++ arch/arm64/boot/dts/qcom/fajita-pvt-v2.1-bu-overlay.dts | 2 ++ arch/arm64/boot/dts/qcom/fajita-pvt-v2.1-overlay.dts | 3 +++ arch/arm64/boot/dts/qcom/fajita-pvt-v2.1-spec-overlay.dts | 2 ++ arch/arm64/boot/dts/qcom/fajita-pvt-v2.1-v1-overlay.dts | 2 ++ 8 files changed, 17 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/enchilada-mp-v2.1-overlay.dts b/arch/arm64/boot/dts/qcom/enchilada-mp-v2.1-overlay.dts index a80230ad5a0f..c2226f1068de 100644 --- a/arch/arm64/boot/dts/qcom/enchilada-mp-v2.1-overlay.dts +++ b/arch/arm64/boot/dts/qcom/enchilada-mp-v2.1-overlay.dts @@ -30,4 +30,6 @@ compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp"; qcom,msm-id = <321 0x20001>; qcom,board-id = <8 0 17819 23>; + oem,project-id = <17819>; + oem,hw-id = <23>; }; diff --git a/arch/arm64/boot/dts/qcom/enchilada-pvt-v2.1-backup-overlay.dts b/arch/arm64/boot/dts/qcom/enchilada-pvt-v2.1-backup-overlay.dts index 65511f6c1f88..817872eec9cb 100644 --- a/arch/arm64/boot/dts/qcom/enchilada-pvt-v2.1-backup-overlay.dts +++ b/arch/arm64/boot/dts/qcom/enchilada-pvt-v2.1-backup-overlay.dts @@ -30,4 +30,6 @@ compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp"; qcom,msm-id = <321 0x20001>; qcom,board-id = <8 0 17819 24>; + oem,project-id = <17819>; + oem,hw-id = <24>; }; diff --git a/arch/arm64/boot/dts/qcom/enchilada-pvt-v2.1-overlay.dts b/arch/arm64/boot/dts/qcom/enchilada-pvt-v2.1-overlay.dts index 57673c63df73..cb24ffded601 100644 --- a/arch/arm64/boot/dts/qcom/enchilada-pvt-v2.1-overlay.dts +++ b/arch/arm64/boot/dts/qcom/enchilada-pvt-v2.1-overlay.dts @@ -30,4 +30,6 @@ compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp"; qcom,msm-id = <321 0x20001>; qcom,board-id = <8 0 17819 22>; + oem,project-id = <17819>; + oem,hw-id = <22>; }; diff --git a/arch/arm64/boot/dts/qcom/fajita-mp-v2.1-spec-overlay.dts b/arch/arm64/boot/dts/qcom/fajita-mp-v2.1-spec-overlay.dts index 17386bf574bf..02e9464b5fbe 100644 --- a/arch/arm64/boot/dts/qcom/fajita-mp-v2.1-spec-overlay.dts +++ b/arch/arm64/boot/dts/qcom/fajita-mp-v2.1-spec-overlay.dts @@ -30,4 +30,6 @@ compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp"; qcom,msm-id = <321 0x20001>; qcom,board-id = <8 0 18801 45>; + oem,project-id = <18801>; + oem,hw-id = <45>; }; diff --git a/arch/arm64/boot/dts/qcom/fajita-pvt-v2.1-bu-overlay.dts b/arch/arm64/boot/dts/qcom/fajita-pvt-v2.1-bu-overlay.dts index 4e18ae61e10b..c4520cd66338 100644 --- a/arch/arm64/boot/dts/qcom/fajita-pvt-v2.1-bu-overlay.dts +++ b/arch/arm64/boot/dts/qcom/fajita-pvt-v2.1-bu-overlay.dts @@ -30,4 +30,6 @@ compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp"; qcom,msm-id = <321 0x20001>; qcom,board-id = <8 0 18801 42>; + oem,project-id = <18801>; + oem,hw-id = <42>; }; diff --git a/arch/arm64/boot/dts/qcom/fajita-pvt-v2.1-overlay.dts b/arch/arm64/boot/dts/qcom/fajita-pvt-v2.1-overlay.dts index 76a31da29cb3..7ec4de135594 100644 --- a/arch/arm64/boot/dts/qcom/fajita-pvt-v2.1-overlay.dts +++ b/arch/arm64/boot/dts/qcom/fajita-pvt-v2.1-overlay.dts @@ -30,4 +30,7 @@ compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp"; qcom,msm-id = <321 0x20001>; qcom,board-id = <8 0 18801 41>; + oem,project-id = <18801>; + oem,hw-id = <41>; + }; diff --git a/arch/arm64/boot/dts/qcom/fajita-pvt-v2.1-spec-overlay.dts b/arch/arm64/boot/dts/qcom/fajita-pvt-v2.1-spec-overlay.dts index 04dcbf331da1..6690e2dac784 100644 --- a/arch/arm64/boot/dts/qcom/fajita-pvt-v2.1-spec-overlay.dts +++ b/arch/arm64/boot/dts/qcom/fajita-pvt-v2.1-spec-overlay.dts @@ -30,4 +30,6 @@ compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp"; qcom,msm-id = <321 0x20001>; qcom,board-id = <8 0 18801 44>; + oem,project-id = <18801>; + oem,hw-id = <44>; }; diff --git a/arch/arm64/boot/dts/qcom/fajita-pvt-v2.1-v1-overlay.dts b/arch/arm64/boot/dts/qcom/fajita-pvt-v2.1-v1-overlay.dts index 876235e7b1be..5aac83a76b5c 100644 --- a/arch/arm64/boot/dts/qcom/fajita-pvt-v2.1-v1-overlay.dts +++ b/arch/arm64/boot/dts/qcom/fajita-pvt-v2.1-v1-overlay.dts @@ -30,4 +30,6 @@ compatible = "qcom,sdm845-mtp", "qcom,sdm845", "qcom,mtp"; qcom,msm-id = <321 0x20001>; qcom,board-id = <8 0 18801 43>; + oem,project-id = <18801>; + oem,hw-id = <43>; }; From 49b83c83f9809701c99031fc28b0f095345d1818 Mon Sep 17 00:00:00 2001 From: LuK1337 Date: Sat, 4 Sep 2021 10:45:48 +0200 Subject: [PATCH 268/356] msm: camera_oneplus: Sync with oneplus/SDM845_R_11.0 Change-Id: I38e22c4c6f6ff69ea4ad7d80441e3a269468c7f6 --- .../msm/camera_oneplus/cam_cdm/cam_cdm_intf.c | 3 +- .../msm/camera_oneplus/cam_core/cam_node.c | 27 +- .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 6 +- .../camera_oneplus/cam_isp/cam_isp_context.c | 2 +- .../cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 19 +- .../isp_hw_mgr/hw_utils/cam_tasklet_util.c | 30 +- .../hw_utils/include/cam_tasklet_util.h | 4 +- .../irq_controller/cam_irq_controller.c | 61 +- .../isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c | 8 +- .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c | 21 +- .../cam_req_mgr/cam_req_mgr_core.c | 3 +- .../cam_sensor_module/cam_cci/cam_cci_dev.c | 5 +- .../cam_sensor_module/cam_cci/cam_cci_dev.h | 4 +- .../cam_sensor_module/cam_cci/cam_cci_soc.c | 4 +- .../cam_eeprom/cam_eeprom_core.c | 47 +- .../cam_flash/cam_flash_core.c | 4 +- .../cam_ois/ROHM_BU24218GWL_OIS.h | 4406 ++++++++--------- .../cam_sensor_module/cam_ois/cam_ois_core.c | 32 +- .../cam_sensor/CAM_SENSOR_SETTINGS.h | 2036 ++++---- .../cam_sensor/cam_sensor_core.c | 7 +- .../cam_sensor/cam_sensor_dev.c | 60 +- .../cam_sensor_utils/cam_sensor_util.c | 6 +- .../camera_oneplus/cam_smmu/cam_smmu_api.c | 2 +- 23 files changed, 3401 insertions(+), 3396 deletions(-) diff --git a/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_intf.c b/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_intf.c index fa98be2285b7..f44adc45add1 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_intf.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_intf.c @@ -166,8 +166,7 @@ int cam_cdm_acquire(struct cam_cdm_acquire_data *data) struct cam_hw_intf *hw; uint32_t hw_index = 0; - if ((!data) || (!data->identifier) || (!data->base_array) || - (!data->base_array_cnt)) + if (!data || !data->base_array_cnt) return -EINVAL; if (get_cdm_mgr_refcount()) { diff --git a/drivers/media/platform/msm/camera_oneplus/cam_core/cam_node.c b/drivers/media/platform/msm/camera_oneplus/cam_core/cam_node.c index 7e5b3ca2fd81..7433ef6eff08 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_core/cam_node.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_core/cam_node.c @@ -63,8 +63,8 @@ static int __cam_node_handle_query_cap(struct cam_node *node, return rc; } -static uint64_t LrmeaRequreCount = 0; -static uint64_t LrmeaReleaseCount = 0; +static uint64_t LrmeaRequreCount; +static uint64_t LrmeaReleaseCount; static int __cam_node_handle_acquire_dev(struct cam_node *node, struct cam_acquire_dev_cmd *acquire) { @@ -73,15 +73,17 @@ static int __cam_node_handle_acquire_dev(struct cam_node *node, if (!acquire) return -EINVAL; - if (!strcmp(node->name, "cam-lrme")){ - CAM_ERR(CAM_CORE, "Acquire device for node %s session_handle =%d, %lld", - node->name,acquire->session_handle, ++LrmeaRequreCount); - } + if (!strcmp(node->name, "cam-lrme")) { + CAM_ERR(CAM_CORE, "Acquire device for node %s session_handle=%d,%lld", + node->name, acquire->session_handle, + ++LrmeaRequreCount); + } ctx = cam_node_get_ctxt_from_free_list(node); if (!ctx) { rc = -ENOMEM; - if (!strcmp(node->name, "cam-lrme")) - CAM_ERR(CAM_CORE, "Can not get context for node %s", node->name); + if (!strcmp(node->name, "cam-lrme")) + CAM_ERR(CAM_CORE, "Can not get context for node %s", + node->name); goto err; } @@ -249,10 +251,11 @@ static int __cam_node_handle_release_dev(struct cam_node *node, CAM_ERR(CAM_CORE, "Invalid session handle for context"); return -EINVAL; } - if (!strcmp(node->name, "cam-lrme")){ - CAM_ERR(CAM_CORE, "cam_node_handle_release_dev %d,node %s, %lld", - release->dev_handle, node->name,++LrmeaReleaseCount); - } + if (!strcmp(node->name, "cam-lrme")) { + CAM_ERR(CAM_CORE, "cam_node_handle_release_dev %d, node %s, %lld", + release->dev_handle, + node->name, ++LrmeaReleaseCount); + } 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", diff --git a/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c index 1d6a6dc8a708..569ac098c68d 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c @@ -2304,8 +2304,7 @@ static int cam_icp_mgr_abort_handle( if (!rem_jiffies) { rc = -ETIMEDOUT; CAM_ERR(CAM_ICP, "FW timeout/err in abort handle command"); - } - else{ + } else { //workq won't do free,if no timeout means //cmd execution finished,so just release it. kfree(abort_cmd); @@ -2376,8 +2375,7 @@ static int cam_icp_mgr_destroy_handle( if (icp_hw_mgr.a5_debug_type == HFI_DEBUG_MODE_QUEUE) cam_icp_mgr_process_dbg_buf(); - } - else{ + } else { //workq won't do free,if no timeout means //cmd execution finished,so just release it. kfree(destroy_cmd); diff --git a/drivers/media/platform/msm/camera_oneplus/cam_isp/cam_isp_context.c b/drivers/media/platform/msm/camera_oneplus/cam_isp/cam_isp_context.c index e1157aa61501..f6e1ff7f5e29 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_isp/cam_isp_context.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/cam_isp_context.c @@ -784,7 +784,7 @@ static int __cam_isp_ctx_handle_error(struct cam_isp_context *ctx_isp, struct cam_ctx_request *req = NULL; struct cam_ctx_request *req_temp; struct cam_isp_ctx_req *req_isp = NULL; - struct cam_req_mgr_error_notify notify; + struct cam_req_mgr_error_notify notify = {}; uint64_t error_request_id; struct cam_context *ctx = ctx_isp->base; diff --git a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 74a7583922df..d84256cac629 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -614,7 +614,8 @@ static int cam_ife_hw_mgr_acquire_res_ife_out_rdi( 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 = CAM_ISP_RESOURCE_VFE_OUT; + 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; return 0; @@ -702,7 +703,8 @@ static int cam_ife_hw_mgr_acquire_res_ife_out_pixel( ife_out_res->hw_res[j]->res_id); } - ife_out_res->res_type = CAM_ISP_RESOURCE_VFE_OUT; + 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; @@ -815,7 +817,8 @@ static int cam_ife_hw_mgr_acquire_res_ife_src( CAM_ERR(CAM_ISP, "Wrong IFE CSID Resource Node"); goto err; } - ife_src_res->res_type = vfe_acquire.rsrc_type; + 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; @@ -984,13 +987,13 @@ static int cam_ife_hw_mgr_acquire_res_ife_csid_ipp( } cam_ife_hw_mgr_put_res(&ife_ctx->res_list_ife_csid, &csid_res); - csid_acquire.res_type = CAM_ISP_RESOURCE_PIX_PATH; + csid_acquire.res_type = (enum cam_isp_resource_type)CAM_ISP_RESOURCE_PIX_PATH; csid_acquire.res_id = CAM_IFE_PIX_PATH_RES_IPP; csid_acquire.cid = cid_res_id; csid_acquire.in_port = in_port; csid_acquire.out_port = in_port->data; - csid_res->res_type = CAM_ISP_RESOURCE_PIX_PATH; + csid_res->res_type = (enum cam_ife_hw_mgr_res_type)CAM_ISP_RESOURCE_PIX_PATH; csid_res->res_id = CAM_IFE_PIX_PATH_RES_IPP; csid_res->is_dual_vfe = in_port->usage_type; @@ -1135,7 +1138,7 @@ static int cam_ife_hw_mgr_acquire_res_ife_csid_rdi( cam_ife_hw_mgr_get_ife_csid_rdi_res_type( out_port->res_type); - csid_acquire.res_type = CAM_ISP_RESOURCE_PIX_PATH; + csid_acquire.res_type = (enum cam_isp_resource_type)CAM_ISP_RESOURCE_PIX_PATH; csid_acquire.cid = cid_res_id; csid_acquire.in_port = in_port; csid_acquire.out_port = out_port; @@ -1175,7 +1178,7 @@ static int cam_ife_hw_mgr_acquire_res_ife_csid_rdi( goto err; } - csid_res->res_type = CAM_ISP_RESOURCE_PIX_PATH; + 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; @@ -2167,7 +2170,7 @@ static int cam_ife_mgr_start_hw(void *hw_mgr_priv, void *start_hw_args) CAM_DBG(CAM_ISP, "Exit...(success)"); return 0; err: - stop_hw_method.hw_stop_cmd = CAM_CSID_HALT_IMMEDIATELY; + stop_hw_method.hw_stop_cmd = (enum cam_isp_hw_stop_cmd)CAM_CSID_HALT_IMMEDIATELY; stop_args.ctxt_to_hw_map = start_args->ctxt_to_hw_map; stop_args.args = (void *)(&stop_hw_method); cam_ife_mgr_stop_hw(hw_mgr_priv, &stop_args); diff --git a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.c b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.c index 949c08cb6d6d..8c71ed904ad9 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.c @@ -82,14 +82,14 @@ struct cam_tasklet_info { * Negative: Failure */ int cam_tasklet_get_cmd( - void *bottom_half, - void **bh_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; + struct cam_tasklet_info *tasklet = bottom_half; + struct cam_tasklet_queue_cmd *tasklet_cmd = NULL; if (!atomic_read(&tasklet->tasklet_active)) { CAM_ERR_RATE_LIMIT(CAM_ISP, "Tasklet is not active!\n"); @@ -103,10 +103,10 @@ int cam_tasklet_get_cmd( rc = -ENODEV; goto spin_unlock; } else { - tasklet_cmd = list_first_entry(&tasklet->free_cmd_list, + 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; + list_del_init(&(tasklet_cmd)->list); + *bh_cmd = tasklet_cmd; } spin_unlock: @@ -125,19 +125,19 @@ int cam_tasklet_get_cmd( * @return: Void */ int cam_tasklet_put_cmd( - void *bottom_half, - void **bh_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; + struct cam_tasklet_info *tasklet = bottom_half; + struct cam_tasklet_queue_cmd *tasklet_cmd = *bh_cmd; spin_lock_irqsave(&tasklet->tasklet_lock, flags); - list_add_tail(&(tasklet_cmd)->list, + list_add_tail(&(tasklet_cmd)->list, &tasklet->free_cmd_list); spin_unlock_irqrestore(&tasklet->tasklet_lock, flags); - return 0; + return 0; } /** @@ -183,7 +183,7 @@ static int cam_tasklet_dequeue_cmd( int cam_tasklet_enqueue_cmd( void *bottom_half, - void *bh_cmd, + void *bh_cmd, void *evt_payload_priv, CAM_IRQ_HANDLER_BOTTOM_HALF bottom_half_handler) { @@ -323,7 +323,7 @@ static void cam_tasklet_action(unsigned long data) while (!cam_tasklet_dequeue_cmd(tasklet_info, &tasklet_cmd)) { tasklet_cmd->bottom_half_handler(tasklet_info->ctx_priv, tasklet_cmd->payload); - cam_tasklet_put_cmd(tasklet_info, (void**)(&tasklet_cmd)); + cam_tasklet_put_cmd(tasklet_info, (void **)(&tasklet_cmd)); } } diff --git a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/include/cam_tasklet_util.h b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/include/cam_tasklet_util.h index 0829d98377f5..76ec4e613b65 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/include/cam_tasklet_util.h +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/include/cam_tasklet_util.h @@ -92,8 +92,8 @@ int cam_tasklet_enqueue_cmd( void *evt_payload_priv, CAM_IRQ_HANDLER_BOTTOM_HALF bottom_half_handler); -int cam_tasklet_get_cmd(void *bottom_half,void **bh_cmd); +int cam_tasklet_get_cmd(void *bottom_half, void **bh_cmd); -int cam_tasklet_put_cmd(void *bottom_half,void **bh_cmd); +int cam_tasklet_put_cmd(void *bottom_half, void **bh_cmd); #endif /* _CAM_TASKLET_UTIL_H_ */ diff --git a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c index ee61c1584b2b..f8b8d0b09b12 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c @@ -298,8 +298,8 @@ int cam_irq_controller_subscribe_irq(void *irq_controller, evt_handler->bottom_half = bottom_half; evt_handler->index = controller->hdl_idx++; - if (irq_bh_api) - evt_handler->irq_bh_api = *irq_bh_api; + if (irq_bh_api) + evt_handler->irq_bh_api = *irq_bh_api; /* Avoid rollover to negative values */ if (controller->hdl_idx > 0x3FFFFFFF) @@ -567,8 +567,8 @@ static void cam_irq_controller_th_processing( bool is_irq_match; int rc = -EINVAL; int i; - void *bh_cmd = NULL; - struct cam_irq_bh_api *irq_bh_api = NULL; + void *bh_cmd = NULL; + struct cam_irq_bh_api *irq_bh_api = NULL; CAM_DBG(CAM_ISP, "Enter"); @@ -593,16 +593,17 @@ static void cam_irq_controller_th_processing( evt_handler->evt_bit_mask_arr[i]; } - irq_bh_api = &evt_handler->irq_bh_api; - bh_cmd = NULL; - - if (irq_bh_api->get_bh_payload_func) { - if (irq_bh_api->get_bh_payload_func( - evt_handler->bottom_half, &bh_cmd)) { - CAM_ERR_RATE_LIMIT(CAM_ISP, "Can't get bh payload"); - continue; - } - } + irq_bh_api = &evt_handler->irq_bh_api; + bh_cmd = NULL; + + if (irq_bh_api->get_bh_payload_func) { + if (irq_bh_api->get_bh_payload_func( + evt_handler->bottom_half, &bh_cmd)) { + CAM_ERR_RATE_LIMIT(CAM_ISP, + "Can't get bh payload"); + continue; + } + } /* * irq_status_arr[0] is dummy argument passed. the entire @@ -612,26 +613,26 @@ static void cam_irq_controller_th_processing( rc = evt_handler->top_half_handler( controller->irq_status_arr[0], (void *)th_payload); - if (rc) { - CAM_ERR(CAM_ISP, - "Top half handler failed with %d", rc); - if (irq_bh_api->put_bh_payload_func && bh_cmd) { - if (irq_bh_api->put_bh_payload_func( - evt_handler->bottom_half, - &bh_cmd)) { - CAM_ERR(CAM_ISP, - "Can't put bh payload"); - } - } - continue; - } - } + if (rc) { + CAM_ERR(CAM_ISP, + "Top half handler failed with %d", rc); + if (irq_bh_api->put_bh_payload_func && bh_cmd) { + if (irq_bh_api->put_bh_payload_func( + evt_handler->bottom_half, + &bh_cmd)) { + CAM_ERR(CAM_ISP, + "Can't put bh payload"); + } + } + continue; + } + } if (!rc && evt_handler->bottom_half_handler) { CAM_DBG(CAM_ISP, "Enqueuing bottom half for %s", controller->name); - if (irq_bh_api->bottom_half_enqueue_func) { - irq_bh_api->bottom_half_enqueue_func( + if (irq_bh_api->bottom_half_enqueue_func) { + irq_bh_api->bottom_half_enqueue_func( evt_handler->bottom_half, bh_cmd, th_payload->evt_payload_priv, diff --git a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c index 688cd369af90..66b9b3bdbac9 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c @@ -537,7 +537,7 @@ int cam_vfe_start(void *hw_priv, void *start_args, uint32_t arg_size) struct cam_hw_info *vfe_hw = hw_priv; struct cam_isp_resource_node *isp_res; int rc = 0; - struct cam_irq_bh_api irq_bh_api; + struct cam_irq_bh_api irq_bh_api; if (!hw_priv || !start_args || (arg_size != sizeof(struct cam_isp_resource_node))) { @@ -548,9 +548,9 @@ int cam_vfe_start(void *hw_priv, void *start_args, uint32_t arg_size) 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; - irq_bh_api.bottom_half_enqueue_func = cam_tasklet_enqueue_cmd; - irq_bh_api.get_bh_payload_func = cam_tasklet_get_cmd; - irq_bh_api.put_bh_payload_func = cam_tasklet_put_cmd; + irq_bh_api.bottom_half_enqueue_func = cam_tasklet_enqueue_cmd; + irq_bh_api.get_bh_payload_func = cam_tasklet_get_cmd; + irq_bh_api.put_bh_payload_func = cam_tasklet_put_cmd; mutex_lock(&vfe_hw->hw_mutex); if (isp_res->res_type == CAM_ISP_RESOURCE_VFE_IN) { diff --git a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c index b057567c799c..c86230986810 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c @@ -1064,7 +1064,7 @@ static int cam_vfe_bus_start_wm(struct cam_isp_resource_node *wm_res) struct cam_vfe_bus_ver2_common_data *common_data = rsrc_data->common_data; uint32_t bus_irq_reg_mask[CAM_VFE_BUS_IRQ_MAX] = {0}; - struct cam_irq_bh_api irq_bh_api; + struct cam_irq_bh_api irq_bh_api; cam_io_w(0xf, common_data->mem_base + rsrc_data->hw_regs->burst_limit); @@ -1085,9 +1085,10 @@ static int cam_vfe_bus_start_wm(struct cam_isp_resource_node *wm_res) CAM_DBG(CAM_ISP, "Subscribe WM%d IRQ", rsrc_data->index); bus_irq_reg_mask[CAM_VFE_BUS_IRQ_REG1] = (1 << rsrc_data->index); - irq_bh_api.bottom_half_enqueue_func = cam_tasklet_enqueue_cmd; - irq_bh_api.get_bh_payload_func = cam_tasklet_get_cmd; - irq_bh_api.put_bh_payload_func = cam_tasklet_put_cmd; + irq_bh_api.bottom_half_enqueue_func = + cam_tasklet_enqueue_cmd; + irq_bh_api.get_bh_payload_func = cam_tasklet_get_cmd; + irq_bh_api.put_bh_payload_func = cam_tasklet_put_cmd; wm_res->irq_handle = cam_irq_controller_subscribe_irq( common_data->bus_irq_controller, CAM_IRQ_PRIORITY_1, bus_irq_reg_mask, wm_res, @@ -1490,7 +1491,7 @@ static int cam_vfe_bus_start_comp_grp(struct cam_isp_resource_node *comp_grp) struct cam_vfe_bus_ver2_common_data *common_data = rsrc_data->common_data; uint32_t bus_irq_reg_mask[CAM_VFE_BUS_IRQ_MAX] = {0}; - struct cam_irq_bh_api irq_bh_api; + struct cam_irq_bh_api irq_bh_api; CAM_DBG(CAM_ISP, "comp group id:%d streaming state:%d", rsrc_data->comp_grp_type, comp_grp->res_state); @@ -1570,9 +1571,9 @@ static int cam_vfe_bus_start_comp_grp(struct cam_isp_resource_node *comp_grp) (rsrc_data->is_master)) || (rsrc_data->comp_grp_type >= CAM_VFE_BUS_VER2_COMP_GRP_0 && rsrc_data->comp_grp_type <= CAM_VFE_BUS_VER2_COMP_GRP_5)) { - irq_bh_api.bottom_half_enqueue_func = cam_tasklet_enqueue_cmd; - irq_bh_api.get_bh_payload_func = cam_tasklet_get_cmd; - irq_bh_api.put_bh_payload_func = cam_tasklet_put_cmd; + irq_bh_api.bottom_half_enqueue_func = cam_tasklet_enqueue_cmd; + irq_bh_api.get_bh_payload_func = cam_tasklet_get_cmd; + irq_bh_api.put_bh_payload_func = cam_tasklet_put_cmd; comp_grp->irq_handle = cam_irq_controller_subscribe_irq( common_data->bus_irq_controller, CAM_IRQ_PRIORITY_1, bus_irq_reg_mask, comp_grp, @@ -2264,13 +2265,13 @@ 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; + 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 (IRQ_HANDLED == rc) ? 0 : -EINVAL; + return (IRQ_HANDLED == rc) ? 0 : -EINVAL; } static int cam_vfe_bus_error_irq_top_half(uint32_t evt_id, diff --git a/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_core.c b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_core.c index 98117ea7c259..ef0cdc3d7baf 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_core.c @@ -2638,7 +2638,8 @@ int cam_req_mgr_link_control(struct cam_req_mgr_link_control *control) link = (struct cam_req_mgr_core_link *) cam_get_device_priv(control->link_hdls[i]); if (!link) { - CAM_ERR_RATE_LIMIT(CAM_CRM, "Link(%d) is NULL on session 0x%x", + CAM_ERR_RATE_LIMIT(CAM_CRM, + "Link(%d) is NULL on session 0x%x", i, control->session_hdl); rc = -EINVAL; break; diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci/cam_cci_dev.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci/cam_cci_dev.c index ed7fd3435e46..1f3e7d46a66a 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci/cam_cci_dev.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci/cam_cci_dev.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018, 2020 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 @@ -274,8 +274,7 @@ static int cam_cci_platform_probe(struct platform_device *pdev) 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.sd_flags = V4L2_SUBDEV_FL_HAS_EVENTS; new_cci_dev->v4l2_dev_str.ent_function = CAM_CCI_DEVICE_TYPE; new_cci_dev->v4l2_dev_str.token = diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci/cam_cci_dev.h b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci/cam_cci_dev.h index e8ba8b1b1c34..8730c6d8b963 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci/cam_cci_dev.h +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci/cam_cci_dev.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2020, 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 @@ -300,6 +300,6 @@ static inline struct v4l2_subdev *cam_cci_get_subdev(void) #endif #define VIDIOC_MSM_CCI_CFG \ - _IOWR('V', BASE_VIDIOC_PRIVATE + 23, struct cam_cci_ctrl *) + _IOWR('V', BASE_VIDIOC_PRIVATE + 23, struct cam_cci_ctrl) #endif /* _CAM_CCI_DEV_H_ */ diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci/cam_cci_soc.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci/cam_cci_soc.c index d104e206c2c3..d6de56d47fdf 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci/cam_cci_soc.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci/cam_cci_soc.c @@ -89,9 +89,9 @@ int cam_cci_init(struct v4l2_subdev *sd, rc = cam_cpas_start(cci_dev->cpas_handle, &ahb_vote, &axi_vote); - if (rc != 0) { + if (rc != 0) CAM_ERR(CAM_CCI, "CPAS start failed"); - } + cam_cci_get_clk_rates(cci_dev, c_ctrl); /* Re-initialize the completion */ diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_eeprom/cam_eeprom_core.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_eeprom/cam_eeprom_core.c index a6fadb4c1121..766f73f523d3 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_eeprom/cam_eeprom_core.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_eeprom/cam_eeprom_core.c @@ -18,7 +18,10 @@ #include "cam_eeprom_soc.h" #include "cam_debug_util.h" +#ifdef CONFIG_PROJECT_INFO #include +#endif + struct ois_vendor_match_tbl { uint16_t ois_id; char ois_name[32]; @@ -51,8 +54,10 @@ static int cam_eeprom_read_memory(struct cam_eeprom_ctrl_t *e_ctrl, int ret = 0; uint32_t reg_data; uint32_t ois_driver_id; - uint16_t eeprom_slave_addr = 0xA0>>1; // 0xA0>>1 is the slave address of main camera Eeprom - uint16_t ois_driver_id_reg_addr = 0x0110; // 0x0110 and 0x0111 are the registers of OIS driver ID + // 0xA0>>1 is the slave address of main camera Eeprom + uint16_t eeprom_slave_addr = 0xA0>>1; + // 0x0110 and 0x0111 are the registers of OIS driver ID + uint16_t ois_driver_id_reg_addr = 0x0110; if (!e_ctrl) { CAM_ERR(CAM_EEPROM, "e_ctrl is NULL"); @@ -155,25 +160,35 @@ static int cam_eeprom_read_memory(struct cam_eeprom_ctrl_t *e_ctrl, } if (e_ctrl->io_master_info.cci_client->sid == eeprom_slave_addr) { - ret = camera_io_dev_read(&(e_ctrl->io_master_info), ois_driver_id_reg_addr, ®_data, - CAMERA_SENSOR_I2C_TYPE_WORD, CAMERA_SENSOR_I2C_TYPE_BYTE); + ret = camera_io_dev_read(&(e_ctrl->io_master_info), + ois_driver_id_reg_addr, ®_data, + CAMERA_SENSOR_I2C_TYPE_WORD, + CAMERA_SENSOR_I2C_TYPE_BYTE); if (ret) { - CAM_ERR(CAM_EEPROM, "failed: to read 0x%x rc %d", ois_driver_id_reg_addr, ret); + CAM_ERR(CAM_EEPROM, "failed: to read 0x%x rc %d", + ois_driver_id_reg_addr, ret); } else { ois_driver_id = reg_data & 0xFF; - ret = camera_io_dev_read(&(e_ctrl->io_master_info), ois_driver_id_reg_addr+1, ®_data, - CAMERA_SENSOR_I2C_TYPE_WORD, CAMERA_SENSOR_I2C_TYPE_BYTE); + ret = camera_io_dev_read(&(e_ctrl->io_master_info), + ois_driver_id_reg_addr+1, ®_data, + CAMERA_SENSOR_I2C_TYPE_WORD, + CAMERA_SENSOR_I2C_TYPE_BYTE); if (ret) { - CAM_ERR(CAM_EEPROM, "failed: to read 0x%x rc %d", ois_driver_id_reg_addr+1, ret); + CAM_ERR(CAM_EEPROM, "failed: to read 0x%x rc %d", + ois_driver_id_reg_addr+1, ret); } else { - ois_driver_id = ((reg_data & 0xFF) << 8) | ois_driver_id; + ois_driver_id = + ((reg_data & 0xFF) << 8) | ois_driver_id; +#ifdef CONFIG_PROJECT_INFO if (ois_driver_id == match_tbl[0].ois_id) { - push_component_info(OIS, match_tbl[0].ois_name, + push_component_info(OIS, + match_tbl[0].ois_name, match_tbl[0].vendor_name); } else if (ois_driver_id == match_tbl[1].ois_id) { push_component_info(OIS, match_tbl[1].ois_name, match_tbl[1].vendor_name); } +#endif CAM_ERR(CAM_EEPROM, "OIS module 0x%x", ois_driver_id); } } @@ -806,12 +821,12 @@ static int32_t cam_eeprom_pkt_parse(struct cam_eeprom_ctrl_t *e_ctrl, void *arg) } } else { 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; - } + vzalloc(e_ctrl->cal_data.num_data); + if (!e_ctrl->cal_data.mapdata) { + rc = -ENOMEM; + CAM_ERR(CAM_EEPROM, "failed"); + goto error; + } } rc = cam_eeprom_power_up(e_ctrl, diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_flash/cam_flash_core.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_flash/cam_flash_core.c index 3452a8e1b698..00e44b8d9b27 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_flash/cam_flash_core.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_flash/cam_flash_core.c @@ -212,7 +212,7 @@ static int cam_flash_ops(struct cam_flash_ctrl *flash_ctrl, if (flash_ctrl->switch_trigger) cam_res_mgr_led_trigger_event( flash_ctrl->switch_trigger, - LED_SWITCH_ON); + (enum led_brightness)LED_SWITCH_ON); return 0; } @@ -240,7 +240,7 @@ int cam_flash_off(struct cam_flash_ctrl *flash_ctrl) if (flash_ctrl->switch_trigger) cam_res_mgr_led_trigger_event(flash_ctrl->switch_trigger, - LED_SWITCH_OFF); + (enum led_brightness)LED_SWITCH_OFF); flash_ctrl->flash_state = CAM_FLASH_STATE_START; return 0; diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ois/ROHM_BU24218GWL_OIS.h b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ois/ROHM_BU24218GWL_OIS.h index e9488c8d7574..ff03f48d53c8 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ois/ROHM_BU24218GWL_OIS.h +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ois/ROHM_BU24218GWL_OIS.h @@ -1,2216 +1,2206 @@ -.start_download = -{ - .reg_settings = - { - {.reg_addr = 0xF010, .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, +.start_download = { +.reg_settings = { +{.reg_addr = 0xF010, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, }, -.firmware = -{ - .reg_settings = - { - {.reg_addr = 0x0000, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0001, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0002, .reg_data = 0xB5, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0003, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0004, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0005, .reg_data = 0x85, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0006, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0007, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0008, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0009, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x000A, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x000B, .reg_data = 0x24, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x000C, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x000D, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x000E, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x000F, .reg_data = 0x67, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0010, .reg_data = 0x4F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0011, .reg_data = 0x67, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0012, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0013, .reg_data = 0x67, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0014, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0015, .reg_data = 0x67, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0016, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0017, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0018, .reg_data = 0x37, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0019, .reg_data = 0xB4, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x001A, .reg_data = 0x4D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x001B, .reg_data = 0x63, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x001C, .reg_data = 0x42, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x001D, .reg_data = 0x84, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x001E, .reg_data = 0x26, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x001F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0020, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0021, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0022, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0023, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0024, .reg_data = 0xF9, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0025, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0026, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0027, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0028, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0029, .reg_data = 0x62, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x002A, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x002B, .reg_data = 0x24, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x002C, .reg_data = 0x42, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x002D, .reg_data = 0x84, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x002E, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x002F, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0030, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0031, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0032, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0033, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0034, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0035, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0036, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0037, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0038, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0039, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x003A, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x003B, .reg_data = 0x5E, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x003C, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x003D, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x003E, .reg_data = 0x42, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x003F, .reg_data = 0x84, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0040, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0041, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0042, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0043, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0044, .reg_data = 0xF9, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0045, .reg_data = 0x1F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0046, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0047, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0048, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0049, .reg_data = 0x5A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x004A, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x004B, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x004C, .reg_data = 0x42, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x004D, .reg_data = 0x84, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x004E, .reg_data = 0x1D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x004F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0050, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0051, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0052, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0053, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0054, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0055, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0056, .reg_data = 0x42, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0057, .reg_data = 0x84, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0058, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0059, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x005A, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x005B, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x005C, .reg_data = 0x49, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x005D, .reg_data = 0x56, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x005E, .reg_data = 0x1A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x005F, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0060, .reg_data = 0x13, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0061, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0062, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0063, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0064, .reg_data = 0xDD, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0065, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0066, .reg_data = 0x2E, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0067, .reg_data = 0x7F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0068, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0069, .reg_data = 0x99, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x006A, .reg_data = 0x26, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x006B, .reg_data = 0x7F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x006C, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x006D, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x006E, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x006F, .reg_data = 0x7F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0070, .reg_data = 0xDA, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0071, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0072, .reg_data = 0x42, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0073, .reg_data = 0x86, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0074, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0075, .reg_data = 0x93, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0076, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0077, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0078, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0079, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x007A, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x007B, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x007C, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x007D, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x007E, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x007F, .reg_data = 0x2D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0080, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0081, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0082, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0083, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0084, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0085, .reg_data = 0x8B, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0086, .reg_data = 0xFA, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0087, .reg_data = 0xAF, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0088, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0089, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x008A, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x008B, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x008C, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x008D, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x008E, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x008F, .reg_data = 0x3B, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0090, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0091, .reg_data = 0x4A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0092, .reg_data = 0xD8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0093, .reg_data = 0x17, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0094, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0095, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0096, .reg_data = 0x55, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0097, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0098, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0099, .reg_data = 0x3C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x009A, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x009B, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x009C, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x009D, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x009E, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x009F, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00A0, .reg_data = 0x31, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00A1, .reg_data = 0x3B, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00A2, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00A3, .reg_data = 0x8C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00A4, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00A5, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00A6, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00A7, .reg_data = 0x83, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00A8, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00A9, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00AA, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00AB, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00AC, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00AD, .reg_data = 0x3E, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00AE, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00AF, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00B0, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00B1, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00B2, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00B3, .reg_data = 0x76, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00B4, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00B5, .reg_data = 0x92, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00B6, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00B7, .reg_data = 0xA3, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00B8, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00B9, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00BA, .reg_data = 0x31, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00BB, .reg_data = 0x3D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00BC, .reg_data = 0xFA, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00BD, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00BE, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00BF, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00C0, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00C1, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00C2, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00C3, .reg_data = 0x6E, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00C4, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00C5, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00C6, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00C7, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00C8, .reg_data = 0xB2, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00C9, .reg_data = 0xCD, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00CA, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00CB, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00CC, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00CD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00CE, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00CF, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00D0, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00D1, .reg_data = 0x3A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00D2, .reg_data = 0xFA, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00D3, .reg_data = 0xBB, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00D4, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00D5, .reg_data = 0x63, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00D6, .reg_data = 0x55, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00D7, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00D8, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00D9, .reg_data = 0x1D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00DA, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00DB, .reg_data = 0x36, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00DC, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00DD, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00DE, .reg_data = 0x42, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00DF, .reg_data = 0x84, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00E0, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00E1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00E2, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00E3, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00E4, .reg_data = 0xE7, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00E5, .reg_data = 0xC5, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00E6, .reg_data = 0xF8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00E7, .reg_data = 0x73, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00E8, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00E9, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00EA, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00EB, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00EC, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00ED, .reg_data = 0x57, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00EE, .reg_data = 0x42, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00EF, .reg_data = 0x84, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00F0, .reg_data = 0xFA, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00F1, .reg_data = 0x70, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00F2, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00F3, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00F4, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00F5, .reg_data = 0xA1, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00F6, .reg_data = 0x24, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00F7, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00F8, .reg_data = 0x91, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00F9, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00FA, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00FB, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00FC, .reg_data = 0x4A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00FD, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00FE, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x00FF, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0100, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0101, .reg_data = 0x89, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0102, .reg_data = 0x99, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0103, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0104, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0105, .reg_data = 0x64, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0106, .reg_data = 0x62, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0107, .reg_data = 0xC8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0108, .reg_data = 0xDB, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0109, .reg_data = 0xF4, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x010A, .reg_data = 0x2C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x010B, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x010C, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x010D, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x010E, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x010F, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0110, .reg_data = 0x4C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0111, .reg_data = 0x2B, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0112, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0113, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0114, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0115, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0116, .reg_data = 0x34, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0117, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0118, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0119, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x011A, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x011B, .reg_data = 0x2C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x011C, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x011D, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x011E, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x011F, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0120, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0121, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0122, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0123, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0124, .reg_data = 0x4C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0125, .reg_data = 0x26, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0126, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0127, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0128, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0129, .reg_data = 0x34, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x012A, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x012B, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x012C, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x012D, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x012E, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x012F, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0130, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0131, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0132, .reg_data = 0x62, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0133, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0134, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0135, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0136, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0137, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0138, .reg_data = 0x34, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0139, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x013A, .reg_data = 0x4C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x013B, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x013C, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x013D, .reg_data = 0x4C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x013E, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x013F, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0140, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0141, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0142, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0143, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0144, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0145, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0146, .reg_data = 0x63, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0147, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0148, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0149, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x014A, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x014B, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x014C, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x014D, .reg_data = 0x1B, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x014E, .reg_data = 0x63, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x014F, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0150, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0151, .reg_data = 0x42, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0152, .reg_data = 0x78, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0153, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0154, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0155, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0156, .reg_data = 0x9A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0157, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0158, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0159, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x015A, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x015B, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x015C, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x015D, .reg_data = 0x2D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x015E, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x015F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0160, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0161, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0162, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0163, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0164, .reg_data = 0x2C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0165, .reg_data = 0x13, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0166, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0167, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0168, .reg_data = 0x4F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0169, .reg_data = 0x16, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x016A, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x016B, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x016C, .reg_data = 0x37, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x016D, .reg_data = 0xB4, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x016E, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x016F, .reg_data = 0x15, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0170, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0171, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0172, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0173, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0174, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0175, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0176, .reg_data = 0x9A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0177, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0178, .reg_data = 0x99, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0179, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x017A, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x017B, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x017C, .reg_data = 0x99, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x017D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x017E, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x017F, .reg_data = 0x88, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0180, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0181, .reg_data = 0x88, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0182, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0183, .reg_data = 0x0B, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0184, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0185, .reg_data = 0xB8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0186, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0187, .reg_data = 0x13, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0188, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0189, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x018A, .reg_data = 0x99, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x018B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x018C, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x018D, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x018E, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x018F, .reg_data = 0x88, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0190, .reg_data = 0x2D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0191, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0192, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0193, .reg_data = 0xB8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0194, .reg_data = 0x99, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0195, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0196, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0197, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0198, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0199, .reg_data = 0x88, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x019A, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x019B, .reg_data = 0x1F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x019C, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x019D, .reg_data = 0xB8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x019E, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x019F, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01A0, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01A1, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01A2, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01A3, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01A4, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01A5, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01A6, .reg_data = 0xBD, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01A7, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01A8, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01A9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01AA, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01AB, .reg_data = 0x15, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01AC, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01AD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01AE, .reg_data = 0x54, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01AF, .reg_data = 0xBD, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01B0, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01B1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01B2, .reg_data = 0x29, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01B3, .reg_data = 0xD9, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01B4, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01B5, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01B6, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01B7, .reg_data = 0x2D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01B8, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01B9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01BA, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01BB, .reg_data = 0xAA, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01BC, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01BD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01BE, .reg_data = 0x19, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01BF, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01C0, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01C1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01C2, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01C3, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01C4, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01C5, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01C6, .reg_data = 0x2B, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01C7, .reg_data = 0x25, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01C8, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01C9, .reg_data = 0x70, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01CA, .reg_data = 0xBA, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01CB, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01CC, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01CD, .reg_data = 0x86, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01CE, .reg_data = 0xB5, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01CF, .reg_data = 0xF1, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01D0, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01D1, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01D2, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01D3, .reg_data = 0x5F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01D4, .reg_data = 0x4C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01D5, .reg_data = 0x5F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01D6, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01D7, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01D8, .reg_data = 0x27, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01D9, .reg_data = 0x7D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01DA, .reg_data = 0x78, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01DB, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01DC, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01DD, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01DE, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01DF, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01E0, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01E1, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01E2, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01E3, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01E4, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01E5, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01E6, .reg_data = 0x26, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01E7, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01E8, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01E9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01EA, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01EB, .reg_data = 0x8C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01EC, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01ED, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01EE, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01EF, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01F0, .reg_data = 0x15, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01F1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01F2, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01F3, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01F4, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01F5, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01F6, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01F7, .reg_data = 0x92, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01F8, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01F9, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01FA, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01FB, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01FC, .reg_data = 0x15, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01FD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01FE, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x01FF, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0200, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0201, .reg_data = 0x55, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0202, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0203, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0204, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0205, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0206, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0207, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0208, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0209, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x020A, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x020B, .reg_data = 0x54, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x020C, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x020D, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x020E, .reg_data = 0x99, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x020F, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0210, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0211, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0212, .reg_data = 0x99, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0213, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0214, .reg_data = 0xD5, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0215, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0216, .reg_data = 0x1A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0217, .reg_data = 0x44, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0218, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0219, .reg_data = 0x51, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x021A, .reg_data = 0x42, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x021B, .reg_data = 0x64, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x021C, .reg_data = 0x99, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x021D, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x021E, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x021F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0220, .reg_data = 0x99, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0221, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0222, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0223, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0224, .reg_data = 0x1A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0225, .reg_data = 0x45, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0226, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0227, .reg_data = 0x49, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0228, .reg_data = 0x42, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0229, .reg_data = 0x6D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x022A, .reg_data = 0xD5, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x022B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x022C, .reg_data = 0xDC, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x022D, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x022E, .reg_data = 0x2C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x022F, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0230, .reg_data = 0xDD, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0231, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0232, .reg_data = 0x2D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0233, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0234, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0235, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0236, .reg_data = 0x26, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0237, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0238, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0239, .reg_data = 0x19, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x023A, .reg_data = 0x1E, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x023B, .reg_data = 0x76, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x023C, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x023D, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x023E, .reg_data = 0x99, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x023F, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0240, .reg_data = 0x1E, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0241, .reg_data = 0x7F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0242, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0243, .reg_data = 0x88, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0244, .reg_data = 0x98, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0245, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0246, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0247, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0248, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0249, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x024A, .reg_data = 0x7F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x024B, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x024C, .reg_data = 0x99, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x024D, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x024E, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x024F, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0250, .reg_data = 0x98, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0251, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0252, .reg_data = 0x77, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0253, .reg_data = 0xC8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0254, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0255, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0256, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0257, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0258, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0259, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x025A, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x025B, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x025C, .reg_data = 0xDD, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x025D, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x025E, .reg_data = 0x2C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x025F, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0260, .reg_data = 0xDD, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0261, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0262, .reg_data = 0x2D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0263, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0264, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0265, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0266, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0267, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0268, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0269, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x026A, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x026B, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x026C, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x026D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x026E, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x026F, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0270, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0271, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0272, .reg_data = 0x98, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0273, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0274, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0275, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0276, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0277, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0278, .reg_data = 0x99, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0279, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x027A, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x027B, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x027C, .reg_data = 0x76, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x027D, .reg_data = 0xC8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x027E, .reg_data = 0x98, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x027F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0280, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0281, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0282, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0283, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0284, .reg_data = 0xB5, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0285, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0286, .reg_data = 0xBD, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0287, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0288, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0289, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x028A, .reg_data = 0x4A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x028B, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x028C, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x028D, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x028E, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x028F, .reg_data = 0x24, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0290, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0291, .reg_data = 0x44, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0292, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0293, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0294, .reg_data = 0xBD, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0295, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0296, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0297, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0298, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0299, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x029A, .reg_data = 0xB5, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x029B, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x029C, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x029D, .reg_data = 0x89, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x029E, .reg_data = 0x4E, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x029F, .reg_data = 0x2D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02A0, .reg_data = 0x36, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02A1, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02A2, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02A3, .reg_data = 0x31, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02A4, .reg_data = 0x1D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02A5, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02A6, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02A7, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02A8, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02A9, .reg_data = 0xF8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02AA, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02AB, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02AC, .reg_data = 0x4D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02AD, .reg_data = 0x2D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02AE, .reg_data = 0x4C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02AF, .reg_data = 0x29, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02B0, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02B1, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02B2, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02B3, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02B4, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02B5, .reg_data = 0x54, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02B6, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02B7, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02B8, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02B9, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02BA, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02BB, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02BC, .reg_data = 0x98, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02BD, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02BE, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02BF, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02C0, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02C1, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02C2, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02C3, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02C4, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02C5, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02C6, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02C7, .reg_data = 0x58, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02C8, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02C9, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02CA, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02CB, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02CC, .reg_data = 0xA9, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02CD, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02CE, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02CF, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02D0, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02D1, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02D2, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02D3, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02D4, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02D5, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02D6, .reg_data = 0x2F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02D7, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02D8, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02D9, .reg_data = 0x4C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02DA, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02DB, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02DC, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02DD, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02DE, .reg_data = 0xE7, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02DF, .reg_data = 0xEC, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02E0, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02E1, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02E2, .reg_data = 0xE7, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02E3, .reg_data = 0xF1, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02E4, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02E5, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02E6, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02E7, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02E8, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02E9, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02EA, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02EB, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02EC, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02ED, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02EE, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02EF, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02F0, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02F1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02F2, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02F3, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02F4, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02F5, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02F6, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02F7, .reg_data = 0x44, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02F8, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02F9, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02FA, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02FB, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02FC, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02FD, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02FE, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x02FF, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0300, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0301, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0302, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0303, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0304, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0305, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0306, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0307, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0308, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0309, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x030A, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x030B, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x030C, .reg_data = 0x91, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x030D, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x030E, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x030F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0310, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0311, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0312, .reg_data = 0x1D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0313, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0314, .reg_data = 0x24, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0315, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0316, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0317, .reg_data = 0x15, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0318, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0319, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x031A, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x031B, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x031C, .reg_data = 0x27, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x031D, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x031E, .reg_data = 0x1D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x031F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0320, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0321, .reg_data = 0x3F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0322, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0323, .reg_data = 0x6E, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0324, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0325, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0326, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0327, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0328, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0329, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x032A, .reg_data = 0x2C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x032B, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x032C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x032D, .reg_data = 0x81, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x032E, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x032F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0330, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0331, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0332, .reg_data = 0x58, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0333, .reg_data = 0x72, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0334, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0335, .reg_data = 0x72, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0336, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0337, .reg_data = 0x3A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0338, .reg_data = 0xDB, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0339, .reg_data = 0xF8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x033A, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x033B, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x033C, .reg_data = 0xA9, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x033D, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x033E, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x033F, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0340, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0341, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0342, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0343, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0344, .reg_data = 0x2C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0345, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0346, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0347, .reg_data = 0x64, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0348, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0349, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x034A, .reg_data = 0xDB, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x034B, .reg_data = 0xEE, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x034C, .reg_data = 0xBD, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x034D, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x034E, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x034F, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0350, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0351, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0352, .reg_data = 0x54, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0353, .reg_data = 0xBD, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0354, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0355, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0356, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0357, .reg_data = 0xCD, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0358, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0359, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x035A, .reg_data = 0x19, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x035B, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x035C, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x035D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x035E, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x035F, .reg_data = 0xBC, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0360, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0361, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0362, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0363, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0364, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0365, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0366, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0367, .reg_data = 0xB5, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0368, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0369, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x036A, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x036B, .reg_data = 0x78, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x036C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x036D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x036E, .reg_data = 0x42, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x036F, .reg_data = 0x88, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0370, .reg_data = 0x24, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0371, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0372, .reg_data = 0xB5, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0373, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0374, .reg_data = 0x2A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0375, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0376, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0377, .reg_data = 0xE4, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0378, .reg_data = 0x23, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0379, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x037A, .reg_data = 0xDC, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x037B, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x037C, .reg_data = 0x6A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x037D, .reg_data = 0x5B, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x037E, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x037F, .reg_data = 0x9B, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0380, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0381, .reg_data = 0x9B, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0382, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0383, .reg_data = 0x9B, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0384, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0385, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0386, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0387, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0388, .reg_data = 0x23, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0389, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x038A, .reg_data = 0xBD, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x038B, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x038C, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x038D, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x038E, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x038F, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0390, .reg_data = 0x4E, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0391, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0392, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0393, .reg_data = 0x9D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0394, .reg_data = 0x19, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0395, .reg_data = 0xAE, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0396, .reg_data = 0x59, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0397, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0398, .reg_data = 0x59, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0399, .reg_data = 0x4D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x039A, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x039B, .reg_data = 0x37, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x039C, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x039D, .reg_data = 0x1E, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x039E, .reg_data = 0x63, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x039F, .reg_data = 0xB5, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03A0, .reg_data = 0x25, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03A1, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03A2, .reg_data = 0x36, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03A3, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03A4, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03A5, .reg_data = 0x2C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03A6, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03A7, .reg_data = 0xB5, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03A8, .reg_data = 0x42, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03A9, .reg_data = 0x93, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03AA, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03AB, .reg_data = 0x5B, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03AC, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03AD, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03AE, .reg_data = 0xDB, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03AF, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03B0, .reg_data = 0x6A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03B1, .reg_data = 0x41, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03B2, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03B3, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03B4, .reg_data = 0x62, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03B5, .reg_data = 0x41, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03B6, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03B7, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03B8, .reg_data = 0xBD, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03B9, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03BA, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03BB, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03BC, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03BD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03BE, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03BF, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03C0, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03C1, .reg_data = 0x79, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03C2, .reg_data = 0xB5, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03C3, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03C4, .reg_data = 0x69, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03C5, .reg_data = 0xC2, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03C6, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03C7, .reg_data = 0x85, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03C8, .reg_data = 0x4B, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03C9, .reg_data = 0x77, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03CA, .reg_data = 0x4C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03CB, .reg_data = 0x77, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03CC, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03CD, .reg_data = 0xA4, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03CE, .reg_data = 0x34, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03CF, .reg_data = 0x78, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03D0, .reg_data = 0x49, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03D1, .reg_data = 0x75, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03D2, .reg_data = 0x1D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03D3, .reg_data = 0x24, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03D4, .reg_data = 0x4C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03D5, .reg_data = 0x75, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03D6, .reg_data = 0x94, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03D7, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03D8, .reg_data = 0x31, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03D9, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03DA, .reg_data = 0x33, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03DB, .reg_data = 0x98, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03DC, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03DD, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03DE, .reg_data = 0x4F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03DF, .reg_data = 0x73, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03E0, .reg_data = 0x34, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03E1, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03E2, .reg_data = 0x4E, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03E3, .reg_data = 0x72, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03E4, .reg_data = 0x37, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03E5, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03E6, .reg_data = 0x78, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03E7, .reg_data = 0x1B, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03E8, .reg_data = 0x2B, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03E9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03EA, .reg_data = 0x4D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03EB, .reg_data = 0x71, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03EC, .reg_data = 0x78, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03ED, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03EE, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03EF, .reg_data = 0x74, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03F0, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03F1, .reg_data = 0x71, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03F2, .reg_data = 0x29, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03F3, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03F4, .reg_data = 0x78, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03F5, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03F6, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03F7, .reg_data = 0x91, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03F8, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03F9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03FA, .reg_data = 0x0E, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03FB, .reg_data = 0x89, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03FC, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03FD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03FE, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x03FF, .reg_data = 0x6C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0400, .reg_data = 0x29, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0401, .reg_data = 0x39, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0402, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0403, .reg_data = 0x6C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0404, .reg_data = 0x29, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0405, .reg_data = 0x3D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0406, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0407, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0408, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0409, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x040A, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x040B, .reg_data = 0x49, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x040C, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x040D, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x040E, .reg_data = 0x78, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x040F, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0410, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0411, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0412, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0413, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0414, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0415, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0416, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0417, .reg_data = 0x2A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0418, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0419, .reg_data = 0xEA, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x041A, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x041B, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x041C, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x041D, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x041E, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x041F, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0420, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0421, .reg_data = 0x59, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0422, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0423, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0424, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0425, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0426, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0427, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0428, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0429, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x042A, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x042B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x042C, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x042D, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x042E, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x042F, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0430, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0431, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0432, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0433, .reg_data = 0xE8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0434, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0435, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0436, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0437, .reg_data = 0xE8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0438, .reg_data = 0x1E, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0439, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x043A, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x043B, .reg_data = 0x15, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x043C, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x043D, .reg_data = 0x4A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x043E, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x043F, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0440, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0441, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0442, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0443, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0444, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0445, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0446, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0447, .reg_data = 0xE8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0448, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0449, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x044A, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x044B, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x044C, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x044D, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x044E, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x044F, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0450, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0451, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0452, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0453, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0454, .reg_data = 0x98, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0455, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0456, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0457, .reg_data = 0x69, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0458, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0459, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x045A, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x045B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x045C, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x045D, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x045E, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x045F, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0460, .reg_data = 0x69, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0461, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0462, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0463, .reg_data = 0x0B, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0464, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0465, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0466, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0467, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0468, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0469, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x046A, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x046B, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x046C, .reg_data = 0xE7, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x046D, .reg_data = 0xF2, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x046E, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x046F, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0470, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0471, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0472, .reg_data = 0x69, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0473, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0474, .reg_data = 0x1E, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0475, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0476, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0477, .reg_data = 0x0E, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0478, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0479, .reg_data = 0x4A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x047A, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x047B, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x047C, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x047D, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x047E, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x047F, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0480, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0481, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0482, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0483, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0484, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0485, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0486, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0487, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0488, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0489, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x048A, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x048B, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x048C, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x048D, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x048E, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x048F, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0490, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0491, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0492, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0493, .reg_data = 0xA9, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0494, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0495, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0496, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0497, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0498, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0499, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x049A, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x049B, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x049C, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x049D, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x049E, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x049F, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04A0, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04A1, .reg_data = 0x89, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04A2, .reg_data = 0x4B, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04A3, .reg_data = 0x45, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04A4, .reg_data = 0x1D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04A5, .reg_data = 0x1B, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04A6, .reg_data = 0x63, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04A7, .reg_data = 0x0B, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04A8, .reg_data = 0x1D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04A9, .reg_data = 0x1B, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04AA, .reg_data = 0x63, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04AB, .reg_data = 0x4B, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04AC, .reg_data = 0x4B, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04AD, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04AE, .reg_data = 0x63, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04AF, .reg_data = 0x8B, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04B0, .reg_data = 0x4E, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04B1, .reg_data = 0x44, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04B2, .reg_data = 0x63, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04B3, .reg_data = 0xCB, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04B4, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04B5, .reg_data = 0x31, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04B6, .reg_data = 0x49, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04B7, .reg_data = 0x42, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04B8, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04B9, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04BA, .reg_data = 0x78, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04BB, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04BC, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04BD, .reg_data = 0x64, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04BE, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04BF, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04C0, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04C1, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04C2, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04C3, .reg_data = 0x41, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04C4, .reg_data = 0x62, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04C5, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04C6, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04C7, .reg_data = 0xF2, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04C8, .reg_data = 0x62, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04C9, .reg_data = 0xB2, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04CA, .reg_data = 0x62, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04CB, .reg_data = 0x72, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04CC, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04CD, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04CE, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04CF, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04D0, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04D1, .reg_data = 0x1F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04D2, .reg_data = 0x6A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04D3, .reg_data = 0x41, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04D4, .reg_data = 0x62, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04D5, .reg_data = 0x41, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04D6, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04D7, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04D8, .reg_data = 0x7B, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04D9, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04DA, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04DB, .reg_data = 0x3C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04DC, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04DD, .reg_data = 0x52, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04DE, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04DF, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04E0, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04E1, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04E2, .reg_data = 0x49, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04E3, .reg_data = 0x33, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04E4, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04E5, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04E6, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04E7, .reg_data = 0xC2, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04E8, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04E9, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04EA, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04EB, .reg_data = 0xD2, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04EC, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04ED, .reg_data = 0x4A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04EE, .reg_data = 0x2A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04EF, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04F0, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04F1, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04F2, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04F3, .reg_data = 0x94, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04F4, .reg_data = 0x4D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04F5, .reg_data = 0x2E, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04F6, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04F7, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04F8, .reg_data = 0x35, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04F9, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04FA, .reg_data = 0xB2, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04FB, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04FC, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04FD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04FE, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x04FF, .reg_data = 0x29, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0500, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0501, .reg_data = 0x5C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0502, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0503, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0504, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0505, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0506, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0507, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0508, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0509, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x050A, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x050B, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x050C, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x050D, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x050E, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x050F, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0510, .reg_data = 0x92, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0511, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0512, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0513, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0514, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0515, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0516, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0517, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0518, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0519, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x051A, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x051B, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x051C, .reg_data = 0x6A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x051D, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x051E, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x051F, .reg_data = 0x2C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0520, .reg_data = 0x6A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0521, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0522, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0523, .reg_data = 0x41, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0524, .reg_data = 0x1A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0525, .reg_data = 0x44, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0526, .reg_data = 0x1A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0527, .reg_data = 0x67, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0528, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0529, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x052A, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x052B, .reg_data = 0x29, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x052C, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x052D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x052E, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x052F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0530, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0531, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0532, .reg_data = 0x15, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0533, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0534, .reg_data = 0x49, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0535, .reg_data = 0x26, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0536, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0537, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0538, .reg_data = 0x31, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0539, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x053A, .reg_data = 0x13, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x053B, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x053C, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x053D, .reg_data = 0x6D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x053E, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x053F, .reg_data = 0x49, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0540, .reg_data = 0x15, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0541, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0542, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0543, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0544, .reg_data = 0x13, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0545, .reg_data = 0x69, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0546, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0547, .reg_data = 0x4D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0548, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0549, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x054A, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x054B, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x054C, .reg_data = 0x9A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x054D, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x054E, .reg_data = 0x1A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x054F, .reg_data = 0x84, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0550, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0551, .reg_data = 0x54, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0552, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0553, .reg_data = 0x64, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0554, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0555, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0556, .reg_data = 0x13, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0557, .reg_data = 0xE2, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0558, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0559, .reg_data = 0x52, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x055A, .reg_data = 0x1A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x055B, .reg_data = 0xCA, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x055C, .reg_data = 0x13, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x055D, .reg_data = 0xD2, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x055E, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x055F, .reg_data = 0x72, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0560, .reg_data = 0x4A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0561, .reg_data = 0x13, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0562, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0563, .reg_data = 0x51, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0564, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0565, .reg_data = 0x91, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0566, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0567, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0568, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0569, .reg_data = 0xD2, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x056A, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x056B, .reg_data = 0x83, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x056C, .reg_data = 0x92, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x056D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x056E, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x056F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0570, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0571, .reg_data = 0xA3, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0572, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0573, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0574, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0575, .reg_data = 0xD2, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0576, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0577, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0578, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0579, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x057A, .reg_data = 0x92, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x057B, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x057C, .reg_data = 0xA9, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x057D, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x057E, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x057F, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0580, .reg_data = 0xF7, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0581, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0582, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0583, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0584, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0585, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0586, .reg_data = 0xFE, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0587, .reg_data = 0xF5, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0588, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0589, .reg_data = 0x3E, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x058A, .reg_data = 0xBD, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x058B, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x058C, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x058D, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x058E, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x058F, .reg_data = 0xB8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0590, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0591, .reg_data = 0xB8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0592, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0593, .reg_data = 0x3C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0594, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0595, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0596, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0597, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0598, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0599, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x059A, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x059B, .reg_data = 0x69, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x059C, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x059D, .reg_data = 0x1A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x059E, .reg_data = 0xB2, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x059F, .reg_data = 0x8B, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05A0, .reg_data = 0x62, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05A1, .reg_data = 0x71, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05A2, .reg_data = 0x62, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05A3, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05A4, .reg_data = 0xE7, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05A5, .reg_data = 0x91, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05A6, .reg_data = 0x62, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05A7, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05A8, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05A9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05AA, .reg_data = 0x17, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05AB, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05AC, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05AD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05AE, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05AF, .reg_data = 0xCD, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05B0, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05B1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05B2, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05B3, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05B4, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05B5, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05B6, .reg_data = 0x19, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05B7, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05B8, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05B9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05BA, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05BB, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05BC, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05BD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05BE, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05BF, .reg_data = 0x2C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05C0, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05C1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05C2, .reg_data = 0x53, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05C3, .reg_data = 0x2C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05C4, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05C5, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05C6, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05C7, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05C8, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05C9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05CA, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05CB, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05CC, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05CD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05CE, .reg_data = 0x1A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05CF, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05D0, .reg_data = 0xC8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05D1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05D2, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05D3, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05D4, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05D5, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05D6, .reg_data = 0x49, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05D7, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05D8, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05D9, .reg_data = 0x70, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05DA, .reg_data = 0x62, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05DB, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05DC, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05DD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05DE, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05DF, .reg_data = 0xC1, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05E0, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05E1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05E2, .reg_data = 0x1B, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05E3, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05E4, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05E5, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05E6, .reg_data = 0xB5, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05E7, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05E8, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05E9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05EA, .reg_data = 0x4B, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05EB, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05EC, .reg_data = 0xA9, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05ED, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05EE, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05EF, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05F0, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05F1, .reg_data = 0x98, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05F2, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05F3, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05F4, .reg_data = 0x49, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05F5, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05F6, .reg_data = 0x98, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05F7, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05F8, .reg_data = 0x72, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05F9, .reg_data = 0x8A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05FA, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05FB, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05FC, .reg_data = 0x72, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05FD, .reg_data = 0xC8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05FE, .reg_data = 0x0B, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x05FF, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0600, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0601, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0602, .reg_data = 0xBD, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0603, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0604, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0605, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0606, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0607, .reg_data = 0x24, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0608, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0609, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x060A, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x060B, .reg_data = 0x49, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x060C, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x060D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x060E, .reg_data = 0x1A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x060F, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0610, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0611, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0612, .reg_data = 0xB5, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0613, .reg_data = 0xFE, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0614, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0615, .reg_data = 0x16, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0616, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0617, .reg_data = 0x0B, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0618, .reg_data = 0x4D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0619, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x061A, .reg_data = 0x4C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x061B, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x061C, .reg_data = 0xF7, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x061D, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x061E, .reg_data = 0x5A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x061F, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0620, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0621, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0622, .reg_data = 0xFD, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0623, .reg_data = 0xD3, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0624, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0625, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0626, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0627, .reg_data = 0x31, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0628, .reg_data = 0x19, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0629, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x062A, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x062B, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x062C, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x062D, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x062E, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x062F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0630, .reg_data = 0xA9, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0631, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0632, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0633, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0634, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0635, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0636, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0637, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0638, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0639, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x063A, .reg_data = 0xBD, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x063B, .reg_data = 0xFE, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x063C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x063D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x063E, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x063F, .reg_data = 0xCD, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0640, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0641, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0642, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0643, .reg_data = 0xB5, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0644, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0645, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0646, .reg_data = 0x19, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0647, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0648, .reg_data = 0x49, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0649, .reg_data = 0x15, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x064A, .reg_data = 0xB5, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x064B, .reg_data = 0x7C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x064C, .reg_data = 0x4E, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x064D, .reg_data = 0x13, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x064E, .reg_data = 0x4A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x064F, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0650, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0651, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0652, .reg_data = 0x4D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0653, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0654, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0655, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0656, .reg_data = 0x91, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0657, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0658, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0659, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x065A, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x065B, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x065C, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x065D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x065E, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x065F, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0660, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0661, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0662, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0663, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0664, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0665, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0666, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0667, .reg_data = 0x69, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0668, .reg_data = 0x6A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0669, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x066A, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x066B, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x066C, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x066D, .reg_data = 0xFC, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x066E, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x066F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0670, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0671, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0672, .reg_data = 0x78, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0673, .reg_data = 0xE8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0674, .reg_data = 0x70, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0675, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0676, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0677, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0678, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0679, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x067A, .reg_data = 0xBD, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x067B, .reg_data = 0x7C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x067C, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x067D, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x067E, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x067F, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0680, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0681, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0682, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0683, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0684, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0685, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0686, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0687, .reg_data = 0x69, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0688, .reg_data = 0x6A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0689, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x068A, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x068B, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x068C, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x068D, .reg_data = 0xFC, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x068E, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x068F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0690, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0691, .reg_data = 0xEF, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0692, .reg_data = 0x78, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0693, .reg_data = 0xE8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0694, .reg_data = 0xE7, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0695, .reg_data = 0xEE, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0696, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0697, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0698, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0699, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x069A, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x069B, .reg_data = 0x15, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x069C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x069D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x069E, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x069F, .reg_data = 0xB5, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x06A0, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x06A1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x06A2, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x06A3, .reg_data = 0xF4, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x06A4, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x06A5, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x06A6, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x06A7, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x06A8, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x06A9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x06AA, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x06AB, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x06AC, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x06AD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x06AE, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x06AF, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x06B0, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x06B1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x06B2, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x06B3, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x06B4, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x06B5, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x06B6, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x06B7, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x06B8, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x06B9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x06BA, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x06BB, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x06BC, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x06BD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x06BE, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x06BF, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x06C0, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x06C1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x06C2, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x06C3, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x06C4, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x06C5, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x06C6, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x06C7, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x06C8, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x06C9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x06CA, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x06CB, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - }, - .size = 1740, //1096//1097//1483 - .addr_type = CAMERA_SENSOR_I2C_TYPE_WORD, - .data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, - .delay = 0, +.size = 1, +.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD, +.data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, +.delay = 1, }, -.init_setting = -{ - .reg_settings = - { - {.reg_addr = 0x1C00, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C01, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C02, .reg_data = 0x77, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C03, .reg_data = 0x7E, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C04, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C05, .reg_data = 0x15, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C06, .reg_data = 0x24, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C07, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C08, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C09, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C0A, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C0B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C0C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C0D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C0E, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C0F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C10, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C11, .reg_data = 0x45, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C12, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C13, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C14, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C15, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C16, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C17, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C18, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C19, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C1A, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C1B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C1C, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C1D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C1E, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C1F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C20, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C21, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C22, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C23, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C24, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C25, .reg_data = 0xEC, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C26, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C27, .reg_data = 0xEC, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C28, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C29, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C2A, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C2B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C2C, .reg_data = 0x0B, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C2D, .reg_data = 0x3F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C2E, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C2F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C30, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C31, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C32, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C33, .reg_data = 0x71, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C34, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C35, .reg_data = 0x27, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C36, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C37, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C38, .reg_data = 0x83, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C39, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C3A, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C3B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C3C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C3D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C3E, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C3F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C40, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C41, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C42, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C43, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C44, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C45, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C46, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C47, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C48, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C49, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C4A, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C4B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C4C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C4D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C4E, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C4F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C50, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C51, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C52, .reg_data = 0x70, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C53, .reg_data = 0x70, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C54, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C55, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C56, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C57, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C58, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C59, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C5A, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C5B, .reg_data = 0x66, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C5C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C5D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C5E, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C5F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C60, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C61, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C62, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C63, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C64, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C65, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C66, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C67, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C68, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C69, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C6A, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C6B, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C6C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C6D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C6E, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C6F, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C70, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C71, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C72, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C73, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C74, .reg_data = 0x82, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C75, .reg_data = 0xCE, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C76, .reg_data = 0x3D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C77, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C78, .reg_data = 0x82, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C79, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C7A, .reg_data = 0x3D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C7B, .reg_data = 0x2F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C7C, .reg_data = 0x3F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C7D, .reg_data = 0xFE, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C7E, .reg_data = 0x3F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C7F, .reg_data = 0xFC, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C80, .reg_data = 0x3F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C81, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C82, .reg_data = 0x3F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C83, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C84, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C85, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C86, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C87, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C88, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C89, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C8A, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C8B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C8C, .reg_data = 0x3E, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C8D, .reg_data = 0xFC, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C8E, .reg_data = 0xC1, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C8F, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C90, .reg_data = 0x7F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C91, .reg_data = 0xF8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C92, .reg_data = 0x7F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C93, .reg_data = 0xF8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C94, .reg_data = 0x1A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C95, .reg_data = 0x5E, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C96, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C97, .reg_data = 0xA5, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C98, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C99, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C9A, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C9B, .reg_data = 0x1B, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C9C, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C9D, .reg_data = 0xCE, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C9E, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1C9F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CA0, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CA1, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CA2, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CA3, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CA4, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CA5, .reg_data = 0x51, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CA6, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CA7, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CA8, .reg_data = 0x3F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CA9, .reg_data = 0xF2, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CAA, .reg_data = 0x3F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CAB, .reg_data = 0xF2, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CAC, .reg_data = 0x3F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CAD, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CAE, .reg_data = 0x7F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CAF, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CB0, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CB1, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CB2, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CB3, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CB4, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CB5, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CB6, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CB7, .reg_data = 0x9A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CB8, .reg_data = 0x6F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CB9, .reg_data = 0xF9, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CBA, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CBB, .reg_data = 0x6D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CBC, .reg_data = 0x7F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CBD, .reg_data = 0xA6, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CBE, .reg_data = 0x16, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CBF, .reg_data = 0xC1, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CC0, .reg_data = 0xDD, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CC1, .reg_data = 0x31, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CC2, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CC3, .reg_data = 0xD5, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CC4, .reg_data = 0x7A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CC5, .reg_data = 0xF7, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CC6, .reg_data = 0x89, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CC7, .reg_data = 0x99, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CC8, .reg_data = 0x3C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CC9, .reg_data = 0xAE, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CCA, .reg_data = 0x87, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CCB, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CCC, .reg_data = 0x3C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CCD, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CCE, .reg_data = 0x7F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CCF, .reg_data = 0x3A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CD0, .reg_data = 0x81, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CD1, .reg_data = 0x82, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CD2, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CD3, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CD4, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CD5, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CD6, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CD7, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CD8, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CD9, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CDA, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CDB, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CDC, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CDD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CDE, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CDF, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CE0, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CE1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CE2, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CE3, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CE4, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CE5, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CE6, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CE7, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CE8, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CE9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CEA, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CEB, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CEC, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CED, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CEE, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CEF, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CF0, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CF1, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CF2, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CF3, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CF4, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CF5, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CF6, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CF7, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CF8, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CF9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CFA, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CFB, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CFC, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CFD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CFE, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1CFF, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D00, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D01, .reg_data = 0x9D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D02, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D03, .reg_data = 0x9D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D04, .reg_data = 0xC6, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D05, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D06, .reg_data = 0xC6, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D07, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D08, .reg_data = 0x19, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D09, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D0A, .reg_data = 0x19, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D0B, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D0C, .reg_data = 0x7C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D0D, .reg_data = 0x5E, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D0E, .reg_data = 0x7C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D0F, .reg_data = 0x5E, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D10, .reg_data = 0x87, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D11, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D12, .reg_data = 0x87, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D13, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D14, .reg_data = 0x3C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D15, .reg_data = 0xAE, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D16, .reg_data = 0x3C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D17, .reg_data = 0xAE, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D18, .reg_data = 0x87, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D19, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D1A, .reg_data = 0x87, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D1B, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D1C, .reg_data = 0x3C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D1D, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D1E, .reg_data = 0x3C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D1F, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D20, .reg_data = 0x7F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D21, .reg_data = 0x3A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D22, .reg_data = 0x7F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D23, .reg_data = 0x3A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D24, .reg_data = 0x81, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D25, .reg_data = 0x82, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D26, .reg_data = 0x81, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D27, .reg_data = 0x82, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D28, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D29, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D2A, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D2B, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D2C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D2D, .reg_data = 0x1F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D2E, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D2F, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D30, .reg_data = 0x3C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D31, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D32, .reg_data = 0x3C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D33, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D34, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D35, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D36, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D37, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D38, .reg_data = 0x75, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D39, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D3A, .reg_data = 0x74, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D3B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D3C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D3D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D3E, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D3F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D40, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D41, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D42, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D43, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D44, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D45, .reg_data = 0x0E, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D46, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D47, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D48, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D49, .reg_data = 0x6D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D4A, .reg_data = 0x7F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D4B, .reg_data = 0xF4, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D4C, .reg_data = 0x82, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D4D, .reg_data = 0x83, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D4E, .reg_data = 0x81, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D4F, .reg_data = 0xA5, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D50, .reg_data = 0x3D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D51, .reg_data = 0x7D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D52, .reg_data = 0x3E, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D53, .reg_data = 0x5B, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D54, .reg_data = 0x82, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D55, .reg_data = 0x86, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D56, .reg_data = 0x81, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D57, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D58, .reg_data = 0x3D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D59, .reg_data = 0x7A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D5A, .reg_data = 0x3E, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D5B, .reg_data = 0x58, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D5C, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D5D, .reg_data = 0xFB, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D5E, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D5F, .reg_data = 0xFB, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D60, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D61, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D62, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D63, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D64, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D65, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D66, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1D67, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, - }, - .size = 360, - .addr_type = CAMERA_SENSOR_I2C_TYPE_WORD, - .data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, - .delay = 0, +.firmware = { +.reg_settings = { +{.reg_addr = 0x0000, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0001, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0002, .reg_data = 0xB5, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0003, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0004, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0005, .reg_data = 0x85, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0006, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0007, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0008, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0009, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x000A, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x000B, .reg_data = 0x24, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x000C, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x000D, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x000E, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x000F, .reg_data = 0x67, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0010, .reg_data = 0x4F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0011, .reg_data = 0x67, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0012, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0013, .reg_data = 0x67, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0014, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0015, .reg_data = 0x67, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0016, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0017, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0018, .reg_data = 0x37, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0019, .reg_data = 0xB4, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x001A, .reg_data = 0x4D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x001B, .reg_data = 0x63, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x001C, .reg_data = 0x42, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x001D, .reg_data = 0x84, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x001E, .reg_data = 0x26, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x001F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0020, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0021, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0022, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0023, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0024, .reg_data = 0xF9, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0025, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0026, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0027, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0028, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0029, .reg_data = 0x62, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x002A, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x002B, .reg_data = 0x24, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x002C, .reg_data = 0x42, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x002D, .reg_data = 0x84, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x002E, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x002F, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0030, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0031, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0032, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0033, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0034, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0035, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0036, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0037, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0038, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0039, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x003A, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x003B, .reg_data = 0x5E, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x003C, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x003D, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x003E, .reg_data = 0x42, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x003F, .reg_data = 0x84, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0040, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0041, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0042, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0043, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0044, .reg_data = 0xF9, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0045, .reg_data = 0x1F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0046, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0047, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0048, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0049, .reg_data = 0x5A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x004A, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x004B, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x004C, .reg_data = 0x42, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x004D, .reg_data = 0x84, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x004E, .reg_data = 0x1D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x004F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0050, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0051, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0052, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0053, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0054, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0055, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0056, .reg_data = 0x42, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0057, .reg_data = 0x84, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0058, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0059, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x005A, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x005B, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x005C, .reg_data = 0x49, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x005D, .reg_data = 0x56, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x005E, .reg_data = 0x1A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x005F, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0060, .reg_data = 0x13, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0061, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0062, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0063, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0064, .reg_data = 0xDD, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0065, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0066, .reg_data = 0x2E, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0067, .reg_data = 0x7F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0068, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0069, .reg_data = 0x99, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x006A, .reg_data = 0x26, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x006B, .reg_data = 0x7F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x006C, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x006D, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x006E, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x006F, .reg_data = 0x7F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0070, .reg_data = 0xDA, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0071, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0072, .reg_data = 0x42, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0073, .reg_data = 0x86, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0074, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0075, .reg_data = 0x93, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0076, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0077, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0078, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0079, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x007A, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x007B, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x007C, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x007D, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x007E, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x007F, .reg_data = 0x2D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0080, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0081, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0082, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0083, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0084, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0085, .reg_data = 0x8B, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0086, .reg_data = 0xFA, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0087, .reg_data = 0xAF, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0088, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0089, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x008A, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x008B, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x008C, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x008D, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x008E, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x008F, .reg_data = 0x3B, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0090, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0091, .reg_data = 0x4A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0092, .reg_data = 0xD8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0093, .reg_data = 0x17, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0094, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0095, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0096, .reg_data = 0x55, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0097, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0098, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0099, .reg_data = 0x3C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x009A, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x009B, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x009C, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x009D, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x009E, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x009F, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00A0, .reg_data = 0x31, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00A1, .reg_data = 0x3B, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00A2, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00A3, .reg_data = 0x8C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00A4, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00A5, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00A6, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00A7, .reg_data = 0x83, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00A8, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00A9, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00AA, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00AB, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00AC, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00AD, .reg_data = 0x3E, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00AE, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00AF, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00B0, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00B1, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00B2, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00B3, .reg_data = 0x76, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00B4, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00B5, .reg_data = 0x92, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00B6, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00B7, .reg_data = 0xA3, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00B8, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00B9, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00BA, .reg_data = 0x31, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00BB, .reg_data = 0x3D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00BC, .reg_data = 0xFA, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00BD, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00BE, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00BF, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00C0, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00C1, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00C2, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00C3, .reg_data = 0x6E, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00C4, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00C5, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00C6, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00C7, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00C8, .reg_data = 0xB2, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00C9, .reg_data = 0xCD, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00CA, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00CB, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00CC, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00CD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00CE, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00CF, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00D0, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00D1, .reg_data = 0x3A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00D2, .reg_data = 0xFA, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00D3, .reg_data = 0xBB, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00D4, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00D5, .reg_data = 0x63, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00D6, .reg_data = 0x55, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00D7, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00D8, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00D9, .reg_data = 0x1D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00DA, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00DB, .reg_data = 0x36, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00DC, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00DD, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00DE, .reg_data = 0x42, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00DF, .reg_data = 0x84, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00E0, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00E1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00E2, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00E3, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00E4, .reg_data = 0xE7, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00E5, .reg_data = 0xC5, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00E6, .reg_data = 0xF8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00E7, .reg_data = 0x73, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00E8, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00E9, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00EA, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00EB, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00EC, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00ED, .reg_data = 0x57, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00EE, .reg_data = 0x42, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00EF, .reg_data = 0x84, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00F0, .reg_data = 0xFA, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00F1, .reg_data = 0x70, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00F2, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00F3, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00F4, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00F5, .reg_data = 0xA1, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00F6, .reg_data = 0x24, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00F7, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00F8, .reg_data = 0x91, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00F9, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00FA, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00FB, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00FC, .reg_data = 0x4A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00FD, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00FE, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x00FF, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0100, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0101, .reg_data = 0x89, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0102, .reg_data = 0x99, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0103, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0104, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0105, .reg_data = 0x64, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0106, .reg_data = 0x62, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0107, .reg_data = 0xC8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0108, .reg_data = 0xDB, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0109, .reg_data = 0xF4, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x010A, .reg_data = 0x2C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x010B, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x010C, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x010D, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x010E, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x010F, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0110, .reg_data = 0x4C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0111, .reg_data = 0x2B, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0112, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0113, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0114, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0115, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0116, .reg_data = 0x34, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0117, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0118, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0119, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x011A, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x011B, .reg_data = 0x2C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x011C, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x011D, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x011E, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x011F, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0120, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0121, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0122, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0123, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0124, .reg_data = 0x4C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0125, .reg_data = 0x26, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0126, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0127, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0128, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0129, .reg_data = 0x34, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x012A, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x012B, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x012C, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x012D, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x012E, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x012F, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0130, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0131, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0132, .reg_data = 0x62, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0133, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0134, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0135, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0136, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0137, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0138, .reg_data = 0x34, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0139, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x013A, .reg_data = 0x4C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x013B, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x013C, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x013D, .reg_data = 0x4C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x013E, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x013F, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0140, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0141, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0142, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0143, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0144, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0145, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0146, .reg_data = 0x63, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0147, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0148, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0149, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x014A, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x014B, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x014C, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x014D, .reg_data = 0x1B, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x014E, .reg_data = 0x63, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x014F, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0150, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0151, .reg_data = 0x42, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0152, .reg_data = 0x78, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0153, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0154, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0155, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0156, .reg_data = 0x9A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0157, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0158, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0159, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x015A, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x015B, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x015C, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x015D, .reg_data = 0x2D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x015E, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x015F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0160, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0161, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0162, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0163, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0164, .reg_data = 0x2C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0165, .reg_data = 0x13, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0166, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0167, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0168, .reg_data = 0x4F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0169, .reg_data = 0x16, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x016A, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x016B, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x016C, .reg_data = 0x37, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x016D, .reg_data = 0xB4, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x016E, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x016F, .reg_data = 0x15, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0170, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0171, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0172, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0173, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0174, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0175, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0176, .reg_data = 0x9A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0177, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0178, .reg_data = 0x99, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0179, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x017A, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x017B, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x017C, .reg_data = 0x99, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x017D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x017E, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x017F, .reg_data = 0x88, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0180, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0181, .reg_data = 0x88, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0182, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0183, .reg_data = 0x0B, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0184, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0185, .reg_data = 0xB8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0186, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0187, .reg_data = 0x13, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0188, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0189, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x018A, .reg_data = 0x99, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x018B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x018C, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x018D, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x018E, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x018F, .reg_data = 0x88, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0190, .reg_data = 0x2D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0191, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0192, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0193, .reg_data = 0xB8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0194, .reg_data = 0x99, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0195, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0196, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0197, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0198, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0199, .reg_data = 0x88, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x019A, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x019B, .reg_data = 0x1F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x019C, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x019D, .reg_data = 0xB8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x019E, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x019F, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01A0, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01A1, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01A2, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01A3, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01A4, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01A5, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01A6, .reg_data = 0xBD, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01A7, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01A8, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01A9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01AA, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01AB, .reg_data = 0x15, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01AC, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01AD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01AE, .reg_data = 0x54, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01AF, .reg_data = 0xBD, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01B0, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01B1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01B2, .reg_data = 0x29, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01B3, .reg_data = 0xD9, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01B4, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01B5, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01B6, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01B7, .reg_data = 0x2D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01B8, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01B9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01BA, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01BB, .reg_data = 0xAA, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01BC, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01BD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01BE, .reg_data = 0x19, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01BF, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01C0, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01C1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01C2, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01C3, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01C4, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01C5, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01C6, .reg_data = 0x2B, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01C7, .reg_data = 0x25, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01C8, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01C9, .reg_data = 0x70, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01CA, .reg_data = 0xBA, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01CB, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01CC, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01CD, .reg_data = 0x86, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01CE, .reg_data = 0xB5, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01CF, .reg_data = 0xF1, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01D0, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01D1, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01D2, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01D3, .reg_data = 0x5F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01D4, .reg_data = 0x4C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01D5, .reg_data = 0x5F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01D6, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01D7, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01D8, .reg_data = 0x27, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01D9, .reg_data = 0x7D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01DA, .reg_data = 0x78, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01DB, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01DC, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01DD, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01DE, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01DF, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01E0, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01E1, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01E2, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01E3, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01E4, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01E5, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01E6, .reg_data = 0x26, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01E7, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01E8, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01E9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01EA, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01EB, .reg_data = 0x8C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01EC, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01ED, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01EE, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01EF, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01F0, .reg_data = 0x15, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01F1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01F2, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01F3, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01F4, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01F5, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01F6, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01F7, .reg_data = 0x92, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01F8, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01F9, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01FA, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01FB, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01FC, .reg_data = 0x15, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01FD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01FE, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x01FF, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0200, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0201, .reg_data = 0x55, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0202, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0203, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0204, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0205, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0206, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0207, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0208, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0209, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x020A, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x020B, .reg_data = 0x54, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x020C, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x020D, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x020E, .reg_data = 0x99, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x020F, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0210, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0211, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0212, .reg_data = 0x99, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0213, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0214, .reg_data = 0xD5, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0215, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0216, .reg_data = 0x1A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0217, .reg_data = 0x44, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0218, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0219, .reg_data = 0x51, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x021A, .reg_data = 0x42, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x021B, .reg_data = 0x64, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x021C, .reg_data = 0x99, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x021D, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x021E, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x021F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0220, .reg_data = 0x99, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0221, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0222, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0223, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0224, .reg_data = 0x1A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0225, .reg_data = 0x45, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0226, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0227, .reg_data = 0x49, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0228, .reg_data = 0x42, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0229, .reg_data = 0x6D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x022A, .reg_data = 0xD5, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x022B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x022C, .reg_data = 0xDC, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x022D, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x022E, .reg_data = 0x2C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x022F, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0230, .reg_data = 0xDD, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0231, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0232, .reg_data = 0x2D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0233, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0234, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0235, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0236, .reg_data = 0x26, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0237, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0238, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0239, .reg_data = 0x19, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x023A, .reg_data = 0x1E, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x023B, .reg_data = 0x76, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x023C, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x023D, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x023E, .reg_data = 0x99, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x023F, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0240, .reg_data = 0x1E, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0241, .reg_data = 0x7F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0242, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0243, .reg_data = 0x88, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0244, .reg_data = 0x98, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0245, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0246, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0247, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0248, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0249, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x024A, .reg_data = 0x7F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x024B, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x024C, .reg_data = 0x99, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x024D, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x024E, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x024F, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0250, .reg_data = 0x98, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0251, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0252, .reg_data = 0x77, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0253, .reg_data = 0xC8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0254, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0255, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0256, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0257, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0258, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0259, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x025A, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x025B, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x025C, .reg_data = 0xDD, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x025D, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x025E, .reg_data = 0x2C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x025F, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0260, .reg_data = 0xDD, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0261, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0262, .reg_data = 0x2D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0263, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0264, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0265, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0266, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0267, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0268, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0269, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x026A, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x026B, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x026C, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x026D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x026E, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x026F, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0270, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0271, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0272, .reg_data = 0x98, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0273, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0274, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0275, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0276, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0277, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0278, .reg_data = 0x99, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0279, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x027A, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x027B, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x027C, .reg_data = 0x76, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x027D, .reg_data = 0xC8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x027E, .reg_data = 0x98, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x027F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0280, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0281, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0282, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0283, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0284, .reg_data = 0xB5, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0285, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0286, .reg_data = 0xBD, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0287, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0288, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0289, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x028A, .reg_data = 0x4A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x028B, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x028C, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x028D, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x028E, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x028F, .reg_data = 0x24, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0290, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0291, .reg_data = 0x44, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0292, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0293, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0294, .reg_data = 0xBD, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0295, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0296, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0297, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0298, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0299, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x029A, .reg_data = 0xB5, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x029B, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x029C, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x029D, .reg_data = 0x89, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x029E, .reg_data = 0x4E, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x029F, .reg_data = 0x2D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02A0, .reg_data = 0x36, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02A1, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02A2, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02A3, .reg_data = 0x31, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02A4, .reg_data = 0x1D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02A5, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02A6, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02A7, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02A8, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02A9, .reg_data = 0xF8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02AA, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02AB, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02AC, .reg_data = 0x4D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02AD, .reg_data = 0x2D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02AE, .reg_data = 0x4C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02AF, .reg_data = 0x29, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02B0, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02B1, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02B2, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02B3, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02B4, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02B5, .reg_data = 0x54, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02B6, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02B7, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02B8, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02B9, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02BA, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02BB, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02BC, .reg_data = 0x98, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02BD, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02BE, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02BF, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02C0, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02C1, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02C2, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02C3, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02C4, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02C5, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02C6, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02C7, .reg_data = 0x58, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02C8, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02C9, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02CA, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02CB, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02CC, .reg_data = 0xA9, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02CD, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02CE, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02CF, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02D0, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02D1, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02D2, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02D3, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02D4, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02D5, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02D6, .reg_data = 0x2F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02D7, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02D8, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02D9, .reg_data = 0x4C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02DA, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02DB, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02DC, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02DD, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02DE, .reg_data = 0xE7, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02DF, .reg_data = 0xEC, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02E0, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02E1, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02E2, .reg_data = 0xE7, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02E3, .reg_data = 0xF1, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02E4, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02E5, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02E6, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02E7, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02E8, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02E9, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02EA, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02EB, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02EC, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02ED, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02EE, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02EF, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02F0, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02F1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02F2, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02F3, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02F4, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02F5, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02F6, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02F7, .reg_data = 0x44, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02F8, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02F9, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02FA, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02FB, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02FC, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02FD, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02FE, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x02FF, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0300, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0301, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0302, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0303, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0304, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0305, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0306, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0307, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0308, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0309, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x030A, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x030B, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x030C, .reg_data = 0x91, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x030D, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x030E, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x030F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0310, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0311, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0312, .reg_data = 0x1D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0313, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0314, .reg_data = 0x24, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0315, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0316, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0317, .reg_data = 0x15, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0318, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0319, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x031A, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x031B, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x031C, .reg_data = 0x27, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x031D, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x031E, .reg_data = 0x1D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x031F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0320, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0321, .reg_data = 0x3F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0322, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0323, .reg_data = 0x6E, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0324, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0325, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0326, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0327, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0328, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0329, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x032A, .reg_data = 0x2C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x032B, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x032C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x032D, .reg_data = 0x81, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x032E, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x032F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0330, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0331, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0332, .reg_data = 0x58, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0333, .reg_data = 0x72, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0334, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0335, .reg_data = 0x72, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0336, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0337, .reg_data = 0x3A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0338, .reg_data = 0xDB, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0339, .reg_data = 0xF8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x033A, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x033B, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x033C, .reg_data = 0xA9, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x033D, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x033E, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x033F, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0340, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0341, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0342, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0343, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0344, .reg_data = 0x2C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0345, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0346, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0347, .reg_data = 0x64, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0348, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0349, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x034A, .reg_data = 0xDB, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x034B, .reg_data = 0xEE, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x034C, .reg_data = 0xBD, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x034D, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x034E, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x034F, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0350, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0351, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0352, .reg_data = 0x54, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0353, .reg_data = 0xBD, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0354, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0355, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0356, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0357, .reg_data = 0xCD, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0358, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0359, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x035A, .reg_data = 0x19, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x035B, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x035C, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x035D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x035E, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x035F, .reg_data = 0xBC, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0360, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0361, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0362, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0363, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0364, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0365, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0366, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0367, .reg_data = 0xB5, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0368, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0369, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x036A, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x036B, .reg_data = 0x78, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x036C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x036D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x036E, .reg_data = 0x42, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x036F, .reg_data = 0x88, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0370, .reg_data = 0x24, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0371, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0372, .reg_data = 0xB5, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0373, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0374, .reg_data = 0x2A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0375, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0376, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0377, .reg_data = 0xE4, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0378, .reg_data = 0x23, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0379, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x037A, .reg_data = 0xDC, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x037B, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x037C, .reg_data = 0x6A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x037D, .reg_data = 0x5B, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x037E, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x037F, .reg_data = 0x9B, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0380, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0381, .reg_data = 0x9B, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0382, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0383, .reg_data = 0x9B, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0384, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0385, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0386, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0387, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0388, .reg_data = 0x23, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0389, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x038A, .reg_data = 0xBD, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x038B, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x038C, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x038D, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x038E, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x038F, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0390, .reg_data = 0x4E, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0391, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0392, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0393, .reg_data = 0x9D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0394, .reg_data = 0x19, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0395, .reg_data = 0xAE, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0396, .reg_data = 0x59, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0397, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0398, .reg_data = 0x59, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0399, .reg_data = 0x4D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x039A, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x039B, .reg_data = 0x37, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x039C, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x039D, .reg_data = 0x1E, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x039E, .reg_data = 0x63, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x039F, .reg_data = 0xB5, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03A0, .reg_data = 0x25, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03A1, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03A2, .reg_data = 0x36, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03A3, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03A4, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03A5, .reg_data = 0x2C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03A6, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03A7, .reg_data = 0xB5, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03A8, .reg_data = 0x42, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03A9, .reg_data = 0x93, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03AA, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03AB, .reg_data = 0x5B, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03AC, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03AD, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03AE, .reg_data = 0xDB, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03AF, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03B0, .reg_data = 0x6A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03B1, .reg_data = 0x41, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03B2, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03B3, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03B4, .reg_data = 0x62, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03B5, .reg_data = 0x41, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03B6, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03B7, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03B8, .reg_data = 0xBD, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03B9, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03BA, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03BB, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03BC, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03BD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03BE, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03BF, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03C0, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03C1, .reg_data = 0x79, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03C2, .reg_data = 0xB5, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03C3, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03C4, .reg_data = 0x69, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03C5, .reg_data = 0xC2, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03C6, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03C7, .reg_data = 0x85, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03C8, .reg_data = 0x4B, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03C9, .reg_data = 0x77, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03CA, .reg_data = 0x4C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03CB, .reg_data = 0x77, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03CC, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03CD, .reg_data = 0xA4, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03CE, .reg_data = 0x34, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03CF, .reg_data = 0x78, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03D0, .reg_data = 0x49, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03D1, .reg_data = 0x75, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03D2, .reg_data = 0x1D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03D3, .reg_data = 0x24, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03D4, .reg_data = 0x4C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03D5, .reg_data = 0x75, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03D6, .reg_data = 0x94, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03D7, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03D8, .reg_data = 0x31, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03D9, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03DA, .reg_data = 0x33, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03DB, .reg_data = 0x98, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03DC, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03DD, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03DE, .reg_data = 0x4F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03DF, .reg_data = 0x73, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03E0, .reg_data = 0x34, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03E1, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03E2, .reg_data = 0x4E, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03E3, .reg_data = 0x72, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03E4, .reg_data = 0x37, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03E5, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03E6, .reg_data = 0x78, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03E7, .reg_data = 0x1B, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03E8, .reg_data = 0x2B, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03E9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03EA, .reg_data = 0x4D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03EB, .reg_data = 0x71, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03EC, .reg_data = 0x78, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03ED, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03EE, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03EF, .reg_data = 0x74, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03F0, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03F1, .reg_data = 0x71, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03F2, .reg_data = 0x29, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03F3, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03F4, .reg_data = 0x78, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03F5, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03F6, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03F7, .reg_data = 0x91, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03F8, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03F9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03FA, .reg_data = 0x0E, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03FB, .reg_data = 0x89, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03FC, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03FD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03FE, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x03FF, .reg_data = 0x6C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0400, .reg_data = 0x29, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0401, .reg_data = 0x39, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0402, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0403, .reg_data = 0x6C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0404, .reg_data = 0x29, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0405, .reg_data = 0x3D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0406, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0407, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0408, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0409, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x040A, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x040B, .reg_data = 0x49, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x040C, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x040D, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x040E, .reg_data = 0x78, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x040F, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0410, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0411, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0412, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0413, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0414, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0415, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0416, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0417, .reg_data = 0x2A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0418, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0419, .reg_data = 0xEA, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x041A, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x041B, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x041C, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x041D, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x041E, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x041F, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0420, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0421, .reg_data = 0x59, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0422, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0423, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0424, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0425, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0426, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0427, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0428, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0429, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x042A, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x042B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x042C, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x042D, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x042E, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x042F, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0430, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0431, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0432, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0433, .reg_data = 0xE8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0434, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0435, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0436, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0437, .reg_data = 0xE8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0438, .reg_data = 0x1E, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0439, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x043A, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x043B, .reg_data = 0x15, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x043C, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x043D, .reg_data = 0x4A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x043E, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x043F, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0440, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0441, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0442, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0443, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0444, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0445, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0446, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0447, .reg_data = 0xE8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0448, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0449, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x044A, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x044B, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x044C, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x044D, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x044E, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x044F, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0450, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0451, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0452, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0453, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0454, .reg_data = 0x98, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0455, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0456, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0457, .reg_data = 0x69, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0458, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0459, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x045A, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x045B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x045C, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x045D, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x045E, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x045F, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0460, .reg_data = 0x69, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0461, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0462, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0463, .reg_data = 0x0B, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0464, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0465, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0466, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0467, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0468, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0469, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x046A, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x046B, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x046C, .reg_data = 0xE7, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x046D, .reg_data = 0xF2, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x046E, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x046F, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0470, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0471, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0472, .reg_data = 0x69, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0473, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0474, .reg_data = 0x1E, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0475, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0476, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0477, .reg_data = 0x0E, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0478, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0479, .reg_data = 0x4A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x047A, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x047B, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x047C, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x047D, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x047E, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x047F, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0480, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0481, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0482, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0483, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0484, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0485, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0486, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0487, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0488, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0489, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x048A, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x048B, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x048C, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x048D, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x048E, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x048F, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0490, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0491, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0492, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0493, .reg_data = 0xA9, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0494, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0495, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0496, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0497, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0498, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0499, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x049A, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x049B, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x049C, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x049D, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x049E, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x049F, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04A0, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04A1, .reg_data = 0x89, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04A2, .reg_data = 0x4B, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04A3, .reg_data = 0x45, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04A4, .reg_data = 0x1D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04A5, .reg_data = 0x1B, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04A6, .reg_data = 0x63, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04A7, .reg_data = 0x0B, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04A8, .reg_data = 0x1D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04A9, .reg_data = 0x1B, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04AA, .reg_data = 0x63, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04AB, .reg_data = 0x4B, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04AC, .reg_data = 0x4B, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04AD, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04AE, .reg_data = 0x63, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04AF, .reg_data = 0x8B, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04B0, .reg_data = 0x4E, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04B1, .reg_data = 0x44, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04B2, .reg_data = 0x63, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04B3, .reg_data = 0xCB, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04B4, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04B5, .reg_data = 0x31, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04B6, .reg_data = 0x49, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04B7, .reg_data = 0x42, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04B8, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04B9, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04BA, .reg_data = 0x78, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04BB, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04BC, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04BD, .reg_data = 0x64, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04BE, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04BF, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04C0, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04C1, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04C2, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04C3, .reg_data = 0x41, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04C4, .reg_data = 0x62, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04C5, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04C6, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04C7, .reg_data = 0xF2, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04C8, .reg_data = 0x62, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04C9, .reg_data = 0xB2, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04CA, .reg_data = 0x62, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04CB, .reg_data = 0x72, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04CC, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04CD, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04CE, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04CF, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04D0, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04D1, .reg_data = 0x1F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04D2, .reg_data = 0x6A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04D3, .reg_data = 0x41, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04D4, .reg_data = 0x62, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04D5, .reg_data = 0x41, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04D6, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04D7, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04D8, .reg_data = 0x7B, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04D9, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04DA, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04DB, .reg_data = 0x3C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04DC, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04DD, .reg_data = 0x52, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04DE, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04DF, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04E0, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04E1, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04E2, .reg_data = 0x49, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04E3, .reg_data = 0x33, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04E4, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04E5, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04E6, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04E7, .reg_data = 0xC2, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04E8, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04E9, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04EA, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04EB, .reg_data = 0xD2, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04EC, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04ED, .reg_data = 0x4A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04EE, .reg_data = 0x2A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04EF, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04F0, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04F1, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04F2, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04F3, .reg_data = 0x94, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04F4, .reg_data = 0x4D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04F5, .reg_data = 0x2E, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04F6, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04F7, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04F8, .reg_data = 0x35, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04F9, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04FA, .reg_data = 0xB2, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04FB, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04FC, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04FD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04FE, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x04FF, .reg_data = 0x29, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0500, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0501, .reg_data = 0x5C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0502, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0503, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0504, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0505, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0506, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0507, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0508, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0509, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x050A, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x050B, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x050C, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x050D, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x050E, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x050F, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0510, .reg_data = 0x92, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0511, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0512, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0513, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0514, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0515, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0516, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0517, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0518, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0519, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x051A, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x051B, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x051C, .reg_data = 0x6A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x051D, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x051E, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x051F, .reg_data = 0x2C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0520, .reg_data = 0x6A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0521, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0522, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0523, .reg_data = 0x41, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0524, .reg_data = 0x1A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0525, .reg_data = 0x44, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0526, .reg_data = 0x1A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0527, .reg_data = 0x67, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0528, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0529, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x052A, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x052B, .reg_data = 0x29, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x052C, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x052D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x052E, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x052F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0530, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0531, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0532, .reg_data = 0x15, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0533, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0534, .reg_data = 0x49, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0535, .reg_data = 0x26, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0536, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0537, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0538, .reg_data = 0x31, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0539, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x053A, .reg_data = 0x13, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x053B, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x053C, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x053D, .reg_data = 0x6D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x053E, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x053F, .reg_data = 0x49, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0540, .reg_data = 0x15, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0541, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0542, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0543, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0544, .reg_data = 0x13, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0545, .reg_data = 0x69, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0546, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0547, .reg_data = 0x4D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0548, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0549, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x054A, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x054B, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x054C, .reg_data = 0x9A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x054D, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x054E, .reg_data = 0x1A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x054F, .reg_data = 0x84, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0550, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0551, .reg_data = 0x54, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0552, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0553, .reg_data = 0x64, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0554, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0555, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0556, .reg_data = 0x13, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0557, .reg_data = 0xE2, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0558, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0559, .reg_data = 0x52, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x055A, .reg_data = 0x1A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x055B, .reg_data = 0xCA, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x055C, .reg_data = 0x13, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x055D, .reg_data = 0xD2, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x055E, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x055F, .reg_data = 0x72, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0560, .reg_data = 0x4A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0561, .reg_data = 0x13, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0562, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0563, .reg_data = 0x51, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0564, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0565, .reg_data = 0x91, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0566, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0567, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0568, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0569, .reg_data = 0xD2, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x056A, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x056B, .reg_data = 0x83, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x056C, .reg_data = 0x92, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x056D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x056E, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x056F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0570, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0571, .reg_data = 0xA3, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0572, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0573, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0574, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0575, .reg_data = 0xD2, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0576, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0577, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0578, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0579, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x057A, .reg_data = 0x92, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x057B, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x057C, .reg_data = 0xA9, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x057D, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x057E, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x057F, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0580, .reg_data = 0xF7, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0581, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0582, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0583, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0584, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0585, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0586, .reg_data = 0xFE, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0587, .reg_data = 0xF5, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0588, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0589, .reg_data = 0x3E, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x058A, .reg_data = 0xBD, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x058B, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x058C, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x058D, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x058E, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x058F, .reg_data = 0xB8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0590, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0591, .reg_data = 0xB8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0592, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0593, .reg_data = 0x3C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0594, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0595, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0596, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0597, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0598, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0599, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x059A, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x059B, .reg_data = 0x69, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x059C, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x059D, .reg_data = 0x1A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x059E, .reg_data = 0xB2, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x059F, .reg_data = 0x8B, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05A0, .reg_data = 0x62, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05A1, .reg_data = 0x71, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05A2, .reg_data = 0x62, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05A3, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05A4, .reg_data = 0xE7, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05A5, .reg_data = 0x91, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05A6, .reg_data = 0x62, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05A7, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05A8, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05A9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05AA, .reg_data = 0x17, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05AB, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05AC, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05AD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05AE, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05AF, .reg_data = 0xCD, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05B0, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05B1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05B2, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05B3, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05B4, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05B5, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05B6, .reg_data = 0x19, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05B7, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05B8, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05B9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05BA, .reg_data = 0x61, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05BB, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05BC, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05BD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05BE, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05BF, .reg_data = 0x2C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05C0, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05C1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05C2, .reg_data = 0x53, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05C3, .reg_data = 0x2C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05C4, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05C5, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05C6, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05C7, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05C8, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05C9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05CA, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05CB, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05CC, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05CD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05CE, .reg_data = 0x1A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05CF, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05D0, .reg_data = 0xC8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05D1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05D2, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05D3, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05D4, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05D5, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05D6, .reg_data = 0x49, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05D7, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05D8, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05D9, .reg_data = 0x70, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05DA, .reg_data = 0x62, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05DB, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05DC, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05DD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05DE, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05DF, .reg_data = 0xC1, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05E0, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05E1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05E2, .reg_data = 0x1B, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05E3, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05E4, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05E5, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05E6, .reg_data = 0xB5, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05E7, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05E8, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05E9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05EA, .reg_data = 0x4B, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05EB, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05EC, .reg_data = 0xA9, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05ED, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05EE, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05EF, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05F0, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05F1, .reg_data = 0x98, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05F2, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05F3, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05F4, .reg_data = 0x49, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05F5, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05F6, .reg_data = 0x98, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05F7, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05F8, .reg_data = 0x72, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05F9, .reg_data = 0x8A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05FA, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05FB, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05FC, .reg_data = 0x72, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05FD, .reg_data = 0xC8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05FE, .reg_data = 0x0B, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x05FF, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0600, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0601, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0602, .reg_data = 0xBD, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0603, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0604, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0605, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0606, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0607, .reg_data = 0x24, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0608, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0609, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x060A, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x060B, .reg_data = 0x49, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x060C, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x060D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x060E, .reg_data = 0x1A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x060F, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0610, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0611, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0612, .reg_data = 0xB5, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0613, .reg_data = 0xFE, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0614, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0615, .reg_data = 0x16, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0616, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0617, .reg_data = 0x0B, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0618, .reg_data = 0x4D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0619, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x061A, .reg_data = 0x4C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x061B, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x061C, .reg_data = 0xF7, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x061D, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x061E, .reg_data = 0x5A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x061F, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0620, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0621, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0622, .reg_data = 0xFD, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0623, .reg_data = 0xD3, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0624, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0625, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0626, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0627, .reg_data = 0x31, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0628, .reg_data = 0x19, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0629, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x062A, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x062B, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x062C, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x062D, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x062E, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x062F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0630, .reg_data = 0xA9, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0631, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0632, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0633, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0634, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0635, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0636, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0637, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0638, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0639, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x063A, .reg_data = 0xBD, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x063B, .reg_data = 0xFE, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x063C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x063D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x063E, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x063F, .reg_data = 0xCD, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0640, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0641, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0642, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0643, .reg_data = 0xB5, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0644, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0645, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0646, .reg_data = 0x19, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0647, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0648, .reg_data = 0x49, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0649, .reg_data = 0x15, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x064A, .reg_data = 0xB5, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x064B, .reg_data = 0x7C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x064C, .reg_data = 0x4E, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x064D, .reg_data = 0x13, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x064E, .reg_data = 0x4A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x064F, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0650, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0651, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0652, .reg_data = 0x4D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0653, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0654, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0655, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0656, .reg_data = 0x91, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0657, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0658, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0659, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x065A, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x065B, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x065C, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x065D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x065E, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x065F, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0660, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0661, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0662, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0663, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0664, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0665, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0666, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0667, .reg_data = 0x69, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0668, .reg_data = 0x6A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0669, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x066A, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x066B, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x066C, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x066D, .reg_data = 0xFC, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x066E, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x066F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0670, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0671, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0672, .reg_data = 0x78, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0673, .reg_data = 0xE8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0674, .reg_data = 0x70, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0675, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0676, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0677, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0678, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0679, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x067A, .reg_data = 0xBD, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x067B, .reg_data = 0x7C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x067C, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x067D, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x067E, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x067F, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0680, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0681, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0682, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0683, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0684, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0685, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0686, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0687, .reg_data = 0x69, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0688, .reg_data = 0x6A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0689, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x068A, .reg_data = 0x47, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x068B, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x068C, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x068D, .reg_data = 0xFC, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x068E, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x068F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0690, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0691, .reg_data = 0xEF, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0692, .reg_data = 0x78, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0693, .reg_data = 0xE8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0694, .reg_data = 0xE7, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0695, .reg_data = 0xEE, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0696, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0697, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0698, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0699, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x069A, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x069B, .reg_data = 0x15, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x069C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x069D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x069E, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x069F, .reg_data = 0xB5, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x06A0, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x06A1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x06A2, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x06A3, .reg_data = 0xF4, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x06A4, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x06A5, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x06A6, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x06A7, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x06A8, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x06A9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x06AA, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x06AB, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x06AC, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x06AD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x06AE, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x06AF, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x06B0, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x06B1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x06B2, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x06B3, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x06B4, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x06B5, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x06B6, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x06B7, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x06B8, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x06B9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x06BA, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x06BB, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x06BC, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x06BD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x06BE, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x06BF, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x06C0, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x06C1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x06C2, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x06C3, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x06C4, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x06C5, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x06C6, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x06C7, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x06C8, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x06C9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x06CA, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x06CB, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, }, -.calib_data = -{ - .reg_settings = - { - {.reg_addr = 0x1DC0, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1DC1, .reg_data = 0x24, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1DC2, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1DC3, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1DC4, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1DC5, .reg_data = 0xea, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1DC6, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1DC7, .reg_data = 0xec, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1DC8, .reg_data = 0xff, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1DC9, .reg_data = 0x5f, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1DCA, .reg_data = 0xff, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1DCB, .reg_data = 0xc3, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1DCC, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1DCD, .reg_data = 0x35, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1DCE, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1DCF, .reg_data = 0x23, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1DD0, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1DD1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1DD2, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1DD3, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1DD4, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1DD5, .reg_data = 0x6a, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1DD6, .reg_data = 0x0d, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1DD7, .reg_data = 0x70, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1DD8, .reg_data = 0x0e, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1DD9, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1DDA, .reg_data = 0xc9, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1DDB, .reg_data = 0x0a, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1DDC, .reg_data = 0xc9, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1DDD, .reg_data = 0x0a, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1DDE, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1DDF, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1DE0, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1DE1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1DE2, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1DE3, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1DE4, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x1DE5, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xF006, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - }, - .size = 39, - .addr_type = CAMERA_SENSOR_I2C_TYPE_WORD, - .data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, - .delay = 0, +.size = 1740, //1096//1097//1483 +.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD, +.data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, +.delay = 0, }, -.control_data_0 = -{ - .reg_settings = - { - {.reg_addr = 0x6020, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00},// servo on - }, - .size = 1, - .addr_type = CAMERA_SENSOR_I2C_TYPE_WORD, - .data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, - .delay = 100, +.init_setting = { +.reg_settings = { +{.reg_addr = 0x1C00, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C01, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C02, .reg_data = 0x77, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C03, .reg_data = 0x7E, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C04, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C05, .reg_data = 0x15, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C06, .reg_data = 0x24, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C07, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C08, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C09, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C0A, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C0B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C0C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C0D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C0E, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C0F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C10, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C11, .reg_data = 0x45, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C12, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C13, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C14, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C15, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C16, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C17, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C18, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C19, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C1A, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C1B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C1C, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C1D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C1E, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C1F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C20, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C21, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C22, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C23, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C24, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C25, .reg_data = 0xEC, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C26, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C27, .reg_data = 0xEC, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C28, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C29, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C2A, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C2B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C2C, .reg_data = 0x0B, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C2D, .reg_data = 0x3F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C2E, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C2F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C30, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C31, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C32, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C33, .reg_data = 0x71, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C34, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C35, .reg_data = 0x27, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C36, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C37, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C38, .reg_data = 0x83, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C39, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C3A, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C3B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C3C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C3D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C3E, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C3F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C40, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C41, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C42, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C43, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C44, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C45, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C46, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C47, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C48, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C49, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C4A, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C4B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C4C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C4D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C4E, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C4F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C50, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C51, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C52, .reg_data = 0x70, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C53, .reg_data = 0x70, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C54, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C55, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C56, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C57, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C58, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C59, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C5A, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C5B, .reg_data = 0x66, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C5C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C5D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C5E, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C5F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C60, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C61, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C62, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C63, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C64, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C65, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C66, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C67, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C68, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C69, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C6A, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C6B, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C6C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C6D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C6E, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C6F, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C70, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C71, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C72, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C73, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C74, .reg_data = 0x82, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C75, .reg_data = 0xCE, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C76, .reg_data = 0x3D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C77, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C78, .reg_data = 0x82, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C79, .reg_data = 0xD1, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C7A, .reg_data = 0x3D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C7B, .reg_data = 0x2F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C7C, .reg_data = 0x3F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C7D, .reg_data = 0xFE, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C7E, .reg_data = 0x3F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C7F, .reg_data = 0xFC, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C80, .reg_data = 0x3F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C81, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C82, .reg_data = 0x3F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C83, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C84, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C85, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C86, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C87, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C88, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C89, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C8A, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C8B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C8C, .reg_data = 0x3E, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C8D, .reg_data = 0xFC, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C8E, .reg_data = 0xC1, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C8F, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C90, .reg_data = 0x7F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C91, .reg_data = 0xF8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C92, .reg_data = 0x7F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C93, .reg_data = 0xF8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C94, .reg_data = 0x1A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C95, .reg_data = 0x5E, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C96, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C97, .reg_data = 0xA5, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C98, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C99, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C9A, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C9B, .reg_data = 0x1B, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C9C, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C9D, .reg_data = 0xCE, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C9E, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1C9F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CA0, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CA1, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CA2, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CA3, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CA4, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CA5, .reg_data = 0x51, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CA6, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CA7, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CA8, .reg_data = 0x3F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CA9, .reg_data = 0xF2, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CAA, .reg_data = 0x3F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CAB, .reg_data = 0xF2, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CAC, .reg_data = 0x3F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CAD, .reg_data = 0xE0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CAE, .reg_data = 0x7F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CAF, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CB0, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CB1, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CB2, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CB3, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CB4, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CB5, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CB6, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CB7, .reg_data = 0x9A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CB8, .reg_data = 0x6F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CB9, .reg_data = 0xF9, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CBA, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CBB, .reg_data = 0x6D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CBC, .reg_data = 0x7F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CBD, .reg_data = 0xA6, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CBE, .reg_data = 0x16, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CBF, .reg_data = 0xC1, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CC0, .reg_data = 0xDD, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CC1, .reg_data = 0x31, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CC2, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CC3, .reg_data = 0xD5, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CC4, .reg_data = 0x7A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CC5, .reg_data = 0xF7, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CC6, .reg_data = 0x89, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CC7, .reg_data = 0x99, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CC8, .reg_data = 0x3C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CC9, .reg_data = 0xAE, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CCA, .reg_data = 0x87, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CCB, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CCC, .reg_data = 0x3C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CCD, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CCE, .reg_data = 0x7F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CCF, .reg_data = 0x3A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CD0, .reg_data = 0x81, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CD1, .reg_data = 0x82, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CD2, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CD3, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CD4, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CD5, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CD6, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CD7, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CD8, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CD9, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CDA, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CDB, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CDC, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CDD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CDE, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CDF, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CE0, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CE1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CE2, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CE3, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CE4, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CE5, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CE6, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CE7, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CE8, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CE9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CEA, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CEB, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CEC, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CED, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CEE, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CEF, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CF0, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CF1, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CF2, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CF3, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CF4, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CF5, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CF6, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CF7, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CF8, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CF9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CFA, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CFB, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CFC, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CFD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CFE, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1CFF, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D00, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D01, .reg_data = 0x9D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D02, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D03, .reg_data = 0x9D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D04, .reg_data = 0xC6, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D05, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D06, .reg_data = 0xC6, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D07, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D08, .reg_data = 0x19, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D09, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D0A, .reg_data = 0x19, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D0B, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D0C, .reg_data = 0x7C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D0D, .reg_data = 0x5E, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D0E, .reg_data = 0x7C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D0F, .reg_data = 0x5E, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D10, .reg_data = 0x87, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D11, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D12, .reg_data = 0x87, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D13, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D14, .reg_data = 0x3C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D15, .reg_data = 0xAE, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D16, .reg_data = 0x3C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D17, .reg_data = 0xAE, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D18, .reg_data = 0x87, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D19, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D1A, .reg_data = 0x87, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D1B, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D1C, .reg_data = 0x3C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D1D, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D1E, .reg_data = 0x3C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D1F, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D20, .reg_data = 0x7F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D21, .reg_data = 0x3A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D22, .reg_data = 0x7F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D23, .reg_data = 0x3A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D24, .reg_data = 0x81, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D25, .reg_data = 0x82, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D26, .reg_data = 0x81, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D27, .reg_data = 0x82, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D28, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D29, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D2A, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D2B, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D2C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D2D, .reg_data = 0x1F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D2E, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D2F, .reg_data = 0x1C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D30, .reg_data = 0x3C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D31, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D32, .reg_data = 0x3C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D33, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D34, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D35, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D36, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D37, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D38, .reg_data = 0x75, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D39, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D3A, .reg_data = 0x74, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D3B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D3C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D3D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D3E, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D3F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D40, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D41, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D42, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D43, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D44, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D45, .reg_data = 0x0E, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D46, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D47, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D48, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D49, .reg_data = 0x6D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D4A, .reg_data = 0x7F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D4B, .reg_data = 0xF4, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D4C, .reg_data = 0x82, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D4D, .reg_data = 0x83, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D4E, .reg_data = 0x81, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D4F, .reg_data = 0xA5, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D50, .reg_data = 0x3D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D51, .reg_data = 0x7D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D52, .reg_data = 0x3E, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D53, .reg_data = 0x5B, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D54, .reg_data = 0x82, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D55, .reg_data = 0x86, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D56, .reg_data = 0x81, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D57, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D58, .reg_data = 0x3D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D59, .reg_data = 0x7A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D5A, .reg_data = 0x3E, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D5B, .reg_data = 0x58, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D5C, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D5D, .reg_data = 0xFB, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D5E, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D5F, .reg_data = 0xFB, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D60, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D61, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D62, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D63, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D64, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D65, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D66, .reg_data = 0xFF, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1D67, .reg_data = 0xD0, .delay = 0x00, .data_mask = 0x00}, }, -.control_data_1 = -{ - .reg_settings = - { - {.reg_addr = 0x614F, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00},// LC on - {.reg_addr = 0x6023, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00},// gyro on - {.reg_addr = 0x6021, .reg_data = 0x7B, .delay = 0x00, .data_mask = 0x00},// zero shutter mode - }, - .size = 3, - .addr_type = CAMERA_SENSOR_I2C_TYPE_WORD, - .data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, - .delay = 10, +.size = 360, +.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD, +.data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, +.delay = 0, }, -.control_data_2 = -{ - .reg_settings = - { - {.reg_addr = 0x6020, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00},// ois on - }, - .size = 1, - .addr_type = CAMERA_SENSOR_I2C_TYPE_WORD, - .data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, - .delay = 0, +.calib_data = { +.reg_settings = { +{.reg_addr = 0x1DC0, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1DC1, .reg_data = 0x24, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1DC2, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1DC3, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1DC4, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1DC5, .reg_data = 0xea, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1DC6, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1DC7, .reg_data = 0xec, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1DC8, .reg_data = 0xff, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1DC9, .reg_data = 0x5f, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1DCA, .reg_data = 0xff, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1DCB, .reg_data = 0xc3, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1DCC, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1DCD, .reg_data = 0x35, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1DCE, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1DCF, .reg_data = 0x23, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1DD0, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1DD1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1DD2, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1DD3, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1DD4, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1DD5, .reg_data = 0x6a, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1DD6, .reg_data = 0x0d, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1DD7, .reg_data = 0x70, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1DD8, .reg_data = 0x0e, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1DD9, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1DDA, .reg_data = 0xc9, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1DDB, .reg_data = 0x0a, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1DDC, .reg_data = 0xc9, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1DDD, .reg_data = 0x0a, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1DDE, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1DDF, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1DE0, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1DE1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1DE2, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1DE3, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1DE4, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x1DE5, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xF006, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +}, +.size = 39, +.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD, +.data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, +.delay = 0, +}, +.control_data_0 = { +.reg_settings = { +// servo on +{.reg_addr = 0x6020, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +}, +.size = 1, +.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD, +.data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, +.delay = 100, +}, +.control_data_1 = { +.reg_settings = { +// LC on +{.reg_addr = 0x614F, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +// gyro on +{.reg_addr = 0x6023, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +// zero shutter mode +{.reg_addr = 0x6021, .reg_data = 0x7B, .delay = 0x00, .data_mask = 0x00}, +}, +.size = 3, +.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD, +.data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, +.delay = 10, +}, +.control_data_2 = { +.reg_settings = { +{.reg_addr = 0x6020, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00},// ois on +}, +.size = 1, +.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD, +.data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, +.delay = 0, }, diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ois/cam_ois_core.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ois/cam_ois_core.c index 612305598ca5..0c1730aa61b3 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ois/cam_ois_core.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ois/cam_ois_core.c @@ -444,7 +444,7 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) struct cam_sensor_i2c_reg_setting hhk_add_setting;//add by hhk struct cam_sensor_i2c_reg_array hhk_add_reg[3];//add by hhk int32_t j = 0; - uint32_t red_reg_data=0; + uint32_t red_reg_data = 0; ioctl_ctrl = (struct cam_control *)arg; if (copy_from_user(&dev_config, (void __user *) ioctl_ctrl->handle, @@ -634,22 +634,20 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) return rc; } - if(o_ctrl->isPollNeeded == true) - { - red_reg_data=0; - for(j = 0; j < 50; j++) - { + if (o_ctrl->isPollNeeded == true) { + red_reg_data = 0; + for (j = 0; j < 50; j++) { rc = camera_io_dev_read(&(o_ctrl->io_master_info), 0x6024, &red_reg_data, CAMERA_SENSOR_I2C_TYPE_WORD, CAMERA_SENSOR_I2C_TYPE_BYTE); if (rc < 0) { CAM_ERR(CAM_OIS, "Failed to read 0x6024"); } else CAM_DBG(CAM_OIS, "calib_data end read 0x6024 = 0x%x", red_reg_data); - if(red_reg_data == 1) + if (red_reg_data == 1) break; else msleep(10); - }//control data 0 + } //control data 0 hhk_add_reg[0].data_mask = 0x00; hhk_add_reg[0].delay = 0x00; hhk_add_reg[0].reg_addr = 0x6020; @@ -658,26 +656,25 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) hhk_add_setting.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD; hhk_add_setting.data_type = CAMERA_SENSOR_I2C_TYPE_BYTE; hhk_add_setting.size = 1; - hhk_add_setting.delay =10; + hhk_add_setting.delay = 10; rc = camera_io_dev_write(&(o_ctrl->io_master_info), &hhk_add_setting); if (rc < 0) { CAM_ERR(CAM_OIS, "Failed to write control_data_0"); goto pwr_dwn; } - red_reg_data=0; - for(j = 0; j < 50; j++) - { + red_reg_data = 0; + for (j = 0; j < 50; j++) { rc = camera_io_dev_read(&(o_ctrl->io_master_info), 0x6024, &red_reg_data, CAMERA_SENSOR_I2C_TYPE_WORD, CAMERA_SENSOR_I2C_TYPE_BYTE); if (rc < 0) { CAM_ERR(CAM_OIS, "Failed to read 0x6024"); } else CAM_DBG(CAM_OIS, "control_data_0 end read 0x6024 = 0x%x", red_reg_data); - if(red_reg_data == 1) + if (red_reg_data == 1) break; else msleep(10); - }//control data 1 + } //control data 1 hhk_add_reg[0].data_mask = 0x00; hhk_add_reg[0].delay = 0x00; hhk_add_reg[0].reg_addr = 0x614F; @@ -700,16 +697,15 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) CAM_ERR(CAM_OIS, "Failed to write control_data_1"); goto pwr_dwn; } - red_reg_data=0; - for(j = 0; j < 50; j++) - { + red_reg_data = 0; + for (j = 0; j < 50; j++) { rc = camera_io_dev_read(&(o_ctrl->io_master_info), 0x6024, &red_reg_data, CAMERA_SENSOR_I2C_TYPE_WORD, CAMERA_SENSOR_I2C_TYPE_BYTE); if (rc < 0) { CAM_ERR(CAM_OIS, "Failed to read 0x6024"); } else CAM_DBG(CAM_OIS, "control_data_1 end read 0x6024 = 0x%x", red_reg_data); - if(red_reg_data == 1) + if (red_reg_data == 1) break; else msleep(10); diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/CAM_SENSOR_SETTINGS.h b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/CAM_SENSOR_SETTINGS.h index aacaf00ae87b..69ccb965a7ea 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/CAM_SENSOR_SETTINGS.h +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/CAM_SENSOR_SETTINGS.h @@ -1,1024 +1,1018 @@ -.imx519_setting = -{ - .reg_setting = - { - {.reg_addr = 0x0136, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0137, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3C7E, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3C7F, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3020, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3E35, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3F7F, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5609, .reg_data = 0x57, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5613, .reg_data = 0x51, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x561F, .reg_data = 0x5E, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5623, .reg_data = 0xD2, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5637, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5657, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5659, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5733, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5905, .reg_data = 0x57, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x590F, .reg_data = 0x51, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x591B, .reg_data = 0x5E, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x591F, .reg_data = 0xD2, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5933, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5953, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5955, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5A2F, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5A85, .reg_data = 0x57, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5A8F, .reg_data = 0x51, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5A9B, .reg_data = 0x5E, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5A9F, .reg_data = 0xD2, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5AB3, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5AD3, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5AD5, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5BAF, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5C15, .reg_data = 0x2A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5C17, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5C19, .reg_data = 0x31, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5C1B, .reg_data = 0x87, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5C25, .reg_data = 0x25, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5C27, .reg_data = 0x7B, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5C29, .reg_data = 0x2A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5C2B, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5C2D, .reg_data = 0x31, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5C2F, .reg_data = 0x87, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5C35, .reg_data = 0x2B, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5C37, .reg_data = 0x81, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5C39, .reg_data = 0x31, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5C3B, .reg_data = 0x87, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5C45, .reg_data = 0x25, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5C47, .reg_data = 0x7B, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5C49, .reg_data = 0x2A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5C4B, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5C4D, .reg_data = 0x31, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5C4F, .reg_data = 0x87, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5C55, .reg_data = 0x2D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5C57, .reg_data = 0x83, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5C59, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5C5B, .reg_data = 0x88, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5C65, .reg_data = 0x29, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5C67, .reg_data = 0x7F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5C69, .reg_data = 0x2E, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5C6B, .reg_data = 0x84, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5C6D, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5C6F, .reg_data = 0x88, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5E69, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5E9D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5F18, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5F1A, .reg_data = 0x0E, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5F20, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5F22, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5F24, .reg_data = 0x0E, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5F28, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5F2A, .reg_data = 0x0E, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5F30, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5F32, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5F34, .reg_data = 0x0E, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5F38, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5F39, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5F3C, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5F3D, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5F3E, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5F61, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5F64, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5F67, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5F6A, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5F6D, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5F70, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5F73, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5F76, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5F79, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5F7C, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5F7F, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5F82, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5F85, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5F88, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5F8B, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5F8E, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5F91, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5F94, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5F97, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5F9D, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5FA0, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5FA3, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5FA6, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5FA9, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5FAC, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5FAF, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5FB5, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5FB8, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5FBB, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5FC1, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5FC4, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5FC7, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5FD1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6302, .reg_data = 0x79, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6305, .reg_data = 0x78, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6306, .reg_data = 0xA5, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6308, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6309, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x630B, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x630D, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x630F, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6311, .reg_data = 0xA4, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6313, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6314, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6316, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6317, .reg_data = 0x31, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6318, .reg_data = 0x4A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x631A, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x631B, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x631C, .reg_data = 0xA4, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x631E, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x631F, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6321, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6323, .reg_data = 0x4A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6328, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6329, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x632A, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x632B, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x632C, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x632D, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x632E, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6330, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6332, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6333, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6334, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6335, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6336, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6338, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x633A, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x633B, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x633C, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x633D, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x633E, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x633F, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6340, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6341, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6342, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6343, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6344, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6345, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6346, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6348, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6349, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x634A, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x634B, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x634C, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x634D, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x634E, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6350, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6351, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6352, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6353, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6354, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6355, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6356, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6357, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6358, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6359, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x635A, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x635B, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x635C, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x635F, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6360, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6361, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6362, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6363, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6364, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6368, .reg_data = 0x70, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x636A, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x636B, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x636C, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x637D, .reg_data = 0xE4, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x637E, .reg_data = 0xB4, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x638C, .reg_data = 0x8E, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x638D, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x638E, .reg_data = 0xE3, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x638F, .reg_data = 0x4C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6390, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6391, .reg_data = 0xC3, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6392, .reg_data = 0xAE, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6393, .reg_data = 0xBA, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6394, .reg_data = 0xEB, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6395, .reg_data = 0x6E, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6396, .reg_data = 0x34, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6397, .reg_data = 0xE3, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6398, .reg_data = 0xCF, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6399, .reg_data = 0x3C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x639A, .reg_data = 0xF3, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x639B, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x639C, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x639D, .reg_data = 0xC1, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x63B9, .reg_data = 0xA3, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x63BA, .reg_data = 0xFE, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x7600, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x79A0, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x79A1, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x79A2, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x79A3, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x79A4, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x79A5, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x79A9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x79AA, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x79AD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x79AF, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x8173, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x835C, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x8A74, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x8C1F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x8C27, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x8C3B, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9004, .reg_data = 0x0B, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x920C, .reg_data = 0x6A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x920D, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x920E, .reg_data = 0x6A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x920F, .reg_data = 0x23, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9214, .reg_data = 0x6A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9215, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9216, .reg_data = 0x6A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9217, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9385, .reg_data = 0x3E, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9387, .reg_data = 0x1B, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x938D, .reg_data = 0x4D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x938F, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9391, .reg_data = 0x1B, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9395, .reg_data = 0x4D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9397, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9399, .reg_data = 0x1B, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x939D, .reg_data = 0x3E, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x939F, .reg_data = 0x2F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x93A5, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x93A7, .reg_data = 0x2F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x93A9, .reg_data = 0x2F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x93AD, .reg_data = 0x34, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x93AF, .reg_data = 0x2F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x93B5, .reg_data = 0x3E, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x93B7, .reg_data = 0x2F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x93BD, .reg_data = 0x4D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x93BF, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x93C1, .reg_data = 0x2F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x93C5, .reg_data = 0x4D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x93C7, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x93C9, .reg_data = 0x2F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x974B, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x995C, .reg_data = 0x8C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x995D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x995E, .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 = 0xAA0A, .reg_data = 0x26, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAE03, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAE04, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAE05, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xBC1C, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAA06, .reg_data = 0x3F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAA07, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAA08, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAA12, .reg_data = 0x3F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAA13, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAA14, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAA1E, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAA1F, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAA20, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAA2A, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAA2B, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAA2C, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAC19, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAC1B, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAC1D, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAC3C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAC3D, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAC3E, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAC3F, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAC40, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAC41, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAC61, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAC63, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAC65, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAC84, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAC85, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAC86, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAC87, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAC88, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAC89, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0111, .reg_data = 0x03, .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 = 0x17, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0343, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0340, .reg_data = 0x0E, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0341, .reg_data = 0x13, .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 = 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 = 0x3F4C, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3F4D, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x4254, .reg_data = 0x7F, .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 = 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 = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0305, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0306, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0307, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0309, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x030B, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x030D, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x030E, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x030F, .reg_data = 0x13, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0310, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0820, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0821, .reg_data = 0xE4, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0822, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0823, .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 = 0x3E3B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0106, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0B00, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3230, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3F14, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3F3C, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3F0D, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3FBC, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3C06, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3C07, .reg_data = 0x06, .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 = 0x3F78, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3F79, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3F7C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3F7D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0202, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0203, .reg_data = 0xE8, .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 = 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 = 0x020E, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x020F, .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 = 0x0100, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - }, - .size = 387, - .addr_type = CAMERA_SENSOR_I2C_TYPE_WORD, - .data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, - .delay = 1, +.imx519_setting = { +.reg_setting = { +{.reg_addr = 0x0136, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0137, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3C7E, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3C7F, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3020, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3E35, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3F7F, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5609, .reg_data = 0x57, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5613, .reg_data = 0x51, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x561F, .reg_data = 0x5E, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5623, .reg_data = 0xD2, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5637, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5657, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5659, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5733, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5905, .reg_data = 0x57, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x590F, .reg_data = 0x51, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x591B, .reg_data = 0x5E, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x591F, .reg_data = 0xD2, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5933, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5953, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5955, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5A2F, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5A85, .reg_data = 0x57, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5A8F, .reg_data = 0x51, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5A9B, .reg_data = 0x5E, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5A9F, .reg_data = 0xD2, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5AB3, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5AD3, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5AD5, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5BAF, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5C15, .reg_data = 0x2A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5C17, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5C19, .reg_data = 0x31, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5C1B, .reg_data = 0x87, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5C25, .reg_data = 0x25, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5C27, .reg_data = 0x7B, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5C29, .reg_data = 0x2A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5C2B, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5C2D, .reg_data = 0x31, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5C2F, .reg_data = 0x87, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5C35, .reg_data = 0x2B, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5C37, .reg_data = 0x81, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5C39, .reg_data = 0x31, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5C3B, .reg_data = 0x87, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5C45, .reg_data = 0x25, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5C47, .reg_data = 0x7B, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5C49, .reg_data = 0x2A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5C4B, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5C4D, .reg_data = 0x31, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5C4F, .reg_data = 0x87, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5C55, .reg_data = 0x2D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5C57, .reg_data = 0x83, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5C59, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5C5B, .reg_data = 0x88, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5C65, .reg_data = 0x29, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5C67, .reg_data = 0x7F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5C69, .reg_data = 0x2E, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5C6B, .reg_data = 0x84, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5C6D, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5C6F, .reg_data = 0x88, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5E69, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5E9D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5F18, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5F1A, .reg_data = 0x0E, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5F20, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5F22, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5F24, .reg_data = 0x0E, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5F28, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5F2A, .reg_data = 0x0E, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5F30, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5F32, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5F34, .reg_data = 0x0E, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5F38, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5F39, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5F3C, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5F3D, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5F3E, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5F61, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5F64, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5F67, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5F6A, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5F6D, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5F70, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5F73, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5F76, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5F79, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5F7C, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5F7F, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5F82, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5F85, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5F88, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5F8B, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5F8E, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5F91, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5F94, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5F97, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5F9D, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5FA0, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5FA3, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5FA6, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5FA9, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5FAC, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5FAF, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5FB5, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5FB8, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5FBB, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5FC1, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5FC4, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5FC7, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5FD1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6302, .reg_data = 0x79, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6305, .reg_data = 0x78, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6306, .reg_data = 0xA5, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6308, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6309, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x630B, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x630D, .reg_data = 0x48, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x630F, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6311, .reg_data = 0xA4, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6313, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6314, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6316, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6317, .reg_data = 0x31, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6318, .reg_data = 0x4A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x631A, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x631B, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x631C, .reg_data = 0xA4, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x631E, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x631F, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6321, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6323, .reg_data = 0x4A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6328, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6329, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x632A, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x632B, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x632C, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x632D, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x632E, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6330, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6332, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6333, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6334, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6335, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6336, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6338, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x633A, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x633B, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x633C, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x633D, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x633E, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x633F, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6340, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6341, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6342, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6343, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6344, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6345, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6346, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6348, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6349, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x634A, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x634B, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x634C, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x634D, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x634E, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6350, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6351, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6352, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6353, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6354, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6355, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6356, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6357, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6358, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6359, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x635A, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x635B, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x635C, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x635F, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6360, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6361, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6362, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6363, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6364, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6368, .reg_data = 0x70, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x636A, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x636B, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x636C, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x637D, .reg_data = 0xE4, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x637E, .reg_data = 0xB4, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x638C, .reg_data = 0x8E, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x638D, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x638E, .reg_data = 0xE3, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x638F, .reg_data = 0x4C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6390, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6391, .reg_data = 0xC3, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6392, .reg_data = 0xAE, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6393, .reg_data = 0xBA, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6394, .reg_data = 0xEB, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6395, .reg_data = 0x6E, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6396, .reg_data = 0x34, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6397, .reg_data = 0xE3, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6398, .reg_data = 0xCF, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6399, .reg_data = 0x3C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x639A, .reg_data = 0xF3, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x639B, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x639C, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x639D, .reg_data = 0xC1, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x63B9, .reg_data = 0xA3, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x63BA, .reg_data = 0xFE, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x7600, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x79A0, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x79A1, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x79A2, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x79A3, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x79A4, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x79A5, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x79A9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x79AA, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x79AD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x79AF, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x8173, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x835C, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x8A74, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x8C1F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x8C27, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x8C3B, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9004, .reg_data = 0x0B, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x920C, .reg_data = 0x6A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x920D, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x920E, .reg_data = 0x6A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x920F, .reg_data = 0x23, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9214, .reg_data = 0x6A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9215, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9216, .reg_data = 0x6A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9217, .reg_data = 0x21, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9385, .reg_data = 0x3E, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9387, .reg_data = 0x1B, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x938D, .reg_data = 0x4D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x938F, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9391, .reg_data = 0x1B, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9395, .reg_data = 0x4D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9397, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9399, .reg_data = 0x1B, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x939D, .reg_data = 0x3E, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x939F, .reg_data = 0x2F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x93A5, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x93A7, .reg_data = 0x2F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x93A9, .reg_data = 0x2F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x93AD, .reg_data = 0x34, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x93AF, .reg_data = 0x2F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x93B5, .reg_data = 0x3E, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x93B7, .reg_data = 0x2F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x93BD, .reg_data = 0x4D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x93BF, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x93C1, .reg_data = 0x2F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x93C5, .reg_data = 0x4D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x93C7, .reg_data = 0x43, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x93C9, .reg_data = 0x2F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x974B, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x995C, .reg_data = 0x8C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x995D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x995E, .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 = 0xAA0A, .reg_data = 0x26, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAE03, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAE04, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAE05, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xBC1C, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAA06, .reg_data = 0x3F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAA07, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAA08, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAA12, .reg_data = 0x3F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAA13, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAA14, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAA1E, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAA1F, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAA20, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAA2A, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAA2B, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAA2C, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAC19, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAC1B, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAC1D, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAC3C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAC3D, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAC3E, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAC3F, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAC40, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAC41, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAC61, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAC63, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAC65, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAC84, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAC85, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAC86, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAC87, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAC88, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAC89, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0111, .reg_data = 0x03, .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 = 0x17, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0343, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0340, .reg_data = 0x0E, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0341, .reg_data = 0x13, .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 = 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 = 0x3F4C, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3F4D, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x4254, .reg_data = 0x7F, .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 = 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 = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0305, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0306, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0307, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0309, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x030B, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x030D, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x030E, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x030F, .reg_data = 0x13, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0310, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0820, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0821, .reg_data = 0xE4, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0822, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0823, .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 = 0x3E3B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0106, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0B00, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3230, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3F14, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3F3C, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3F0D, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3FBC, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3C06, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3C07, .reg_data = 0x06, .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 = 0x3F78, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3F79, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3F7C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3F7D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0202, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0203, .reg_data = 0xE8, .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 = 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 = 0x020E, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x020F, .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 = 0x0100, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, }, -.imx376k_setting = -{ - .reg_setting = - { - {.reg_addr = 0x0136, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0137, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3C7D, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3C7E, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3C7F, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0B06, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3F02, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3F22, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3F7F, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x4421, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x4430, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x4431, .reg_data = 0xDC, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5222, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x56B7, .reg_data = 0x74, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6204, .reg_data = 0xC6, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x620E, .reg_data = 0x27, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6210, .reg_data = 0x69, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6211, .reg_data = 0xD6, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6213, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6215, .reg_data = 0x5A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6216, .reg_data = 0x75, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6218, .reg_data = 0x5A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6219, .reg_data = 0x75, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6220, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6222, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6225, .reg_data = 0x19, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6228, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6229, .reg_data = 0x70, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x622B, .reg_data = 0x64, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x622E, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6231, .reg_data = 0x71, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6234, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6236, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6237, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6239, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x623C, .reg_data = 0x19, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x623F, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6240, .reg_data = 0x71, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6242, .reg_data = 0x64, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6243, .reg_data = 0x44, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6245, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6246, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6248, .reg_data = 0x71, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x624B, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x624D, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x625C, .reg_data = 0xC9, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x625F, .reg_data = 0x92, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6262, .reg_data = 0x26, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6264, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6265, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6267, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x626A, .reg_data = 0x19, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x626D, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x626E, .reg_data = 0x72, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6270, .reg_data = 0x64, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6271, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6273, .reg_data = 0xC8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6276, .reg_data = 0x91, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6279, .reg_data = 0x27, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x627B, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x627C, .reg_data = 0x55, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x627F, .reg_data = 0x95, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6282, .reg_data = 0x84, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6283, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6284, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6285, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6286, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6287, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6288, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6289, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x628A, .reg_data = 0x1B, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x628B, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x628C, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x628E, .reg_data = 0x35, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x628F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6290, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6291, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6292, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6293, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6294, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6296, .reg_data = 0x54, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6297, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6298, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6299, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x629A, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x629B, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x629C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x629D, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x629E, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x629F, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62A0, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62B1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62B2, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62B3, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62B5, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62B6, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62B7, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62B8, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62B9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62BA, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62BB, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62BC, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62BD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62BE, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62BF, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62D0, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62D1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62D2, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62D4, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62D5, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62D6, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62D7, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62D8, .reg_data = 0xD8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62D9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62DA, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62DB, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62DC, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62DD, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62DE, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62EF, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62F0, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62F1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62F3, .reg_data = 0x58, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62F4, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62F5, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62F6, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62F7, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62F8, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62F9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62FA, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62FB, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62FC, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62FD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62FE, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62FF, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6300, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6301, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6302, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6303, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6304, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6305, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6306, .reg_data = 0x1B, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6307, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6308, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x630A, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x630B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x630C, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x630E, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x630F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6310, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6312, .reg_data = 0x58, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6313, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6314, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6315, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6316, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6317, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6318, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6319, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x631A, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x631B, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x631C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x632D, .reg_data = 0x0E, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x632E, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x632F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6331, .reg_data = 0x44, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6332, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6333, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6334, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6335, .reg_data = 0xE8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6336, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6337, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6338, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6339, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x633A, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x633B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x634C, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x634D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x634E, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6350, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6351, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6352, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6353, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6354, .reg_data = 0xD8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6355, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6356, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6357, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6358, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6359, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x635A, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x636B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x636C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x636D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x636F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6370, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6371, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6372, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6373, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6374, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6375, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6376, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6377, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6378, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6379, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x637A, .reg_data = 0x13, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x637B, .reg_data = 0xD4, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6388, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6389, .reg_data = 0x82, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x638A, .reg_data = 0xC8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x639D, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x7BA0, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x7BA9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x7BAA, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x7BAD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9002, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9003, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9004, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9006, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9200, .reg_data = 0x93, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9201, .reg_data = 0x85, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9202, .reg_data = 0x93, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9203, .reg_data = 0x87, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9204, .reg_data = 0x93, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9205, .reg_data = 0x8D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9206, .reg_data = 0x93, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9207, .reg_data = 0x8F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9208, .reg_data = 0x62, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9209, .reg_data = 0x2C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x920A, .reg_data = 0x62, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x920B, .reg_data = 0x2F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x920C, .reg_data = 0x6A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x920D, .reg_data = 0x23, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x920E, .reg_data = 0x71, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x920F, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9210, .reg_data = 0x71, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9211, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9212, .reg_data = 0x71, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9213, .reg_data = 0x0B, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9214, .reg_data = 0x6A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9215, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9216, .reg_data = 0x71, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9217, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9218, .reg_data = 0x71, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9219, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x935D, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9389, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x938B, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9391, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9393, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9395, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9397, .reg_data = 0x5A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9399, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x939B, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x939D, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x939F, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x93A1, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x93A3, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xB3F1, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xB3F2, .reg_data = 0x0E, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xBC40, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xBC82, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xBC83, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xBC84, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xBC85, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xE0A6, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAA3F, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAA41, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAA43, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAA5D, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAA5F, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAA61, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAACF, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAAD1, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAAD3, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAAED, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAAEF, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAAF1, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xB6D9, .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 = 0x15, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0343, .reg_data = 0xF8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0340, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0341, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3F39, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3F3A, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3F3B, .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 = 0x14, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0349, .reg_data = 0x3F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x034A, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x034B, .reg_data = 0x27, .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 = 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 = 0x3F4D, .reg_data = 0x81, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3F4C, .reg_data = 0x81, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x4254, .reg_data = 0x7F, .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 = 0x0A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x040D, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x040E, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x040F, .reg_data = 0x94, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x034C, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x034D, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x034E, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x034F, .reg_data = 0x94, .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 = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0306, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0307, .reg_data = 0xFA, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x030B, .reg_data = 0x02, .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 = 0x5E, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0310, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0820, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0821, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0822, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0823, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xBC41, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0106, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0B00, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0B05, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3230, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3602, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3607, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3C00, .reg_data = 0x74, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3C01, .reg_data = 0x5F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3C02, .reg_data = 0x73, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3C03, .reg_data = 0x64, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3C04, .reg_data = 0x54, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3C05, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3C06, .reg_data = 0xBE, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3C07, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3C08, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3C09, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3C0A, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3C0B, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3C0C, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3E20, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3E3D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3F14, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3F17, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3F3C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3F78, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3F79, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3F7A, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3F7B, .reg_data = 0xBC, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x562B, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x562D, .reg_data = 0x34, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5617, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x7849, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9104, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0202, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0203, .reg_data = 0x70, .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 = 375, - .addr_type = CAMERA_SENSOR_I2C_TYPE_WORD, - .data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, - .delay = 1, +.size = 387, +.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD, +.data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, +.delay = 1, }, -.imx371_setting = -{ - .reg_setting = - { - {.reg_addr = 0x0136, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0137, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3C7D, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3C7E, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3C7F, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3F02, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3F7F, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x4421, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x4430, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x4431, .reg_data = 0xDC, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5222, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x562B, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x562D, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x56B7, .reg_data = 0x74, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6200, .reg_data = 0x95, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6201, .reg_data = 0xB9, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6202, .reg_data = 0x58, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6220, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6222, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6225, .reg_data = 0x19, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6228, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6229, .reg_data = 0x70, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x622A, .reg_data = 0xC3, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x622B, .reg_data = 0x64, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x622C, .reg_data = 0x54, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x622E, .reg_data = 0xB8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x622F, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6231, .reg_data = 0x73, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6233, .reg_data = 0x42, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6234, .reg_data = 0xEA, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6235, .reg_data = 0x8C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6236, .reg_data = 0x35, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6237, .reg_data = 0xC5, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6239, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x623A, .reg_data = 0x96, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x623C, .reg_data = 0x19, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x623F, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6240, .reg_data = 0x59, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6241, .reg_data = 0x83, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6242, .reg_data = 0x64, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6243, .reg_data = 0x54, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6245, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6246, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6248, .reg_data = 0x53, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x624A, .reg_data = 0x42, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x624B, .reg_data = 0xA5, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x624C, .reg_data = 0x98, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x624D, .reg_data = 0x35, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6265, .reg_data = 0x45, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6267, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x626A, .reg_data = 0x19, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x626D, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x626E, .reg_data = 0x72, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x626F, .reg_data = 0xC3, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6270, .reg_data = 0x64, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6271, .reg_data = 0x58, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6273, .reg_data = 0xC8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6276, .reg_data = 0x91, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6279, .reg_data = 0x27, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x627B, .reg_data = 0x36, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6282, .reg_data = 0x82, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6283, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6286, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6287, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6288, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x628A, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x628B, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x628C, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x628E, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6290, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6292, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6296, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x629A, .reg_data = 0xF8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x629B, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x629D, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x629F, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62B1, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62B5, .reg_data = 0x3C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62B9, .reg_data = 0xC8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62BC, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62BD, .reg_data = 0x70, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62D0, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62D4, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62D8, .reg_data = 0xB8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62DB, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62DC, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x62DD, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x637A, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x637B, .reg_data = 0xD4, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6388, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x6389, .reg_data = 0x82, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x638A, .reg_data = 0xC8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x639D, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x7BA0, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x7BA9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x7BAA, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x7BAD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9002, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9003, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9004, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9006, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9200, .reg_data = 0x93, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9201, .reg_data = 0x85, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9202, .reg_data = 0x93, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9203, .reg_data = 0x87, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9204, .reg_data = 0x93, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9205, .reg_data = 0x8D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9206, .reg_data = 0x93, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9207, .reg_data = 0x8F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9208, .reg_data = 0x6A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9209, .reg_data = 0x23, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x920A, .reg_data = 0x6A, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x920B, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x920C, .reg_data = 0x71, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x920D, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x920E, .reg_data = 0x71, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x920F, .reg_data = 0x0B, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x935D, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9389, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x938B, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9391, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9393, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9395, .reg_data = 0x82, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9397, .reg_data = 0x78, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x9399, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x939B, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAA3F, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAA41, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAA43, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAA5D, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAA5F, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAA61, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAACF, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAAD1, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAAD3, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAAED, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAAEF, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xAAF1, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xB388, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xBC40, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xE0A5, .reg_data = 0x0B, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xE0A6, .reg_data = 0x0B, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x5617, .reg_data = 0x0A, .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 = 0x17, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0343, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0340, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0341, .reg_data = 0xE0, .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 = 0x4254, .reg_data = 0x7F, .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 = 0x14, .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 = 0x80, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0xBC41, .reg_data = 0x01, .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 = 0x80, .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 = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0306, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0307, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x030B, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x030D, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x030E, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x030F, .reg_data = 0xDA, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0310, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0820, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0821, .reg_data = 0x70, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0822, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0823, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3E20, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3E37, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3E3B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3614, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3616, .reg_data = 0x0E, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3617, .reg_data = 0x66, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0106, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0B00, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0B05, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0B06, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3230, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3602, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3C00, .reg_data = 0x5B, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3C01, .reg_data = 0x54, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3C02, .reg_data = 0x77, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3C03, .reg_data = 0x66, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3C04, .reg_data = 0xC8, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3C05, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3C06, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3C07, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3F14, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3F17, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3F3C, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3F78, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3F79, .reg_data = 0xB4, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3F7C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x3F7D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0202, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, - {.reg_addr = 0x0203, .reg_data = 0xE8, .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 = 232, - .addr_type = CAMERA_SENSOR_I2C_TYPE_WORD, - .data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, - .delay = 1, +.imx376k_setting = { +.reg_setting = { +{.reg_addr = 0x0136, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0137, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3C7D, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3C7E, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3C7F, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0B06, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3F02, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3F22, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3F7F, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x4421, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x4430, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x4431, .reg_data = 0xDC, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5222, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x56B7, .reg_data = 0x74, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6204, .reg_data = 0xC6, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x620E, .reg_data = 0x27, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6210, .reg_data = 0x69, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6211, .reg_data = 0xD6, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6213, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6215, .reg_data = 0x5A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6216, .reg_data = 0x75, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6218, .reg_data = 0x5A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6219, .reg_data = 0x75, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6220, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6222, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6225, .reg_data = 0x19, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6228, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6229, .reg_data = 0x70, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x622B, .reg_data = 0x64, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x622E, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6231, .reg_data = 0x71, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6234, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6236, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6237, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6239, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x623C, .reg_data = 0x19, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x623F, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6240, .reg_data = 0x71, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6242, .reg_data = 0x64, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6243, .reg_data = 0x44, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6245, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6246, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6248, .reg_data = 0x71, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x624B, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x624D, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x625C, .reg_data = 0xC9, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x625F, .reg_data = 0x92, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6262, .reg_data = 0x26, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6264, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6265, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6267, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x626A, .reg_data = 0x19, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x626D, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x626E, .reg_data = 0x72, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6270, .reg_data = 0x64, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6271, .reg_data = 0x68, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6273, .reg_data = 0xC8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6276, .reg_data = 0x91, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6279, .reg_data = 0x27, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x627B, .reg_data = 0x46, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x627C, .reg_data = 0x55, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x627F, .reg_data = 0x95, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6282, .reg_data = 0x84, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6283, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6284, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6285, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6286, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6287, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6288, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6289, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x628A, .reg_data = 0x1B, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x628B, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x628C, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x628E, .reg_data = 0x35, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x628F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6290, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6291, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6292, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6293, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6294, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6296, .reg_data = 0x54, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6297, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6298, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6299, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x629A, .reg_data = 0x10, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x629B, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x629C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x629D, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x629E, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x629F, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62A0, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62B1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62B2, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62B3, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62B5, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62B6, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62B7, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62B8, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62B9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62BA, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62BB, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62BC, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62BD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62BE, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62BF, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62D0, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62D1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62D2, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62D4, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62D5, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62D6, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62D7, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62D8, .reg_data = 0xD8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62D9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62DA, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62DB, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62DC, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62DD, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62DE, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62EF, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62F0, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62F1, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62F3, .reg_data = 0x58, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62F4, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62F5, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62F6, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62F7, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62F8, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62F9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62FA, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62FB, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62FC, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62FD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62FE, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62FF, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6300, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6301, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6302, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6303, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6304, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6305, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6306, .reg_data = 0x1B, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6307, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6308, .reg_data = 0x30, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x630A, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x630B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x630C, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x630E, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x630F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6310, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6312, .reg_data = 0x58, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6313, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6314, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6315, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6316, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6317, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6318, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6319, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x631A, .reg_data = 0x60, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x631B, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x631C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x632D, .reg_data = 0x0E, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x632E, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x632F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6331, .reg_data = 0x44, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6332, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6333, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6334, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6335, .reg_data = 0xE8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6336, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6337, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6338, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6339, .reg_data = 0xF0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x633A, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x633B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x634C, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x634D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x634E, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6350, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6351, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6352, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6353, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6354, .reg_data = 0xD8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6355, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6356, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6357, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6358, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6359, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x635A, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x636B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x636C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x636D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x636F, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6370, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6371, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6372, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6373, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6374, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6375, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6376, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6377, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6378, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6379, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x637A, .reg_data = 0x13, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x637B, .reg_data = 0xD4, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6388, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6389, .reg_data = 0x82, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x638A, .reg_data = 0xC8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x639D, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x7BA0, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x7BA9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x7BAA, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x7BAD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9002, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9003, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9004, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9006, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9200, .reg_data = 0x93, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9201, .reg_data = 0x85, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9202, .reg_data = 0x93, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9203, .reg_data = 0x87, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9204, .reg_data = 0x93, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9205, .reg_data = 0x8D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9206, .reg_data = 0x93, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9207, .reg_data = 0x8F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9208, .reg_data = 0x62, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9209, .reg_data = 0x2C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x920A, .reg_data = 0x62, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x920B, .reg_data = 0x2F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x920C, .reg_data = 0x6A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x920D, .reg_data = 0x23, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x920E, .reg_data = 0x71, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x920F, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9210, .reg_data = 0x71, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9211, .reg_data = 0x09, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9212, .reg_data = 0x71, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9213, .reg_data = 0x0B, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9214, .reg_data = 0x6A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9215, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9216, .reg_data = 0x71, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9217, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9218, .reg_data = 0x71, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9219, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x935D, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9389, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x938B, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9391, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9393, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9395, .reg_data = 0x65, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9397, .reg_data = 0x5A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9399, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x939B, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x939D, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x939F, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x93A1, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x93A3, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xB3F1, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xB3F2, .reg_data = 0x0E, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xBC40, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xBC82, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xBC83, .reg_data = 0xB0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xBC84, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xBC85, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xE0A6, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAA3F, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAA41, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAA43, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAA5D, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAA5F, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAA61, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAACF, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAAD1, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAAD3, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAAED, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAAEF, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAAF1, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xB6D9, .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 = 0x15, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0343, .reg_data = 0xF8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0340, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0341, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3F39, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3F3A, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3F3B, .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 = 0x14, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0349, .reg_data = 0x3F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x034A, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x034B, .reg_data = 0x27, .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 = 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 = 0x3F4D, .reg_data = 0x81, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3F4C, .reg_data = 0x81, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x4254, .reg_data = 0x7F, .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 = 0x0A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x040D, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x040E, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x040F, .reg_data = 0x94, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x034C, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x034D, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x034E, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x034F, .reg_data = 0x94, .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 = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0306, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0307, .reg_data = 0xFA, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x030B, .reg_data = 0x02, .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 = 0x5E, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0310, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0820, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0821, .reg_data = 0xA0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0822, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0823, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xBC41, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0106, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0B00, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0B05, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3230, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3602, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3607, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3C00, .reg_data = 0x74, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3C01, .reg_data = 0x5F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3C02, .reg_data = 0x73, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3C03, .reg_data = 0x64, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3C04, .reg_data = 0x54, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3C05, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3C06, .reg_data = 0xBE, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3C07, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3C08, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3C09, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3C0A, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3C0B, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3C0C, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3E20, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3E3D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3F14, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3F17, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3F3C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3F78, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3F79, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3F7A, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3F7B, .reg_data = 0xBC, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x562B, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x562D, .reg_data = 0x34, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5617, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x7849, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9104, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0202, .reg_data = 0x12, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0203, .reg_data = 0x70, .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 = 375, +.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD, +.data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, +.delay = 1, +}, +.imx371_setting = { +.reg_setting = { +{.reg_addr = 0x0136, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0137, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3C7D, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3C7E, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3C7F, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3F02, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3F7F, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x4421, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x4430, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x4431, .reg_data = 0xDC, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5222, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x562B, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x562D, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x56B7, .reg_data = 0x74, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6200, .reg_data = 0x95, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6201, .reg_data = 0xB9, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6202, .reg_data = 0x58, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6220, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6222, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6225, .reg_data = 0x19, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6228, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6229, .reg_data = 0x70, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x622A, .reg_data = 0xC3, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x622B, .reg_data = 0x64, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x622C, .reg_data = 0x54, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x622E, .reg_data = 0xB8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x622F, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6231, .reg_data = 0x73, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6233, .reg_data = 0x42, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6234, .reg_data = 0xEA, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6235, .reg_data = 0x8C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6236, .reg_data = 0x35, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6237, .reg_data = 0xC5, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6239, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x623A, .reg_data = 0x96, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x623C, .reg_data = 0x19, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x623F, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6240, .reg_data = 0x59, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6241, .reg_data = 0x83, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6242, .reg_data = 0x64, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6243, .reg_data = 0x54, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6245, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6246, .reg_data = 0xA8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6248, .reg_data = 0x53, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x624A, .reg_data = 0x42, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x624B, .reg_data = 0xA5, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x624C, .reg_data = 0x98, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x624D, .reg_data = 0x35, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6265, .reg_data = 0x45, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6267, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x626A, .reg_data = 0x19, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x626D, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x626E, .reg_data = 0x72, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x626F, .reg_data = 0xC3, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6270, .reg_data = 0x64, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6271, .reg_data = 0x58, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6273, .reg_data = 0xC8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6276, .reg_data = 0x91, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6279, .reg_data = 0x27, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x627B, .reg_data = 0x36, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6282, .reg_data = 0x82, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6283, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6286, .reg_data = 0x07, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6287, .reg_data = 0xC0, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6288, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x628A, .reg_data = 0x18, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x628B, .reg_data = 0x80, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x628C, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x628E, .reg_data = 0x32, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6290, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6292, .reg_data = 0x0A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6296, .reg_data = 0x50, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x629A, .reg_data = 0xF8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x629B, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x629D, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x629F, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62B1, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62B5, .reg_data = 0x3C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62B9, .reg_data = 0xC8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62BC, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62BD, .reg_data = 0x70, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62D0, .reg_data = 0x06, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62D4, .reg_data = 0x38, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62D8, .reg_data = 0xB8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62DB, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62DC, .reg_data = 0x40, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x62DD, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x637A, .reg_data = 0x11, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x637B, .reg_data = 0xD4, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6388, .reg_data = 0x22, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x6389, .reg_data = 0x82, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x638A, .reg_data = 0xC8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x639D, .reg_data = 0x20, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x7BA0, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x7BA9, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x7BAA, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x7BAD, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9002, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9003, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9004, .reg_data = 0x08, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9006, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9200, .reg_data = 0x93, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9201, .reg_data = 0x85, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9202, .reg_data = 0x93, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9203, .reg_data = 0x87, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9204, .reg_data = 0x93, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9205, .reg_data = 0x8D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9206, .reg_data = 0x93, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9207, .reg_data = 0x8F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9208, .reg_data = 0x6A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9209, .reg_data = 0x23, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x920A, .reg_data = 0x6A, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x920B, .reg_data = 0x0F, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x920C, .reg_data = 0x71, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x920D, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x920E, .reg_data = 0x71, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x920F, .reg_data = 0x0B, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x935D, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9389, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x938B, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9391, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9393, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9395, .reg_data = 0x82, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9397, .reg_data = 0x78, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x9399, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x939B, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAA3F, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAA41, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAA43, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAA5D, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAA5F, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAA61, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAACF, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAAD1, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAAD3, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAAED, .reg_data = 0x05, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAAEF, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xAAF1, .reg_data = 0x02, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xB388, .reg_data = 0x28, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xBC40, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xE0A5, .reg_data = 0x0B, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xE0A6, .reg_data = 0x0B, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x5617, .reg_data = 0x0A, .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 = 0x17, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0343, .reg_data = 0x90, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0340, .reg_data = 0x0D, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0341, .reg_data = 0xE0, .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 = 0x4254, .reg_data = 0x7F, .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 = 0x14, .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 = 0x80, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0xBC41, .reg_data = 0x01, .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 = 0x80, .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 = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0306, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0307, .reg_data = 0x0C, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x030B, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x030D, .reg_data = 0x04, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x030E, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x030F, .reg_data = 0xDA, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0310, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0820, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0821, .reg_data = 0x70, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0822, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0823, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3E20, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3E37, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3E3B, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3614, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3616, .reg_data = 0x0E, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3617, .reg_data = 0x66, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0106, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0B00, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0B05, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0B06, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3230, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3602, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3C00, .reg_data = 0x5B, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3C01, .reg_data = 0x54, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3C02, .reg_data = 0x77, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3C03, .reg_data = 0x66, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3C04, .reg_data = 0xC8, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3C05, .reg_data = 0x14, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3C06, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3C07, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3F14, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3F17, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3F3C, .reg_data = 0x01, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3F78, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3F79, .reg_data = 0xB4, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3F7C, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x3F7D, .reg_data = 0x00, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0202, .reg_data = 0x03, .delay = 0x00, .data_mask = 0x00}, +{.reg_addr = 0x0203, .reg_data = 0xE8, .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 = 232, +.addr_type = CAMERA_SENSOR_I2C_TYPE_WORD, +.data_type = CAMERA_SENSOR_I2C_TYPE_BYTE, +.delay = 1, }, \ No newline at end of file diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/cam_sensor_core.c index a0aef5b9a6fa..1ca9acc33140 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/cam_sensor_core.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/cam_sensor_core.c @@ -17,7 +17,9 @@ #include "cam_soc_util.h" #include "cam_trace.h" +#ifdef CONFIG_PROJECT_INFO #include +#endif struct camera_vendor_match_tbl { uint16_t sensor_id; @@ -777,7 +779,9 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, struct cam_sensor_power_ctrl_t *power_info = &s_ctrl->sensordata->power_info; uint32_t count = 0, i; +#ifdef CONFIG_PROJECT_INFO enum COMPONENT_TYPE CameraID; +#endif if (!s_ctrl || !arg) { CAM_ERR(CAM_SENSOR, "s_ctrl is NULL"); @@ -901,6 +905,7 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, 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) @@ -922,7 +927,7 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, else push_component_info(CameraID, match_tbl[i].sensor_name, match_tbl[i].vendor_name); - +#endif } break; case CAM_ACQUIRE_DEV: { diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/cam_sensor_dev.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/cam_sensor_dev.c index 7e79d1a597f4..f6c38885ad29 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/cam_sensor_dev.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/cam_sensor_dev.c @@ -24,9 +24,9 @@ struct cam_sensor_i2c_reg_setting_array { }; struct cam_sensor_settings { - struct cam_sensor_i2c_reg_setting_array imx519_setting; - struct cam_sensor_i2c_reg_setting_array imx376k_setting; - struct cam_sensor_i2c_reg_setting_array imx371_setting; + struct cam_sensor_i2c_reg_setting_array imx519_setting; + struct cam_sensor_i2c_reg_setting_array imx376k_setting; + struct cam_sensor_i2c_reg_setting_array imx371_setting; }; struct cam_sensor_settings sensor_settings = { @@ -57,33 +57,33 @@ static long cam_sensor_subdev_ioctl(struct v4l2_subdev *sd, break; } - if (s_ctrl->sensordata->slave_info.sensor_id == 0x519) { - sensor_setting.reg_setting = sensor_settings.imx519_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.imx519_setting.size; - sensor_setting.delay = sensor_settings.imx519_setting.delay; - } else if(s_ctrl->sensordata->slave_info.sensor_id == 0x376) { - sensor_setting.reg_setting = sensor_settings.imx376k_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.imx376k_setting.size; - sensor_setting.delay = sensor_settings.imx376k_setting.delay; - } else if(s_ctrl->sensordata->slave_info.sensor_id == 0x371) { - sensor_setting.reg_setting = sensor_settings.imx371_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.imx371_setting.size; - sensor_setting.delay = sensor_settings.imx371_setting.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"); - } else { - CAM_ERR(CAM_SENSOR, "FTM successfully to write sensor setting"); - } - break; + if (s_ctrl->sensordata->slave_info.sensor_id == 0x519) { + sensor_setting.reg_setting = sensor_settings.imx519_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.imx519_setting.size; + sensor_setting.delay = sensor_settings.imx519_setting.delay; + } else if (s_ctrl->sensordata->slave_info.sensor_id == 0x376) { + sensor_setting.reg_setting = sensor_settings.imx376k_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.imx376k_setting.size; + sensor_setting.delay = sensor_settings.imx376k_setting.delay; + } else if (s_ctrl->sensordata->slave_info.sensor_id == 0x371) { + sensor_setting.reg_setting = sensor_settings.imx371_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.imx371_setting.size; + sensor_setting.delay = sensor_settings.imx371_setting.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"); + } else { + CAM_ERR(CAM_SENSOR, "FTM successfully to write sensor setting"); + } + break; default: CAM_ERR(CAM_SENSOR, "Invalid ioctl cmd: %d", cmd); rc = -EINVAL; diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c index a0128ab0d141..3179b74d364d 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c @@ -151,7 +151,7 @@ int32_t cam_sensor_handle_poll( CAM_ERR(CAM_SENSOR, "Failed in allocating mem for list"); return -ENOMEM; } - (*offset) = 0;//add by HHK fox fix delayus invalid + *offset = 0;//add by HHK fox fix delayus invalid i2c_list->op_code = CAM_SENSOR_I2C_POLL; i2c_list->i2c_settings.data_type = cond_wait->data_type; @@ -199,7 +199,7 @@ int32_t cam_sensor_handle_random_write( cam_cmd_i2c_random_wr->header.addr_type; i2c_list->i2c_settings.data_type = cam_cmd_i2c_random_wr->header.data_type; - (*offset) = 0;//add by HHK fox fix delayus invalid + *offset = 0;//add by HHK fox fix delayus invalid for (cnt = 0; cnt < (cam_cmd_i2c_random_wr->header.count); cnt++) { i2c_list->i2c_settings.reg_setting[cnt].reg_addr = @@ -254,7 +254,7 @@ static int32_t cam_sensor_handle_continuous_write( cam_cmd_i2c_continuous_wr->header.data_type; i2c_list->i2c_settings.size = cam_cmd_i2c_continuous_wr->header.count; - (*offset) = 0;//add by HHK fox fix delayus invalid + *offset = 0;//add by HHK fox fix delayus invalid for (cnt = 0; cnt < (cam_cmd_i2c_continuous_wr->header.count); cnt++) { i2c_list->i2c_settings.reg_setting[cnt].reg_addr = diff --git a/drivers/media/platform/msm/camera_oneplus/cam_smmu/cam_smmu_api.c b/drivers/media/platform/msm/camera_oneplus/cam_smmu/cam_smmu_api.c index ecfc5665085b..6b1f6e85400e 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_smmu/cam_smmu_api.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_smmu/cam_smmu_api.c @@ -2924,7 +2924,7 @@ int cam_smmu_destroy_handle(int handle) cam_smmu_clean_kernel_buffer_list(idx); } - if (&iommu_cb_set.cb_info[idx].is_secure) { + 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; From d574d9217943cfa17b73831f27a31b78ae6c14b7 Mon Sep 17 00:00:00 2001 From: LuK1337 Date: Sun, 29 Aug 2021 17:25:29 +0200 Subject: [PATCH 269/356] ARM: dts: msm: Sync PIL memory map with oneplus/SDM845_R_11.0 Change-Id: I5b9f0af1a972374437dda5ad013acb241ddf2d80 --- arch/arm64/boot/dts/qcom/sdm845.dtsi | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index 03b98b2e877f..dea895bef76e 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -482,25 +482,25 @@ pil_cdsp_mem: cdsp_region@0x95d00000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x95d00000 0 0x800000>; + reg = <0 0x95d00000 0 0x900000>; }; - pil_mba_mem: mba_region@0x96500000 { + pil_mba_mem: mba_region@0x96600000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x96500000 0 0x200000>; + reg = <0 0x96600000 0 0x200000>; }; - pil_slpi_mem: slpi_region@0x96700000 { + pil_slpi_mem: slpi_region@0x96800000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x96700000 0 0x1400000>; + reg = <0 0x96800000 0 0x1400000>; }; - pil_spss_mem: pil_spss_region@0x97b00000 { + pil_spss_mem: pil_spss_region@0x97c00000 { compatible = "removed-dma-pool"; no-map; - reg = <0 0x97b00000 0 0x100000>; + reg = <0 0x97c00000 0 0x100000>; }; adsp_mem: adsp_region { From d9b85dbad62d389361ffa1f738010d1418f22a2a Mon Sep 17 00:00:00 2001 From: LuK1337 Date: Wed, 8 Sep 2021 12:34:07 +0200 Subject: [PATCH 270/356] ARM: dts: msm: Sync panel dts with oneplus/SDM845_R_11.0 Change-Id: I9fc95d72e90b8934569f3aa1337ae7534cdafa6f --- .../qcom/dsi-panel-samsung_s6e3fc2x01.dtsi | 142 ++++++++++++++---- .../qcom/dsi-panel-samsung_sofef00_m_cmd.dtsi | 63 +++++++- 2 files changed, 177 insertions(+), 28 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-samsung_s6e3fc2x01.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-samsung_s6e3fc2x01.dtsi index 47b0ea5158c8..1b7da404730d 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-samsung_s6e3fc2x01.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-samsung_s6e3fc2x01.dtsi @@ -205,35 +205,27 @@ ]; qcom,mdss-dsi-panel-hbm-on-command-5 = [ - /*ELVSS OFF*/ - 39 01 00 00 00 00 03 F0 5A 5A - 15 01 00 00 00 00 02 B0 07 - 15 01 00 00 00 00 02 B7 01 - 15 01 00 00 00 00 02 B0 08 - 15 01 00 00 00 00 02 B7 12 - 39 01 00 00 00 00 03 F0 A5 A5 - /*DLY OFF*/ - 39 01 00 00 00 00 03 F0 5A 5A - 39 01 00 00 00 00 04 B7 00 01 5B - 39 01 00 00 00 00 03 F0 A5 A5 - 15 01 00 00 0A 00 02 53 E0 - 39 01 00 00 00 00 03 51 03 FF - /*DLY ON*/ + /*ELVSS OFF*/ 39 01 00 00 00 00 03 F0 5A 5A - 39 01 00 00 00 00 04 B7 00 01 53 + 15 01 00 00 00 00 02 B0 08 + 15 01 00 00 00 00 02 B7 12 39 01 00 00 00 00 03 F0 A5 A5 - ]; - qcom,mdss-dsi-panel-hbm-off-command = [ - /*DLY OFF*/ + /*DLY OFF*/ 39 01 00 00 00 00 03 F0 5A 5A 39 01 00 00 00 00 04 B7 00 01 5B - 39 01 00 00 00 00 03 F0 A5 A5 - 39 01 00 00 00 00 02 53 20 - /*DLY ON*/ + 39 01 00 00 22 00 03 F0 A5 A5 + /*HBM ON */ + 15 01 00 00 00 00 02 53 E0 + 39 01 00 00 0E 00 03 51 03 FF + /*DLY ON*/ 39 01 00 00 00 00 03 F0 5A 5A 39 01 00 00 00 00 04 B7 00 01 53 39 01 00 00 00 00 03 F0 A5 A5 ]; + qcom,mdss-dsi-panel-hbm-off-command = [ + /*HBM off */ + 15 01 00 00 00 00 02 53 20 + ]; qcom,mdss-dsi-panel-hbm-max-brightness-command-on = [ 39 01 00 00 00 00 03 F0 5A 5A 15 01 00 00 00 00 02 B0 07 @@ -280,40 +272,133 @@ qcom,mdss-dsi-hbm-off-command-state = "dsi_hs_mode"; 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 */ + 39 01 00 00 00 00 03 9F A5 A5 + 05 01 00 00 0A 00 01 28 + 05 01 00 00 78 00 01 10 + 05 01 00 00 05 00 01 11 + 39 01 00 00 00 00 03 9F 5A 5A + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 01 + 15 01 00 00 64 00 02 CD 02 + 15 01 00 00 00 00 02 53 22 + 15 01 00 00 00 00 02 B0 A5 + 15 01 00 00 00 00 02 C7 00 + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 9F A5 A5 + 05 01 00 00 00 00 01 12 + 05 01 00 00 00 00 01 29 + 39 01 00 00 00 00 03 9F 5A 5A ]; qcom,mdss-dsi-panel-aod-off-command = [ + 39 01 00 00 00 00 03 9F A5 A5 + 05 01 00 00 0A 00 01 28 + 39 01 00 00 00 00 03 9F 5A 5A + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 01 + 15 01 00 00 64 00 02 CD 01 + 15 01 00 00 00 00 02 53 28 + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 9F A5 A5 + 05 01 00 00 00 00 01 13 + 05 01 00 00 00 00 01 29 + 39 01 00 00 00 00 03 9F 5A 5A ]; qcom,mdss-dsi-panel-aod-off-samsung-command = [ + 39 01 00 00 00 00 03 9F A5 A5 + 05 01 00 00 0A 00 01 28 + 39 01 00 00 00 00 03 9F 5A 5A + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 01 + 15 01 00 00 64 00 02 CD 01 + 15 01 00 00 00 00 02 53 28 + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 9F A5 A5 + 05 01 00 00 00 00 01 13 + 05 01 00 00 00 00 01 29 + 39 01 00 00 00 00 03 9F 5A 5A ]; qcom,mdss-dsi-panel-aod-off-new-command = [ + 39 01 00 00 00 00 03 9F A5 A5 + 05 01 00 00 0A 00 01 28 + 39 01 00 00 00 00 03 9F 5A 5A + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 01 + 15 01 00 00 64 00 02 CD 01 + 15 01 00 00 00 00 02 53 28 + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 9F A5 A5 + 05 01 00 00 00 00 01 13 + 05 01 00 00 00 00 01 29 + 39 01 00 00 00 00 03 9F 5A 5A ]; - qcom,mdss-dsi-panel-aod-off-new-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 = [ - /*ELVSS OFF*/ 39 01 00 00 00 00 03 F0 5A 5A 15 01 00 00 00 00 02 B0 07 15 01 00 00 00 00 02 B7 01 15 01 00 00 00 00 02 B0 08 15 01 00 00 00 00 02 B7 12 - 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 10 00 03 F0 A5 A5 /*DLY OFF*/ 39 01 00 00 00 00 03 F0 5A 5A 39 01 00 00 00 00 04 B7 00 01 5B 39 01 00 00 00 00 03 F0 A5 A5 - 15 01 00 00 0A 00 02 53 E0 - 39 01 00 00 00 00 03 51 03 FF + 15 01 00 00 00 00 02 53 E0 + 39 01 00 00 0E 00 03 51 03 FF /*DLY ON*/ 39 01 00 00 00 00 03 F0 5A 5A 39 01 00 00 00 00 04 B7 00 01 53 39 01 00 00 00 00 03 F0 A5 A5 ]; qcom,mdss-dsi-panel-aod-off-hbm-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-real-aod-off-hbm-on-command = [ + /*aod off*/ + 39 01 00 00 00 00 03 9F A5 A5 + 05 01 00 00 0A 00 01 28 + 39 01 00 00 00 00 03 9F 5A 5A + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 01 + 15 01 00 00 64 00 02 CD 01 + 15 01 00 00 00 00 02 53 28 + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 9F A5 A5 + 05 01 00 00 00 00 01 13 + 05 01 00 00 00 00 01 29 + 39 01 00 00 00 00 03 9F 5A 5A + /*hbm on*/ + /*ELVSS OFF*/ + 39 00 00 00 00 00 03 F0 5A 5A + 15 00 00 00 00 00 02 B0 08 + 15 00 00 00 00 00 02 B7 12 + 39 00 00 00 00 00 03 F0 A5 A5 + /*DLY OFF*/ + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 04 B7 00 01 5B + 39 00 00 00 00 00 03 F0 A5 A5 + /*HBM ON */ + 15 00 00 00 00 00 02 53 E0 + 39 01 00 00 00 00 03 51 03 FF + /*DLY OFF*/ + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 04 B7 00 01 53 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-panel-real-aod-off-hbm-on-command-state = "dsi_hs_mode"; 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 04 B7 00 01 5B @@ -325,6 +410,11 @@ 39 01 00 00 00 00 03 F0 A5 A5 ]; qcom,mdss-dsi-panel-hbm-off-aod-on-command-state = "dsi_lp_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-aod-on-command-state = "dsi_lp_mode"; qcom,mdss-dsi-aod-off-command-state = "dsi_lp_mode"; qcom,mdss-dsi-aod-mode-command-state = "dsi_lp_mode"; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-samsung_sofef00_m_cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-samsung_sofef00_m_cmd.dtsi index 43d612154580..38059ea1792a 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-samsung_sofef00_m_cmd.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-samsung_sofef00_m_cmd.dtsi @@ -184,14 +184,46 @@ qcom,mdss-dsi-panel-hbm-max-brightness-command-on-state = "dsi_lp_mode"; qcom,mdss-dsi-panel-hbm-max-brightness-command-off-state = "dsi_lp_mode"; qcom,mdss-dsi-panel-aod-on-command-1 = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 53 23 + 05 01 00 00 00 00 02 39 + 39 01 00 00 00 00 03 F0 A5 A5 ]; qcom,mdss-dsi-panel-aod-on-command-2 = [ ]; qcom,mdss-dsi-panel-aod-on-command-3 = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 53 22 + 05 01 00 00 00 00 02 39 + 39 01 00 00 00 00 03 F0 A5 A5 ]; qcom,mdss-dsi-panel-aod-on-command-4 = [ ]; + qcom,mdss-dsi-panel-aod-on-command-5 = [ + 15 01 00 00 00 00 01 28 + 39 01 00 00 12 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 49 + 15 01 00 00 00 00 02 CB FF + 15 01 00 00 00 00 02 B0 4F + 15 01 00 00 00 00 02 CB C8 + 15 01 00 00 00 00 02 F7 03 + 39 01 00 00 00 00 03 F0 A5 A5 + 05 01 00 00 12 00 01 10 + 05 01 00 00 82 00 01 11 + 39 01 00 00 06 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 01 + 15 01 00 00 00 00 02 BB 03 + 15 01 00 00 00 00 08 EF F0 31 00 33 31 14 35 + 15 01 00 00 78 00 02 53 22 + 05 01 00 00 01 00 02 39 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 12 00 01 29 + ]; qcom,mdss-dsi-panel-aod-off-command = [ + 39 01 00 00 00 00 03 F0 5A 5A + 15 01 00 00 00 00 02 53 28 + 05 01 00 00 00 00 02 38 + 39 01 00 00 00 00 03 F0 A5 A5 ]; qcom,mdss-dsi-panel-aod-mode-command-1 = [ 39 01 00 00 00 00 03 F0 5A 5A @@ -220,7 +252,27 @@ qcom,mdss-dsi-aod-on-command-state = "dsi_lp_mode"; qcom,mdss-dsi-aod-off-command-state = "dsi_lp_mode"; qcom,mdss-dsi-aod-mode-command-state = "dsi_lp_mode"; - + qcom,mdss-dsi-panel-real-aod-off-hbm-on-command = [ + 15 01 00 00 00 00 01 28 + 39 01 00 00 12 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 49 + 15 01 00 00 00 00 02 CB FF + 15 01 00 00 00 00 02 B0 4F + 15 01 00 00 00 00 02 CB C8 + 15 01 00 00 00 00 02 F7 03 + 39 01 00 00 00 00 03 F0 A5 A5 + 05 01 00 00 12 00 01 10 + 05 01 00 00 82 00 01 11 + 39 01 00 00 06 00 03 F0 5A 5A + 15 01 00 00 00 00 02 B0 01 + 15 01 00 00 00 00 02 BB 03 + 15 01 00 00 00 00 08 EF F0 31 00 33 31 14 35 + 15 01 00 00 78 00 02 53 28 + 05 01 00 00 01 00 02 38 + 39 01 00 00 00 00 03 F0 A5 A5 + 15 01 00 00 12 00 01 29 + ]; + qcom,mdss-dsi-panel-real-aod-off-hbm-on-command-state = "dsi_hs_mode"; qcom,mdss-dsi-panel-serial-num-command = [ 06 01 00 00 00 00 01 A1 ]; @@ -313,8 +365,15 @@ 39 01 00 00 00 00 02 E2 00 39 01 00 00 00 00 02 b0 4D 39 01 00 00 00 00 02 E2 00 - 39 01 00 00 00 00 03 f0 A5 A5 + 39 01 00 00 00 00 03 f0 A5 A5 ]; + + 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-customer-p3-enable-command-state = "dsi_lp_mode"; qcom,mdss-dsi-customer-srgb-enable-command-state = "dsi_lp_mode"; qcom,mdss-dsi-laoding-effect-enable-command-state = "dsi_lp_mode"; From fbbb1e9eb60d456c359b9019b3919789d0f66526 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Fri, 1 Apr 2022 10:18:50 +0000 Subject: [PATCH 271/356] ARM: dts: msm: Import some changes from oneplus/SDM845_R_11.0 Change-Id: I3992581efd95cdf6a0d2f16bdf89e4e846a285c2 --- arch/arm64/boot/dts/qcom/pm8998.dtsi | 2 +- arch/arm64/boot/dts/qcom/pmi8998.dtsi | 10 +--------- arch/arm64/boot/dts/qcom/sdm845.dtsi | 7 ++++--- 3 files changed, 6 insertions(+), 13 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/pm8998.dtsi b/arch/arm64/boot/dts/qcom/pm8998.dtsi index 9e6e231f9622..7d7168eeee2d 100644 --- a/arch/arm64/boot/dts/qcom/pm8998.dtsi +++ b/arch/arm64/boot/dts/qcom/pm8998.dtsi @@ -54,7 +54,7 @@ qcom,pull-up = <1>; qcom,s1-timer = <6720>; qcom,s2-timer = <2000>; - qcom,s2-type = ; + qcom,s2-type = ; qcom,use-bark; }; }; diff --git a/arch/arm64/boot/dts/qcom/pmi8998.dtsi b/arch/arm64/boot/dts/qcom/pmi8998.dtsi index 1b7efd5c51ba..a4407664b5f2 100644 --- a/arch/arm64/boot/dts/qcom/pmi8998.dtsi +++ b/arch/arm64/boot/dts/qcom/pmi8998.dtsi @@ -848,20 +848,12 @@ trips { low_soc: low-soc { - temperature = <10>; + temperature = <5>; hysteresis = <0>; type = "passive"; }; }; cooling-maps { - soc_cpu4 { - trip = <&low_soc>; - cooling-device = <&cpu4_isolate 1 1>; - }; - soc_cpu5 { - trip = <&low_soc>; - cooling-device = <&cpu5_isolate 1 1>; - }; soc_map6 { trip = <&low_soc>; cooling-device = <&cpu6_isolate 1 1>; diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index dea895bef76e..00f3c38311f6 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -2780,7 +2780,7 @@ qcom,iommu-dma-addr-pool = <0x20000000 0x40000000>; /* modem tables in IMEM */ qcom,additional-mapping = <0x146BD000 0x146BD000 0x2000>; - qcom,iommu-dma = "fastmap"; + qcom,iommu-dma = "bypass"; }; ipa_smmu_wlan: ipa_smmu_wlan { @@ -2788,13 +2788,14 @@ iommus = <&apps_smmu 0x721 0x0>; /* ipa-uc ram */ qcom,additional-mapping = <0x1E60000 0x1E60000 0x80000>; - qcom,iommu-dma = "atomic"; + qcom,iommu-dma = "bypass"; }; ipa_smmu_uc: ipa_smmu_uc { compatible = "qcom,ipa-smmu-uc-cb"; iommus = <&apps_smmu 0x722 0x0>; qcom,iommu-dma-addr-pool = <0x40000000 0x20000000>; + qcom,iommu-dma = "bypass"; }; }; @@ -3068,7 +3069,7 @@ , ; qcom,iommu-dma-addr-pool = <0xa0000000 0x10000000>; - qcom,iommu-dma = "fastmap"; + qcom,iommu-dma = "bypass"; qcom,iommu-faults = "stall-disable", "non-fatal"; qcom,hyp_enabled; qcom,wlan-msa-memory = <0x100000>; From 7fd0f1aeef8e3761679bcc91e61bfe1d03eca294 Mon Sep 17 00:00:00 2001 From: LuK1337 Date: Wed, 8 Sep 2021 14:24:49 +0200 Subject: [PATCH 272/356] drivers: power: Sync with oneplus/SDM845_R_11.0 Coincidentally, this also restores bunch of code that I removed. Change-Id: If1008605910d816a8cecf304655c4e3e180428d0 --- drivers/power/supply/power_supply_sysfs.c | 3 + .../power/supply/qcom/bq27541_fuelgauger.c | 37 +++- drivers/power/supply/qcom/fg-util.c | 2 +- drivers/power/supply/qcom/oneplus_fastchg.c | 54 +++++- drivers/power/supply/qcom/qg-reg.h | 181 +++++++++--------- drivers/power/supply/qcom/qg-sdam.c | 22 +++ drivers/power/supply/qcom/qg-sdam.h | 4 + drivers/power/supply/qcom/qpnp-fg-gen3.c | 36 +++- drivers/power/supply/qcom/qpnp-qg.c | 41 ++++ drivers/power/supply/qcom/qpnp-smb2.c | 52 ++--- drivers/power/supply/qcom/smb-lib.c | 112 +++++++++-- drivers/power/supply/qcom/smb-lib.h | 15 +- include/linux/power/oem_external_fg.h | 1 + include/linux/power_supply.h | 3 + 14 files changed, 408 insertions(+), 155 deletions(-) diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c index 01ab8b04c998..02c2877c3acd 100644 --- a/drivers/power/supply/power_supply_sysfs.c +++ b/drivers/power/supply/power_supply_sysfs.c @@ -407,6 +407,9 @@ static struct device_attribute power_supply_attrs[] = { POWER_SUPPLY_ATTR(temp_cold), POWER_SUPPLY_ATTR(temp_hot), POWER_SUPPLY_ATTR(system_temp_level), + POWER_SUPPLY_ATTR(battery_health), + POWER_SUPPLY_ATTR(op_disable_charge), + POWER_SUPPLY_ATTR(remaining_capacity), POWER_SUPPLY_ATTR(resistance), POWER_SUPPLY_ATTR(resistance_capacitive), POWER_SUPPLY_ATTR(resistance_id), diff --git a/drivers/power/supply/qcom/bq27541_fuelgauger.c b/drivers/power/supply/qcom/bq27541_fuelgauger.c index c914c2255522..86c99ee10950 100755 --- a/drivers/power/supply/qcom/bq27541_fuelgauger.c +++ b/drivers/power/supply/qcom/bq27541_fuelgauger.c @@ -93,6 +93,7 @@ #define BQ27411_REG_AI 0x10 #define BQ27411_REG_SOC 0x1c #define BQ27411_REG_HEALTH 0x20 +#define BQ27411_REG_FCC 0xE #define BQ27411_REG_OVER_TEMP 0x40 #define BQ27411_REG_GET_OVER_TEMP_EN 0x0002 @@ -249,6 +250,7 @@ struct bq27541_device_info { bool disable_calib_soc; unsigned long lcd_off_time; unsigned long soc_pre_time; + /* david.liu@oneplus.tw, 2016/05/16 Fix capacity won't udate */ unsigned long soc_store_time; #ifdef CONFIG_GAUGE_BQ27411 /* david.liu@bsp, 20161004 Add BQ27411 support */ @@ -262,7 +264,6 @@ struct bq27541_device_info { }; /*add by yangrujin@bsp 2016/3/16, reduce bq resume time*/ - #include struct update_pre_capacity_data { @@ -912,6 +913,28 @@ static int bq27541_remaining_capacity(struct bq27541_device_info *di) return cap; } +static int bq27541_full_chg_capacity(struct bq27541_device_info *di) +{ + int ret; + int cap = 0; + + if (di->allow_reading) { +#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; + } + } + + return cap; +} + static int bq27541_batt_health(struct bq27541_device_info *di) { int ret; @@ -943,6 +966,11 @@ 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); @@ -1107,6 +1135,8 @@ static struct external_battery_gauge bq27541_batt_gauge = { .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 @@ -1203,6 +1233,7 @@ static void update_battery_soc_work(struct work_struct *work) bq27541_get_batt_remaining_capacity(); pr_debug("battery remain capacity:%d\n", bq27541_get_batt_health()); + bq27541_get_batt_full_chg_capacity(); bq27541_set_allow_reading(false); bq27541_temperature_thrshold_update(temp); if (!bq27541_di->already_modify_smooth) @@ -1507,6 +1538,8 @@ static void update_pre_capacity_func(struct work_struct *w) 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"); @@ -1585,7 +1618,7 @@ static int unseal(u32 key) bq27541_cntl_cmd(bq27541_di, 0xffff); usleep_range(10000, 10001); - if (get_boot_mode() == MSM_BOOT_MODE__RECOVERY) + if (get_boot_mode() == MSM_BOOT_MODE__RECOVERY || get_boot_mode() == MSM_BOOT_MODE__CHARGE) SEAL_POLLING_RETRY_LIMIT_2 = 10; else SEAL_POLLING_RETRY_LIMIT_2 = 100; diff --git a/drivers/power/supply/qcom/fg-util.c b/drivers/power/supply/qcom/fg-util.c index a8cdce3e6221..d37807b06280 100644 --- a/drivers/power/supply/qcom/fg-util.c +++ b/drivers/power/supply/qcom/fg-util.c @@ -1461,7 +1461,7 @@ static ssize_t fg_sram_dfs_reg_write(struct file *file, const char __user *buf, { int bytes_read; int data; - int pos = 0; + u32 pos = 0; int cnt = 0; u8 *values; char *kbuf; diff --git a/drivers/power/supply/qcom/oneplus_fastchg.c b/drivers/power/supply/qcom/oneplus_fastchg.c index 022edd1b262d..c0167951994d 100755 --- a/drivers/power/supply/qcom/oneplus_fastchg.c +++ b/drivers/power/supply/qcom/oneplus_fastchg.c @@ -23,7 +23,6 @@ #define BYTE_OFFSET 2 #define BYTES_TO_WRITE 16 - #define READ_COUNT 192 #define FW_CHECK_FAIL 0 #define FW_CHECK_SUCCESS 1 @@ -54,8 +53,8 @@ struct fastchg_device_info { bool is_mcl_verion; int mcu_reset_ahead; int erase_count; - int addr_low; - int addr_high; + int addr_low; + int addr_high; int adapter_update_report; int adapter_update_real; int battery_type; @@ -78,8 +77,8 @@ struct fastchg_device_info { struct delayed_work update_firmware; struct delayed_work update_fireware_version_work; struct delayed_work adapter_update_work; - char fw_id[12]; - char manu_name[12]; + char fw_id[255]; + char manu_name[255]; }; struct fastchg_device_info *fastchg_di; @@ -173,6 +172,36 @@ static void init_enhance_dash_exist_node(void) //for mcu_data irq delay issue 2017.10.14@Infi extern void msm_cpuidle_set_sleep_disable(bool disable); +static int is_usb_pluged(void) +{ + static struct power_supply *psy; + union power_supply_propval ret = {0,}; + int usb_present, rc; + + if (!psy) { + psy = power_supply_get_by_name("usb"); + if (!psy) { + pr_err("fastchg failed to get ps usb\n"); + return -EINVAL; + } + } + + rc = power_supply_get_property(psy, POWER_SUPPLY_PROP_PRESENT, &ret); + if (rc) { + pr_err("fastchg failed to get POWER_SUPPLY_PROP_PRESENT\n"); + return -EINVAL; + } + + if (ret.intval < 0) { + pr_err("fastchg get POWER_SUPPLY_PROP_PRESENT EINVAL \n"); + return -EINVAL; + } + + pr_info("%s usb_present [%d]\n", __func__, usb_present); + usb_present = ret.intval; + return usb_present; +} + void opchg_set_data_active(struct fastchg_device_info *chip) { gpio_direction_input(chip->ap_data); @@ -317,7 +346,6 @@ static bool n76e_fw_check(struct fastchg_device_info *chip) return FW_CHECK_SUCCESS; } - static bool dashchg_fw_check(void) { unsigned char addr_buf[2] = {0x88, 0x00}; @@ -506,9 +534,9 @@ static void dashchg_fw_update(struct work_struct *work) /* 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(); + else + rc = n76e_fw_check(di); if (rc == FW_CHECK_FAIL) { download_again++; if (download_again > 3) @@ -1136,7 +1164,16 @@ static long dash_dev_ioctl(struct file *filp, unsigned int cmd, dash_write(di, ALLOW_DATA); break; case DASH_NOTIFY_UPDATE_ADAPTER_INFO: + if (is_usb_pluged() > 0) { 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); + } else { + pr_err("usb is not online."); + } break; case DASH_NOTIFY_BAD_CONNECTED: @@ -1505,6 +1542,7 @@ static int dash_probe(struct i2c_client *client, const struct i2c_device_id *id) ret = -ENOMEM; goto err_check_functionality_failed; } + di->client = mcu_client = client; di->firmware_already_updated = false; di->irq_enabled = true; diff --git a/drivers/power/supply/qcom/qg-reg.h b/drivers/power/supply/qcom/qg-reg.h index f97d8c3d1f1f..6ce4f381a865 100644 --- a/drivers/power/supply/qcom/qg-reg.h +++ b/drivers/power/supply/qcom/qg-reg.h @@ -6,131 +6,132 @@ #ifndef __QG_REG_H__ #define __QG_REG_H__ -#define PERPH_TYPE_REG 0x04 +#define PERPH_TYPE_REG 0x04 -#define PERPH_SUBTYPE_REG 0x05 -#define QG_ADC_IBAT_5A 0x3 -#define QG_ADC_IBAT_10A 0x4 +#define PERPH_SUBTYPE_REG 0x05 +#define QG_ADC_IBAT_5A 0x3 +#define QG_ADC_IBAT_10A 0x4 -#define QG_TYPE 0x0D +#define QG_TYPE 0x0D -#define QG_STATUS1_REG 0x08 -#define QG_OK_BIT BIT(7) -#define BATTERY_PRESENT_BIT BIT(0) -#define ESR_MEAS_DONE_BIT BIT(4) +#define QG_STATUS1_REG 0x08 +#define QG_OK_BIT BIT(7) +#define BATTERY_PRESENT_BIT BIT(0) +#define ESR_MEAS_DONE_BIT BIT(4) -#define QG_STATUS2_REG 0x09 -#define BATTERY_MISSING_BIT BIT(3) -#define GOOD_OCV_BIT BIT(1) +#define QG_STATUS2_REG 0x09 +#define BATTERY_MISSING_BIT BIT(3) +#define GOOD_OCV_BIT BIT(1) -#define QG_STATUS3_REG 0x0A -#define COUNT_FIFO_RT_MASK GENMASK(3, 0) +#define QG_STATUS3_REG 0x0A +#define COUNT_FIFO_RT_MASK GENMASK(3, 0) -#define QG_STATUS4_REG 0x0B -#define ESR_MEAS_IN_PROGRESS_BIT BIT(4) +#define QG_STATUS4_REG 0x0B +#define ESR_MEAS_IN_PROGRESS_BIT BIT(4) -#define QG_INT_RT_STS_REG 0x10 -#define FIFO_UPDATE_DONE_RT_STS_BIT BIT(3) -#define VBAT_LOW_INT_RT_STS_BIT BIT(1) -#define BATTERY_MISSING_INT_RT_STS_BIT BIT(0) +#define QG_INT_RT_STS_REG 0x10 +#define FIFO_UPDATE_DONE_RT_STS_BIT BIT(3) +#define VBAT_LOW_INT_RT_STS_BIT BIT(1) +#define BATTERY_MISSING_INT_RT_STS_BIT BIT(0) -#define QG_INT_LATCHED_STS_REG 0x18 -#define FIFO_UPDATE_DONE_INT_LAT_STS_BIT BIT(3) +#define QG_INT_LATCHED_STS_REG 0x18 +#define FIFO_UPDATE_DONE_INT_LAT_STS_BIT BIT(3) -#define QG_STATE_TRIG_CMD_REG 0x40 -#define S7_PON_OCV_START BIT(3) +#define QG_STATE_TRIG_CMD_REG 0x40 +#define S7_PON_OCV_START BIT(3) -#define QG_DATA_CTL1_REG 0x41 -#define MASTER_HOLD_OR_CLR_BIT BIT(0) +#define QG_DATA_CTL1_REG 0x41 +#define MASTER_HOLD_OR_CLR_BIT BIT(0) -#define QG_DATA_CTL2_REG 0x42 -#define BURST_AVG_HOLD_FOR_READ_BIT BIT(0) +#define QG_DATA_CTL2_REG 0x42 +#define BURST_AVG_HOLD_FOR_READ_BIT BIT(0) -#define QG_MODE_CTL1_REG 0x43 -#define PARALLEL_IBAT_SENSE_EN_BIT BIT(7) +#define QG_MODE_CTL1_REG 0x43 +#define PARALLEL_IBAT_SENSE_EN_BIT BIT(7) -#define QG_MODE_CTL2_REG 0x44 -#define VI_MODE_BIT BIT(0) +#define QG_MODE_CTL2_REG 0x44 +#define VI_MODE_BIT BIT(0) -#define QG_VBAT_EMPTY_THRESHOLD_REG 0x4B -#define QG_VBAT_LOW_THRESHOLD_REG 0x4C +#define QG_VBAT_EMPTY_THRESHOLD_REG 0x4B +#define QG_VBAT_LOW_THRESHOLD_REG 0x4C -#define QG_S2_NORMAL_MEAS_CTL2_REG 0x51 -#define FIFO_LENGTH_MASK GENMASK(5, 3) -#define FIFO_LENGTH_SHIFT 3 -#define NUM_OF_ACCUM_MASK GENMASK(2, 0) +#define QG_S2_NORMAL_MEAS_CTL2_REG 0x51 +#define FIFO_LENGTH_MASK GENMASK(5, 3) +#define FIFO_LENGTH_SHIFT 3 +#define NUM_OF_ACCUM_MASK GENMASK(2, 0) -#define QG_S2_NORMAL_MEAS_CTL3_REG 0x52 +#define QG_S2_NORMAL_MEAS_CTL3_REG 0x52 -#define QG_S3_SLEEP_OCV_MEAS_CTL4_REG 0x59 -#define S3_SLEEP_OCV_TIMER_MASK GENMASK(2, 0) +#define QG_S3_SLEEP_OCV_MEAS_CTL4_REG 0x59 +#define S3_SLEEP_OCV_TIMER_MASK GENMASK(2, 0) -#define QG_S3_SLEEP_OCV_TREND_CTL2_REG 0x5C -#define TREND_TOL_MASK GENMASK(5, 0) +#define QG_S3_SLEEP_OCV_TREND_CTL2_REG 0x5C +#define TREND_TOL_MASK GENMASK(5, 0) -#define QG_S3_SLEEP_OCV_IBAT_CTL1_REG 0x5D -#define SLEEP_IBAT_QUALIFIED_LENGTH_MASK GENMASK(2, 0) +#define QG_S3_SLEEP_OCV_IBAT_CTL1_REG 0x5D +#define SLEEP_IBAT_QUALIFIED_LENGTH_MASK GENMASK(2, 0) -#define QG_S3_ENTRY_IBAT_THRESHOLD_REG 0x5E -#define QG_S3_EXIT_IBAT_THRESHOLD_REG 0x5F +#define QG_S3_ENTRY_IBAT_THRESHOLD_REG 0x5E +#define QG_S3_EXIT_IBAT_THRESHOLD_REG 0x5F -#define QG_S5_OCV_VALIDATE_MEAS_CTL1_REG 0x60 -#define ALLOW_S5_BIT BIT(7) +#define QG_S5_OCV_VALIDATE_MEAS_CTL1_REG 0x60 +#define ALLOW_S5_BIT BIT(7) -#define QG_S7_PON_OCV_MEAS_CTL1_REG 0x64 -#define ADC_CONV_DLY_MASK GENMASK(3, 0) +#define QG_S7_PON_OCV_MEAS_CTL1_REG 0x64 +#define ADC_CONV_DLY_MASK GENMASK(3, 0) -#define QG_ESR_MEAS_TRIG_REG 0x68 -#define HW_ESR_MEAS_START_BIT BIT(0) +#define QG_ESR_MEAS_TRIG_REG 0x68 +#define HW_ESR_MEAS_START_BIT BIT(0) -#define QG_S7_PON_OCV_V_DATA0_REG 0x70 -#define QG_S7_PON_OCV_I_DATA0_REG 0x72 -#define QG_S3_GOOD_OCV_V_DATA0_REG 0x74 -#define QG_S3_GOOD_OCV_I_DATA0_REG 0x76 +#define QG_S7_PON_OCV_V_DATA0_REG 0x70 +#define QG_S7_PON_OCV_I_DATA0_REG 0x72 +#define QG_S3_GOOD_OCV_V_DATA0_REG 0x74 +#define QG_S3_GOOD_OCV_I_DATA0_REG 0x76 -#define QG_PRE_ESR_V_DATA0_REG 0x78 -#define QG_PRE_ESR_I_DATA0_REG 0x7A -#define QG_POST_ESR_V_DATA0_REG 0x7C -#define QG_POST_ESR_I_DATA0_REG 0x7E +#define QG_PRE_ESR_V_DATA0_REG 0x78 +#define QG_PRE_ESR_I_DATA0_REG 0x7A +#define QG_POST_ESR_V_DATA0_REG 0x7C +#define QG_POST_ESR_I_DATA0_REG 0x7E -#define QG_S2_NORMAL_AVG_V_DATA0_REG 0x80 -#define QG_S2_NORMAL_AVG_I_DATA0_REG 0x82 +#define QG_S2_NORMAL_AVG_V_DATA0_REG 0x80 +#define QG_S2_NORMAL_AVG_I_DATA0_REG 0x82 -#define QG_V_ACCUM_DATA0_RT_REG 0x88 -#define QG_I_ACCUM_DATA0_RT_REG 0x8B -#define QG_ACCUM_CNT_RT_REG 0x8E +#define QG_V_ACCUM_DATA0_RT_REG 0x88 +#define QG_I_ACCUM_DATA0_RT_REG 0x8B +#define QG_ACCUM_CNT_RT_REG 0x8E -#define QG_V_FIFO0_DATA0_REG 0x90 -#define QG_I_FIFO0_DATA0_REG 0xA0 +#define QG_V_FIFO0_DATA0_REG 0x90 +#define QG_I_FIFO0_DATA0_REG 0xA0 -#define QG_SOC_MONOTONIC_REG 0xBF +#define QG_SOC_MONOTONIC_REG 0xBF -#define QG_LAST_ADC_V_DATA0_REG 0xC0 -#define QG_LAST_ADC_I_DATA0_REG 0xC2 +#define QG_LAST_ADC_V_DATA0_REG 0xC0 +#define QG_LAST_ADC_I_DATA0_REG 0xC2 -#define QG_LAST_BURST_AVG_I_DATA0_REG 0xC6 +#define QG_LAST_BURST_AVG_I_DATA0_REG 0xC6 -#define QG_LAST_S3_SLEEP_V_DATA0_REG 0xCC +#define QG_LAST_S3_SLEEP_V_DATA0_REG 0xCC /* SDAM offsets */ -#define QG_SDAM_VALID_OFFSET 0x46 /* 1-byte 0x46 */ -#define QG_SDAM_SOC_OFFSET 0x47 /* 1-byte 0x47 */ -#define QG_SDAM_TEMP_OFFSET 0x48 /* 2-byte 0x48-0x49 */ -#define QG_SDAM_RBAT_OFFSET 0x4A /* 2-byte 0x4A-0x4B */ -#define QG_SDAM_OCV_OFFSET 0x4C /* 4-byte 0x4C-0x4F */ -#define QG_SDAM_IBAT_OFFSET 0x50 /* 4-byte 0x50-0x53 */ -#define QG_SDAM_TIME_OFFSET 0x54 /* 4-byte 0x54-0x57 */ -#define QG_SDAM_CYCLE_COUNT_OFFSET 0x58 /* 16-byte 0x58-0x67 */ -#define QG_SDAM_LEARNED_CAPACITY_OFFSET 0x68 /* 2-byte 0x68-0x69 */ -#define QG_SDAM_ESR_CHARGE_DELTA_OFFSET 0x6A /* 4-byte 0x6A-0x6D */ -#define QG_SDAM_ESR_DISCHARGE_DELTA_OFFSET 0x6E /* 4-byte 0x6E-0x71 */ -#define QG_SDAM_ESR_CHARGE_SF_OFFSET 0x72 /* 2-byte 0x72-0x73 */ -#define QG_SDAM_ESR_DISCHARGE_SF_OFFSET 0x74 /* 2-byte 0x74-0x75 */ -#define QG_SDAM_BATT_AGE_LEVEL_OFFSET 0x76 /* 1-byte 0x76 */ -#define QG_SDAM_FLASH_OCV_OFFSET 0x84 /* 1-byte 0x84 */ -#define QG_SDAM_MAX_OFFSET 0xA4 +#define QG_SDAM_VALID_OFFSET 0x46 /* 1-byte 0x46 */ +#define QG_SDAM_SOC_OFFSET 0x47 /* 1-byte 0x47 */ +#define QG_SDAM_TEMP_OFFSET 0x48 /* 2-byte 0x48-0x49 */ +#define QG_SDAM_RBAT_OFFSET 0x4A /* 2-byte 0x4A-0x4B */ +#define QG_SDAM_OCV_OFFSET 0x4C /* 4-byte 0x4C-0x4F */ +#define QG_SDAM_IBAT_OFFSET 0x50 /* 4-byte 0x50-0x53 */ +#define QG_SDAM_TIME_OFFSET 0x54 /* 4-byte 0x54-0x57 */ +#define QG_SDAM_CYCLE_COUNT_OFFSET 0x58 /* 16-byte 0x58-0x67 */ +#define QG_SDAM_LEARNED_CAPACITY_OFFSET 0x68 /* 2-byte 0x68-0x69 */ +#define QG_SDAM_ESR_CHARGE_DELTA_OFFSET 0x6A /* 4-byte 0x6A-0x6D */ +#define QG_SDAM_ESR_DISCHARGE_DELTA_OFFSET 0x6E /* 4-byte 0x6E-0x71 */ +#define QG_SDAM_ESR_CHARGE_SF_OFFSET 0x72 /* 2-byte 0x72-0x73 */ +#define QG_SDAM_ESR_DISCHARGE_SF_OFFSET 0x74 /* 2-byte 0x74-0x75 */ +#define QG_SDAM_BATT_AGE_LEVEL_OFFSET 0x76 /* 1-byte 0x76 */ +#define QG_SDAM_MAGIC_OFFSET 0x80 /* 4-byte 0x80-0x83 */ +#define QG_SDAM_FLASH_OCV_OFFSET 0x84 /* 1-byte 0x84 */ +#define QG_SDAM_MAX_OFFSET 0xA4 /* Below offset is used by PBS */ -#define QG_SDAM_PON_OCV_OFFSET 0xBC /* 2-byte 0xBC-0xBD */ +#define QG_SDAM_PON_OCV_OFFSET 0xBC /* 2-byte 0xBC-0xBD */ #endif diff --git a/drivers/power/supply/qcom/qg-sdam.c b/drivers/power/supply/qcom/qg-sdam.c index 74e9a0edb4ba..8f48afa51fec 100644 --- a/drivers/power/supply/qcom/qg-sdam.c +++ b/drivers/power/supply/qcom/qg-sdam.c @@ -86,6 +86,11 @@ static struct qg_sdam_info sdam_info[] = { .offset = QG_SDAM_BATT_AGE_LEVEL_OFFSET, .length = 1, }, + [SDAM_MAGIC] = { + .name = "SDAM_MAGIC_OFFSET", + .offset = QG_SDAM_MAGIC_OFFSET, + .length = 4, + }, [SDAM_FLASH_OCV] = { .name = "SDAM_FLASH_OCV_OFFSET", .offset = QG_SDAM_FLASH_OCV_OFFSET, @@ -245,6 +250,23 @@ int qg_sdam_write_all(u32 *sdam_data) return 0; } +int qg_sdam_clear(void) +{ + int i, rc = 0; + struct qg_sdam *chip = the_chip; + u8 data = 0; + + if (!chip) { + pr_err("Invalid sdam-chip pointer\n"); + return -EINVAL; + } + + for (i = SDAM_MIN_OFFSET; i <= SDAM_MAX_OFFSET; i++) + rc |= qg_sdam_multibyte_write(i, &data, 1); + + return rc; +} + int qg_sdam_init(struct device *dev) { int rc; diff --git a/drivers/power/supply/qcom/qg-sdam.h b/drivers/power/supply/qcom/qg-sdam.h index 5222b87380b0..77385b807f21 100644 --- a/drivers/power/supply/qcom/qg-sdam.h +++ b/drivers/power/supply/qcom/qg-sdam.h @@ -7,6 +7,8 @@ #define __QG_SDAM_H__ #define SDAM_TYPE 0x2E +#define SDAM_MIN_OFFSET 0x45 +#define SDAM_MAX_OFFSET 0xB3 enum qg_sdam_param { SDAM_VALID, @@ -21,6 +23,7 @@ enum qg_sdam_param { SDAM_ESR_DISCHARGE_DELTA, SDAM_ESR_CHARGE_SF, SDAM_ESR_DISCHARGE_SF, + SDAM_MAGIC, SDAM_BATT_AGE_LEVEL, SDAM_FLASH_OCV, SDAM_MAX, @@ -38,5 +41,6 @@ int qg_sdam_write_all(u32 *sdam_data); int qg_sdam_read_all(u32 *sdam_data); int qg_sdam_multibyte_write(u32 offset, u8 *sdam_data, u32 length); int qg_sdam_multibyte_read(u32 offset, u8 *sdam_data, u32 length); +int qg_sdam_clear(void); #endif diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c index fe42ee05997a..2e13b61f6999 100644 --- a/drivers/power/supply/qcom/qpnp-fg-gen3.c +++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c @@ -979,8 +979,11 @@ static int fg_delta_bsoc_irq_en_cb(struct votable *votable, void *data, if (enable) { enable_irq(fg->irqs[BSOC_DELTA_IRQ].irq); + if (fg->irqs[BSOC_DELTA_IRQ].wakeable) + enable_irq_wake(fg->irqs[BSOC_DELTA_IRQ].irq); } else { - disable_irq_wake(fg->irqs[BSOC_DELTA_IRQ].irq); + if (fg->irqs[BSOC_DELTA_IRQ].wakeable) + disable_irq_wake(fg->irqs[BSOC_DELTA_IRQ].irq); disable_irq_nosync(fg->irqs[BSOC_DELTA_IRQ].irq); } @@ -3719,6 +3722,16 @@ static int fg_psy_get_property(struct power_supply *psy, } else pval->intval = -400; break; + /*yangfb@bsp,add for battery health*/ + case POWER_SUPPLY_PROP_BATTERY_HEALTH: + if (fg->use_external_fg && external_fg + && external_fg->get_batt_health) + pval->intval = external_fg->get_batt_health(); + else if (get_extern_fg_regist_done() == false) + pval->intval = -1; + else + pval->intval = -1; + break; case POWER_SUPPLY_PROP_COLD_TEMP: rc = fg_get_jeita_threshold(fg, JEITA_COLD, &pval->intval); if (rc < 0) { @@ -3778,7 +3791,20 @@ static int fg_psy_get_property(struct power_supply *psy, pval->intval = chip->cl.init_cc_uah; break; case POWER_SUPPLY_PROP_CHARGE_FULL: - pval->intval = chip->cl.learned_cc_uah; + 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 + pval->intval = chip->cl.learned_cc_uah; + 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_COUNTER: rc = fg_get_charge_counter(fg, &pval->intval); @@ -4164,10 +4190,12 @@ static enum power_supply_property fg_psy_props[] = { POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, POWER_SUPPLY_PROP_CC_STEP, POWER_SUPPLY_PROP_CC_STEP_SEL, + POWER_SUPPLY_PROP_REAL_CAPACITY, + POWER_SUPPLY_PROP_BATTERY_HEALTH, /* david.liu@bsp, 20171023 Battery & Charging porting */ POWER_SUPPLY_PROP_SET_ALLOW_READ_EXTERN_FG_IIC, POWER_SUPPLY_PROP_BQ_SOC, - POWER_SUPPLY_PROP_REAL_CAPACITY, + POWER_SUPPLY_PROP_REMAINING_CAPACITY, POWER_SUPPLY_PROP_FG_RESET_CLOCK, }; @@ -5740,7 +5768,7 @@ static int fg_gen3_probe(struct platform_device *pdev) device_init_wakeup(fg->dev, true); schedule_delayed_work(&fg->profile_load_work, 0); - pr_debug("FG GEN3 driver probed successfully\n"); + pr_info("FG GEN3 driver probed successfully\n"); return 0; exit: fg_cleanup(chip); diff --git a/drivers/power/supply/qcom/qpnp-qg.c b/drivers/power/supply/qcom/qpnp-qg.c index 31cb23c51a9b..902e69f57f68 100644 --- a/drivers/power/supply/qcom/qpnp-qg.c +++ b/drivers/power/supply/qcom/qpnp-qg.c @@ -3420,6 +3420,41 @@ static int qg_set_wa_flags(struct qpnp_qg *chip) return 0; } +#define SDAM_MAGIC_NUMBER 0x12345678 +static int qg_sanitize_sdam(struct qpnp_qg *chip) +{ + int rc = 0; + u32 data = 0; + + rc = qg_sdam_read(SDAM_MAGIC, &data); + if (rc < 0) { + pr_err("Failed to read SDAM rc=%d\n", rc); + return rc; + } + + if (data == SDAM_MAGIC_NUMBER) { + qg_dbg(chip, QG_DEBUG_PON, "SDAM valid\n"); + } else if (data == 0) { + rc = qg_sdam_write(SDAM_MAGIC, SDAM_MAGIC_NUMBER); + if (!rc) + qg_dbg(chip, QG_DEBUG_PON, "First boot. SDAM initilized\n"); + chip->first_profile_load = true; + } else { + /* SDAM has invalid value */ + rc = qg_sdam_clear(); + if (!rc) { + pr_err("SDAM uninitialized, SDAM reset\n"); + rc = qg_sdam_write(SDAM_MAGIC, SDAM_MAGIC_NUMBER); + } + chip->first_profile_load = true; + } + + if (rc < 0) + pr_err("Failed in SDAM operation, rc=%d\n", rc); + + return rc; +} + #define ADC_CONV_DLY_512MS 0xA #define IBAT_5A_FCC_MA 4800 #define IBAT_10A_FCC_MA 9600 @@ -4752,6 +4787,12 @@ static int qpnp_qg_probe(struct platform_device *pdev) return rc; } + rc = qg_sanitize_sdam(chip); + if (rc < 0) { + pr_err("Failed to sanitize SDAM, rc=%d\n", rc); + return rc; + } + rc = qg_soc_init(chip); if (rc < 0) { pr_err("Failed to initialize SOC scaling init rc=%d\n", rc); diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c index cbfcf696858b..1db495e1a375 100644 --- a/drivers/power/supply/qcom/qpnp-smb2.c +++ b/drivers/power/supply/qcom/qpnp-smb2.c @@ -301,7 +301,6 @@ static int smb2_parse_dt(struct smb2 *chip) struct device_node *node = chg->dev->of_node; /* david.liu@bsp, 20171023 Battery & Charging porting */ int byte_len, rc = 0; - /*yangfb@bsp, 20180302,enable stm6620 sheepmode */ enum of_gpio_flags flags; if (!node) { @@ -428,6 +427,7 @@ static int smb2_parse_dt(struct smb2 *chip) chg->FFC_NORMAL_CUTOFF, chg->FFC_WARM_CUTOFF, chg->FFC_VBAT_FULL); + chg->plug_irq = of_get_named_gpio_flags(node, "op,usb-check", 0, &flags); chg->vbus_ctrl = of_get_named_gpio_flags(node, @@ -1317,8 +1317,8 @@ static enum power_supply_property smb2_batt_props[] = { POWER_SUPPLY_PROP_CHARGE_FULL, POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, - POWER_SUPPLY_PROP_CYCLE_COUNT, POWER_SUPPLY_PROP_FCC_STEPPER_ENABLE, + POWER_SUPPLY_PROP_OP_DISABLE_CHARGE, }; static int smb2_batt_get_prop(struct power_supply *psy, @@ -1349,6 +1349,9 @@ static int smb2_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_OP_DISABLE_CHARGE: + val->intval = chg->chg_disabled; + break; /* david.liu@bsp, 20171023 Battery & Charging porting */ case POWER_SUPPLY_PROP_CHARGE_NOW: rc = smblib_get_prop_usb_voltage_now(chg, val); @@ -1460,7 +1463,6 @@ static int smb2_batt_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_CHARGE_COUNTER: case POWER_SUPPLY_PROP_CHARGE_FULL: case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: - case POWER_SUPPLY_PROP_CYCLE_COUNT: case POWER_SUPPLY_PROP_VOLTAGE_NOW: case POWER_SUPPLY_PROP_TEMP: case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW: @@ -1514,7 +1516,17 @@ static int smb2_batt_set_prop(struct power_supply *psy, pr_info("set iusb %d uA\n", val->intval); if (__debug_mask == PR_OP_DEBUG || val->intval == 900000) - op_usb_icl_set(chg, val->intval); + op_usb_icl_set(chg, val->intval); + break; + case POWER_SUPPLY_PROP_OP_DISABLE_CHARGE: + vote(chg->chg_disable_votable, FORCE_RECHARGE_VOTER, + (bool)val->intval, 0); + if (val->intval) { + switch_mode_to_normal(); + op_set_fast_chg_allow(chg, false); + } + chg->chg_disabled = (bool)val->intval; + pr_info("user set disable chg %d\n", val->intval); break; case POWER_SUPPLY_PROP_CHARGE_NOW: rc = smblib_set_prop_chg_voltage(chg, val); @@ -1536,11 +1548,11 @@ static int smb2_batt_set_prop(struct power_supply *psy, 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; + 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; break; case POWER_SUPPLY_PROP_IS_AGING_TEST: chg->is_aging_test = (bool)val->intval; @@ -1650,6 +1662,7 @@ static int smb2_batt_prop_is_writeable(struct power_supply *psy, case POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED: case POWER_SUPPLY_PROP_SW_JEITA_ENABLED: case POWER_SUPPLY_PROP_DIE_HEALTH: + case POWER_SUPPLY_PROP_OP_DISABLE_CHARGE: return 1; default: break; @@ -2373,15 +2386,6 @@ static int smb2_post_init(struct smb2 *chip) * not requested */ rerun_election(chg->usb_icl_votable); - /* yangfb@bsp, 20180124 ,for EID-1772 */ - /* configure power role for UDP-role */ - rc = smblib_masked_write(chg, TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, - TYPEC_POWER_ROLE_CMD_MASK, UFP_EN_CMD_BIT); - if (rc < 0) { - dev_err(chg->dev, - "Couldn't configure power role for UDP rc=%d\n", rc); - return rc; - } /* Force charger in Sink Only mode */ if (chg->ufp_only_mode) { @@ -2879,6 +2883,7 @@ static const struct file_operations proc_ship_mode_operations = { .llseek = noop_llseek, }; #endif + static irqreturn_t op_usb_plugin_irq_handler(int irq, void *dev_id) { schedule_work(&g_chip->otg_switch_work); @@ -2922,7 +2927,7 @@ static void request_plug_irq(struct smb_charger *chip) chip->pre_cable_pluged = 0; } -void requset_vbus_ctrl_gpio(struct smb_charger *chg) +void request_vbus_ctrl_gpio(struct smb_charger *chg) { int ret; @@ -3131,8 +3136,9 @@ static int smb2_probe(struct platform_device *pdev) device_init_wakeup(chg->dev, true); chg->probe_done = true; + request_vbus_ctrl_gpio(chg); request_plug_irq(chg); - requset_vbus_ctrl_gpio(chg); + pr_info("QPNP SMB2 probed successfully usb:present=%d type=%d batt:present = %d health = %d charge = %d\n", usb_present, chg->real_charger_type, batt_present, batt_health, batt_charge_type); @@ -3168,7 +3174,7 @@ static int smb2_remove(struct platform_device *pdev) /* david.liu@bsp, 20170330 Fix system crash */ if (chg->usb_psy) - power_supply_unregister(chg->batt_psy); + power_supply_unregister(chg->usb_psy); if (chg->batt_psy) power_supply_unregister(chg->batt_psy); if (chg->vconn_vreg && chg->vconn_vreg->rdev) @@ -3190,8 +3196,8 @@ static void smb2_shutdown(struct platform_device *pdev) pr_info("smbchg_shutdown\n"); if (chg->ship_mode) { pr_info("smbchg_shutdown enter ship_mode\n"); - smblib_masked_write(chg, SHIP_MODE_REG, - SHIP_MODE_EN_BIT, SHIP_MODE_EN_BIT); + smblib_masked_write(chg, SHIP_MODE_REG, SHIP_MODE_EN_BIT, + SHIP_MODE_EN_BIT); msleep(1000); pr_err("after 1s\n"); while (1) diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c index 537d0881800a..7eb9c50d8e60 100644 --- a/drivers/power/supply/qcom/smb-lib.c +++ b/drivers/power/supply/qcom/smb-lib.c @@ -54,12 +54,6 @@ struct smb_charger *g_chg; struct qpnp_pon *pm_pon; -/*2018/06/14 @bsp add for support notify audio adapter switch*/ -static BLOCKING_NOTIFIER_HEAD(typec_cc_chain); -static int cc_notifier_call_chain(unsigned long val); -/* infi@bsp, 2018/08/08 add for support audio_adaptor trigger when reboot */ -bool audio_adapter_flag; -EXPORT_SYMBOL(audio_adapter_flag); static struct external_battery_gauge *fast_charger; static int op_charging_en(struct smb_charger *chg, bool en); @@ -101,6 +95,14 @@ static void op_clean_enhache_status(void); __func__, ##__VA_ARGS__); \ } while (0) +/*2018/06/14 @bsp add for support notify audio adapter switch*/ +static BLOCKING_NOTIFIER_HEAD(typec_cc_chain); +static int cc_notifier_call_chain(unsigned long val); + +/* infi@bsp, 2018/08/08 add for support audio_adaptor trigger when reboot */ +bool audio_adapter_flag; +EXPORT_SYMBOL(audio_adapter_flag); + static bool is_secure(struct smb_charger *chg, int addr) { if (addr == SHIP_MODE_REG || addr == FREQ_CLK_DIV_REG) @@ -1082,7 +1084,9 @@ int smblib_set_icl_current(struct smb_charger *chg, int icl_ua) { int rc = 0; bool override; +/* david.liu@bsp, 20171023 Battery & Charging porting */ pr_info("icl_ua=%d\n", icl_ua); + /* suspend and return if 25mA or less is requested */ if (icl_ua <= USBIN_25MA) return smblib_set_usb_suspend(chg, true); @@ -2342,6 +2346,55 @@ int op_set_prop_otg_switch(struct smb_charger *chg, pre_otg_switch = chg->otg_switch; chg->otg_switch = enable; + if (chg->otg_switch == pre_otg_switch) + return rc; + + pr_info("set otg_switch=%d\n", chg->otg_switch); + if (chg->otg_switch) + power_role = 0; + else + power_role = UFP_EN_CMD_BIT; + + for (i = 0; i < 10; i++) { + rc = smblib_masked_write(chg, + TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, + TYPEC_POWER_ROLE_CMD_MASK, power_role); + if (rc < 0) { + smblib_err(chg, "Couldn't write 0x%02x to 0x1368 rc=%d\n", + power_role, rc); + return rc; + } + usleep_range(30000, 31000); + ctrl = 0; + rc = smblib_read(chg, + TYPE_C_INTRPT_ENB_SOFTWARE_CTRL_REG, &ctrl); + if (rc < 0) { + smblib_err(chg, "Couldn't read err=%d\n", rc); + return rc; + } + if ((power_role == 0) && ((ctrl & POWER_ROLE_BIT) == 0)) + break; + if ((power_role == UFP_EN_CMD_BIT) && (ctrl & UFP_EN_CMD_BIT)) + break; + } + pr_info("retry time = %d,ctrl = %d\n", i, ctrl); + if (i == 10) + pr_err("retry time over\n"); + + return rc; +} + +int op_set_otg_switch(struct smb_charger *chg, bool enable) +{ + int rc = 0; + u8 power_role; + u8 ctrl = 0; + bool pre_otg_switch; + int i = 0; + + pre_otg_switch = chg->otg_switch; + chg->otg_switch = enable; + if (chg->otg_switch == pre_otg_switch) return rc; @@ -3959,11 +4012,15 @@ static inline void op_dump_reg(struct smb_charger *chip, 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)); - smblib_read(chip, addr, ®); + rc = smblib_read(chip, addr, ®); + if (rc < 0) + smblib_err(chip, "op_dump_reg read error addr=%d rc=%d\n", + addr, rc); scnprintf(reg_val, sizeof(reg_val), "%x=%0x;", addr, reg); strlcat(dump_val, reg_val, sizeof(dump_val)); @@ -4545,6 +4602,7 @@ static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising) return; apsd_result = smblib_update_usb_type(chg); + if (!chg->typec_legacy_valid) smblib_force_legacy_icl(chg, apsd_result->pst); @@ -4572,6 +4630,7 @@ static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising) default: break; } + /* david.liu@bsp, 20171023 Battery & Charging porting */ if ((apsd_result->bit) == SDP_CHARGER_BIT) current_limit_ua = SDP_CURRENT_UA; @@ -4872,6 +4931,7 @@ static void typec_sink_insertion(struct smb_charger *chg) } typec_mode = smblib_get_prop_typec_mode(chg); + /*2018/06/14 @bsp add for support notify audio adapter switch*/ if (typec_mode == POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER) { chg->is_audio_adapter = true; @@ -5035,7 +5095,6 @@ static void smblib_handle_typec_removal(struct smb_charger *chg) if (chg->is_audio_adapter) { /* wait for the audio driver to lower its en gpio */ msleep(*chg->audio_headset_drp_wait_ms); - chg->is_audio_adapter = false; audio_adapter_flag = false; pr_info("Type-C removal, audio_adapter_present=(%d),notify!\n", @@ -5546,7 +5605,12 @@ static int op_charging_en(struct smb_charger *chg, bool en) { int rc; - pr_err("enable=%d\n", en); + 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); @@ -5608,6 +5672,8 @@ bool is_fastchg_allowed(struct smb_charger *chg) low_temp_full = op_get_fast_low_temp_full(chg); fw_updated = get_fastchg_firmware_updated_status(chg); + if (chg->chg_disabled) + return false; if (!fw_updated) return false; if (chg->usb_enum_status) @@ -5684,9 +5750,12 @@ static void op_handle_usb_removal(struct smb_charger *chg) chg->recovery_boost_count = 0; chg->dash_check_count = 0; chg->ffc_count = 0; + chg->chg_disabled = 0; vote(chg->fcc_votable, - DEFAULT_VOTER, true, SDP_CURRENT_UA); + DEFAULT_VOTER, true, SDP_CURRENT_UA); set_sdp_current(chg, USBIN_500MA); + vote(chg->chg_disable_votable, + FORCE_RECHARGE_VOTER, false, 0); op_battery_temp_region_set(chg, BATT_TEMP_INVALID); } @@ -6071,6 +6140,10 @@ static void retrigger_dash_work(struct work_struct *work) chg->ck_dash_count = 0; return; } + if (chg->chg_disabled) { + chg->ck_dash_count = 0; + return; + } if (chg->ck_dash_count >= DASH_CHECK_COUNT) { pr_info("retrger dash\n"); chg->re_trigr_dash_done = true; @@ -7020,6 +7093,9 @@ static int msm_drm_notifier_callback(struct notifier_block *self, container_of(self, struct smb_charger, msm_drm_notifier); int *blank; + if (!evdata) + return 0; + if (evdata->id != MSM_DRM_PRIMARY_DISPLAY) return 0; if (event != MSM_DRM_EARLY_EVENT_BLANK) @@ -7445,7 +7521,6 @@ int plugin_update(struct smb_charger *chg) return rc; } - static void op_otg_switch(struct work_struct *work) { int usb_pluged; @@ -7459,6 +7534,7 @@ static void op_otg_switch(struct work_struct *work) return; } pr_info("%s,usb_present:%d\n", __func__, usb_pluged); + if (usb_pluged) { vote(g_chg->otg_toggle_votable, HW_DETECT_VOTER, 1, 0); g_chg->hw_detect = 1; @@ -7472,6 +7548,7 @@ static void op_otg_switch(struct work_struct *work) g_chg->pre_cable_pluged = usb_pluged; } + static int get_usb_temp(struct smb_charger *chg) { struct qpnp_vadc_chip *vadc_dev; @@ -7600,6 +7677,10 @@ static void op_heartbeat_work(struct work_struct *work) power_supply_changed(chg->batt_psy); chg->dash_on = get_prop_fast_chg_started(chg); if (chg->dash_on) { + if (chg->chg_disabled) { + set_usb_switch(chg, false); + goto out; + } switch_fast_chg(chg); pr_info("fast chg started, usb_switch=%d\n", op_is_usb_switch_on(chg)); @@ -7772,14 +7853,7 @@ static int load_data(struct smb_charger *chg) return SOC_INVALID; } - /* the fist time connect battery, the PM 0x88d bit7 is 0, */ - /* we do not need load this data. */ - if (flag) - shutdown_soc = (stored_soc >> 1); - /* get data from bit1~bit7 */ - else - shutdown_soc = SOC_INVALID; - + shutdown_soc = (stored_soc >> 1); pr_info("stored_soc[0x%x], shutdown_soc[%d]\n", stored_soc, shutdown_soc); return shutdown_soc; diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h index 580a4638190a..02cc0ff7a6dd 100644 --- a/drivers/power/supply/qcom/smb-lib.h +++ b/drivers/power/supply/qcom/smb-lib.h @@ -82,6 +82,7 @@ enum print_reason { #define OTG_VOTER "OTG_VOTER" #define PL_FCC_LOW_VOTER "PL_FCC_LOW_VOTER" #define WBC_VOTER "WBC_VOTER" +#define FORCE_RECHARGE_VOTER "FORCE_RECHARGE_VOTER" #define MOISTURE_VOTER "MOISTURE_VOTER" #define HVDCP2_ICL_VOTER "HVDCP2_ICL_VOTER" #define OV_VOTER "OV_VOTER" @@ -277,9 +278,7 @@ struct smb_charger { struct mutex vconn_oc_lock; /* david.liu@bsp, 20171023 Battery & Charging porting */ struct mutex sw_dash_lock; -/*yangfb@bsp, 20180302,enable stm6620 sheepmode */ - struct pinctrl_state *pinctrl_state_default; - struct pinctrl *pinctrl; + /* power supplies */ struct power_supply *batt_psy; struct power_supply *usb_psy; @@ -346,11 +345,10 @@ struct smb_charger { struct delayed_work op_re_set_work; struct delayed_work op_check_apsd_work; struct work_struct get_aicl_work; + struct work_struct otg_switch_work; struct delayed_work dash_check_work; struct delayed_work revertboost_recovery_work; struct delayed_work connecter_check_work; - struct delayed_work op_icl_set_work; - struct work_struct otg_switch_work; struct wakeup_source chg_wake_lock; struct delayed_work clear_hdc_work; struct work_struct otg_oc_work; @@ -397,11 +395,11 @@ struct smb_charger { int ck_apsd_count; int ck_dash_count; int recovery_boost_count; - int op_icl_val; int plug_irq; - int sw_iterm_ma; int pre_cable_pluged; int hw_detect; + int op_icl_val; + int sw_iterm_ma; bool otg_switch; bool use_fake_chgvol; bool use_fake_temp; @@ -418,6 +416,7 @@ struct smb_charger { 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; @@ -627,8 +626,8 @@ 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); -void op_disconnect_vbus(struct smb_charger *chg, bool enable); int plugin_update(struct smb_charger *chg); +void op_disconnect_vbus(struct smb_charger *chg, bool enable); int smblib_set_prop_input_current_limited(struct smb_charger *chg, const union power_supply_propval *val); diff --git a/include/linux/power/oem_external_fg.h b/include/linux/power/oem_external_fg.h index d6163341b68b..7c7b2e6d4ca4 100644 --- a/include/linux/power/oem_external_fg.h +++ b/include/linux/power/oem_external_fg.h @@ -37,6 +37,7 @@ struct external_battery_gauge { 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); diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 911178903806..c9dfa2a7080a 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -277,6 +277,9 @@ enum power_supply_property { POWER_SUPPLY_PROP_COLD_TEMP, POWER_SUPPLY_PROP_HOT_TEMP, POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL, + POWER_SUPPLY_PROP_BATTERY_HEALTH, + POWER_SUPPLY_PROP_OP_DISABLE_CHARGE, + POWER_SUPPLY_PROP_REMAINING_CAPACITY, POWER_SUPPLY_PROP_RESISTANCE, POWER_SUPPLY_PROP_RESISTANCE_CAPACITIVE, POWER_SUPPLY_PROP_RESISTANCE_ID, /* in Ohms */ From 329665fad85792e25d98ef127cd7d59cf906e5ad Mon Sep 17 00:00:00 2001 From: LuK1337 Date: Fri, 16 Apr 2021 14:52:14 +0200 Subject: [PATCH 273/356] Revert "power: fg-gen3: Report TIME_TO_FULL_NOW property" When DASH charging, fg_get_time_to_full() returns invalid data, e.g. it returns that the phone will charge to full in 61522 seconds. This (partially) reverts commit 1e4fbcb18664ee390f369b9777a36fa3b63fb54d. Change-Id: I3325b52c504c802cf4073794f39e118fd2068916 --- drivers/power/supply/qcom/qpnp-fg-gen3.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c index 2e13b61f6999..5deafc16a090 100644 --- a/drivers/power/supply/qcom/qpnp-fg-gen3.c +++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c @@ -3815,9 +3815,6 @@ static int fg_psy_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG: rc = fg_get_time_to_full(fg, &pval->intval); break; - case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW: - rc = fg_get_time_to_full(fg, &pval->intval); - break; case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: rc = fg_get_time_to_empty(fg, &pval->intval); break; @@ -4184,7 +4181,6 @@ static enum power_supply_property fg_psy_props[] = { POWER_SUPPLY_PROP_CHARGE_COUNTER_SHADOW, POWER_SUPPLY_PROP_TIME_TO_FULL_AVG, POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, - POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, POWER_SUPPLY_PROP_SOC_REPORTING_READY, POWER_SUPPLY_PROP_DEBUG_BATTERY, POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, From dd34ca474e7f56c220f3a42ea220f559cac40dd7 Mon Sep 17 00:00:00 2001 From: LuK1337 Date: Sat, 4 Sep 2021 10:48:45 +0200 Subject: [PATCH 274/356] oneplus: Sync with oneplus/SDM845_R_11.0 Change-Id: I9974f09b2cfe5ff8ca2d537c00a9cb31ee32cf05 --- drivers/oneplus/Kconfig | 1 + drivers/oneplus/Makefile | 1 + drivers/oneplus/coretech/Kconfig | 11 + drivers/oneplus/coretech/Makefile | 2 + .../coretech/cpufreq_bouncing/Makefile | 1 + .../cpufreq_bouncing/cpufreq_bouncing.c | 485 ++++++++++ drivers/oneplus/coretech/houston/houston.c | 194 +++- drivers/oneplus/coretech/houston/houston.h | 17 + drivers/oneplus/coretech/tpd/Makefile | 1 + drivers/oneplus/coretech/tpd/tpd.c | 882 ++++++++++++++++++ .../coretech/uxcore/core/opchain_core.c | 4 +- .../coretech/uxcore/core/opchain_proxy.c | 2 +- drivers/oneplus/drivers/Kconfig | 6 + .../input/fingerprint/fpc/fpc1020_tee.c | 14 - .../drivers/oem_debug/oem_force_dump.c | 5 +- drivers/oneplus/drivers/oem_trace/oem_trace.c | 14 +- .../param_read_write/param_read_write.c | 4 +- .../include/linux/oem/cpufreq_bouncing.h | 19 + drivers/oneplus/include/linux/oem/tpd.h | 74 ++ drivers/oneplus/op_freezer/Kconfig | 5 + drivers/oneplus/op_freezer/Makefile | 2 + drivers/oneplus/op_freezer/op_freezer.c | 187 ++++ .../oneplus/op_freezer/op_freezer_netfilter.c | 232 +++++ 23 files changed, 2133 insertions(+), 30 deletions(-) create mode 100644 drivers/oneplus/coretech/cpufreq_bouncing/Makefile create mode 100644 drivers/oneplus/coretech/cpufreq_bouncing/cpufreq_bouncing.c create mode 100644 drivers/oneplus/coretech/houston/houston.h create mode 100644 drivers/oneplus/coretech/tpd/Makefile create mode 100755 drivers/oneplus/coretech/tpd/tpd.c create mode 100644 drivers/oneplus/include/linux/oem/cpufreq_bouncing.h create mode 100755 drivers/oneplus/include/linux/oem/tpd.h create mode 100755 drivers/oneplus/op_freezer/Kconfig create mode 100755 drivers/oneplus/op_freezer/Makefile create mode 100755 drivers/oneplus/op_freezer/op_freezer.c create mode 100755 drivers/oneplus/op_freezer/op_freezer_netfilter.c diff --git a/drivers/oneplus/Kconfig b/drivers/oneplus/Kconfig index 6063218df409..07d7c0370e85 100755 --- a/drivers/oneplus/Kconfig +++ b/drivers/oneplus/Kconfig @@ -1,3 +1,4 @@ source "drivers/oneplus/coretech/Kconfig" source "drivers/oneplus/drivers/Kconfig" source "drivers/oneplus/fs/Kconfig" +source "drivers/oneplus/op_freezer/Kconfig" diff --git a/drivers/oneplus/Makefile b/drivers/oneplus/Makefile index 1b9a785237be..7a4e000d8f6f 100755 --- a/drivers/oneplus/Makefile +++ b/drivers/oneplus/Makefile @@ -1,3 +1,4 @@ obj-y += coretech/ obj-y += drivers/ obj-y += fs/ +obj-$(CONFIG_OP_FREEZER) += op_freezer/ diff --git a/drivers/oneplus/coretech/Kconfig b/drivers/oneplus/coretech/Kconfig index 1f61087e021d..02b9660d85f1 100644 --- a/drivers/oneplus/coretech/Kconfig +++ b/drivers/oneplus/coretech/Kconfig @@ -33,3 +33,14 @@ config SMART_BOOST default n help Smart Boost feature +config TPD + default n + bool "a task placement decision for cpu limitation" + help + Task affinity by decison +config CPUFREQ_BOUNCING + default n + bool "A power optimization feature to control excessive heating of devices" +config OPLUS_FEATURE_SUGOV_TL + default n + bool "A power optimization feature target loads" diff --git a/drivers/oneplus/coretech/Makefile b/drivers/oneplus/coretech/Makefile index d1c172f25c8f..558662334db5 100755 --- a/drivers/oneplus/coretech/Makefile +++ b/drivers/oneplus/coretech/Makefile @@ -6,3 +6,5 @@ obj-$(CONFIG_HOUSTON) += houston/ obj-$(CONFIG_MEMPLUS) += memplus/ obj-$(CONFIG_OPCHAIN) += uxcore/ uxcore/core/ obj-$(CONFIG_SMART_BOOST) += smartboost/ smartboost/core/ +obj-$(CONFIG_TPD) += tpd/ +obj-$(CONFIG_CPUFREQ_BOUNCING) += cpufreq_bouncing/ diff --git a/drivers/oneplus/coretech/cpufreq_bouncing/Makefile b/drivers/oneplus/coretech/cpufreq_bouncing/Makefile new file mode 100644 index 000000000000..88aeadb4728b --- /dev/null +++ b/drivers/oneplus/coretech/cpufreq_bouncing/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_CPUFREQ_BOUNCING) += cpufreq_bouncing.o diff --git a/drivers/oneplus/coretech/cpufreq_bouncing/cpufreq_bouncing.c b/drivers/oneplus/coretech/cpufreq_bouncing/cpufreq_bouncing.c new file mode 100644 index 000000000000..848184810906 --- /dev/null +++ b/drivers/oneplus/coretech/cpufreq_bouncing/cpufreq_bouncing.c @@ -0,0 +1,485 @@ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include + +#define NSEC_TO_MSEC(val) (val / NSEC_PER_MSEC) +#define MSEC_TO_NSEC(val) (val * NSEC_PER_MSEC) +#define CLUS_MAX 2 + +struct cpufreq_bouncing { + /* statistics */ + u64 last_ts; + u64 last_freq_update_ts; + u64 acc; + + /* restriction */ + int limit_freq; + int limit_level; + u64 limit_thres; + + /* freqs */ + int freq_sorting; + int freq_levels; + unsigned int *freqs; // quick mapping + + /* config */ + bool enable; + int cur_level; + + /* config: ceil */ + int max_level; + int down_speed; + s64 down_limit_ns; + unsigned int max_freq; + + /* config: floor */ + int min_level; + int up_speed; + s64 up_limit_ns; + unsigned int min_freq; +} cb_stuff[CLUS_MAX] = { + /* silver */ + { + }, + /* gold */ + { + .enable = true, + .down_limit_ns = 50 * NSEC_PER_MSEC, + .up_limit_ns = 50 * NSEC_PER_MSEC, + .limit_thres = 30 * NSEC_PER_MSEC, + .limit_freq = 2169600, + .limit_level = 16, + .down_speed = 2, + .up_speed = 1, + } +}; + +/* init config */ +static bool enable = false; +module_param_named(enable, enable, bool, 0644); + +static bool debug = false; +module_param_named(debug, debug, bool, 0644); + +static unsigned int decay = 80; +module_param_named(decay, decay, uint, 0644); + +static DEFINE_PER_CPU(struct cpufreq_bouncing*, cbs); + +static int cb_pol_idx = 0; + +static bool cb_switch = false; + +static inline struct cpufreq_bouncing* cb_get(int cpu) +{ + if (likely(cb_switch)) + return per_cpu(cbs, cpu); + + return NULL; +} + +/* module parameters */ +static int cb_config_store(const char *buf, const struct kernel_param *kp) +{ + /* + for limit_thres, down/up limit will use ms as unit + format: + echo "2,0,5,3000,3,2000,3,2000" > config + */ + struct pack { + int clus; + bool enable; + + int limit_level; + u64 limit_thres_ms; + + int down_speed; + s64 down_limit_ms; + + int up_speed; + s64 up_limit_ms; + } v; + struct cpufreq_bouncing *cb; + + if (debug) + pr_info("%s\n", buf); + + if (sscanf(buf, "%d,%d,%d,%llu,%d,%lld,%d,%lld\n", + &v.clus, + &v.enable, + &v.limit_level, + &v.limit_thres_ms, + &v.down_speed, + &v.down_limit_ms, + &v.up_speed, + &v.up_limit_ms) != 8) + goto out; + + if (v.clus < 0 || v.clus >= cb_pol_idx) + goto out; + + cb = &cb_stuff[v.clus]; + + if (v.limit_level < 0 || v.limit_level > cb->max_level) + goto out; + + if (v.down_speed < 0 || v.down_speed > cb->freq_levels) + goto out; + + if (v.up_speed < 0 || v.up_speed > cb->freq_levels) + goto out; + + if (v.down_limit_ms < 0 || v.up_limit_ms < 0 || + v.limit_thres_ms < 0) + goto out; + + /* begin update config */ + cb->enable = false; + cb->last_ts = 0; + cb->last_freq_update_ts = 0; + cb->acc = 0; + cb->limit_level = v.limit_level; + if (cb->freqs) + cb->limit_freq = cb->freqs[cb->limit_level]; + cb->limit_thres = MSEC_TO_NSEC(v.limit_thres_ms); + cb->down_speed = v.down_speed; + cb->down_limit_ns = MSEC_TO_NSEC(v.down_limit_ms); + cb->up_speed = v.up_speed; + cb->up_limit_ns = MSEC_TO_NSEC(v.up_limit_ms); + cb->enable = v.enable; + + return 0; +out: + pr_warn("config: invalid:%s\n", buf); + return 0; +} + +static struct kernel_param_ops cb_config_ops = { + .set = cb_config_store, +}; +module_param_cb(config, &cb_config_ops, NULL, 0220); + +static int cb_dump_show(char *buf, const struct kernel_param *kp) +{ + struct cpufreq_bouncing *cb; + int i, j, cnt = 0; + + for (i = 0; i < min(CLUS_MAX, cb_pol_idx); ++i) { + cb = &cb_stuff[i]; + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "=====\n"); + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "clus %d (switch %d)\n", i, cb_switch); + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "last_ts: %llu\n", cb->last_ts); + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "last_freq_update_ts: %llu\n", cb->last_freq_update_ts); + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "acc: %llu\n", cb->acc); + + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "limit_freq: %d\n", cb->limit_freq); + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "limit_level: %d\n", cb->limit_level); + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "limit_thres: %llu\n", cb->limit_thres); + + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "enable: %d\n", cb->enable); + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "cur_level: %d\n", cb->cur_level); + + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "max_freq: %u %d\n", cb->max_freq, cb->max_level); + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "down_speed: %d\n", cb->down_speed); + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "down_limit_ns: %lld\n", cb->down_limit_ns); + + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "min_freq: %u %d\n", cb->min_freq, cb->min_level); + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "up_speed: %d\n", cb->up_speed); + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "up_limit_ns: %lld\n", cb->up_limit_ns); + + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "freq_sorting: %d\n", cb->freq_sorting); + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "freq_levels: %d\n", cb->freq_levels); + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "freq idx:"); + for (j = 0; j < cb->freq_levels; ++j) + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "\t%u", j); + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "\n"); + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "freq clk:"); + for (j = 0; j < cb->freq_levels; ++j) + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "\t%u", cb->freqs[j]); + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "\n"); + } + + return cnt; +} + +static struct kernel_param_ops cb_dump_ops = { + .get = cb_dump_show, +}; +module_param_cb(dump, &cb_dump_ops, NULL, 0444); + + +unsigned int cb_get_cap(int cpu) +{ + struct cpufreq_bouncing *cb = cb_get(cpu); + + /* return UINT_MAX as no limited */ + if (unlikely(!cb)) + return UINT_MAX; + + if (unlikely(cb->freqs)) + return UINT_MAX; + + return cb->freqs[cb->cur_level]; +} + +unsigned int cb_cap(struct cpufreq_policy *pol, unsigned int freq) +{ + struct cpufreq_bouncing *cb; + unsigned int capped = freq; + int cpu; + + if (!enable) + return freq; + + /* can remove since we're calling from sugov_fast_switch path */ +// if (!pol->fast_switch_enabled) +// return freq; + + cpu = cpumask_first(pol->related_cpus); + cb = cb_get(cpu); + + if (unlikely(!cb)) + return freq; + + if (!cb->enable) + return freq; + + /* don't have quick mapping */ + if (unlikely(!cb->freqs)) + return freq; + + capped = min(freq, cb->freqs[cb->cur_level]); + + if (debug) + pr_info("cpu %d, orig %u, capped %d\n", cpu, freq, capped); + + return capped; +} + +static inline bool clus_isolated(int cpu) +{ + struct cpufreq_policy *pol = cpufreq_cpu_get_raw(cpu); + int i; + + if (unlikely(!pol)) + return true; + + for_each_cpu(i, pol->related_cpus) + if (!cpu_isolated(i)) + return false; + + return true; +} + +void cb_reset(int cpu, u64 time) +{ + struct cpufreq_bouncing *cb; + + if (!enable) + return; + + cb = cb_get(cpu); + if (!cb) + return; + + /* reset only when cluster has no active cpu */ + if (!clus_isolated(cpu)) + return; + + cb->last_ts = time; + cb->last_freq_update_ts = time; + cb->acc = 0; + cb->cur_level = cb->max_level; +} + +void cb_update(struct cpufreq_policy *pol, u64 time) +{ + // TODO can skip a bit? + struct cpufreq_bouncing *cb; + u64 delta, update_delta; + int cpu; + + if (!enable) + return; + + cpu = cpumask_first(pol->related_cpus); + cb = cb_get(cpu); + + if (unlikely(!cb)) + return; + + if (!cb->enable) + return; + +// if (unlikely(!pol->fast_switch_enabled)) +// return; + + /* for first update */ + if (unlikely(!cb->last_ts)) + cb->last_ts = cb->last_freq_update_ts = time; + + // FIXME check overflow + // NOTE pol->cur should always updated + delta = time - cb->last_ts; + update_delta = time - cb->last_freq_update_ts; + + /* check cpufreq */ + if (pol->cur >= cb->limit_freq) { + /* accumulate delta time */ + cb->acc += delta; + } else { + /* decay accumulate time */ + cb->acc = cb->acc * decay / 100;; + } + + /* check if need to update limitation */ + if (cb->acc >= cb->limit_thres) { + /* check last update */ + if (update_delta >= cb->down_limit_ns) { + cb->cur_level -= cb->down_speed; + cb->last_freq_update_ts = time; + } + } else { + /* check last update */ + if (update_delta >= cb->up_limit_ns) { + cb->cur_level += cb->up_speed; + cb->last_freq_update_ts = time; + } + } + + /* cap level */ + cb->cur_level = max(cb->limit_level, min(cb->cur_level, cb->max_level)); + + if (debug) + pr_info("cpu %d update: ts now %llu last %llu last_update %llu delta %llu update_d %llu cur %u acc %llu, cur_level %d\n", + cpu, + NSEC_TO_MSEC(time), + NSEC_TO_MSEC(cb->last_ts), + NSEC_TO_MSEC(cb->last_freq_update_ts), + NSEC_TO_MSEC(delta), + NSEC_TO_MSEC(update_delta), + pol->cur, + NSEC_TO_MSEC(cb->acc), + cb->cur_level); + + cb->last_ts = time; +} + +static int __cpufreq_policy_parser(int cpu, int cb_idx) +{ + struct cpufreq_policy *pol = cpufreq_cpu_get_raw(cpu); + struct cpufreq_frequency_table *table, *pos; + struct cpufreq_bouncing* cb; + + unsigned int freq = 0, max_freq = 0, min_freq = UINT_MAX; + int idx, freq_levels = 0; + + if (unlikely(!pol)) { + pr_err("cpu %d can't find realted cpufreq policy\n", cpu); + return -1; + } + + if (cb_idx >= CLUS_MAX) { + pr_err("clus %d out of limit\n", cb_idx); + return -1; + } + + cb = &cb_stuff[cb_idx]; + table = pol->freq_table; + cb->freq_sorting = pol->freq_table_sorted; + /* get freq_levels */ + cpufreq_for_each_valid_entry(pos, table) { + ++freq_levels; + freq = pos->frequency; + if (freq > max_freq) { + max_freq = freq; + cb->max_level = freq_levels; + cb->cur_level = freq_levels; + cb->max_freq = max_freq; + } + if (freq < min_freq) { + min_freq = freq; + cb->min_level = freq_levels; + cb->min_freq = min_freq; + } + } + + cb->freq_levels = freq_levels; + cb->freqs = (unsigned int *) kmalloc(sizeof(unsigned int) * freq_levels, GFP_KERNEL); + if (cb->freqs) { + /* setup freqs */ + idx = 0; + table = pol->freq_table; + cpufreq_for_each_valid_entry(pos, table) { + freq = pos->frequency; + cb->freqs[idx] = freq; + ++idx; + } + } else { + pr_err("can't alloc memory for freqs\n"); + cb->enable = false; + } + return cpu + cpumask_weight(pol->related_cpus); +} + +static void cb_parse_cpufreq(void) +{ + int i = 0, j, prev = 0; + bool valid = true; + + while (i != nr_cpu_ids && cb_pol_idx != CLUS_MAX) { + i = __cpufreq_policy_parser(i, cb_pol_idx); + if (i < 0) + break; + for (j = prev; j < i; ++j) + per_cpu(cbs, j) = &cb_stuff[cb_pol_idx]; + prev = i; + ++cb_pol_idx; + } + + for (i = 0; i < nr_cpu_ids && valid; ++i) { + if (!per_cpu(cbs, i)) { + pr_warn("break on cpu%d\n", i); + valid = false; + } + } + + cb_switch = valid; + smp_wmb(); +} + +static void cb_clean_up(void) +{ + struct cpufreq_bouncing *cb; + int i; + enable = false; + smp_wmb(); + + for (i = 0; i < CLUS_MAX; ++i) { + cb = &cb_stuff[i]; + if (cb->freqs) { + kfree(cb->freqs); + cb->freqs = NULL; + } + } +} + +static int __init cb_init(void) +{ + pr_info("cpufreq bouncing init\n"); + cb_parse_cpufreq(); + return 0; +} + +static void __exit cb_exit(void) +{ + cb_clean_up(); + pr_info("cpufreq bouncing exit\n"); +} +device_initcall(cb_init); + diff --git a/drivers/oneplus/coretech/houston/houston.c b/drivers/oneplus/coretech/houston/houston.c index f3f5cfe35bb2..4ec7e0b6e6d0 100644 --- a/drivers/oneplus/coretech/houston/houston.c +++ b/drivers/oneplus/coretech/houston/houston.c @@ -14,6 +14,10 @@ #include #include #include +#include "houston.h" +#include "../drivers/gpu/msm/kgsl.h" +#include "../drivers/gpu/msm/kgsl_pwrctrl.h" +#include #define HT_POLLING_MIN_INTERVAL (100) #define HT_REPORT_PERIOD_MAX (18000) @@ -39,6 +43,19 @@ enum { HT_SEN_0, HT_SEN_1, HT_SEN_2, + 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_MONITOR_SIZE }; @@ -61,9 +78,57 @@ const char *ht_monitor_case[HT_MONITOR_SIZE] = { "cpu3-gold-usr", "xo-therm-adc", "msm-therm-adc", - "quiet-therm-adc" + "quiet-therm-adc", + "process name", + "layer name", + "pid", + "fps_align", + "actualFps", + "predictFps", + "Vsync", + "gameFps", + "NULL", + "NULL", + "NULL", + "NULL", + "missedLayer" }; +/* + * 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, +}; + +static struct game_fps_data_struct +{ + u64 fps; + u64 enqueue_time; +} game_fps_data; + +static atomic_t cached_fps[2]; + +static atomic64_t fps_align_ns; + +static struct kgsl_pwrctrl *gpwr; + static unsigned int ht_all_mask; static unsigned int report_period = 600; @@ -109,6 +174,10 @@ static struct kernel_param_ops ht_sample_period_ops = { }; module_param_cb(sample_period, &ht_sample_period_ops, NULL, 0644); +/* fps */ +static int game_fps_pid = -1; +module_param_named(game_fps_pid, game_fps_pid, int, 0664); + /* NOTE better not use this directly */ int sidx; int smps[HT_REPORT_PERIOD_MAX][HT_MONITOR_SIZE]; // samples @@ -174,9 +243,6 @@ void ht_register_thermal_zone_device(struct thermal_zone_device *tzd) /* tzd is guaranteed has value */ pr_info("tzd: %s id: %d\n", tzd->type, tzd->id); - if (!tzd->type) - return; - idx = ht_mapping_tags(tzd->type); if (idx == HT_MONITOR_SIZE) @@ -200,6 +266,121 @@ void ht_register_power_supply(struct power_supply *psy) } } +void ht_register_kgsl_pwrctrl(void *pwr) +{ + gpwr = (struct kgsl_pwrctrl *) pwr; + pr_info("Registered lgsl pwrctrl\n"); +} + +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; + static int cur_idx; + int ret; + + if (strlen(buf) >= FPS_DATA_BUF_SIZE) + return 0; + + ret = sscanf(buf, "%llu,%llu,%llu,%llu,%llu,%lld\n", + &fps_data[0], &fps_data[1], &fps_data[2], &fps_data[3], + &fps_data[4], &fps_align); + if (ret != 6) { + pr_err("fps data params invalid. got %d inputs instead of %d,%s has been ignored\n", + (FPS_COLS+1), ret, buf); + return 0; + } + + game_fps_data.enqueue_time = fps_align; + game_fps_data.fps = fps_data[3]; + + pr_info("fps data params: %llu %llu %llu %llu %llu %lld\n", + fps_data[0], fps_data[1], fps_data[2], + fps_data[3], fps_data[4], fps_align); + + atomic_set(&cached_fps[0], (fps_data[7])); + atomic_set(&cached_fps[1], ((fps_data[1] + 5)/10)); + atomic64_set(&fps_align_ns, fps_align); + + if (!monitor.buf) + return 0; + + if (cur_idx != sidx) { + 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]; + monitor.buf->data[cur_idx][HT_FPS_2] = fps_data[1]; + monitor.buf->data[cur_idx][HT_FPS_3] = fps_data[2]; + monitor.buf->data[cur_idx][HT_FPS_4] = fps_data[3]; + monitor.buf->data[cur_idx][HT_FPS_PID] = fps_data[4]; + monitor.buf->data[cur_idx][HT_FPS_ALIGN] = fps_align; + + 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); + +static int get_gpu_percentage(void) +{ + struct kgsl_clk_stats *stats = NULL; + + if (gpwr) { + stats = &gpwr->clk_stats; + return stats->total_old != 0 ? (stats->busy_old * 100 / stats->total_old) : 0; + } + return 0; +} + +static int game_info_show(char *buf, const struct kernel_param *kp) +{ + int gpu, cpu, fps; + static u64 last_enqueue_time; + + if (game_fps_pid == -1) { + gpu = -1; + cpu = -1; + fps = -1; + } else { + cpu = ohm_get_cur_cpuload(true); + gpu = get_gpu_percentage(); + fps = game_fps_data.fps / 10; + + if (fps < 0 || fps > 150) { + pr_err("fps: %d is out of range", fps); + fps = 0; + } + if (game_fps_data.enqueue_time == last_enqueue_time) { + pr_err("Did not update the fps data"); + fps = 0; + } + last_enqueue_time = game_fps_data.enqueue_time; + } + return snprintf(buf, PAGE_SIZE, "%d %d %d\n", gpu, cpu, fps); +} + +static struct kernel_param_ops game_info_ops = { + .get = game_info_show, +}; +module_param_cb(game_info, &game_info_ops, NULL, 0664); + #define SILVER_CLUS_IDX 0 #define GOLDEN_CLUS_IDX 4 static void ht_collect_resources(void) @@ -430,6 +611,11 @@ 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)? 100: 1; diff --git a/drivers/oneplus/coretech/houston/houston.h b/drivers/oneplus/coretech/houston/houston.h new file mode 100644 index 000000000000..5ec8d6925daa --- /dev/null +++ b/drivers/oneplus/coretech/houston/houston.h @@ -0,0 +1,17 @@ +#ifndef __INCLUDE_HOUSTON__ +#define __INCLUDE_HOUSTON__ + +#ifndef pr_fmt +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#endif + +#define MAX_REPORT_PERIOD 18000 + +#define FPS_COLS 5 +#define FPS_LAYER_LEN 128 +#define FPS_PROCESS_NAME_LEN 64 +#define FPS_DATA_BUF_SIZE 256 + +extern int ohm_get_cur_cpuload(bool ctrl); + +#endif diff --git a/drivers/oneplus/coretech/tpd/Makefile b/drivers/oneplus/coretech/tpd/Makefile new file mode 100644 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..a9c51750f851 --- /dev/null +++ b/drivers/oneplus/coretech/tpd/tpd.c @@ -0,0 +1,882 @@ +#include +#include +#include +#include +#include +#include + +/* + * Task Placement Decision + * + * two main rules as below: + * 1. trigger tpd with tgid and thread's name which will be limited + * through online config, framework can tag threads and limit cpu placement + * of tagged threads that are also foreground task. + * tpd_cmds + * 2. trigger tpd with tgid and thread_id + * control the placement limitation by itself, set tpd_ctl = 1 will limit + * cpu placement of tagged threads, but need release by itself to set tpd_enable = 0, + * tpd_ctl = 0 and task->tpd = 0 + * tpd_id + * 3. control the placement limitation by itself, set tpd_ctl = 1 will limit + * cpu placement of tagged threads, but need release by itself to set tpd_enable = 0, + * tpd_ctl = 0 and task->tpd = 0 + * tpd_dynamic + */ +extern bool is_fg(int uid); + +struct tgid_list_entry { + int pid; + struct list_head node; +}; + +struct monitor_gp { + int decision; /* cpu affinity */ + spinlock_t tgid_list_lock; /* used to check dynamic tpd task */ + struct list_head tgid_head;/* used to check dynamic tpd task */ + spinlock_t miss_list_lock; /* used to check if need re-tag or not */ + unsigned int miss_list_tgid[MAX_MISS_LIST];/* used to check if need re-tag or not */ + char miss_list[MAX_MISS_LIST][TASK_COMM_LEN];/* used to check if need re-tag or not */ + int not_yet; + int cur_idx; +}; + +/* monitor group for dynamic tpd threads */ +static struct monitor_gp mgp[TPD_GROUP_MAX]; + +#define MAX_CLUSTERS 3 +static int cluster_total; +struct tpd_cpuinfo { + int first_cpu; + cpumask_t related_cpus; +}; +static struct tpd_cpuinfo clusters[MAX_CLUSTERS]; + +static atomic_t tpd_enable_rc = ATOMIC_INIT(0); +static int tpd_enable_rc_show(char *buf, const struct kernel_param *kp) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&tpd_enable_rc)); +} + +static struct kernel_param_ops tpd_enable_rc_ops = { + .get = tpd_enable_rc_show, +}; + +module_param_cb(tpd_en_rc, &tpd_enable_rc_ops, NULL, 0664); + +static int tpd_log_lv = 2; +module_param_named(log_lv, tpd_log_lv, int, 0664); + +static atomic_t tpd_ctl = ATOMIC_INIT(0); /* used to ignore fg task checking */ + +static bool should_update_tpd_enable(int enable) { + + bool ret = true; + int refcnt = 0; + + if (enable) { + if (atomic_inc_return(&tpd_enable_rc) > 1) + ret = false; + } else { + refcnt = atomic_read(&tpd_enable_rc); + if (refcnt < 1) { + ret = false; + goto out; + } + + /* tpd_enable ref count must greater or equal tpd_ctl */ + if (refcnt - 1 < atomic_read(&tpd_ctl)) { + ret = false; + goto out; + } + + if (atomic_dec_return(&tpd_enable_rc) > 0) { + tpd_loge("tpd cannot disable"); + ret = false; + } + } + +out: + tpd_logv("should_update_tpd_enable? %d", ret); + + return ret; +} + +static int tpd_enable = 0; +static int tpd_enable_store(const char *buf, const struct kernel_param *kp) +{ + int val; + + if (sscanf(buf, "%d\n", &val) <= 0) + return 0; + + if (should_update_tpd_enable(val)) + tpd_enable = val; + + return 0; +} + +static int tpd_enable_show(char *buf, const struct kernel_param *kp) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", tpd_enable); +} + +static struct kernel_param_ops tpd_enable_ops = { + .set = tpd_enable_store, + .get = tpd_enable_show, +}; + +module_param_cb(tpd_enable, &tpd_enable_ops, NULL, 0664); + +bool is_tpd_enable(void) +{ + return tpd_enable; +} + +static int miss_list_show(char *buf, const struct kernel_param *kp) +{ + int i, j; + int cnt = 0; + + for (j = TPD_GROUP_MEDIAPROVIDER; j < TPD_GROUP_MAX; ++j) { + spin_lock(&mgp[j].miss_list_lock); + if (mgp[j].not_yet > 0) { + for (i = 0; i < MAX_MISS_LIST; ++i) { + if(strlen(mgp[j].miss_list[i]) > 0) { + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "%s %d\n", mgp[j].miss_list[i], mgp[j].miss_list_tgid[i]); + } + } + } + spin_unlock(&mgp[j].miss_list_lock); + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "\n"); + } + return cnt; +} + +static struct kernel_param_ops miss_list_ops = { + .get = miss_list_show, +}; + +module_param_cb(miss_list, &miss_list_ops, NULL, 0664); + +bool is_dynamic_tpd_task(struct task_struct *tsk) +{ + int gid, len = 0, i; + bool ret = false; + struct monitor_gp *group; + struct tgid_list_entry *p; + struct task_struct *leader; + + /* this is for all tpd tasks reset(dynamic/not dynamic tpd tasks) */ + if (!tpd_enable) { + tsk->tpd = 0; + tsk->dtpdg = -1; + tsk->dtpd = 0; + return ret; + } + + /* return if current has dead */ + if (current->exit_state) + return ret; + + rcu_read_lock(); + leader = find_task_by_vpid(tsk->tgid); + rcu_read_unlock(); + + if (leader == NULL) + return ret; + + gid = leader->dtpdg; + /* not dynamic tpd task will return */ + if (gid < TPD_GROUP_MEDIAPROVIDER || gid >= TPD_GROUP_MAX) + return ret; + + group = &mgp[gid]; + + switch (gid) { + case TPD_GROUP_MEDIAPROVIDER: + + spin_lock(&group->tgid_list_lock); + + /* no dynamic tpd task enable of this dynamic tpd group id */ + if (list_empty(&group->tgid_head)) { + if (tsk->dtpd) { + tsk->dtpd = 0; + tsk->tpd = 0; + } + spin_unlock(&group->tgid_list_lock); + return ret; + } + + list_for_each_entry(p, &group->tgid_head, node) { + if (leader->pid != p->pid) + continue; + + /* parent of thread was dynamic tpd task */ + /* dynamic tpd task has already tagged */ + if (tsk->dtpd && tsk->tpd) { + ret = true; + break; + } + + /* start tagging process */ +#ifdef CONFIG_IM + /*binder thread of media provider */ + if (im_binder(tsk)) { + tsk->dtpd = 1; /* dynamic tpd */ + tsk->tpd = group->decision; + ret = true; + break; + } +#endif + +#ifdef CONFIG_ONEPLUS_FG_OPT + #if 0 + /* fuse related thread of media provider */ + if (tsk->fuse_boost) { + tsk->dtpd = 1; /* dynamic tpd */ + tsk->tpd = group->decision; + ret = true; + break; + } + #endif +#endif + /* re-tag missed thread, only one name with one thread */ + spin_lock(&group->miss_list_lock); + if (group->not_yet > 0) { + for (i = 0; i < MAX_MISS_LIST; ++i) { + len = strlen(group->miss_list[i]); + if (len == 0) + continue; + if (group->miss_list_tgid[i] != p->pid) + continue; + if (!strncmp(tsk->comm, group->miss_list[i], len)) { + strcpy(group->miss_list[i], ""); + group->miss_list_tgid[i] = 0; + tsk->dtpd = 1; + tsk->tpd = group->decision; + group->not_yet--; + ret = true; + break; + } + } + + if (ret) { + spin_unlock(&group->miss_list_lock); + break; + } + } + spin_unlock(&group->miss_list_lock); + /* end tagging process */ + } + spin_unlock(&group->tgid_list_lock); + + /* reset flag if dynamic tpd task removed (tgid was removed) */ + if (!ret) { + if (tsk->dtpd) { + tsk->dtpd = 0; + tsk->tpd = 0; + } + } + break; + default: + break; + } + + return ret; +} + +static void set_tpd_ctl(int force) +{ + if (force) + atomic_inc(&tpd_ctl); + else { + if (atomic_read(&tpd_ctl) > 0) + atomic_dec(&tpd_ctl); + } +} + +static int tpd_ctl_store(const char *buf, const struct kernel_param *kp) +{ + int val; + + if (sscanf(buf, "%d\n", &val) <= 0) + return 0; + + set_tpd_ctl(val); + + return 0; +} + +static int tpd_ctl_show(char *buf, const struct kernel_param *kp) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&tpd_ctl)); +} + +static struct kernel_param_ops tpd_ctl_ops = { + .set = tpd_ctl_store, + .get = tpd_ctl_show, +}; + +module_param_cb(tpd_ctl, &tpd_ctl_ops, NULL, 0664); + +static inline void tagging(struct task_struct *tsk, int decision) +{ + if (tsk == NULL) { + tpd_loge("task cannot set"); + return; + } + + tpd_logv("%s task: %s pid:%d decision:%d\n", __func__, tsk->comm, tsk->pid, decision); + + tsk->tpd = decision; +} + +static inline void tagging_by_name(struct task_struct *tsk, char* name, int decision, int *cnt) +{ + size_t tlen = 0, len = 0; + + tlen = strlen(name); + if (tlen == 0) + return; + + len = strlen(tsk->comm); + + if (len != tlen) + return; + + if (!strncmp(tsk->comm, name, tlen)) { + tpd_logv("%s task: %s pid:%d decision:%d name=%s\n", __func__, tsk->comm, tsk->pid, decision, name); + tsk->tpd = decision; + *cnt = *cnt + 1; + } +} + +static void tag_from_tgid(unsigned int tgid, int decision, char* thread_name, int *cnt) +{ + struct task_struct *p, *t; + + rcu_read_lock(); + p = find_task_by_vpid(tgid); + if (p) { + for_each_thread(p, t) + tagging_by_name(t, thread_name, decision, cnt); + } + rcu_read_unlock(); + +} + +static inline void dy_tagging_by_name(struct task_struct *tsk, const char* name, int decision, int dtpd, int *cnt) +{ + size_t tlen = 0, len = 0; + + tlen = strlen(name); + if (tlen == 0) + return; + + len = strlen(tsk->comm); + + if (len != tlen) + return; + + if (!strncmp(tsk->comm, name, tlen)) { + tpd_logv("%s task: %s pid:%d decision:%d name=%s, dtpd=%d\n", __func__, tsk->comm, tsk->pid, decision, name, dtpd); + tsk->tpd = decision; + tsk->dtpd = dtpd; + *cnt = *cnt + 1; + } +} + +static void dy_tag_from_tgid(unsigned int tgid, int decision, const char* thread_name, int dtpd, int *cnt) +{ + struct task_struct *p, *t; + + rcu_read_lock(); + p = find_task_by_vpid(tgid); + if (p) { + for_each_thread(p, t) + dy_tagging_by_name(t, thread_name, decision, dtpd, cnt); + } + rcu_read_unlock(); + +} + +/* set dtpd group id in the main thread */ +static void tag_dtpdg(unsigned int tgid, unsigned int dtpdg) +{ + struct task_struct *p; + + rcu_read_lock(); + p = find_task_by_vpid(tgid); + if (p) { + p->dtpdg = dtpdg; + } + rcu_read_unlock(); + +} + +static int tpd_cmd_store(const char *buf, const struct kernel_param *kp) +{ + unsigned int tgid = 0; + int tp_decision = -1; + char threads[MAX_THREAD_INPUT][TASK_COMM_LEN] = {{0}, {0}, {0}, {0}, {0}, {0}}; + int ret, i, cnt = 0; + + ret = sscanf(buf, "%u %d %s %s %s %s %s %s\n", + &tgid, &tp_decision, + threads[0], threads[1], threads[2], threads[3], threads[4], threads[5]); + + tpd_logi("tpd params: %u %d %s %s %s %s %s %s, from %s %d, total=%d\n", + tgid, tp_decision, threads[0], threads[1], threads[2], threads[3], threads[4], threads[5], + current->comm, current->pid, ret); + + for (i = 0; i < MAX_THREAD_INPUT; i++) { + if (strlen(threads[i]) > 0) + tag_from_tgid(tgid, tp_decision, threads[i], &cnt); + } + + tpd_logv("tpd tagging count = %d\n", cnt); + + return 0; +} + +static struct kernel_param_ops tpd_cmd_ops = { + .set = tpd_cmd_store, +}; +module_param_cb(tpd_cmds, &tpd_cmd_ops, NULL, 0664); + +static void tag_from_tid(unsigned int pid, unsigned int tid, int decision) +{ + struct task_struct *p; + + rcu_read_lock(); + p = find_task_by_vpid(tid); + if (p) { + if (p->group_leader && (p->group_leader->pid == pid)) { + tpd_logv("tpd tagging task pid= %d\n", pid); + tagging(p, decision); + } + } else { + tpd_loge("cannot find task!!! pid = %d", tid); + } + rcu_read_unlock(); +} + +static int tpd_store(const char *buf, const struct kernel_param *kp) +{ + unsigned int pid = 0; + unsigned int tid = 0; + int tpdenable = 0; + int tp_decision = -1; + int ret; + + ret = sscanf(buf, "%u,%u,%d,%d\n", + &pid, &tid, &tpdenable, &tp_decision); + + tpd_logi("tpd param pid:%u tid:%u, tpd_enable:%d decision:%d from %s %d\n", + pid, tid, tpdenable, tp_decision, current->comm, current->pid); + + if (ret != 4) { + tpd_loge("Invalid params!!!!!!"); + return 0; + } + + tag_from_tid(pid, tid, tpdenable ? tp_decision : 0); + + set_tpd_ctl(tpdenable); + + /* update tpd_enable ref cnt*/ + if (should_update_tpd_enable(tpdenable)) + tpd_enable = tpdenable; + + return 0; +} + +static struct kernel_param_ops tpd_ops = { + .set = tpd_store, +}; +module_param_cb(tpd_id, &tpd_ops, NULL, 0664); + +static void tgid_list_add(struct monitor_gp *_mgp, int pid) +{ + struct tgid_list_entry *p; + + p = kmalloc(sizeof(struct tgid_list_entry), GFP_KERNEL); + if (p == NULL) + return; + p->pid = pid; + INIT_LIST_HEAD(&p->node); + + spin_lock(&_mgp->tgid_list_lock); + list_add_tail(&p->node, &_mgp->tgid_head); + tpd_logv("add main thread: %d", pid); + spin_unlock(&_mgp->tgid_list_lock); +} + +void tpd_tglist_del(struct task_struct *tsk) +{ + struct tgid_list_entry *p, *next; + struct monitor_gp *group; + + if (!tsk->pid) + return; + + if (tsk->dtpdg < 0 || tsk->dtpdg >= TPD_GROUP_MAX) + return; + + group = &mgp[tsk->dtpdg]; + + spin_lock(&group->tgid_list_lock); + + if (list_empty(&group->tgid_head)) + goto unlock; + + list_for_each_entry_safe(p, next, &group->tgid_head, node) { + if (p != NULL && (p->pid == tsk->pid)) { + list_del_init(&p->node); + tpd_logv("remove task: %d", tsk->pid); + kfree(p); + break; + } + } + + /* if no tgid in list, disable tpd_ctl && try to disable tpd */ + if (list_empty(&group->tgid_head)) { + set_tpd_ctl(0); + if (should_update_tpd_enable(0)) + tpd_enable = 0; + } + +unlock: + spin_unlock(&group->tgid_list_lock); +} + +/* return true if list size is from one to empty */ +static bool tgid_list_del(struct monitor_gp *_mgp, int pid) +{ + struct tgid_list_entry *p, *next; + bool ret = false; + + spin_lock(&_mgp->tgid_list_lock); + /* do nothing if list empty */ + if (list_empty(&_mgp->tgid_head)) + goto unlock; + + list_for_each_entry_safe(p, next, &_mgp->tgid_head, node) { + if (p != NULL && (p->pid == pid)) { + list_del_init(&p->node); + tpd_logv("remove main thread: %d", pid); + kfree(p); + break; + } + } + /* re-check if list is empty after list deletion */ + if (list_empty(&_mgp->tgid_head)) + ret = true; + +unlock: + spin_unlock(&_mgp->tgid_list_lock); + return ret; +} + +static int list_show(char *buf, const struct kernel_param *kp) +{ + struct tgid_list_entry *p; + int cnt = 0; + int i; + + for (i = 0; i < TPD_GROUP_MAX; ++i) { + spin_lock(&mgp[i].tgid_list_lock); + + if (list_empty(&mgp[i].tgid_head)) + goto unlock; + + list_for_each_entry(p, &mgp[i].tgid_head, node) { + cnt += snprintf(buf + cnt, PAGE_SIZE - cnt, "%d %d\n", i, p->pid); + } +unlock: + spin_unlock(&mgp[i].tgid_list_lock); + } + + return cnt; +} + +static struct kernel_param_ops tgid_list_ops = { + .get = list_show, +}; + +module_param_cb(tgid_list, &tgid_list_ops, NULL, 0664); + +#define MONITOR_THREAD_NUM 1 +static int tpd_process_trigger_store(const char *buf, const struct kernel_param *kp) +{ + unsigned int tgid = 0; + int tpdenable = 0; + int tp_decision = -1; + int tpd_group = -1; + int ret, i, cnt = 0, j; + const char *threads[MONITOR_THREAD_NUM] = {"bg"}; + struct monitor_gp *group; + + ret = sscanf(buf, "%d,%u,%d,%d\n", + &tpd_group, &tgid, &tpdenable, &tp_decision); + + tpd_logi("tpd param group:%d pid:%u tpd_enable:%d decision:%d from %s %d\n", + tpd_group, tgid, tpdenable, tp_decision, current->comm, current->pid); + + if (ret != 4) { + tpd_loge("Invalid params!!!!!!"); + return 0; + } + + if (tpd_group >= TPD_GROUP_MAX || tpd_group < 0) { + tpd_loge("Invalid group!!!!!!"); + return 0; + } + + group = &mgp[tpd_group]; + + if (!tpdenable) { + if (tgid_list_del(group, tgid)) + group->decision = 0; + + tag_dtpdg(tgid, -1); + } else { + group->decision = tp_decision; + tgid_list_add(group, tgid); + tag_dtpdg(tgid, tpd_group); + } + + set_tpd_ctl(tpdenable); + + + /* tagged by name from group: media provider */ + if (tpd_group == TPD_GROUP_MEDIAPROVIDER) { + for(i = 0; i < MONITOR_THREAD_NUM; i++) { + cnt = 0; + dy_tag_from_tgid(tgid, tpdenable ? tp_decision : 0, threads[i], tpdenable, &cnt); + /* can't find thread to tag/un-tag */ + if (cnt == 0) { + spin_lock(&group->miss_list_lock); + if (tpdenable) { + /* need re-tag, add thread name into miss_list */ + strncpy(group->miss_list[group->cur_idx], threads[i], strlen(threads[i])); + group->miss_list_tgid[group->cur_idx] = tgid; + group->cur_idx = (group->cur_idx + 1) % MAX_MISS_LIST; + group->not_yet++; + } else { + /* dynmic tpd disabled when miss_list still have thread need to tag, we clear the miss list */ + for (j = 0; j < MAX_MISS_LIST; ++j) { + if (group->miss_list_tgid[j] == tgid) { + strcpy(group->miss_list[j], ""); + group->miss_list_tgid[j] = 0; + group->not_yet--; + } + } + } + spin_unlock(&group->miss_list_lock); + } + } + } + + tpd_logv("tagging count = %d, tpd enable set:%d", cnt, tpdenable); + + /* update tpd_enable by ref cnt */ + if (should_update_tpd_enable(tpdenable)) + tpd_enable = tpdenable; + + return 0; +} + +static struct kernel_param_ops tpd_pt_ops = { + .set = tpd_process_trigger_store, +}; +module_param_cb(tpd_dynamic, &tpd_pt_ops, NULL, 0664); + +int tpd_suggested_cpu(struct task_struct* tsk, int request_cpu) +{ + int suggest_cpu = request_cpu; + int uid = task_uid(tsk).val; + + if (!(is_fg(uid) || atomic_read(&tpd_ctl))) + goto out; + + switch (tsk->tpd) { + case TPD_TYPE_S: + case TPD_TYPE_GS: + case TPD_TYPE_PS: + case TPD_TYPE_PGS: + suggest_cpu = clusters[0].first_cpu;; + break; + case TPD_TYPE_G: + case TPD_TYPE_PG: + suggest_cpu = clusters[1].first_cpu;; + break; + case TPD_TYPE_P: + if (cluster_total == MAX_CLUSTERS) + suggest_cpu = clusters[2].first_cpu; + else + suggest_cpu = clusters[1].first_cpu; + break; + default: + tpd_loge("suggest cpu unexpected case: tpd = %d\n", tsk->tpd); + break; + } +out: + tpd_logi("pid = %d: comm = %s, tpd = %d, suggest_cpu = %d, task is fg? %d, tpd_ctl = %d\n", tsk->pid, tsk->comm, + tsk->tpd, suggest_cpu, is_fg(uid), atomic_read(&tpd_ctl)); + return suggest_cpu; +} + +int tpd_suggested(struct task_struct* tsk, int request_cluster) +{ + int suggest_cluster = request_cluster; + int uid = task_uid(tsk).val; + + if (!(is_fg(uid) || atomic_read(&tpd_ctl))) + goto out; + + switch (tsk->tpd) { + case TPD_TYPE_S: + case TPD_TYPE_GS: + case TPD_TYPE_PS: + case TPD_TYPE_PGS: + suggest_cluster = 0; + break; + case TPD_TYPE_G: + case TPD_TYPE_PG: + suggest_cluster = 1; + break; + case TPD_TYPE_P: + if (cluster_total == MAX_CLUSTERS) + suggest_cluster = 2; + else + suggest_cluster = 1; + break; + default: + break; + } +out: + tpd_logi("pid = %d: comm = %s, tpd = %d, suggest_cpu = %d, task is fg? %d, tpd_ctl = %d\n", tsk->pid, tsk->comm, + tsk->tpd, suggest_cluster, is_fg(uid), atomic_read(&tpd_ctl)); + return suggest_cluster; +} + +void tpd_mask(struct task_struct* tsk, cpumask_t *request) +{ + int i = 0, j, x; + int tmp_tpd; + int uid = task_uid(tsk).val; + + cpumask_t mask = CPU_MASK_NONE; + + if (!(is_fg(uid) || atomic_read(&tpd_ctl))) { + if (!is_fg(uid)) + tpd_logv("task is not fg!!!\n"); + return; + } + + tmp_tpd = tsk->tpd; + while (tmp_tpd > 0) { + if (tmp_tpd & 1) { + for_each_cpu(j, &clusters[i].related_cpus) + cpumask_set_cpu(j, &mask); + i++; + } + tmp_tpd = tmp_tpd >> 1; + } + + cpumask_copy(request, &mask); + tpd_logi("tpd_mask: related_cpus = "); + for_each_cpu(x, request) + tpd_logi("%d ", x); + + tpd_logi("pid = %d: comm = %s, tpd = %d, task is fg? %d, tpd_ctl = %d\n", tsk->pid, tsk->comm, + tsk->tpd, is_fg(uid), atomic_read(&tpd_ctl)); +} + +bool tpd_check(struct task_struct *tsk, int dest_cpu) +{ + bool mismatch = false; + int uid = task_uid(tsk).val; + + if (!(is_fg(uid) || atomic_read(&tpd_ctl))) + goto out; + + switch (tsk->tpd) { + case TPD_TYPE_S: + if (!cpumask_test_cpu(dest_cpu, &clusters[0].related_cpus)) + mismatch = true; + break; + case TPD_TYPE_G: + if (!cpumask_test_cpu(dest_cpu, &clusters[1].related_cpus)) + mismatch = true; + break; + case TPD_TYPE_GS: + /* if no gold plus cores, mid = max*/ + if (cluster_total == 3 && cpumask_test_cpu(dest_cpu, &clusters[2].related_cpus)) + mismatch = true; + break; + case TPD_TYPE_P: + if (cluster_total == 3 && !cpumask_test_cpu(dest_cpu, &clusters[2].related_cpus)) + mismatch = true; + break; + case TPD_TYPE_PS: + if (cpumask_test_cpu(dest_cpu, &clusters[1].related_cpus)) + mismatch = true; + break; + case TPD_TYPE_PG: + if (cpumask_test_cpu(dest_cpu, &clusters[0].related_cpus)) + 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, is_fg(uid)); + + return mismatch; +} + +void tpd_init_policy(struct cpufreq_policy *policy) +{ + struct tpd_cpuinfo *cpu_info; + int i; + + cpu_info = &clusters[cluster_total]; + cpu_info->first_cpu = policy->cpu; + cpumask_copy(&cpu_info->related_cpus, policy->related_cpus); + cluster_total++; + + tpd_logd("policy->cpu = %d, related_cpus = ", policy->cpu); + for_each_cpu(i, policy->related_cpus) + tpd_logd("%d ", i); +} + +static void tpd_mgp_init() +{ + int i, j; + + for (i = 0; i < TPD_GROUP_MAX; ++i) { + mgp[i].decision = 0; + spin_lock_init(&mgp[i].tgid_list_lock); + INIT_LIST_HEAD(&mgp[i].tgid_head); + spin_lock_init(&mgp[i].miss_list_lock); + for (j = 0; j < MAX_MISS_LIST; j++) { + mgp[i].miss_list_tgid[j] = 0; + strcpy(mgp[i].miss_list[j], ""); + } + mgp[i].not_yet = 0; + mgp[i].cur_idx = 0; + } +} + +static int tpd_init(void) +{ + tpd_mgp_init(); + tpd_logv("tpd init\n"); + return 0; +} + +pure_initcall(tpd_init); diff --git a/drivers/oneplus/coretech/uxcore/core/opchain_core.c b/drivers/oneplus/coretech/uxcore/core/opchain_core.c index 5411ec4f1aa2..5a1ac3bececc 100644 --- a/drivers/oneplus/coretech/uxcore/core/opchain_core.c +++ b/drivers/oneplus/coretech/uxcore/core/opchain_core.c @@ -213,11 +213,11 @@ static void ctech_opc_binder_parse(void *rq, void *cur, int send) { /* dont move forward to cache diverse histories as many as possible */ - if (chain_on && !TASK_EXIT_STATE_R(TASK_GROUP_LEADER_R(cur)) && + 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 (send) { + if (chain_on && send) { ctech_ux_mark(rq, cur, UT_ETASK); ctech_ux_clock_base_mark(rq, cur); } diff --git a/drivers/oneplus/coretech/uxcore/core/opchain_proxy.c b/drivers/oneplus/coretech/uxcore/core/opchain_proxy.c index e5fe88e95b6a..9cb81dbea688 100644 --- a/drivers/oneplus/coretech/uxcore/core/opchain_proxy.c +++ b/drivers/oneplus/coretech/uxcore/core/opchain_proxy.c @@ -39,7 +39,7 @@ 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 = 1; +unsigned int __read_mostly chain_on = 0; unsigned int __read_mostly latest_ms = 100; unsigned int __read_mostly latest_threshold = 100000000; diff --git a/drivers/oneplus/drivers/Kconfig b/drivers/oneplus/drivers/Kconfig index d9db3bed32c0..71ebd08e8bde 100644 --- a/drivers/oneplus/drivers/Kconfig +++ b/drivers/oneplus/drivers/Kconfig @@ -23,4 +23,10 @@ config PARAM_READ_WRITE if you want to read/write the param partition in kernel, then you must say Y here. +config DEBUG_PARAM_DUMP + bool "Param debug support" + default n + help + if you want to dump contents of param partition for debug purpose + source "drivers/oneplus/drivers/input/fingerprint/Kconfig" diff --git a/drivers/oneplus/drivers/input/fingerprint/fpc/fpc1020_tee.c b/drivers/oneplus/drivers/input/fingerprint/fpc/fpc1020_tee.c index de61f1ba141d..601da6c982ea 100644 --- a/drivers/oneplus/drivers/input/fingerprint/fpc/fpc1020_tee.c +++ b/drivers/oneplus/drivers/input/fingerprint/fpc/fpc1020_tee.c @@ -58,25 +58,11 @@ static const char * const pctl_names[] = { //"fpc1020_irq_active", }; -struct vreg_config { - char *name; - unsigned long vmin; - unsigned long vmax; - int ua_load; -}; - -static const struct vreg_config const vreg_conf[] = { - { "vdd_ana", 1800000UL, 1800000UL, 6000, }, - { "vcc_spi", 1800000UL, 1800000UL, 10, }, - { "vdd_io", 1800000UL, 1800000UL, 6000, }, -}; - struct fpc1020_data { struct device *dev; struct pinctrl *fingerprint_pinctrl; struct pinctrl_state *pinctrl_state[ARRAY_SIZE(pctl_names)]; - struct regulator *vreg[ARRAY_SIZE(vreg_conf)]; struct wakeup_source ttw_wl; int irq_gpio; diff --git a/drivers/oneplus/drivers/oem_debug/oem_force_dump.c b/drivers/oneplus/drivers/oem_debug/oem_force_dump.c index 36ac1a7f8157..4f2e8beb09e8 100644 --- a/drivers/oneplus/drivers/oem_debug/oem_force_dump.c +++ b/drivers/oneplus/drivers/oem_debug/oem_force_dump.c @@ -121,7 +121,10 @@ void oem_check_force_dump_key(unsigned int code, int value) break; case STEP_DEBUG1: - if (code == KEY_VOLUMEDOWN && !value) { + if (code == KEY_POWER && value) { + message_state = 1; + state = NONE; + } else if (code == KEY_VOLUMEDOWN && !value) { message_state = 2; queue_work(smg_workwq, &smg_work); state = NONE; diff --git a/drivers/oneplus/drivers/oem_trace/oem_trace.c b/drivers/oneplus/drivers/oem_trace/oem_trace.c index 19ffdc458d1d..beeeec92ba9d 100755 --- a/drivers/oneplus/drivers/oem_trace/oem_trace.c +++ b/drivers/oneplus/drivers/oem_trace/oem_trace.c @@ -170,7 +170,7 @@ struct sysinfo i; allowed = ((totalram_pages - hugetlb_total_pages()) * sysctl_overcommit_ratio / 100) + total_swap_pages; - cached = global_page_state(NR_FILE_PAGES) - + cached = global_node_page_state(NR_FILE_PAGES) - total_swapcache_pages() - i.bufferram; if (cached < 0) cached = 0; @@ -263,8 +263,8 @@ struct sysinfo i; #endif K(i.totalswap), K(i.freeswap), - K(global_page_state(NR_FILE_DIRTY)), - K(global_page_state(NR_WRITEBACK)), + K(global_node_page_state(NR_FILE_DIRTY)), + K(global_node_page_state(NR_WRITEBACK)), #ifdef CONFIG_TRANSPARENT_HUGEPAGE K(global_page_state(NR_PAGETABLE) + global_page_state(NR_ANON_TRANSPARENT_HUGEPAGES) * @@ -272,8 +272,8 @@ struct sysinfo i; #else K(global_page_state(NR_PAGETABLE)), #endif - K(global_page_state(NR_FILE_MAPPED)), - K(global_page_state(NR_SHMEM)), + K(global_node_page_state(NR_FILE_MAPPED)), + K(global_node_page_state(NR_SHMEM)), K(global_page_state(NR_SLAB_RECLAIMABLE) + global_page_state(NR_SLAB_UNRECLAIMABLE)), K(global_page_state(NR_SLAB_RECLAIMABLE)), @@ -283,9 +283,9 @@ struct sysinfo i; #ifdef CONFIG_QUICKLIST K(quicklist_total_size()), #endif - K(global_page_state(NR_UNSTABLE_NFS)), + K(global_node_page_state(NR_UNSTABLE_NFS)), K(global_page_state(NR_BOUNCE)), - K(global_page_state(NR_WRITEBACK_TEMP)), + K(global_node_page_state(NR_WRITEBACK_TEMP)), K(allowed), K(committed), (unsigned long)VMALLOC_TOTAL >> 10, diff --git a/drivers/oneplus/drivers/param_read_write/param_read_write.c b/drivers/oneplus/drivers/param_read_write/param_read_write.c index 9e2cd569ced8..c81d830cf525 100644 --- a/drivers/oneplus/drivers/param_read_write/param_read_write.c +++ b/drivers/oneplus/drivers/param_read_write/param_read_write.c @@ -332,12 +332,14 @@ static int __init param_init(void) return -1; } mutex_init(¶m_ram_zone.mutex); + +#ifdef CONFIG_DEBUG_PARAM_DUMP for (i = 0; i < NUM_PARAM_PLAINTEXT_SEGMENT; i++) { - break;//do not dump param printk("===dump chunk %d===\n", i); print_hex_dump (KERN_ERR, "",DUMP_PREFIX_OFFSET,16, 4, param_ram_zone.buffer +1024*i, default_param_data_dump_size,1); } +#endif param_init_done= 1; diff --git a/drivers/oneplus/include/linux/oem/cpufreq_bouncing.h b/drivers/oneplus/include/linux/oem/cpufreq_bouncing.h new file mode 100644 index 000000000000..b334c8450d80 --- /dev/null +++ b/drivers/oneplus/include/linux/oem/cpufreq_bouncing.h @@ -0,0 +1,19 @@ +#ifndef __CPUFREQ_BOUNCING_H__ +#define __CPUFREQ_BOUNCING_H__ + +#include + +#ifdef CONFIG_CPUFREQ_BOUNCING +void cb_update(struct cpufreq_policy *pol, u64 time); +void cb_reset(int cpu, u64 time); +unsigned int cb_cap(struct cpufreq_policy *pol, unsigned int freq); +unsigned int cb_get_cap(int cpu); +#else +static inline void cb_reset(int cpu, u64 time) {} +static inline void cb_update(struct cpufreq_policy *pol, u64 time) {} +static inline unsigned int cb_cap(struct cpufreq_policy *pol, unsigned int freq) { return freq; } +static inline unsigned int cb_get_cap(int cpu) { return UINT_MAX; } +#endif + +#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..ea0743a6a8f9 --- /dev/null +++ b/drivers/oneplus/include/linux/oem/tpd.h @@ -0,0 +1,74 @@ +#ifndef __TPD_H__ +#define __TPD_H__ + +#include +#include +#include + +#define TPD_CLUSTER_0 (1 << 0) +#define TPD_CLUSTER_1 (1 << 1) +#define TPD_CLUSTER_2 (1 << 2) + +#define TPD_TYPE_S TPD_CLUSTER_0 /* Silver only */ +#define TPD_TYPE_G TPD_CLUSTER_1 /* gold only */ +#define TPD_TYPE_GS (TPD_CLUSTER_1 | TPD_CLUSTER_0) /* sliver + gold */ +#define TPD_TYPE_P TPD_CLUSTER_2 /* gold+ only */ +#define TPD_TYPE_PS (TPD_CLUSTER_2 | TPD_CLUSTER_0) /* gold+ + silver */ +#define TPD_TYPE_PG (TPD_CLUSTER_2 | TPD_CLUSTER_1) /* gold+ + gold */ +#define TPD_TYPE_PGS (TPD_CLUSTER_2 | TPD_CLUSTER_1 | TPD_CLUSTER_0) /* all */ + +#define MAX_THREAD_INPUT 6 +#define MAX_MISS_LIST 20 + +#define TPD_TAG "TPD_DEBUG: " + +#define tpd_logv(fmt...) \ + do { \ + if (tpd_log_lv < 1) \ + pr_info(TPD_TAG fmt); \ + } while (0) + +#define tpd_logi(fmt...) \ + do { \ + if (tpd_log_lv < 2) \ + pr_info(TPD_TAG fmt); \ + } while (0) + +#define tpd_logw(fmt...) \ + do { \ + if (tpd_log_lv < 3) \ + pr_warn(TPD_TAG fmt); \ + } while (0) + +#define tpd_loge(fmt...) pr_err(TPD_TAG fmt) +#define tpd_logd(fmt...) pr_debug(TPD_TAG fmt) + +enum dynamic_tpd_type { + TPD_GROUP_MEDIAPROVIDER = 0, + + TPD_GROUP_MAX +}; + +#ifdef CONFIG_TPD +extern bool is_tpd_enable(void); +extern int tpd_suggested(struct task_struct* tsk, int request_cluster); +extern int tpd_suggested_cpu(struct task_struct* tsk, int request_cpu); +extern void tpd_mask(struct task_struct* tsk, cpumask_t *request); +extern bool tpd_check(struct task_struct *tsk, int dest_cpu); +extern bool is_dynamic_tpd_task(struct task_struct *tsk); +static inline bool is_tpd_task(struct task_struct *tsk) { return tsk ? (tsk->tpd > 0) : false; } +extern void tpd_tglist_del(struct task_struct *tsk); +extern void tpd_init_policy(struct cpufreq_policy *policy); +#else +static inline bool is_tpd_enable(void) { return false; } +static inline int tpd_suggested(struct task_struct* tsk, int request_cluster) { return request_cluster; } +static inline int tpd_suggested_cpu(struct task_struct* tsk, int request_cpu) { return request_cpu; } +static inline void tpd_mask(struct task_struct* tsk, cpumask_t *request) {} +static inline bool tpd_check(struct task_struct *tsk, int dest_cpu) { return false; } +static inline bool is_dynamic_tpd_task(struct task_struct *tsk) { return false; } +static inline bool is_tpd_task(struct task_struct *tsk) { return false; } +static inline void tpd_tglist_del(struct task_struct *tsk) {}; +static inline void tpd_init_policy(struct cpufreq_policy *policy) {} +#endif + +#endif diff --git a/drivers/oneplus/op_freezer/Kconfig b/drivers/oneplus/op_freezer/Kconfig new file mode 100755 index 000000000000..00dfd0a00566 --- /dev/null +++ b/drivers/oneplus/op_freezer/Kconfig @@ -0,0 +1,5 @@ +config OP_FREEZER + bool "op_freezer kernel and freezer native communication channel" + default n + help + Key events (signal/network package/binder) report to freezer native. \ No newline at end of file diff --git a/drivers/oneplus/op_freezer/Makefile b/drivers/oneplus/op_freezer/Makefile new file mode 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; +} + From 6a5433f2846dab0f6137f02770231b3f05ad40a7 Mon Sep 17 00:00:00 2001 From: LuK1337 Date: Sat, 4 Sep 2021 10:51:47 +0200 Subject: [PATCH 275/356] input: synaptics: s3320: Sync with oneplus/SDM845_R_11.0 Change-Id: I2f1524ff91777f513690337fa8a3d95b69e6ab07 --- drivers/input/touchscreen/synaptics_driver_s3320.c | 2 +- drivers/input/touchscreen/synaptics_dsx_fw_update.c | 10 +++------- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/input/touchscreen/synaptics_driver_s3320.c b/drivers/input/touchscreen/synaptics_driver_s3320.c index 4d2d703d94c5..5ac704c66382 100644 --- a/drivers/input/touchscreen/synaptics_driver_s3320.c +++ b/drivers/input/touchscreen/synaptics_driver_s3320.c @@ -367,7 +367,7 @@ static int synaptics_rmi4_i2c_write_word(struct i2c_client* client, unsigned char addr,unsigned short data); static int synaptics_mode_change(int mode); int tp_single_tap_en(struct synaptics_ts_data *ts, bool enable); -int opticalfp_irq_handler(struct fp_underscreen_info* tp_info); +int opticalfp_irq_handler(struct fp_underscreen_info *tp_info); int gf_opticalfp_irq_handler(int event); #ifdef TPD_USE_EINT diff --git a/drivers/input/touchscreen/synaptics_dsx_fw_update.c b/drivers/input/touchscreen/synaptics_dsx_fw_update.c index 719fcfc30103..93db8d645bd8 100644 --- a/drivers/input/touchscreen/synaptics_dsx_fw_update.c +++ b/drivers/input/touchscreen/synaptics_dsx_fw_update.c @@ -2386,16 +2386,12 @@ static enum flash_area fwu_go_nogo(void) TPD_ERR("%s: Image firmware ID = %d\n", __func__, image_fw_id); - if (image_fw_id > device_fw_id) { + if (image_fw_id != device_fw_id) { flash_area = UI_FIRMWARE; - goto exit; - } else if (image_fw_id < device_fw_id) { - TPD_ERR("%s: Image firmware ID older than device firmware ID\n", + TPD_ERR("%s Device firmware ID & Image firmware ID aren't same, updating firmware\n", __func__); - flash_area = NONE; goto exit; } - /* Get device config ID */ retval = fwu_get_device_config_id(); if (retval < 0) { @@ -3853,7 +3849,7 @@ static int fwu_recovery_reset(void) static int fwu_start_recovery(void) { - int retval; + int retval = 0; const struct firmware *fw_entry = NULL; struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; From 7a1333df7b041fbc5eb7ef1df237e05c82144348 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Tue, 15 Mar 2022 23:32:21 +0000 Subject: [PATCH 276/356] oneplus: Fix unused variable warnings Change-Id: I2f9f2caa498caa32e5814869e31b0260cb13271f --- .../cam_sensor_module/cam_eeprom/cam_eeprom_core.c | 2 +- .../cam_sensor_module/cam_sensor/cam_sensor_core.c | 4 ++-- drivers/oneplus/drivers/param_read_write/param_read_write.c | 4 ++++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_eeprom/cam_eeprom_core.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_eeprom/cam_eeprom_core.c index 766f73f523d3..8b3c7024bcbb 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_eeprom/cam_eeprom_core.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_eeprom/cam_eeprom_core.c @@ -20,7 +20,6 @@ #ifdef CONFIG_PROJECT_INFO #include -#endif struct ois_vendor_match_tbl { uint16_t ois_id; @@ -31,6 +30,7 @@ static struct ois_vendor_match_tbl match_tbl[] = { {0x24, "BU24218GWL", "Rohm"}, {0x28, "BU24228GWL", "Rohm"}, }; +#endif /** * cam_eeprom_read_memory() - read map data into buffer diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/cam_sensor_core.c index 1ca9acc33140..ee3039910343 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/cam_sensor_core.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/cam_sensor_core.c @@ -19,7 +19,6 @@ #ifdef CONFIG_PROJECT_INFO #include -#endif struct camera_vendor_match_tbl { uint16_t sensor_id; @@ -31,6 +30,7 @@ static struct camera_vendor_match_tbl match_tbl[] = { {0x376, "imx376k", "Sony"}, {0x371, "imx371", "Sony"}, }; +#endif static struct cam_sensor_i2c_reg_array lotid_on_setting[2] = { { @@ -778,8 +778,8 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, struct cam_sensor_power_setting *pd = NULL; struct cam_sensor_power_ctrl_t *power_info = &s_ctrl->sensordata->power_info; - uint32_t count = 0, i; #ifdef CONFIG_PROJECT_INFO + uint32_t count = 0, i; enum COMPONENT_TYPE CameraID; #endif diff --git a/drivers/oneplus/drivers/param_read_write/param_read_write.c b/drivers/oneplus/drivers/param_read_write/param_read_write.c index c81d830cf525..659d6cc87e8a 100644 --- a/drivers/oneplus/drivers/param_read_write/param_read_write.c +++ b/drivers/oneplus/drivers/param_read_write/param_read_write.c @@ -25,7 +25,9 @@ #define PARAM_PARTITION "/dev/block/bootdevice/by-name/param" #define READ_CHUNK_MAX_SIZE (1024) #define WRITE_CHUNK_MAX_SIZE (1024) +#ifdef CONFIG_DEBUG_PARAM_DUMP static uint default_param_data_dump_size= DEFAULT_PARAM_DUMP_SIZE; +#endif typedef struct{ phys_addr_t paddr; @@ -323,7 +325,9 @@ struct miscdevice param_misc = { static int __init param_init(void) { +#ifdef CONFIG_DEBUG_PARAM_DUMP int i; +#endif int ret = 0; if(param_ram_buffer_map((phys_addr_t)param_ram_zone.paddr, From afcb156a6c694651d086a90416c806a820bd98f7 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Tue, 15 Mar 2022 23:20:58 +0000 Subject: [PATCH 277/356] project_info: Fix snprintf size argument too large warnings Change-Id: I0954d89f690554a3d25278df8b2f2c930e6c17d7 --- drivers/soc/qcom/project_info.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/soc/qcom/project_info.c b/drivers/soc/qcom/project_info.c index 78bfbad63d3d..845c101416d3 100644 --- a/drivers/soc/qcom/project_info.c +++ b/drivers/soc/qcom/project_info.c @@ -482,7 +482,7 @@ void get_ddr_manufacture_name(void) for (i = 0; i < length; i++) { if (ddr_manufacture_list[i].id == GET_PROJECT_INFO(ddr_manufacture_info)) { - snprintf(ddr_manufacture, BUF_SIZE, "%s", + snprintf(ddr_manufacture, sizeof(ddr_manufacture), "%s", ddr_manufacture_list[i].name); break; } @@ -499,7 +499,7 @@ void get_cpu_type(void) for (i = 0; i < length; i++) { if (cpu_list_msm[i].id == GET_PROJECT_INFO(platform_id)) { - snprintf(cpu_type, BUF_SIZE, + snprintf(cpu_type, sizeof(cpu_type), "%s", cpu_list_msm[i].name); break; } From fadc5f8794b3caee34fd97bf9c58d68c6f28b6ce Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Wed, 16 Mar 2022 00:01:37 +0000 Subject: [PATCH 278/356] project_info: Remove redefinition of totalram_pages Defined on linux/swap.h Change-Id: I88eb4e80ff72f97953218105aef58871a541f287 --- drivers/soc/qcom/project_info.c | 1 + include/linux/project_info.h | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soc/qcom/project_info.c b/drivers/soc/qcom/project_info.c index 845c101416d3..a57502196aae 100644 --- a/drivers/soc/qcom/project_info.c +++ b/drivers/soc/qcom/project_info.c @@ -21,6 +21,7 @@ #include #include #include +#include static struct component_info component_info_desc[COMPONENT_MAX]; static struct kobject *project_info_kobj; diff --git a/include/linux/project_info.h b/include/linux/project_info.h index cc8eb05f7e71..e0b1de6dfc1f 100644 --- a/include/linux/project_info.h +++ b/include/linux/project_info.h @@ -11,7 +11,6 @@ typedef __u8 uint8; #include #include //extern uint32_t chip_serial_num; -extern unsigned long totalram_pages __read_mostly; struct project_info { char project_name[8]; //eg, 16859 From 4d5946ee4f58bad412d93e4e84bc00fb482fa99e Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Tue, 15 Mar 2022 23:49:02 +0000 Subject: [PATCH 279/356] touchscreen: Fix warnings Change-Id: Ie33b24f85522bb171e8377ac8ee793d4e9270822 --- drivers/input/touchscreen/fw_update_v7.if | 2 +- drivers/input/touchscreen/synaptics_driver_s3320.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/input/touchscreen/fw_update_v7.if b/drivers/input/touchscreen/fw_update_v7.if index 026855b17d90..b853089124e1 100644 --- a/drivers/input/touchscreen/fw_update_v7.if +++ b/drivers/input/touchscreen/fw_update_v7.if @@ -1688,7 +1688,7 @@ static int scan_pdt(void) fwu->f34_fd.query_base_addr = add_buf[0]; fwu->f34_fd.ctrl_base_addr = add_buf[2]; fwu->f34_fd.data_base_addr = add_buf[3]; - if (add_buf[4]>>5 && 0x2) + if ((add_buf[4]>>5) & 0x2) fwu->bl_version = BL_V7; TPD_ERR("F34_query_base_addr[0x%x],F34_ctrl_base_addr[0x%x],F34_data_base_addr[0x%x]\n",\ add_buf[0],add_buf[2],add_buf[3]); diff --git a/drivers/input/touchscreen/synaptics_driver_s3320.c b/drivers/input/touchscreen/synaptics_driver_s3320.c index 5ac704c66382..19acd9a1be56 100644 --- a/drivers/input/touchscreen/synaptics_driver_s3320.c +++ b/drivers/input/touchscreen/synaptics_driver_s3320.c @@ -4717,7 +4717,7 @@ static ssize_t key_switch_read_func(struct file *file, char __user *user_buf, si TPD_ERR("%s left:%s right:%s\n", __func__, key_switch?"key_back":"key_appselect", key_switch?"key_appselect":"key_back"); - ret = snprintf(page, PAGE_SIZE, "key_switch left:%s right:%s\n", + ret = snprintf(page, sizeof(page), "key_switch left:%s right:%s\n", key_switch?"key_back":"key_appselect", key_switch?"key_appselect":"key_back"); ret = simple_read_from_buffer(user_buf, count, ppos, page, strlen(page)); From dc0cb75d85d0efc1ccd01808bc99fa86ce6de64e Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Sat, 24 Sep 2022 21:06:46 -0400 Subject: [PATCH 280/356] touchscreen: Avoid VLA --- drivers/input/touchscreen/synaptics_driver_s3320.c | 2 +- drivers/input/touchscreen/synaptics_s3320_redremote.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/input/touchscreen/synaptics_driver_s3320.c b/drivers/input/touchscreen/synaptics_driver_s3320.c index 19acd9a1be56..c134c9790a97 100644 --- a/drivers/input/touchscreen/synaptics_driver_s3320.c +++ b/drivers/input/touchscreen/synaptics_driver_s3320.c @@ -1085,7 +1085,7 @@ int synaptics_rmi4_i2c_write_block( { int retval; unsigned char retry; - unsigned char buf[length + 1]; + unsigned char buf[2]; struct i2c_msg msg[] = { { .addr = client->addr, diff --git a/drivers/input/touchscreen/synaptics_s3320_redremote.c b/drivers/input/touchscreen/synaptics_s3320_redremote.c index ad4df62c2463..23d35341d225 100644 --- a/drivers/input/touchscreen/synaptics_s3320_redremote.c +++ b/drivers/input/touchscreen/synaptics_s3320_redremote.c @@ -403,7 +403,7 @@ int remote_rmi4_i2c_write(unsigned short addr, unsigned char *data, unsigned sho { int retval; unsigned char retry; - unsigned char buf[length + 1]; + unsigned char buf[2]; struct i2c_client* i2c_client = remote_rmi4_get_i2c_client(); struct i2c_msg msg[] = { { @@ -523,7 +523,7 @@ static ssize_t rmidev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) { ssize_t retval; - unsigned char tmpbuf[count + 1]; + unsigned char tmpbuf[16]; struct rmidev_data *dev_data = filp->private_data; //printk("synap %s\n",__func__); if (IS_ERR(dev_data)) { @@ -572,7 +572,7 @@ 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[count + 1]; + unsigned char tmpbuf[16]; struct rmidev_data *dev_data = filp->private_data; printk("synap %s\n",__func__); From 65a72a33fc606dc4cf945d1aa0810bead4fb7044 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Sat, 24 Sep 2022 21:11:56 -0400 Subject: [PATCH 281/356] touchscreen: sys_* -> ksys_* --- .../touchscreen/synaptics_driver_s3320.c | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/input/touchscreen/synaptics_driver_s3320.c b/drivers/input/touchscreen/synaptics_driver_s3320.c index c134c9790a97..5e92e2c982fa 100644 --- a/drivers/input/touchscreen/synaptics_driver_s3320.c +++ b/drivers/input/touchscreen/synaptics_driver_s3320.c @@ -2646,7 +2646,7 @@ static ssize_t synaptics_rmi4_baseline_show_s3508(struct device *dev, char *buf, old_fs = get_fs(); set_fs(KERNEL_DS); - fd = sys_open(data_buf, O_WRONLY | O_CREAT | O_TRUNC, 0); + fd = ksys_open(data_buf, O_WRONLY | O_CREAT | O_TRUNC, 0); if (fd < 0) { TPD_ERR("Open log file '%s' failed.\n", data_buf); set_fs(old_fs); @@ -2722,7 +2722,7 @@ static ssize_t synaptics_rmi4_baseline_show_s3508(struct device *dev, char *buf, baseline_data = (tmp_h<<8)|tmp_l; if (fd >= 0){ sprintf(data_buf, "%d,", baseline_data); - sys_write(fd, data_buf, strlen(data_buf)); + ksys_write(fd, data_buf, strlen(data_buf)); } if( (y < RX_NUM ) && (x < TX_NUM) ){ //printk("%4d ,",baseline_data); @@ -2764,14 +2764,14 @@ static ssize_t synaptics_rmi4_baseline_show_s3508(struct device *dev, char *buf, } //printk("\n synaptics:s3320 TX_NUM:%d\n",x); if (fd >= 0){ - sys_write(fd, "\n", 1); + ksys_write(fd, "\n", 1); } } if(!enable_cbc){ enable_cbc = 1; if (fd >= 0){ - sys_write(fd, "\n", 1); + ksys_write(fd, "\n", 1); } TPD_ERR("enable cbc baseline test again\n"); goto TEST_WITH_CBC_s3508; @@ -2958,7 +2958,7 @@ static ssize_t synaptics_rmi4_baseline_show_s3508(struct device *dev, char *buf, TPD_ERR("ROLAND----> err_RT253 is %d\n", err_RT253); END: if (fd >= 0) { - sys_close(fd); + ksys_close(fd); set_fs(old_fs); } //release_firmware(fw); @@ -3062,7 +3062,7 @@ static ssize_t synaptics_rmi4_baseline_show_s3706( old_fs = get_fs(); set_fs(KERNEL_DS); - fd = sys_open(data_buf, O_WRONLY | O_CREAT | O_TRUNC, 0); + fd = ksys_open(data_buf, O_WRONLY | O_CREAT | O_TRUNC, 0); if (fd < 0) { TPD_ERR("Open log file '%s' failed.\n", data_buf); set_fs(old_fs); @@ -3157,7 +3157,7 @@ static ssize_t synaptics_rmi4_baseline_show_s3706( baseline_data = (tmp_h << 8) | tmp_l; if (fd >= 0) { snprintf(data_buf, 20, "%d,", baseline_data); - sys_write(fd, data_buf, strlen(data_buf)); + ksys_write(fd, data_buf, strlen(data_buf)); } if ((y < RX_NUM) && (x < TX_NUM)) { /*printk("%4d ,",baseline_data);*/ @@ -3210,13 +3210,13 @@ static ssize_t synaptics_rmi4_baseline_show_s3706( } /*printk("\n synaptics:s3320 TX_NUM:%d\n",x);*/ if (fd >= 0) - sys_write(fd, "\n", 1); + ksys_write(fd, "\n", 1); } if (!enable_cbc) { enable_cbc = 1; if (fd >= 0) - sys_write(fd, "\n", 1); + ksys_write(fd, "\n", 1); TPD_ERR("enable cbc baseline test again\n"); goto TEST_WITH_CBC_s3508; } @@ -3362,7 +3362,7 @@ static ssize_t synaptics_rmi4_baseline_show_s3706( } END: if (fd >= 0) { - sys_close(fd); + ksys_close(fd); set_fs(old_fs); } From 9c0c6d20db31f9babbb1c486f2fb923b2a2b7327 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Sat, 24 Sep 2022 22:13:37 -0400 Subject: [PATCH 282/356] touchscreen: Switch to DRIVER_ATTR_RW --- .../touchscreen/synaptics_driver_s3320.c | 36 +++++++++++-------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/drivers/input/touchscreen/synaptics_driver_s3320.c b/drivers/input/touchscreen/synaptics_driver_s3320.c index 5e92e2c982fa..9ab388f0da56 100644 --- a/drivers/input/touchscreen/synaptics_driver_s3320.c +++ b/drivers/input/touchscreen/synaptics_driver_s3320.c @@ -2330,7 +2330,7 @@ static ssize_t tp_sleep_write_func(struct file *file, const char *buffer, size_t } #endif -static ssize_t tp_show(struct device_driver *ddri, char *buf) +static ssize_t tp_debug_log_show(struct device_driver *ddri, char *buf) { // uint8_t ret = 0; struct synaptics_ts_data *ts = ts_g; @@ -2340,19 +2340,19 @@ static ssize_t tp_show(struct device_driver *ddri, char *buf) return 0; a = synaptics_rmi4_i2c_read_word(ts->client, F01_RMI_DATA_BASE); if( a < 0 ) - TPD_ERR("tp_show read i2c err\n"); + TPD_ERR("tp_debug_log_show read i2c err\n"); b = synaptics_rmi4_i2c_read_byte(ts->client, F01_RMI_DATA01); if( b < 0 ) - TPD_ERR("tp_show read i2c err\n"); + TPD_ERR("tp_debug_log_show read i2c err\n"); c = synaptics_rmi4_i2c_read_byte(ts->client, F12_2D_DATA_BASE); if( c < 0 ) - TPD_ERR("tp_show read i2c err\n"); + TPD_ERR("tp_debug_log_show read i2c err\n"); return sprintf(buf, "F01_RMI_DATA_BASE[0x%x]=0x%x;F01_RMI_DATA01[0x%x]=0x%x;F12_2D_DATA_BASE[0x%x]=0x%x;\n", \ F01_RMI_DATA_BASE,a,F01_RMI_DATA01,b,F12_2D_DATA_BASE,c); } -static ssize_t store_tp(struct device_driver *ddri, const char *buf, size_t count) +static ssize_t tp_debug_log_store(struct device_driver *ddri, const char *buf, size_t count) { int tmp = 0; if( 1 == sscanf(buf, "%d", &tmp) ){ @@ -2428,7 +2428,7 @@ static void checkCMD_RT133(void) #endif -static ssize_t tp_baseline_show(struct device_driver *ddri, char *buf) +static ssize_t tp_baseline_image_show(struct device_driver *ddri, char *buf) { int ret = 0; int x, y; @@ -2526,7 +2526,7 @@ static ssize_t tp_baseline_show(struct device_driver *ddri, char *buf) } -static ssize_t tp_rawdata_show(struct device_driver *ddri, char *buf) +static ssize_t tp_delta_image_show(struct device_driver *ddri, char *buf) { int ret = 0; int x, y; @@ -2571,7 +2571,14 @@ static ssize_t tp_rawdata_show(struct device_driver *ddri, char *buf) return num_read_chars; } -static ssize_t tp_delta_store(struct device_driver *ddri, +static ssize_t tp_delta_image_store(struct device_driver *ddri, + const char *buf, size_t count) +{ + TPDTM_DMESG("tp_test_store is not support\n"); + return count; +} + +static ssize_t tp_baseline_image_store(struct device_driver *ddri, const char *buf, size_t count) { TPDTM_DMESG("tp_test_store is not support\n"); @@ -3408,7 +3415,7 @@ static ssize_t synaptics_rmi4_baseline_show_s3706( } -static ssize_t tp_baseline_show_with_cbc(struct device_driver *ddri, char *buf) +static ssize_t tp_baseline_image_with_cbc_show(struct device_driver *ddri, char *buf) { int ret = 0; int x,y; @@ -3530,7 +3537,7 @@ static ssize_t synaptics_rmi4_baseline_show(struct device *dev, char *buf, bool } } -static ssize_t tp_test_store(struct device_driver *ddri, +static ssize_t tp_baseline_image_with_cbc_store(struct device_driver *ddri, const char *buf, size_t count) { TPDTM_DMESG("tp_test_store is not support\n"); @@ -4093,12 +4100,11 @@ static ssize_t tp_gesture_touch_hold_store(struct device *dev, return size; } -//static DRIVER_ATTR(tp_baseline_image_with_cbc, 0664, tp_baseline_show_with_cbc, tp_test_store); static DEVICE_ATTR(test_limit, 0664, synaptics_test_limit_show, synaptics_test_limit_store); -static DRIVER_ATTR(tp_baseline_image, 0664, tp_baseline_show, tp_delta_store); -static DRIVER_ATTR(tp_baseline_image_with_cbc, 0664, tp_baseline_show_with_cbc, tp_test_store); -static DRIVER_ATTR(tp_delta_image, 0664, tp_rawdata_show, NULL); -static DRIVER_ATTR(tp_debug_log, 0664, tp_show, store_tp); +static DRIVER_ATTR_RW(tp_baseline_image); +static DRIVER_ATTR_RW(tp_baseline_image_with_cbc); +static DRIVER_ATTR_RW(tp_delta_image); +static DRIVER_ATTR_RW(tp_debug_log); static DEVICE_ATTR(tp_fw_update, 0664, synaptics_update_fw_show, synaptics_update_fw_store); static DEVICE_ATTR(tp_doze_time, 0664, tp_doze_time_show, tp_doze_time_store); static DEVICE_ATTR(tp_gesture_touch_hold, 0664, From 7084ade903319a193470a7b7376e3f08a44d5adf Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Sat, 24 Sep 2022 21:30:08 -0400 Subject: [PATCH 283/356] touchscreen: Update wakeup source for 4.19 --- drivers/input/touchscreen/synaptics_driver_s3320.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/input/touchscreen/synaptics_driver_s3320.c b/drivers/input/touchscreen/synaptics_driver_s3320.c index 9ab388f0da56..112935f44a47 100644 --- a/drivers/input/touchscreen/synaptics_driver_s3320.c +++ b/drivers/input/touchscreen/synaptics_driver_s3320.c @@ -498,7 +498,7 @@ struct synaptics_ts_data { int regulator_avdd_vmin; int regulator_avdd_vmax; int regulator_avdd_current; - struct wakeup_source source; + struct wakeup_source *source; uint32_t irq_flags; uint32_t max_x; @@ -1995,9 +1995,9 @@ static irqreturn_t synaptics_irq_thread_fn(int irq, void *dev_id) { struct synaptics_ts_data *ts = (struct synaptics_ts_data *)dev_id; touch_disable(ts); - __pm_stay_awake(&ts->source); //avoid system enter suspend lead to i2c error + __pm_stay_awake(ts->source); //avoid system enter suspend lead to i2c error synaptics_ts_work_func(&ts->report_work); - __pm_relax(&ts->source); + __pm_relax(ts->source); return IRQ_HANDLED; } #endif @@ -2074,7 +2074,7 @@ static ssize_t gesture_switch_write_func(struct file *file, const char __user *p TPD_ERR("%s: read proc input error.\n", __func__); return count; } - __pm_stay_awake(&ts->source); //avoid system enter suspend lead to i2c error + __pm_stay_awake(ts->source); //avoid system enter suspend lead to i2c error mutex_lock(&ts->mutex); ret = sscanf(buf,"%d",&write_flag); gesture_switch = write_flag; @@ -2097,7 +2097,7 @@ static ssize_t gesture_switch_write_func(struct file *file, const char __user *p } } mutex_unlock(&ts->mutex); - __pm_relax(&ts->source); + __pm_relax(ts->source); return count; } @@ -5911,7 +5911,7 @@ static int synaptics_ts_probe(struct i2c_client *client, const struct i2c_device goto exit_createworkqueue_failed; } INIT_DELAYED_WORK(&ts->base_work,tp_baseline_get_work); - wakeup_source_init(&ts->source, "tp_syna"); + ts->source = wakeup_source_register(NULL, "tp_syna"); ret = synaptics_init_panel(ts); /* will also switch back to page 0x04 */ if (ret < 0) { From 004bdb7f7537bd8949f82a8e0519d5355dbc2dd2 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Sat, 24 Sep 2022 22:35:02 -0400 Subject: [PATCH 284/356] oneplus: Use __kernel_write --- drivers/oneplus/drivers/param_read_write/param_read_write.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/oneplus/drivers/param_read_write/param_read_write.c b/drivers/oneplus/drivers/param_read_write/param_read_write.c index 659d6cc87e8a..2e516f6579f5 100644 --- a/drivers/oneplus/drivers/param_read_write/param_read_write.c +++ b/drivers/oneplus/drivers/param_read_write/param_read_write.c @@ -73,7 +73,7 @@ static int write_param_partition(const char *buf, unsigned long count, 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); + ret = __kernel_write(filp, (char __user *)buf, count, &filp->f_pos); out: set_fs(fs); From 9a69ea14f7a7440d034231b1e8aed0a79e7f80c4 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Sat, 24 Sep 2022 22:37:52 -0400 Subject: [PATCH 285/356] oneplus: Include correct uaccess header --- drivers/oneplus/drivers/param_read_write/param_read_write.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/oneplus/drivers/param_read_write/param_read_write.c b/drivers/oneplus/drivers/param_read_write/param_read_write.c index 2e516f6579f5..0e49c40af2d9 100644 --- a/drivers/oneplus/drivers/param_read_write/param_read_write.c +++ b/drivers/oneplus/drivers/param_read_write/param_read_write.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -19,6 +18,7 @@ #include #include #include +#include #define DISABLE_PARAM_DEBUG_LOG From 773dd758848c2e37a899cc8e4537ea8cd2c12511 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Sun, 25 Sep 2022 00:18:12 -0400 Subject: [PATCH 286/356] power: smb-lib: Update wakeup source for 4.19 --- drivers/power/supply/qcom/smb-lib.c | 6 +++--- drivers/power/supply/qcom/smb-lib.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c index 7eb9c50d8e60..1875d772856b 100644 --- a/drivers/power/supply/qcom/smb-lib.c +++ b/drivers/power/supply/qcom/smb-lib.c @@ -4143,10 +4143,10 @@ void smblib_usb_plugin_locked(struct smb_charger *chg) if (last_vbus_present != chg->vbus_present) { if (chg->vbus_present) { pr_info("acquire chg_wake_lock\n"); - __pm_stay_awake(&chg->chg_wake_lock); + __pm_stay_awake(chg->chg_wake_lock); } else { pr_info("release chg_wake_lock\n"); - __pm_relax(&chg->chg_wake_lock); + __pm_relax(chg->chg_wake_lock); } } if (vbus_rising) { @@ -8740,7 +8740,7 @@ int smblib_init(struct smb_charger *chg) schedule_delayed_work(&chg->heartbeat_work, msecs_to_jiffies(HEARTBEAT_INTERVAL_MS)); notify_dash_unplug_register(¬ify_unplug_event); - wakeup_source_init(&chg->chg_wake_lock, "chg_wake_lock"); + chg->chg_wake_lock = wakeup_source_register(NULL, "chg_wake_lock"); g_chg = chg; regsister_notify_usb_enumeration_status(&usb_enumeration); diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h index 02cc0ff7a6dd..9f73557f0c08 100644 --- a/drivers/power/supply/qcom/smb-lib.h +++ b/drivers/power/supply/qcom/smb-lib.h @@ -349,7 +349,7 @@ struct smb_charger { struct delayed_work dash_check_work; struct delayed_work revertboost_recovery_work; struct delayed_work connecter_check_work; - struct wakeup_source chg_wake_lock; + struct wakeup_source *chg_wake_lock; struct delayed_work clear_hdc_work; struct work_struct otg_oc_work; struct work_struct vconn_oc_work; From 94d92c76142bbd6550455db56e13dbd6d789f060 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Sun, 25 Sep 2022 12:02:40 -0400 Subject: [PATCH 287/356] power: oneplus: Update wakeup source for 4.19 --- .../power/supply/qcom/bq27541_fuelgauger.c | 8 ++--- drivers/power/supply/qcom/oneplus_fastchg.c | 35 +++++++++---------- 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/drivers/power/supply/qcom/bq27541_fuelgauger.c b/drivers/power/supply/qcom/bq27541_fuelgauger.c index 86c99ee10950..d0643315388d 100755 --- a/drivers/power/supply/qcom/bq27541_fuelgauger.c +++ b/drivers/power/supply/qcom/bq27541_fuelgauger.c @@ -224,7 +224,7 @@ struct bq27541_device_info { 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 wakeup_source *update_soc_wake_lock; struct power_supply *batt_psy; int saltate_counter; /* Add for retry when config fail */ @@ -1541,7 +1541,7 @@ static void update_pre_capacity_func(struct work_struct *w) bq27541_get_batt_remaining_capacity(); bq27541_get_batt_full_chg_capacity(); bq27541_set_allow_reading(false); - __pm_relax(&bq27541_di->update_soc_wake_lock); + __pm_relax(bq27541_di->update_soc_wake_lock); pr_info("exit\n"); } @@ -1994,7 +1994,7 @@ static int bq27541_battery_probe(struct i2c_client *client, new_client = client; - wakeup_source_init(&di->update_soc_wake_lock, "bq_delt_soc_wake_lock"); + di->update_soc_wake_lock = wakeup_source_register(NULL, "bq_delt_soc_wake_lock"); di->soc_pre = DEFAULT_INVALID_SOC_PRE; di->temp_pre = 0; #ifndef CONFIG_GAUGE_BQ27411 @@ -2119,7 +2119,7 @@ static int bq27541_battery_resume(struct device *dev) 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); + __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, diff --git a/drivers/power/supply/qcom/oneplus_fastchg.c b/drivers/power/supply/qcom/oneplus_fastchg.c index c0167951994d..ba9bb90802cb 100755 --- a/drivers/power/supply/qcom/oneplus_fastchg.c +++ b/drivers/power/supply/qcom/oneplus_fastchg.c @@ -71,8 +71,8 @@ struct fastchg_device_info { 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 wakeup_source *fastchg_wake_lock; + struct wakeup_source *fastchg_update_fireware_lock; struct delayed_work update_firmware; struct delayed_work update_fireware_version_work; @@ -490,7 +490,7 @@ static void dashchg_fw_update(struct work_struct *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); + __pm_stay_awake(di->fastchg_update_fireware_lock); if (di->n76e_present) rc = n76e_fw_check(di); else @@ -498,7 +498,7 @@ static void dashchg_fw_update(struct work_struct *work) if (rc == FW_CHECK_SUCCESS) { di->firmware_already_updated = true; reset_mcu_and_request_irq(di); - __pm_relax(&di->fastchg_update_fireware_lock); + __pm_relax(di->fastchg_update_fireware_lock); set_property_on_smbcharger(POWER_SUPPLY_PROP_SWITCH_DASH, true); pr_info("FW check success\n"); /* david@bsp add log */ return; @@ -555,7 +555,7 @@ static void dashchg_fw_update(struct work_struct *work) /* jump to app code end */ di->firmware_already_updated = true; reset_mcu_and_request_irq(di); - __pm_relax(&di->fastchg_update_fireware_lock); + __pm_relax(di->fastchg_update_fireware_lock); set_property_on_smbcharger(POWER_SUPPLY_PROP_SWITCH_DASH, true); pr_info("result=success\n"); return; @@ -563,7 +563,7 @@ static void dashchg_fw_update(struct work_struct *work) update_fw_err: di->firmware_already_updated = true; reset_mcu_and_request_irq(di); - __pm_relax(&di->fastchg_update_fireware_lock); + __pm_relax(di->fastchg_update_fireware_lock); set_property_on_smbcharger(POWER_SUPPLY_PROP_SWITCH_DASH, true); pr_err("result=fail\n"); } @@ -900,7 +900,7 @@ void di_watchdog(unsigned long data) schedule_work(&di->charger_present_status_work); pr_err("switch off fastchg\n"); - __pm_relax(&di->fastchg_wake_lock); + __pm_relax(di->fastchg_wake_lock); } #define MAX_BUFFER_SIZE 1024 @@ -1042,7 +1042,7 @@ static void adapter_update_work_func(struct work_struct *work) pr_info("%s end update_result:%d\n", __func__, update_result); - __pm_relax(&chip->fastchg_wake_lock); + __pm_relax(chip->fastchg_wake_lock); op_bus_vote(true); } @@ -1098,7 +1098,7 @@ static long dash_dev_ioctl(struct file *filp, unsigned int cmd, 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); + __pm_stay_awake(di->fastchg_wake_lock); bq27541_data->set_allow_reading(false); di->fast_chg_allow = false; di->fast_normal_to_warm = false; @@ -1131,7 +1131,7 @@ static long dash_dev_ioctl(struct file *filp, unsigned int cmd, notify_check_usb_suspend(true, true); oneplus_notify_dash_charger_present(false); oneplus_notify_pmic_check_charger_present(); - __pm_relax(&di->fastchg_wake_lock); + __pm_relax(di->fastchg_wake_lock); } break; case DASH_NOTIFY_ALLOW_READING_IIC: @@ -1190,7 +1190,7 @@ static long dash_dev_ioctl(struct file *filp, unsigned int cmd, di->fast_chg_ing = false; notify_check_usb_suspend(true, false); oneplus_notify_pmic_check_charger_present(); - __pm_relax(&di->fastchg_wake_lock); + __pm_relax(di->fastchg_wake_lock); } else if (arg == DASH_NOTIFY_NORMAL_TEMP_FULL + 3) { op_switch_normal_set(); } @@ -1209,7 +1209,7 @@ static long dash_dev_ioctl(struct file *filp, unsigned int cmd, notify_check_usb_suspend(true, false); oneplus_notify_pmic_check_charger_present(); oneplus_notify_dash_charger_present(false); - __pm_relax(&di->fastchg_wake_lock); + __pm_relax(di->fastchg_wake_lock); } break; case DASH_NOTIFY_ADAPTER_FW_UPDATE: @@ -1223,7 +1223,7 @@ static long dash_dev_ioctl(struct file *filp, unsigned int cmd, di->fast_chg_started = false; oneplus_notify_dash_charger_present(true); dash_write(di, ALLOW_DATA); - __pm_stay_awake(&di->fastchg_wake_lock); + __pm_stay_awake(di->fastchg_wake_lock); dash_adapter_update(di); } break; @@ -1235,7 +1235,7 @@ static long dash_dev_ioctl(struct file *filp, unsigned int cmd, /* data err */ bq27541_data->set_allow_reading(true); di->fast_chg_started = false; - __pm_relax(&di->fastchg_wake_lock); + __pm_relax(di->fastchg_wake_lock); di->fast_chg_allow = false; di->fast_switch_to_normal = false; di->fast_normal_to_warm = false; @@ -1254,7 +1254,7 @@ static long dash_dev_ioctl(struct file *filp, unsigned int cmd, 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); + __pm_relax(di->fastchg_wake_lock); notify_check_usb_suspend(true, true); oneplus_notify_pmic_check_charger_present(); } @@ -1563,9 +1563,8 @@ static int dash_probe(struct i2c_client *client, const struct i2c_device_id *id) mutex_init(&di->read_mutex); init_waitqueue_head(&di->read_wq); - wakeup_source_init(&di->fastchg_wake_lock, "fastcg_wake_lock"); - wakeup_source_init(&di->fastchg_update_fireware_lock, - "fastchg_fireware_lock"); + di->fastchg_wake_lock = wakeup_source_register(NULL, "fastcg_wake_lock"); + di->fastchg_update_fireware_lock = wakeup_source_register(NULL, "fastchg_fireware_lock"); INIT_WORK(&di->fastcg_work, fastcg_work_func); INIT_WORK(&di->charger_present_status_work, From 63c849895675d05ee3c0c02f7f7df002daa68c10 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Sun, 25 Sep 2022 12:11:33 -0400 Subject: [PATCH 288/356] power: oneplus: Fix build on 4.19 --- drivers/power/supply/qcom/op_dash_adapter.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/power/supply/qcom/op_dash_adapter.c b/drivers/power/supply/qcom/op_dash_adapter.c index 9d7a468837c6..0e5826bfca57 100644 --- a/drivers/power/supply/qcom/op_dash_adapter.c +++ b/drivers/power/supply/qcom/op_dash_adapter.c @@ -220,6 +220,7 @@ static unsigned char dash_uart_rx_byte( static void dash_uart_irq_fiq_enable(bool enable) { +#if 0 if (enable) { preempt_enable(); local_fiq_enable(); @@ -229,6 +230,7 @@ static void dash_uart_irq_fiq_enable(bool enable) local_fiq_disable(); preempt_disable(); } +#endif } static int dash_uart_write_some_addr( From d203ef158882698fd957b821d7c7a1c2ca844634 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Sun, 25 Sep 2022 12:27:42 -0400 Subject: [PATCH 289/356] power: oneplus: Switch to __init_timer Stolen from SM8250_R_11.0 --- drivers/power/supply/qcom/oneplus_fastchg.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/power/supply/qcom/oneplus_fastchg.c b/drivers/power/supply/qcom/oneplus_fastchg.c index ba9bb90802cb..8d2d5beafd7b 100755 --- a/drivers/power/supply/qcom/oneplus_fastchg.c +++ b/drivers/power/supply/qcom/oneplus_fastchg.c @@ -882,9 +882,9 @@ static void update_fireware_version_func(struct work_struct *work) snprintf(di->manu_name, 255, "%s", "ONEPLUS"); push_component_info(FAST_CHARGE, di->fw_id, di->manu_name); } -void di_watchdog(unsigned long data) +void di_watchdog(struct timer_list *t) { - struct fastchg_device_info *di = (struct fastchg_device_info *)data; + struct fastchg_device_info *di = fastchg_di; pr_err("di_watchdog can't receive mcu data\n"); bq27541_data->set_allow_reading(true); @@ -1576,9 +1576,9 @@ static int dash_probe(struct i2c_client *client, const struct i2c_device_id *id) /*pm_qos_add_request(&big_cpu_update_freq, PM_QOS_C1_CPUFREQ_MIN, MIN_CPUFREQ);*/ - init_timer(&di->watchdog); - di->watchdog.data = (unsigned long)di; - di->watchdog.function = di_watchdog; + __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"; From e6a9367a35347a4a1c48901775da5d0e719543e5 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Sun, 9 Apr 2023 18:09:00 +0000 Subject: [PATCH 290/356] ARM64: configs: Initial enchilada defconfig Just a copy of sdm845-perf_defconfig. --- arch/arm64/configs/vendor/enchilada_defconfig | 687 ++++++++++++++++++ 1 file changed, 687 insertions(+) create mode 100644 arch/arm64/configs/vendor/enchilada_defconfig diff --git a/arch/arm64/configs/vendor/enchilada_defconfig b/arch/arm64/configs/vendor/enchilada_defconfig new file mode 100644 index 000000000000..51b3327b36bc --- /dev/null +++ b/arch/arm64/configs/vendor/enchilada_defconfig @@ -0,0 +1,687 @@ +CONFIG_LOCALVERSION="-perf" +CONFIG_AUDIT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_PREEMPT=y +CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_SCHED_WALT=y +CONFIG_TASKSTATS=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_PSI=y +CONFIG_RCU_EXPERT=y +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_RCU_NOCB_CPU=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_IKHEADERS=y +CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 +CONFIG_CGROUPS=y +CONFIG_MEMCG=y +CONFIG_MEMCG_SWAP=y +CONFIG_BLK_CGROUP=y +CONFIG_CGROUP_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_PID_NS is not set +CONFIG_SCHED_TUNE=y +CONFIG_BLK_DEV_INITRD=y +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_LZ4 is not set +# CONFIG_FHANDLE is not set +CONFIG_KALLSYMS_ALL=y +CONFIG_BPF_LSM=y +CONFIG_BPF_SYSCALL=y +CONFIG_BPF_JIT_ALWAYS_ON=y +CONFIG_USERFAULTFD=y +# CONFIG_RSEQ is not set +CONFIG_EMBEDDED=y +# CONFIG_SLUB_DEBUG is not set +# CONFIG_COMPAT_BRK is not set +CONFIG_SLAB_FREELIST_RANDOM=y +CONFIG_SLAB_FREELIST_HARDENED=y +CONFIG_PROFILING=y +# CONFIG_ZONE_DMA32 is not set +CONFIG_ARCH_QCOM=y +CONFIG_ARCH_SDM845=y +CONFIG_PCI=y +CONFIG_PCI_MSM=y +CONFIG_PCI_MSM_MSI=y +CONFIG_SCHED_MC=y +CONFIG_NR_CPUS=8 +CONFIG_SECCOMP=y +CONFIG_OKL4_GUEST=y +# CONFIG_UNMAP_KERNEL_AT_EL0 is not set +CONFIG_ARM64_SSBD=y +CONFIG_ARMV8_DEPRECATED=y +CONFIG_SWP_EMULATION=y +CONFIG_CP15_BARRIER_EMULATION=y +CONFIG_SETEND_EMULATION=y +CONFIG_ARM64_SW_TTBR0_PAN=y +# CONFIG_ARM64_VHE is not set +CONFIG_RANDOMIZE_BASE=y +CONFIG_CMDLINE="cgroup_disable=pressure" +CONFIG_CMDLINE_EXTEND=y +# CONFIG_EFI is not set +CONFIG_KRYO_PMU_WORKAROUND=y +CONFIG_BUILD_ARM64_DT_OVERLAY=y +CONFIG_COMPAT=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_ENERGY_MODEL=y +CONFIG_CPU_IDLE=y +CONFIG_ARM_CPUIDLE=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_FREQ_TIMES=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_BOOST=y +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y +CONFIG_ARM_QCOM_CPUFREQ_HW=y +CONFIG_CRYPTO_SHA1_ARM64_CE=y +CONFIG_CRYPTO_SHA2_ARM64_CE=y +CONFIG_CRYPTO_GHASH_ARM64_CE=y +CONFIG_CRYPTO_AES_ARM64_CE_CCM=y +CONFIG_CRYPTO_AES_ARM64_CE_BLK=y +CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y +CONFIG_JUMP_LABEL=y +CONFIG_PANIC_ON_REFCOUNT_ERROR=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_BLK_INLINE_ENCRYPTION=y +CONFIG_BLK_INLINE_ENCRYPTION_FALLBACK=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_CFQ_GROUP_IOSCHED=y +CONFIG_IOSCHED_BFQ=y +CONFIG_BFQ_GROUP_IOSCHED=y +CONFIG_GKI_HIDDEN_GPU_CONFIGS=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_DEFAULT_MMAP_MIN_ADDR=32768 +CONFIG_CMA=y +CONFIG_ZSMALLOC=y +CONFIG_BALANCE_ANON_FILE_RECLAIM=y +CONFIG_HAVE_USERSPACE_LOW_MEMORY_KILLER=y +CONFIG_MEMFD_ASHMEM_SHIM=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=y +CONFIG_XFRM_INTERFACE=y +CONFIG_XFRM_MIGRATE=y +CONFIG_XFRM_STATISTICS=y +CONFIG_NET_KEY=y +CONFIG_XDP_SOCKETS=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_NET_IPGRE_DEMUX=y +CONFIG_SYN_COOKIES=y +CONFIG_NET_IPVTI=y +CONFIG_INET_AH=y +CONFIG_INET_ESP=y +CONFIG_INET_IPCOMP=y +CONFIG_INET_UDP_DIAG=y +CONFIG_INET_DIAG_DESTROY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_VTI=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_SUBTREES=y +CONFIG_NETFILTER=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_DSCP=y +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_NOTRACK=y +CONFIG_NETFILTER_XT_TARGET_TEE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_BPF=y +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_DSCP=y +CONFIG_NETFILTER_XT_MATCH_ESP=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +# CONFIG_NETFILTER_XT_MATCH_L2TP is not set +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y +CONFIG_NETFILTER_XT_MATCH_OWNER=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_RPFILTER=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_NAT=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_MATCH_RPFILTER=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +CONFIG_BRIDGE_NF_EBTABLES=y +CONFIG_BRIDGE_EBT_BROUTE=y +CONFIG_IP_SCTP=y +CONFIG_L2TP=y +CONFIG_L2TP_V3=y +CONFIG_L2TP_IP=y +CONFIG_L2TP_ETH=y +CONFIG_BRIDGE=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_PRIO=y +CONFIG_NET_SCH_MULTIQ=y +CONFIG_NET_SCH_TBF=y +CONFIG_NET_SCH_NETEM=y +CONFIG_NET_SCH_INGRESS=y +CONFIG_NET_CLS_FW=y +CONFIG_NET_CLS_U32=y +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_FLOW=y +CONFIG_NET_CLS_BPF=y +CONFIG_NET_CLS_MATCHALL=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_CMP=y +CONFIG_NET_EMATCH_NBYTE=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_EMATCH_META=y +CONFIG_NET_EMATCH_TEXT=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_POLICE=y +CONFIG_NET_ACT_GACT=y +CONFIG_NET_ACT_MIRRED=y +CONFIG_NET_ACT_SKBEDIT=y +CONFIG_NET_ACT_BPF=y +CONFIG_QRTR=y +CONFIG_QRTR_SMD=y +CONFIG_BPF_JIT=y +CONFIG_SOCKEV_NLMCAST=y +CONFIG_BT=y +CONFIG_MSM_BT_POWER=y +CONFIG_BTFM_SLIM_WCN3990=y +CONFIG_CFG80211=y +CONFIG_CFG80211_INTERNAL_REGDB=y +CONFIG_RFKILL=y +CONFIG_NFC_NQ=y +CONFIG_FW_LOADER_USER_HELPER=y +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +# CONFIG_FW_CACHE is not set +CONFIG_REGMAP_WCD_IRQ=y +CONFIG_DMA_CMA=y +CONFIG_ZRAM=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_LOOP_MIN_COUNT=16 +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_HDCP_QSEECOM=y +CONFIG_QSEECOM=y +CONFIG_UID_SYS_STATS=y +CONFIG_QPNP_MISC=y +CONFIG_OKL4_USER_VIRQ=y +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_SG=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_UFSHCD=y +CONFIG_SCSI_UFSHCD_PLATFORM=y +CONFIG_SCSI_UFS_QCOM=y +CONFIG_SCSI_UFS_CRYPTO=y +CONFIG_SCSI_UFS_CRYPTO_QTI=y +CONFIG_MD=y +CONFIG_BLK_DEV_DM=y +CONFIG_DM_CRYPT=y +CONFIG_DM_DEFAULT_KEY=y +CONFIG_DM_SNAPSHOT=y +CONFIG_DM_UEVENT=y +CONFIG_DM_VERITY=y +CONFIG_DM_VERITY_FEC=y +CONFIG_DM_BOW=y +CONFIG_NETDEVICES=y +CONFIG_BONDING=y +CONFIG_DUMMY=y +CONFIG_WIREGUARD=y +CONFIG_TUN=y +CONFIG_VETH=y +CONFIG_SKY2=y +CONFIG_RMNET=y +CONFIG_RMNET_DATA=y +CONFIG_RMNET_DATA_FC=y +CONFIG_SMSC911X=y +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_MPPE=y +CONFIG_PPTP=y +CONFIG_PPPOL2TP=y +CONFIG_USB_RTL8150=y +CONFIG_USB_RTL8152=y +CONFIG_USB_LAN78XX=y +CONFIG_USB_USBNET=y +CONFIG_WCNSS_MEM_PRE_ALLOC=y +CONFIG_CLD_LL_CORE=y +CONFIG_CNSS_GENL=y +CONFIG_INPUT_EVDEV=y +CONFIG_KEYBOARD_GPIO=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_JOYSTICK=y +CONFIG_JOYSTICK_XPAD=y +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +CONFIG_INPUT_TABLET=y +CONFIG_TABLET_USB_ACECAD=y +CONFIG_TABLET_USB_AIPTEK=y +CONFIG_TABLET_USB_GTCO=y +CONFIG_TABLET_USB_HANWANG=y +CONFIG_TABLET_USB_KBTAB=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_FTS=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_QPNP_POWER_ON=y +CONFIG_INPUT_QTI_HAPTICS=y +CONFIG_INPUT_UINPUT=y +# CONFIG_SERIO_SERPORT is not set +# CONFIG_VT is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_DEVMEM is not set +CONFIG_SERIAL_MSM_GENI=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_MSM_LEGACY=y +# CONFIG_DEVPORT is not set +CONFIG_DIAG_CHAR=y +CONFIG_MSM_ADSPRPC=y +CONFIG_OKL4_PIPE=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_QCOM_GENI=y +CONFIG_SPI=y +CONFIG_SPI_QCOM_GENI=y +CONFIG_SPI_SPIDEV=y +CONFIG_SPMI=y +CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y +CONFIG_PINCTRL_QCOM_SPMI_PMIC=y +CONFIG_PINCTRL_SDM845=y +CONFIG_GPIO_SYSFS=y +CONFIG_POWER_RESET_QCOM=y +CONFIG_POWER_RESET_XGENE=y +CONFIG_POWER_RESET_SYSCON=y +CONFIG_QPNP_SMB2=y +CONFIG_SMB1355_SLAVE_CHARGER=y +CONFIG_QPNP_QNOVO=y +CONFIG_QPNP_FG_GEN3=y +CONFIG_THERMAL=y +CONFIG_THERMAL_WRITABLE_TRIPS=y +CONFIG_THERMAL_GOV_USER_SPACE=y +CONFIG_THERMAL_GOV_LOW_LIMITS=y +CONFIG_CPU_THERMAL=y +CONFIG_DEVFREQ_THERMAL=y +CONFIG_QCOM_SPMI_TEMP_ALARM=y +CONFIG_THERMAL_TSENS=y +CONFIG_QTI_ADC_TM=y +CONFIG_QTI_VIRTUAL_SENSOR=y +CONFIG_QTI_QMI_COOLING_DEVICE=y +CONFIG_QTI_THERMAL_LIMITS_DCVS=y +CONFIG_QTI_AOP_REG_COOLING_DEVICE=y +CONFIG_REGULATOR_COOLING_DEVICE=y +CONFIG_MSM_BCL_PERIPHERAL_CTL=y +CONFIG_QTI_CPU_ISOLATE_COOLING_DEVICE=y +CONFIG_MFD_I2C_PMIC=y +CONFIG_MFD_SPMI_PMIC=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_PROXY_CONSUMER=y +CONFIG_REGULATOR_QPNP_LABIBB=y +CONFIG_REGULATOR_REFGEN=y +CONFIG_REGULATOR_RPMH=y +CONFIG_REGULATOR_STUB=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y +CONFIG_MEDIA_RADIO_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +CONFIG_VIDEO_ADV_DEBUG=y +CONFIG_VIDEO_FIXED_MINOR_RANGES=y +CONFIG_MEDIA_USB_SUPPORT=y +CONFIG_USB_VIDEO_CLASS=y +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_MSM_VIDC_LEGACY_V4L2=y +CONFIG_VIDEO_V4L2_VIDEOBUF2_CORE=y +CONFIG_DRM=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +# CONFIG_LCD_CLASS_DEVICE is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_BACKLIGHT_QCOM_SPMI_WLED=y +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_USB_AUDIO=y +CONFIG_SND_USB_AUDIO_QMI=y +CONFIG_SND_SOC=y +CONFIG_UHID=y +CONFIG_HID_APPLE=y +CONFIG_HID_DRAGONRISE=y +CONFIG_DRAGONRISE_FF=y +CONFIG_HID_ELECOM=y +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MULTITOUCH=y +CONFIG_HID_NINTENDO=y +CONFIG_HID_PANTHERLORD=y +CONFIG_PANTHERLORD_FF=y +CONFIG_HID_PLANTRONICS=y +CONFIG_HID_PLAYSTATION=y +CONFIG_PLAYSTATION_FF=y +CONFIG_HID_SONY=y +CONFIG_SONY_FF=y +CONFIG_HID_STEAM=y +CONFIG_HID_GREENASIA=y +CONFIG_GREENASIA_FF=y +CONFIG_HID_WACOM=y +CONFIG_HID_WIIMOTE=y +CONFIG_USB_HIDDEV=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_ACM=y +CONFIG_USB_STORAGE=y +CONFIG_USB_DWC3=y +CONFIG_USB_DWC3_MSM=y +CONFIG_USB_ISP1760=y +CONFIG_USB_ISP1760_HOST_ROLE=y +CONFIG_USB_SERIAL=y +CONFIG_USB_SERIAL_CP210X=y +CONFIG_USB_SERIAL_FTDI_SIO=y +CONFIG_USB_EHSET_TEST_FIXTURE=y +CONFIG_USB_LINK_LAYER_TEST=y +CONFIG_NOP_USB_XCEIV=y +CONFIG_USB_MSM_SSPHY_QMP=y +CONFIG_MSM_QUSB_PHY=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_VBUS_DRAW=900 +CONFIG_USB_CONFIGFS=y +CONFIG_USB_CONFIGFS_UEVENT=y +CONFIG_USB_CONFIGFS_NCM=y +CONFIG_USB_CONFIGFS_MASS_STORAGE=y +CONFIG_USB_CONFIGFS_F_FS=y +CONFIG_USB_CONFIGFS_F_ACC=y +CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y +CONFIG_USB_CONFIGFS_F_UAC1=y +CONFIG_USB_CONFIGFS_F_UAC2=y +CONFIG_USB_CONFIGFS_F_MIDI=y +CONFIG_USB_CONFIGFS_F_HID=y +CONFIG_USB_CONFIGFS_F_UVC=y +CONFIG_USB_CONFIGFS_F_DIAG=y +CONFIG_USB_CONFIGFS_F_CDEV=y +CONFIG_USB_CONFIGFS_F_CCID=y +CONFIG_USB_CONFIGFS_F_QDSS=y +CONFIG_USB_CONFIGFS_F_GSI=y +CONFIG_USB_CONFIGFS_F_MTP=y +CONFIG_USB_CONFIGFS_F_PTP=y +CONFIG_TYPEC=y +CONFIG_USB_PD_POLICY=y +CONFIG_QPNP_USB_PDPHY=y +CONFIG_MMC=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_MSM=y +CONFIG_MMC_CQHCI_CRYPTO=y +CONFIG_MMC_CQHCI_CRYPTO_QTI=y +CONFIG_LEDS_QTI_TRI_LED=y +CONFIG_LEDS_QPNP_FLASH_V2=y +CONFIG_LEDS_TRIGGER_TIMER=y +CONFIG_EDAC=y +CONFIG_EDAC_KRYO_ARM64=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_PM8XXX=y +CONFIG_DMADEVICES=y +CONFIG_QCOM_GPI_DMA=y +CONFIG_UIO=y +CONFIG_UIO_MSM_SHAREDMEM=y +CONFIG_STAGING=y +CONFIG_ASHMEM=y +CONFIG_ION=y +CONFIG_ION_POOL_AUTO_REFILL=y +CONFIG_ION_LEGACY=y +CONFIG_QPNP_COINCELL=y +CONFIG_QPNP_REVID=y +CONFIG_SPS=y +CONFIG_SPS_SUPPORT_NDP_BAM=y +CONFIG_IPA3=y +CONFIG_IPA_WDI_UNIFIED_API=y +CONFIG_RMNET_IPA3=y +CONFIG_RNDIS_IPA=y +CONFIG_USB_BAM=y +CONFIG_QCOM_GENI_SE=y +CONFIG_QCOM_CLK_RPMH=y +CONFIG_SPMI_PMIC_CLKDIV=y +CONFIG_MSM_CLK_AOP_QMP=y +CONFIG_MSM_GCC_SDM845=y +CONFIG_MSM_VIDEOCC_SDM845=y +CONFIG_MSM_DISPCC_SDM845=y +CONFIG_MSM_CAMCC_SDM845=y +CONFIG_MSM_GPUCC_SDM845=y +CONFIG_HWSPINLOCK=y +CONFIG_HWSPINLOCK_QCOM=y +CONFIG_MAILBOX=y +CONFIG_QCOM_APCS_IPC=y +CONFIG_MSM_QMP=y +CONFIG_IOMMU_IO_PGTABLE_FAST=y +CONFIG_ARM_SMMU=y +CONFIG_QCOM_LAZY_MAPPING=y +CONFIG_RPMSG_CHAR=y +CONFIG_RPMSG_QCOM_GLINK_SMEM=y +CONFIG_RPMSG_QCOM_GLINK_SPSS=y +CONFIG_RPMSG_QCOM_GLINK_SPI=y +CONFIG_QCOM_COMMAND_DB=y +CONFIG_QCOM_RUN_QUEUE_STATS=y +CONFIG_QCOM_LLCC=y +CONFIG_QCOM_SDM845_LLCC=y +CONFIG_QCOM_MDT_LOADER=y +CONFIG_QCOM_QMI_HELPERS=y +CONFIG_QCOM_QMI_RMNET=y +CONFIG_QCOM_QMI_DFC=y +CONFIG_QCOM_QMI_POWER_COLLAPSE=y +CONFIG_QCOM_RPMH=y +CONFIG_QCOM_SMEM=y +CONFIG_QCOM_EARLY_RANDOM=y +CONFIG_QCOM_MEMORY_DUMP_V2=y +CONFIG_QCOM_SMP2P=y +CONFIG_MSM_PIL_MSS_QDSP6V5=y +CONFIG_SETUP_SSR_NOTIF_TIMEOUTS=y +CONFIG_SSR_SYSMON_NOTIF_TIMEOUT=20000 +CONFIG_SSR_SUBSYS_NOTIF_TIMEOUT=20000 +CONFIG_PANIC_ON_SSR_NOTIF_TIMEOUT=y +CONFIG_QCOM_SECURE_BUFFER=y +CONFIG_MSM_SERVICE_LOCATOR=y +CONFIG_MSM_SERVICE_NOTIFIER=y +CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_PIL=y +CONFIG_MSM_SYSMON_QMI_COMM=y +CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_MSM_BOOT_STATS=y +CONFIG_QCOM_DCC_V2=y +CONFIG_QCOM_EUD=y +CONFIG_QCOM_FSA4480_I2C=y +CONFIG_QCOM_WATCHDOG_V2=y +CONFIG_QCOM_INITIAL_LOGBUF=y +CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y +CONFIG_QCOM_BUS_SCALING=y +CONFIG_QCOM_BUS_CONFIG_RPMH=y +CONFIG_MSM_SPCOM_LEGACY=y +CONFIG_MSM_SPSS_UTILS=y +CONFIG_QSEE_IPC_IRQ_BRIDGE=y +CONFIG_QCOM_GLINK=y +CONFIG_QCOM_GLINK_PKT=y +CONFIG_QCOM_SMP2P_SLEEPSTATE=y +CONFIG_MSM_CDSP_LOADER=y +CONFIG_QCOM_SMCINVOKE=y +CONFIG_MSM_EVENT_TIMER=y +CONFIG_MSM_PM=y +CONFIG_QTI_RPM_STATS_LOG=y +CONFIG_QTEE_SHM_BRIDGE=y +CONFIG_MEM_SHARE_QMI_SERVICE=y +CONFIG_MSM_PERFORMANCE=y +CONFIG_QCOM_CDSP_RM=y +CONFIG_QTI_CRYPTO_COMMON=y +CONFIG_QTI_CRYPTO_TZ=y +CONFIG_ICNSS=y +CONFIG_ICNSS_QMI=y +CONFIG_DEVFREQ_GOV_PASSIVE=y +CONFIG_QCOM_BIMC_BWMON=y +CONFIG_ARM_MEMLAT_MON=y +CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y +CONFIG_DEVFREQ_GOV_QCOM_CACHE_HWMON=y +CONFIG_DEVFREQ_GOV_MEMLAT=y +CONFIG_DEVFREQ_GOV_CDSPL3=y +CONFIG_ARM_QCOM_DEVFREQ_FW=y +CONFIG_DEVFREQ_SIMPLE_DEV=y +CONFIG_QCOM_DEVFREQ_DEVBW=y +CONFIG_EXTCON_USB_GPIO=y +CONFIG_IIO=y +CONFIG_QCOM_SPMI_ADC5=y +CONFIG_QCOM_RRADC=y +CONFIG_PWM=y +CONFIG_PWM_QTI_LPG=y +CONFIG_ARM_GIC_V3_ACL=y +CONFIG_QCOM_PDC=y +CONFIG_RAS=y +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_ANDROID_BINDERFS=y +CONFIG_ANDROID_VENDOR_HOOKS=y +# CONFIG_NVMEM_SYSFS is not set +CONFIG_QCOM_QFPROM=y +CONFIG_NVMEM_SPMI_SDAM=y +CONFIG_SLIMBUS_MSM_NGD=y +CONFIG_ESOC=y +CONFIG_ESOC_DEV=y +CONFIG_ESOC_CLIENT=y +CONFIG_ESOC_MDM_4x=y +CONFIG_ESOC_MDM_DRV=y +CONFIG_SENSORS_SSC=y +CONFIG_QCOM_KGSL=y +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_F2FS_FS=y +CONFIG_F2FS_FS_SECURITY=y +CONFIG_F2FS_UNFAIR_RWSEM=y +CONFIG_FS_ENCRYPTION=y +CONFIG_FS_ENCRYPTION_INLINE_CRYPT=y +CONFIG_FS_VERITY=y +CONFIG_FS_VERITY_BUILTIN_SIGNATURES=y +CONFIG_QUOTA=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +CONFIG_QFMT_V2=y +CONFIG_FUSE_FS=y +CONFIG_OVERLAY_FS=y +CONFIG_INCREMENTAL_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_SDCARD_FS=y +CONFIG_EROFS_FS=y +CONFIG_EROFS_FS_PCPU_KTHREAD=y +CONFIG_EROFS_FS_PCPU_KTHREAD_HIPRI=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +CONFIG_UNICODE=y +CONFIG_SECURITY=y +CONFIG_SECURITY_NETWORK=y +CONFIG_HARDENED_USERCOPY=y +CONFIG_STATIC_USERMODEHELPER=y +CONFIG_STATIC_USERMODEHELPER_PATH="" +CONFIG_SECURITY_SELINUX=y +CONFIG_INIT_ON_ALLOC_DEFAULT_ON=y +CONFIG_CRYPTO_CCM=y +CONFIG_CRYPTO_GCM=y +CONFIG_CRYPTO_CHACHA20POLY1305=y +CONFIG_CRYPTO_XCBC=y +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_LZ4=y +CONFIG_CRYPTO_ANSI_CPRNG=y +CONFIG_CRYPTO_DRBG_HASH=y +CONFIG_CRYPTO_DRBG_CTR=y +CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y +CONFIG_CRYPTO_DEV_QCRYPTO=y +CONFIG_CRYPTO_DEV_QCEDEV=y +CONFIG_CRYPTO_DEV_QCOM_ICE=y +CONFIG_PRINTK_TIME=y +CONFIG_DEBUG_INFO=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_PANIC_TIMEOUT=-1 +CONFIG_SCHEDSTATS=y +CONFIG_SCHED_STACK_END_CHECK=y +# CONFIG_DEBUG_PREEMPT is not set +CONFIG_IPC_LOGGING=y +CONFIG_BUG_ON_DATA_CORRUPTION=y +CONFIG_CC_WERROR=y +CONFIG_DEBUG_ALIGN_RODATA=y From 188f5c247449b8e73d8b26d40116825c128355d5 Mon Sep 17 00:00:00 2001 From: Davide Garberi Date: Sat, 29 Feb 2020 11:15:26 +0100 Subject: [PATCH 291/356] ARM64: configs: enchilada: Enable CONFIG_BUILD_ARM64_DT_OVERLAY Change-Id: I25959ef7eec025a5506cb6de863c09555a1dd4ce --- arch/arm64/configs/vendor/enchilada_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/vendor/enchilada_defconfig b/arch/arm64/configs/vendor/enchilada_defconfig index 51b3327b36bc..1df4b39750ae 100644 --- a/arch/arm64/configs/vendor/enchilada_defconfig +++ b/arch/arm64/configs/vendor/enchilada_defconfig @@ -68,6 +68,7 @@ CONFIG_RANDOMIZE_BASE=y CONFIG_CMDLINE="cgroup_disable=pressure" CONFIG_CMDLINE_EXTEND=y # CONFIG_EFI is not set +CONFIG_BUILD_ARM64_DT_OVERLAY=y CONFIG_KRYO_PMU_WORKAROUND=y CONFIG_BUILD_ARM64_DT_OVERLAY=y CONFIG_COMPAT=y From 7d8b5699b0bec2789afbdfcad00f51d49f4878db Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Thu, 6 Apr 2023 18:25:22 +0000 Subject: [PATCH 292/356] ARM64: enchilada: Enable appended DTB --- arch/arm64/configs/vendor/enchilada_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/vendor/enchilada_defconfig b/arch/arm64/configs/vendor/enchilada_defconfig index 1df4b39750ae..9236da48112b 100644 --- a/arch/arm64/configs/vendor/enchilada_defconfig +++ b/arch/arm64/configs/vendor/enchilada_defconfig @@ -68,6 +68,7 @@ CONFIG_RANDOMIZE_BASE=y CONFIG_CMDLINE="cgroup_disable=pressure" CONFIG_CMDLINE_EXTEND=y # CONFIG_EFI is not set +CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y CONFIG_BUILD_ARM64_DT_OVERLAY=y CONFIG_KRYO_PMU_WORKAROUND=y CONFIG_BUILD_ARM64_DT_OVERLAY=y From 0b611b6ea1c10afca2ee088f69789eb38f022e26 Mon Sep 17 00:00:00 2001 From: Luca Stefani Date: Sat, 1 Aug 2020 08:52:53 +0200 Subject: [PATCH 293/356] ARM64: enchilada: Enable QCACLD Change-Id: I22b3d3adf31c95a91275d0c795403b4097201430 --- arch/arm64/configs/vendor/enchilada_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/vendor/enchilada_defconfig b/arch/arm64/configs/vendor/enchilada_defconfig index 9236da48112b..4c5247639185 100644 --- a/arch/arm64/configs/vendor/enchilada_defconfig +++ b/arch/arm64/configs/vendor/enchilada_defconfig @@ -514,6 +514,7 @@ CONFIG_ION_POOL_AUTO_REFILL=y CONFIG_ION_LEGACY=y CONFIG_QPNP_COINCELL=y CONFIG_QPNP_REVID=y +CONFIG_QCA_CLD_WLAN=y CONFIG_SPS=y CONFIG_SPS_SUPPORT_NDP_BAM=y CONFIG_IPA3=y From 2833efdf373e2413e6202d83d70b795bfcbf68da Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Sun, 2 Apr 2023 13:26:03 +0000 Subject: [PATCH 294/356] oneplus: Disable debug options by default --- drivers/oneplus/drivers/Kconfig | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/oneplus/drivers/Kconfig b/drivers/oneplus/drivers/Kconfig index 71ebd08e8bde..26ad89c2ad33 100644 --- a/drivers/oneplus/drivers/Kconfig +++ b/drivers/oneplus/drivers/Kconfig @@ -1,19 +1,19 @@ config OEM_DEBUG_SUPPORT - default y + default n bool config OEM_SYSRQ_X - default y + default n depends on OEM_DEBUG_SUPPORT bool "echo x > /proc/sysrq-trigger to get init process stacktrace" config OEM_TRACE_SUPPORT - default y + default n depends on OEM_DEBUG_SUPPORT bool "OEM debug function, enable it will register the device, which under /dev/otracer." config OEM_FORCE_DUMP - default y + default n bool "OEM force dump function, it will enable goto the force dump" config PARAM_READ_WRITE From 2777cdcfb774a14726c7a2e3aadfe9fb842fa781 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Sun, 2 Apr 2023 14:07:49 +0000 Subject: [PATCH 295/356] project_info: Update for 4.19 --- drivers/soc/qcom/project_info.c | 38 ++++++++++++++++----------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/drivers/soc/qcom/project_info.c b/drivers/soc/qcom/project_info.c index a57502196aae..43cd6394ab9a 100644 --- a/drivers/soc/qcom/project_info.c +++ b/drivers/soc/qcom/project_info.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include @@ -65,15 +65,14 @@ void save_dump_reason_to_smem(char *info, char *function_name) { int strl = 0, strl1 = 0; static int flag = 0; + size_t size; /* Make sure save_dump_reason_to_smem() is not called infinite times by panic() during DDR bit flip crash etc */ if (flag > 1) return; - dp_info = smem_alloc(SMEM_DUMP_INFO, - sizeof(struct dump_info), 0, - SMEM_ANY_HOST_FLAG); + dp_info = qcom_smem_get(QCOM_SMEM_HOST_ANY, SMEM_DUMP_INFO, &size); if (IS_ERR_OR_NULL(dp_info)) pr_err("%s: get dp_info failure\n", __func__); @@ -543,16 +542,16 @@ struct a_borad_version a_borad_version_string_arry_gpio[]={ uint32 get_hw_version(void) { + size_t size; + if (strnstr(saved_command_line, "androidboot.platform_name=", strlen(saved_command_line))) - project_info_desc_v2 = smem_find(SMEM_PROJECT_INFO, - sizeof(struct project_info_v2), - 0, - SMEM_ANY_HOST_FLAG); + project_info_desc_v2 = qcom_smem_get(QCOM_SMEM_HOST_ANY, + SMEM_PROJECT_INFO, + &size); else - project_info_desc_v1 = smem_find(SMEM_PROJECT_INFO, - sizeof(struct project_info), - 0, - SMEM_ANY_HOST_FLAG); + project_info_desc_v1 = qcom_smem_get(QCOM_SMEM_HOST_ANY, + SMEM_PROJECT_INFO, + &size); if (IS_ERR_OR_NULL(project_info_desc_v1) && IS_ERR_OR_NULL(project_info_desc_v2)) pr_err("%s: get project_info failure\n", __func__); @@ -568,20 +567,19 @@ int __init init_project_info(void) { static bool project_info_init_done; int ddr_size = 0; + size_t size; if (project_info_init_done) return 0; if (strnstr(saved_command_line, "androidboot.platform_name=", strlen(saved_command_line))) - project_info_desc_v2 = smem_find(SMEM_PROJECT_INFO, - sizeof(struct project_info_v2), - 0, - SMEM_ANY_HOST_FLAG); + project_info_desc_v2 = qcom_smem_get(QCOM_SMEM_HOST_ANY, + SMEM_PROJECT_INFO, + &size); else - project_info_desc_v1 = smem_find(SMEM_PROJECT_INFO, - sizeof(struct project_info), - 0, - SMEM_ANY_HOST_FLAG); + project_info_desc_v1 = qcom_smem_get(QCOM_SMEM_HOST_ANY, + SMEM_PROJECT_INFO, + &size); if (IS_ERR_OR_NULL(project_info_desc_v1) && IS_ERR_OR_NULL(project_info_desc_v2)) { pr_err("%s: get project_info failure\n", __func__); From 9a8005d9d329780c882bc93eb177b61a58791126 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Sun, 2 Apr 2023 14:41:02 +0000 Subject: [PATCH 296/356] ARM64: configs: enchilada: Disable CLO touchscreen drivers --- arch/arm64/configs/vendor/enchilada_defconfig | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/arm64/configs/vendor/enchilada_defconfig b/arch/arm64/configs/vendor/enchilada_defconfig index 4c5247639185..a8b7d13ff684 100644 --- a/arch/arm64/configs/vendor/enchilada_defconfig +++ b/arch/arm64/configs/vendor/enchilada_defconfig @@ -344,7 +344,9 @@ CONFIG_TABLET_USB_GTCO=y CONFIG_TABLET_USB_HANWANG=y CONFIG_TABLET_USB_KBTAB=y CONFIG_INPUT_TOUCHSCREEN=y -CONFIG_TOUCHSCREEN_FTS=y +# CONFIG_TOUCHSCREEN_ST is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_DSX is not set +# CONFIG_TOUCHSCREEN_SYNAPTICS_TCM is not set CONFIG_INPUT_MISC=y CONFIG_INPUT_QPNP_POWER_ON=y CONFIG_INPUT_QTI_HAPTICS=y From 98b4b254d451de8b257bce2ac6682cb2fb87c260 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Sun, 2 Apr 2023 14:07:25 +0000 Subject: [PATCH 297/356] op_rf_cable_monitor: Update for 4.19 --- drivers/soc/qcom/op_rf_cable_monitor.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/soc/qcom/op_rf_cable_monitor.c b/drivers/soc/qcom/op_rf_cable_monitor.c index 32e8a96b4afc..3715c395ee70 100644 --- a/drivers/soc/qcom/op_rf_cable_monitor.c +++ b/drivers/soc/qcom/op_rf_cable_monitor.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include @@ -35,7 +35,7 @@ struct cable_data { struct delayed_work work; struct workqueue_struct *wqueue; struct device *dev; - struct wakeup_source wl; + struct wakeup_source *wl; atomic_t running; int rf_v3; int rf_v3_pre; @@ -52,9 +52,11 @@ static char *cmdline_find_option(char *str) int modify_rf_cable_smem_info(uint32 status) { - project_info_desc = smem_find(SMEM_PROJECT_INFO, - sizeof(struct project_info), 0, - SMEM_ANY_HOST_FLAG); + 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__); @@ -99,7 +101,7 @@ static void rf_cable_work(struct work_struct *work) irqreturn_t cable_interrupt(int irq, void *_dev) { - __pm_wakeup_event(&_cdata->wl, + __pm_wakeup_event(_cdata->wl, msecs_to_jiffies(CABLE_WAKELOCK_HOLD_TIME)); queue_delayed_work(_cdata->wqueue, &_cdata->work, msecs_to_jiffies(1)); @@ -289,8 +291,7 @@ static int op_rf_cable_probe(struct platform_device *pdev) pr_err("requested irq %d\n", _cdata->irq_1); enable_irq_wake(_cdata->irq_1); - wakeup_source_init(&_cdata->wl, - "rf_cable_wake_lock"); + _cdata->wl = wakeup_source_register(NULL, "rf_cable_wake_lock"); spin_lock_init(&_cdata->lock); atomic_set(&_cdata->running, gpio_get_value(_cdata->cable_gpio_0) || From 2044e78faf3693c2f666d519c445e7b35d613448 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Sun, 2 Apr 2023 15:09:13 +0000 Subject: [PATCH 298/356] oneplus: Add separate Kconfig entry for boot mode driver --- drivers/oneplus/drivers/Kconfig | 6 ++++++ drivers/oneplus/drivers/boot_mode/Makefile | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/oneplus/drivers/Kconfig b/drivers/oneplus/drivers/Kconfig index 26ad89c2ad33..c702953620fc 100644 --- a/drivers/oneplus/drivers/Kconfig +++ b/drivers/oneplus/drivers/Kconfig @@ -29,4 +29,10 @@ config DEBUG_PARAM_DUMP help if you want to dump contents of param partition for debug purpose +config OEM_BOOT_MODE + bool "OEM boot mode driver" + default n + help + Say y here to enable the boot mode driver + source "drivers/oneplus/drivers/input/fingerprint/Kconfig" diff --git a/drivers/oneplus/drivers/boot_mode/Makefile b/drivers/oneplus/drivers/boot_mode/Makefile index d4708a023dbe..1550d0bf4e59 100644 --- a/drivers/oneplus/drivers/boot_mode/Makefile +++ b/drivers/oneplus/drivers/boot_mode/Makefile @@ -1 +1 @@ -obj-$(CONFIG_OEM_DEBUG_SUPPORT) += boot_mode.o +obj-$(CONFIG_OEM_BOOT_MODE) += boot_mode.o From 9a0f17d7820aaf71d07d57f89c9d251645c5d0b3 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Sun, 2 Apr 2023 15:00:23 +0000 Subject: [PATCH 299/356] ARM64: configs: enchilada: Enable oneplus charger drivers --- arch/arm64/configs/vendor/enchilada_defconfig | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/arm64/configs/vendor/enchilada_defconfig b/arch/arm64/configs/vendor/enchilada_defconfig index a8b7d13ff684..d72f27f4a1b5 100644 --- a/arch/arm64/configs/vendor/enchilada_defconfig +++ b/arch/arm64/configs/vendor/enchilada_defconfig @@ -376,9 +376,10 @@ CONFIG_POWER_RESET_QCOM=y CONFIG_POWER_RESET_XGENE=y CONFIG_POWER_RESET_SYSCON=y CONFIG_QPNP_SMB2=y -CONFIG_SMB1355_SLAVE_CHARGER=y CONFIG_QPNP_QNOVO=y CONFIG_QPNP_FG_GEN3=y +CONFIG_FG_BQ27541=y +CONFIG_ONEPLUS_FASTCHG=y CONFIG_THERMAL=y CONFIG_THERMAL_WRITABLE_TRIPS=y CONFIG_THERMAL_GOV_USER_SPACE=y @@ -507,6 +508,7 @@ CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_PM8XXX=y CONFIG_DMADEVICES=y CONFIG_QCOM_GPI_DMA=y +CONFIG_OEM_BOOT_MODE=y CONFIG_UIO=y CONFIG_UIO_MSM_SHAREDMEM=y CONFIG_STAGING=y @@ -599,6 +601,7 @@ CONFIG_QTI_CRYPTO_COMMON=y CONFIG_QTI_CRYPTO_TZ=y CONFIG_ICNSS=y CONFIG_ICNSS_QMI=y +CONFIG_RF_CABLE_DETECT=y CONFIG_DEVFREQ_GOV_PASSIVE=y CONFIG_QCOM_BIMC_BWMON=y CONFIG_ARM_MEMLAT_MON=y From 4192d460e865fb0f399cabceefbf33ff1bac6bea Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Thu, 6 Apr 2023 19:00:16 +0000 Subject: [PATCH 300/356] ARM64: dts: Remove led nodes These need to be updated for the tri-led driver on 4.19, if needed. --- arch/arm64/boot/dts/qcom/enchilada.dtsi | 39 ------------------------- arch/arm64/boot/dts/qcom/fajita.dtsi | 39 ------------------------- 2 files changed, 78 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/enchilada.dtsi b/arch/arm64/boot/dts/qcom/enchilada.dtsi index 4593fbd0dc8a..2a64ad7480f5 100644 --- a/arch/arm64/boot/dts/qcom/enchilada.dtsi +++ b/arch/arm64/boot/dts/qcom/enchilada.dtsi @@ -920,45 +920,6 @@ status = "disabled"; qcom,lra-res-cal-period = <32>; }; -&red_led { - qcom,use-blink; - qcom,duty-pcts = [00 05 0a 0f 14 1d 28 32 3c 4b 64]; - qcom,duty-ms = <20>; - qcom,start-idx = <1>; - qcom,idx-len = <11>; - qcom,lut-flags = <0x1f>; - qcom,ramp-step-ms = <100>; - qcom,pause-lo = <2000>; - qcom,pause-hi = <1000>; - /delete-property/ linux,default-trigger; -}; - -&green_led { - qcom,use-blink; - qcom,duty-pcts = [00 05 0a 0f 14 1d 28 32 3c 4b 64]; - qcom,duty-ms = <20>; - qcom,start-idx = <13>; - qcom,idx-len = <11>; - qcom,lut-flags = <0x1f>; - qcom,ramp-step-ms = <100>; - qcom,pause-lo = <2000>; - qcom,pause-hi = <1000>; - /delete-property/ linux,default-trigger; -}; - -&blue_led { - qcom,use-blink; - qcom,duty-pcts = [00 05 0a 0f 14 1d 28 32 3c 4b 64]; - qcom,duty-ms = <20>; - qcom,start-idx = <13>; - qcom,idx-len = <11>; - qcom,lut-flags = <0x1f>; - qcom,ramp-step-ms = <100>; - qcom,pause-lo = <2000>; - qcom,pause-hi = <1000>; - /delete-property/ linux,default-trigger; -}; - &sde_dsi_active { mux { pins = "gpio6", "gpio25", "gpio26"; diff --git a/arch/arm64/boot/dts/qcom/fajita.dtsi b/arch/arm64/boot/dts/qcom/fajita.dtsi index 927d14446d34..4e231ef93047 100644 --- a/arch/arm64/boot/dts/qcom/fajita.dtsi +++ b/arch/arm64/boot/dts/qcom/fajita.dtsi @@ -1117,45 +1117,6 @@ status = "disabled"; qcom,lra-res-cal-period = <32>; }; -&red_led { - qcom,use-blink; - qcom,duty-pcts = [00 05 0a 0f 14 1d 28 32 3c 4b 64]; - qcom,duty-ms = <20>; - qcom,start-idx = <1>; - qcom,idx-len = <11>; - qcom,lut-flags = <0x1f>; - qcom,ramp-step-ms = <100>; - qcom,pause-lo = <2000>; - qcom,pause-hi = <1000>; - /delete-property/ linux,default-trigger; -}; - -&green_led { - qcom,use-blink; - qcom,duty-pcts = [00 05 0a 0f 14 1d 28 32 3c 4b 64]; - qcom,duty-ms = <20>; - qcom,start-idx = <13>; - qcom,idx-len = <11>; - qcom,lut-flags = <0x1f>; - qcom,ramp-step-ms = <100>; - qcom,pause-lo = <2000>; - qcom,pause-hi = <1000>; - /delete-property/ linux,default-trigger; -}; - -&blue_led { - qcom,use-blink; - qcom,duty-pcts = [00 05 0a 0f 14 1d 28 32 3c 4b 64]; - qcom,duty-ms = <20>; - qcom,start-idx = <13>; - qcom,idx-len = <11>; - qcom,lut-flags = <0x1f>; - qcom,ramp-step-ms = <100>; - qcom,pause-lo = <2000>; - qcom,pause-hi = <1000>; - /delete-property/ linux,default-trigger; -}; - &sde_dsi_active { mux { pins = "gpio6", "gpio25", "gpio26"; From 5f5508639651cc5e35d8beda1a69b6b1629c7117 Mon Sep 17 00:00:00 2001 From: MrArtemSid Date: Thu, 4 Nov 2021 23:03:51 +0400 Subject: [PATCH 301/356] ARM64: dts: qcom: Update display config for 4.19 * Update panel nodes to match the string passed by the bootloader * Set panel DSI clontroller, PHY and clocks * Remove deprecated qcom,dsi-display nodes, override qcom,dsi-display-primary instead * Remove unused LAB, IBB and OLED regulators Co-authored-by: Edwin Moquete --- .../boot/dts/qcom/dsi-panel-samsung_dsc.dtsi | 4 +- .../qcom/dsi-panel-samsung_s6e3fc1_cmd.dtsi | 4 +- .../qcom/dsi-panel-samsung_s6e3fc2x01.dtsi | 4 +- .../qcom/dsi-panel-samsung_sefeg01_s_cmd.dtsi | 4 +- .../qcom/dsi-panel-samsung_sofef00_m_cmd.dtsi | 4 +- .../dsi-panel-samsung_sofef00_m_video.dtsi | 4 +- .../boot/dts/qcom/enchilada-dvt-usb30.dtsi | 2 +- arch/arm64/boot/dts/qcom/enchilada.dtsi | 122 +++--------------- arch/arm64/boot/dts/qcom/fajita.dtsi | 122 +++--------------- .../boot/dts/qcom/sdm845-sde-display.dtsi | 3 - 10 files changed, 57 insertions(+), 216 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-samsung_dsc.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-samsung_dsc.dtsi index 59ecdfb593f5..2dc8484ed814 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-samsung_dsc.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-samsung_dsc.dtsi @@ -11,13 +11,15 @@ */ &mdss_mdp { - dsi_samsung_dsc_cmd: qcom,mdss_dsi_samsung_dsc_cmd { + dsi_samsung_dsc_cmd: dsi_samsung_dsc_cmd_display { qcom,mdss-dsi-panel-name = "samsung dsc cmd mode 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,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>; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-samsung_s6e3fc1_cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-samsung_s6e3fc1_cmd.dtsi index bc47af8ad4e2..252955b54826 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-samsung_s6e3fc1_cmd.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-samsung_s6e3fc1_cmd.dtsi @@ -11,13 +11,15 @@ */ &mdss_mdp { - dsi_samsung_s6e3fc1_cmd: qcom,mdss_dsi_samsung_s6e3fc1_cmd { + dsi_samsung_s6e3fc1_cmd: dsi_samsung_s6e3fc1_cmd_display { qcom,mdss-dsi-panel-name = "samsung s6e3fc1 cmd mode dsi panel"; qcom,mdss-dsi-panel-manufacture = "SAMSUNG"; qcom,mdss-dsi-panel-version = "S6E3FC1"; qcom,mdss-dsi-backlight-version = "SAMSUNG"; qcom,mdss-dsi-backlight-manufacture = "SAMSUNG"; 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>; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-samsung_s6e3fc2x01.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-samsung_s6e3fc2x01.dtsi index 1b7da404730d..1f4e60797c3e 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-samsung_s6e3fc2x01.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-samsung_s6e3fc2x01.dtsi @@ -11,13 +11,15 @@ */ &mdss_mdp { - dsi_samsung_s6e3fc2x01_cmd: qcom,mdss_dsi_samsung_s6e3fc2x01_cmd { + dsi_samsung_s6e3fc2x01_cmd: dsi_samsung_s6e3fc2x01_cmd_display { qcom,mdss-dsi-panel-name = "samsung s6e3fc2x01 cmd mode dsi panel"; qcom,mdss-dsi-panel-manufacture = "SAMSUNG"; qcom,mdss-dsi-panel-version = "S6E3FC2X01"; qcom,mdss-dsi-backlight-version = "SAMSUNG"; qcom,mdss-dsi-backlight-manufacture = "SAMSUNG"; 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>; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-samsung_sefeg01_s_cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-samsung_sefeg01_s_cmd.dtsi index ad639e58aa63..4d0a9988a005 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-samsung_sefeg01_s_cmd.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-samsung_sefeg01_s_cmd.dtsi @@ -11,13 +11,15 @@ */ &mdss_mdp { - dsi_samsung_sofeg01_s_cmd: qcom,mdss_dsi_samsung_sofeg01_s_cmd { + dsi_samsung_sofeg01_s_cmd: dsi_samsung_sofeg01_s_cmd_display { qcom,mdss-dsi-panel-name = "samsung sofeg01_s cmd mode dsi panel"; qcom,mdss-dsi-panel-manufacture = "SAMSUNG"; qcom,mdss-dsi-panel-version = "SOFEG01_S"; qcom,mdss-dsi-backlight-version = "SAMSUNG"; qcom,mdss-dsi-backlight-manufacture = "SAMSUNG"; 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>; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-samsung_sofef00_m_cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-samsung_sofef00_m_cmd.dtsi index 38059ea1792a..d22ff8e66d95 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-samsung_sofef00_m_cmd.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-samsung_sofef00_m_cmd.dtsi @@ -11,13 +11,15 @@ */ &mdss_mdp { - dsi_samsung_sofef00_m_cmd: qcom,mdss_dsi_samsung_sofef00_m_cmd { + dsi_samsung_sofef00_m_cmd: dsi_samsung_sofef00_m_cmd_display { qcom,mdss-dsi-panel-name = "samsung sofef00_m cmd 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_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>; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-samsung_sofef00_m_video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-samsung_sofef00_m_video.dtsi index 128043c1eed7..819b967009db 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-samsung_sofef00_m_video.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-samsung_sofef00_m_video.dtsi @@ -11,7 +11,7 @@ */ &mdss_mdp { - dsi_samsung_sofef00_m_video: qcom,mdss_dsi_samsung_sofef00_m_video { + dsi_samsung_sofef00_m_video: dsi_samsung_sofef00_m_video_display { qcom,mdss-dsi-panel-name = "samsung sofef00_m video mode dsi panel"; qcom,mdss-dsi-panel-manufacture = "SAMSUNG"; @@ -19,6 +19,8 @@ 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>; diff --git a/arch/arm64/boot/dts/qcom/enchilada-dvt-usb30.dtsi b/arch/arm64/boot/dts/qcom/enchilada-dvt-usb30.dtsi index a733457224be..fc5f041454fc 100644 --- a/arch/arm64/boot/dts/qcom/enchilada-dvt-usb30.dtsi +++ b/arch/arm64/boot/dts/qcom/enchilada-dvt-usb30.dtsi @@ -33,7 +33,7 @@ }; &mdss_mdp { - connectors = <&sde_rscc &sde_wb &sde_dp>; + connectors = <&sde_rscc &sde_wb &sde_dp &sde_dsi>; }; &sde_dp_aux_active { diff --git a/arch/arm64/boot/dts/qcom/enchilada.dtsi b/arch/arm64/boot/dts/qcom/enchilada.dtsi index 2a64ad7480f5..c6571c40c6fd 100644 --- a/arch/arm64/boot/dts/qcom/enchilada.dtsi +++ b/arch/arm64/boot/dts/qcom/enchilada.dtsi @@ -149,108 +149,6 @@ reserved-memory { }; }; - dsi_samsung_s6e3fc1_cmd_display: qcom,dsi-display@17 { - compatible = "qcom,dsi-display"; - label = "dsi_samsung_s6e3fc1_cmd_display"; - qcom,display-type = "primary"; - qcom,dsi-ctrl = <&mdss_dsi0>; - qcom,dsi-phy = <&mdss_dsi_phy0>; - clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, - <&mdss_dsi0_pll PCLK_MUX_0_CLK>; - clock-names = "mux_byte_clk", "mux_pixel_clk"; - pinctrl-names = "panel_active", "panel_suspend"; - pinctrl-0 = <&sde_dsi_active &sde_te_active &esd_check_active>; - pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend &esd_check_suspend>; - qcom,dsi-panel = <&dsi_samsung_s6e3fc1_cmd>; - vddio-supply = <&pm8998_l14>; - qcom,platform-te-gpio = <&tlmm 30 0>; - }; - - dsi_samsung_sofef00_m_cmd_display: qcom,dsi-display@18 { - compatible = "qcom,dsi-display"; - label = "dsi_samsung_sofef00_m_cmd_display"; - qcom,display-type = "primary"; - qcom,dsi-ctrl = <&mdss_dsi0>; - qcom,dsi-phy = <&mdss_dsi_phy0>; - clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, - <&mdss_dsi0_pll PCLK_MUX_0_CLK>; - clock-names = "mux_byte_clk", "mux_pixel_clk"; - pinctrl-names = "panel_active", "panel_suspend"; - pinctrl-0 = <&sde_dsi_active &sde_te_active &esd_check_active>; - pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend &esd_check_suspend>; - qcom,dsi-panel = <&dsi_samsung_sofef00_m_cmd>; - vddio-supply = <&pm8998_l14>; - qcom,platform-te-gpio = <&tlmm 30 0>; - }; - - dsi_samsung_sofef00_m_video_display: qcom,dsi-display@19 { - compatible = "qcom,dsi-display"; - label = "dsi_samsung_sofef00_m_video_display"; - qcom,display-type = "primary"; - qcom,dsi-ctrl = <&mdss_dsi0>; - qcom,dsi-phy = <&mdss_dsi_phy0>; - clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, - <&mdss_dsi0_pll PCLK_MUX_0_CLK>; - clock-names = "mux_byte_clk", "mux_pixel_clk"; - pinctrl-names = "panel_active", "panel_suspend"; - pinctrl-0 = <&sde_dsi_active &sde_te_active &esd_check_active>; - pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend &esd_check_suspend>; - qcom,dsi-panel = <&dsi_samsung_sofef00_m_video>; - vddio-supply = <&pm8998_l14>; - qcom,platform-te-gpio = <&tlmm 30 0>; - }; - -dsi_samsung_sofeg01_s_cmd_display: qcom,dsi-display@20 { - compatible = "qcom,dsi-display"; - label = "dsi_samsung_sofeg01_s_cmd_display"; - qcom,display-type = "primary"; - qcom,dsi-ctrl = <&mdss_dsi0>; - qcom,dsi-phy = <&mdss_dsi_phy0>; - clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, - <&mdss_dsi0_pll PCLK_MUX_0_CLK>; - clock-names = "mux_byte_clk", "mux_pixel_clk"; - pinctrl-names = "panel_active", "panel_suspend"; - pinctrl-0 = <&sde_dsi_active &sde_te_active &esd_check_active>; - pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend &esd_check_suspend>; - qcom,dsi-panel = <&dsi_samsung_sofeg01_s_cmd>; - vddio-supply = <&pm8998_l14>; - qcom,platform-te-gpio = <&tlmm 30 0>; - }; -dsi_samsung_s6e3fc2x01_cmd_display: qcom,dsi-display@21 { - compatible = "qcom,dsi-display"; - label = "dsi_samsung_s6e3fc2x01_cmd_display"; - qcom,display-type = "primary"; - qcom,dsi-ctrl = <&mdss_dsi0>; - qcom,dsi-phy = <&mdss_dsi_phy0>; - clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, - <&mdss_dsi0_pll PCLK_MUX_0_CLK>; - clock-names = "mux_byte_clk", "mux_pixel_clk"; - pinctrl-names = "panel_active", "panel_suspend"; - pinctrl-0 = <&sde_dsi_active &sde_te_active &esd_check_active>; - pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend &esd_check_suspend>; - qcom,dsi-panel = <&dsi_samsung_s6e3fc2x01_cmd>; - vddio-supply = <&pm8998_l14>; - qcom,platform-te-gpio = <&tlmm 30 0>; - }; - -dsi_samsung_dsc_cmd_display: qcom,dsi-display@22 { - compatible = "qcom,dsi-display"; - label = "dsi_samsung_dsc_cmd_display"; - qcom,display-type = "primary"; - qcom,dsi-ctrl = <&mdss_dsi0>; - qcom,dsi-phy = <&mdss_dsi_phy0>; - clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, - <&mdss_dsi0_pll PCLK_MUX_0_CLK>; - clock-names = "mux_byte_clk", "mux_pixel_clk"; - pinctrl-names = "panel_active", "panel_suspend"; - pinctrl-0 = <&sde_dsi_active &sde_te_active &esd_check_active>; - pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend &esd_check_suspend>; - qcom,dsi-panel = <&dsi_samsung_dsc_cmd>; - vddio-supply = <&pm8998_l14>; - qcom,platform-te-gpio = <&tlmm 30 0>; - }; - - oem_serial_pinctrl { compatible = "oem,oem_serial_pinctrl"; pinctrl-names = "uart_pinctrl_active","uart_pinctrl_deactive"; @@ -407,6 +305,7 @@ status = "disabled"; &dsi_samsung_s6e3fc1_cmd { qcom,dsi-display-active; qcom,panel-supply-entries = <&dsi_panel_pwr_supply_no_labibb_2>; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; qcom,mdss-brightness-max-level = <1023>; qcom,mdss-dsi-bl-min-level = <1>; @@ -431,6 +330,7 @@ status = "disabled"; &dsi_samsung_sofef00_m_cmd { qcom,panel-supply-entries = <&dsi_panel_pwr_supply_no_labibb_2>; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; qcom,mdss-brightness-max-level = <1023>; qcom,mdss-dsi-bl-min-level = <1>; @@ -455,6 +355,7 @@ status = "disabled"; &dsi_samsung_sofef00_m_video { qcom,panel-supply-entries = <&dsi_panel_pwr_supply_no_labibb_2>; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; qcom,mdss-brightness-max-level = <1023>; qcom,mdss-dsi-bl-min-level = <1>; @@ -479,6 +380,7 @@ status = "disabled"; &dsi_samsung_sofeg01_s_cmd { qcom,panel-supply-entries = <&dsi_panel_pwr_supply_no_labibb_2>; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; qcom,mdss-brightness-max-level = <1023>; qcom,mdss-dsi-bl-min-level = <1>; @@ -503,6 +405,7 @@ status = "disabled"; &dsi_samsung_s6e3fc2x01_cmd { qcom,panel-supply-entries = <&dsi_panel_pwr_supply_no_labibb_2>; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; qcom,mdss-brightness-max-level = <1023>; qcom,mdss-dsi-bl-min-level = <1>; @@ -529,6 +432,7 @@ status = "disabled"; &dsi_samsung_dsc_cmd { qcom,panel-supply-entries = <&dsi_panel_pwr_supply_no_labibb_2>; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; qcom,mdss-brightness-max-level = <1023>; qcom,mdss-dsi-bl-min-level = <1>; @@ -554,6 +458,18 @@ status = "disabled"; }; }; +&sde_dsi { + qcom,dsi-default-panel = <&dsi_samsung_sofef00_m_cmd>; + qcom,dsi-ctrl = <&mdss_dsi0>; + qcom,dsi-phy = <&mdss_dsi_phy0>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "mux_byte_clk0", "mux_pixel_clk0"; + pinctrl-0 = <&sde_dsi_active &sde_te_active &esd_check_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend &esd_check_suspend>; + qcom,platform-te-gpio = <&tlmm 30 0>; +}; + &qupv3_se4_i2c { status = "ok"; max98927@3a { @@ -887,7 +803,7 @@ status = "disabled"; status = "disabled"; }; &mdss_mdp { - connectors = <&sde_rscc &sde_wb>; + connectors = <&sde_rscc &sde_wb &sde_dsi>; }; &sde_dp{ status = "disabled"; diff --git a/arch/arm64/boot/dts/qcom/fajita.dtsi b/arch/arm64/boot/dts/qcom/fajita.dtsi index 4e231ef93047..ad244f2bc4cb 100644 --- a/arch/arm64/boot/dts/qcom/fajita.dtsi +++ b/arch/arm64/boot/dts/qcom/fajita.dtsi @@ -175,108 +175,6 @@ reserved-memory { }; }; - dsi_samsung_s6e3fc1_cmd_display: qcom,dsi-display@17 { - compatible = "qcom,dsi-display"; - label = "dsi_samsung_s6e3fc1_cmd_display"; - qcom,display-type = "primary"; - qcom,dsi-ctrl = <&mdss_dsi0>; - qcom,dsi-phy = <&mdss_dsi_phy0>; - clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, - <&mdss_dsi0_pll PCLK_MUX_0_CLK>; - clock-names = "mux_byte_clk", "mux_pixel_clk"; - pinctrl-names = "panel_active", "panel_suspend"; - pinctrl-0 = <&sde_dsi_active &sde_te_active &esd_check_active>; - pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend &esd_check_suspend>; - qcom,dsi-panel = <&dsi_samsung_s6e3fc1_cmd>; - vddio-supply = <&pm8998_l14>; - qcom,platform-te-gpio = <&tlmm 30 0>; - }; - - dsi_samsung_sofef00_m_cmd_display: qcom,dsi-display@18 { - compatible = "qcom,dsi-display"; - label = "dsi_samsung_sofef00_m_cmd_display"; - qcom,display-type = "primary"; - qcom,dsi-ctrl = <&mdss_dsi0>; - qcom,dsi-phy = <&mdss_dsi_phy0>; - clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, - <&mdss_dsi0_pll PCLK_MUX_0_CLK>; - clock-names = "mux_byte_clk", "mux_pixel_clk"; - pinctrl-names = "panel_active", "panel_suspend"; - pinctrl-0 = <&sde_dsi_active &sde_te_active &esd_check_active>; - pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend &esd_check_suspend>; - qcom,dsi-panel = <&dsi_samsung_sofef00_m_cmd>; - vddio-supply = <&pm8998_l14>; - qcom,platform-te-gpio = <&tlmm 30 0>; - }; - - dsi_samsung_sofef00_m_video_display: qcom,dsi-display@19 { - compatible = "qcom,dsi-display"; - label = "dsi_samsung_sofef00_m_video_display"; - qcom,display-type = "primary"; - qcom,dsi-ctrl = <&mdss_dsi0>; - qcom,dsi-phy = <&mdss_dsi_phy0>; - clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, - <&mdss_dsi0_pll PCLK_MUX_0_CLK>; - clock-names = "mux_byte_clk", "mux_pixel_clk"; - pinctrl-names = "panel_active", "panel_suspend"; - pinctrl-0 = <&sde_dsi_active &sde_te_active &esd_check_active>; - pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend &esd_check_suspend>; - qcom,dsi-panel = <&dsi_samsung_sofef00_m_video>; - vddio-supply = <&pm8998_l14>; - qcom,platform-te-gpio = <&tlmm 30 0>; - }; - -dsi_samsung_sofeg01_s_cmd_display: qcom,dsi-display@20 { - compatible = "qcom,dsi-display"; - label = "dsi_samsung_sofeg01_s_cmd_display"; - qcom,display-type = "primary"; - qcom,dsi-ctrl = <&mdss_dsi0>; - qcom,dsi-phy = <&mdss_dsi_phy0>; - clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, - <&mdss_dsi0_pll PCLK_MUX_0_CLK>; - clock-names = "mux_byte_clk", "mux_pixel_clk"; - pinctrl-names = "panel_active", "panel_suspend"; - pinctrl-0 = <&sde_dsi_active &sde_te_active &esd_check_active>; - pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend &esd_check_suspend>; - qcom,dsi-panel = <&dsi_samsung_sofeg01_s_cmd>; - vddio-supply = <&pm8998_l14>; - qcom,platform-te-gpio = <&tlmm 30 0>; - }; - -dsi_samsung_s6e3fc2x01_cmd_display: qcom,dsi-display@21 { - compatible = "qcom,dsi-display"; - label = "dsi_samsung_s6e3fc2x01_cmd_display"; - qcom,display-type = "primary"; - qcom,dsi-ctrl = <&mdss_dsi0>; - qcom,dsi-phy = <&mdss_dsi_phy0>; - clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, - <&mdss_dsi0_pll PCLK_MUX_0_CLK>; - clock-names = "mux_byte_clk", "mux_pixel_clk"; - pinctrl-names = "panel_active", "panel_suspend"; - pinctrl-0 = <&sde_dsi_active &sde_te_active &esd_check_active>; - pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend &esd_check_suspend>; - qcom,dsi-panel = <&dsi_samsung_s6e3fc2x01_cmd>; - vddio-supply = <&pm8998_l14>; - qcom,platform-te-gpio = <&tlmm 10 0>; - }; - -dsi_samsung_dsc_cmd_display: qcom,dsi-display@22 { - compatible = "qcom,dsi-display"; - label = "dsi_samsung_dsc_cmd_display"; - qcom,display-type = "primary"; - qcom,dsi-ctrl = <&mdss_dsi0>; - qcom,dsi-phy = <&mdss_dsi_phy0>; - clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, - <&mdss_dsi0_pll PCLK_MUX_0_CLK>; - clock-names = "mux_byte_clk", "mux_pixel_clk"; - pinctrl-names = "panel_active", "panel_suspend"; - pinctrl-0 = <&sde_dsi_active &sde_te_active &esd_check_active>; - pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend &esd_check_suspend>; - qcom,dsi-panel = <&dsi_samsung_dsc_cmd>; - vddio-supply = <&pm8998_l14>; - qcom,platform-te-gpio = <&tlmm 10 0>; - }; - oem_serial_pinctrl { compatible = "oem,oem_serial_pinctrl"; pinctrl-names = "uart_pinctrl_active","uart_pinctrl_deactive"; @@ -512,6 +410,7 @@ status = "disabled"; &dsi_samsung_s6e3fc1_cmd { qcom,dsi-display-active; qcom,panel-supply-entries = <&dsi_panel_pwr_supply_no_labibb_2>; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; qcom,mdss-brightness-max-level = <1023>; qcom,mdss-dsi-bl-min-level = <1>; @@ -536,6 +435,7 @@ status = "disabled"; &dsi_samsung_sofef00_m_cmd { qcom,panel-supply-entries = <&dsi_panel_pwr_supply_no_labibb_2>; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; qcom,mdss-brightness-max-level = <1023>; qcom,mdss-dsi-bl-min-level = <1>; @@ -560,6 +460,7 @@ status = "disabled"; &dsi_samsung_sofef00_m_video { qcom,panel-supply-entries = <&dsi_panel_pwr_supply_no_labibb_2>; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; qcom,mdss-brightness-max-level = <1023>; qcom,mdss-dsi-bl-min-level = <1>; @@ -584,6 +485,7 @@ status = "disabled"; &dsi_samsung_sofeg01_s_cmd { qcom,panel-supply-entries = <&dsi_panel_pwr_supply_no_labibb_2>; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; qcom,mdss-brightness-max-level = <1023>; qcom,mdss-dsi-bl-min-level = <1>; @@ -608,6 +510,7 @@ status = "disabled"; &dsi_samsung_s6e3fc2x01_cmd { qcom,panel-supply-entries = <&dsi_panel_pwr_supply_no_labibb_2>; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; qcom,mdss-brightness-max-level = <1023>; qcom,mdss-brightness-default-val = <200>; @@ -635,6 +538,7 @@ status = "disabled"; &dsi_samsung_dsc_cmd { qcom,panel-supply-entries = <&dsi_panel_pwr_supply_no_labibb_2>; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; qcom,mdss-brightness-max-level = <1023>; qcom,mdss-dsi-bl-min-level = <1>; @@ -660,6 +564,18 @@ status = "disabled"; }; }; +&sde_dsi { + qcom,dsi-default-panel = <&dsi_samsung_s6e3fc2x01_cmd>; + qcom,dsi-ctrl = <&mdss_dsi0>; + qcom,dsi-phy = <&mdss_dsi_phy0>; + clocks = <&mdss_dsi0_pll BYTECLK_MUX_0_CLK>, + <&mdss_dsi0_pll PCLK_MUX_0_CLK>; + clock-names = "mux_byte_clk0", "mux_pixel_clk0"; + pinctrl-0 = <&sde_dsi_active &sde_te_active &esd_check_active>; + pinctrl-1 = <&sde_dsi_suspend &sde_te_suspend &esd_check_suspend>; + qcom,platform-te-gpio = <&tlmm 30 0>; +}; + &qupv3_se4_i2c { status = "ok"; max98927@3a { @@ -1084,7 +1000,7 @@ status = "disabled"; status = "disabled"; }; &mdss_mdp { - connectors = <&sde_rscc &sde_wb>; + connectors = <&sde_rscc &sde_wb &sde_dsi>; }; &sde_dp{ status = "disabled"; diff --git a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi index 3a7aa883a256..3aef751a67f8 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-sde-display.dtsi @@ -122,9 +122,6 @@ qcom,panel-te-source = <0>; vddio-supply = <&pm8998_l14>; - lab-supply = <&lab_regulator>; - ibb-supply = <&ibb_regulator>; - oled-vdda-supply = <&pm8998_l22>; qcom,mdp = <&mdss_mdp>; qcom,dsi-default-panel = <&dsi_nt35597_truly_dsc_cmd>; From 963c4cffec77da3e266d2b19920a5340eb1ae23b Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Fri, 7 Apr 2023 03:06:57 +0000 Subject: [PATCH 302/356] ARM64: dts: Remove unused display nodes --- arch/arm64/boot/dts/qcom/enchilada.dtsi | 7 ------- arch/arm64/boot/dts/qcom/fajita.dtsi | 7 ------- 2 files changed, 14 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/enchilada.dtsi b/arch/arm64/boot/dts/qcom/enchilada.dtsi index c6571c40c6fd..0ed96039a1d0 100644 --- a/arch/arm64/boot/dts/qcom/enchilada.dtsi +++ b/arch/arm64/boot/dts/qcom/enchilada.dtsi @@ -290,10 +290,6 @@ status = "disabled"; &quat_mi2s_sd0_sleep &quat_mi2s_sd1_sleep >; }; -&dsi_nt35597_truly_dsc_cmd_display { - /delete-property/qcom,dsi-display-active; -}; - &mdss_dsi1 { status = "disabled"; }; @@ -799,9 +795,6 @@ status = "disabled"; status = "disabled"; }; -&dsi_nt35597_truly_dsc_cmd_display { - status = "disabled"; -}; &mdss_mdp { connectors = <&sde_rscc &sde_wb &sde_dsi>; }; diff --git a/arch/arm64/boot/dts/qcom/fajita.dtsi b/arch/arm64/boot/dts/qcom/fajita.dtsi index ad244f2bc4cb..083332b6fca5 100644 --- a/arch/arm64/boot/dts/qcom/fajita.dtsi +++ b/arch/arm64/boot/dts/qcom/fajita.dtsi @@ -389,10 +389,6 @@ status = "disabled"; &quat_mi2s_sd0_sleep &quat_mi2s_sd1_sleep >; }; -&dsi_nt35597_truly_dsc_cmd_display { - /delete-property/qcom,dsi-display-active; -}; - &mdss_dsi1 { status = "disabled"; }; @@ -996,9 +992,6 @@ status = "disabled"; status = "disabled"; }; -&dsi_nt35597_truly_dsc_cmd_display { - status = "disabled"; -}; &mdss_mdp { connectors = <&sde_rscc &sde_wb &sde_dsi>; }; From 4818864f9f7cc2fe5caf25a8b945a95558134605 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Mon, 10 Apr 2023 01:00:19 +0000 Subject: [PATCH 303/356] ARM64: dts: qcom: Remove pm8998_rtc node The qpnp-rtc driver doesn't exist on 4.19 --- arch/arm64/boot/dts/qcom/enchilada.dtsi | 5 ----- arch/arm64/boot/dts/qcom/fajita.dtsi | 5 ----- 2 files changed, 10 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/enchilada.dtsi b/arch/arm64/boot/dts/qcom/enchilada.dtsi index 0ed96039a1d0..3f4669a2a472 100644 --- a/arch/arm64/boot/dts/qcom/enchilada.dtsi +++ b/arch/arm64/boot/dts/qcom/enchilada.dtsi @@ -809,11 +809,6 @@ status = "disabled"; status = "disabled"; }; -&pm8998_rtc { - compatible = "qcom,qpnp-rtc"; - qcom,qpnp-rtc-alarm-pwrup = <1>; -}; - &pmi8998_haptics { status = "okay"; qcom,wave-shape = "sine"; diff --git a/arch/arm64/boot/dts/qcom/fajita.dtsi b/arch/arm64/boot/dts/qcom/fajita.dtsi index 083332b6fca5..5b746edd9345 100644 --- a/arch/arm64/boot/dts/qcom/fajita.dtsi +++ b/arch/arm64/boot/dts/qcom/fajita.dtsi @@ -1006,11 +1006,6 @@ status = "disabled"; status = "disabled"; }; -&pm8998_rtc { - compatible = "qcom,qpnp-rtc"; - qcom,qpnp-rtc-alarm-pwrup = <1>; -}; - &pmi8998_haptics { status = "okay"; qcom,wave-shape = "sine"; From be60240c54a69aeb35f1e0af3c8df0433b00f593 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Tue, 11 Apr 2023 21:16:42 +0000 Subject: [PATCH 304/356] fingerprint: Update wakeup source for 4.19 --- .../drivers/input/fingerprint/fpc/fpc1020_tee.c | 8 ++++---- .../drivers/input/fingerprint/goodix/gf_spi.c | 12 ++++++------ .../drivers/input/fingerprint/goodix/gf_spi.h | 1 + 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/oneplus/drivers/input/fingerprint/fpc/fpc1020_tee.c b/drivers/oneplus/drivers/input/fingerprint/fpc/fpc1020_tee.c index 601da6c982ea..4da2b4a8092a 100644 --- a/drivers/oneplus/drivers/input/fingerprint/fpc/fpc1020_tee.c +++ b/drivers/oneplus/drivers/input/fingerprint/fpc/fpc1020_tee.c @@ -64,7 +64,7 @@ struct fpc1020_data { struct pinctrl *fingerprint_pinctrl; struct pinctrl_state *pinctrl_state[ARRAY_SIZE(pctl_names)]; - struct wakeup_source ttw_wl; + struct wakeup_source *ttw_wl; int irq_gpio; int rst_gpio; struct mutex lock; /* To set/get exported values in sysfs */ @@ -329,7 +329,7 @@ static irqreturn_t fpc1020_irq_handler(int irq, void *handle) dev_dbg(fpc1020->dev, "%s\n", __func__); if (atomic_read(&fpc1020->wakeup_enabled)) { - __pm_wakeup_event(&fpc1020->ttw_wl, FPC_TTW_HOLD_TIME); + __pm_wakeup_event(fpc1020->ttw_wl, FPC_TTW_HOLD_TIME); } sysfs_notify(&fpc1020->dev->kobj, NULL, dev_attr_irq.attr.name); @@ -468,7 +468,7 @@ static int fpc1020_probe(struct platform_device *pdev) /* Request that the interrupt should be wakeable */ enable_irq_wake(gpio_to_irq(fpc1020->irq_gpio)); - wakeup_source_init(&fpc1020->ttw_wl, "fpc_ttw_wl"); + fpc1020->ttw_wl = wakeup_source_register(NULL, "fpc_ttw_wl"); rc = fpc1020_input_init(fpc1020); if (rc){ @@ -496,7 +496,7 @@ static int fpc1020_remove(struct platform_device *pdev) sysfs_remove_group(&pdev->dev.kobj, &attribute_group); mutex_destroy(&fpc1020->lock); - wakeup_source_trash(&fpc1020->ttw_wl); + wakeup_source_unregister(fpc1020->ttw_wl); dev_info(&pdev->dev, "%s\n", __func__); return 0; diff --git a/drivers/oneplus/drivers/input/fingerprint/goodix/gf_spi.c b/drivers/oneplus/drivers/input/fingerprint/goodix/gf_spi.c index 3c9ea95f0456..83e03d8c6f91 100644 --- a/drivers/oneplus/drivers/input/fingerprint/goodix/gf_spi.c +++ b/drivers/oneplus/drivers/input/fingerprint/goodix/gf_spi.c @@ -76,7 +76,6 @@ 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; struct gf_key_map maps[] = { @@ -321,13 +320,13 @@ static void nav_event_input(struct gf_dev *gf_dev, gf_nav_event_t nav_event) static irqreturn_t gf_irq(int irq, void *handle) { + struct gf_dev *gf_dev = &gf; #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); + __pm_wakeup_event(gf_dev->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 @@ -687,6 +686,7 @@ static const struct attribute_group gf_attribute_group = { int gf_opticalfp_irq_handler(int event) { + struct gf_dev *gf_dev = &gf; char msg = 0; pr_info("[info]:%s, event %d", __func__, event); @@ -702,7 +702,7 @@ int gf_opticalfp_irq_handler(int event) sendnlmsg(&msg); } - __pm_wakeup_event(&fp_wakelock, 10*HZ); + __pm_wakeup_event(gf_dev->fp_wakelock, 10*HZ); return 0; } @@ -907,7 +907,7 @@ static int gf_probe(struct platform_device *pdev) * liuyan mv wakelock here * it should before irq */ - wakeup_source_init(&fp_wakelock, "fp_wakelock"); + gf_dev->fp_wakelock = wakeup_source_register(NULL, "fp_wakelock"); status = irq_setup(gf_dev); if (status) goto err_irq; @@ -1020,7 +1020,7 @@ static int gf_remove(struct platform_device *pdev) { struct gf_dev *gf_dev = &gf; - wakeup_source_trash(&fp_wakelock); + wakeup_source_unregister(gf_dev->fp_wakelock); #if defined(CONFIG_FB) fb_unregister_client(&gf_dev->notifier); diff --git a/drivers/oneplus/drivers/input/fingerprint/goodix/gf_spi.h b/drivers/oneplus/drivers/input/fingerprint/goodix/gf_spi.h index f5e25717818d..463767d7d410 100644 --- a/drivers/oneplus/drivers/input/fingerprint/goodix/gf_spi.h +++ b/drivers/oneplus/drivers/input/fingerprint/goodix/gf_spi.h @@ -168,6 +168,7 @@ struct gf_dev { signed enable_gpio; int screen_state; int proximity_state; /* 0:far 1:near */ + struct wakeup_source *fp_wakelock; }; int gf_pinctrl_init(struct gf_dev* gf_dev); int gf_parse_dts(struct gf_dev* gf_dev); From 3c910de9ce9e09cc1ef0c6dfadfa6c4b0b01a464 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Tue, 11 Apr 2023 19:29:53 +0000 Subject: [PATCH 305/356] ARM64: enchilada: Enable touchscreen and fingerprint drivers --- arch/arm64/configs/vendor/enchilada_defconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/configs/vendor/enchilada_defconfig b/arch/arm64/configs/vendor/enchilada_defconfig index d72f27f4a1b5..b927ae521ac9 100644 --- a/arch/arm64/configs/vendor/enchilada_defconfig +++ b/arch/arm64/configs/vendor/enchilada_defconfig @@ -347,6 +347,7 @@ CONFIG_INPUT_TOUCHSCREEN=y # CONFIG_TOUCHSCREEN_ST is not set # CONFIG_TOUCHSCREEN_SYNAPTICS_DSX is not set # CONFIG_TOUCHSCREEN_SYNAPTICS_TCM is not set +CONFIG_TOUCHSCREEN_SYNAPTICS_S3320_I2C_RMI=y CONFIG_INPUT_MISC=y CONFIG_INPUT_QPNP_POWER_ON=y CONFIG_INPUT_QTI_HAPTICS=y @@ -635,6 +636,9 @@ CONFIG_ESOC_CLIENT=y CONFIG_ESOC_MDM_4x=y CONFIG_ESOC_MDM_DRV=y CONFIG_SENSORS_SSC=y +CONFIG_FINGERPRINT_DETECT=y +CONFIG_FINGERPRINT_FPC=y +CONFIG_FINGERPRINT_GOODIX=y CONFIG_QCOM_KGSL=y CONFIG_EXT4_FS=y CONFIG_EXT4_FS_POSIX_ACL=y From 9a7ca788413b1bdd68069bca4bf78594231b3df0 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Wed, 12 Apr 2023 01:16:39 +0000 Subject: [PATCH 306/356] touchscreen: Don't call opticalfp_irq_handler() We aren't building the silead fp driver --- drivers/input/touchscreen/synaptics_driver_s3320.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/input/touchscreen/synaptics_driver_s3320.c b/drivers/input/touchscreen/synaptics_driver_s3320.c index 112935f44a47..4477945ba1e2 100644 --- a/drivers/input/touchscreen/synaptics_driver_s3320.c +++ b/drivers/input/touchscreen/synaptics_driver_s3320.c @@ -367,7 +367,6 @@ static int synaptics_rmi4_i2c_write_word(struct i2c_client* client, unsigned char addr,unsigned short data); static int synaptics_mode_change(int mode); int tp_single_tap_en(struct synaptics_ts_data *ts, bool enable); -int opticalfp_irq_handler(struct fp_underscreen_info *tp_info); int gf_opticalfp_irq_handler(int event); #ifdef TPD_USE_EINT @@ -1235,7 +1234,6 @@ static int set_tp_info(struct synaptics_ts_data *ts, uint8_t up_down) tp_info.y = tp_infor[3]<<8|tp_infor[2]; tp_info.area_rate = tp_infor[5]<<8|tp_infor[4]; tp_info.touch_state = up_down; - opticalfp_irq_handler(&tp_info); return ret; } From 1d8c0408ced399532058d4785f09f3dc69bd6cb6 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Sun, 25 Sep 2022 10:04:25 -0400 Subject: [PATCH 307/356] power: smb-lib: Kang get_usb_temp() from SM8250_R_11.0 --- drivers/power/supply/qcom/qpnp-smb2.c | 49 ++++++++++++++++++++++++++- drivers/power/supply/qcom/smb-lib.c | 30 ++++++++++------ drivers/power/supply/qcom/smb-lib.h | 4 +++ 3 files changed, 71 insertions(+), 12 deletions(-) diff --git a/drivers/power/supply/qcom/qpnp-smb2.c b/drivers/power/supply/qcom/qpnp-smb2.c index 1db495e1a375..018ebd210e31 100644 --- a/drivers/power/supply/qcom/qpnp-smb2.c +++ b/drivers/power/supply/qcom/qpnp-smb2.c @@ -19,6 +19,7 @@ #include #include #include +#include /* david.liu@bsp, 20171023 Battery & Charging porting */ #include #include @@ -605,6 +606,22 @@ static int smb2_parse_dt(struct smb2 *chip) chg->ufp_only_mode = of_property_read_bool(node, "qcom,ufp-only-mode"); + rc = of_property_match_string(node, "io-channel-names", + "gpio12_voltage"); + if (rc >= 0) { + chg->iio.op_connector_temp_chan = iio_channel_get(chg->dev, + "gpio12_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; + } + } + return 0; } @@ -2884,6 +2901,35 @@ static const struct file_operations proc_ship_mode_operations = { }; #endif +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"); + + return 0; +} + static irqreturn_t op_usb_plugin_irq_handler(int irq, void *dev_id) { schedule_work(&g_chip->otg_switch_work); @@ -2981,7 +3027,7 @@ static int smb2_probe(struct platform_device *pdev) rc = smb2_parse_dt(chip); if (rc < 0) { pr_err("Couldn't parse device tree rc=%d\n", rc); - goto cleanup; + return rc; } rc = smblib_init(chg); @@ -3137,6 +3183,7 @@ static int smb2_probe(struct platform_device *pdev) device_init_wakeup(chg->dev, true); chg->probe_done = true; request_vbus_ctrl_gpio(chg); + op_config_usb_temperature_adc(chg); request_plug_irq(chg); pr_info("QPNP SMB2 probed successfully usb:present=%d type=%d batt:present = %d health = %d charge = %d\n", diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c index 1875d772856b..266f73d5e819 100644 --- a/drivers/power/supply/qcom/smb-lib.c +++ b/drivers/power/supply/qcom/smb-lib.c @@ -7548,29 +7548,35 @@ static void op_otg_switch(struct work_struct *work) g_chg->pre_cable_pluged = usb_pluged; } - +#define USB_CONNECTOR_DEFAULT_TEMP 25 static int get_usb_temp(struct smb_charger *chg) { - struct qpnp_vadc_chip *vadc_dev; - struct qpnp_vadc_result result; - int ret, i; + int ret, i, result; - vadc_dev = qpnp_get_vadc(chg->dev, "usb-temp"); - if (IS_ERR(vadc_dev)) { - ret = PTR_ERR(vadc_dev); - pr_err("vadc property missing, ret=%d\n", ret); - return ret; + 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; } - ret = qpnp_vadc_read(vadc_dev, VADC_AMUX5_GPIO_PU1, &result); - chg->connecter_voltage = (int) result.physical/1000; 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; } + pr_debug("connectter vol:%d,temp:%d\n", chg->connecter_voltage, con_volt_30k[i]); + return con_temp_30k[i]; } @@ -8698,6 +8704,8 @@ static void smblib_iio_deinit(struct smb_charger *chg) iio_channel_release(chg->iio.usbin_v_chan); if (!IS_ERR_OR_NULL(chg->iio.batt_i_chan)) iio_channel_release(chg->iio.batt_i_chan); + if (!IS_ERR_OR_NULL(chg->iio.op_connector_temp_chan)) + iio_channel_release(chg->iio.op_connector_temp_chan); } int smblib_init(struct smb_charger *chg) diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h index 9f73557f0c08..bc37763aa8ee 100644 --- a/drivers/power/supply/qcom/smb-lib.h +++ b/drivers/power/supply/qcom/smb-lib.h @@ -243,6 +243,7 @@ struct smb_iio { struct iio_channel *connector_temp_thr1_chan; struct iio_channel *connector_temp_thr2_chan; struct iio_channel *connector_temp_thr3_chan; + struct iio_channel *op_connector_temp_chan; }; struct reg_info { @@ -492,6 +493,8 @@ struct smb_charger { bool in_chg_lock; bool fcc_stepper_enable; bool ufp_only_mode; + struct pinctrl_state *usb_temperature_default; + struct pinctrl *pinctrl; /* workaround flag */ u32 wa_flags; @@ -517,6 +520,7 @@ struct smb_charger { int pulse_cnt; int die_health; + int filter_count; }; /* david.liu@bsp, 20171023 Battery & Charging porting */ From d85aa2ad1d275658b542eff66667a622e99f4d19 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Wed, 12 Apr 2023 16:13:39 +0000 Subject: [PATCH 308/356] iio: adc: Add OnePlus adc channels --- drivers/iio/adc/qcom-spmi-adc5.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/iio/adc/qcom-spmi-adc5.c b/drivers/iio/adc/qcom-spmi-adc5.c index d5f06dffb7de..d80e3ac9cda0 100644 --- a/drivers/iio/adc/qcom-spmi-adc5.c +++ b/drivers/iio/adc/qcom-spmi-adc5.c @@ -989,6 +989,10 @@ static const struct adc_channels adc_chans_rev2[ADC_MAX_CHANNEL] = { SCALE_HW_CALIB_THERM_100K_PULLUP) [ANA_IN] = ADC_CHAN_TEMP("drax_temp", 1, SCALE_HW_CALIB_PMIC_THERM) + [ADC_AMUX_THM4_PU2] = ADC_CHAN_TEMP("pa1_therm", 1, + SCALE_HW_CALIB_THERM_100K_PULLUP) + [VADC_LR_MUX7_HW_ID] = ADC_CHAN_VOLT("gpio12_v", 1, + SCALE_HW_CALIB_DEFAULT) }; static int adc_get_dt_channel_data(struct adc_chip *adc, From e7076ae1e436e1cba6a69a8b435844299c085a85 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Sun, 25 Sep 2022 11:02:09 -0400 Subject: [PATCH 309/356] ARM64: dts: Update thermal config for 4.19 --- arch/arm64/boot/dts/qcom/enchilada.dtsi | 38 +++++++------- arch/arm64/boot/dts/qcom/fajita.dtsi | 68 ++++++++++++++----------- 2 files changed, 58 insertions(+), 48 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/enchilada.dtsi b/arch/arm64/boot/dts/qcom/enchilada.dtsi index 3f4669a2a472..aeb00dd6c30d 100644 --- a/arch/arm64/boot/dts/qcom/enchilada.dtsi +++ b/arch/arm64/boot/dts/qcom/enchilada.dtsi @@ -9,6 +9,9 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ + +#include + /*recommand add our code to this dtsi*/ #include "dsi-panel-samsung_s6e3fc1_cmd.dtsi" #include "dsi-panel-samsung_sofef00_m_cmd.dtsi" @@ -1879,28 +1882,26 @@ status = "disabled"; /* OnePlus add thermistor, by rio.zhao*/ &pm8998_vadc { - chan@50 { + pa1_therm { label = "pa1_therm"; - reg = <0x50>; - qcom,decimation = <2>; - qcom,pre-div-channel-scaling = <0>; - qcom,calibration-type = "ratiometric"; - qcom,scale-function = <2>; - qcom,hw-settle-time = <2>; - qcom,fast-avg-setup = <0>; + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; }; }; &pm8998_adc_tm { - chan@50 { - label = "pa1_therm"; - reg = <0x50>; - qcom,pre-div-channel-scaling = <0>; - qcom,calibration-type = "ratiometric"; - qcom,scale-function = <2>; - qcom,hw-settle-time = <2>; - qcom,btm-channel-number = <0x90>; - qcom,thermal-node; + io-channels = <&pm8998_vadc ADC_VPH_PWR>, + <&pm8998_vadc ADC_XO_THERM_PU2>, + <&pm8998_vadc ADC_AMUX_THM1_PU2>, + <&pm8998_vadc ADC_AMUX_THM3_PU2>, + <&pm8998_vadc ADC_AMUX_THM5_PU2>, + <&pm8998_vadc ADC_AMUX_THM4_PU2>; + pa1_therm { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; }; }; @@ -1908,8 +1909,9 @@ status = "disabled"; pa1-therml-adc { polling-delay-passive = <0>; polling-delay = <0>; - thermal-sensors = <&pm8998_adc_tm 0x50>; + thermal-sensors = <&pm8998_adc_tm ADC_AMUX_THM4_PU2>; thermal-governor = "user_space"; + wake-capable-sensor; trips { active-config0 { diff --git a/arch/arm64/boot/dts/qcom/fajita.dtsi b/arch/arm64/boot/dts/qcom/fajita.dtsi index 5b746edd9345..0f37e409c51d 100644 --- a/arch/arm64/boot/dts/qcom/fajita.dtsi +++ b/arch/arm64/boot/dts/qcom/fajita.dtsi @@ -9,6 +9,9 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ + +#include + /*recommand add our code to this dtsi*/ #include "dsi-panel-samsung_s6e3fc1_cmd.dtsi" #include "dsi-panel-samsung_sofef00_m_cmd.dtsi" @@ -687,15 +690,12 @@ status = "disabled"; }; &pm8998_vadc { - chan@36 { - label = "gpio12_adc"; - reg = <0x36>; - qcom,decimation = <2>; - qcom,pre-div-channel-scaling = <0>; - qcom,calibration-type = "absolute"; - qcom,scale-function = <0>; - qcom,hw-settle-time = <2>; - qcom,fast-avg-setup = <0>; + gpio12_v { + reg = ; + label = "gpio12_v"; + qcom,ratiometric; + qcom,hw-settle-time = <800>; + qcom,pre-scaling = <1 1>; }; }; @@ -762,10 +762,19 @@ status = "disabled"; qcom,msm-bus,num-paths = <1>; qcom,msm-bus,vectors-KBps = <1 731 0 300000000>, <1 731 0 0>; - - qcom,usb-temp-vadc = <&pm8998_vadc>; op,vbus-ctrl-gpio = <&pmi8998_gpios 3 GPIO_ACTIVE_LOW>; - + io-channels = <&pmi8998_rradc 8>, + <&pmi8998_rradc 10>, + <&pmi8998_rradc 3>, + <&pmi8998_rradc 4>, + <&pm8998_vadc VADC_LR_MUX7_HW_ID>; + io-channel-names = "charger_temp", + "charger_temp_max", + "usbin_i", + "usbin_v", + "gpio12_voltage"; + pinctrl-names = "op_usb_temp_adc_default"; + pinctrl-0 = <&gpio12_adc_default>; }; &pmi8998_fg { @@ -2085,28 +2094,26 @@ status = "disabled"; /* OnePlus add thermistor, by rio.zhao*/ &pm8998_vadc { - chan@50 { + pa1_therm { label = "pa1_therm"; - reg = <0x50>; - qcom,decimation = <2>; - qcom,pre-div-channel-scaling = <0>; - qcom,calibration-type = "ratiometric"; - qcom,scale-function = <2>; - qcom,hw-settle-time = <2>; - qcom,fast-avg-setup = <0>; + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; }; }; &pm8998_adc_tm { - chan@50 { - label = "pa1_therm"; - reg = <0x50>; - qcom,pre-div-channel-scaling = <0>; - qcom,calibration-type = "ratiometric"; - qcom,scale-function = <2>; - qcom,hw-settle-time = <2>; - qcom,btm-channel-number = <0x90>; - qcom,thermal-node; + io-channels = <&pm8998_vadc ADC_VPH_PWR>, + <&pm8998_vadc ADC_XO_THERM_PU2>, + <&pm8998_vadc ADC_AMUX_THM1_PU2>, + <&pm8998_vadc ADC_AMUX_THM3_PU2>, + <&pm8998_vadc ADC_AMUX_THM5_PU2>, + <&pm8998_vadc ADC_AMUX_THM4_PU2>; + pa1_therm { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; }; }; @@ -2114,8 +2121,9 @@ status = "disabled"; pa1-therml-adc { polling-delay-passive = <0>; polling-delay = <0>; - thermal-sensors = <&pm8998_adc_tm 0x50>; + thermal-sensors = <&pm8998_adc_tm ADC_AMUX_THM4_PU2>; thermal-governor = "user_space"; + wake-capable-sensor; trips { active-config0 { From c8405d544634cb1f02829c19a1e075e180911ffb Mon Sep 17 00:00:00 2001 From: LuK1337 Date: Tue, 5 Nov 2019 16:56:57 +0100 Subject: [PATCH 310/356] techpack: audio: Import OnePlus changes EdwinMoq: Adapt for 4.19 Change-Id: I23df31c518b18446eafe6d9940066e935044ab45 --- techpack/audio/asoc/codecs/Kbuild | 3 + techpack/audio/asoc/codecs/fsa4840/Kbuild | 123 + techpack/audio/asoc/codecs/fsa4840/fsa4480.h | 62 + techpack/audio/asoc/codecs/fsa4840/fsa4840.c | 547 +++ techpack/audio/asoc/codecs/max98927/Kbuild | 123 + .../audio/asoc/codecs/max98927/max98927.c | 2225 ++++++++++ .../audio/asoc/codecs/max98927/max98927.h | 1256 ++++++ techpack/audio/asoc/codecs/tfa9874/Kbuild | 126 + techpack/audio/asoc/codecs/tfa9874/config.h | 41 + techpack/audio/asoc/codecs/tfa9874/dbgprint.h | 165 + techpack/audio/asoc/codecs/tfa9874/tfa.h | 49 + .../asoc/codecs/tfa9874/tfa1_tfafieldnames.h | 900 ++++ .../codecs/tfa9874/tfa2_tfafieldnames_N1C.h | 1522 +++++++ .../tfa9874/tfa9872_device_genregs_POR.h | 121 + .../codecs/tfa9874/tfa9872_tfafieldnames.h | 1219 +++++ .../codecs/tfa9874/tfa9874_tfafieldnames.h | 830 ++++ .../codecs/tfa9874/tfa9887_tfafieldnames.h | 61 + .../codecs/tfa9874/tfa9890_tfafieldnames.h | 76 + .../asoc/codecs/tfa9874/tfa9891_genregs.h | 1125 +++++ .../codecs/tfa9874/tfa9891_tfafieldnames.h | 515 +++ .../codecs/tfa9874/tfa9894_tfafieldnames.h | 1065 +++++ .../codecs/tfa9874/tfa9896_tfafieldnames.h | 919 ++++ techpack/audio/asoc/codecs/tfa9874/tfa98xx.c | 3336 ++++++++++++++ techpack/audio/asoc/codecs/tfa9874/tfa98xx.h | 131 + .../asoc/codecs/tfa9874/tfa98xx_genregs_N1C.h | 3853 ++++++++++++++++ .../asoc/codecs/tfa9874/tfa98xx_parameters.h | 741 ++++ .../codecs/tfa9874/tfa98xx_tfafieldnames.h | 147 + .../codecs/tfa9874/tfa9912_device_genregs.h | 255 ++ .../codecs/tfa9874/tfa9912_tfafieldnames.h | 1764 ++++++++ .../audio/asoc/codecs/tfa9874/tfaContUtil.h | 110 + techpack/audio/asoc/codecs/tfa9874/tfaOsal.h | 52 + .../audio/asoc/codecs/tfa9874/tfa_container.c | 2312 ++++++++++ .../audio/asoc/codecs/tfa9874/tfa_container.h | 364 ++ .../audio/asoc/codecs/tfa9874/tfa_debug.c | 416 ++ .../audio/asoc/codecs/tfa9874/tfa_device.h | 296 ++ techpack/audio/asoc/codecs/tfa9874/tfa_dsp.c | 3910 +++++++++++++++++ .../audio/asoc/codecs/tfa9874/tfa_dsp_fw.h | 168 + techpack/audio/asoc/codecs/tfa9874/tfa_ext.h | 57 + techpack/audio/asoc/codecs/tfa9874/tfa_init.c | 1674 +++++++ .../audio/asoc/codecs/tfa9874/tfa_internal.h | 39 + .../audio/asoc/codecs/tfa9874/tfa_service.h | 1021 +++++ techpack/audio/asoc/codecs/tfa9874/versions.h | 3 + techpack/audio/asoc/codecs/wcd-mbhc-adc.c | 11 +- techpack/audio/asoc/codecs/wcd-mbhc-v2.c | 89 + .../audio/asoc/codecs/wcd934x/wcd934x-mbhc.c | 33 + .../asoc/codecs/wcd934x/wcd934x-regmap.c | 3 +- techpack/audio/asoc/codecs/wcd934x/wcd934x.c | 5 + techpack/audio/asoc/msm-pcm-routing-v2.c | 7 +- techpack/audio/asoc/sdm845.c | 535 ++- techpack/audio/config/sdm845auto.conf | 3 + techpack/audio/config/sdm845autoconf.h | 3 + techpack/audio/dsp/q6afe.c | 224 + .../audio/include/asoc/wcd9xxx-slimslave.h | 5 + techpack/audio/include/dsp/apr_audio-v2.h | 39 + 54 files changed, 34669 insertions(+), 10 deletions(-) create mode 100644 techpack/audio/asoc/codecs/fsa4840/Kbuild create mode 100644 techpack/audio/asoc/codecs/fsa4840/fsa4480.h create mode 100644 techpack/audio/asoc/codecs/fsa4840/fsa4840.c create mode 100644 techpack/audio/asoc/codecs/max98927/Kbuild create mode 100644 techpack/audio/asoc/codecs/max98927/max98927.c create mode 100644 techpack/audio/asoc/codecs/max98927/max98927.h create mode 100644 techpack/audio/asoc/codecs/tfa9874/Kbuild create mode 100644 techpack/audio/asoc/codecs/tfa9874/config.h create mode 100644 techpack/audio/asoc/codecs/tfa9874/dbgprint.h create mode 100644 techpack/audio/asoc/codecs/tfa9874/tfa.h create mode 100644 techpack/audio/asoc/codecs/tfa9874/tfa1_tfafieldnames.h create mode 100644 techpack/audio/asoc/codecs/tfa9874/tfa2_tfafieldnames_N1C.h create mode 100644 techpack/audio/asoc/codecs/tfa9874/tfa9872_device_genregs_POR.h create mode 100644 techpack/audio/asoc/codecs/tfa9874/tfa9872_tfafieldnames.h create mode 100644 techpack/audio/asoc/codecs/tfa9874/tfa9874_tfafieldnames.h create mode 100644 techpack/audio/asoc/codecs/tfa9874/tfa9887_tfafieldnames.h create mode 100644 techpack/audio/asoc/codecs/tfa9874/tfa9890_tfafieldnames.h create mode 100644 techpack/audio/asoc/codecs/tfa9874/tfa9891_genregs.h create mode 100644 techpack/audio/asoc/codecs/tfa9874/tfa9891_tfafieldnames.h create mode 100644 techpack/audio/asoc/codecs/tfa9874/tfa9894_tfafieldnames.h create mode 100644 techpack/audio/asoc/codecs/tfa9874/tfa9896_tfafieldnames.h create mode 100644 techpack/audio/asoc/codecs/tfa9874/tfa98xx.c create mode 100644 techpack/audio/asoc/codecs/tfa9874/tfa98xx.h create mode 100644 techpack/audio/asoc/codecs/tfa9874/tfa98xx_genregs_N1C.h create mode 100644 techpack/audio/asoc/codecs/tfa9874/tfa98xx_parameters.h create mode 100644 techpack/audio/asoc/codecs/tfa9874/tfa98xx_tfafieldnames.h create mode 100644 techpack/audio/asoc/codecs/tfa9874/tfa9912_device_genregs.h create mode 100644 techpack/audio/asoc/codecs/tfa9874/tfa9912_tfafieldnames.h create mode 100644 techpack/audio/asoc/codecs/tfa9874/tfaContUtil.h create mode 100644 techpack/audio/asoc/codecs/tfa9874/tfaOsal.h create mode 100644 techpack/audio/asoc/codecs/tfa9874/tfa_container.c create mode 100644 techpack/audio/asoc/codecs/tfa9874/tfa_container.h create mode 100644 techpack/audio/asoc/codecs/tfa9874/tfa_debug.c create mode 100644 techpack/audio/asoc/codecs/tfa9874/tfa_device.h create mode 100644 techpack/audio/asoc/codecs/tfa9874/tfa_dsp.c create mode 100644 techpack/audio/asoc/codecs/tfa9874/tfa_dsp_fw.h create mode 100644 techpack/audio/asoc/codecs/tfa9874/tfa_ext.h create mode 100644 techpack/audio/asoc/codecs/tfa9874/tfa_init.c create mode 100644 techpack/audio/asoc/codecs/tfa9874/tfa_internal.h create mode 100644 techpack/audio/asoc/codecs/tfa9874/tfa_service.h create mode 100644 techpack/audio/asoc/codecs/tfa9874/versions.h diff --git a/techpack/audio/asoc/codecs/Kbuild b/techpack/audio/asoc/codecs/Kbuild index 63215b3c497d..b2c317437e76 100644 --- a/techpack/audio/asoc/codecs/Kbuild +++ b/techpack/audio/asoc/codecs/Kbuild @@ -257,6 +257,9 @@ ifeq ($(KERNEL_BUILD), 1) obj-y += rouleur/ obj-y += wsa883x/ obj-y += sdm660_cdc/ + obj-y += fsa4840/ + obj-y += max98927/ + obj-y += tfa9874/ endif # Module information used by KBuild framework obj-$(CONFIG_WCD9XXX_CODEC_CORE) += wcd_core_dlkm.o diff --git a/techpack/audio/asoc/codecs/fsa4840/Kbuild b/techpack/audio/asoc/codecs/fsa4840/Kbuild new file mode 100644 index 000000000000..478479d21a92 --- /dev/null +++ b/techpack/audio/asoc/codecs/fsa4840/Kbuild @@ -0,0 +1,123 @@ +# We can build either as part of a standalone Kernel build or as +# an external module. Determine which mechanism is being used +ifeq ($(MODNAME),) + KERNEL_BUILD := 1 +else + KERNEL_BUILD := 0 +endif + +ifeq ($(KERNEL_BUILD), 1) + # These are configurable via Kconfig for kernel-based builds + # Need to explicitly configure for Android-based builds + AUDIO_BLD_DIR := $(shell pwd)/kernel/msm-4.19 + AUDIO_ROOT := $(AUDIO_BLD_DIR)/techpack/audio +endif + +ifeq ($(KERNEL_BUILD), 0) + ifeq ($(CONFIG_ARCH_SDM845), y) + include $(AUDIO_ROOT)/config/sdm845auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sdm845autoconf.h + endif + ifeq ($(CONFIG_ARCH_SDM670), y) + include $(AUDIO_ROOT)/config/sdm710auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sdm710autoconf.h + endif + ifeq ($(CONFIG_ARCH_SDM450), y) + include $(AUDIO_ROOT)/config/sdm710auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sdm710autoconf.h + endif + ifeq ($(CONFIG_ARCH_SM6150), y) + include $(AUDIO_ROOT)/config/sm6150auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sm6150autoconf.h + endif + ifeq ($(CONFIG_ARCH_KONA), y) + include $(AUDIO_ROOT)/config/konaauto.conf + INCS += -include $(AUDIO_ROOT)/config/konaautoconf.h + endif + ifeq ($(CONFIG_ARCH_LITO), y) + include $(AUDIO_ROOT)/config/litoauto.conf + export + INCS += -include $(AUDIO_ROOT)/config/litoautoconf.h + endif +endif + +# As per target team, build is done as follows: +# Defconfig : build with default flags +# Slub : defconfig + CONFIG_SLUB_DEBUG := y + +# CONFIG_SLUB_DEBUG_ON := y + CONFIG_PAGE_POISONING := y +# Perf : Using appropriate msmXXXX-perf_defconfig +# +# Shipment builds (user variants) should not have any debug feature +# enabled. This is identified using 'TARGET_BUILD_VARIANT'. Slub builds +# are identified using the CONFIG_SLUB_DEBUG_ON configuration. Since +# there is no other way to identify defconfig builds, QTI internal +# representation of perf builds (identified using the string 'perf'), +# is used to identify if the build is a slub or defconfig one. This +# way no critical debug feature will be enabled for perf and shipment +# builds. Other OEMs are also protected using the TARGET_BUILD_VARIANT +# config. + +############ UAPI ############ +UAPI_DIR := uapi +UAPI_INC := -I$(AUDIO_ROOT)/include/$(UAPI_DIR) + +############ COMMON ############ +COMMON_DIR := include +COMMON_INC := -I$(AUDIO_ROOT)/$(COMMON_DIR) + +############ fsa4840 ############ +ifdef CONFIG_SND_SOC_FSA4840 + FSA4840_OBJS += fsa4840.o +endif + +LINUX_INC += -Iinclude/linux + +INCS += $(COMMON_INC) \ + $(UAPI_INC) + +EXTRA_CFLAGS += $(INCS) + + +CDEFINES += -DANI_LITTLE_BYTE_ENDIAN \ + -DANI_LITTLE_BIT_ENDIAN \ + -DDOT11F_LITTLE_ENDIAN_HOST \ + -DANI_COMPILER_TYPE_GCC \ + -DANI_OS_TYPE_ANDROID=6 \ + -DPTT_SOCK_SVC_ENABLE \ + -Wall\ + -Werror\ + -D__linux__ + +KBUILD_CPPFLAGS += $(CDEFINES) + +# Currently, for versions of gcc which support it, the kernel Makefile +# is disabling the maybe-uninitialized warning. Re-enable it for the +# AUDIO driver. Note that we must use EXTRA_CFLAGS here so that it +# will override the kernel settings. +ifeq ($(call cc-option-yn, -Wmaybe-uninitialized),y) +EXTRA_CFLAGS += -Wmaybe-uninitialized +endif +#EXTRA_CFLAGS += -Wmissing-prototypes + +ifeq ($(call cc-option-yn, -Wheader-guard),y) +EXTRA_CFLAGS += -Wheader-guard +endif + +ifeq ($(KERNEL_BUILD), 0) +KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/ipc/Module.symvers +KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/dsp/Module.symvers +KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/Module.symvers +KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/codecs/Module.symvers +KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/soc/Module.symvers +endif + +# Module information used by KBuild framework +obj-$(CONFIG_SND_SOC_FSA4840) += fsa4840_dlkm.o +fsa4840_dlkm-y := $(FSA4840_OBJS) + +# inject some build related information +DEFINES += -DBUILD_TIMESTAMP=\"$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')\" diff --git a/techpack/audio/asoc/codecs/fsa4840/fsa4480.h b/techpack/audio/asoc/codecs/fsa4840/fsa4480.h new file mode 100644 index 000000000000..634eb0391c6d --- /dev/null +++ b/techpack/audio/asoc/codecs/fsa4840/fsa4480.h @@ -0,0 +1,62 @@ +#ifndef __FSA4480_INC__ +#define __FSA4480_INC__ + +#include +#include +#include +/*2018/06/14 @bsp add for support notify audio adapter switch*/ +#include + +#define FSA4480_DEVID 0x00 +#define FSA4480_OVPMSK 0x01 +#define FSA4480_OVPFLG 0x02 +#define FSA4480_OVPST 0x03 +#define FSA4480_SWEN 0x04 +#define FSA4480_SWSEL 0x05 +#define FSA4480_SWST0 0x06 +#define FSA4480_SWST1 0x07 +#define FSA4480_CNT_L 0x08 +#define FSA4480_CNT_R 0x09 +#define FSA4480_CNT_MIC 0x0A +#define FSA4480_CNT_SEN 0x0B +#define FSA4480_CNT_GND 0x0C +#define FSA4480_TIM_R 0x0D +#define FSA4480_TIM_MIC 0x0E +#define FSA4480_TIM_SEN 0x0F +#define FSA4480_TIM_GND 0x10 +#define FSA4480_ACC_DET 0x11 +#define FSA4480_FUN_EN 0x12 +#define FSA4480_RES_SET 0x13 +#define FSA4480_RES_VAL 0x14 +#define FSA4480_RES_THR 0x15 +#define FSA4480_RES_INV 0x16 +#define FSA4480_JACTYP 0x17 +#define FSA4480_DECINT 0x18 +#define FSA4480_DECMSK 0x19 +#define FSA4480_AUDREG1 0x1A +#define FSA4480_AUDREG2 0x1B +#define FSA4480_AUDDATA0 0x1C +#define FSA4480_AUDDATA1 0x1D +#define FSA4480_RESET 0x1E +#define FSA4480_CURSET 0x1F + +#define FSA4480_ALLSW 0 +#define FSA4480_USB 1 +#define FSA4480_Audio 2 +#define FSA4480_MIC 3 +#define FSA4480_SBU 4 + +struct fsa4480 { + struct i2c_client *i2c; + struct mutex fsa_lock; + wait_queue_head_t wq; + struct device *dev; + int mbhc_en; + struct delayed_work call_wcd_dwork; +}; + +/*2018/06/14 @bsp add for support notify audio adapter switch*/ +extern int register_cc_notifier_client(struct notifier_block *nb); +extern int unregister_cc_notifier_client(struct notifier_block *nb); + +#endif diff --git a/techpack/audio/asoc/codecs/fsa4840/fsa4840.c b/techpack/audio/asoc/codecs/fsa4840/fsa4840.c new file mode 100644 index 000000000000..145cc64ae941 --- /dev/null +++ b/techpack/audio/asoc/codecs/fsa4840/fsa4840.c @@ -0,0 +1,547 @@ +/* + * + * Copyright + * Aurthor:suzhiguang@oneplus.com + * 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 +#include +#include +#include +#include "fsa4480.h" + +#define I2C_RETRIES 2 +#define I2C_RETRY_DELAY 5 /* ms */ + +struct fsa4480 *gFsa4480; +bool fsa4480_enable = false; +EXPORT_SYMBOL_GPL(fsa4480_enable); +extern bool audio_adapter_flag; + +/* +*suzhiguang:read register value +*register address +*read value +*/ +int fsa4480_read_data(struct fsa4480 *fsa, + unsigned char reg, + int len, unsigned char value[]) +{ + struct i2c_client *fsa_client; + int err; + int tries = 0; + int error = 0; + struct i2c_msg msgs[] = { + { + .flags = 0, + .len = 1, + .buf = ®, + }, { + .flags = I2C_M_RD, + .len = len, + .buf = value, + }, + }; + + if (fsa == NULL) { + pr_err("fsa read data:No device available\n"); + return -1; + } + + if (fsa->i2c) { + fsa_client = fsa->i2c; + msgs[0].addr = fsa_client->addr; + msgs[1].addr = fsa_client->addr; + + do { + err = i2c_transfer(fsa_client->adapter, msgs, + ARRAY_SIZE(msgs)); + if (err != ARRAY_SIZE(msgs)) + msleep_interruptible(I2C_RETRY_DELAY); + } while ((err != ARRAY_SIZE(msgs)) && (++tries < I2C_RETRIES)); + + if (err != ARRAY_SIZE(msgs)) { + dev_err(&fsa_client->dev, "read transfer error %d\n", + err); + error = -1; + } + + } else { + pr_err("No device available\n"); + error = -1; + } + return error; +} + +/* +*suzhiguang:write register value +*/ +int fsa4480_write_data(struct fsa4480 *fsa, char *writebuf, int writelen) +{ + int ret = 0; + struct i2c_client *client; + + client = fsa->i2c; + if (writelen > 0) { + struct i2c_msg msgs[] = { + { + .addr = client->addr, + .flags = 0, + .len = writelen, + .buf = writebuf, + }, + }; + ret = i2c_transfer(client->adapter, msgs, 1); + if (ret < 0) + pr_err("fsa4480_write_data [IIC]: i2c_write error, ret=%d", ret); + } + + return ret; +} + +/* +*suzhiguang:write register value +*register address +*write value +*/ +int fsa4480_i2c_write_reg(struct fsa4480 *fsa, unsigned char regaddr, unsigned char regvalue) +{ + unsigned char buf[2] = {0}; + + if (fsa == NULL) { + pr_err("fsa write reg: No device available\n"); + return -1; + } + + buf[0] = regaddr; + buf[1] = regvalue; + return fsa4480_write_data(fsa, buf, sizeof(buf)); +} + +#if 0 +static void parseString(const char *buf) +{ + int i,j; + char commandStr[10]; + char regStr[10]; + char valueStr[10]; + int reg, value; + + pr_err("fsa input buffer is %s\n", buf); + for(i=0,j=0; buf[i]!=' ' && buf[i]!='\0'; i++,j++){ + commandStr[j] = buf[i]; + } + commandStr[j] = '\0'; + pr_err("commandStr is %s\n", commandStr); + if (buf[i] =='\0') + return; + + for(; buf[i]==' ' && buf[i]!='\0'; i++){} + if (buf[i] == '\0') + return; + + + for(j=0;buf[i]!=' ' && buf[i]!='\0';i++,j++) { + regStr[j] = buf[i]; + } + regStr[j] = '\0'; + pr_err("regStr is %s\n", regStr); + if (buf[i] =='\0') + return; + + for(; buf[i]==' ' && buf[i]!='\0'; i++){} + if (buf[i] == '\0') + return; + + + for(j=0;buf[i]!=' ' && buf[i]!='\0';i++,j++) { + valueStr[j] = buf[i]; + } + valueStr[j] = '\0'; + pr_err("regStr is %s\n", valueStr); + + reg = atoi(regStr); + value = atoi(valueStr); + + pr_err("parse comand is %s reg =0x%x value = 0x%x\n", commandStr, reg, value); +} +#endif + +static ssize_t fsa4480_state_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned char reg04 = 0 , reg05 = 0, reg17 = 0, val = 0; + unsigned char regValue = 0; + + pr_err("%s",__func__); + + if (gFsa4480 == NULL) { + pr_err("%s:No fsa device found.\n",__func__); + return -EINVAL; + } + +// parseString(buf); + + if (sysfs_streq(buf, "lr")) { + + pr_err("%s lr\n",__func__); + fsa4480_i2c_write_reg(gFsa4480, FSA4480_SWEN, 0x9f); + fsa4480_i2c_write_reg(gFsa4480, FSA4480_SWSEL, 0x00); + fsa4480_read_data(gFsa4480, FSA4480_SWEN, 1, ®Value); + pr_err("%s FSA4480_SWEN = %x\n", __func__, regValue); + fsa4480_read_data(gFsa4480, FSA4480_SWSEL, 1, ®Value); + pr_err("%s FSA4480_SWSEL = %x\n", __func__, regValue); + + } else if(sysfs_streq(buf, "mic")) { + + } else if(sysfs_streq(buf, "all")) { + + fsa4480_i2c_write_reg(gFsa4480, FSA4480_SWEN, 0x98); + fsa4480_i2c_write_reg(gFsa4480, FSA4480_SWSEL, 0x00); + + fsa4480_i2c_write_reg(gFsa4480, FSA4480_SWEN, 0x9b); + fsa4480_i2c_write_reg(gFsa4480, FSA4480_FUN_EN, 0x0d); + msleep_interruptible(30); + + fsa4480_read_data(gFsa4480, FSA4480_JACTYP, 1, ®17); + fsa4480_read_data(gFsa4480, FSA4480_SWEN, 1, ®04); + fsa4480_read_data(gFsa4480, FSA4480_SWSEL, 1, ®05); + msleep_interruptible(10); + val = reg17; + switch(val) + { + case 0x08: // 4 pole, + case 0x04: // 4 pole, + // automatically configure if it is 4 pole audio jack + break; + case 0x02: // 3 pole + fsa4480_i2c_write_reg(gFsa4480, FSA4480_SWEN, (reg04 & 0x7f)); + msleep_interruptible(50); + fsa4480_i2c_write_reg(gFsa4480, FSA4480_SWEN, (reg04 | 0x80)); + break; + default: + pr_err("No audio accessory was recognized\n"); + break; + } + } else if(sysfs_streq(buf, "off")) { + fsa4480_read_data(gFsa4480, FSA4480_SWEN, 1, ®04); + fsa4480_read_data(gFsa4480, FSA4480_SWSEL, 1, ®05); + + fsa4480_i2c_write_reg(gFsa4480, FSA4480_SWEN, (reg04 & 0x98)); + fsa4480_i2c_write_reg(gFsa4480, FSA4480_SWSEL, (reg05 | 0x18)); + msleep_interruptible(30); + } else { + count = -EINVAL; + } + return count; +} + +static ssize_t fsa4480_state_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + int err = 0; + u8 reg = 0x0; + u8 statu = 0x0; + char *temp = buf; + ssize_t buf_size = 0; + + if (gFsa4480 == NULL) { + pr_err("%s:No fsa device found.\n",__func__); + return -EINVAL; + } + + for (reg = 0x0; reg <= FSA4480_RESET; reg++) { + err = fsa4480_read_data(gFsa4480, reg, 1, &statu); + if (err < 0) { + pr_err("%s: read reg %#04x is failed\n", __func__, reg); + } + sprintf(temp,"%#04x: %#04x\n", reg, statu); + memset(&statu, 0, sizeof(statu)); + while (*temp != '\0') { + buf_size++; + temp++; + } + } + + *temp = '\0'; + + pr_err("%s:%s\n", __func__, buf); + + return buf_size; +} + +static struct device_attribute fsa4480_state_attr = + __ATTR(test, 0444, fsa4480_state_show, fsa4480_state_store); + + +/* +*suzhiguang:fsa init. +*/ +#if 0 +static void fsa4480_init(struct fsa4480 *fsa4480) +{ + fsa4480_i2c_write_reg(fsa4480, FSA4480_OVPMSK, 0xff); // OVP Interrupt Mask: ffh= disable all OVP interrupt +// fsa4480_i2c_write_reg(FSA4480_DECMSK, 0x00); // Audio Jack and Moisture Detection Interrupt Mask: + + fsa4480_i2c_write_reg(fsa4480, FSA4480_AUDDATA0, 0x20); // set mic threshold data0 + fsa4480_i2c_write_reg(fsa4480, FSA4480_AUDDATA1, 0xff); // set mic threshold data1 + + +/* + //Configure audio turn on timing to suppress pop noise + fsa4480_i2c_write_reg(FSA4480_CNT_L,0x01); // Set Audio L slow turn on timing, + fsa4480_i2c_write_reg(FSA4480_CNT_R,0x01); // Set Audio R slow turn on timing, + fsa4480_i2c_write_reg(FSA4480_CNT_MIC,0x01); // Set Audio MIC slow turn on timing, + fsa4480_i2c_write_reg(FSA4480_CNT_SEN,0x01); // Set Audio Sense slow turn on timing, + fsa4480_i2c_write_reg(FSA4480_CNT_GND,0x01); // Set Audio Ground slow turn on timing, + fsa4480_i2c_write_reg(FSA4480_TIM_R,0x00); // Set Delay between R and L + fsa4480_i2c_write_reg(FSA4480_TIM_MIC,0x00); // Set Delay between Mic and L + fsa4480_i2c_write_reg(FSA4480_TIM_SEN,0x00); // Set Delay between Sense and L + fsa4480_i2c_write_reg(FSA4480_TIM_GND,0x00); // Set Delay between Analog Ground and L +*/ + +/* + //configure moisture detection + fsa4480_i2c_write_reg(FSA4480_RES_SET, 0x00); // select which pin is enabled for moisture detection + fsa4480_i2c_write_reg(FSA4480_RES_THR, 0x16); // set detection threshold: 16h = 22 or 220 Kohm + fsa4480_i2c_write_reg(FSA4480_RES_INV, 0x00); // set detection interval: 00h =single + +*/ + + fsa4480_i2c_write_reg(fsa4480, FSA4480_FUN_EN, 0x0d); // Function Setting: h4b= DEC open drain output, + fsa4480_i2c_write_reg(fsa4480, FSA4480_SWEN, 0x80); // Switch Enable: 80h= enable FSA4480 device +// fsa4480_i2c_write_reg(FSA4480_SWSEL, 0x18); // set default switch: 18h= to DP/DN +} +#endif + +/*2018/06/14 @bsp add for support notify audio adapter switch*/ +static int cc_audio_adapter_detect_callback(struct notifier_block *nb, + unsigned long value, void *data) +{ + unsigned char reg04 =0 , reg05 =0, reg17 =0, val = 0; + + if (gFsa4480 == NULL) { + pr_err("%s:No fsa device found.\n",__func__); + return NOTIFY_OK; + } + + if (value == 1) { + pr_err("%s:audio_adapter attached!\n", __func__); + pr_err("%s:open the audio switch!\n", __func__); + + fsa4480_i2c_write_reg(gFsa4480, FSA4480_SWEN, 0x9f); + fsa4480_i2c_write_reg(gFsa4480, FSA4480_SWSEL, 0x00); + msleep_interruptible(1); + fsa4480_i2c_write_reg(gFsa4480, FSA4480_FUN_EN, 0x0d); + msleep_interruptible(30); + + fsa4480_read_data(gFsa4480, FSA4480_JACTYP, 1, ®17); + fsa4480_read_data(gFsa4480, FSA4480_SWEN, 1, ®04); + fsa4480_read_data(gFsa4480, FSA4480_SWSEL, 1, ®05); + pr_err("%s:FSA4480_JACTYP =%x FSA4480_SWEN =%x FSA4480_SWSEL =%x\n", + __func__, reg17, reg04, reg05); + + msleep_interruptible(10); + val = reg17; + switch(val) + { + case 0x08: // 4 pole, + case 0x04: // 4 pole, + // automatically configure if it is 4 pole audio jack + break; + case 0x02: // 3 pole + reg04 |= 0x7; + fsa4480_i2c_write_reg(gFsa4480, FSA4480_SWEN, (reg04 & 0x7f)); + msleep_interruptible(50); + fsa4480_i2c_write_reg(gFsa4480, FSA4480_SWEN, (reg04 | 0x80)); + fsa4480_read_data(gFsa4480, FSA4480_SWEN, 1, ®04); + pr_err("%s: reg04 is %#x\n", __func__, reg04); + break; + default: + pr_err("fsa4480 No audio accessory was recognized"); + + } + + if (gpio_is_valid(gFsa4480->mbhc_en)) { + gpio_set_value_cansleep(gFsa4480->mbhc_en, 1); + pr_err("gFsa4480->mbhc_en set to 1\n"); + } else { + pr_err("gpio_is_valid failed\n"); + } + + } else if (value == 0) { + pr_err("%s:audio_adapter removal!\n", __func__); + pr_err("%s:close the audio switch!\n", __func__); + + if (gpio_is_valid(gFsa4480->mbhc_en)) { + gpio_set_value_cansleep(gFsa4480->mbhc_en, 0); + pr_err("gpio set value to 0\n"); + } else { + pr_err("gpio_is_valid failed\n"); + } + fsa4480_i2c_write_reg(gFsa4480, FSA4480_SWEN, 0x80); + fsa4480_i2c_write_reg(gFsa4480, FSA4480_SWSEL, 0x18); + usleep_range(50, 55); + fsa4480_i2c_write_reg(gFsa4480, FSA4480_SWEN, 0x98); + } else + pr_err("%s:audio adapter value = %lu\n", __func__, value); + + return NOTIFY_OK; +} + +static struct notifier_block typec_cc_notifier = { + .notifier_call = cc_audio_adapter_detect_callback, +}; + +/* liuhaituo@MM.Audio 2018/8/8 Solve not detected the headset after restarting the phone + * after plugging in the headset + */ +static void call_wcd_detect_headset(struct work_struct *work) +{ + if (audio_adapter_flag) + cc_audio_adapter_detect_callback(NULL, 1, NULL); + + pr_err("%s: enter\n", __func__); + register_cc_notifier_client(&typec_cc_notifier); + pr_err("%s: exit\n", __func__); +} + +/* +*suzhiguang:fsa probe. +*/ +static int fsa4480_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct fsa4480 *fsa4480; + struct device_node *np = i2c->dev.of_node; + unsigned char regValue = 0; + int ret = 0; + + pr_err("fsa4480_i2c_probe addr=0x%x\n", i2c->addr); + + if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C)) { + dev_err(&i2c->dev, "check_functionality failed\n"); + return -EIO; + } + + fsa4480 = devm_kzalloc(&i2c->dev, sizeof(struct fsa4480), GFP_KERNEL); + if (fsa4480 == NULL) + return -ENOMEM; + + fsa4480->dev = &i2c->dev; + fsa4480->i2c = i2c; + i2c_set_clientdata(i2c, fsa4480); + + if (fsa4480_read_data(fsa4480, FSA4480_DEVID, 1, ®Value) < 0) { + pr_err("fsa4480 read device id error\n"); + return -EINVAL; + } else { + pr_err("fsa4480 device id = %x\n", regValue); + } + + if (regValue == 0x9) { + pr_err("fsa:fsa4480 found\n"); + gFsa4480 = fsa4480; + fsa4480_enable = true; + } else { + pr_err("fsa:no fsa4480 found.\n"); + return 0; + } + + fsa4480->mbhc_en = of_get_named_gpio(np, "mbhc_en", 0); + if (fsa4480->mbhc_en < 0){ + pr_err("fsa4480 of get gpio failed\n"); + return ret; + } else { + ret = devm_gpio_request_one(&i2c->dev, fsa4480->mbhc_en, + GPIOF_OUT_INIT_LOW, "FSA4480_MBHC"); + if (ret) { + pr_err("%s devm_gpio_request_one fsa4480->mbhc_en failed\n",__func__); + return ret; + } + } + //fsa4480_init(fsa4480); + + ret = sysfs_create_file(&i2c->dev.kobj, &fsa4480_state_attr.attr); + if(ret < 0) + { + pr_err("%s sysfs_create_file fsa4480_state_attr error.",__func__); + } + + /* liuhaituo@MM.Audio 2018/8/8 Solve not detected the headset after restarting the phone + * after plugging in the headset*/ + INIT_DELAYED_WORK(&fsa4480->call_wcd_dwork, call_wcd_detect_headset); + schedule_delayed_work(&fsa4480->call_wcd_dwork, msecs_to_jiffies(8000)); + return 0; +} + +static int fsa4480_i2c_remove(struct i2c_client *i2c) +{ +/*2018/06/14 @bsp add for support notify audio adapter switch*/ + unregister_cc_notifier_client(&typec_cc_notifier); + return 0; +} + +static const struct i2c_device_id fsa4480_i2c_id[] = { + { "fsa4480", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, fsa4480_i2c_id); + +#ifdef CONFIG_OF +static struct of_device_id fsa4480_dt_match[] = { + { .compatible = "fsa,fsa4480" }, + { }, +}; +#endif + +static struct i2c_driver fsa4480_i2c_driver = { + .driver = { + .name = "fsa4480", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(fsa4480_dt_match), + }, + .probe = fsa4480_i2c_probe, + .remove = fsa4480_i2c_remove, + .id_table = fsa4480_i2c_id, +}; + +static int __init fsa4480_i2c_init(void) +{ + int ret = 0; + + pr_err("fsa4480 driver fsa4480_i2c_init\n"); + + ret = i2c_add_driver(&fsa4480_i2c_driver); + + return ret; +} +module_init(fsa4480_i2c_init); + +static void __exit fsa4480_i2c_exit(void) +{ + i2c_del_driver(&fsa4480_i2c_driver); +} +module_exit(fsa4480_i2c_exit); + +MODULE_DESCRIPTION("ASoC FSA4480 driver"); +MODULE_LICENSE("GPL"); diff --git a/techpack/audio/asoc/codecs/max98927/Kbuild b/techpack/audio/asoc/codecs/max98927/Kbuild new file mode 100644 index 000000000000..0feef7cd8ca5 --- /dev/null +++ b/techpack/audio/asoc/codecs/max98927/Kbuild @@ -0,0 +1,123 @@ +# We can build either as part of a standalone Kernel build or as +# an external module. Determine which mechanism is being used +ifeq ($(MODNAME),) + KERNEL_BUILD := 1 +else + KERNEL_BUILD := 0 +endif + +ifeq ($(KERNEL_BUILD), 1) + # These are configurable via Kconfig for kernel-based builds + # Need to explicitly configure for Android-based builds + AUDIO_BLD_DIR := $(shell pwd)/kernel/msm-4.19 + AUDIO_ROOT := $(AUDIO_BLD_DIR)/techpack/audio +endif + +ifeq ($(KERNEL_BUILD), 0) + ifeq ($(CONFIG_ARCH_SDM845), y) + include $(AUDIO_ROOT)/config/sdm845auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sdm845autoconf.h + endif + ifeq ($(CONFIG_ARCH_SDM670), y) + include $(AUDIO_ROOT)/config/sdm710auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sdm710autoconf.h + endif + ifeq ($(CONFIG_ARCH_SDM450), y) + include $(AUDIO_ROOT)/config/sdm710auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sdm710autoconf.h + endif + ifeq ($(CONFIG_ARCH_SM6150), y) + include $(AUDIO_ROOT)/config/sm6150auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sm6150autoconf.h + endif + ifeq ($(CONFIG_ARCH_KONA), y) + include $(AUDIO_ROOT)/config/konaauto.conf + INCS += -include $(AUDIO_ROOT)/config/konaautoconf.h + endif + ifeq ($(CONFIG_ARCH_LITO), y) + include $(AUDIO_ROOT)/config/litoauto.conf + export + INCS += -include $(AUDIO_ROOT)/config/litoautoconf.h + endif +endif + +# As per target team, build is done as follows: +# Defconfig : build with default flags +# Slub : defconfig + CONFIG_SLUB_DEBUG := y + +# CONFIG_SLUB_DEBUG_ON := y + CONFIG_PAGE_POISONING := y +# Perf : Using appropriate msmXXXX-perf_defconfig +# +# Shipment builds (user variants) should not have any debug feature +# enabled. This is identified using 'TARGET_BUILD_VARIANT'. Slub builds +# are identified using the CONFIG_SLUB_DEBUG_ON configuration. Since +# there is no other way to identify defconfig builds, QTI internal +# representation of perf builds (identified using the string 'perf'), +# is used to identify if the build is a slub or defconfig one. This +# way no critical debug feature will be enabled for perf and shipment +# builds. Other OEMs are also protected using the TARGET_BUILD_VARIANT +# config. + +############ UAPI ############ +UAPI_DIR := uapi +UAPI_INC := -I$(AUDIO_ROOT)/include/$(UAPI_DIR) + +############ COMMON ############ +COMMON_DIR := include +COMMON_INC := -I$(AUDIO_ROOT)/$(COMMON_DIR) + +############ max98927 ############ +ifdef CONFIG_SND_SOC_MAX98927 + MAX98927_OBJS += max98927.o +endif + +LINUX_INC += -Iinclude/linux + +INCS += $(COMMON_INC) \ + $(UAPI_INC) + +EXTRA_CFLAGS += $(INCS) + + +CDEFINES += -DANI_LITTLE_BYTE_ENDIAN \ + -DANI_LITTLE_BIT_ENDIAN \ + -DDOT11F_LITTLE_ENDIAN_HOST \ + -DANI_COMPILER_TYPE_GCC \ + -DANI_OS_TYPE_ANDROID=6 \ + -DPTT_SOCK_SVC_ENABLE \ + -Wall\ + -Werror\ + -D__linux__ + +KBUILD_CPPFLAGS += $(CDEFINES) + +# Currently, for versions of gcc which support it, the kernel Makefile +# is disabling the maybe-uninitialized warning. Re-enable it for the +# AUDIO driver. Note that we must use EXTRA_CFLAGS here so that it +# will override the kernel settings. +ifeq ($(call cc-option-yn, -Wmaybe-uninitialized),y) +EXTRA_CFLAGS += -Wmaybe-uninitialized +endif +#EXTRA_CFLAGS += -Wmissing-prototypes + +ifeq ($(call cc-option-yn, -Wheader-guard),y) +EXTRA_CFLAGS += -Wheader-guard +endif + +ifeq ($(KERNEL_BUILD), 0) +KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/ipc/Module.symvers +KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/dsp/Module.symvers +KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/Module.symvers +KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/codecs/Module.symvers +KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/soc/Module.symvers +endif + +# Module information used by KBuild framework +obj-$(CONFIG_SND_SOC_MAX98927) += max98927_dlkm.o +max98927_dlkm-y := $(MAX98927_OBJS) + +# inject some build related information +DEFINES += -DBUILD_TIMESTAMP=\"$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')\" diff --git a/techpack/audio/asoc/codecs/max98927/max98927.c b/techpack/audio/asoc/codecs/max98927/max98927.c new file mode 100644 index 000000000000..3a63ea9660bd --- /dev/null +++ b/techpack/audio/asoc/codecs/max98927/max98927.c @@ -0,0 +1,2225 @@ +/* + * max98927.c -- ALSA SoC Stereo MAX98927 driver + * Copyright 2013-15 Maxim Integrated Products + * 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 "max98927.h" + +//#undef pr_info +//#define pr_info pr_err + +//#undef pr_debug +//#define pr_debug pr_err + +//suzhiguang +int smartpa_present = 0; +EXPORT_SYMBOL_GPL(smartpa_present); + +struct max98927_priv *g_max98927 = NULL; +EXPORT_SYMBOL_GPL(g_max98927); + +#define USE_DSM_MISC_DEV 1 + +#ifdef USE_DSM_MISC_DEV +extern int afe_dsm_rx_set_params(uint8_t *payload, int size); +extern int afe_dsm_rx_get_params(uint8_t *payload, int size); +extern int afe_dsm_set_calib(uint8_t* payload); +extern int afe_dsm_pre_calib(uint8_t* payload); +extern int afe_dsm_post_calib(uint8_t* payload); +extern int afe_dsm_get_calib(uint8_t* payload); +extern int afe_dsm_get_average_calib(uint8_t* payload); +extern int afe_dsm_ramp_dn_cfg(uint8_t *payload, int delay_in_ms); +extern int afe_dsm_get_libary_info(uint32_t* payload, int size); +static DEFINE_MUTEX(dsm_lock); +#endif + +static int max98927_info_rivision_ctl(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo); +static int max98927_get_rivision_ctl(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int max98927_set_rivision_ctl(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + +#define Q_DSM_ADAPTIVE_FC 9 +#define Q_DSM_ADAPTIVE_DC_RES 27 + +static unsigned int i2c_states = 0; +static int delay_array_msec[] = {10, 20, 30, 40, 50}; + +int reg_common_map[][2] = { + {MAX98927_Brownout_level_infinite_hold, 0x00}, + {MAX98927_Brownout_level_hold, 0x00}, + {MAX98927_Brownout__level_1_current_limit, 0x14}, + {MAX98927_Brownout__level_1_amp_1_control_1, 0x00}, + {MAX98927_Brownout__level_1_amp_1_control_2, 0x0c}, + {MAX98927_Brownout__level_1_amp_1_control_3, 0x00}, + {MAX98927_Brownout__level_2_current_limit, 0x10}, + {MAX98927_Brownout__level_2_amp_1_control_1, 0x00}, + {MAX98927_Brownout__level_2_amp_1_control_2, 0x0c}, + {MAX98927_Brownout__level_2_amp_1_control_3, 0x00}, + {MAX98927_Brownout__level_3_current_limit, 0x0c}, + {MAX98927_Brownout__level_3_amp_1_control_1, 0x06}, + {MAX98927_Brownout__level_3_amp_1_control_2, 0x18}, + {MAX98927_Brownout__level_3_amp_1_control_3, 0x0c}, + {MAX98927_Brownout__level_4_current_limit, 0x08}, + {MAX98927_Brownout__level_4_amp_1_control_1, 0x0e}, + {MAX98927_Brownout__level_4_amp_1_control_2, 0x80}, + {MAX98927_Brownout__level_4_amp_1_control_3, 0x00}, + {MAX98927_Brownout_threshold_hysterysis, 0x00}, + {MAX98927_Brownout_AMP_limiter_attack_release, 0x00}, + {MAX98927_Brownout_AMP_gain_attack_release, 0x00}, + {MAX98927_Brownout_AMP1_clip_mode, 0x00}, + {MAX98927_Meas_ADC_Config, 0x07}, + {MAX98927_Meas_ADC_Thermal_Warning_Threshhold, 0x78}, + {MAX98927_Meas_ADC_Thermal_Shutdown_Threshhold, 0xFF}, + {MAX98927_Pin_Config, 0x55}, + {MAX98927_Measurement_DSP_Config, 0xF7}, + {MAX98927_PCM_Tx_Enables_B, 0x00}, + {MAX98927_PCM_Rx_Enables_B, 0x00}, + {MAX98927_PCM_Tx_Channel_Sources_B, 0x00}, + {MAX98927_PCM_Tx_HiZ_Control_B, 0xFF}, + {MAX98927_Measurement_enables, 0x03}, + {MAX98927_PDM_Rx_Enable, 0x00}, + {MAX98927_AMP_volume_control, 0x38}, + {MAX98927_AMP_DSP_Config, 0x33}, + {MAX98927_DRE_Control, 0x01}, + {MAX98927_Speaker_Gain, 0x05}, + {MAX98927_SSM_Configuration, 0x85}, + {MAX98927_Boost_Control_0, 0x0c}, + {MAX98927_Boost_Control_1, 0x3e}, + {MAX98927_Meas_ADC_Base_Divide_MSByte, 0x00}, + {MAX98927_Meas_ADC_Base_Divide_LSByte, 0x00}, + {MAX98927_Meas_ADC_Thermal_Hysteresis, 0x00}, + {MAX98927_Env_Tracker_Vout_Headroom, 0x08}, + {MAX98927_Env_Tracker_Control, 0x01}, + {MAX98927_Brownout_enables, 0x00}, +}; + +int reg_channel_map[][7][2] = { + { //mono + {MAX98927_Boost_Control_3, 0x01}, + {MAX98927_PCM_Tx_Channel_Sources_A, 0x01}, + {MAX98927_PCM_Rx_Enables_A, 0x03}, + {MAX98927_PCM_Tx_Enables_A, 0x03}, + {MAX98927_PCM_Tx_HiZ_Control_A, 0xFC}, + {MAX98927_PCM_to_speaker_monomix_A, 0x80}, + {MAX98927_PCM_to_speaker_monomix_B, 0x00}, + }, + { //left channel + {MAX98927_Boost_Control_3, 0x01}, + {MAX98927_PCM_Tx_Channel_Sources_A, 0x00}, + {MAX98927_PCM_Rx_Enables_A, 0x01}, + {MAX98927_PCM_Tx_Enables_A, 0x01}, + {MAX98927_PCM_Tx_HiZ_Control_A, 0xFE}, + {MAX98927_PCM_to_speaker_monomix_A, 0x80}, + {MAX98927_PCM_to_speaker_monomix_B, 0x00}, + }, + { // right channel + {MAX98927_Boost_Control_3, 0x09}, + {MAX98927_PCM_Tx_Channel_Sources_A, 0x11}, + {MAX98927_PCM_Rx_Enables_A, 0x02}, + {MAX98927_PCM_Tx_Enables_A, 0x02}, + {MAX98927_PCM_Tx_HiZ_Control_A, 0xFD}, + {MAX98927_PCM_to_speaker_monomix_A, 0x81}, + {MAX98927_PCM_to_speaker_monomix_B, 0x01}, + }, + +}; + +static bool max98927_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MAX98927_Interrupt_Raw_1: + case MAX98927_Interrupt_Raw_2: + case MAX98927_Interrupt_Raw_3: + case MAX98927_Interrupt_State_1: + case MAX98927_Interrupt_State_2: + case MAX98927_Interrupt_State_3: + case MAX98927_Interrupt_Flag_1: + case MAX98927_Interrupt_Flag_2: + case MAX98927_Interrupt_Flag_3: + case MAX98927_Interrupt_Enable_1: + case MAX98927_Interrupt_Enable_2: + case MAX98927_Interrupt_Enable_3: + case MAX98927_IRQ_Control: + case MAX98927_Clock_monitor_enable: + case MAX98927_Watchdog_Control: + case MAX98927_Meas_ADC_Thermal_Warning_Threshhold: + case MAX98927_Meas_ADC_Thermal_Shutdown_Threshhold: + case MAX98927_Meas_ADC_Thermal_Hysteresis: + case MAX98927_Pin_Config: + case MAX98927_PCM_Rx_Enables_A: + case MAX98927_PCM_Rx_Enables_B: + case MAX98927_PCM_Tx_Enables_A: + case MAX98927_PCM_Tx_Enables_B: + case MAX98927_PCM_Tx_HiZ_Control_A: + case MAX98927_PCM_Tx_HiZ_Control_B: + case MAX98927_PCM_Tx_Channel_Sources_A: + case MAX98927_PCM_Tx_Channel_Sources_B: + case MAX98927_PCM_Mode_Config: + case MAX98927_PCM_Master_Mode: + case MAX98927_PCM_Clock_setup: + case MAX98927_PCM_Sample_rate_setup_1: + case MAX98927_PCM_Sample_rate_setup_2: + case MAX98927_PCM_to_speaker_monomix_A: + case MAX98927_PCM_to_speaker_monomix_B: + case MAX98927_ICC_RX_Enables_A: + case MAX98927_ICC_RX_Enables_B: + case MAX98927_ICC_TX_Enables_A: + case MAX98927_ICC_TX_Enables_B: + case MAX98927_ICC_Data_Order_Select: + case MAX98927_ICC_HiZ_Manual_Mode: + case MAX98927_ICC_TX_HiZ_Enables_A: + case MAX98927_ICC_TX_HiZ_Enables_B: + case MAX98927_ICC_Link_Enables: + case MAX98927_PDM_Tx_Enables: + case MAX98927_PDM_Tx_HiZ_Control: + case MAX98927_PDM_Tx_Control: + case MAX98927_PDM_Rx_Enable: + case MAX98927_AMP_volume_control: + case MAX98927_AMP_DSP_Config: + case MAX98927_Tone_Generator_and_DC_Config: + case MAX98927_DRE_Control: + case MAX98927_AMP_enables: + case MAX98927_Speaker_source_select: + case MAX98927_Speaker_Gain: + case MAX98927_SSM_Configuration: + case MAX98927_Measurement_enables: + case MAX98927_Measurement_DSP_Config: + case MAX98927_Boost_Control_0: + case MAX98927_Boost_Control_3: + case MAX98927_Boost_Control_1: + case MAX98927_Meas_ADC_Config: + case MAX98927_Meas_ADC_Base_Divide_MSByte: + case MAX98927_Meas_ADC_Base_Divide_LSByte: + case MAX98927_Meas_ADC_Chan_0_Divide: + case MAX98927_Meas_ADC_Chan_1_Divide: + case MAX98927_Meas_ADC_Chan_2_Divide: + case MAX98927_Meas_ADC_Chan_0_Filt_Config: + case MAX98927_Meas_ADC_Chan_1_Filt_Config: + case MAX98927_Meas_ADC_Chan_2_Filt_Config: + case MAX98927_Meas_ADC_Chan_0_Readback: + case MAX98927_Meas_ADC_Chan_1_Readback: + case MAX98927_Meas_ADC_Chan_2_Readback: + case MAX98927_Brownout_status: + case MAX98927_Brownout_enables: + case MAX98927_Brownout_level_infinite_hold: + case MAX98927_Brownout_level_hold: + case MAX98927_Brownout__level_1_threshold: + case MAX98927_Brownout__level_2_threshold: + case MAX98927_Brownout__level_3_threshold: + case MAX98927_Brownout__level_4_threshold: + case MAX98927_Brownout_threshold_hysterysis: + case MAX98927_Brownout_AMP_limiter_attack_release: + case MAX98927_Brownout_AMP_gain_attack_release: + case MAX98927_Brownout_AMP1_clip_mode: + case MAX98927_Brownout__level_1_current_limit: + case MAX98927_Brownout__level_1_amp_1_control_1: + case MAX98927_Brownout__level_1_amp_1_control_2: + case MAX98927_Brownout__level_1_amp_1_control_3: + case MAX98927_Brownout__level_2_current_limit: + case MAX98927_Brownout__level_2_amp_1_control_1: + case MAX98927_Brownout__level_2_amp_1_control_2: + case MAX98927_Brownout__level_2_amp_1_control_3: + case MAX98927_Brownout__level_3_current_limit: + case MAX98927_Brownout__level_3_amp_1_control_1: + case MAX98927_Brownout__level_3_amp_1_control_2: + case MAX98927_Brownout__level_3_amp_1_control_3: + case MAX98927_Brownout__level_4_current_limit: + case MAX98927_Brownout__level_4_amp_1_control_1: + case MAX98927_Brownout__level_4_amp_1_control_2: + case MAX98927_Brownout__level_4_amp_1_control_3: + case MAX98927_Env_Tracker_Vout_Headroom: + case MAX98927_Env_Tracker_Boost_Vout_Delay: + case MAX98927_Env_Tracker_Release_Rate: + case MAX98927_Env_Tracker_Hold_Rate: + case MAX98927_Env_Tracker_Control: + case MAX98927_Env_Tracker__Boost_Vout_ReadBack: + case MAX98927_Global_Enable: + case MAX98927_REV_ID: + return true; + default: + return false; + } +} + +static bool max98927_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case MAX98927_Interrupt_Raw_1: + case MAX98927_Interrupt_Raw_2: + case MAX98927_Interrupt_Raw_3: + case MAX98927_Interrupt_State_1: + case MAX98927_Interrupt_State_2: + case MAX98927_Interrupt_State_3: + case MAX98927_Interrupt_Flag_1: + case MAX98927_Interrupt_Flag_2: + case MAX98927_Interrupt_Flag_3: + case MAX98927_Meas_ADC_Chan_0_Readback: + case MAX98927_Meas_ADC_Chan_1_Readback: + case MAX98927_Meas_ADC_Chan_2_Readback: + case MAX98927_Brownout_status: + case MAX98927_Env_Tracker__Boost_Vout_ReadBack: + return true; + default: + return false; + } +} + +#ifdef USE_DSM_MISC_DEV +#define PKG_HEADER (48) +#define PAYLOAD_COUNT (110) + +#ifdef CONFIG_DEBUG_FS +typedef enum { + DSM_API_MONO_SPKER = 0x00000000,//the mono speaker + DSM_API_STEREO_SPKER = 0x03000000,//the stereo speakers + + DSM_API_L_CHAN = 0x01000000,//the left channel speaker Id + DSM_API_R_CHAN = 0x02000000,//the left channel speaker Id + + DSM_API_CHANNEL_1 = 0x01000000, + DSM_API_CHANNEL_2 = 0x02000000, + DSM_API_CHANNEL_3 = 0x04000000, + DSM_API_CHANNEL_4 = 0x08000000, + DSM_API_CHANNEL_5 = 0x10000000, + DSM_API_CHANNEL_6 = 0x20000000, + DSM_API_CHANNEL_7 = 0x40000000, + DSM_API_CHANNEL_8 = 0x80000000, + + DSM_MAX_SUPPORTED_CHANNELS = 8 +} DSM_API_CHANNEL_ID; + +#define DSM_SET_MONO_PARAM(cmdId) ((cmdId&0x00FFFFFF)|DSM_API_MONO_SPKER) +#define DSM_SET_STEREO_PARAM(cmdId) ((cmdId&0x00FFFFFF)|DSM_API_STEREO_SPKER) +#define DSM_SET_LEFT_PARAM(cmdId) ((cmdId&0x00FFFFFF)|DSM_API_L_CHAN) +#define DSM_SET_RIGHT_PARAM(cmdId) ((cmdId&0x00FFFFFF)|DSM_API_R_CHAN) + +enum working_mode { + DSM_MODE_NONE = 0, + DSM_MODE_LEFT_ONLY, + DSM_MODE_RIGHT_ONLY, + DSM_MODE_LEFT_RIGHT, + DSM_MODE_RIGHT_LEFT, + DSM_MODE_CALIB_START, + DSM_MODE_CALIB_ING, + DSM_MODE_RDC, + DSM_MODE_CALIB_DONE, +}; + +typedef struct dsm_params { + uint32_t mode; + uint32_t pcount; + uint32_t pdata[PAYLOAD_COUNT]; +} dsm_param_t; + +struct param_info { + int pid; + char name[80]; + int q_val; +}; + + +//MULTIPLE = 3.33, rdc/(1<<27) * MULTIPLE = [min, max] ohm +#define RDC_MIN (241833636) //1.801801 * (1<<27), 1.801801 * MULTIPLE = 6 ohm +#define RDC_MAX (403056239) //3.003003 * (1<<27), 3.003003 * MULTIPLE = 10 ohm + +#endif + +static uint32_t gParam[PKG_HEADER+PAYLOAD_COUNT]; + +static int maxdsm_open(struct inode *inode, struct file *filep) +{ + return 0; +} + +#define ADAPTIVE_FC (16) +#define ADAPTIVE_DC_RES (18) + +static ssize_t maxdsm_read(struct file *filep, char __user *buf, + size_t count, loff_t *ppos) +{ + int rc; + uint8_t *payload = (uint8_t *)&gParam[PKG_HEADER]; + + if (count > sizeof(uint32_t)*PAYLOAD_COUNT) + count = sizeof(uint32_t)*PAYLOAD_COUNT; + + mutex_lock(&dsm_lock); + rc = afe_dsm_rx_get_params(payload, sizeof(uint32_t)*PAYLOAD_COUNT); + + if (rc != 0) { + pr_err("%s: afe_dsm_rx_get_params failed - %d\n", __func__, rc); + } + rc = copy_to_user(buf, payload, count); + if (rc != 0) { + pr_err("%s: copy_to_user failed - %d\n", __func__, rc); + } + mutex_unlock(&dsm_lock); + + return rc; +} + +static ssize_t maxdsm_write(struct file *filep, const char __user *buf, + size_t count, loff_t *ppos) +{ + int rc; + uint8_t *payload = (uint8_t *)&gParam[PKG_HEADER]; + + if (count > sizeof(uint32_t)*PAYLOAD_COUNT) + count = sizeof(uint32_t)*PAYLOAD_COUNT; + + mutex_lock(&dsm_lock); + rc = copy_from_user(payload, buf, count); + if (rc != 0) { + pr_err("%s: copy_from_user failed - %d\n", __func__, rc); + goto exit; + } + + afe_dsm_rx_set_params(payload, count); +exit: + mutex_unlock(&dsm_lock); + + return rc; +} + +static const struct file_operations dsm_ctrl_fops = { + .owner = THIS_MODULE, + .open = maxdsm_open, + .release = NULL, + .read = maxdsm_read, + .write = maxdsm_write, + .mmap = NULL, + .poll = NULL, + .fasync = NULL, + .llseek = NULL, +}; + +static struct miscdevice dsm_ctrl_miscdev = { + .minor = MISC_DYNAMIC_MINOR, + .name = "dsm_ctrl_dev", + .fops = &dsm_ctrl_fops +}; +#endif + +#ifdef CONFIG_DEBUG_FS +/* max. length of a alsa mixer control name */ +#define MAX_CONTROL_NAME 48 +#define CALIBRATE_FILE "/persist/spkr_calibration.bin" +#define CALIBRATE_FILE_R "/persist/spkr_calibration_r.bin" + +#if 0 +static int max989xx_create_calibfile(void) +{ + struct file *pfile = NULL; + mm_segment_t old_fs; + int ret = 0; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + pfile = filp_open(CALIBRATE_FILE, O_RDWR | O_CREAT, 0666); + if (!IS_ERR(pfile)) { + pr_info("%s: %s create success! \n", __func__, CALIBRATE_FILE); + filp_close(pfile, NULL); + } else { + pr_info("%s: %s create failed! \n", __func__, CALIBRATE_FILE); + ret = -1; + } + + set_fs(old_fs); + + return ret; + +} +#endif + +static int max989xx_calib_save(uint32_t calib_value) +{ + struct file *pfile = NULL; + mm_segment_t old_fs; + int ret = 0; + loff_t pos = 0; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + pfile = filp_open(CALIBRATE_FILE, O_RDWR | O_CREAT, 0666); + if (!IS_ERR(pfile)) { + pr_info("%s: save calib_value=%d \n", __func__, calib_value); + vfs_write(pfile, (char *)&calib_value, sizeof(uint32_t), &pos); + filp_close(pfile, NULL); + } else { + pr_info("%s: %s open failed! \n", __func__, CALIBRATE_FILE); + ret = -1; + } + + set_fs(old_fs); + + return ret; +} + +static int max989xx_calib_save_right(uint32_t calib_value) +{ + struct file *pfile = NULL; + mm_segment_t old_fs; + int ret = 0; + loff_t pos = 0; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + + pfile = filp_open(CALIBRATE_FILE_R, O_RDWR | O_CREAT, 0666); + if (!IS_ERR(pfile)) { + pr_info("%s: save calib_value=%d \n", __func__, calib_value); + vfs_write(pfile, (char *)&calib_value, sizeof(uint32_t), &pos); + filp_close(pfile, NULL); + } else { + pr_info("%s: %s open failed! \n", __func__, CALIBRATE_FILE_R); + ret = -1; + } + + set_fs(old_fs); + + return ret; +} + +static bool rdc_check_valid(uint32_t rdc) +{ + if (rdc > RDC_MIN && rdc < RDC_MAX) { + return true; + } + + pr_info("%s: rdc=%d invalid, [%d, %d] \n", __func__, rdc, RDC_MIN, RDC_MAX); + return false; +} + +static ssize_t max989xx_dbgfs_calibrate_read(struct file *file, + char __user *user_buf, size_t count, + loff_t *ppos) +{ + struct i2c_client *i2c = file->private_data; + struct max98927_priv *max989xx = i2c_get_clientdata(i2c); + uint32_t *payload = (uint32_t *)&gParam[PKG_HEADER]; + int ret = 0; + uint32_t impedance_l, impedance_r; + uint32_t calibrate_done = 2; + char *str; + //wait for playback stabilization + pr_info("%s: enter... \n", __func__); + mutex_lock(&dsm_lock); + ret = afe_dsm_pre_calib((uint8_t* )payload); + ret |= afe_dsm_get_calib((uint8_t* )payload); + if (ret == 0) { + impedance_l = *payload; + impedance_r = *(payload+1); + if (!rdc_check_valid(impedance_l)) { + impedance_l = 0xCACACACA; //calibration failed specail code + *payload = 0xCACACACA; + } + max989xx->ref_RDC[MAX98927L] = impedance_l; + max989xx_calib_save(impedance_l); + + if (max989xx->mono_stereo == 3) { + if (!rdc_check_valid(impedance_r)) { + impedance_r = 0xCACACACA; //calibration failed specail code + *(payload+1) = 0xCACACACA; + } + max989xx->ref_RDC[MAX98927R] = impedance_r; + max989xx_calib_save_right(impedance_r); + } + + afe_dsm_set_calib((uint8_t *)(payload)); + } else { + pr_info("%s failed to calibrate \n", __func__); + ret = -EIO; + goto exit; + } + + str = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!str) { + pr_info("%s failed to kmalloc \n", __func__); + ret = -ENOMEM; + goto exit; + } + + pr_info("%s: calibrate [impedance]=%d \n", __func__, impedance_l); + ret = snprintf(str, PAGE_SIZE, "%d:%d\n",calibrate_done, impedance_l); + if (max989xx->mono_stereo == 3) { + pr_info("%s: calibrate [impedance_r]=%d \n", __func__, impedance_r); + ret += snprintf(str+ret, PAGE_SIZE, "%d\n", impedance_r); + } + ret = simple_read_from_buffer(user_buf, count, ppos, str, ret); + kfree(str); + +exit: + afe_dsm_post_calib((uint8_t* )payload); + mutex_unlock(&dsm_lock); + return ret; +} + +static ssize_t max989xx_dbgfs_impedance_read(struct file *file, + char __user *user_buf, size_t count, + loff_t *ppos) +{ + struct i2c_client *i2c = file->private_data; + struct max98927_priv *max989xx = i2c_get_clientdata(i2c); + uint32_t *payload = (uint32_t *)&gParam[PKG_HEADER]; + int ret = 0; + uint32_t impedance = 0, impedance_r = 0; + char *str; + + afe_dsm_get_calib((uint8_t *)payload); + impedance = *payload; + if (!rdc_check_valid(impedance)) { + pr_info("%s failed to read impedance. \n", __func__); + ret = -EIO; + goto exit; + } + + if (max989xx->mono_stereo == 3) { + impedance_r = *(payload + 1); + if (!rdc_check_valid(impedance_r)) { + pr_info("%s failed to read impedance_r. \n", __func__); + ret = -EIO; + goto exit; + } + } + + str = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!str) { + pr_info("%s failed to kmalloc \n", __func__); + ret = -ENOMEM; + goto exit; + } + + pr_info("%s: [impedance] = %d \n", __func__, impedance); + ret = snprintf(str, PAGE_SIZE, "%d\n", impedance); + if (max989xx->mono_stereo == 3) { + pr_info("%s: [impedance_r] = %d \n", __func__, impedance_r); + ret += snprintf(str+ret, PAGE_SIZE, "%d\n", impedance_r); + } + ret = simple_read_from_buffer(user_buf, count, ppos, str, ret); + kfree(str); + +exit: + + return ret; +} + +static struct snd_kcontrol_new max98927_at_controls[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "SPK_PA rivision", + .info = max98927_info_rivision_ctl, + .get = max98927_get_rivision_ctl, + .put = max98927_set_rivision_ctl, + }, +}; + +static ssize_t max98927_state_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + pr_err("%s",__func__); + + return 0; +} +static ssize_t max98927_state_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + + struct max98927_priv *max989xx = g_max98927; + uint32_t *payload = (uint32_t *)&gParam[PKG_HEADER]; + int ret = 0; + uint32_t impedance_l, impedance_r; + uint32_t calibrate_done = 2; + char *str; + + //wait for playback stabilization + pr_info("%s: enter... \n", __func__); + mutex_lock(&dsm_lock); + ret = afe_dsm_pre_calib((uint8_t* )payload); + ret |= afe_dsm_get_calib((uint8_t* )payload); + if (ret == 0) { + impedance_l = *payload; + impedance_r = *(payload+1); + if (!rdc_check_valid(impedance_l)) { + impedance_l = 0xCACACACA; //calibration failed specail code + *payload = 0xCACACACA; + } + max989xx->ref_RDC[MAX98927L] = impedance_l; +// impedance = impedance_l; + max989xx_calib_save(impedance_l); + + if (max989xx->mono_stereo == 3) { + if (!rdc_check_valid(impedance_r)) { + impedance_r = 0xCACACACA; //calibration failed specail code + *(payload+1) = 0xCACACACA; + } + max989xx->ref_RDC[MAX98927R] = impedance_r; + max989xx_calib_save_right(impedance_r); + } + + afe_dsm_set_calib((uint8_t *)(payload)); + } else { + pr_info("%s failed to calibrate \n", __func__); + ret = -EIO; + goto exit; + } + + str = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!str) { + pr_info("%s failed to kmalloc \n", __func__); + ret = -ENOMEM; + goto exit; + } + + pr_info("%s: calibrate [impedance]=%d \n", __func__, impedance_l); + ret = snprintf(str, PAGE_SIZE, "%d\n", impedance_l); + if (max989xx->mono_stereo == 3) { + pr_info("%s: calibrate [impedance_r]=%d \n", __func__, impedance_r); + ret += snprintf(str+ret, PAGE_SIZE, "%d\n", impedance_r); + } + + ret = sprintf(buf,"%d:%d\n",calibrate_done,impedance_l); + + kfree(str); + +exit: + + afe_dsm_post_calib((uint8_t* )payload); + mutex_unlock(&dsm_lock); + return ret; +} + +static struct device_attribute max98927_state_attr = + __ATTR(calibra, 0444, max98927_state_show, max98927_state_store); + + +struct dsm_info_t { + int32_t averageTemp[2]; + int32_t bits_per_sample; + int32_t sampling_rate; + int32_t Q_factor; + int32_t working_mode; + int32_t enable_flag; + int32_t num_channels; + int32_t maxTempQ19[2]; //Q19, in Hz, valid floating-point range = [0, 4194304) + int32_t minTempQ19[2]; //Q19, in Hz, valid floating-point range = [0, 4194304) + int32_t maxFcQ9[2]; //Q9, in Hz, valid floating-point range = [0, 4194304) + int32_t minFcQ9[2]; //Q9, in Hz, valid floating-point range = [0, 4194304) + int32_t maxRdcQ27[2]; //Q27, valid floating-point range = [0, 16) + int32_t minRdcQ27[2]; //Q27 +}; +static ssize_t max989xx_dbgfs_info_read(struct file *file, + char __user *user_buf, size_t count, + loff_t *ppos) +{ + //struct i2c_client *i2c = file->private_data; + //struct max98927_priv *max989xx = i2c_get_clientdata(i2c); + uint32_t *payload = (uint32_t *)&gParam[PKG_HEADER]; + int ret = 0; + struct dsm_info_t* pInfo; + char *str; + + afe_dsm_get_libary_info(payload, 100); + pInfo = (struct dsm_info_t* ) payload; + + str = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!str) { + pr_info("%s failed to kmalloc \n", __func__); + ret = -ENOMEM; + goto exit; + } + + pr_info("%s: [average temp] = %d \n", __func__, pInfo->averageTemp[0]); + ret = snprintf(str, PAGE_SIZE, "%d\n", pInfo->averageTemp[0]); + ret = simple_read_from_buffer(user_buf, count, ppos, str, ret); + kfree(str); + +exit: + + return ret; +} + +static ssize_t max989xx_dbgfs_f0_read(struct file *file, + char __user *user_buf, size_t count, + loff_t *ppos) +{ + //struct i2c_client *i2c = file->private_data; + //struct max98927_priv *max989xx = i2c_get_clientdata(i2c); + uint32_t *payload = (uint32_t *)&gParam[PKG_HEADER]; + int ret = 0; + uint32_t f0 = 0; + char *str; + + afe_dsm_get_calib((uint8_t *)payload); + f0 = *(payload+2); + if (!rdc_check_valid(f0)) { + pr_info("%s failed to read f0. \n", __func__); + ret = -EIO; + goto exit; + } + + str = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!str) { + pr_info("%s failed to kmalloc \n", __func__); + ret = -ENOMEM; + goto exit; + } + + pr_info("%s: [f0] = %d \n", __func__, f0); + ret = snprintf(str, PAGE_SIZE, "%d\n", f0); + ret = simple_read_from_buffer(user_buf, count, ppos, str, ret); + kfree(str); + +exit: + + return ret; +} + + +static ssize_t max989xx_dbgfs_temperature_read(struct file *file, + char __user *user_buf, size_t count, + loff_t *ppos) +{ + //struct i2c_client *i2c = file->private_data; + //struct max98927_priv *max989xx = i2c_get_clientdata(i2c); + uint32_t *payload = (uint32_t *)&gParam[PKG_HEADER]; + int ret = 0; + uint32_t coiltemp = 0; + char *str; + + + afe_dsm_get_calib((uint8_t *)payload); + coiltemp = *(payload + 4); + pr_info("%s: [coiltemp] = %d \n", __func__, coiltemp); + + str = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!str) { + pr_info("%s failed to kmalloc \n", __func__); + ret = -ENOMEM; + goto exit; + } + + ret = snprintf(str, PAGE_SIZE, "%d\n", coiltemp); + ret = simple_read_from_buffer(user_buf, count, ppos, str, ret); + kfree(str); + +exit: + + return ret; +} + +static const struct file_operations max989xx_dbgfs_calibrate_fops = { + .open = simple_open, + .read = max989xx_dbgfs_calibrate_read, + .llseek = default_llseek, +}; + +static const struct file_operations max989xx_dbgfs_impedance_fops = { + .open = simple_open, + .read = max989xx_dbgfs_impedance_read, + .llseek = default_llseek, +}; + +static const struct file_operations max989xx_dbgfs_f0_fops = { + .open = simple_open, + .read = max989xx_dbgfs_f0_read, + .llseek = default_llseek, +}; +static const struct file_operations max989xx_dbgfs_temperature_fops = { + .open = simple_open, + .read = max989xx_dbgfs_temperature_read, + .llseek = default_llseek, +}; + +static const struct file_operations max989xx_dbgfs_info_fops = { + .open = simple_open, + .read = max989xx_dbgfs_info_read, + .llseek = default_llseek, +}; + +static void max989xx_debug_init(struct max98927_priv *max989xx, struct i2c_client *i2c) +{ + char name[60]; + + scnprintf(name, MAX_CONTROL_NAME, "%s", i2c->name); + max989xx->dbg_dir = debugfs_create_dir(name, NULL); + debugfs_create_file("calibrate", S_IRUGO|S_IWUGO, max989xx->dbg_dir, + i2c, &max989xx_dbgfs_calibrate_fops); + debugfs_create_file("impedance", S_IRUGO|S_IWUGO, max989xx->dbg_dir, + i2c, &max989xx_dbgfs_impedance_fops); + debugfs_create_file("f0detect", S_IRUGO|S_IWUGO, max989xx->dbg_dir, + i2c, &max989xx_dbgfs_f0_fops); + debugfs_create_file("temperature", S_IRUGO|S_IWUGO, max989xx->dbg_dir, + i2c, &max989xx_dbgfs_temperature_fops); + debugfs_create_file("infomation", S_IRUGO|S_IWUGO, max989xx->dbg_dir, + i2c, &max989xx_dbgfs_info_fops); + +} + +static void max989xx_debug_remove(struct max98927_priv *max989xx) +{ + if (max989xx->dbg_dir) + debugfs_remove_recursive(max989xx->dbg_dir); +} +#endif + +static int max989xx_calib_get(uint32_t* calib_value) +{ + struct file *pfile = NULL; + mm_segment_t old_fs; + int found = 0; + loff_t pos = 0; + + *calib_value = 0; + old_fs = get_fs(); + set_fs(KERNEL_DS); + + pfile = filp_open(CALIBRATE_FILE, O_RDONLY, 0); + if (!IS_ERR_OR_NULL(pfile)) { + found = 1; + vfs_read(pfile, (char *)calib_value, sizeof(uint32_t), &pos); + pr_info("%s get calib_value %d \n", __func__, *calib_value); + filp_close(pfile, NULL); + } else { + pr_info("%s No found\n", __func__); + found = 0; + } + + set_fs(old_fs); + + return found; +} + +static int max989xx_calib_get_r(uint32_t* calib_value) +{ + struct file *pfile = NULL; + mm_segment_t old_fs; + int found = 0; + loff_t pos = 0; + + *calib_value = 0; + old_fs = get_fs(); + set_fs(KERNEL_DS); + + pfile = filp_open(CALIBRATE_FILE_R, O_RDONLY, 0); + if (!IS_ERR_OR_NULL(pfile)) { + found = 1; + vfs_read(pfile, (char *)calib_value, sizeof(uint32_t), &pos); + pr_info("%s get calib_value %d \n", __func__, *calib_value); + filp_close(pfile, NULL); + } else { + pr_info("%s No found\n", __func__); + found = 0; + } + + set_fs(old_fs); + + return found; +} + + +int max98927_wrapper_read(struct max98927_priv *max98927, bool speaker, + unsigned int reg, unsigned int *val) +{ + int ret = -1; + if(i2c_states & (1 << speaker)){ + ret = regmap_read(max98927->regmap[speaker], reg, val); + } + return ret; +} + +void max98927_wrapper_write(struct max98927_priv *max98927, + unsigned int reg, unsigned int val) +{ + int i; + for(i = 0; i < MAX_CHANNEL_NUM; i++){ + if(i2c_states & (1 << i)){ + regmap_write(max98927->regmap[i], reg, val); + } + } +} + +void max98927_wrap_update_bits(struct max98927_priv *max98927, + unsigned int reg, unsigned int mask, unsigned int val) +{ + int i; + for(i = 0; i < MAX_CHANNEL_NUM; i++){ + if(i2c_states & (1 << i)){ + regmap_update_bits(max98927->regmap[i], reg, mask, val); + } + } +} + +static int max98927_reg_get_w(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + int reg = mc->reg; + unsigned int shift = mc->shift; + int max = mc->max; + unsigned int mask = (1 << fls(max)) - 1; + unsigned int invert = mc->invert; + unsigned int val; + + max98927_wrapper_read(max98927, 0, reg, &val); + + val = (val >> shift) & mask; + + if (invert) + ucontrol->value.integer.value[0] = max - val; + else + ucontrol->value.integer.value[0] = val; + + return 0; +} + +static int max98927_reg_put_w(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + int reg = mc->reg; + unsigned int shift = mc->shift; + int max = mc->max; + unsigned int mask = (1 << fls(max)) - 1; + unsigned int invert = mc->invert; + + unsigned int val = (ucontrol->value.integer.value[0] & mask); + if (invert) + val = max - val; + mask = mask << shift; + val = val << shift; + + max98927_wrap_update_bits(max98927, reg, mask, val); + pr_info("%s: register 0x%02X, value 0x%02X\n", + __func__, reg, val); + return 0; +} +static int max98927_reg_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol, unsigned int reg, + unsigned int mask, unsigned int shift) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + int data; + + max98927_wrapper_read(max98927, 0, reg, &data); + ucontrol->value.integer.value[0] = + (data & mask) >> shift; + return 0; +} + +static int max98927_reg_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol, unsigned int reg, + unsigned int mask, unsigned int shift) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + + unsigned int sel = ucontrol->value.integer.value[0]; + max98927_wrap_update_bits(max98927, reg, mask, sel << shift); + pr_info("%s: register 0x%02X, value 0x%02X\n", + __func__, reg, sel); + return 0; +} + +static int max98927_dai_set_fmt(struct snd_soc_dai *codec_dai, + unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + + pr_info("%s: fmt 0x%08X\n", __func__, fmt); + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + max98927_wrap_update_bits(max98927, MAX98927_PCM_Master_Mode, + MAX98927_PCM_Master_Mode_PCM_MSTR_MODE_Mask, + MAX98927_PCM_Master_Mode_PCM_MSTR_MODE_SLAVE); + break; + case SND_SOC_DAIFMT_CBM_CFM: + max98927->master = true; + max98927_wrap_update_bits(max98927, MAX98927_PCM_Master_Mode, + MAX98927_PCM_Master_Mode_PCM_MSTR_MODE_Mask, + MAX98927_PCM_Master_Mode_PCM_MSTR_MODE_MASTER); + break; + case SND_SOC_DAIFMT_CBS_CFM: + max98927_wrap_update_bits(max98927, MAX98927_PCM_Master_Mode, + MAX98927_PCM_Master_Mode_PCM_MSTR_MODE_Mask, + MAX98927_PCM_Master_Mode_PCM_MSTR_MODE_HYBRID); + break; + default: + pr_info("DAI clock mode unsupported"); + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + max98927_wrap_update_bits(max98927, MAX98927_PCM_Mode_Config, + MAX98927_PCM_Mode_Config_PCM_BCLKEDGE, + 0); + break; + case SND_SOC_DAIFMT_IB_NF: + max98927_wrap_update_bits(max98927, MAX98927_PCM_Mode_Config, + MAX98927_PCM_Mode_Config_PCM_BCLKEDGE, + MAX98927_PCM_Mode_Config_PCM_BCLKEDGE); + break; + default: + pr_info("DAI invert mode unsupported"); + return -EINVAL; + } + + /* interface format */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + max98927->iface |= SND_SOC_DAIFMT_I2S; + max98927_wrap_update_bits(max98927, MAX98927_PCM_Mode_Config, + MAX98927_PCM_Mode_Config_PCM_FORMAT_Mask, + MAX98927_PCM_Mode_Config_PCM_FORMAT_I2S); + break; + case SND_SOC_DAIFMT_LEFT_J: + max98927->iface |= SND_SOC_DAIFMT_LEFT_J; + max98927_wrap_update_bits(max98927, MAX98927_PCM_Mode_Config, + MAX98927_PCM_Mode_Config_PCM_FORMAT_Mask, + MAX98927_PCM_Mode_Config_PCM_FORMAT_LEFT); + break; + default: + return -EINVAL; + } + return 0; +} + +/* codec MCLK rate in master mode */ +static const int rate_table[] = { + 5644800, 6000000, 6144000, 6500000, + 9600000, 11289600, 12000000, 12288000, + 13000000, 19200000, +}; + +static int max98927_set_clock(struct max98927_priv *max98927, + struct snd_pcm_hw_params *params) +{ + /* BCLK/LRCLK ratio calculation */ + int blr_clk_ratio = 2 * max98927->ch_size; + int reg = MAX98927_PCM_Clock_setup; + int mask = MAX98927_PCM_Clock_setup_PCM_BSEL_Mask; + int value; + + if (max98927->master) { + int i; + /* match rate to closest value */ + for (i = 0; i < ARRAY_SIZE(rate_table); i++) { + if (rate_table[i] >= max98927->sysclk) + break; + } + if (i == ARRAY_SIZE(rate_table)) { + pr_err("%s couldn't get the MCLK to match codec\n", __func__); + return -EINVAL; + } + max98927_wrap_update_bits(max98927, MAX98927_PCM_Master_Mode, + MAX98927_PCM_Master_Mode_PCM_MCLK_RATE_Mask, + i << MAX98927_PCM_Master_Mode_PCM_MCLK_RATE_SHIFT); + } + + switch (blr_clk_ratio) { + case 32: + value = 2; + break; + case 48: + value = 3; + break; + case 64: + value = 4; + break; + default: + return -EINVAL; + } + + pr_info("%s: BLCK fix to %d\n", __func__, blr_clk_ratio); + max98927_wrap_update_bits(max98927, + reg, mask, value); + return 0; +} + +static int max98927_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + int sampling_rate = 0; + + switch (snd_pcm_format_width(params_format(params))) { + case 16: + max98927_wrap_update_bits(max98927, + MAX98927_PCM_Mode_Config, + MAX98927_PCM_Mode_Config_PCM_CHANSZ_Mask, + MAX98927_PCM_Mode_Config_PCM_CHANSZ_16); + max98927->ch_size = 16; + break; + case 24: + //max98927_wrap_update_bits(max98927, + // MAX98927_PCM_Mode_Config, + // MAX98927_PCM_Mode_Config_PCM_CHANSZ_Mask, + // MAX98927_PCM_Mode_Config_PCM_CHANSZ_24); + //max98927->ch_size = 24; + //break; + case 32: + max98927_wrap_update_bits(max98927, + MAX98927_PCM_Mode_Config, + MAX98927_PCM_Mode_Config_PCM_CHANSZ_Mask, + MAX98927_PCM_Mode_Config_PCM_CHANSZ_32); + max98927->ch_size = 32; + break; + default: + pr_err("%s: format unsupported %d", + __func__, params_format(params)); + goto err; + } + pr_info("%s: format supported %d", + __func__, max98927->ch_size); + + switch (params_rate(params)) { + case 8000: + sampling_rate |= + MAX98927_PCM_Sample_rate_setup_1_DIG_IF_SR_8000; + break; + case 11025: + sampling_rate |= + MAX98927_PCM_Sample_rate_setup_1_DIG_IF_SR_11025; + break; + case 12000: + sampling_rate |= + MAX98927_PCM_Sample_rate_setup_1_DIG_IF_SR_12000; + break; + case 16000: + sampling_rate |= + MAX98927_PCM_Sample_rate_setup_1_DIG_IF_SR_16000; + break; + case 22050: + sampling_rate |= + MAX98927_PCM_Sample_rate_setup_1_DIG_IF_SR_22050; + break; + case 24000: + sampling_rate |= + MAX98927_PCM_Sample_rate_setup_1_DIG_IF_SR_24000; + break; + case 32000: + sampling_rate |= + MAX98927_PCM_Sample_rate_setup_1_DIG_IF_SR_32000; + break; + case 44100: + sampling_rate |= + MAX98927_PCM_Sample_rate_setup_1_DIG_IF_SR_44100; + break; + case 48000: + sampling_rate |= + MAX98927_PCM_Sample_rate_setup_1_DIG_IF_SR_48000; + break; + default: + pr_err("%s rate %d not supported\n", __func__, params_rate(params)); + goto err; + } + /* set DAI_SR to correct LRCLK frequency */ + max98927_wrap_update_bits(max98927, MAX98927_PCM_Sample_rate_setup_1, + MAX98927_PCM_Sample_rate_setup_1_DIG_IF_SR_Mask, sampling_rate); + max98927_wrap_update_bits(max98927, MAX98927_PCM_Sample_rate_setup_2, + MAX98927_PCM_Sample_rate_setup_2_SPK_SR_Mask, sampling_rate<<4); + if (max98927->interleave_mode){ + max98927_wrap_update_bits(max98927, MAX98927_PCM_Sample_rate_setup_2, + MAX98927_PCM_Sample_rate_setup_2_IVADC_SR_Mask, (sampling_rate-3)); + } else { + max98927_wrap_update_bits(max98927, MAX98927_PCM_Sample_rate_setup_2, + MAX98927_PCM_Sample_rate_setup_2_IVADC_SR_Mask, sampling_rate); + } + + return max98927_set_clock(max98927, params); +err: + return -EINVAL; +} + +#define MAX98927_RATES SNDRV_PCM_RATE_8000_48000 + +#define MAX98927_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) + +static int max98927_dai_set_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = dai->codec; + struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + pr_info("%s: clk_id %d, freq %d, dir %d\n", __func__, clk_id, freq, dir); + + max98927->sysclk = freq; + return 0; +} + +static int max98927_stream_mute(struct snd_soc_dai *codec_dai, int mute, int stream) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + uint32_t* payload = (uint32_t *)&gParam[PKG_HEADER]; + int rc = 0; + uint32_t impedance = 0; + + pr_info("%s--- stream %d, mute %d \n", __func__, stream, mute); + + if (!max98927) { + pr_err("%s ------ priv data null pointer\n", __func__); + return 0; + } + + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + if (mute) { + if (max98927->path_status) + afe_dsm_ramp_dn_cfg((uint8_t*)payload, 25); + max98927_wrap_update_bits(max98927, MAX98927_Global_Enable, MAX98927_Global_Enable_EN, 0); + max98927_wrap_update_bits(max98927, MAX98927_AMP_enables, MAX98927_AMP_enables, 0); + max98927->spk_mode = 0; + pr_info("%s ------ disable max98927 playback \n", __func__); + } else { + if (max98927->mono_stereo == 0x3) { // in stereo mode , we need put some changes into mixer ctl + if (max98927->spk_mode & (0x1 << MAX98927L)) { + regmap_update_bits(max98927->regmap[MAX98927L], MAX98927_AMP_enables, + MAX98927_AMP_enables_SPK_EN, 1); + regmap_update_bits(max98927->regmap[MAX98927L], MAX98927_Global_Enable, + MAX98927_Global_Enable_EN, 1); + } else if (max98927->spk_mode & (0x1 << MAX98927R)) { + regmap_update_bits(max98927->regmap[MAX98927R], MAX98927_AMP_enables, + MAX98927_AMP_enables_SPK_EN, 1); + regmap_update_bits(max98927->regmap[MAX98927R], MAX98927_Global_Enable, + MAX98927_Global_Enable_EN, 1); + } + } else { + max98927_wrap_update_bits(max98927, MAX98927_AMP_enables, MAX98927_AMP_enables_SPK_EN, 1); + max98927_wrap_update_bits(max98927, MAX98927_Global_Enable, MAX98927_Global_Enable_EN, 1); + } + + pr_info("%s ------ enable max98927 playback \n", __func__); + } + } else if(stream == SNDRV_PCM_STREAM_CAPTURE) { //feedback path disable and enable + if (mute) { + /* max98927_wrapper_write(max98927, MAX98927_Measurement_enables, 0x0); */ + max98927->path_status = 0; + pr_info("%s ------ disable max98927 capture\n", __func__); + } else { + max98927_wrapper_write(max98927, MAX98927_Measurement_enables, 0x3); + max98927->path_status |= i2c_states; // flag to status of feedback (0: means feedback is inactive, other: feedback is active, DSM should be started to protect speaker) + if (max98927->mono_stereo == 0x0 || (max98927->mono_stereo & 0x1)) { + if (!rdc_check_valid(max98927->ref_RDC[MAX98927L]) && max98927->ref_RDC[MAX98927L] != 0xCACACACA){ + rc = max989xx_calib_get(&impedance); + if (rdc_check_valid(impedance) || impedance == 0xCACACACA) { + max98927->ref_RDC[MAX98927L] = impedance; + pr_info("%s: ref_RDC left =%d \n", __func__, max98927->ref_RDC[MAX98927L]); + } + } + } + if (max98927->mono_stereo & 0x2) { + if (!rdc_check_valid(max98927->ref_RDC[MAX98927R]) && max98927->ref_RDC[MAX98927R] != 0xCACACACA){ + impedance = 0; + rc = max989xx_calib_get_r(&impedance); + if (rdc_check_valid(impedance) || impedance == 0xCACACACA) { + max98927->ref_RDC[MAX98927R] = impedance; + pr_info("%s: ref_RDC right=%d \n", __func__, max98927->ref_RDC[MAX98927R]); + } + } + } + mutex_lock(&dsm_lock); + *payload = max98927->ref_RDC[MAX98927L]; + *(payload+1) = max98927->ref_RDC[MAX98927R]; + afe_dsm_set_calib((uint8_t *)payload); + //load calibration to DSM + mutex_unlock(&dsm_lock); + pr_info("%s ------ enable max98927 capture\n", __func__); + } + } + + return 0; +} + +static const struct snd_soc_dai_ops max98927_dai_ops = { + .set_sysclk = max98927_dai_set_sysclk, + .set_fmt = max98927_dai_set_fmt, + .hw_params = max98927_dai_hw_params, + .mute_stream = max98927_stream_mute, +}; + +static int max98927_feedforward_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + u32 ret = 0; + //struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + /* uint32_t* payload = (uint32_t *)&gParam[PKG_HEADER]; */ + + if(!max98927){ + pr_err("%s------priv data null pointer\n", __func__); + return ret; + } + pr_info("%s---feedforward event %d\n", __func__, event); + switch(event){ + case SND_SOC_DAPM_POST_PMU: + break; + case SND_SOC_DAPM_POST_PMD: + break; + case SND_SOC_DAPM_PRE_PMU: + break; + case SND_SOC_DAPM_PRE_PMD: + break; + default: + break; + } + return ret; +} +static int max98927_feedback_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + u32 ret = 0; + //struct snd_soc_codec *codec = w->codec; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + if(!max98927){ + pr_err("%s------priv data null pointer\n", __func__); + return ret; + } + pr_info("%s---feedback event %d\n", __func__, event); + switch(event){ + case SND_SOC_DAPM_POST_PMU: + /* max98927_wrapper_write(max98927, MAX98927_Measurement_enables, 0x3); */ + break; + case SND_SOC_DAPM_POST_PMD: + /* max98927_wrapper_write(max98927, MAX98927_Measurement_enables, 0x0); */ + break; + default: + break; + } + return ret; +} + +static const struct snd_soc_dapm_widget max98927_dapm_widgets[] = { + SND_SOC_DAPM_DAC_E("DACs", "HiFi Playback", SND_SOC_NOPM, 0, 0, + max98927_feedforward_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("ADCs", "HiFi Capture", SND_SOC_NOPM, 0, 0, + max98927_feedback_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_INPUT("MAX98927_IN"), + SND_SOC_DAPM_OUTPUT("MAX98927_OUT"), +}; + +/*zhiguang.su@MultiMediaService,2017-04-26,add ftm spk pa rivision test*/ +static int max98927_info_rivision_ctl(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + pr_err("%s\n", __func__); + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 5; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 5; + + return 0; +} + +static int max98927_get_rivision_ctl(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + int ret; + unsigned int reg; + + pr_err("%s\n", __func__); + ret = regmap_read(max98927->regmap[0], MAX98927_REV_ID , ®); + if (ret < 0) { + pr_err("%s Failed to read Revision register: %d\n", + __func__, ret); + ucontrol->value.integer.value[0] = 0; + }else + ucontrol->value.integer.value[0] = 1; + + return 0; +} + +static int max98927_set_rivision_ctl(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_err("%s\n", __func__); + ucontrol->value.integer.value[0] = 0; + return 1; +} + +static DECLARE_TLV_DB_SCALE(max98927_spk_tlv, 300, 300, 0); +static DECLARE_TLV_DB_SCALE(max98927_digital_tlv, -1600, 25, 0); + +static int max98927_spk_gain_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = max98927->spk_gain; + pr_info("max98927_spk_gain_get: spk_gain setting returned %d\n", + (int) ucontrol->value.integer.value[0]); + + return 0; +} + +static int max98927_spk_gain_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + unsigned int sel = ucontrol->value.integer.value[0]; + pr_info("max98927_spk_gain_put: %d\n",sel); + + if (sel < ((1 << MAX98927_Speaker_Gain_Width) - 1)) { + max98927_wrap_update_bits(max98927, MAX98927_Speaker_Gain, + MAX98927_Speaker_Gain_SPK_PCM_GAIN_Mask, sel); + max98927->spk_gain = sel; + } + return 0; +} + +static int max98927_digital_gain_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = max98927->digital_gain; + pr_info("%s: spk_gain setting returned %d\n", __func__, + (int) ucontrol->value.integer.value[0]); + return 0; +} + +static int max98927_digital_gain_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + unsigned int sel = ucontrol->value.integer.value[0]; + pr_info("max98927_digital_gain_put: %d\n",sel); + + if (sel <= ((1 << MAX98927_AMP_VOL_WIDTH) - 1)) { + max98927_wrap_update_bits(max98927, MAX98927_AMP_volume_control, + MAX98927_AMP_volume_control_AMP_VOL_Mask, sel); + max98927->digital_gain = sel; + } + return 0; +} + +static int max98927_boost_voltage_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + return max98927_reg_get(kcontrol, ucontrol, MAX98927_Boost_Control_0, + MAX98927_Boost_Control_0_BST_VOUT_Mask, 0); +} + +static int max98927_boost_voltage_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + return max98927_reg_put(kcontrol, ucontrol, MAX98927_Boost_Control_0, + MAX98927_Boost_Control_0_BST_VOUT_Mask, 0); +} + +static int max98927_boost_input_limit_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + return max98927_reg_get(kcontrol, ucontrol, MAX98927_Boost_Control_1, + MAX98927_Boost_Control_1_BST_ILIM_Mask, MAX98927_BST_ILIM_SHIFT); +} + +static int max98927_boost_input_limit_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + return max98927_reg_put(kcontrol, ucontrol, MAX98927_Boost_Control_1, + MAX98927_Boost_Control_1_BST_ILIM_Mask, MAX98927_BST_ILIM_SHIFT); +} + +static int max98927_spk_src_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + return max98927_reg_get(kcontrol, ucontrol, MAX98927_Speaker_source_select, + MAX98927_Speaker_source_select_SPK_SOURCE_Mask, 0); +} + +static int max98927_spk_src_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + return max98927_reg_put(kcontrol, ucontrol, MAX98927_Speaker_source_select, + MAX98927_Speaker_source_select_SPK_SOURCE_Mask, 0); +} + +static int max98927_mono_out_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + return max98927_reg_get(kcontrol, ucontrol, MAX98927_PCM_to_speaker_monomix_A, + MAX98927_PCM_to_speaker_monomix_A_DMONOMIX_CH0_SOURCE_Mask, 0); +} + +static int max98927_mono_out_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + return max98927_reg_put(kcontrol, ucontrol, MAX98927_PCM_to_speaker_monomix_A, + MAX98927_PCM_to_speaker_monomix_A_DMONOMIX_CH0_SOURCE_Mask, 0); +} + +static int max98927_mono_out_get_l(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + int data = 0; + if(i2c_states & MAX98927_CH0){ + regmap_read(max98927->regmap[MAX98927L], MAX98927_PCM_to_speaker_monomix_A, &data); + ucontrol->value.integer.value[0] = + (data & MAX98927_PCM_to_speaker_monomix_A_DMONOMIX_CH0_SOURCE_Mask); + pr_info("%s: value:%d", __func__, data); + } + + return 0; +} + +static int max98927_mono_out_put_l(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + unsigned int sel = ucontrol->value.integer.value[0]; + + if(i2c_states & MAX98927_CH0){ + regmap_update_bits(max98927->regmap[MAX98927L], MAX98927_PCM_to_speaker_monomix_A, + MAX98927_PCM_to_speaker_monomix_A_DMONOMIX_CH0_SOURCE_Mask, sel); + regmap_update_bits(max98927->regmap[MAX98927L], MAX98927_PCM_Rx_Enables_A, + 0xf, sel+1); + pr_info("%s: register 0x%02X, value 0x%02X\n", + __func__, MAX98927_PCM_to_speaker_monomix_A, sel); + } + + return 0; +} + +static int max98927_mono_out_get_r(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + int data = 0; + + if(i2c_states & MAX98927_CH1){ + regmap_read(max98927->regmap[MAX98927R], MAX98927_PCM_to_speaker_monomix_A, &data); + ucontrol->value.integer.value[0] = + (data & MAX98927_PCM_to_speaker_monomix_A_DMONOMIX_CH0_SOURCE_Mask); + } + pr_info("%s: value:%d", __func__, data); + return 0; +} + +static int max98927_mono_out_put_r(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + unsigned int sel = ucontrol->value.integer.value[0]; + if(i2c_states & MAX98927_CH1){ + regmap_update_bits(max98927->regmap[MAX98927R], MAX98927_PCM_to_speaker_monomix_A, + MAX98927_PCM_to_speaker_monomix_A_DMONOMIX_CH0_SOURCE_Mask, sel); + regmap_update_bits(max98927->regmap[MAX98927R], MAX98927_PCM_Rx_Enables_A, 0xf, sel+1); + pr_info("%s: register 0x%02X, value 0x%02X\n", + __func__, MAX98927_PCM_to_speaker_monomix_A, sel); + } else { + pr_info("%s: mono mode not support!!\n", __func__); + } + return 0; +} + +static int max98927_feedback_en_get_l(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + int data = 0; + + if(i2c_states & MAX98927_CH0){ + regmap_read(max98927->regmap[MAX98927L], MAX98927_Measurement_enables, &data); + ucontrol->value.integer.value[0] = data; + pr_info("%s: value:%d", __func__, data); + } + + return 0; +} + +static int max98927_feedback_en_put_l(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + unsigned int sel = ucontrol->value.integer.value[0]; + + if(i2c_states & MAX98927_CH0){ + regmap_write(max98927->regmap[MAX98927L], MAX98927_Measurement_enables, sel); + pr_info("%s: register 0x%02X, value 0x%02X\n", + __func__, MAX98927_Measurement_enables, sel); + } + return 0; +} + +static int max98927_feedback_en_get_r(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + int data = 0; + + if(i2c_states & MAX98927_CH1){ + regmap_read(max98927->regmap[MAX98927R], MAX98927_Measurement_enables, &data); + ucontrol->value.integer.value[0] = data; + } + pr_info("%s: value:%d", __func__, data); + return 0; +} + +static int max98927_feedback_en_put_r(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + unsigned int sel = ucontrol->value.integer.value[0]; + if(i2c_states & MAX98927_CH1){ + regmap_write(max98927->regmap[MAX98927R], MAX98927_Measurement_enables, sel); + pr_info("%s: register 0x%02X, value 0x%02X\n", + __func__, MAX98927_Measurement_enables, sel); + } else { + pr_info("%s: mono mode not support!!\n", __func__); + } + return 0; +} + +static int max98927_left_channel_enable_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + int data_global = 0; + int data_amp = 0; + //int data = 0; + + if(i2c_states & MAX98927_CH0){ + regmap_read(max98927->regmap[MAX98927L], MAX98927_Global_Enable, &data_global); + regmap_read(max98927->regmap[MAX98927L], MAX98927_AMP_enables, &data_amp); + ucontrol->value.integer.value[0] = (data_global & MAX98927_Global_Enable_EN) + & (data_amp & MAX98927_AMP_enables_SPK_EN); + } + + pr_info("%s: value:%d", __func__, (int)ucontrol->value.integer.value[0]); + return 0; +} + +static int max98927_left_channel_enable_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + unsigned int sel = ucontrol->value.integer.value[0]; + max98927->spk_mode &= ~0x1; + max98927->spk_mode |= sel; + + pr_info("%s: register 0x%02X, value 0x%02X\n", + __func__, MAX98927_Global_Enable, sel); + return 0; +} + +static int max98927_right_channel_enable_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + int data_global = 0; + int data_amp = 0; + + if(i2c_states & MAX98927_CH1){ + regmap_read(max98927->regmap[MAX98927R], MAX98927_Global_Enable, &data_global); + regmap_read(max98927->regmap[MAX98927R], MAX98927_AMP_enables, &data_amp); + ucontrol->value.integer.value[0] = (data_global & MAX98927_Global_Enable_EN) + & (data_amp & MAX98927_AMP_enables_SPK_EN); + } + + pr_info("%s: value:%d", __func__, (int)ucontrol->value.integer.value[0]); + return 0; +} + +static int max98927_right_channel_enable_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + unsigned int sel = ucontrol->value.integer.value[0]; + max98927->spk_mode &= ~0x2; + max98927->spk_mode |= sel<<0x1; + pr_info("%s: register 0x%02X, value 0x%02X\n", + __func__, MAX98927_Global_Enable, sel); + return 0; +} + +static const char * const max98927_boost_voltage_text[] = { + "6.5V", "6.625V", "6.75V", "6.875V", "7V", "7.125V", "7.25V", "7.375V", + "7.5V", "7.625V", "7.75V", "7.875V", "8V", "8.125V", "8.25V", "8.375V", + "8.5V", "8.625V", "8.75V", "8.875V", "9V", "9.125V", "9.25V", "9.375V", + "9.5V", "9.625V", "9.75V", "9.875V", "10V" +}; + +static const char * const max98927_boost_current_limit_text[] = { + "1.0A", "1.1A", "1.2A", "1.3A", "1.4A", "1.5A", "1.6A", "1.7A", "1.8A", "1.9A", + "2.0A", "2.1A", "2.2A", "2.3A", "2.4A", "2.5A", "2.6A", "2.7A", "2.8A", "2.9A", + "3.0A", "3.1A", "3.2A", "3.3A", "3.4A", "3.5A", "3.6A", "3.7A", "3.8A", "3.9A", + "4.0A", "4.1A" +}; + +static const char * const max98927_speaker_source_text[] = { + "i2s", "reserved", "tone", "pdm" +}; + +static const char * const max98927_monomix_output_text[] = { + "ch_0", "ch_1", "ch_1_2_div" +}; +static const char * const max98927_feedback_switch_text[] = { + "OFF", "V_EN", "I_EN", "ON" +}; + +static const struct soc_enum max98927_enum[] = { + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(max98927_monomix_output_text), max98927_monomix_output_text), + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(max98927_speaker_source_text), max98927_speaker_source_text), + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(max98927_boost_voltage_text), max98927_boost_voltage_text), + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(max98927_feedback_switch_text), max98927_feedback_switch_text), + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(max98927_boost_current_limit_text), max98927_boost_current_limit_text), +}; + +static const struct snd_kcontrol_new max98927_snd_controls[] = { + SOC_SINGLE_EXT_TLV("Speaker Volume", MAX98927_Speaker_Gain, + 0, (1<dapm; + struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); + + pr_info("%s: enter\n", __func__); + + max98927->codec = codec; + snd_soc_dapm_ignore_suspend(dapm, "MAX98927_OUT"); + snd_soc_dapm_ignore_suspend(dapm, "MAX98927_IN"); + snd_soc_dapm_ignore_suspend(dapm, "HiFi Playback"); + snd_soc_dapm_ignore_suspend(dapm, "HiFi Capture"); + + snd_soc_add_codec_controls(max98927->codec, max98927_at_controls, + ARRAY_SIZE(max98927_at_controls)); + + + snd_soc_dapm_sync(dapm); + + g_max98927 = max98927; + return 0; +} + +static const struct snd_soc_codec_driver soc_codec_dev_max98927 = { + .probe = max98927_probe, + .component_driver = { + .dapm_routes = max98927_audio_map, + .num_dapm_routes = ARRAY_SIZE(max98927_audio_map), + .dapm_widgets = max98927_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(max98927_dapm_widgets), + .controls = max98927_snd_controls, + .num_controls = ARRAY_SIZE(max98927_snd_controls), + }, +}; + +static const struct regmap_config max98927_regmap = { + .reg_bits = 16, + .val_bits = 8, + .max_register = MAX98927_REV_ID, + .readable_reg = max98927_readable_register, + .volatile_reg = max98927_volatile_register, + .cache_type = REGCACHE_RBTREE, +}; + +int max98927_get_i2c_states(void) +{ + return i2c_states; +} +EXPORT_SYMBOL(max98927_get_i2c_states); + +static int max98927_reset(struct i2c_client *i2c, struct max98927_priv* max98927) +{ + int ret = 0; + max98927->reset_gpio_l= of_get_named_gpio(i2c->dev.of_node, "maxim,98927-reset-gpio", 0); + pr_info("max98927_reset:%d------\n", max98927->reset_gpio_l); + + if (max98927->reset_gpio_l > 0){ + ret = gpio_request(max98927->reset_gpio_l, "max_98927_reset"); + if (ret) { + pr_err("max98927_i2c_probe : failed to request rest gpio %d error:%d\n", + max98927->reset_gpio_l, ret); + gpio_free(max98927->reset_gpio_l); + return ret; + } + gpio_direction_output(max98927->reset_gpio_l, 0); + msleep(10); + gpio_direction_output(max98927->reset_gpio_l, 1); + msleep(5); + } + return ret; +} + +static bool check_max98927_presence(struct regmap* regmap) +{ + int rc = 0, reg = 0, i; + + rc = regmap_read(regmap, MAX98927_REV_ID, ®); + for (i = 0; rc && i < ARRAY_SIZE(delay_array_msec); i++) { + pr_err("Failed reading version=%u - retry(%d)\n", reg, i); + /* retry after delay of increasing order */ + msleep(delay_array_msec[i]); + rc = regmap_read(regmap, MAX98927_REV_ID, ®); + } + if (rc) { + pr_err("Failed reading version=%u rc=%d\n", reg, rc); + return false; + }else{ + pr_info("max98927 device version 0x%02X\n", reg); + return true; + } +} +static int max98927_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + static struct max98927_priv *max98927 = NULL; + int value, i, ret = 0; + unsigned int presence = 0; + + pr_err("****** %s id.name =%s id.driver_data= %d \n",__func__,id->name,(int)(id->driver_data)); + + if (!max98927) { + max98927 = devm_kzalloc(&i2c->dev, + sizeof(*max98927), GFP_KERNEL); + if (!max98927) { + pr_info("------%s devm_kzalloc error!!\n", __func__); + return -ENOMEM; + } + } + if (!of_property_read_u32(i2c->dev.of_node, "mono_stereo_mode", &value)) { + if (value > 3) { + pr_err("only support max to 2 channel!\n"); + value = 0; + } + max98927->mono_stereo = value; // 0: mono 1: left only 2: right only 3: stereo + } + + if (!of_property_read_u32(i2c->dev.of_node, "interleave_mode", &value)) { + if (value > 1) { + pr_info("interleave number is wrong:\n"); + } + max98927->interleave_mode = value; + } +#if 0 + if (!max98927->i2c_pull) { + max98927->i2c_pull = devm_regulator_get(&i2c->dev, "i2c-pull"); + if (IS_ERR(max98927->i2c_pull)) { + pr_err("regulator i2c_pull get failed\n "); + devm_kfree(&i2c->dev, max98927); + return PTR_ERR(max98927->i2c_pull); + } + + ret = regulator_enable(max98927->i2c_pull); + if (ret) { + pr_err("regulator_enable i2c_pull failed! \n"); + devm_kfree(&i2c->dev, max98927); + return ret; + } + } + max98927->max989xx_vdd = regulator_get(&i2c->dev, "max989xx_vdd"); + if (IS_ERR(max98927->max989xx_vdd)) { + pr_err("regulator max989xx_vdd get failed\n "); + devm_kfree(&i2c->dev, max98927); + return PTR_ERR(max98927->max989xx_vdd); + } else { + if (regulator_count_voltages(max98927->max989xx_vdd) > 0) { + ret = regulator_set_voltage(max98927->max989xx_vdd, 1800000, 1800000); + if (ret) { + pr_err("%s Regulator set vdd failed ret=%d\n", __func__, ret); + return ret; + } + + ret = regulator_set_load(max98927->max989xx_vdd, 200000); + if (ret) { + pr_err("%s failed to set load, ret=%d\n", __func__, ret); + return ret; + } + } + } + + ret = regulator_enable(max98927->max989xx_vdd); + if (ret) { + pr_err("regulator_enable max989xx_vdd failed! \n"); + devm_kfree(&i2c->dev, max98927); + return ret; + } +#endif + + ret = max98927_reset(i2c, max98927); // reset pin to chip hardware reset. + + i2c_set_clientdata(i2c, max98927); + + max98927->regmap[id->driver_data] = + devm_regmap_init_i2c(i2c, &max98927_regmap); + if(IS_ERR(max98927->regmap[id->driver_data])){ + ret = PTR_ERR(max98927->regmap[id->driver_data]); + dev_err(&i2c->dev, + "Failed to allocate chennel %lu regmap : %d\n", id->driver_data, ret); + }else{ //below initialize the register by mode and chip status. + if(check_max98927_presence(max98927->regmap[id->driver_data])){ + presence = (1 << id->driver_data); + if(max98927->mono_stereo == 0){ + i2c_states |= presence; //mark this chip, then app can address it. + for (i = 0;i < sizeof(reg_channel_map[0])/sizeof(reg_channel_map[0][0]);i++) + regmap_write(max98927->regmap[id->driver_data], reg_channel_map[0][i][0], reg_channel_map[0][i][1]); + }else if(max98927->mono_stereo & presence){ + i2c_states |= presence; //mark this chip, then app can address it. + for (i = 0;i < sizeof(reg_channel_map[id->driver_data+1])/sizeof(reg_channel_map[id->driver_data+1][0]);i++) + regmap_write(max98927->regmap[id->driver_data], + reg_channel_map[id->driver_data+1][i][0], reg_channel_map[id->driver_data+1][i][1]); + } + for (i = 0;i < sizeof(reg_common_map)/sizeof(reg_common_map[0]);i++) + regmap_write(max98927->regmap[id->driver_data], reg_common_map[i][0], reg_common_map[i][1]); + + if (max98927->interleave_mode) + regmap_write(max98927->regmap[id->driver_data], MAX98927_PCM_Tx_Channel_Sources_B, 0x20); + + } + } + if(presence){ + smartpa_present = 1; + if(max98927->dev == NULL){ + dev_set_name(&i2c->dev, "%s", "max98927"); //rename the i2c clinet name for easy to use. + ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_max98927, + max98927_dai, ARRAY_SIZE(max98927_dai)); + pr_err("****** %s snd_soc_register_codec id =%d\n",__func__,(int)(id->driver_data)); + if (ret < 0) { + pr_err("max98927 Failed to register codec: %d\n", ret); + i2c_states = 0; + return ret; + } + max98927->dev = &i2c->dev; + pr_info("max98927 register codec ok.\n"); +#ifdef USE_DSM_MISC_DEV + ret = misc_register(&dsm_ctrl_miscdev); + if (ret != 0) + pr_err("max98927 misc_register error:%d\n", ret); +#endif + + #ifdef CONFIG_DEBUG_FS + max989xx_debug_init(max98927, i2c); + #endif + } + ret = sysfs_create_file(&i2c->dev.kobj, &max98927_state_attr.attr); + if(ret < 0) + { + pr_err("%s sysfs_create_file max98927_state_attr err.",__func__); + } + }else + { + pr_err("max98927 detection failed at %s - %x. \n", i2c->name, i2c->addr); + //suzhiguang,should release when no smartpa detect. + gpio_free(max98927->reset_gpio_l); + } + return ret; +} + +static int max98927_i2c_remove(struct i2c_client *client) +{ + struct max98927_priv *max98927 = i2c_get_clientdata(client); + if(max98927) { + if(max98927->dev == &client->dev) { + snd_soc_unregister_codec(&client->dev); + i2c_set_clientdata(client, NULL); +#ifdef CONFIG_DEBUG_FS + max989xx_debug_remove(max98927); +#endif + kfree(max98927); +#ifdef USE_DSM_MISC_DEV + misc_deregister(&dsm_ctrl_miscdev); +#endif + } + } + + return 0; +} + +static const struct i2c_device_id max98927_i2c_id[] = { + { "max98927L", MAX98927L }, + { "max98927R", MAX98927R }, + { }, +}; + +MODULE_DEVICE_TABLE(i2c, max98927_i2c_id); + +static const struct of_device_id max98927_of_match[] = { + { .compatible = "maxim,max98927L", }, + { .compatible = "maxim,max98927R", }, + { } +}; +MODULE_DEVICE_TABLE(of, max98927_of_match); + +static struct i2c_driver max98927_i2c_driver = { + .driver = { + .name = "max98927", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(max98927_of_match), + .pm = NULL, + }, + .probe = max98927_i2c_probe, + .remove = max98927_i2c_remove, + .id_table = max98927_i2c_id, +}; + +module_i2c_driver(max98927_i2c_driver) + +MODULE_DESCRIPTION("ALSA SoC MAX98927 driver"); +MODULE_AUTHOR("Maxim Integrated Inc."); +MODULE_LICENSE("GPL"); diff --git a/techpack/audio/asoc/codecs/max98927/max98927.h b/techpack/audio/asoc/codecs/max98927/max98927.h new file mode 100644 index 000000000000..eea40a7e4ee5 --- /dev/null +++ b/techpack/audio/asoc/codecs/max98927/max98927.h @@ -0,0 +1,1256 @@ +/* + * AnishBestPingPongerAliveButNotAsGoodAsMax.h + * + * Auto generated by Maxim Integrated, supporting revision + * Search for #BYHAND for flags on special cases to fix by hand + * #BYHAND width doesn't match: (this is usually when a bit has shorthand or formulaic descriptions) + * #BYHAND width >= 5: + */ +#ifndef __MAX98927_REGISTERDEFS_H +#define __MAX98927_REGISTERDEFS_H +#ifdef CONFIG_SND_SOC_MAXIM_DSM +#include +#endif /* CONFIG_SND_SOC_MAXIM_DSM */ + +#define MAX98927L 0 +#define MAX98927R 1 +#define MAX_CHANNEL_NUM (2) +typedef enum +{ + // Interrupt Raw 1 (Address 0x0001) + MAX98927_Interrupt_Raw_1 = 0x0001, + MAX98927_Interrupt_Raw_1_BDE_ACTIVE_END_RAW = (0x1 << 0), + MAX98927_Interrupt_Raw_1_BDE_ACTIVE_BGN_RAW = (0x1 << 1), + MAX98927_Interrupt_Raw_1_BDE_LEVEL_CHANGE_RAW = (0x1 << 2), + MAX98927_Interrupt_Raw_1_BDE_L8_RAW = (0x1 << 3), + MAX98927_Interrupt_Raw_1_THERMWARN_END_RAW = (0x1 << 4), + MAX98927_Interrupt_Raw_1_THERMWARN_START_RAW = (0x1 << 5), + MAX98927_Interrupt_Raw_1_THERMSHDN_END_RAW = (0x1 << 6), + MAX98927_Interrupt_Raw_1_THERMSHDN_START_RAW = (0x1 << 7), + + // Interrupt Raw 2 (Address 0x0002) + MAX98927_Interrupt_Raw_2 = 0x0002, + MAX98927_Interrupt_Raw_2_WATCHDOGWARN_RAW = (0x1 << 0), + MAX98927_Interrupt_Raw_2_WATCHDOGFAIL_RAW = (0x1 << 1), + MAX98927_Interrupt_Raw_2_BOOSTCURRLIM_RAW = (0x1 << 2), + MAX98927_Interrupt_Raw_2_CLKSTOP_RAW = (0x1 << 3), + MAX98927_Interrupt_Raw_2_CLKSTART_RAW = (0x1 << 4), + MAX98927_Interrupt_Raw_2_MEASADC_END_RAW = (0x1 << 5), + MAX98927_Interrupt_Raw_2_PWRDN_DONE_RAW = (0x1 << 6), + MAX98927_Interrupt_Raw_2_PWRUP_DONE_RAW = (0x1 << 7), + + // Interrupt Raw 3 (Address 0x0003) + MAX98927_Interrupt_Raw_3 = 0x0003, + MAX98927_Interrupt_Raw_3_PWRUP_FAIL_RAW = (0x1 << 0), + MAX98927_Interrupt_Raw_3_AUTH_DONE_RAW = (0x1 << 1), + MAX98927_Interrupt_Raw_3_SPK_OVC_RAW = (0x1 << 2), + MAX98927_Interrupt_Raw_3_BST_UVLO_RAW = (0x1 << 3), + + // Interrupt State 1 (Address 0x0004) + MAX98927_Interrupt_State_1 = 0x0004, + MAX98927_Interrupt_State_1_BDE_ACTIVE_END_STATE = (0x1 << 0), + MAX98927_Interrupt_State_1_BDE_ACTIVE_BGN_STATE = (0x1 << 1), + MAX98927_Interrupt_State_1_BDE_LEVEL_CHANGE_STATE = (0x1 << 2), + MAX98927_Interrupt_State_1_BDE_L8_STATE = (0x1 << 3), + MAX98927_Interrupt_State_1_THERMWARN_END_STATE = (0x1 << 4), + MAX98927_Interrupt_State_1_THERMWARN_START_STATE = (0x1 << 5), + MAX98927_Interrupt_State_1_THERMSHDN_END_STATE = (0x1 << 6), + MAX98927_Interrupt_State_1_THERMSHDN_START_STATE = (0x1 << 7), + + // Interrupt State 2 (Address 0x0005) + MAX98927_Interrupt_State_2 = 0x0005, + MAX98927_Interrupt_State_2_WATCHDOGWARN_STATE = (0x1 << 0), + MAX98927_Interrupt_State_2_WATCHDOGFAIL_STATE = (0x1 << 1), + MAX98927_Interrupt_State_2_BOOSTCURRLIM_STATE = (0x1 << 2), + MAX98927_Interrupt_State_2_CLKSTOP_STATE = (0x1 << 3), + MAX98927_Interrupt_State_2_CLKSTART_STATE = (0x1 << 4), + MAX98927_Interrupt_State_2_MEASADC_END_STATE = (0x1 << 5), + MAX98927_Interrupt_State_2_PWRDN_DONE_STATE = (0x1 << 6), + MAX98927_Interrupt_State_2_PWRUP_DONE_STATE = (0x1 << 7), + + // Interrupt State 3 (Address 0x0006) + MAX98927_Interrupt_State_3 = 0x0006, + MAX98927_Interrupt_State_3_PWRUP_FAIL_STATE = (0x1 << 0), + MAX98927_Interrupt_State_3_AUTH_DONE_STATE = (0x1 << 1), + MAX98927_Interrupt_State_3_SPK_OVC_STATE = (0x1 << 2), + MAX98927_Interrupt_State_3_BST_UVLO_STATE = (0x1 << 3), + + // Interrupt Flag 1 (Address 0x0007) + MAX98927_Interrupt_Flag_1 = 0x0007, + MAX98927_Interrupt_Flag_1_BDE_ACTIVE_END_FLAG = (0x1 << 0), + MAX98927_Interrupt_Flag_1_BDE_ACTIVE_BGN_FLAG = (0x1 << 1), + MAX98927_Interrupt_Flag_1_BDE_LEVEL_CHANGE_FLAG = (0x1 << 2), + MAX98927_Interrupt_Flag_1_BDE_L8_FLAG = (0x1 << 3), + MAX98927_Interrupt_Flag_1_THERMWARN_END_FLAG = (0x1 << 4), + MAX98927_Interrupt_Flag_1_THERMWARN_START_FLAG = (0x1 << 5), + MAX98927_Interrupt_Flag_1_THERMSHDN_END_FLAG = (0x1 << 6), + MAX98927_Interrupt_Flag_1_THERMSHDN_START_FLAG = (0x1 << 7), + + // Interrupt Flag 2 (Address 0x0008) + MAX98927_Interrupt_Flag_2 = 0x0008, + MAX98927_Interrupt_Flag_2_WATCHDOGWARN_FLAG = (0x1 << 0), + MAX98927_Interrupt_Flag_2_WATCHDOGFAIL_FLAG = (0x1 << 1), + MAX98927_Interrupt_Flag_2_BOOSTCURRLIM_FLAG = (0x1 << 2), + MAX98927_Interrupt_Flag_2_CLKSTOP_FLAG = (0x1 << 3), + MAX98927_Interrupt_Flag_2_CLKSTART_FLAG = (0x1 << 4), + MAX98927_Interrupt_Flag_2_MEASADC_END_FLAG = (0x1 << 5), + MAX98927_Interrupt_Flag_2_PWRDN_DONE_FLAG = (0x1 << 6), + MAX98927_Interrupt_Flag_2_PWRUP_DONE_FLAG = (0x1 << 7), + + // Interrupt Flag 3 (Address 0x0009) + MAX98927_Interrupt_Flag_3 = 0x0009, + MAX98927_Interrupt_Flag_3_PWRUP_FAIL_FLAG = (0x1 << 0), + MAX98927_Interrupt_Flag_3_AUTH_DONE_FLAG = (0x1 << 1), + MAX98927_Interrupt_Flag_3_SPK_OVC_FLAG = (0x1 << 2), + MAX98927_Interrupt_Flag_3_BST_UVLO_FLAG = (0x1 << 3), + + // Interrupt Enable 1 (Address 0x000a) + MAX98927_Interrupt_Enable_1 = 0x000a, + MAX98927_Interrupt_Enable_1_BDE_ACTIVE_END_EN = (0x1 << 0), + MAX98927_Interrupt_Enable_1_BDE_ACTIVE_BGN_EN = (0x1 << 1), + MAX98927_Interrupt_Enable_1_BDE_LEVEL_CHANGE_EN = (0x1 << 2), + MAX98927_Interrupt_Enable_1_BDE_L8_EN = (0x1 << 3), + MAX98927_Interrupt_Enable_1_THERMWARN_END_EN = (0x1 << 4), + MAX98927_Interrupt_Enable_1_THERMWARN_START_EN = (0x1 << 5), + MAX98927_Interrupt_Enable_1_THERMSHDN_END_EN = (0x1 << 6), + MAX98927_Interrupt_Enable_1_THERMSHDN_START_EN = (0x1 << 7), + + // Interrupt Enable 2 (Address 0x000b) + MAX98927_Interrupt_Enable_2 = 0x000b, + MAX98927_Interrupt_Enable_2_WATCHDOGWARN_EN = (0x1 << 0), + MAX98927_Interrupt_Enable_2_WATCHDOGFAIL_EN = (0x1 << 1), + MAX98927_Interrupt_Enable_2_BOOSTCURRLIM_EN = (0x1 << 2), + MAX98927_Interrupt_Enable_2_CLKSTOP_EN = (0x1 << 3), + MAX98927_Interrupt_Enable_2_CLKSTART_EN = (0x1 << 4), + MAX98927_Interrupt_Enable_2_MEASADC_END_EN = (0x1 << 5), + MAX98927_Interrupt_Enable_2_PWRDN_DONE_EN = (0x1 << 6), + MAX98927_Interrupt_Enable_2_PWRUP_DONE_EN = (0x1 << 7), + + // Interrupt Enable 3 (Address 0x000c) + MAX98927_Interrupt_Enable_3 = 0x000c, + MAX98927_Interrupt_Enable_3_PWRUP_FAIL_EN = (0x1 << 0), + MAX98927_Interrupt_Enable_3_AUTH_DONE_EN = (0x1 << 1), + MAX98927_Interrupt_Enable_3_SPK_OVC_EN = (0x1 << 2), + MAX98927_Interrupt_Enable_3_BST_UVLO_EN = (0x1 << 3), + + // Interrupt Flag Clear 1 (Address 0x000d) + MAX98927_Interrupt_Flag_Clear_1 = 0x000d, + MAX98927_Interrupt_Flag_Clear_1_BDE_ACTIVE_END_CLR = (0x1 << 0), + MAX98927_Interrupt_Flag_Clear_1_BDE_ACTIVE_BGN_CLR = (0x1 << 1), + MAX98927_Interrupt_Flag_Clear_1_BDE_LEVEL_CHANGE_CLR = (0x1 << 2), + MAX98927_Interrupt_Flag_Clear_1_BDE_L8_CLR = (0x1 << 3), + MAX98927_Interrupt_Flag_Clear_1_THERMWARN_END_CLR = (0x1 << 4), + MAX98927_Interrupt_Flag_Clear_1_THERMWARN_START_CLR = (0x1 << 5), + MAX98927_Interrupt_Flag_Clear_1_THERMSHDN_END_CLR = (0x1 << 6), + MAX98927_Interrupt_Flag_Clear_1_THERMSHDN_START_CLR = (0x1 << 7), + + // Interrupt Flag Clear 2 (Address 0x000e) + MAX98927_Interrupt_Flag_Clear_2 = 0x000e, + MAX98927_Interrupt_Flag_Clear_2_WATCHDOGWARN_CLR = (0x1 << 0), + MAX98927_Interrupt_Flag_Clear_2_WATCHDOGFAIL_CLR = (0x1 << 1), + MAX98927_Interrupt_Flag_Clear_2_BOOSTCURRLIM_CLR = (0x1 << 2), + MAX98927_Interrupt_Flag_Clear_2_CLKSTOP_CLR = (0x1 << 3), + MAX98927_Interrupt_Flag_Clear_2_CLKSTART_CLR = (0x1 << 4), + MAX98927_Interrupt_Flag_Clear_2_MEASADC_END_CLR = (0x1 << 5), + MAX98927_Interrupt_Flag_Clear_2_PWRDN_DONE_CLR = (0x1 << 6), + MAX98927_Interrupt_Flag_Clear_2_PWRUP_DONE_CLR = (0x1 << 7), + + // Interrupt Flag Clear 3 (Address 0x000f) + MAX98927_Interrupt_Flag_Clear_3 = 0x000f, + MAX98927_Interrupt_Flag_Clear_3_PWRUP_FAIL_CLR = (0x1 << 0), + MAX98927_Interrupt_Flag_Clear_3_AUTH_DONE_CLR = (0x1 << 1), + MAX98927_Interrupt_Flag_Clear_3_SPK_OVC_CLR = (0x1 << 2), + MAX98927_Interrupt_Flag_Clear_3_BST_UVLO_CLR = (0x1 << 3), + + // IRQ Control (Address 0x0010) + MAX98927_IRQ_Control = 0x0010, + MAX98927_IRQ_Control_IRQ_EN = (0x1 << 0), + MAX98927_IRQ_Control_IRQ_POL = (0x1 << 1), + MAX98927_IRQ_Control_IRQ_MODE = (0x1 << 2), + + // Clock monitor enable (Address 0x0011) + MAX98927_Clock_monitor_enable = 0x0011, + MAX98927_Clock_monitor_enable_CMON_ENA = (0x1 << 0), + MAX98927_Clock_monitor_enable_CMON_AUTORESTART_ENA = (0x1 << 1), + + // Watchdog Control (Address 0x0012) + MAX98927_Watchdog_Control = 0x0012, + MAX98927_Watchdog_Control_WDT_ENA = (0x1 << 0), + MAX98927_Watchdog_Control_WDT_MODE = (0x1 << 1), + MAX98927_Watchdog_Control_WDT_TO_SEL_Mask = (0x3 << 2), + //Specific_bit_values_goes_here + MAX98927_Watchdog_Control_WDT_TO_SEL_5 = (0x0 << 2), + MAX98927_Watchdog_Control_WDT_TO_SEL_10 = (0x1 << 2), + MAX98927_Watchdog_Control_WDT_TO_SEL_35 = (0x2 << 2), + MAX98927_Watchdog_Control_WDT_TO_SEL_50 = (0x3 << 2), + MAX98927_Watchdog_Control_WDT_HW_SOURCE = (0x1 << 4), + + // Watchdog SW Reset (Address 0x0013) + MAX98927_Watchdog_SW_Reset = 0x0013, + //#BYHAND width >= 5: + MAX98927_Watchdog_SW_Reset_WDT_SW_RST_Mask = (0xff << 0), + + // Meas ADC Thermal Warning Threshhold (Address 0x0014) + MAX98927_Meas_ADC_Thermal_Warning_Threshhold = 0x0014, + //#BYHAND width >= 5: + MAX98927_Meas_ADC_Thermal_Warning_Threshhold_MEAS_ADC_WARN_THRESH_Mask = (0xff << 0), + + // Meas ADC Thermal Shutdown Threshhold (Address 0x0015) + MAX98927_Meas_ADC_Thermal_Shutdown_Threshhold = 0x0015, + //#BYHAND width >= 5: + MAX98927_Meas_ADC_Thermal_Shutdown_Threshhold_MEAS_ADC_SHDN_THRESH_Mask = (0xff << 0), + + // Meas ADC Thermal Hysteresis (Address 0x0016) + MAX98927_Meas_ADC_Thermal_Hysteresis = 0x0016, + //#BYHAND width >= 5: + MAX98927_Meas_ADC_Thermal_Hysteresis_MEAS_ADC_THERM_HYST_Mask = (0x1f << 0), + + // Pin Config (Address 0x0017) + MAX98927_Pin_Config = 0x0017, + MAX98927_Pin_Config_DOUT_DRV_Mask = (0x3 << 0), + //Specific_bit_values_goes_here + //#BYHAND width doesn't match: 4 != 2 + MAX98927_Pin_Config_DOUT_DRV_01 = (0x0 << 0), + MAX98927_Pin_Config_DOUT_DRV_11 = (0x2 << 0), + MAX98927_Pin_Config_BCLK_DRV_Mask = (0x3 << 2), + //Specific_bit_values_goes_here + //#BYHAND width doesn't match: 4 != 2 + MAX98927_Pin_Config_BCLK_DRV_01 = (0x0 << 2), + MAX98927_Pin_Config_BCLK_DRV_11 = (0x2 << 2), + MAX98927_Pin_Config_LRCLK_DRV_Mask = (0x3 << 4), + //Specific_bit_values_goes_here + //#BYHAND width doesn't match: 4 != 2 + MAX98927_Pin_Config_LRCLK_DRV_01 = (0x0 << 4), + MAX98927_Pin_Config_LRCLK_DRV_11 = (0x2 << 4), + MAX98927_Pin_Config_ICC_DRV_Mask = (0x3 << 6), + //Specific_bit_values_goes_here + //#BYHAND width doesn't match: 4 != 2 + MAX98927_Pin_Config_ICC_DRV_01 = (0x0 << 6), + MAX98927_Pin_Config_ICC_DRV_11 = (0x2 << 6), + + // PCM Rx Enables A (Address 0x0018) + MAX98927_PCM_Rx_Enables_A = 0x0018, + MAX98927_PCM_Rx_Enables_A_PCM_RX_CH0_EN = (0x1 << 0), + MAX98927_PCM_Rx_Enables_A_PCM_RX_CH1_EN = (0x1 << 1), + MAX98927_PCM_Rx_Enables_A_PCM_RX_CH2_EN = (0x1 << 2), + MAX98927_PCM_Rx_Enables_A_PCM_RX_CH3_EN = (0x1 << 3), + MAX98927_PCM_Rx_Enables_A_PCM_RX_CH4_EN = (0x1 << 4), + MAX98927_PCM_Rx_Enables_A_PCM_RX_CH5_EN = (0x1 << 5), + MAX98927_PCM_Rx_Enables_A_PCM_RX_CH6_EN = (0x1 << 6), + MAX98927_PCM_Rx_Enables_A_PCM_RX_CH7_EN = (0x1 << 7), + + // PCM Rx Enables B (Address 0x0019) + MAX98927_PCM_Rx_Enables_B = 0x0019, + MAX98927_PCM_Rx_Enables_B_PCM_RX_CH8_EN = (0x1 << 0), + MAX98927_PCM_Rx_Enables_B_PCM_RX_CH9_EN = (0x1 << 1), + MAX98927_PCM_Rx_Enables_B_PCM_RX_CH10_EN = (0x1 << 2), + MAX98927_PCM_Rx_Enables_B_PCM_RX_CH11_EN = (0x1 << 3), + MAX98927_PCM_Rx_Enables_B_PCM_RX_CH12_EN = (0x1 << 4), + MAX98927_PCM_Rx_Enables_B_PCM_RX_CH13_EN = (0x1 << 5), + MAX98927_PCM_Rx_Enables_B_PCM_RX_CH14_EN = (0x1 << 6), + MAX98927_PCM_Rx_Enables_B_PCM_RX_CH15_EN = (0x1 << 7), + + // PCM Tx Enables A (Address 0x001a) + MAX98927_PCM_Tx_Enables_A = 0x001a, + MAX98927_PCM_Tx_Enables_A_PCM_TX_CH0_EN = (0x1 << 0), + MAX98927_PCM_Tx_Enables_A_PCM_TX_CH1_EN = (0x1 << 1), + MAX98927_PCM_Tx_Enables_A_PCM_TX_CH2_EN = (0x1 << 2), + MAX98927_PCM_Tx_Enables_A_PCM_TX_CH3_EN = (0x1 << 3), + MAX98927_PCM_Tx_Enables_A_PCM_TX_CH4_EN = (0x1 << 4), + MAX98927_PCM_Tx_Enables_A_PCM_TX_CH5_EN = (0x1 << 5), + MAX98927_PCM_Tx_Enables_A_PCM_TX_CH6_EN = (0x1 << 6), + MAX98927_PCM_Tx_Enables_A_PCM_TX_CH7_EN = (0x1 << 7), + + // PCM Tx Enables B (Address 0x001b) + MAX98927_PCM_Tx_Enables_B = 0x001b, + MAX98927_PCM_Tx_Enables_B_PCM_TX_CH8_EN = (0x1 << 0), + MAX98927_PCM_Tx_Enables_B_PCM_TX_CH9_EN = (0x1 << 1), + MAX98927_PCM_Tx_Enables_B_PCM_TX_CH10_EN = (0x1 << 2), + MAX98927_PCM_Tx_Enables_B_PCM_TX_CH11_EN = (0x1 << 3), + MAX98927_PCM_Tx_Enables_B_PCM_TX_CH12_EN = (0x1 << 4), + MAX98927_PCM_Tx_Enables_B_PCM_TX_CH13_EN = (0x1 << 5), + MAX98927_PCM_Tx_Enables_B_PCM_TX_CH14_EN = (0x1 << 6), + MAX98927_PCM_Tx_Enables_B_PCM_TX_CH15_EN = (0x1 << 7), + + // PCM Tx HiZ Control A (Address 0x001c) + MAX98927_PCM_Tx_HiZ_Control_A = 0x001c, + MAX98927_PCM_Tx_HiZ_Control_A_PCM_TX_CH0_HIZ = (0x1 << 0), + MAX98927_PCM_Tx_HiZ_Control_A_PCM_TX_CH1_HIZ = (0x1 << 1), + MAX98927_PCM_Tx_HiZ_Control_A_PCM_TX_CH2_HIZ = (0x1 << 2), + MAX98927_PCM_Tx_HiZ_Control_A_PCM_TX_CH3_HIZ = (0x1 << 3), + MAX98927_PCM_Tx_HiZ_Control_A_PCM_TX_CH4_HIZ = (0x1 << 4), + MAX98927_PCM_Tx_HiZ_Control_A_PCM_TX_CH5_HIZ = (0x1 << 5), + MAX98927_PCM_Tx_HiZ_Control_A_PCM_TX_CH6_HIZ = (0x1 << 6), + MAX98927_PCM_Tx_HiZ_Control_A_PCM_TX_CH7_HIZ = (0x1 << 7), + + // PCM Tx HiZ Control B (Address 0x001d) + MAX98927_PCM_Tx_HiZ_Control_B = 0x001d, + MAX98927_PCM_Tx_HiZ_Control_B_PCM_TX_CH8_HIZ = (0x1 << 0), + MAX98927_PCM_Tx_HiZ_Control_B_PCM_TX_CH9_HIZ = (0x1 << 1), + MAX98927_PCM_Tx_HiZ_Control_B_PCM_TX_CH10_HIZ = (0x1 << 2), + MAX98927_PCM_Tx_HiZ_Control_B_PCM_TX_CH11_HIZ = (0x1 << 3), + MAX98927_PCM_Tx_HiZ_Control_B_PCM_TX_CH12_HIZ = (0x1 << 4), + MAX98927_PCM_Tx_HiZ_Control_B_PCM_TX_CH13_HIZ = (0x1 << 5), + MAX98927_PCM_Tx_HiZ_Control_B_PCM_TX_CH14_HIZ = (0x1 << 6), + MAX98927_PCM_Tx_HiZ_Control_B_PCM_TX_CH15_HIZ = (0x1 << 7), + + // PCM Tx Channel Sources A (Address 0x001e) + MAX98927_PCM_Tx_Channel_Sources_A = 0x001e, + MAX98927_PCM_Tx_Channel_Sources_A_PCM_IVADC_V_DEST_Mask = (0xf << 0), + //Specific_bit_values_goes_here + //#BYHAND width doesn't match: 16 != 3 + MAX98927_PCM_Tx_Channel_Sources_A_PCM_IVADC_I_DEST_Mask = (0xf << 4), + //Specific_bit_values_goes_here + //#BYHAND width doesn't match: 16 != 3 + + // PCM Tx Channel Sources B (Address 0x001f) + MAX98927_PCM_Tx_Channel_Sources_B = 0x001f, + MAX98927_PCM_Tx_Channel_Sources_B_PCM_AMP_DSP_DEST_Mask = (0xf << 0), + //Specific_bit_values_goes_here + //#BYHAND width doesn't match: 16 != 3 + + // PCM Mode Config (Address 0x0020) + MAX98927_PCM_Mode_Config = 0x0020, + MAX98927_PCM_Mode_Config_PCM_TX_EXTRA_HIZ = (0x1 << 0), + MAX98927_PCM_Mode_Config_PCM_CHANSEL = (0x1 << 1), + MAX98927_PCM_Mode_Config_PCM_BCLKEDGE = (0x1 << 2), + MAX98927_PCM_Mode_Config_PCM_FORMAT_Mask = (0x7 << 3), + //Specific_bit_values_goes_here + //#BYHAND width doesn't match: 8 != 4 + MAX98927_PCM_Mode_Config_PCM_FORMAT_I2S = (0x0 << 3), + MAX98927_PCM_Mode_Config_PCM_FORMAT_LEFT = (0x1 << 3), + MAX98927_PCM_Mode_Config_PCM_FORMAT_TDM_0 = (0x3 << 3), + MAX98927_PCM_Mode_Config_PCM_FORMAT_TDM_1 = (0x4 << 3), + MAX98927_PCM_Mode_Config_PCM_FORMAT_TDM_2 = (0x5 << 3), + MAX98927_PCM_Mode_Config_PCM_FORMAT_ = (0x6 << 3), + MAX98927_PCM_Mode_Config_PCM_CHANSZ_Mask = (0x3 << 6), + //Specific_bit_values_goes_here + //#BYHAND width doesn't match: 4 != 2 + MAX98927_PCM_Mode_Config_PCM_CHANSZ_16 = (0x1 << 6), + MAX98927_PCM_Mode_Config_PCM_CHANSZ_24 = (0x2 << 6), + MAX98927_PCM_Mode_Config_PCM_CHANSZ_32 = (0x3 << 6), + + // PCM Master Mode (Address 0x0021) + MAX98927_PCM_Master_Mode = 0x0021, + MAX98927_PCM_Master_Mode_PCM_MSTR_MODE_Mask = (0x3 << 0), + //Specific_bit_values_goes_here + //#BYHAND width doesn't match: 4 != 2 + MAX98927_PCM_Master_Mode_PCM_MSTR_MODE_SLAVE = (0x0 << 0), + MAX98927_PCM_Master_Mode_PCM_MSTR_MODE_MASTER = (0x3 << 0), + MAX98927_PCM_Master_Mode_PCM_MSTR_MODE_HYBRID = (0x1 << 0), + MAX98927_PCM_Master_Mode_PCM_MCLK_RATE_Mask = (0xf << 2), + //Specific_bit_values_goes_here + //#BYHAND width doesn't match: 16 != 6 + MAX98927_PCM_Master_Mode_PCM_CLK_SOURCE = (0x1 << 6), + + // PCM Clock setup (Address 0x0022) + MAX98927_PCM_Clock_setup = 0x0022, + MAX98927_PCM_Clock_setup_PCM_BSEL_Mask = (0xf << 0), + //Specific_bit_values_goes_here + //#BYHAND width doesn't match: 16 != 6 + MAX98927_PCM_Clock_setup_PCM_MSEL_Mask = (0xf << 4), + //Specific_bit_values_goes_here + //#BYHAND width doesn't match: 16 != 6 + + // PCM Sample rate setup 1 (Address 0x0023) + MAX98927_PCM_Sample_rate_setup_1 = 0x0023, + MAX98927_PCM_Sample_rate_setup_1_DIG_IF_SR_Mask = (0xf << 0), + //Specific_bit_values_goes_here + //#BYHAND width doesn't match: 16 != 8 + MAX98927_PCM_Sample_rate_setup_1_DIG_IF_SR_8000 = (0x0 << 0), + MAX98927_PCM_Sample_rate_setup_1_DIG_IF_SR_11025 = (0x1 << 0), + MAX98927_PCM_Sample_rate_setup_1_DIG_IF_SR_12000 = (0x2 << 0), + MAX98927_PCM_Sample_rate_setup_1_DIG_IF_SR_16000 = (0x3 << 0), + MAX98927_PCM_Sample_rate_setup_1_DIG_IF_SR_22050 = (0x4 << 0), + MAX98927_PCM_Sample_rate_setup_1_DIG_IF_SR_24000 = (0x5 << 0), + MAX98927_PCM_Sample_rate_setup_1_DIG_IF_SR_32000 = (0x6 << 0), + MAX98927_PCM_Sample_rate_setup_1_DIG_IF_SR_44100 = (0x7 << 0), + MAX98927_PCM_Sample_rate_setup_1_DIG_IF_SR_48000 = (0x8 << 0), + + // PCM Sample rate setup 1 (Address 0x0024) + MAX98927_PCM_Sample_rate_setup_2 = 0x0024, + MAX98927_PCM_Sample_rate_setup_2_IVADC_SR_Mask = (0xf << 0), + //Specific_bit_values_goes_here + //#BYHAND width doesn't match: 16 != 6 + MAX98927_PCM_Sample_rate_setup_2_SPK_SR_Mask = (0xf << 4), + //Specific_bit_values_goes_here + //#BYHAND width doesn't match: 16 != 8 + MAX98927_PCM_Sample_rate_setup_2_SPK_SR_0001 = (0x0 << 4), + MAX98927_PCM_Sample_rate_setup_2_SPK_SR_0011 = (0x2 << 4), + MAX98927_PCM_Sample_rate_setup_2_SPK_SR_0101 = (0x4 << 4), + MAX98927_PCM_Sample_rate_setup_2_SPK_SR_0111 = (0x6 << 4), + MAX98927_PCM_Sample_rate_setup_2_SPK_SR_1001 = (0x8 << 4), + MAX98927_PCM_Sample_rate_setup_2_SPK_SR_1011 = (0xa << 4), + MAX98927_PCM_Sample_rate_setup_2_SPK_SR_1101 = (0xc << 4), + MAX98927_PCM_Sample_rate_setup_2_SPK_SR_ = (0xf << 4), + + // PCM to speaker monomix A (Address 0x0025) + MAX98927_PCM_to_speaker_monomix_A = 0x0025, + MAX98927_PCM_to_speaker_monomix_A_DMONOMIX_CH0_SOURCE_Mask = (0xf << 0), + //Specific_bit_values_goes_here + //#BYHAND width doesn't match: 16 != 3 + MAX98927_PCM_to_speaker_monomix_A_DMONOMIX_CFG_Mask = (0x3 << 6), + //Specific_bit_values_goes_here + //#BYHAND width doesn't match: 4 != 2 + MAX98927_PCM_to_speaker_monomix_A_DMONOMIX_CFG_1 = (0x0 << 6), + MAX98927_PCM_to_speaker_monomix_A_DMONOMIX_CFG_3 = (0x0 << 6), + + // PCM to speaker monomix B (Address 0x0026) + MAX98927_PCM_to_speaker_monomix_B = 0x0026, + MAX98927_PCM_to_speaker_monomix_B_DMONOMIX_CH1_SOURCE_Mask = (0xf << 0), + //Specific_bit_values_goes_here + //#BYHAND width doesn't match: 16 != 3 + + // ICC RX Enables A (Address 0x0027) + MAX98927_ICC_RX_Enables_A = 0x0027, + MAX98927_ICC_RX_Enables_A_ICC_RX_CH0_EN = (0x1 << 0), + MAX98927_ICC_RX_Enables_A_ICC_RX_CH1_EN = (0x1 << 1), + MAX98927_ICC_RX_Enables_A_ICC_RX_CH2_EN = (0x1 << 2), + MAX98927_ICC_RX_Enables_A_ICC_RX_CH3_EN = (0x1 << 3), + MAX98927_ICC_RX_Enables_A_ICC_RX_CH4_EN = (0x1 << 4), + MAX98927_ICC_RX_Enables_A_ICC_RX_CH5_EN = (0x1 << 5), + MAX98927_ICC_RX_Enables_A_ICC_RX_CH6_EN = (0x1 << 6), + MAX98927_ICC_RX_Enables_A_ICC_RX_CH7_EN = (0x1 << 7), + + // ICC RX Enables B (Address 0x0028) + MAX98927_ICC_RX_Enables_B = 0x0028, + MAX98927_ICC_RX_Enables_B_ICC_RX_CH8_EN = (0x1 << 0), + MAX98927_ICC_RX_Enables_B_ICC_RX_CH9_EN = (0x1 << 1), + MAX98927_ICC_RX_Enables_B_ICC_RX_CH10_EN = (0x1 << 2), + MAX98927_ICC_RX_Enables_B_ICC_RX_CH11_EN = (0x1 << 3), + MAX98927_ICC_RX_Enables_B_ICC_RX_CH12_EN = (0x1 << 4), + MAX98927_ICC_RX_Enables_B_ICC_RX_CH13_EN = (0x1 << 5), + MAX98927_ICC_RX_Enables_B_ICC_RX_CH14_EN = (0x1 << 6), + MAX98927_ICC_RX_Enables_B_ICC_RX_CH15_EN = (0x1 << 7), + + // ICC TX Enables A (Address 0x002b) + MAX98927_ICC_TX_Enables_A = 0x002b, + MAX98927_ICC_TX_Enables_A_ICC_TX_CH0_EN = (0x1 << 0), + MAX98927_ICC_TX_Enables_A_ICC_TX_CH1_EN = (0x1 << 1), + MAX98927_ICC_TX_Enables_A_ICC_TX_CH2_EN = (0x1 << 2), + MAX98927_ICC_TX_Enables_A_ICC_TX_CH3_EN = (0x1 << 3), + MAX98927_ICC_TX_Enables_A_ICC_TX_CH4_EN = (0x1 << 4), + MAX98927_ICC_TX_Enables_A_ICC_TX_CH5_EN = (0x1 << 5), + MAX98927_ICC_TX_Enables_A_ICC_TX_CH6_EN = (0x1 << 6), + MAX98927_ICC_TX_Enables_A_ICC_TX_CH7_EN = (0x1 << 7), + + // ICC TX Enables B (Address 0x002c) + MAX98927_ICC_TX_Enables_B = 0x002c, + MAX98927_ICC_TX_Enables_B_ICC_TX_CH8_EN = (0x1 << 0), + MAX98927_ICC_TX_Enables_B_ICC_TX_CH9_EN = (0x1 << 1), + MAX98927_ICC_TX_Enables_B_ICC_TX_CH10_EN = (0x1 << 2), + MAX98927_ICC_TX_Enables_B_ICC_TX_CH11_EN = (0x1 << 3), + MAX98927_ICC_TX_Enables_B_ICC_TX_CH12_EN = (0x1 << 4), + MAX98927_ICC_TX_Enables_B_ICC_TX_CH13_EN = (0x1 << 5), + MAX98927_ICC_TX_Enables_B_ICC_TX_CH14_EN = (0x1 << 6), + MAX98927_ICC_TX_Enables_B_ICC_TX_CH15_EN = (0x1 << 7), + + // ICC Data Order Select (Address 0x002d) + MAX98927_ICC_Data_Order_Select = 0x002d, + MAX98927_ICC_Data_Order_Select_ICC_DRIVE_MODE = (0x1 << 3), + + // ICC HiZ Manual Mode (Address 0x002e) + MAX98927_ICC_HiZ_Manual_Mode = 0x002e, + MAX98927_ICC_HiZ_Manual_Mode_ICC_TX_HIZ_MANUAL = (0x1 << 0), + MAX98927_ICC_HiZ_Manual_Mode_ICC_TX_EXTRA_HIZ = (0x1 << 1), + + // ICC TX HiZ Enables A (Address 0x002f) + MAX98927_ICC_TX_HiZ_Enables_A = 0x002f, + MAX98927_ICC_TX_HiZ_Enables_A_ICC_TX_CH0_HIZ = (0x1 << 0), + MAX98927_ICC_TX_HiZ_Enables_A_ICC_TX_CH1_HIZ = (0x1 << 1), + MAX98927_ICC_TX_HiZ_Enables_A_ICC_TX_CH2_HIZ = (0x1 << 2), + MAX98927_ICC_TX_HiZ_Enables_A_ICC_TX_CH3_HIZ = (0x1 << 3), + MAX98927_ICC_TX_HiZ_Enables_A_ICC_TX_CH4_HIZ = (0x1 << 4), + MAX98927_ICC_TX_HiZ_Enables_A_ICC_TX_CH5_HIZ = (0x1 << 5), + MAX98927_ICC_TX_HiZ_Enables_A_ICC_TX_CH6_HIZ = (0x1 << 6), + MAX98927_ICC_TX_HiZ_Enables_A_ICC_TX_CH7_HIZ = (0x1 << 7), + + // ICC TX HiZ Enables B (Address 0x0030) + MAX98927_ICC_TX_HiZ_Enables_B = 0x0030, + MAX98927_ICC_TX_HiZ_Enables_B_ICC_TX_CH8_HIZ = (0x1 << 0), + MAX98927_ICC_TX_HiZ_Enables_B_ICC_TX_CH9_HIZ = (0x1 << 1), + MAX98927_ICC_TX_HiZ_Enables_B_ICC_TX_CH10_HIZ = (0x1 << 2), + MAX98927_ICC_TX_HiZ_Enables_B_ICC_TX_CH11_HIZ = (0x1 << 3), + MAX98927_ICC_TX_HiZ_Enables_B_ICC_TX_CH12_HIZ = (0x1 << 4), + MAX98927_ICC_TX_HiZ_Enables_B_ICC_TX_CH13_HIZ = (0x1 << 5), + MAX98927_ICC_TX_HiZ_Enables_B_ICC_TX_CH14_HIZ = (0x1 << 6), + MAX98927_ICC_TX_HiZ_Enables_B_ICC_TX_CH15_HIZ = (0x1 << 7), + + // ICC Link Enables (Address 0x0031) + MAX98927_ICC_Link_Enables = 0x0031, + MAX98927_ICC_Link_Enables_ICC_LINK_EN = (0x1 << 1), + + // PDM Tx Enables (Address 0x0032) + MAX98927_PDM_Tx_Enables = 0x0032, + MAX98927_PDM_Tx_Enables_PDM_TX_EN = (0x1 << 0), + MAX98927_PDM_Tx_Enables_PDM_TX_CLK_DIV2 = (0x1 << 1), + + // PDM Tx HiZ Control (Address 0x0033) + MAX98927_PDM_Tx_HiZ_Control = 0x0033, + MAX98927_PDM_Tx_HiZ_Control_PDM_TX_HIZ = (0x1 << 0), + + // PDM Tx Control (Address 0x0034) + MAX98927_PDM_Tx_Control = 0x0034, + MAX98927_PDM_Tx_Control_PDM_TX_CH0_SOURCE = (0x1 << 0), + MAX98927_PDM_Tx_Control_PDM_TX_CH1_SOURCE = (0x1 << 1), + + // PDM Rx Enable (Address 0x0034) + MAX98927_PDM_Rx_Enable = 0x0035, + MAX98927_PDM_Rx_Enable_PDM_RX_EN = (0x1 << 0), + MAX98927_PDM_Rx_Enable_PDM_DSP_EN = (0x1 << 1), + MAX98927_PDM_Rx_Enable_PDM_DITH_EN = (0x1 << 2), + MAX98927_PDM_Rx_Enable_PDM_RX_CH_SEL = (0x1 << 3), + MAX98927_PDM_Rx_Enable_PDM_FIFO_RDY_LVL_Mask = (0xf << 4), + //Specific_bit_values_goes_here + //#BYHAND width doesn't match: 16 != 5 + + // AMP volume control (Address 0x0036) + MAX98927_AMP_volume_control = 0x0036, + //#BYHAND width >= 5: + MAX98927_AMP_volume_control_AMP_VOL_Mask = (0x7f << 0), + MAX98927_AMP_volume_control_AMP_VOL_SEL = (0x1 << 7), + + // AMP DSP Config (Address 0x0037) + MAX98927_AMP_DSP_Config = 0x0037, + MAX98927_AMP_DSP_Config_AMP_DCBLK_EN = (0x1 << 0), + MAX98927_AMP_DSP_Config_AMP_DITH_EN = (0x1 << 1), + MAX98927_AMP_DSP_Config_DAC_HALF_REF_CURRENT = (0x1 << 2), + MAX98927_AMP_DSP_Config_DAC_DOUBLE_RFB = (0x1 << 3), + MAX98927_AMP_DSP_Config_AMP_VOL_RMP_BYPASS = (0x1 << 4), + MAX98927_AMP_DSP_Config_DAC_INVERT = (0x1 << 5), + + // Tone Generator and DC Config (Address 0x0038) + MAX98927_Tone_Generator_and_DC_Config = 0x0038, + MAX98927_Tone_Generator_and_DC_Config_TONE_CONFIG_Mask = (0xf << 0), + //Specific_bit_values_goes_here + //#BYHAND width doesn't match: 16 != 6 + + // DRE Control (Address 0x0039) + MAX98927_DRE_Control = 0x0039, + MAX98927_DRE_Control_DRE_EN = (0x1 << 0), + + // AMP enables (Address 0x003a) + MAX98927_AMP_enables = 0x003a, + MAX98927_AMP_enables_SPK_EN = (0x1 << 0), + + // Speaker source select (Address 0x003b) + MAX98927_Speaker_source_select = 0x003b, + MAX98927_Speaker_source_select_SPK_SOURCE_Mask = (0x3 << 0), + //Specific_bit_values_goes_here + //#BYHAND width doesn't match: 4 != 2 + MAX98927_Speaker_source_select_SPK_SOURCE_01 = (0x0 << 0), + MAX98927_Speaker_source_select_SPK_SOURCE_11 = (0x2 << 0), + + // Speaker Gain (Address 0x003c) + MAX98927_Speaker_Gain = 0x003c, + MAX98927_Speaker_Gain_SPK_PCM_GAIN_Mask = (0x7 << 0), + //Specific_bit_values_goes_here + //#BYHAND width doesn't match: 8 != 4 + MAX98927_Speaker_Gain_SPK_PCM_GAIN_001 = (0x0 << 0), + MAX98927_Speaker_Gain_SPK_PCM_GAIN_011 = (0x2 << 0), + MAX98927_Speaker_Gain_SPK_PCM_GAIN_101 = (0x4 << 0), + MAX98927_Speaker_Gain_SPK_PCM_GAIN_111 = (0x6 << 0), + MAX98927_Speaker_Gain_SPK_PDM_GAIN_Mask = (0x7 << 4), + //Specific_bit_values_goes_here + //#BYHAND width doesn't match: 8 != 4 + MAX98927_Speaker_Gain_SPK_PDM_GAIN_001 = (0x0 << 4), + MAX98927_Speaker_Gain_SPK_PDM_GAIN_011 = (0x2 << 4), + MAX98927_Speaker_Gain_SPK_PDM_GAIN_101 = (0x4 << 4), + MAX98927_Speaker_Gain_SPK_PDM_GAIN_111 = (0x6 << 4), + + // SSM Configuration (Address 0x003d) + MAX98927_SSM_Configuration = 0x003d, + MAX98927_SSM_Configuration_SSM_MOD_INDEX_Mask = (0x7 << 0), + //Specific_bit_values_goes_here + //#BYHAND width doesn't match: 8 != 4 + MAX98927_SSM_Configuration_SSM_MOD_INDEX_001 = (0x0 << 0), + MAX98927_SSM_Configuration_SSM_MOD_INDEX_011 = (0x2 << 0), + MAX98927_SSM_Configuration_SSM_MOD_INDEX_101 = (0x4 << 0), + MAX98927_SSM_Configuration_SSM_MOD_INDEX_ = (0x6 << 0), + MAX98927_SSM_Configuration_SPK_FSW_SEL = (0x1 << 3), + MAX98927_SSM_Configuration_SSM_ENA = (0x1 << 7), + + // Measurement enables (Address 0x003e) + MAX98927_Measurement_enables = 0x003e, + MAX98927_Measurement_enables_IVADC_V_EN = (0x1 << 0), + MAX98927_Measurement_enables_IVADC_I_EN = (0x1 << 1), + + // Measurement DSP Config (Address 0x003f) + MAX98927_Measurement_DSP_Config = 0x003f, + MAX98927_Measurement_DSP_Config_MEAS_V_DCBLK_EN = (0x1 << 0), + MAX98927_Measurement_DSP_Config_MEAS_I_DCBLK_EN = (0x1 << 1), + MAX98927_Measurement_DSP_Config_MEAS_DITH_EN = (0x1 << 2), + MAX98927_Measurement_DSP_Config_MEAS_V_DCBLK_Mask = (0x3 << 4), + //Specific_bit_values_goes_here + //#BYHAND width doesn't match: 4 != 2 + MAX98927_Measurement_DSP_Config_MEAS_V_DCBLK_01 = (0x0 << 4), + MAX98927_Measurement_DSP_Config_MEAS_V_DCBLK_11 = (0x2 << 4), + MAX98927_Measurement_DSP_Config_MEAS_I_DCBLK_Mask = (0x3 << 6), + //Specific_bit_values_goes_here + //#BYHAND width doesn't match: 4 != 2 + MAX98927_Measurement_DSP_Config_MEAS_I_DCBLK_01 = (0x0 << 6), + MAX98927_Measurement_DSP_Config_MEAS_I_DCBLK_11 = (0x2 << 6), + + // Boost Control 0 (Address 0x0040) + MAX98927_Boost_Control_0 = 0x0040, + //#BYHAND width >= 5: + MAX98927_Boost_Control_0_BST_VOUT_Mask = (0x1f << 0), + MAX98927_Boost_Control_0_EXT_PVDD_EN = (0x1 << 7), + + // Boost Control 3 (Address 0x0041) + MAX98927_Boost_Control_3 = 0x0041, + MAX98927_Boost_Control_3_BST_SKIPLOAD_Mask = (0x3 << 0), + //Specific_bit_values_goes_here + //#BYHAND width doesn't match: 4 != 2 + MAX98927_Boost_Control_3_BST_SKIPLOAD_01 = (0x0 << 0), + MAX98927_Boost_Control_3_BST_SKIPLOAD_11 = (0x2 << 0), + MAX98927_Boost_Control_3_BST_PHASE_Mask = (0x7 << 2), + //Specific_bit_values_goes_here + //#BYHAND width doesn't match: 8 != 3 + MAX98927_Boost_Control_3_BST_PHASE_001 = (0x0 << 2), + MAX98927_Boost_Control_3_BST_PHASE_011 = (0x2 << 2), + MAX98927_Boost_Control_3_BST_PHASE_ = (0x1 << 2), + MAX98927_Boost_Control_3_BST_SLOWSTART = (0x1 << 5), + + // Boost Control 1 (Address 0x0042) + MAX98927_Boost_Control_1 = 0x0042, + //#BYHAND width >= 5: + MAX98927_Boost_Control_1_BST_ILIM_Mask = (0x1f << 1), + + // Meas ADC Config (Address 0x0043) + MAX98927_Meas_ADC_Config = 0x0043, + MAX98927_Meas_ADC_Config_MEAS_ADC_CH0_EN = (0x1 << 0), + MAX98927_Meas_ADC_Config_MEAS_ADC_CH1_EN = (0x1 << 1), + MAX98927_Meas_ADC_Config_MEAS_ADC_CH2_EN = (0x1 << 2), + + // Meas ADC Base Divide MSByte (Address 0x0044) + MAX98927_Meas_ADC_Base_Divide_MSByte = 0x0044, + //#BYHAND width >= 5: + MAX98927_Meas_ADC_Base_Divide_MSByte_MEAS_ADC_BASE_DIV_Mask = (0xff << 0), + + // Meas ADC Base Divide LSByte (Address 0x0045) + MAX98927_Meas_ADC_Base_Divide_LSByte = 0x0045, + //#BYHAND width >= 5: + MAX98927_Meas_ADC_Base_Divide_LSByte_MEAS_ADC_BASE_DIV_Mask = (0xff << 0), + + // Meas ADC Chan 0 Divide (Address 0x0046) + MAX98927_Meas_ADC_Chan_0_Divide = 0x0046, + //#BYHAND width >= 5: + MAX98927_Meas_ADC_Chan_0_Divide_MEAS_ADC_CH0_DIV_Mask = (0xff << 0), + + // Meas ADC Chan 1 Divide (Address 0x0047) + MAX98927_Meas_ADC_Chan_1_Divide = 0x0047, + //#BYHAND width >= 5: + MAX98927_Meas_ADC_Chan_1_Divide_MEAS_ADC_CH1_DIV_Mask = (0xff << 0), + + // Meas ADC Chan 2 Divide (Address 0x0048) + MAX98927_Meas_ADC_Chan_2_Divide = 0x0048, + //#BYHAND width >= 5: + MAX98927_Meas_ADC_Chan_2_Divide_MEAS_ADC_CH2_DIV_Mask = (0xff << 0), + + // Meas ADC Chan 0 Filt Config (Address 0x0049) + MAX98927_Meas_ADC_Chan_0_Filt_Config = 0x0049, + MAX98927_Meas_ADC_Chan_0_Filt_Config_MEAS_ADC_CH0_FILT_AVG_Mask = (0x7 << 0), + //Specific_bit_values_goes_here + //#BYHAND width doesn't match: 8 != 3 + MAX98927_Meas_ADC_Chan_0_Filt_Config_MEAS_ADC_CH0_FILT_AVG_001 = (0x0 << 0), + MAX98927_Meas_ADC_Chan_0_Filt_Config_MEAS_ADC_CH0_FILT_AVG_011 = (0x2 << 0), + MAX98927_Meas_ADC_Chan_0_Filt_Config_MEAS_ADC_CH0_FILT_AVG_101 = (0x4 << 0), + MAX98927_Meas_ADC_Chan_0_Filt_Config_MEAS_ADC_CH0_FILT_EN = (0x1 << 3), + + // Meas ADC Chan 1 Filt Config (Address 0x004a) + MAX98927_Meas_ADC_Chan_1_Filt_Config = 0x004a, + MAX98927_Meas_ADC_Chan_1_Filt_Config_MEAS_ADC_CH1_FILT_AVG_Mask = (0x7 << 0), + //Specific_bit_values_goes_here + //#BYHAND width doesn't match: 8 != 3 + MAX98927_Meas_ADC_Chan_1_Filt_Config_MEAS_ADC_CH1_FILT_AVG_001 = (0x0 << 0), + MAX98927_Meas_ADC_Chan_1_Filt_Config_MEAS_ADC_CH1_FILT_AVG_011 = (0x2 << 0), + MAX98927_Meas_ADC_Chan_1_Filt_Config_MEAS_ADC_CH1_FILT_AVG_101 = (0x4 << 0), + MAX98927_Meas_ADC_Chan_1_Filt_Config_MEAS_ADC_CH1_FILT_EN = (0x1 << 3), + + // Meas ADC Chan 2 Filt Config (Address 0x004b) + MAX98927_Meas_ADC_Chan_2_Filt_Config = 0x004b, + MAX98927_Meas_ADC_Chan_2_Filt_Config_MEAS_ADC_CH2_FILT_AVG_Mask = (0x7 << 0), + //Specific_bit_values_goes_here + //#BYHAND width doesn't match: 8 != 3 + MAX98927_Meas_ADC_Chan_2_Filt_Config_MEAS_ADC_CH2_FILT_AVG_001 = (0x0 << 0), + MAX98927_Meas_ADC_Chan_2_Filt_Config_MEAS_ADC_CH2_FILT_AVG_011 = (0x2 << 0), + MAX98927_Meas_ADC_Chan_2_Filt_Config_MEAS_ADC_CH2_FILT_AVG_101 = (0x4 << 0), + MAX98927_Meas_ADC_Chan_2_Filt_Config_MEAS_ADC_CH2_FILT_EN = (0x1 << 3), + + // Meas ADC Chan 0 Readback (Address 0x004c) + MAX98927_Meas_ADC_Chan_0_Readback = 0x004c, + //#BYHAND width >= 5: + MAX98927_Meas_ADC_Chan_0_Readback_MEAS_ADC_CH0_DATA_Mask = (0xff << 0), + + // Meas ADC Chan 1 Readback (Address 0x004d) + MAX98927_Meas_ADC_Chan_1_Readback = 0x004d, + //#BYHAND width >= 5: + MAX98927_Meas_ADC_Chan_1_Readback_MEAS_ADC_CH1_DATA_Mask = (0xff << 0), + + // Meas ADC Chan 2 Readback (Address 0x004e) + MAX98927_Meas_ADC_Chan_2_Readback = 0x004e, + //#BYHAND width >= 5: + MAX98927_Meas_ADC_Chan_2_Readback_MEAS_ADC_CH2_DATA_Mask = (0xff << 0), + + // Brownout status (Address 0x0051) + MAX98927_Brownout_status = 0x0051, + MAX98927_Brownout_status_BDE_STATE_Mask = (0xf << 0), + //Specific_bit_values_goes_here + //#BYHAND width doesn't match: 16 != 4 + + // Brownout enables (Address 0x0052) + MAX98927_Brownout_enables = 0x0052, + MAX98927_Brownout_enables_BDE_EN = (0x1 << 0), + MAX98927_Brownout_enables_BDE_AMP_EN = (0x1 << 1), + MAX98927_Brownout_enables_AMP_DSP_EN = (0x1 << 2), + + // Brownout level infinite hold (Address 0x0053) + MAX98927_Brownout_level_infinite_hold = 0x0053, + MAX98927_Brownout_level_infinite_hold_BDE_L8_INF_HLD = (0x1 << 1), + + // Brownout level infinite hold clear (Address 0x0054) + MAX98927_Brownout_level_infinite_hold_clear = 0x0054, + MAX98927_Brownout_level_infinite_hold_clear_BDE_L8_HLD_RLS = (0x1 << 1), + + // Brownout level hold (Address 0x0055) + MAX98927_Brownout_level_hold = 0x0055, + //#BYHAND width >= 5: + MAX98927_Brownout_level_hold_BDE_HLD_Mask = (0xff << 0), + + // Brownout level 1 threshold (Address 0x0056) + MAX98927_Brownout__level_1_threshold = 0x005a, + //#BYHAND width >= 5: + MAX98927_Brownout__level_1_threshold_BDE_L1_VTHRESH_Mask = (0xff << 0), + + // Brownout level 2 threshold (Address 0x0057) + MAX98927_Brownout__level_2_threshold = 0x005b, + //#BYHAND width >= 5: + MAX98927_Brownout__level_2_threshold_BDE_L2_VTHRESH_Mask = (0xff << 0), + + // Brownout level 3 threshold (Address 0x0058) + MAX98927_Brownout__level_3_threshold = 0x005c, + //#BYHAND width >= 5: + MAX98927_Brownout__level_3_threshold_BDE_L3_VTHRESH_Mask = (0xff << 0), + + // Brownout level 4 threshold (Address 0x0059) + MAX98927_Brownout__level_4_threshold = 0x005d, + //#BYHAND width >= 5: + MAX98927_Brownout__level_4_threshold_BDE_L4_VTHRESH_Mask = (0xff << 0), + + // Brownout level 5 threshold (Address 0x005a) + MAX98927_Brownout__level_5_threshold = 0x005a, + //#BYHAND width >= 5: + MAX98927_Brownout__level_5_threshold_BDE_L5_VTHRESH_Mask = (0xff << 0), + + // Brownout level 6 threshold (Address 0x005b) + MAX98927_Brownout__level_6_threshold = 0x005b, + //#BYHAND width >= 5: + MAX98927_Brownout__level_6_threshold_BDE_L6_VTHRESH_Mask = (0xff << 0), + + // Brownout level 7 threshold (Address 0x005c) + MAX98927_Brownout__level_7_threshold = 0x005c, + //#BYHAND width >= 5: + MAX98927_Brownout__level_7_threshold_BDE_L7_VTHRESH_Mask = (0xff << 0), + + // Brownout level 8 threshold (Address 0x005d) + MAX98927_Brownout__level_8_threshold = 0x005d, + //#BYHAND width >= 5: + MAX98927_Brownout__level_8_threshold_BDE_L8_VTHRESH_Mask = (0xff << 0), + + // Brownout threshold hysterysis (Address 0x005e) + MAX98927_Brownout_threshold_hysterysis = 0x005e, + //#BYHAND width >= 5: + MAX98927_Brownout_threshold_hysterysis_BDE_VTHRESH_HYST_Mask = (0xff << 0), + + // Brownout AMP limiter attack/release (Address 0x005f) + MAX98927_Brownout_AMP_limiter_attack_release = 0x005f, + MAX98927_Brownout_AMP_limiter_attack_release_AMP_LIM_RLS_Mask = (0xf << 0), + //Specific_bit_values_goes_here + //#BYHAND width doesn't match: 16 != 8 + MAX98927_Brownout_AMP_limiter_attack_release_AMP_LIM_RLS_0001 = (0x0 << 0), + MAX98927_Brownout_AMP_limiter_attack_release_AMP_LIM_RLS_0011 = (0x2 << 0), + MAX98927_Brownout_AMP_limiter_attack_release_AMP_LIM_RLS_0101 = (0x4 << 0), + MAX98927_Brownout_AMP_limiter_attack_release_AMP_LIM_RLS_0111 = (0x6 << 0), + MAX98927_Brownout_AMP_limiter_attack_release_AMP_LIM_RLS_1001 = (0x8 << 0), + MAX98927_Brownout_AMP_limiter_attack_release_AMP_LIM_RLS_1011 = (0xa << 0), + MAX98927_Brownout_AMP_limiter_attack_release_AMP_LIM_RLS_1101 = (0xc << 0), + MAX98927_Brownout_AMP_limiter_attack_release_AMP_LIM_RLS_1111 = (0xe << 0), + MAX98927_Brownout_AMP_limiter_attack_release_AMP_LIM_ATK_Mask = (0xf << 4), + //Specific_bit_values_goes_here + //#BYHAND width doesn't match: 16 != 8 + MAX98927_Brownout_AMP_limiter_attack_release_AMP_LIM_ATK_0001 = (0x0 << 4), + MAX98927_Brownout_AMP_limiter_attack_release_AMP_LIM_ATK_0011 = (0x2 << 4), + MAX98927_Brownout_AMP_limiter_attack_release_AMP_LIM_ATK_0101 = (0x4 << 4), + MAX98927_Brownout_AMP_limiter_attack_release_AMP_LIM_ATK_0111 = (0x6 << 4), + MAX98927_Brownout_AMP_limiter_attack_release_AMP_LIM_ATK_1001 = (0x8 << 4), + MAX98927_Brownout_AMP_limiter_attack_release_AMP_LIM_ATK_1011 = (0xa << 4), + MAX98927_Brownout_AMP_limiter_attack_release_AMP_LIM_ATK_1101 = (0xc << 4), + MAX98927_Brownout_AMP_limiter_attack_release_AMP_LIM_ATK_1111 = (0xe << 4), + + // Brownout AMP gain attack/release (Address 0x0060) + MAX98927_Brownout_AMP_gain_attack_release = 0x0060, + MAX98927_Brownout_AMP_gain_attack_release_AMP_GAIN_RLS_Mask = (0xf << 0), + //Specific_bit_values_goes_here + //#BYHAND width doesn't match: 16 != 8 + MAX98927_Brownout_AMP_gain_attack_release_AMP_GAIN_RLS_0001 = (0x0 << 0), + MAX98927_Brownout_AMP_gain_attack_release_AMP_GAIN_RLS_0011 = (0x2 << 0), + MAX98927_Brownout_AMP_gain_attack_release_AMP_GAIN_RLS_0101 = (0x4 << 0), + MAX98927_Brownout_AMP_gain_attack_release_AMP_GAIN_RLS_0111 = (0x6 << 0), + MAX98927_Brownout_AMP_gain_attack_release_AMP_GAIN_RLS_1001 = (0x8 << 0), + MAX98927_Brownout_AMP_gain_attack_release_AMP_GAIN_RLS_1011 = (0xa << 0), + MAX98927_Brownout_AMP_gain_attack_release_AMP_GAIN_RLS_1101 = (0xc << 0), + MAX98927_Brownout_AMP_gain_attack_release_AMP_GAIN_RLS_1111 = (0xe << 0), + MAX98927_Brownout_AMP_gain_attack_release_AMP_GAIN_ATK_Mask = (0xf << 4), + //Specific_bit_values_goes_here + //#BYHAND width doesn't match: 16 != 8 + MAX98927_Brownout_AMP_gain_attack_release_AMP_GAIN_ATK_0001 = (0x0 << 4), + MAX98927_Brownout_AMP_gain_attack_release_AMP_GAIN_ATK_0011 = (0x2 << 4), + MAX98927_Brownout_AMP_gain_attack_release_AMP_GAIN_ATK_0101 = (0x4 << 4), + MAX98927_Brownout_AMP_gain_attack_release_AMP_GAIN_ATK_0111 = (0x6 << 4), + MAX98927_Brownout_AMP_gain_attack_release_AMP_GAIN_ATK_1001 = (0x8 << 4), + MAX98927_Brownout_AMP_gain_attack_release_AMP_GAIN_ATK_1011 = (0xa << 4), + MAX98927_Brownout_AMP_gain_attack_release_AMP_GAIN_ATK_1101 = (0xc << 4), + MAX98927_Brownout_AMP_gain_attack_release_AMP_GAIN_ATK_1111 = (0xe << 4), + + // Brownout AMP1 clip mode (Address 0x0061) + MAX98927_Brownout_AMP1_clip_mode = 0x0061, + MAX98927_Brownout_AMP1_clip_mode_AMP_CLIP_MODE = (0x1 << 0), + + // Brownout level 1 current limit (Address 0x0062) + MAX98927_Brownout__level_1_current_limit = 0x0072, + //#BYHAND width >= 5: + MAX98927_Brownout__level_1_current_limit_BDE_L1_ILIM_Mask = (0x3f << 0), + + // Brownout level 1 amp 1 control 1 (Address 0x0063) + MAX98927_Brownout__level_1_amp_1_control_1 = 0x0073, + MAX98927_Brownout__level_1_amp_1_control_1_BDE_L1_AMP1_LIM_Mask = (0xf << 0), + //Specific_bit_values_goes_here + //#BYHAND width doesn't match: 16 != 3 + + // Brownout level 1 amp 1 control 2 (Address 0x0064) + MAX98927_Brownout__level_1_amp_1_control_2 = 0x0074, + //#BYHAND width >= 5: + MAX98927_Brownout__level_1_amp_1_control_2_BDE_L1_AMP1_CLIP_Mask = (0x3f << 0), + + // Brownout level 1 amp 1 control 3 (Address 0x0065) + MAX98927_Brownout__level_1_amp_1_control_3 = 0x0075, + //#BYHAND width >= 5: + MAX98927_Brownout__level_1_amp_1_control_3_BDE_L1_AMP1_GAIN_Mask = (0x3f << 0), + + // Brownout level 2 current limit (Address 0x0066) + MAX98927_Brownout__level_2_current_limit = 0x0076, + //#BYHAND width >= 5: + MAX98927_Brownout__level_2_current_limit_BDE_L2_ILIM_Mask = (0x3f << 0), + + // Brownout level 2 amp 1 control 1 (Address 0x0067) + MAX98927_Brownout__level_2_amp_1_control_1 = 0x0077, + MAX98927_Brownout__level_2_amp_1_control_1_BDE_L2_AMP1_LIM_Mask = (0xf << 0), + //Specific_bit_values_goes_here + //#BYHAND width doesn't match: 16 != 3 + + // Brownout level 2 amp 1 control 2 (Address 0x0068) + MAX98927_Brownout__level_2_amp_1_control_2 = 0x0078, + //#BYHAND width >= 5: + MAX98927_Brownout__level_2_amp_1_control_2_BDE_L2_AMP1_CLIP_Mask = (0x3f << 0), + + // Brownout level 2 amp 1 control 3 (Address 0x0069) + MAX98927_Brownout__level_2_amp_1_control_3 = 0x0079, + //#BYHAND width >= 5: + MAX98927_Brownout__level_2_amp_1_control_3_BDE_L2_AMP1_GAIN_Mask = (0x3f << 0), + + // Brownout level 3 current limit (Address 0x006a) + MAX98927_Brownout__level_3_current_limit = 0x007a, + //#BYHAND width >= 5: + MAX98927_Brownout__level_3_current_limit_BDE_L3_ILIM_Mask = (0x3f << 0), + + // Brownout level 3 amp 1 control 1 (Address 0x006b) + MAX98927_Brownout__level_3_amp_1_control_1 = 0x007b, + MAX98927_Brownout__level_3_amp_1_control_1_BDE_L3_AMP1_LIM_Mask = (0xf << 0), + //Specific_bit_values_goes_here + //#BYHAND width doesn't match: 16 != 3 + + // Brownout level 3 amp 1 control 2 (Address 0x006c) + MAX98927_Brownout__level_3_amp_1_control_2 = 0x007c, + //#BYHAND width >= 5: + MAX98927_Brownout__level_3_amp_1_control_2_BDE_L3_AMP1_CLIP_Mask = (0x3f << 0), + + // Brownout level 3 amp 1 control 3 (Address 0x006d) + MAX98927_Brownout__level_3_amp_1_control_3 = 0x007d, + //#BYHAND width >= 5: + MAX98927_Brownout__level_3_amp_1_control_3_BDE_L3_AMP1_GAIN_Mask = (0x3f << 0), + + // Brownout level 4 current limit (Address 0x006e) + MAX98927_Brownout__level_4_current_limit = 0x007e, + //#BYHAND width >= 5: + MAX98927_Brownout__level_4_current_limit_BDE_L4_ILIM_Mask = (0x3f << 0), + + // Brownout level 4 amp 1 control 1 (Address 0x006f) + MAX98927_Brownout__level_4_amp_1_control_1 = 0x007f, + MAX98927_Brownout__level_4_amp_1_control_1_BDE_L4_AMP1_LIM_Mask = (0xf << 0), + //Specific_bit_values_goes_here + //#BYHAND width doesn't match: 16 != 3 + + // Brownout level 4 amp 1 control 2 (Address 0x0070) + MAX98927_Brownout__level_4_amp_1_control_2 = 0x0080, + //#BYHAND width >= 5: + MAX98927_Brownout__level_4_amp_1_control_2_BDE_L4_AMP1_CLIP_Mask = (0x3f << 0), + + // Brownout level 4 amp 1 control 3 (Address 0x0071) + MAX98927_Brownout__level_4_amp_1_control_3 = 0x0081, + //#BYHAND width >= 5: + MAX98927_Brownout__level_4_amp_1_control_3_BDE_L4_AMP1_GAIN_Mask = (0x3f << 0), + + // Brownout level 5 current limit (Address 0x0072) + MAX98927_Brownout__level_5_current_limit = 0x0072, + //#BYHAND width >= 5: + MAX98927_Brownout__level_5_current_limit_BDE_L5_ILIM_Mask = (0x3f << 0), + + // Brownout level 5 amp 1 control 1 (Address 0x0073) + MAX98927_Brownout__level_5_amp_1_control_1 = 0x0073, + MAX98927_Brownout__level_5_amp_1_control_1_BDE_L5_AMP1_LIM_Mask = (0xf << 0), + //Specific_bit_values_goes_here + //#BYHAND width doesn't match: 16 != 3 + + // Brownout level 5 amp 1 control 2 (Address 0x0074) + MAX98927_Brownout__level_5_amp_1_control_2 = 0x0074, + //#BYHAND width >= 5: + MAX98927_Brownout__level_5_amp_1_control_2_BDE_L5_AMP1_CLIP_Mask = (0x3f << 0), + + // Brownout level 5 amp 1 control 3 (Address 0x0075) + MAX98927_Brownout__level_5_amp_1_control_3 = 0x0075, + //#BYHAND width >= 5: + MAX98927_Brownout__level_5_amp_1_control_3_BDE_L5_AMP1_GAIN_Mask = (0x3f << 0), + + // Brownout level 6 current limit (Address 0x0076) + MAX98927_Brownout__level_6_current_limit = 0x0076, + //#BYHAND width >= 5: + MAX98927_Brownout__level_6_current_limit_BDE_L6_ILIM_Mask = (0x3f << 0), + + // Brownout level 6 amp 1 control 1 (Address 0x0077) + MAX98927_Brownout__level_6_amp_1_control_1 = 0x0077, + MAX98927_Brownout__level_6_amp_1_control_1_BDE_L6_AMP1_LIM_Mask = (0xf << 0), + //Specific_bit_values_goes_here + //#BYHAND width doesn't match: 16 != 3 + + // Brownout level 6 amp 1 control 2 (Address 0x0078) + MAX98927_Brownout__level_6_amp_1_control_2 = 0x0078, + //#BYHAND width >= 5: + MAX98927_Brownout__level_6_amp_1_control_2_BDE_L6_AMP1_CLIP_Mask = (0x3f << 0), + + // Brownout level 6 amp 1 control 3 (Address 0x0079) + MAX98927_Brownout__level_6_amp_1_control_3 = 0x0079, + //#BYHAND width >= 5: + MAX98927_Brownout__level_6_amp_1_control_3_BDE_L6_AMP1_GAIN_Mask = (0x3f << 0), + + // Brownout level 7 current limit (Address 0x007a) + MAX98927_Brownout__level_7_current_limit = 0x007a, + //#BYHAND width >= 5: + MAX98927_Brownout__level_7_current_limit_BDE_L7_ILIM_Mask = (0x3f << 0), + + // Brownout level 7 amp 1 control 1 (Address 0x007b) + MAX98927_Brownout__level_7_amp_1_control_1 = 0x007b, + MAX98927_Brownout__level_7_amp_1_control_1_BDE_L7_AMP1_LIM_Mask = (0xf << 0), + //Specific_bit_values_goes_here + //#BYHAND width doesn't match: 16 != 3 + + // Brownout level 7 amp 1 control 2 (Address 0x007c) + MAX98927_Brownout__level_7_amp_1_control_2 = 0x007c, + //#BYHAND width >= 5: + MAX98927_Brownout__level_7_amp_1_control_2_BDE_L7_AMP1_CLIP_Mask = (0x3f << 0), + + // Brownout level 7 amp 1 control 3 (Address 0x007d) + MAX98927_Brownout__level_7_amp_1_control_3 = 0x007d, + //#BYHAND width >= 5: + MAX98927_Brownout__level_7_amp_1_control_3_BDE_L7_AMP1_GAIN_Mask = (0x3f << 0), + + // Brownout level 8 current limit (Address 0x007e) + MAX98927_Brownout__level_8_current_limit = 0x007e, + //#BYHAND width >= 5: + MAX98927_Brownout__level_8_current_limit_BDE_L8_ILIM_Mask = (0x3f << 0), + + // Brownout level 8 amp 1 control 1 (Address 0x007f) + MAX98927_Brownout__level_8_amp_1_control_1 = 0x007f, + MAX98927_Brownout__level_8_amp_1_control_1_BDE_L8_AMP1_LIM_Mask = (0xf << 0), + //Specific_bit_values_goes_here + //#BYHAND width doesn't match: 16 != 3 + + // Brownout level 8 amp 1 control 2 (Address 0x0080) + MAX98927_Brownout__level_8_amp_1_control_2 = 0x0080, + //#BYHAND width >= 5: + MAX98927_Brownout__level_8_amp_1_control_2_BDE_L8_AMP1_CLIP_Mask = (0x3f << 0), + MAX98927_Brownout__level_8_amp_1_control_2_BDE_L8_AMP1_MUTE = (0x1 << 7), + + // Brownout level 8 amp 1 control 3 (Address 0x0081) + MAX98927_Brownout__level_8_amp_1_control_3 = 0x0081, + //#BYHAND width >= 5: + MAX98927_Brownout__level_8_amp_1_control_3_BDE_L8_AMP1_GAIN_Mask = (0x3f << 0), + + // Env Tracker Vout Headroom (Address 0x0082) + MAX98927_Env_Tracker_Vout_Headroom = 0x0082, + //#BYHAND width >= 5: + MAX98927_Env_Tracker_Vout_Headroom_ENV_TRACKER_BST_VOUT_HEADROOM_Mask = (0x1f << 0), + + // Env Tracker Boost Vout Delay (Address 0x0083) + MAX98927_Env_Tracker_Boost_Vout_Delay = 0x0083, + //#BYHAND width >= 5: + MAX98927_Env_Tracker_Boost_Vout_Delay_ENV_TRACKER_BST_VOUT_DELAY_Mask = (0x1f << 0), + MAX98927_Env_Tracker_Boost_Vout_Delay_ENV_TRACKER_BDE_MODE = (0x1 << 7), + + // Env Tracker Release Rate (Address 0x0084) + MAX98927_Env_Tracker_Release_Rate = 0x0084, + MAX98927_Env_Tracker_Release_Rate_ENV_TRACKER_RLS_RATE_Mask = (0x7 << 0), + //Specific_bit_values_goes_here + //#BYHAND width doesn't match: 8 != 4 + MAX98927_Env_Tracker_Release_Rate_ENV_TRACKER_RLS_RATE_001 = (0x0 << 0), + MAX98927_Env_Tracker_Release_Rate_ENV_TRACKER_RLS_RATE_011 = (0x2 << 0), + MAX98927_Env_Tracker_Release_Rate_ENV_TRACKER_RLS_RATE_101 = (0x4 << 0), + MAX98927_Env_Tracker_Release_Rate_ENV_TRACKER_RLS_RATE_111 = (0x6 << 0), + MAX98927_Env_Tracker_Release_Rate_ENV_TRACKER_PEAK_DET_LPF_BYP_EN = (0x1 << 3), + MAX98927_Env_Tracker_Release_Rate_ENV_TRACKER_RLS_RATE_SCALE_Mask = (0x3 << 4), + //Specific_bit_values_goes_here + //#BYHAND width doesn't match: 4 != 2 + MAX98927_Env_Tracker_Release_Rate_ENV_TRACKER_RLS_RATE_SCALE_01 = (0x0 << 4), + MAX98927_Env_Tracker_Release_Rate_ENV_TRACKER_RLS_RATE_SCALE_11 = (0x2 << 4), + + // Env Tracker Hold Rate (Address 0x0085) + MAX98927_Env_Tracker_Hold_Rate = 0x0085, + MAX98927_Env_Tracker_Hold_Rate_ENV_TRACKER_HOLD_RATE_Mask = (0x7 << 0), + //Specific_bit_values_goes_here + //#BYHAND width doesn't match: 8 != 4 + MAX98927_Env_Tracker_Hold_Rate_ENV_TRACKER_HOLD_RATE_001 = (0x0 << 0), + MAX98927_Env_Tracker_Hold_Rate_ENV_TRACKER_HOLD_RATE_011 = (0x2 << 0), + MAX98927_Env_Tracker_Hold_Rate_ENV_TRACKER_HOLD_RATE_101 = (0x4 << 0), + MAX98927_Env_Tracker_Hold_Rate_ENV_TRACKER_HOLD_RATE_111 = (0x6 << 0), + + // Env Tracker Control (Address 0x0086) + MAX98927_Env_Tracker_Control = 0x0086, + MAX98927_Env_Tracker_Control_ENV_TRACKER_EN = (0x1 << 0), + + // Env Tracker Boost Vout ReadBack (Address 0x0087) + MAX98927_Env_Tracker__Boost_Vout_ReadBack = 0x0087, + //#BYHAND width >= 5: + MAX98927_Env_Tracker__Boost_Vout_ReadBack_ENV_TRACKER_BST_VOUT_RD_Mask = (0x1f << 0), + + // Advanced Settings (Address 0x0089) + MAX98927_Advanced_Settings = 0x0089, + MAX98927_Advanced_Settings_DAC_HALF_FIR = (0x1 << 0), + MAX98927_Advanced_Settings_PDM_MOD_SEL = (0x1 << 1), + MAX98927_Advanced_Settings_ISOCH_EN = (0x1 << 2), + + // DAC Test 1 (Address 0x009f) + MAX98927_DAC_Test_1 = 0x009f, + MAX98927_DAC_Test_1_DAC_PCM_TIMING = (0x1 << 0), + MAX98927_DAC_Test_1_DAC_HALFI_AMP = (0x1 << 1), + MAX98927_DAC_Test_1_DAC_LONG_HOLD = (0x1 << 3), + MAX98927_DAC_Test_1_DAC_DISABLE_CHOP = (0x1 << 4), + MAX98927_DAC_Test_1_DAC_TM = (0x1 << 5), + MAX98927_DAC_Test_1_DAC_INVERT_DACCLK = (0x1 << 6), + + // Authentication key 0 (Address 0x00ea) + MAX98927_Authentication_key_0 = 0x00ea, + //#BYHAND width >= 5: + MAX98927_Authentication_key_0_AUTH_KEY_Mask = (0xff << 0), + + // Authentication key 1 (Address 0x00eb) + MAX98927_Authentication_key_1 = 0x00eb, + //#BYHAND width >= 5: + MAX98927_Authentication_key_1_AUTH_KEY_Mask = (0xff << 0), + + // Authentication key 2 (Address 0x00ec) + MAX98927_Authentication_key_2 = 0x00ec, + //#BYHAND width >= 5: + MAX98927_Authentication_key_2_AUTH_KEY_Mask = (0xff << 0), + + // Authentication key 3 (Address 0x00ed) + MAX98927_Authentication_key_3 = 0x00ed, + //#BYHAND width >= 5: + MAX98927_Authentication_key_3_AUTH_KEY_Mask = (0xff << 0), + + // Authentication enable (Address 0x00ee) + MAX98927_Authentication_enable = 0x00ee, + MAX98927_Authentication_enable_AUTH_EN = (0x1 << 0), + + // Authentication result 0 (Address 0x00ef) + MAX98927_Authentication_result_0 = 0x00ef, + //#BYHAND width >= 5: + MAX98927_Authentication_result_0_AUTH_RESULT_Mask = (0xff << 0), + + // Authentication result 1 (Address 0x00f0) + MAX98927_Authentication_result_1 = 0x00f0, + //#BYHAND width >= 5: + MAX98927_Authentication_result_1_AUTH_RESULT_Mask = (0xff << 0), + + // Authentication result 2 (Address 0x00f1) + MAX98927_Authentication_result_2 = 0x00f1, + //#BYHAND width >= 5: + MAX98927_Authentication_result_2_AUTH_RESULT_Mask = (0xff << 0), + + // Authentication result 3 (Address 0x00f2) + MAX98927_Authentication_result_3 = 0x00f2, + //#BYHAND width >= 5: + MAX98927_Authentication_result_3_AUTH_RESULT_Mask = (0xff << 0), + + // Authentication result 4 (Address 0x00f3) + MAX98927_Authentication_result_4 = 0x00f3, + //#BYHAND width >= 5: + MAX98927_Authentication_result_4_AUTH_RESULT_Mask = (0xff << 0), + + // Authentication result 5 (Address 0x00f4) + MAX98927_Authentication_result_5 = 0x00f4, + //#BYHAND width >= 5: + MAX98927_Authentication_result_5_AUTH_RESULT_Mask = (0xff << 0), + + // Authentication result 6 (Address 0x00f5) + MAX98927_Authentication_result_6 = 0x00f5, + //#BYHAND width >= 5: + MAX98927_Authentication_result_6_AUTH_RESULT_Mask = (0xff << 0), + + // Authentication result 7 (Address 0x00f6) + MAX98927_Authentication_result_7 = 0x00f6, + //#BYHAND width >= 5: + MAX98927_Authentication_result_7_AUTH_RESULT_Mask = (0xff << 0), + + // Authentication result 8 (Address 0x00f7) + MAX98927_Authentication_result_8 = 0x00f7, + //#BYHAND width >= 5: + MAX98927_Authentication_result_8_AUTH_RESULT_Mask = (0xff << 0), + + // Authentication result 9 (Address 0x00f8) + MAX98927_Authentication_result_9 = 0x00f8, + //#BYHAND width >= 5: + MAX98927_Authentication_result_9_AUTH_RESULT_Mask = (0xff << 0), + + // Authentication result 10 (Address 0x00f9) + MAX98927_Authentication_result_10 = 0x00f9, + //#BYHAND width >= 5: + MAX98927_Authentication_result_10_AUTH_RESULT_Mask = (0xff << 0), + + // Authentication result 11 (Address 0x00fa) + MAX98927_Authentication_result_11 = 0x00fa, + //#BYHAND width >= 5: + MAX98927_Authentication_result_11_AUTH_RESULT_Mask = (0xff << 0), + + // Authentication result 12 (Address 0x00fb) + MAX98927_Authentication_result_12 = 0x00fb, + //#BYHAND width >= 5: + MAX98927_Authentication_result_12_AUTH_RESULT_Mask = (0xff << 0), + + // Authentication result 13 (Address 0x00fc) + MAX98927_Authentication_result_13 = 0x00fc, + //#BYHAND width >= 5: + MAX98927_Authentication_result_13_AUTH_RESULT_Mask = (0xff << 0), + + // Authentication result 14 (Address 0x00fd) + MAX98927_Authentication_result_14 = 0x00fd, + //#BYHAND width >= 5: + MAX98927_Authentication_result_14_AUTH_RESULT_Mask = (0xff << 0), + + // Authentication result 15 (Address 0x00fe) + MAX98927_Authentication_result_15 = 0x00fe, + //#BYHAND width >= 5: + MAX98927_Authentication_result_15_AUTH_RESULT_Mask = (0xff << 0), + + // Global Enable (Address 0x00ff) + MAX98927_Global_Enable = 0x00ff, + MAX98927_Global_Enable_EN = (0x1 << 0), + // Software Reset (Address 0x0100) + MAX98927_Software_Reset = 0x0100, + MAX98927_Software_Reset_RST = (0x1 << 0), + + // REV ID (Address 0x01ff) + MAX98927_REV_ID = 0x01ff, + //#BYHAND width >= 5: + MAX98927_REV_ID_REV_ID_Mask = (0xff << 0), + + +} MAX98927Registers; + +typedef enum{ + MAX98927_CH0 = (1 << 0), + MAX98927_CH1 = (1 << 1), + MAX98927_CH2 = (1 << 2), + MAX98927_CH3 = (1 << 3), +} MAX98927_CHANNEL_SHIT; + +struct max98927_priv { + struct device *dev; + struct regmap *regmap[MAX_CHANNEL_NUM]; + struct snd_soc_codec *codec; + struct max98927_pdata *pdata; + unsigned int spk_mode; + unsigned int spk_gain; + unsigned int sysclk; + unsigned int v_l_slot; + unsigned int i_l_slot; + unsigned int v_r_slot; + unsigned int i_r_slot; + unsigned int mono_stereo; + unsigned int i2c_states; + bool interleave_mode; + unsigned int ch_size; + unsigned int rate; + unsigned int iface; + unsigned int master; + unsigned int thres_hyste; + unsigned int level5_hold; + unsigned int level6_hold; + unsigned int level7_hold; + unsigned int level8_hold; + unsigned int amp_limit; + unsigned int amp_limit_rel; + unsigned int amp1_level; + unsigned int amp2_level; + unsigned int amp3_level; + unsigned int amp1_level8; + unsigned int amp2_level8; + unsigned int amp3_level8; + unsigned int amp1_level7; + unsigned int amp2_level7; + unsigned int amp3_level7; + unsigned int amp1_level6; + unsigned int amp2_level6; + unsigned int amp3_level6; + unsigned int amp1_level5; + unsigned int amp2_level5; + unsigned int amp3_level5; + unsigned int digital_gain; + unsigned int pdm_gain; + unsigned int level_hold; + unsigned int ref_RDC[2]; + unsigned int path_status; + int reset_gpio_l; + int reset_gpio_r; //dongchen to delete +#ifdef CONFIG_DEBUG_FS + struct dentry *dbg_dir; +#endif + struct regulator *max989xx_vdd; +}; + +#define MAX98927_GLOBAL_SHIFT 0 +#define M98927_DAI_MSEL_SHIFT 4 +#define M98927_DAI_BSEL_SHIFT 0 +#define M98927_DAI_BSEL_32 (2 << M98927_DAI_BSEL_SHIFT) +#define M98927_DAI_BSEL_48 (3 << M98927_DAI_BSEL_SHIFT) +#define M98927_DAI_BSEL_64 (4 << M98927_DAI_BSEL_SHIFT) +#define M98927_DAI_MSEL_32 (2 << M98927_DAI_MSEL_SHIFT) +#define M98927_DAI_MSEL_48 (3 << M98927_DAI_MSEL_SHIFT) +#define M98927_DAI_MSEL_64 (4 << M98927_DAI_MSEL_SHIFT) +#define MAX98927_Speaker_Gain_Width 3 +#define MAX98927_SPK_RMP_EN_SHIFT 4 +#define MAX98927_PDM_GAIN_SHIFT 4 +#define MAX98927_pdm_Gain_Width 3 +#define MAX98927_AMP_VOL_WIDTH 7 +#define MAX98927_AMP_VOL_LOCATION_SHIFT 7 +#define MAX98927_PDM_Rx_Enable_PDM_CH_SHIFT 3 +#define MAX98927_PCM_to_speaker_monomix_A_SHIFT 6 +#define MAX98927_PCM_Sample_rate_setup_2_DIG_IF_SR_48000 (0x8 << 4) +#define MAX98927_PCM_FORMAT_DSP_A (0x3 << 3) +#define MAX98927_DRE_Control_DRE_SHIFT 0 +#define MAX98927_PCM_Master_Mode_PCM_MCLK_RATE_SHIFT (2) +#define MAX98927_Brownout_AMP_limiter_attack_release_shift 4 +#define MAX98927_BDE_DSP_SHIFT 2 +#define MAX98927_Speaker_Gain_SPK_PDM_GAIN_SHIFT (4) +#define MAX98927_BDE_AMP_SHIFT 1 +#define MAX98927_BST_ILIM_SHIFT 1 +#endif // __MAX98927_REGISTERDEFS_H diff --git a/techpack/audio/asoc/codecs/tfa9874/Kbuild b/techpack/audio/asoc/codecs/tfa9874/Kbuild new file mode 100644 index 000000000000..4f61be5e63f7 --- /dev/null +++ b/techpack/audio/asoc/codecs/tfa9874/Kbuild @@ -0,0 +1,126 @@ +# We can build either as part of a standalone Kernel build or as +# an external module. Determine which mechanism is being used +ifeq ($(MODNAME),) + KERNEL_BUILD := 1 +else + KERNEL_BUILD := 0 +endif + +ifeq ($(KERNEL_BUILD), 1) + # These are configurable via Kconfig for kernel-based builds + # Need to explicitly configure for Android-based builds + AUDIO_BLD_DIR := $(shell pwd)/kernel/msm-4.19 + AUDIO_ROOT := $(AUDIO_BLD_DIR)/techpack/audio +endif + +ifeq ($(KERNEL_BUILD), 0) + ifeq ($(CONFIG_ARCH_SDM845), y) + include $(AUDIO_ROOT)/config/sdm845auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sdm845autoconf.h + endif + ifeq ($(CONFIG_ARCH_SDM670), y) + include $(AUDIO_ROOT)/config/sdm710auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sdm710autoconf.h + endif + ifeq ($(CONFIG_ARCH_SDM450), y) + include $(AUDIO_ROOT)/config/sdm710auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sdm710autoconf.h + endif + ifeq ($(CONFIG_ARCH_SM6150), y) + include $(AUDIO_ROOT)/config/sm6150auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sm6150autoconf.h + endif + ifeq ($(CONFIG_ARCH_KONA), y) + include $(AUDIO_ROOT)/config/konaauto.conf + INCS += -include $(AUDIO_ROOT)/config/konaautoconf.h + endif + ifeq ($(CONFIG_ARCH_LITO), y) + include $(AUDIO_ROOT)/config/litoauto.conf + export + INCS += -include $(AUDIO_ROOT)/config/litoautoconf.h + endif +endif + +# As per target team, build is done as follows: +# Defconfig : build with default flags +# Slub : defconfig + CONFIG_SLUB_DEBUG := y + +# CONFIG_SLUB_DEBUG_ON := y + CONFIG_PAGE_POISONING := y +# Perf : Using appropriate msmXXXX-perf_defconfig +# +# Shipment builds (user variants) should not have any debug feature +# enabled. This is identified using 'TARGET_BUILD_VARIANT'. Slub builds +# are identified using the CONFIG_SLUB_DEBUG_ON configuration. Since +# there is no other way to identify defconfig builds, QTI internal +# representation of perf builds (identified using the string 'perf'), +# is used to identify if the build is a slub or defconfig one. This +# way no critical debug feature will be enabled for perf and shipment +# builds. Other OEMs are also protected using the TARGET_BUILD_VARIANT +# config. + +############ UAPI ############ +UAPI_DIR := uapi +UAPI_INC := -I$(AUDIO_ROOT)/include/$(UAPI_DIR) + +############ COMMON ############ +COMMON_DIR := include +COMMON_INC := -I$(AUDIO_ROOT)/$(COMMON_DIR) + +############ tfa98xx ############ +ifdef CONFIG_SND_SOC_TFA98XX + TFA98XX_OBJS += tfa98xx.o + TFA98XX_OBJS += tfa_container.o + TFA98XX_OBJS += tfa_dsp.o + TFA98XX_OBJS += tfa_init.o +endif + +LINUX_INC += -Iinclude/linux + +INCS += $(COMMON_INC) \ + $(UAPI_INC) + +EXTRA_CFLAGS += $(INCS) + + +CDEFINES += -DANI_LITTLE_BYTE_ENDIAN \ + -DANI_LITTLE_BIT_ENDIAN \ + -DDOT11F_LITTLE_ENDIAN_HOST \ + -DANI_COMPILER_TYPE_GCC \ + -DANI_OS_TYPE_ANDROID=6 \ + -DPTT_SOCK_SVC_ENABLE \ + -Wall\ + -Werror\ + -D__linux__ + +KBUILD_CPPFLAGS += $(CDEFINES) + +# Currently, for versions of gcc which support it, the kernel Makefile +# is disabling the maybe-uninitialized warning. Re-enable it for the +# AUDIO driver. Note that we must use EXTRA_CFLAGS here so that it +# will override the kernel settings. +ifeq ($(call cc-option-yn, -Wmaybe-uninitialized),y) +EXTRA_CFLAGS += -Wmaybe-uninitialized +endif +#EXTRA_CFLAGS += -Wmissing-prototypes + +ifeq ($(call cc-option-yn, -Wheader-guard),y) +EXTRA_CFLAGS += -Wheader-guard +endif + +ifeq ($(KERNEL_BUILD), 0) +KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/ipc/Module.symvers +KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/dsp/Module.symvers +KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/Module.symvers +KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/codecs/Module.symvers +KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/soc/Module.symvers +endif + +# Module information used by KBuild framework +obj-$(CONFIG_SND_SOC_TFA98XX) += tfa98xx_dlkm.o +tfa98xx_dlkm-y := $(TFA98XX_OBJS) + +# inject some build related information +DEFINES += -DBUILD_TIMESTAMP=\"$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')\" diff --git a/techpack/audio/asoc/codecs/tfa9874/config.h b/techpack/audio/asoc/codecs/tfa9874/config.h new file mode 100644 index 000000000000..82b4d2265eee --- /dev/null +++ b/techpack/audio/asoc/codecs/tfa9874/config.h @@ -0,0 +1,41 @@ +/* + * Copyright 2014-2017 NXP Semiconductors + * + * 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. + */ + +/* + Linux kernel specific definitions used by code shared with + Linux/Windows user space. +*/ + +#ifndef __CONFIG_LINUX_KERNEL_INC__ +#define __CONFIG_LINUX_KERNEL_INC__ + +#include +#include +#include +#include +#include + +#define _ASSERT(e) +#define PRINT_ASSERT(e)if ((e)) printk(KERN_ERR "PrintAssert:%s (%s:%d) error code:%d\n",__FUNCTION__,__FILE__,__LINE__, e) + +#if defined(CONFIG_TRACING) && defined(DEBUG) + #define tfa98xx_trace_printk(...) +#else + #define tfa98xx_trace_printk(...) +#endif + +#endif /* __CONFIG_LINUX_KERNEL_INC__ */ + diff --git a/techpack/audio/asoc/codecs/tfa9874/dbgprint.h b/techpack/audio/asoc/codecs/tfa9874/dbgprint.h new file mode 100644 index 000000000000..c30157c84e73 --- /dev/null +++ b/techpack/audio/asoc/codecs/tfa9874/dbgprint.h @@ -0,0 +1,165 @@ +/* + * Copyright 2014-2017 NXP Semiconductors + * + * 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 _DBGPRINT_H +# define _DBGPRINT_H + +/* Debugging macro's. */ +# ifndef DEBUG +# define DEBUG +# endif + +# ifndef ASSERT +//#define ASSERT +# endif + //TODO wwwim +# ifndef _ASSERT + #define _ASSERT(e) +# endif + +# ifndef PREFIX +# define PREFIX "tfa98xx: " +# define DRIVER_NAME "tfa98xx" +# endif + +#ifdef __KERNEL__ + +# ifdef DEBUG +# define _DEBUG(level,fmt,va...) do {\ + if (unlikely(debug >= (level))) \ + printk(KERN_INFO PREFIX "%s:%d: "fmt,__func__,__LINE__,##va); \ + } while (0) + +# else +# define _DEBUG(level,fmt,va...) do {} while(0) +# endif + +# define MSG(fmt,va...) printk(KERN_INFO PREFIX "%s:%d: "fmt,__func__,__LINE__,##va) +# define _ERRORMSG(fmt,va...) printk(KERN_ERR PREFIX "ERROR %s:%d: "fmt,__func__,__LINE__, ##va) + + +# define DEBUG0(x...) MSG(x) +# define DEBUG1(x...) _DEBUG(1,x) +# define DEBUG2(x...) _DEBUG(2,x) +# define DEBUG3(x...) _DEBUG(3,x) +# define ERRORMSG(x...) _ERRORMSG(x) +# define PRINT(x...) printk(x) +# define PRINT_ERROR(x...) printk(KERN_INFO PREFIX " **ERROR** " x) +# define PRINT_ASSERT(e)if ((e)) printk(KERN_ERR "PrintAssert:%s (%s:%d) error code:%d\n",__FUNCTION__,__FILE__,__LINE__, e) + +# define PRINT_ENTRY DEBUG2("+[%s]\n", __func__) +# define PRINT_EXIT DEBUG2("-[%s]\n", __func__) + +# ifdef ASSERT +# define assert(cond,action) do { if (unlikely(!(cond))) { DEBUG0("Assert: %s\n",#cond); action; }} while(0) +# else +# define assert(cond,action) do { } while (0) +# endif + +#else /* __KERNEL__ */ +#if defined(WIN32) || defined(_X64) +#include +/* user mode */ +# ifdef DEBUG +# define _DEBUGMSG(level,fmt,...) printf(PREFIX "%s:%d: "fmt,__FUNCTION__,__LINE__,__VA_ARGS__); +# else +# define _DEBUGMSG(level,fmt,...) do {} while(0) +# endif + +# define _ERRORMSG(fmt,...) printf(PREFIX "%s:%s:%d: "fmt,__FILE__,__FUNCTION__,__LINE__,__VA_ARGS__) + +# define DEBUG0(...) MSG(__VA_ARGS__) +# define DEBUG1(...) _DEBUGMSG(1,__VA_ARGS__) +# define DEBUG2(...) _DEBUGMSG(2,__VA_ARGS__) +# define DEBUG3(...) _DEBUGMSG(3,__VA_ARGS__) +# define ERRORMSG(fmt,...) _ERRORMSG(fmt,__VA_ARGS__) +# define PRINT(...) printf(__VA_ARGS__) +/* +# define PRINT(...) { FILE *stream; \ + if((stream = freopen("nxp_tfa.txt", "ab+", stdout)) == NULL) exit(-1); \ + printf(__VA_ARGS__); \ + freopen( "CON", "ab+", stdout ); \ + } +*/ +# define PRINT_ERROR(...) fprintf(stderr,__VA_ARGS__) +# define PRINT_FILE(file,...) fprintf(file,__VA_ARGS__) +# define PRINT_ASSERT(e)if ((e)) fprintf(stderr, "PrintAssert:%s (%s:%d) error code:%d\n",__FUNCTION__,__FILE__,__LINE__, e) +//# define PRINT_ASSERT(e) if ((e)) fprintf(stderr, "PrintAssert:%s (%s:%d) %s\n",__FUNCTION__,__FILE__,__LINE__, Tfa98xx_GetErrorString(e)) + +#elif defined(__CODE_RED) +#include "app_global.h" +# ifdef DEBUG +# define _DEBUG(level,fmt,va...) TB_TRACE_INF(TbTracePfx2("tfa",TB_FUNC,va)) +//printf(PREFIX "%s:%d: "fmt,__func__,__LINE__,##va); +# else +# define _DEBUG(level,fmt,va...) do {} while(0) +# endif + +# define MSG(fmt,...) TB_TRACE_INF(TbTracePfx2("tfa",TB_FUNC,__VA_ARGS__)) +//printf(PREFIX "%s:%s:%d: "fmt,__FILE__,__func__,__LINE__,##va) +//TB_TRACE_INF(TbTracePfx2(APP_PFX,TB_FUNC,"path=%s, chan=%u, muted=%s, vol=%d\n", +// path->isRecording ? "recording" : "playback", +// i, +// channelVol.currentMuteValue ? "YES" : "NO", +// channelVol.currentVolumeValue +// )); +//# define _ERRORMSG(fmt,va...) TB_TRACE_INF(TbTracePfx2("tfa",TB_FUNC,va)) +# define ERRORMSG(...) TB_TRACE_INF(TbTracePfx2("tfa",TB_FUNC,__VA_ARGS__)) +//fprintf(stderr, PREFIX "ERROR %s:%s:%d: "fmt,__FILE__,__func__,__LINE__, ##va) + +# define DEBUG0(x...) MSG(x) +# define DEBUG1(x...) _DEBUG(1,x) +# define DEBUG2(x...) _DEBUG(2,x) +# define DEBUG3(x...) _DEBUG(3,x) +//# define ERRORMSG(x...) _ERRORMSG(x) +# define PRINT(x...) TB_TRACE_INF(TbTracePfx2("tfa",TB_FUNC,x)) +//printf(x) +# define PRINT_ERROR(x...) TB_TRACE_INF(TbTracePfx2("tfa",TB_FUNC,x)) +//fprintf(stderr,__VA_ARGS__) +# define PRINT_FILE(file,x...) TB_TRACE_INF(TbTracePfx2("tfa",TB_FUNC,x)) +//fprintf(file,__VA_ARGS__) +# define PRINT_ASSERT(e) +//TB_TRACE_INF(TbTracePfx2("tfa",TB_FUNC,Tfa98xx_GetErrorString(e))) +//if ((e)) fprintf(stderr, "PrintAssert:%s (%s:%d) %s\n",__FUNCTION__,__FILE__,__LINE__, Tfa98xx_GetErrorString(e)) +#else +#include +/* user mode */ +# ifdef DEBUG +# define _DEBUG(level,fmt,va...) printf(PREFIX "%s:%d: "fmt,__func__,__LINE__,##va); +# else +# define _DEBUG(level,fmt,va...) do {} while(0) +# endif + +# define MSG(fmt,va...) printf(PREFIX "%s:%s:%d: "fmt,__FILE__,__func__,__LINE__,##va) +# define _ERRORMSG(fmt,va...) fprintf(stderr, PREFIX "ERROR %s:%s:%d: "fmt,__FILE__,__func__,__LINE__, ##va) + +# define DEBUG0(x...) MSG(x) +# define DEBUG1(x...) _DEBUG(1,x) +# define DEBUG2(x...) _DEBUG(2,x) +# define DEBUG3(x...) _DEBUG(3,x) +# define ERRORMSG(x...) _ERRORMSG(x) +# define PRINT(x...) printf(x) +# define PRINT_ERROR(...) fprintf(stderr,__VA_ARGS__) +# define PRINT_FILE(file,...) fprintf(file,__VA_ARGS__) +# define PRINT_ASSERT(e)if ((e)) fprintf(stderr, "PrintAssert:%s (%s:%d) error code:%d\n",__FUNCTION__,__FILE__,__LINE__, e) +//# define PRINT_ASSERT(e) if ((e)) fprintf(stderr, "PrintAssert:%s (%s:%d) %s\n",__FUNCTION__,__FILE__,__LINE__, Tfa98xx_GetErrorString(e)) + + +#endif /* WIN32 */ + +#endif /* user */ + +#endif /* _DBGPRINT_H --------------- */ diff --git a/techpack/audio/asoc/codecs/tfa9874/tfa.h b/techpack/audio/asoc/codecs/tfa9874/tfa.h new file mode 100644 index 000000000000..2cf59f107e89 --- /dev/null +++ b/techpack/audio/asoc/codecs/tfa9874/tfa.h @@ -0,0 +1,49 @@ +/* + * Copyright 2015-2017 NXP Semiconductors + * + * 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 TFA_H_ +#define TFA_H_ + +/* set the limit for the container file length */ +#define TFA_MAX_CNT_LENGTH (256*1024) + +extern struct tfa_device **devs; + +/** + * tfa error return codes + */ +enum tfa_error { + tfa_error_ok, /**< no error */ + tfa_error_device, /**< no response from device */ + tfa_error_bad_param,/**< parameter no accepted */ + tfa_error_noclock, /**< required clock not present */ + tfa_error_timeout, /**< a timeout occurred */ + tfa_error_dsp, /**< a DSP error was returned */ + tfa_error_container,/**< no or wrong container file */ + tfa_error_max /**< impossible value, max enum */ +}; + +enum Tfa98xx_Error tfa_write_filters(struct tfa_device *tfa, int prof_idx); + +struct tfa_device ** tfa_devs_create(int count); +void tfa_devs_destroy(int count); + +struct tfa_device ** tfa_get_device_struct(void); + +int tfa_plop_noise_interrupt(struct tfa_device *tfa, int profile, int vstep); +void tfa_lp_mode_interrupt(struct tfa_device *tfa); + +#endif /* TFA_H_ */ diff --git a/techpack/audio/asoc/codecs/tfa9874/tfa1_tfafieldnames.h b/techpack/audio/asoc/codecs/tfa9874/tfa1_tfafieldnames.h new file mode 100644 index 000000000000..f83156ea9e11 --- /dev/null +++ b/techpack/audio/asoc/codecs/tfa9874/tfa1_tfafieldnames.h @@ -0,0 +1,900 @@ +/** Filename: Tfa1_TfaFieldnames.h + * This file was generated automatically on 03/20/2015 at 01:55:46 PM. + * Source file: TFA9897N1B_I2C_list_URT_Source_v34.xls + */ +#define TFA9897_I2CVERSION 34 +typedef enum nxpTfa1BfEnumList { + TFA1_BF_VDDS = 0x0000, /*!< Power-on-reset flag */ + TFA1_BF_PLLS = 0x0010, /*!< PLL lock */ + TFA1_BF_OTDS = 0x0020, /*!< Over Temperature Protection alarm */ + TFA1_BF_OVDS = 0x0030, /*!< Over Voltage Protection alarm */ + TFA1_BF_UVDS = 0x0040, /*!< Under Voltage Protection alarm */ + TFA1_BF_OCDS = 0x0050, /*!< Over Current Protection alarm */ + TFA1_BF_CLKS = 0x0060, /*!< Clocks stable flag */ + TFA1_BF_CLIPS = 0x0070, /*!< Amplifier clipping */ + TFA1_BF_MTPB = 0x0080, /*!< MTP busy */ + TFA1_BF_NOCLK = 0x0090, /*!< Flag lost clock from clock generation unit */ + TFA1_BF_SPKS = 0x00a0, /*!< Speaker error flag */ + TFA1_BF_ACS = 0x00b0, /*!< Cold Start flag */ + TFA1_BF_SWS = 0x00c0, /*!< Flag Engage */ + TFA1_BF_WDS = 0x00d0, /*!< Flag watchdog reset */ + TFA1_BF_AMPS = 0x00e0, /*!< Amplifier is enabled by manager */ + TFA1_BF_AREFS = 0x00f0, /*!< References are enabled by manager */ + TFA1_BF_BATS = 0x0109, /*!< Battery voltage readout; 0 .. 5.5 [V] */ + TFA1_BF_TEMPS = 0x0208, /*!< Temperature readout from the temperature sensor */ + TFA1_BF_REV = 0x030b, /*!< Device type number is B97 */ + TFA1_BF_RCV = 0x0420, /*!< Enable Receiver Mode */ + TFA1_BF_CHS12 = 0x0431, /*!< Channel Selection TDM input for Coolflux */ + TFA1_BF_INPLVL= 0x0450, /*!< Input level selection control */ + TFA1_BF_CHSA = 0x0461, /*!< Input selection for amplifier */ + TFA1_BF_I2SDOE= 0x04b0, /*!< Enable data output */ + TFA1_BF_AUDFS = 0x04c3, /*!< Audio sample rate setting */ + TFA1_BF_BSSCR = 0x0501, /*!< Protection Attack Time */ + TFA1_BF_BSST = 0x0523, /*!< ProtectionThreshold */ + TFA1_BF_BSSRL = 0x0561, /*!< Protection Maximum Reduction */ + TFA1_BF_BSSRR = 0x0582, /*!< Battery Protection Release Time */ + TFA1_BF_BSSHY = 0x05b1, /*!< Battery Protection Hysteresis */ + TFA1_BF_BSSR = 0x05e0, /*!< battery voltage for I2C read out only */ + TFA1_BF_BSSBY = 0x05f0, /*!< bypass clipper battery protection */ + TFA1_BF_DPSA = 0x0600, /*!< Enable dynamic powerstage activation */ + TFA1_BF_CFSM = 0x0650, /*!< Soft mute in CoolFlux */ + TFA1_BF_BSSS = 0x0670, /*!< BatSenseSteepness */ + TFA1_BF_VOL = 0x0687, /*!< volume control (in CoolFlux) */ + TFA1_BF_DCVO = 0x0702, /*!< Boost Voltage */ + TFA1_BF_DCMCC = 0x0733, /*!< Max boost coil current - step of 175 mA */ + TFA1_BF_DCIE = 0x07a0, /*!< Adaptive boost mode */ + TFA1_BF_DCSR = 0x07b0, /*!< Soft RampUp/Down mode for DCDC controller */ + TFA1_BF_DCPAVG= 0x07c0, /*!< ctrl_peak2avg for analog part of DCDC */ + TFA1_BF_TROS = 0x0800, /*!< Select external temperature also the ext_temp will be put on the temp read out */ + TFA1_BF_EXTTS = 0x0818, /*!< external temperature setting to be given by host */ + TFA1_BF_PWDN = 0x0900, /*!< Device Mode */ + TFA1_BF_I2CR = 0x0910, /*!< I2C Reset */ + TFA1_BF_CFE = 0x0920, /*!< Enable CoolFlux */ + TFA1_BF_AMPE = 0x0930, /*!< Enable Amplifier */ + TFA1_BF_DCA = 0x0940, /*!< EnableBoost */ + TFA1_BF_SBSL = 0x0950, /*!< Coolflux configured */ + TFA1_BF_AMPC = 0x0960, /*!< Selection on how Amplifier is enabled */ + TFA1_BF_DCDIS = 0x0970, /*!< DCDC not connected */ + TFA1_BF_PSDR = 0x0980, /*!< IDDQ test amplifier */ + TFA1_BF_DCCV = 0x0991, /*!< Coil Value */ + TFA1_BF_CCFD = 0x09b0, /*!< Selection CoolFlux Clock */ + TFA1_BF_INTPAD= 0x09c1, /*!< INT pad configuration control */ + TFA1_BF_IPLL = 0x09e0, /*!< PLL input reference clock selection */ + TFA1_BF_MTPK = 0x0b07, /*!< 5Ah, 90d To access KEY1_Protected registers (Default for engineering) */ + TFA1_BF_CVFDLY= 0x0c25, /*!< Fractional delay adjustment between current and voltage sense */ + TFA1_BF_TDMPRF= 0x1011, /*!< TDM_usecase */ + TFA1_BF_TDMEN = 0x1030, /*!< TDM interface control */ + TFA1_BF_TDMCKINV= 0x1040, /*!< TDM clock inversion */ + TFA1_BF_TDMFSLN= 0x1053, /*!< TDM FS length */ + TFA1_BF_TDMFSPOL= 0x1090, /*!< TDM FS polarity */ + TFA1_BF_TDMSAMSZ= 0x10a4, /*!< TDM Sample Size for all tdm sinks/sources */ + TFA1_BF_TDMSLOTS= 0x1103, /*!< Number of slots */ + TFA1_BF_TDMSLLN= 0x1144, /*!< Slot length */ + TFA1_BF_TDMBRMG= 0x1194, /*!< Bits remaining */ + TFA1_BF_TDMDDEL= 0x11e0, /*!< Data delay */ + TFA1_BF_TDMDADJ= 0x11f0, /*!< Data adjustment */ + TFA1_BF_TDMTXFRM= 0x1201, /*!< TXDATA format */ + TFA1_BF_TDMUUS0= 0x1221, /*!< TXDATA format unused slot sd0 */ + TFA1_BF_TDMUUS1= 0x1241, /*!< TXDATA format unused slot sd1 */ + TFA1_BF_TDMSI0EN= 0x1270, /*!< TDM sink0 enable */ + TFA1_BF_TDMSI1EN= 0x1280, /*!< TDM sink1 enable */ + TFA1_BF_TDMSI2EN= 0x1290, /*!< TDM sink2 enable */ + TFA1_BF_TDMSO0EN= 0x12a0, /*!< TDM source0 enable */ + TFA1_BF_TDMSO1EN= 0x12b0, /*!< TDM source1 enable */ + TFA1_BF_TDMSO2EN= 0x12c0, /*!< TDM source2 enable */ + TFA1_BF_TDMSI0IO= 0x12d0, /*!< tdm_sink0_io */ + TFA1_BF_TDMSI1IO= 0x12e0, /*!< tdm_sink1_io */ + TFA1_BF_TDMSI2IO= 0x12f0, /*!< tdm_sink2_io */ + TFA1_BF_TDMSO0IO= 0x1300, /*!< tdm_source0_io */ + TFA1_BF_TDMSO1IO= 0x1310, /*!< tdm_source1_io */ + TFA1_BF_TDMSO2IO= 0x1320, /*!< tdm_source2_io */ + TFA1_BF_TDMSI0SL= 0x1333, /*!< sink0_slot [GAIN IN] */ + TFA1_BF_TDMSI1SL= 0x1373, /*!< sink1_slot [CH1 IN] */ + TFA1_BF_TDMSI2SL= 0x13b3, /*!< sink2_slot [CH2 IN] */ + TFA1_BF_TDMSO0SL= 0x1403, /*!< source0_slot [GAIN OUT] */ + TFA1_BF_TDMSO1SL= 0x1443, /*!< source1_slot [Voltage Sense] */ + TFA1_BF_TDMSO2SL= 0x1483, /*!< source2_slot [Current Sense] */ + TFA1_BF_NBCK = 0x14c3, /*!< NBCK */ + TFA1_BF_INTOVDDS= 0x2000, /*!< flag_por_int_out */ + TFA1_BF_INTOPLLS= 0x2010, /*!< flag_pll_lock_int_out */ + TFA1_BF_INTOOTDS= 0x2020, /*!< flag_otpok_int_out */ + TFA1_BF_INTOOVDS= 0x2030, /*!< flag_ovpok_int_out */ + TFA1_BF_INTOUVDS= 0x2040, /*!< flag_uvpok_int_out */ + TFA1_BF_INTOOCDS= 0x2050, /*!< flag_ocp_alarm_int_out */ + TFA1_BF_INTOCLKS= 0x2060, /*!< flag_clocks_stable_int_out */ + TFA1_BF_INTOCLIPS= 0x2070, /*!< flag_clip_int_out */ + TFA1_BF_INTOMTPB= 0x2080, /*!< mtp_busy_int_out */ + TFA1_BF_INTONOCLK= 0x2090, /*!< flag_lost_clk_int_out */ + TFA1_BF_INTOSPKS= 0x20a0, /*!< flag_cf_speakererror_int_out */ + TFA1_BF_INTOACS= 0x20b0, /*!< flag_cold_started_int_out */ + TFA1_BF_INTOSWS= 0x20c0, /*!< flag_engage_int_out */ + TFA1_BF_INTOWDS= 0x20d0, /*!< flag_watchdog_reset_int_out */ + TFA1_BF_INTOAMPS= 0x20e0, /*!< flag_enbl_amp_int_out */ + TFA1_BF_INTOAREFS= 0x20f0, /*!< flag_enbl_ref_int_out */ + TFA1_BF_INTOACK= 0x2201, /*!< Interrupt status register output - Corresponding flag */ + TFA1_BF_INTIVDDS= 0x2300, /*!< flag_por_int_in */ + TFA1_BF_INTIPLLS= 0x2310, /*!< flag_pll_lock_int_in */ + TFA1_BF_INTIOTDS= 0x2320, /*!< flag_otpok_int_in */ + TFA1_BF_INTIOVDS= 0x2330, /*!< flag_ovpok_int_in */ + TFA1_BF_INTIUVDS= 0x2340, /*!< flag_uvpok_int_in */ + TFA1_BF_INTIOCDS= 0x2350, /*!< flag_ocp_alarm_int_in */ + TFA1_BF_INTICLKS= 0x2360, /*!< flag_clocks_stable_int_in */ + TFA1_BF_INTICLIPS= 0x2370, /*!< flag_clip_int_in */ + TFA1_BF_INTIMTPB= 0x2380, /*!< mtp_busy_int_in */ + TFA1_BF_INTINOCLK= 0x2390, /*!< flag_lost_clk_int_in */ + TFA1_BF_INTISPKS= 0x23a0, /*!< flag_cf_speakererror_int_in */ + TFA1_BF_INTIACS= 0x23b0, /*!< flag_cold_started_int_in */ + TFA1_BF_INTISWS= 0x23c0, /*!< flag_engage_int_in */ + TFA1_BF_INTIWDS= 0x23d0, /*!< flag_watchdog_reset_int_in */ + TFA1_BF_INTIAMPS= 0x23e0, /*!< flag_enbl_amp_int_in */ + TFA1_BF_INTIAREFS= 0x23f0, /*!< flag_enbl_ref_int_in */ + TFA1_BF_INTIACK= 0x2501, /*!< Interrupt register input */ + TFA1_BF_INTENVDDS= 0x2600, /*!< flag_por_int_enable */ + TFA1_BF_INTENPLLS= 0x2610, /*!< flag_pll_lock_int_enable */ + TFA1_BF_INTENOTDS= 0x2620, /*!< flag_otpok_int_enable */ + TFA1_BF_INTENOVDS= 0x2630, /*!< flag_ovpok_int_enable */ + TFA1_BF_INTENUVDS= 0x2640, /*!< flag_uvpok_int_enable */ + TFA1_BF_INTENOCDS= 0x2650, /*!< flag_ocp_alarm_int_enable */ + TFA1_BF_INTENCLKS= 0x2660, /*!< flag_clocks_stable_int_enable */ + TFA1_BF_INTENCLIPS= 0x2670, /*!< flag_clip_int_enable */ + TFA1_BF_INTENMTPB= 0x2680, /*!< mtp_busy_int_enable */ + TFA1_BF_INTENNOCLK= 0x2690, /*!< flag_lost_clk_int_enable */ + TFA1_BF_INTENSPKS= 0x26a0, /*!< flag_cf_speakererror_int_enable */ + TFA1_BF_INTENACS= 0x26b0, /*!< flag_cold_started_int_enable */ + TFA1_BF_INTENSWS= 0x26c0, /*!< flag_engage_int_enable */ + TFA1_BF_INTENWDS= 0x26d0, /*!< flag_watchdog_reset_int_enable */ + TFA1_BF_INTENAMPS= 0x26e0, /*!< flag_enbl_amp_int_enable */ + TFA1_BF_INTENAREFS= 0x26f0, /*!< flag_enbl_ref_int_enable */ + TFA1_BF_INTENACK= 0x2801, /*!< Interrupt enable register */ + TFA1_BF_INTPOLVDDS= 0x2900, /*!< flag_por_int_pol */ + TFA1_BF_INTPOLPLLS= 0x2910, /*!< flag_pll_lock_int_pol */ + TFA1_BF_INTPOLOTDS= 0x2920, /*!< flag_otpok_int_pol */ + TFA1_BF_INTPOLOVDS= 0x2930, /*!< flag_ovpok_int_pol */ + TFA1_BF_INTPOLUVDS= 0x2940, /*!< flag_uvpok_int_pol */ + TFA1_BF_INTPOLOCDS= 0x2950, /*!< flag_ocp_alarm_int_pol */ + TFA1_BF_INTPOLCLKS= 0x2960, /*!< flag_clocks_stable_int_pol */ + TFA1_BF_INTPOLCLIPS= 0x2970, /*!< flag_clip_int_pol */ + TFA1_BF_INTPOLMTPB= 0x2980, /*!< mtp_busy_int_pol */ + TFA1_BF_INTPOLNOCLK= 0x2990, /*!< flag_lost_clk_int_pol */ + TFA1_BF_INTPOLSPKS= 0x29a0, /*!< flag_cf_speakererror_int_pol */ + TFA1_BF_INTPOLACS= 0x29b0, /*!< flag_cold_started_int_pol */ + TFA1_BF_INTPOLSWS= 0x29c0, /*!< flag_engage_int_pol */ + TFA1_BF_INTPOLWDS= 0x29d0, /*!< flag_watchdog_reset_int_pol */ + TFA1_BF_INTPOLAMPS= 0x29e0, /*!< flag_enbl_amp_int_pol */ + TFA1_BF_INTPOLAREFS= 0x29f0, /*!< flag_enbl_ref_int_pol */ + TFA1_BF_INTPOLACK= 0x2b01, /*!< Interrupt status flags polarity register */ + TFA1_BF_CLIP = 0x4900, /*!< Bypass clip control */ + TFA1_BF_CIMTP = 0x62b0, /*!< start copying all the data from i2cregs_mtp to mtp [Key 2 protected] */ + TFA1_BF_RST = 0x7000, /*!< Reset CoolFlux DSP */ + TFA1_BF_DMEM = 0x7011, /*!< Target memory for access */ + TFA1_BF_AIF = 0x7030, /*!< Autoincrement-flag for memory-address */ + TFA1_BF_CFINT = 0x7040, /*!< Interrupt CoolFlux DSP */ + TFA1_BF_REQ = 0x7087, /*!< request for access (8 channels) */ + TFA1_BF_REQCMD= 0x7080, /*!< Firmware event request rpc command */ + TFA1_BF_REQRST= 0x7090, /*!< Firmware event request reset restart */ + TFA1_BF_REQMIPS= 0x70a0, /*!< Firmware event request short on mips */ + TFA1_BF_REQMUTED= 0x70b0, /*!< Firmware event request mute sequence ready */ + TFA1_BF_REQVOL= 0x70c0, /*!< Firmware event request volume ready */ + TFA1_BF_REQDMG= 0x70d0, /*!< Firmware event request speaker damage detected */ + TFA1_BF_REQCAL= 0x70e0, /*!< Firmware event request calibration completed */ + TFA1_BF_REQRSV= 0x70f0, /*!< Firmware event request reserved */ + TFA1_BF_MADD = 0x710f, /*!< memory-address to be accessed */ + TFA1_BF_MEMA = 0x720f, /*!< activate memory access (24- or 32-bits data is written/read to/from memory */ + TFA1_BF_ERR = 0x7307, /*!< Coolflux error flags */ + TFA1_BF_ACK = 0x7387, /*!< acknowledge of requests (8 channels) */ + TFA1_BF_MTPOTC= 0x8000, /*!< Calibration schedule (key2 protected) */ + TFA1_BF_MTPEX = 0x8010, /*!< (key2 protected) */ +} nxpTfa1BfEnumList_t; +#define TFA1_NAMETABLE static tfaBfName_t Tfa1DatasheetNames[]= {\ + { 0x0, "VDDS"}, /* Power-on-reset flag , */\ + { 0x10, "PLLS"}, /* PLL lock , */\ + { 0x20, "OTDS"}, /* Over Temperature Protection alarm , */\ + { 0x30, "OVDS"}, /* Over Voltage Protection alarm , */\ + { 0x40, "UVDS"}, /* Under Voltage Protection alarm , */\ + { 0x50, "OCDS"}, /* Over Current Protection alarm , */\ + { 0x60, "CLKS"}, /* Clocks stable flag , */\ + { 0x70, "CLIPS"}, /* Amplifier clipping , */\ + { 0x80, "MTPB"}, /* MTP busy , */\ + { 0x90, "NOCLK"}, /* Flag lost clock from clock generation unit , */\ + { 0xa0, "SPKS"}, /* Speaker error flag , */\ + { 0xb0, "ACS"}, /* Cold Start flag , */\ + { 0xc0, "SWS"}, /* Flag Engage , */\ + { 0xd0, "WDS"}, /* Flag watchdog reset , */\ + { 0xe0, "AMPS"}, /* Amplifier is enabled by manager , */\ + { 0xf0, "AREFS"}, /* References are enabled by manager , */\ + { 0x109, "BATS"}, /* Battery voltage readout; 0 .. 5.5 [V] , */\ + { 0x208, "TEMPS"}, /* Temperature readout from the temperature sensor , */\ + { 0x30b, "REV"}, /* Device type number is B97 , */\ + { 0x420, "RCV"}, /* Enable Receiver Mode , */\ + { 0x431, "CHS12"}, /* Channel Selection TDM input for Coolflux , */\ + { 0x450, "INPLVL"}, /* Input level selection control , */\ + { 0x461, "CHSA"}, /* Input selection for amplifier , */\ + { 0x4b0, "I2SDOE"}, /* Enable data output , */\ + { 0x4c3, "AUDFS"}, /* Audio sample rate setting , */\ + { 0x501, "SSCR"}, /* Protection Attack Time , */\ + { 0x523, "SST"}, /* ProtectionThreshold , */\ + { 0x561, "SSRL"}, /* Protection Maximum Reduction , */\ + { 0x582, "SSRR"}, /* Battery Protection Release Time , */\ + { 0x5b1, "SSHY"}, /* Battery Protection Hysteresis , */\ + { 0x5e0, "SSR"}, /* battery voltage for I2C read out only , */\ + { 0x5f0, "SSBY"}, /* bypass clipper battery protection , */\ + { 0x600, "DPSA"}, /* Enable dynamic powerstage activation , */\ + { 0x650, "CFSM"}, /* Soft mute in CoolFlux , */\ + { 0x670, "SSS"}, /* BatSenseSteepness , */\ + { 0x687, "VOL"}, /* volume control (in CoolFlux) , */\ + { 0x702, "DCVO"}, /* Boost Voltage , */\ + { 0x733, "DCMCC"}, /* Max boost coil current - step of 175 mA , */\ + { 0x7a0, "DCIE"}, /* Adaptive boost mode , */\ + { 0x7b0, "DCSR"}, /* Soft RampUp/Down mode for DCDC controller , */\ + { 0x7c0, "DCPAVG"}, /* ctrl_peak2avg for analog part of DCDC , */\ + { 0x800, "TROS"}, /* Select external temperature also the ext_temp will be put on the temp read out , */\ + { 0x818, "EXTTS"}, /* external temperature setting to be given by host , */\ + { 0x900, "PWDN"}, /* Device Mode , */\ + { 0x910, "I2CR"}, /* I2C Reset , */\ + { 0x920, "CFE"}, /* Enable CoolFlux , */\ + { 0x930, "AMPE"}, /* Enable Amplifier , */\ + { 0x940, "DCA"}, /* EnableBoost , */\ + { 0x950, "SBSL"}, /* Coolflux configured , */\ + { 0x960, "AMPC"}, /* Selection on how Amplifier is enabled , */\ + { 0x970, "DCDIS"}, /* DCDC not connected , */\ + { 0x980, "PSDR"}, /* IDDQ test amplifier , */\ + { 0x991, "DCCV"}, /* Coil Value , */\ + { 0x9b0, "CCFD"}, /* Selection CoolFlux Clock , */\ + { 0x9c1, "INTPAD"}, /* INT pad configuration control , */\ + { 0x9e0, "IPLL"}, /* PLL input reference clock selection , */\ + { 0xb07, "MTPK"}, /* 5Ah, 90d To access KEY1_Protected registers (Default for engineering), */\ + { 0xc25, "CVFDLY"}, /* Fractional delay adjustment between current and voltage sense, */\ + { 0x1011, "TDMPRF"}, /* TDM_usecase , */\ + { 0x1030, "TDMEN"}, /* TDM interface control , */\ + { 0x1040, "TDMCKINV"}, /* TDM clock inversion , */\ + { 0x1053, "TDMFSLN"}, /* TDM FS length , */\ + { 0x1090, "TDMFSPOL"}, /* TDM FS polarity , */\ + { 0x10a4, "TDMSAMSZ"}, /* TDM Sample Size for all tdm sinks/sources , */\ + { 0x1103, "TDMSLOTS"}, /* Number of slots , */\ + { 0x1144, "TDMSLLN"}, /* Slot length , */\ + { 0x1194, "TDMBRMG"}, /* Bits remaining , */\ + { 0x11e0, "TDMDDEL"}, /* Data delay , */\ + { 0x11f0, "TDMDADJ"}, /* Data adjustment , */\ + { 0x1201, "TDMTXFRM"}, /* TXDATA format , */\ + { 0x1221, "TDMUUS0"}, /* TXDATA format unused slot sd0 , */\ + { 0x1241, "TDMUUS1"}, /* TXDATA format unused slot sd1 , */\ + { 0x1270, "TDMSI0EN"}, /* TDM sink0 enable , */\ + { 0x1280, "TDMSI1EN"}, /* TDM sink1 enable , */\ + { 0x1290, "TDMSI2EN"}, /* TDM sink2 enable , */\ + { 0x12a0, "TDMSO0EN"}, /* TDM source0 enable , */\ + { 0x12b0, "TDMSO1EN"}, /* TDM source1 enable , */\ + { 0x12c0, "TDMSO2EN"}, /* TDM source2 enable , */\ + { 0x12d0, "TDMSI0IO"}, /* tdm_sink0_io , */\ + { 0x12e0, "TDMSI1IO"}, /* tdm_sink1_io , */\ + { 0x12f0, "TDMSI2IO"}, /* tdm_sink2_io , */\ + { 0x1300, "TDMSO0IO"}, /* tdm_source0_io , */\ + { 0x1310, "TDMSO1IO"}, /* tdm_source1_io , */\ + { 0x1320, "TDMSO2IO"}, /* tdm_source2_io , */\ + { 0x1333, "TDMSI0SL"}, /* sink0_slot [GAIN IN] , */\ + { 0x1373, "TDMSI1SL"}, /* sink1_slot [CH1 IN] , */\ + { 0x13b3, "TDMSI2SL"}, /* sink2_slot [CH2 IN] , */\ + { 0x1403, "TDMSO0SL"}, /* source0_slot [GAIN OUT] , */\ + { 0x1443, "TDMSO1SL"}, /* source1_slot [Voltage Sense] , */\ + { 0x1483, "TDMSO2SL"}, /* source2_slot [Current Sense] , */\ + { 0x14c3, "NBCK"}, /* NBCK , */\ + { 0x2000, "INTOVDDS"}, /* flag_por_int_out , */\ + { 0x2010, "INTOPLLS"}, /* flag_pll_lock_int_out , */\ + { 0x2020, "INTOOTDS"}, /* flag_otpok_int_out , */\ + { 0x2030, "INTOOVDS"}, /* flag_ovpok_int_out , */\ + { 0x2040, "INTOUVDS"}, /* flag_uvpok_int_out , */\ + { 0x2050, "INTOOCDS"}, /* flag_ocp_alarm_int_out , */\ + { 0x2060, "INTOCLKS"}, /* flag_clocks_stable_int_out , */\ + { 0x2070, "INTOCLIPS"}, /* flag_clip_int_out , */\ + { 0x2080, "INTOMTPB"}, /* mtp_busy_int_out , */\ + { 0x2090, "INTONOCLK"}, /* flag_lost_clk_int_out , */\ + { 0x20a0, "INTOSPKS"}, /* flag_cf_speakererror_int_out , */\ + { 0x20b0, "INTOACS"}, /* flag_cold_started_int_out , */\ + { 0x20c0, "INTOSWS"}, /* flag_engage_int_out , */\ + { 0x20d0, "INTOWDS"}, /* flag_watchdog_reset_int_out , */\ + { 0x20e0, "INTOAMPS"}, /* flag_enbl_amp_int_out , */\ + { 0x20f0, "INTOAREFS"}, /* flag_enbl_ref_int_out , */\ + { 0x2201, "INTOACK"}, /* Interrupt status register output - Corresponding flag, */\ + { 0x2300, "INTIVDDS"}, /* flag_por_int_in , */\ + { 0x2310, "INTIPLLS"}, /* flag_pll_lock_int_in , */\ + { 0x2320, "INTIOTDS"}, /* flag_otpok_int_in , */\ + { 0x2330, "INTIOVDS"}, /* flag_ovpok_int_in , */\ + { 0x2340, "INTIUVDS"}, /* flag_uvpok_int_in , */\ + { 0x2350, "INTIOCDS"}, /* flag_ocp_alarm_int_in , */\ + { 0x2360, "INTICLKS"}, /* flag_clocks_stable_int_in , */\ + { 0x2370, "INTICLIPS"}, /* flag_clip_int_in , */\ + { 0x2380, "INTIMTPB"}, /* mtp_busy_int_in , */\ + { 0x2390, "INTINOCLK"}, /* flag_lost_clk_int_in , */\ + { 0x23a0, "INTISPKS"}, /* flag_cf_speakererror_int_in , */\ + { 0x23b0, "INTIACS"}, /* flag_cold_started_int_in , */\ + { 0x23c0, "INTISWS"}, /* flag_engage_int_in , */\ + { 0x23d0, "INTIWDS"}, /* flag_watchdog_reset_int_in , */\ + { 0x23e0, "INTIAMPS"}, /* flag_enbl_amp_int_in , */\ + { 0x23f0, "INTIAREFS"}, /* flag_enbl_ref_int_in , */\ + { 0x2501, "INTIACK"}, /* Interrupt register input , */\ + { 0x2600, "INTENVDDS"}, /* flag_por_int_enable , */\ + { 0x2610, "INTENPLLS"}, /* flag_pll_lock_int_enable , */\ + { 0x2620, "INTENOTDS"}, /* flag_otpok_int_enable , */\ + { 0x2630, "INTENOVDS"}, /* flag_ovpok_int_enable , */\ + { 0x2640, "INTENUVDS"}, /* flag_uvpok_int_enable , */\ + { 0x2650, "INTENOCDS"}, /* flag_ocp_alarm_int_enable , */\ + { 0x2660, "INTENCLKS"}, /* flag_clocks_stable_int_enable , */\ + { 0x2670, "INTENCLIPS"}, /* flag_clip_int_enable , */\ + { 0x2680, "INTENMTPB"}, /* mtp_busy_int_enable , */\ + { 0x2690, "INTENNOCLK"}, /* flag_lost_clk_int_enable , */\ + { 0x26a0, "INTENSPKS"}, /* flag_cf_speakererror_int_enable , */\ + { 0x26b0, "INTENACS"}, /* flag_cold_started_int_enable , */\ + { 0x26c0, "INTENSWS"}, /* flag_engage_int_enable , */\ + { 0x26d0, "INTENWDS"}, /* flag_watchdog_reset_int_enable , */\ + { 0x26e0, "INTENAMPS"}, /* flag_enbl_amp_int_enable , */\ + { 0x26f0, "INTENAREFS"}, /* flag_enbl_ref_int_enable , */\ + { 0x2801, "INTENACK"}, /* Interrupt enable register , */\ + { 0x2900, "INTPOLVDDS"}, /* flag_por_int_pol , */\ + { 0x2910, "INTPOLPLLS"}, /* flag_pll_lock_int_pol , */\ + { 0x2920, "INTPOLOTDS"}, /* flag_otpok_int_pol , */\ + { 0x2930, "INTPOLOVDS"}, /* flag_ovpok_int_pol , */\ + { 0x2940, "INTPOLUVDS"}, /* flag_uvpok_int_pol , */\ + { 0x2950, "INTPOLOCDS"}, /* flag_ocp_alarm_int_pol , */\ + { 0x2960, "INTPOLCLKS"}, /* flag_clocks_stable_int_pol , */\ + { 0x2970, "INTPOLCLIPS"}, /* flag_clip_int_pol , */\ + { 0x2980, "INTPOLMTPB"}, /* mtp_busy_int_pol , */\ + { 0x2990, "INTPOLNOCLK"}, /* flag_lost_clk_int_pol , */\ + { 0x29a0, "INTPOLSPKS"}, /* flag_cf_speakererror_int_pol , */\ + { 0x29b0, "INTPOLACS"}, /* flag_cold_started_int_pol , */\ + { 0x29c0, "INTPOLSWS"}, /* flag_engage_int_pol , */\ + { 0x29d0, "INTPOLWDS"}, /* flag_watchdog_reset_int_pol , */\ + { 0x29e0, "INTPOLAMPS"}, /* flag_enbl_amp_int_pol , */\ + { 0x29f0, "INTPOLAREFS"}, /* flag_enbl_ref_int_pol , */\ + { 0x2b01, "INTPOLACK"}, /* Interrupt status flags polarity register , */\ + { 0x4900, "CLIP"}, /* Bypass clip control , */\ + { 0x62b0, "CIMTP"}, /* start copying all the data from i2cregs_mtp to mtp [Key 2 protected], */\ + { 0x7000, "RST"}, /* Reset CoolFlux DSP , */\ + { 0x7011, "DMEM"}, /* Target memory for access , */\ + { 0x7030, "AIF"}, /* Autoincrement-flag for memory-address , */\ + { 0x7040, "CFINT"}, /* Interrupt CoolFlux DSP , */\ + { 0x7087, "REQ"}, /* request for access (8 channels) , */\ + { 0x7080, "REQCMD"}, /* Firmware event request rpc command , */\ + { 0x7090, "REQRST"}, /* Firmware event request reset restart , */\ + { 0x70a0, "REQMIPS"}, /* Firmware event request short on mips , */\ + { 0x70b0, "REQMUTED"}, /* Firmware event request mute sequence ready , */\ + { 0x70c0, "REQVOL"}, /* Firmware event request volume ready , */\ + { 0x70d0, "REQDMG"}, /* Firmware event request speaker damage detected , */\ + { 0x70e0, "REQCAL"}, /* Firmware event request calibration completed , */\ + { 0x70f0, "REQRSV"}, /* Firmware event request reserved , */\ + { 0x710f, "MADD"}, /* memory-address to be accessed , */\ + { 0x720f, "MEMA"}, /* activate memory access (24- or 32-bits data is written/read to/from memory, */\ + { 0x7307, "ERR"}, /* Coolflux error flags , */\ + { 0x7387, "ACK"}, /* acknowledge of requests (8 channels) , */\ + { 0x7380, "ACKCMD"}, /* Firmware event acknowledge rpc command , */\ + { 0x7390, "ACKRST"}, /* Firmware event acknowledge reset restart , */\ + { 0x73a0, "ACKMIPS"}, /* Firmware event acknowledge short on mips , */\ + { 0x73b0, "ACKMUTED"}, /* Firmware event acknowledge mute sequence ready , */\ + { 0x73c0, "ACKVOL"}, /* Firmware event acknowledge volume ready , */\ + { 0x73d0, "ACKDMG"}, /* Firmware event acknowledge speaker damage detected, */\ + { 0x73e0, "ACKCAL"}, /* Firmware event acknowledge calibration completed , */\ + { 0x73f0, "ACKRSV"}, /* Firmware event acknowledge reserved , */\ + { 0x8000, "MTPOTC"}, /* Calibration schedule (key2 protected) , */\ + { 0x8010, "MTPEX"}, /* (key2 protected) , */\ + { 0x8045, "SWPROFIL" },\ + { 0x80a5, "SWVSTEP" },\ + { 0xffff,"Unknown bitfield enum" } /* not found */\ +}; + +#define TFA1_BITNAMETABLE static tfaBfName_t Tfa1BitNames[]= {\ + { 0x0, "flag_por"}, /* Power-on-reset flag , */\ + { 0x10, "flag_pll_lock"}, /* PLL lock , */\ + { 0x20, "flag_otpok"}, /* Over Temperature Protection alarm , */\ + { 0x30, "flag_ovpok"}, /* Over Voltage Protection alarm , */\ + { 0x40, "flag_uvpok"}, /* Under Voltage Protection alarm , */\ + { 0x50, "flag_ocp_alarm"}, /* Over Current Protection alarm , */\ + { 0x60, "flag_clocks_stable"}, /* Clocks stable flag , */\ + { 0x70, "flag_clip"}, /* Amplifier clipping , */\ + { 0x80, "mtp_busy"}, /* MTP busy , */\ + { 0x90, "flag_lost_clk"}, /* Flag lost clock from clock generation unit , */\ + { 0xa0, "flag_cf_speakererror"}, /* Speaker error flag , */\ + { 0xb0, "flag_cold_started"}, /* Cold Start flag , */\ + { 0xc0, "flag_engage"}, /* Flag Engage , */\ + { 0xd0, "flag_watchdog_reset"}, /* Flag watchdog reset , */\ + { 0xe0, "flag_enbl_amp"}, /* Amplifier is enabled by manager , */\ + { 0xf0, "flag_enbl_ref"}, /* References are enabled by manager , */\ + { 0x109, "bat_adc"}, /* Battery voltage readout; 0 .. 5.5 [V] , */\ + { 0x208, "temp_adc"}, /* Temperature readout from the temperature sensor , */\ + { 0x30b, "rev_reg"}, /* Device type number is B97 , */\ + { 0x420, "ctrl_rcv"}, /* Enable Receiver Mode , */\ + { 0x431, "chan_sel"}, /* Channel Selection TDM input for Coolflux , */\ + { 0x450, "input_level"}, /* Input level selection control , */\ + { 0x461, "vamp_sel"}, /* Input selection for amplifier , */\ + { 0x4c3, "audio_fs"}, /* Audio sample rate setting , */\ + { 0x501, "vbat_prot_attacktime"}, /* Protection Attack Time , */\ + { 0x523, "vbat_prot_thlevel"}, /* ProtectionThreshold , */\ + { 0x561, "vbat_prot_max_reduct"}, /* Protection Maximum Reduction , */\ + { 0x582, "vbat_prot_release_t"}, /* Battery Protection Release Time , */\ + { 0x5b1, "vbat_prot_hysterese"}, /* Battery Protection Hysteresis , */\ + { 0x5d0, "reset_min_vbat"}, /* reset clipper , */\ + { 0x5e0, "sel_vbat"}, /* battery voltage for I2C read out only , */\ + { 0x5f0, "bypass_clipper"}, /* bypass clipper battery protection , */\ + { 0x600, "dpsa"}, /* Enable dynamic powerstage activation , */\ + { 0x650, "cf_mute"}, /* Soft mute in CoolFlux , */\ + { 0x670, "batsense_steepness"}, /* BatSenseSteepness , */\ + { 0x687, "vol"}, /* volume control (in CoolFlux) , */\ + { 0x702, "boost_volt"}, /* Boost Voltage , */\ + { 0x733, "boost_cur"}, /* Max boost coil current - step of 175 mA , */\ + { 0x7a0, "boost_intel"}, /* Adaptive boost mode , */\ + { 0x7b0, "boost_speed"}, /* Soft RampUp/Down mode for DCDC controller , */\ + { 0x7c0, "boost_peak2avg"}, /* ctrl_peak2avg for analog part of DCDC , */\ + { 0x800, "ext_temp_sel"}, /* Select external temperature also the ext_temp will be put on the temp read out , */\ + { 0x818, "ext_temp"}, /* external temperature setting to be given by host , */\ + { 0x8b2, "dcdc_synchronisation"}, /* DCDC synchronisation off + 7 positions , */\ + { 0x900, "powerdown"}, /* Device Mode , */\ + { 0x910, "reset"}, /* I2C Reset , */\ + { 0x920, "enbl_coolflux"}, /* Enable CoolFlux , */\ + { 0x930, "enbl_amplifier"}, /* Enable Amplifier , */\ + { 0x940, "enbl_boost"}, /* EnableBoost , */\ + { 0x950, "coolflux_configured"}, /* Coolflux configured , */\ + { 0x960, "sel_enbl_amplifier"}, /* Selection on how Amplifier is enabled , */\ + { 0x970, "dcdcoff_mode"}, /* DCDC not connected , */\ + { 0x980, "iddqtest"}, /* IDDQ test amplifier , */\ + { 0x991, "coil_value"}, /* Coil Value , */\ + { 0x9b0, "sel_cf_clock"}, /* Selection CoolFlux Clock , */\ + { 0x9c1, "int_pad_io"}, /* INT pad configuration control , */\ + { 0x9e0, "sel_fs_bck"}, /* PLL input reference clock selection , */\ + { 0x9f0, "sel_scl_cf_clock"}, /* Coolflux sub-system clock , */\ + { 0xb07, "mtpkey2"}, /* 5Ah, 90d To access KEY1_Protected registers (Default for engineering), */\ + { 0xc00, "enbl_volt_sense"}, /* Voltage sense enabling control bit , */\ + { 0xc10, "vsense_pwm_sel"}, /* Voltage sense PWM source selection control , */\ + { 0xc25, "vi_frac_delay"}, /* Fractional delay adjustment between current and voltage sense, */\ + { 0xc80, "sel_voltsense_out"}, /* TDM output data selection control , */\ + { 0xc90, "vsense_bypass_avg"}, /* Voltage Sense Average Block Bypass , */\ + { 0xd05, "cf_frac_delay"}, /* Fractional delay adjustment between current and voltage sense by firmware, */\ + { 0xe00, "bypass_dcdc_curr_prot"}, /* Control to switch off dcdc current reduction with bat protection, */\ + { 0xe80, "disable_clock_sh_prot"}, /* disable clock_sh protection , */\ + { 0xe96, "reserve_reg_1_15_9"}, /* , */\ + { 0x1011, "tdm_usecase"}, /* TDM_usecase , */\ + { 0x1030, "tdm_enable"}, /* TDM interface control , */\ + { 0x1040, "tdm_clk_inversion"}, /* TDM clock inversion , */\ + { 0x1053, "tdm_fs_ws_length"}, /* TDM FS length , */\ + { 0x1090, "tdm_fs_ws_polarity"}, /* TDM FS polarity , */\ + { 0x10a4, "tdm_sample_size"}, /* TDM Sample Size for all tdm sinks/sources , */\ + { 0x1103, "tdm_nb_of_slots"}, /* Number of slots , */\ + { 0x1144, "tdm_slot_length"}, /* Slot length , */\ + { 0x1194, "tdm_bits_remaining"}, /* Bits remaining , */\ + { 0x11e0, "tdm_data_delay"}, /* Data delay , */\ + { 0x11f0, "tdm_data_adjustment"}, /* Data adjustment , */\ + { 0x1201, "tdm_txdata_format"}, /* TXDATA format , */\ + { 0x1221, "tdm_txdata_format_unused_slot_sd0"}, /* TXDATA format unused slot sd0 , */\ + { 0x1241, "tdm_txdata_format_unused_slot_sd1"}, /* TXDATA format unused slot sd1 , */\ + { 0x1270, "tdm_sink0_enable"}, /* TDM sink0 enable , */\ + { 0x1280, "tdm_sink1_enable"}, /* TDM sink1 enable , */\ + { 0x1290, "tdm_sink2_enable"}, /* TDM sink2 enable , */\ + { 0x12a0, "tdm_source0_enable"}, /* TDM source0 enable , */\ + { 0x12b0, "tdm_source1_enable"}, /* TDM source1 enable , */\ + { 0x12c0, "tdm_source2_enable"}, /* TDM source2 enable , */\ + { 0x12d0, "tdm_sink0_io"}, /* tdm_sink0_io , */\ + { 0x12e0, "tdm_sink1_io"}, /* tdm_sink1_io , */\ + { 0x12f0, "tdm_sink2_io"}, /* tdm_sink2_io , */\ + { 0x1300, "tdm_source0_io"}, /* tdm_source0_io , */\ + { 0x1310, "tdm_source1_io"}, /* tdm_source1_io , */\ + { 0x1320, "tdm_source2_io"}, /* tdm_source2_io , */\ + { 0x1333, "tdm_sink0_slot"}, /* sink0_slot [GAIN IN] , */\ + { 0x1373, "tdm_sink1_slot"}, /* sink1_slot [CH1 IN] , */\ + { 0x13b3, "tdm_sink2_slot"}, /* sink2_slot [CH2 IN] , */\ + { 0x1403, "tdm_source0_slot"}, /* source0_slot [GAIN OUT] , */\ + { 0x1443, "tdm_source1_slot"}, /* source1_slot [Voltage Sense] , */\ + { 0x1483, "tdm_source2_slot"}, /* source2_slot [Current Sense] , */\ + { 0x14c3, "tdm_nbck"}, /* NBCK , */\ + { 0x1500, "flag_tdm_lut_error"}, /* TDM LUT error flag , */\ + { 0x1512, "flag_tdm_status"}, /* TDM interface status bits , */\ + { 0x1540, "flag_tdm_error"}, /* TDM interface error indicator , */\ + { 0x2000, "flag_por_int_out"}, /* flag_por_int_out , */\ + { 0x2010, "flag_pll_lock_int_out"}, /* flag_pll_lock_int_out , */\ + { 0x2020, "flag_otpok_int_out"}, /* flag_otpok_int_out , */\ + { 0x2030, "flag_ovpok_int_out"}, /* flag_ovpok_int_out , */\ + { 0x2040, "flag_uvpok_int_out"}, /* flag_uvpok_int_out , */\ + { 0x2050, "flag_ocp_alarm_int_out"}, /* flag_ocp_alarm_int_out , */\ + { 0x2060, "flag_clocks_stable_int_out"}, /* flag_clocks_stable_int_out , */\ + { 0x2070, "flag_clip_int_out"}, /* flag_clip_int_out , */\ + { 0x2080, "mtp_busy_int_out"}, /* mtp_busy_int_out , */\ + { 0x2090, "flag_lost_clk_int_out"}, /* flag_lost_clk_int_out , */\ + { 0x20a0, "flag_cf_speakererror_int_out"}, /* flag_cf_speakererror_int_out , */\ + { 0x20b0, "flag_cold_started_int_out"}, /* flag_cold_started_int_out , */\ + { 0x20c0, "flag_engage_int_out"}, /* flag_engage_int_out , */\ + { 0x20d0, "flag_watchdog_reset_int_out"}, /* flag_watchdog_reset_int_out , */\ + { 0x20e0, "flag_enbl_amp_int_out"}, /* flag_enbl_amp_int_out , */\ + { 0x20f0, "flag_enbl_ref_int_out"}, /* flag_enbl_ref_int_out , */\ + { 0x2100, "flag_voutcomp_int_out"}, /* flag_voutcomp_int_out , */\ + { 0x2110, "flag_voutcomp93_int_out"}, /* flag_voutcomp93_int_out , */\ + { 0x2120, "flag_voutcomp86_int_out"}, /* flag_voutcomp86_int_out , */\ + { 0x2130, "flag_hiz_int_out"}, /* flag_hiz_int_out , */\ + { 0x2140, "flag_ocpokbst_int_out"}, /* flag_ocpokbst_int_out , */\ + { 0x2150, "flag_peakcur_int_out"}, /* flag_peakcur_int_out , */\ + { 0x2160, "flag_ocpokap_int_out"}, /* flag_ocpokap_int_out , */\ + { 0x2170, "flag_ocpokan_int_out"}, /* flag_ocpokan_int_out , */\ + { 0x2180, "flag_ocpokbp_int_out"}, /* flag_ocpokbp_int_out , */\ + { 0x2190, "flag_ocpokbn_int_out"}, /* flag_ocpokbn_int_out , */\ + { 0x21a0, "flag_adc10_ready_int_out"}, /* flag_adc10_ready_int_out , */\ + { 0x21b0, "flag_clipa_high_int_out"}, /* flag_clipa_high_int_out , */\ + { 0x21c0, "flag_clipa_low_int_out"}, /* flag_clipa_low_int_out , */\ + { 0x21d0, "flag_clipb_high_int_out"}, /* flag_clipb_high_int_out , */\ + { 0x21e0, "flag_clipb_low_int_out"}, /* flag_clipb_low_int_out , */\ + { 0x21f0, "flag_tdm_error_int_out"}, /* flag_tdm_error_int_out , */\ + { 0x2201, "interrupt_out3"}, /* Interrupt status register output - Corresponding flag, */\ + { 0x2300, "flag_por_int_in"}, /* flag_por_int_in , */\ + { 0x2310, "flag_pll_lock_int_in"}, /* flag_pll_lock_int_in , */\ + { 0x2320, "flag_otpok_int_in"}, /* flag_otpok_int_in , */\ + { 0x2330, "flag_ovpok_int_in"}, /* flag_ovpok_int_in , */\ + { 0x2340, "flag_uvpok_int_in"}, /* flag_uvpok_int_in , */\ + { 0x2350, "flag_ocp_alarm_int_in"}, /* flag_ocp_alarm_int_in , */\ + { 0x2360, "flag_clocks_stable_int_in"}, /* flag_clocks_stable_int_in , */\ + { 0x2370, "flag_clip_int_in"}, /* flag_clip_int_in , */\ + { 0x2380, "mtp_busy_int_in"}, /* mtp_busy_int_in , */\ + { 0x2390, "flag_lost_clk_int_in"}, /* flag_lost_clk_int_in , */\ + { 0x23a0, "flag_cf_speakererror_int_in"}, /* flag_cf_speakererror_int_in , */\ + { 0x23b0, "flag_cold_started_int_in"}, /* flag_cold_started_int_in , */\ + { 0x23c0, "flag_engage_int_in"}, /* flag_engage_int_in , */\ + { 0x23d0, "flag_watchdog_reset_int_in"}, /* flag_watchdog_reset_int_in , */\ + { 0x23e0, "flag_enbl_amp_int_in"}, /* flag_enbl_amp_int_in , */\ + { 0x23f0, "flag_enbl_ref_int_in"}, /* flag_enbl_ref_int_in , */\ + { 0x2400, "flag_voutcomp_int_in"}, /* flag_voutcomp_int_in , */\ + { 0x2410, "flag_voutcomp93_int_in"}, /* flag_voutcomp93_int_in , */\ + { 0x2420, "flag_voutcomp86_int_in"}, /* flag_voutcomp86_int_in , */\ + { 0x2430, "flag_hiz_int_in"}, /* flag_hiz_int_in , */\ + { 0x2440, "flag_ocpokbst_int_in"}, /* flag_ocpokbst_int_in , */\ + { 0x2450, "flag_peakcur_int_in"}, /* flag_peakcur_int_in , */\ + { 0x2460, "flag_ocpokap_int_in"}, /* flag_ocpokap_int_in , */\ + { 0x2470, "flag_ocpokan_int_in"}, /* flag_ocpokan_int_in , */\ + { 0x2480, "flag_ocpokbp_int_in"}, /* flag_ocpokbp_int_in , */\ + { 0x2490, "flag_ocpokbn_int_in"}, /* flag_ocpokbn_int_in , */\ + { 0x24a0, "flag_adc10_ready_int_in"}, /* flag_adc10_ready_int_in , */\ + { 0x24b0, "flag_clipa_high_int_in"}, /* flag_clipa_high_int_in , */\ + { 0x24c0, "flag_clipa_low_int_in"}, /* flag_clipa_low_int_in , */\ + { 0x24d0, "flag_clipb_high_int_in"}, /* flag_clipb_high_int_in , */\ + { 0x24e0, "flag_clipb_low_int_in"}, /* flag_clipb_low_int_in , */\ + { 0x24f0, "flag_tdm_error_int_in"}, /* flag_tdm_error_int_in , */\ + { 0x2501, "interrupt_in3"}, /* Interrupt register input , */\ + { 0x2600, "flag_por_int_enable"}, /* flag_por_int_enable , */\ + { 0x2610, "flag_pll_lock_int_enable"}, /* flag_pll_lock_int_enable , */\ + { 0x2620, "flag_otpok_int_enable"}, /* flag_otpok_int_enable , */\ + { 0x2630, "flag_ovpok_int_enable"}, /* flag_ovpok_int_enable , */\ + { 0x2640, "flag_uvpok_int_enable"}, /* flag_uvpok_int_enable , */\ + { 0x2650, "flag_ocp_alarm_int_enable"}, /* flag_ocp_alarm_int_enable , */\ + { 0x2660, "flag_clocks_stable_int_enable"}, /* flag_clocks_stable_int_enable , */\ + { 0x2670, "flag_clip_int_enable"}, /* flag_clip_int_enable , */\ + { 0x2680, "mtp_busy_int_enable"}, /* mtp_busy_int_enable , */\ + { 0x2690, "flag_lost_clk_int_enable"}, /* flag_lost_clk_int_enable , */\ + { 0x26a0, "flag_cf_speakererror_int_enable"}, /* flag_cf_speakererror_int_enable , */\ + { 0x26b0, "flag_cold_started_int_enable"}, /* flag_cold_started_int_enable , */\ + { 0x26c0, "flag_engage_int_enable"}, /* flag_engage_int_enable , */\ + { 0x26d0, "flag_watchdog_reset_int_enable"}, /* flag_watchdog_reset_int_enable , */\ + { 0x26e0, "flag_enbl_amp_int_enable"}, /* flag_enbl_amp_int_enable , */\ + { 0x26f0, "flag_enbl_ref_int_enable"}, /* flag_enbl_ref_int_enable , */\ + { 0x2700, "flag_voutcomp_int_enable"}, /* flag_voutcomp_int_enable , */\ + { 0x2710, "flag_voutcomp93_int_enable"}, /* flag_voutcomp93_int_enable , */\ + { 0x2720, "flag_voutcomp86_int_enable"}, /* flag_voutcomp86_int_enable , */\ + { 0x2730, "flag_hiz_int_enable"}, /* flag_hiz_int_enable , */\ + { 0x2740, "flag_ocpokbst_int_enable"}, /* flag_ocpokbst_int_enable , */\ + { 0x2750, "flag_peakcur_int_enable"}, /* flag_peakcur_int_enable , */\ + { 0x2760, "flag_ocpokap_int_enable"}, /* flag_ocpokap_int_enable , */\ + { 0x2770, "flag_ocpokan_int_enable"}, /* flag_ocpokan_int_enable , */\ + { 0x2780, "flag_ocpokbp_int_enable"}, /* flag_ocpokbp_int_enable , */\ + { 0x2790, "flag_ocpokbn_int_enable"}, /* flag_ocpokbn_int_enable , */\ + { 0x27a0, "flag_adc10_ready_int_enable"}, /* flag_adc10_ready_int_enable , */\ + { 0x27b0, "flag_clipa_high_int_enable"}, /* flag_clipa_high_int_enable , */\ + { 0x27c0, "flag_clipa_low_int_enable"}, /* flag_clipa_low_int_enable , */\ + { 0x27d0, "flag_clipb_high_int_enable"}, /* flag_clipb_high_int_enable , */\ + { 0x27e0, "flag_clipb_low_int_enable"}, /* flag_clipb_low_int_enable , */\ + { 0x27f0, "flag_tdm_error_int_enable"}, /* flag_tdm_error_int_enable , */\ + { 0x2801, "interrupt_enable3"}, /* Interrupt enable register , */\ + { 0x2900, "flag_por_int_pol"}, /* flag_por_int_pol , */\ + { 0x2910, "flag_pll_lock_int_pol"}, /* flag_pll_lock_int_pol , */\ + { 0x2920, "flag_otpok_int_pol"}, /* flag_otpok_int_pol , */\ + { 0x2930, "flag_ovpok_int_pol"}, /* flag_ovpok_int_pol , */\ + { 0x2940, "flag_uvpok_int_pol"}, /* flag_uvpok_int_pol , */\ + { 0x2950, "flag_ocp_alarm_int_pol"}, /* flag_ocp_alarm_int_pol , */\ + { 0x2960, "flag_clocks_stable_int_pol"}, /* flag_clocks_stable_int_pol , */\ + { 0x2970, "flag_clip_int_pol"}, /* flag_clip_int_pol , */\ + { 0x2980, "mtp_busy_int_pol"}, /* mtp_busy_int_pol , */\ + { 0x2990, "flag_lost_clk_int_pol"}, /* flag_lost_clk_int_pol , */\ + { 0x29a0, "flag_cf_speakererror_int_pol"}, /* flag_cf_speakererror_int_pol , */\ + { 0x29b0, "flag_cold_started_int_pol"}, /* flag_cold_started_int_pol , */\ + { 0x29c0, "flag_engage_int_pol"}, /* flag_engage_int_pol , */\ + { 0x29d0, "flag_watchdog_reset_int_pol"}, /* flag_watchdog_reset_int_pol , */\ + { 0x29e0, "flag_enbl_amp_int_pol"}, /* flag_enbl_amp_int_pol , */\ + { 0x29f0, "flag_enbl_ref_int_pol"}, /* flag_enbl_ref_int_pol , */\ + { 0x2a00, "flag_voutcomp_int_pol"}, /* flag_voutcomp_int_pol , */\ + { 0x2a10, "flag_voutcomp93_int_pol"}, /* flag_voutcomp93_int_pol , */\ + { 0x2a20, "flag_voutcomp86_int_pol"}, /* flag_voutcomp86_int_pol , */\ + { 0x2a30, "flag_hiz_int_pol"}, /* flag_hiz_int_pol , */\ + { 0x2a40, "flag_ocpokbst_int_pol"}, /* flag_ocpokbst_int_pol , */\ + { 0x2a50, "flag_peakcur_int_pol"}, /* flag_peakcur_int_pol , */\ + { 0x2a60, "flag_ocpokap_int_pol"}, /* flag_ocpokap_int_pol , */\ + { 0x2a70, "flag_ocpokan_int_pol"}, /* flag_ocpokan_int_pol , */\ + { 0x2a80, "flag_ocpokbp_int_pol"}, /* flag_ocpokbp_int_pol , */\ + { 0x2a90, "flag_ocpokbn_int_pol"}, /* flag_ocpokbn_int_pol , */\ + { 0x2aa0, "flag_adc10_ready_int_pol"}, /* flag_adc10_ready_int_pol , */\ + { 0x2ab0, "flag_clipa_high_int_pol"}, /* flag_clipa_high_int_pol , */\ + { 0x2ac0, "flag_clipa_low_int_pol"}, /* flag_clipa_low_int_pol , */\ + { 0x2ad0, "flag_clipb_high_int_pol"}, /* flag_clipb_high_int_pol , */\ + { 0x2ae0, "flag_clipb_low_int_pol"}, /* flag_clipb_low_int_pol , */\ + { 0x2af0, "flag_tdm_error_int_pol"}, /* flag_tdm_error_int_pol , */\ + { 0x2b01, "status_polarity3"}, /* Interrupt status flags polarity register , */\ + { 0x3000, "flag_voutcomp"}, /* flag_voutcomp, indication Vset is larger than Vbat, */\ + { 0x3010, "flag_voutcomp93"}, /* flag_voutcomp93, indication Vset is larger than 1.07* Vbat, */\ + { 0x3020, "flag_voutcomp86"}, /* flag_voutcomp86, indication Vset is larger than 1.14* Vbat, */\ + { 0x3030, "flag_hiz"}, /* flag_hiz, indication Vbst is larger than Vbat , */\ + { 0x3040, "flag_ocpokbst"}, /* flag_ocpokbst, indication no over current in boost converter pmos switch, */\ + { 0x3050, "flag_peakcur"}, /* flag_peakcur, indication current is max in dcdc converter, */\ + { 0x3060, "flag_ocpokap"}, /* flag_ocpokap, indication no over current in amplifier "a" pmos output stage, */\ + { 0x3070, "flag_ocpokan"}, /* flag_ocpokan, indication no over current in amplifier "a" nmos output stage, */\ + { 0x3080, "flag_ocpokbp"}, /* flag_ocpokbp, indication no over current in amplifier "b" pmos output stage, */\ + { 0x3090, "flag_ocpokbn"}, /* flag_ocpokbn, indication no over current in amplifier"b" nmos output stage, */\ + { 0x30a0, "flag_adc10_ready"}, /* flag_adc10_ready, indication adc10 is ready , */\ + { 0x30b0, "flag_clipa_high"}, /* flag_clipa_high, indication pmos amplifier "a" is clipping, */\ + { 0x30c0, "flag_clipa_low"}, /* flag_clipa_low, indication nmos amplifier "a" is clipping, */\ + { 0x30d0, "flag_clipb_high"}, /* flag_clipb_high, indication pmos amplifier "b" is clipping, */\ + { 0x30e0, "flag_clipb_low"}, /* flag_clipb_low, indication nmos amplifier "b" is clipping, */\ + { 0x310f, "mtp_man_data_out"}, /* single word read from MTP (manual copy) , */\ + { 0x3200, "key01_locked"}, /* key01_locked, indication key 1 is locked , */\ + { 0x3210, "key02_locked"}, /* key02_locked, indication key 2 is locked , */\ + { 0x3225, "mtp_ecc_tcout"}, /* mtp_ecc_tcout , */\ + { 0x3280, "mtpctrl_valid_test_rd"}, /* mtp test readout for read , */\ + { 0x3290, "mtpctrl_valid_test_wr"}, /* mtp test readout for write , */\ + { 0x32a0, "flag_in_alarm_state"}, /* Alarm state , */\ + { 0x32b0, "mtp_ecc_err2"}, /* two or more bit errors detected in MTP, can not reconstruct value, */\ + { 0x32c0, "mtp_ecc_err1"}, /* one bit error detected in MTP, reconstructed value, */\ + { 0x32d0, "mtp_mtp_hvf"}, /* high voltage ready flag for MTP , */\ + { 0x32f0, "mtp_zero_check_fail"}, /* zero check failed (tbd) for MTP , */\ + { 0x3309, "data_adc10_tempbat"}, /* data_adc10_tempbat[9;0], adc 10 data output for testing, */\ + { 0x400f, "hid_code"}, /* 5A6Bh, 23147d to access registers (Default for engineering), */\ + { 0x4100, "bypass_hp"}, /* Bypass_High Pass Filter , */\ + { 0x4110, "hard_mute"}, /* Hard Mute , */\ + { 0x4120, "soft_mute"}, /* Soft Mute , */\ + { 0x4134, "pwm_delay"}, /* PWM DelayBits to set the delay , */\ + { 0x4180, "pwm_shape"}, /* PWM Shape , */\ + { 0x4190, "pwm_bitlength"}, /* PWM Bitlength in noise shaper , */\ + { 0x4203, "drive"}, /* Drive bits to select amount of power stage amplifier, */\ + { 0x4240, "reclock_pwm"}, /* , */\ + { 0x4250, "reclock_voltsense"}, /* , */\ + { 0x4281, "dpsalevel"}, /* DPSA Threshold level , */\ + { 0x42a1, "dpsa_release"}, /* DPSA Release time , */\ + { 0x42c0, "coincidence"}, /* Prevent simultaneously switching of output stage , */\ + { 0x42d0, "kickback"}, /* Prevent double pulses of output stage , */\ + { 0x4306, "drivebst"}, /* Drive bits to select the powertransistor sections boost converter, */\ + { 0x43a0, "ocptestbst"}, /* Boost OCP. For old ocp (ctrl_reversebst is 0);For new ocp (ctrl_reversebst is 1);, */\ + { 0x43d0, "test_abistfft_enbl"}, /* FFT coolflux , */\ + { 0x43f0, "test_bcontrol"}, /* test _bcontrol , */\ + { 0x4400, "reversebst"}, /* OverCurrent Protection selection of power stage boost converter, */\ + { 0x4410, "sensetest"}, /* Test option for the sense NMOS in booster for current mode control., */\ + { 0x4420, "enbl_engagebst"}, /* Enable power stage dcdc controller , */\ + { 0x4470, "enbl_slopecur"}, /* Enable bit of max-current dac , */\ + { 0x4480, "enbl_voutcomp"}, /* Enable vout comparators , */\ + { 0x4490, "enbl_voutcomp93"}, /* Enable vout-93 comparators , */\ + { 0x44a0, "enbl_voutcomp86"}, /* Enable vout-86 comparators , */\ + { 0x44b0, "enbl_hizcom"}, /* Enable hiz comparator , */\ + { 0x44c0, "enbl_peakcur"}, /* Enable peak current , */\ + { 0x44d0, "bypass_ovpglitch"}, /* Bypass OVP Glitch Filter , */\ + { 0x44e0, "enbl_windac"}, /* Enable window dac , */\ + { 0x44f0, "enbl_powerbst"}, /* Enable line of the powerstage , */\ + { 0x4507, "ocp_thr"}, /* ocp_thr threshold level for OCP , */\ + { 0x4580, "bypass_glitchfilter"}, /* Bypass glitch filter , */\ + { 0x4590, "bypass_ovp"}, /* Bypass OVP , */\ + { 0x45a0, "bypass_uvp"}, /* Bypass UVP , */\ + { 0x45b0, "bypass_otp"}, /* Bypass OTP , */\ + { 0x45c0, "bypass_ocp"}, /* Bypass OCP , */\ + { 0x45d0, "bypass_ocpcounter"}, /* BypassOCPCounter , */\ + { 0x45e0, "bypass_lost_clk"}, /* Bypasslost_clk detector , */\ + { 0x45f0, "vpalarm"}, /* vpalarm (uvp ovp handling) , */\ + { 0x4600, "bypass_gc"}, /* bypass_gc, bypasses the CS gain correction , */\ + { 0x4610, "cs_gain_control"}, /* gain control by means of MTP or i2c; 0 is MTP , */\ + { 0x4627, "cs_gain"}, /* + / - 128 steps in steps of 1/4 percent 2's compliment, */\ + { 0x46a0, "bypass_lp"}, /* bypass Low-Pass filter in temperature sensor , */\ + { 0x46b0, "bypass_pwmcounter"}, /* bypass_pwmcounter , */\ + { 0x46c0, "cs_negfixed"}, /* does not switch to neg , */\ + { 0x46d2, "cs_neghyst"}, /* switches to neg depending on level , */\ + { 0x4700, "switch_fb"}, /* switch_fb , */\ + { 0x4713, "se_hyst"}, /* se_hyst , */\ + { 0x4754, "se_level"}, /* se_level , */\ + { 0x47a5, "ktemp"}, /* temperature compensation trimming , */\ + { 0x4800, "cs_negin"}, /* negin , */\ + { 0x4810, "cs_sein"}, /* cs_sein , */\ + { 0x4820, "cs_coincidence"}, /* Coincidence current sense , */\ + { 0x4830, "iddqtestbst"}, /* for iddq testing in powerstage of boost convertor , */\ + { 0x4840, "coincidencebst"}, /* Switch protection on to prevent simultaneously switching power stages bst and amp, */\ + { 0x4876, "delay_se_neg"}, /* delay of se and neg , */\ + { 0x48e1, "cs_ttrack"}, /* sample & hold track time , */\ + { 0x4900, "bypass_clip"}, /* Bypass clip control , */\ + { 0x4920, "cf_cgate_off"}, /* to disable clock gating in the coolflux , */\ + { 0x4940, "clipfast"}, /* clock switch for battery protection clipper, it switches back to old frequency, */\ + { 0x4950, "cs_8ohm"}, /* 8 ohm mode for current sense (gain mode) , */\ + { 0x4974, "delay_clock_sh"}, /* delay_sh, tunes S7H delay , */\ + { 0x49c0, "inv_clksh"}, /* Invert the sample/hold clock for current sense ADC, */\ + { 0x49d0, "inv_neg"}, /* Invert neg signal , */\ + { 0x49e0, "inv_se"}, /* Invert se signal , */\ + { 0x49f0, "setse"}, /* switches between Single Ende and differential mode; 1 is single ended, */\ + { 0x4a12, "adc10_sel"}, /* select the input to convert the 10b ADC , */\ + { 0x4a60, "adc10_reset"}, /* Global asynchronous reset (active HIGH) 10 bit ADC, */\ + { 0x4a81, "adc10_test"}, /* Test mode selection signal 10 bit ADC , */\ + { 0x4aa0, "bypass_lp_vbat"}, /* lp filter in batt sensor , */\ + { 0x4ae0, "dc_offset"}, /* switch offset control on/off, is decimator offset control, */\ + { 0x4af0, "tsense_hibias"}, /* bit to set the biasing in temp sensor to high , */\ + { 0x4b00, "adc13_iset"}, /* Micadc Setting of current consumption. Debug use only, */\ + { 0x4b14, "adc13_gain"}, /* Micadc gain setting (2-compl) , */\ + { 0x4b61, "adc13_slowdel"}, /* Micadc Delay setting for internal clock. Debug use only, */\ + { 0x4b83, "adc13_offset"}, /* Micadc ADC offset setting , */\ + { 0x4bc0, "adc13_bsoinv"}, /* Micadc bit stream output invert mode for test , */\ + { 0x4bd0, "adc13_resonator_enable"}, /* Micadc Give extra SNR with less stability. Debug use only, */\ + { 0x4be0, "testmicadc"}, /* Mux at input of MICADC for test purpose , */\ + { 0x4c0f, "abist_offset"}, /* offset control for ABIST testing , */\ + { 0x4d05, "windac"}, /* for testing direct control windac , */\ + { 0x4dc3, "pwm_dcc_cnt"}, /* control pwm duty cycle when enbl_pwm_dcc is 1 , */\ + { 0x4e04, "slopecur"}, /* for testing direct control slopecur , */\ + { 0x4e50, "ctrl_dem"}, /* dyn element matching control, rest of codes are optional, */\ + { 0x4ed0, "enbl_pwm_dcc"}, /* to enable direct control of pwm duty cycle , */\ + { 0x5007, "gain"}, /* Gain setting of the gain multiplier , */\ + { 0x5081, "sourceb"}, /* Set OUTB to , */\ + { 0x50a1, "sourcea"}, /* Set OUTA to , */\ + { 0x50c1, "sourcebst"}, /* Sets the source of the pwmbst output to boost converter input for testing, */\ + { 0x50e0, "tdm_enable_loopback"}, /* TDM loopback test , */\ + { 0x5104, "pulselengthbst"}, /* pulse length setting test input for boost converter, */\ + { 0x5150, "bypasslatchbst"}, /* bypass_latch in boost converter , */\ + { 0x5160, "invertbst"}, /* invert pwmbst test signal , */\ + { 0x5174, "pulselength"}, /* pulse length setting test input for amplifier , */\ + { 0x51c0, "bypasslatch"}, /* bypass_latch in PWM source selection module , */\ + { 0x51d0, "invertb"}, /* invert pwmb test signal , */\ + { 0x51e0, "inverta"}, /* invert pwma test signal , */\ + { 0x51f0, "bypass_ctrlloop"}, /* bypass_ctrlloop bypasses the control loop of the amplifier, */\ + { 0x5210, "test_rdsona"}, /* tbd for rdson testing , */\ + { 0x5220, "test_rdsonb"}, /* tbd for rdson testing , */\ + { 0x5230, "test_rdsonbst"}, /* tbd for rdson testing , */\ + { 0x5240, "test_cvia"}, /* tbd for rdson testing , */\ + { 0x5250, "test_cvib"}, /* tbd for rdson testing , */\ + { 0x5260, "test_cvibst"}, /* tbd for rdson testing , */\ + { 0x5306, "digimuxa_sel"}, /* DigimuxA input selection control (see Digimux list for details), */\ + { 0x5376, "digimuxb_sel"}, /* DigimuxB input selection control (see Digimux list for details), */\ + { 0x5400, "hs_mode"}, /* hs_mode, high speed mode I2C bus , */\ + { 0x5412, "test_parametric_io"}, /* test_parametric_io for testing pads , */\ + { 0x5440, "enbl_ringo"}, /* enbl_ringo, for test purpose to check with ringo , */\ + { 0x5456, "digimuxc_sel"}, /* DigimuxC input selection control (see Digimux list for details), */\ + { 0x54c0, "dio_ehs"}, /* Slew control for DIO in output mode , */\ + { 0x54d0, "gainio_ehs"}, /* Slew control for GAINIO in output mode , */\ + { 0x550d, "enbl_amp"}, /* enbl_amp for testing to enable all analoge blocks in amplifier, */\ + { 0x5600, "use_direct_ctrls"}, /* use_direct_ctrls, to overrule several functions direct for testing, */\ + { 0x5610, "rst_datapath"}, /* rst_datapath, datapath reset , */\ + { 0x5620, "rst_cgu"}, /* rst_cgu, cgu reset , */\ + { 0x5637, "enbl_ref"}, /* for testing to enable all analoge blocks in references, */\ + { 0x56b0, "enbl_engage"}, /* Enable output stage amplifier , */\ + { 0x56c0, "use_direct_clk_ctrl"}, /* use_direct_clk_ctrl, to overrule several functions direct for testing, */\ + { 0x56d0, "use_direct_pll_ctrl"}, /* use_direct_pll_ctrl, to overrule several functions direct for testing, */\ + { 0x56e0, "use_direct_ctrls_2"}, /* use_direct_sourseamp_ctrls, to overrule several functions direct for testing, */\ + { 0x5707, "anamux"}, /* Anamux control , */\ + { 0x57c0, "ocptest"}, /* ctrl_ocptest, deactivates the over current protection in the power stages of the amplifier. The ocp flag signals stay active., */\ + { 0x57e0, "otptest"}, /* otptest, test mode otp amplifier , */\ + { 0x57f0, "reverse"}, /* 1: Normal mode, slope is controlled , */\ + { 0x5813, "pll_selr"}, /* pll_selr , */\ + { 0x5854, "pll_selp"}, /* pll_selp , */\ + { 0x58a5, "pll_seli"}, /* pll_seli , */\ + { 0x5950, "pll_mdec_msb"}, /* most significant bits of pll_mdec[16] , */\ + { 0x5960, "pll_ndec_msb"}, /* most significant bits of pll_ndec[9] , */\ + { 0x5970, "pll_frm"}, /* pll_frm , */\ + { 0x5980, "pll_directi"}, /* pll_directi , */\ + { 0x5990, "pll_directo"}, /* pll_directo , */\ + { 0x59a0, "enbl_pll"}, /* enbl_pll , */\ + { 0x59f0, "pll_bypass"}, /* pll_bypass , */\ + { 0x5a0f, "tsig_freq"}, /* tsig_freq, internal sinus test generator, frequency control, */\ + { 0x5b02, "tsig_freq_msb"}, /* select internal sinus test generator, frequency control msb bits, */\ + { 0x5b30, "inject_tsig"}, /* inject_tsig, control bit to switch to internal sinus test generator, */\ + { 0x5b44, "adc10_prog_sample"}, /* control ADC10 , */\ + { 0x5c0f, "pll_mdec"}, /* bits 15..0 of pll_mdec[16;0] , */\ + { 0x5d06, "pll_pdec"}, /* pll_pdec , */\ + { 0x5d78, "pll_ndec"}, /* bits 8..0 of pll_ndec[9;0] , */\ + { 0x6007, "mtpkey1"}, /* 5Ah, 90d To access KEY1_Protected registers (Default for engineering), */\ + { 0x6185, "mtp_ecc_tcin"}, /* Mtp_ecc_tcin , */\ + { 0x6203, "mtp_man_address_in"}, /* address from I2C regs for writing one word single mtp, */\ + { 0x6260, "mtp_ecc_eeb"}, /* enable code bit generation (active low!) , */\ + { 0x6270, "mtp_ecc_ecb"}, /* enable correction signal (active low!) , */\ + { 0x6280, "man_copy_mtp_to_iic"}, /* start copying single word from mtp to i2cregs_mtp , */\ + { 0x6290, "man_copy_iic_to_mtp"}, /* start copying single word from i2cregs_mtp to mtp [Key 1 protected], */\ + { 0x62a0, "auto_copy_mtp_to_iic"}, /* start copying all the data from mtp to i2cregs_mtp, */\ + { 0x62b0, "auto_copy_iic_to_mtp"}, /* start copying all the data from i2cregs_mtp to mtp [Key 2 protected], */\ + { 0x62d2, "mtp_speed_mode"}, /* Speed mode , */\ + { 0x6340, "mtp_direct_enable"}, /* mtp_direct_enable (key1 protected) , */\ + { 0x6350, "mtp_direct_wr"}, /* mtp_direct_wr (key1 protected) , */\ + { 0x6360, "mtp_direct_rd"}, /* mtp_direct_rd (key1 protected) , */\ + { 0x6370, "mtp_direct_rst"}, /* mtp_direct_rst (key1 protected) , */\ + { 0x6380, "mtp_direct_ers"}, /* mtp_direct_ers (key1 protected) , */\ + { 0x6390, "mtp_direct_prg"}, /* mtp_direct_prg (key1 protected) , */\ + { 0x63a0, "mtp_direct_epp"}, /* mtp_direct_epp (key1 protected) , */\ + { 0x63b4, "mtp_direct_test"}, /* mtp_direct_test (key1 protected) , */\ + { 0x640f, "mtp_man_data_in"}, /* single word to be written to MTP (manual copy) , */\ + { 0x7000, "cf_rst_dsp"}, /* Reset CoolFlux DSP , */\ + { 0x7011, "cf_dmem"}, /* Target memory for access , */\ + { 0x7030, "cf_aif"}, /* Autoincrement-flag for memory-address , */\ + { 0x7040, "cf_int"}, /* Interrupt CoolFlux DSP , */\ + { 0x7087, "cf_req"}, /* request for access (8 channels) , */\ + { 0x710f, "cf_madd"}, /* memory-address to be accessed , */\ + { 0x720f, "cf_mema"}, /* activate memory access (24- or 32-bits data is written/read to/from memory, */\ + { 0x7307, "cf_err"}, /* Coolflux error flags , */\ + { 0x7387, "cf_ack"}, /* acknowledge of requests (8 channels) , */\ + { 0x8000, "calibration_onetime"}, /* Calibration schedule (key2 protected) , */\ + { 0x8010, "calibr_ron_done"}, /* (key2 protected) , */\ + { 0x8105, "calibr_vout_offset"}, /* calibr_vout_offset (DCDCoffset) 2's compliment (key1 protected), */\ + { 0x8163, "calibr_delta_gain"}, /* delta gain for vamp (alpha) 2's compliment (key1 protected), */\ + { 0x81a5, "calibr_offs_amp"}, /* offset for vamp (Ampoffset) 2's compliment (key1 protected), */\ + { 0x8207, "calibr_gain_cs"}, /* gain current sense (Imeasalpha) 2's compliment (key1 protected), */\ + { 0x8284, "calibr_temp_offset"}, /* temperature offset 2's compliment (key1 protected), */\ + { 0x82d2, "calibr_temp_gain"}, /* temperature gain 2's compliment (key1 protected) , */\ + { 0x830f, "calibr_ron"}, /* Ron resistance of coil (key1 protected) , */\ + { 0x8505, "type_bits_HW"}, /* Key1_Protected_MTP5 , */\ + { 0x8601, "type_bits_1_0_SW"}, /* MTP-control SW , */\ + { 0x8681, "type_bits_8_9_SW"}, /* MTP-control SW , */\ + { 0x870f, "type_bits2_SW"}, /* MTP-control SW2 , */\ + { 0x8806, "htol_iic_addr"}, /* 7-bit I2C address to be used during HTOL testing , */\ + { 0x8870, "htol_iic_addr_en"}, /* HTOL_I2C_Address_Enable , */\ + { 0x8881, "ctrl_ovp_response"}, /* OVP response control , */\ + { 0x88a0, "disable_ovp_alarm_state"}, /* OVP alarm state control , */\ + { 0x88b0, "enbl_stretch_ovp"}, /* OVP alram strech control , */\ + { 0x88c0, "cf_debug_mode"}, /* Coolflux debug mode , */\ + { 0x8a0f, "production_data1"}, /* (key1 protected) , */\ + { 0x8b0f, "production_data2"}, /* (key1 protected) , */\ + { 0x8c0f, "production_data3"}, /* (key1 protected) , */\ + { 0x8d0f, "production_data4"}, /* (key1 protected) , */\ + { 0x8e0f, "production_data5"}, /* (key1 protected) , */\ + { 0x8f0f, "production_data6"}, /* (key1 protected) , */\ + { 0xffff,"Unknown bitfield enum" } /* not found */\ +}; + +enum tfa1_irq { + tfa1_irq_vdds = 0, + tfa1_irq_plls = 1, + tfa1_irq_ds = 2, + tfa1_irq_vds = 3, + tfa1_irq_uvds = 4, + tfa1_irq_cds = 5, + tfa1_irq_clks = 6, + tfa1_irq_clips = 7, + tfa1_irq_mtpb = 8, + tfa1_irq_clk = 9, + tfa1_irq_spks = 10, + tfa1_irq_acs = 11, + tfa1_irq_sws = 12, + tfa1_irq_wds = 13, + tfa1_irq_amps = 14, + tfa1_irq_arefs = 15, + tfa1_irq_ack = 32, + tfa1_irq_max = 33, + tfa1_irq_all = -1 /* all irqs */}; + +#define TFA1_IRQ_NAMETABLE static tfaIrqName_t Tfa1IrqNames[]= {\ + { 0, "VDDS"},\ + { 1, "PLLS"},\ + { 2, "DS"},\ + { 3, "VDS"},\ + { 4, "UVDS"},\ + { 5, "CDS"},\ + { 6, "CLKS"},\ + { 7, "CLIPS"},\ + { 8, "MTPB"},\ + { 9, "CLK"},\ + { 10, "SPKS"},\ + { 11, "ACS"},\ + { 12, "SWS"},\ + { 13, "WDS"},\ + { 14, "AMPS"},\ + { 15, "AREFS"},\ + { 16, "16"},\ + { 17, "17"},\ + { 18, "18"},\ + { 19, "19"},\ + { 20, "20"},\ + { 21, "21"},\ + { 22, "22"},\ + { 23, "23"},\ + { 24, "24"},\ + { 25, "25"},\ + { 26, "26"},\ + { 27, "27"},\ + { 28, "28"},\ + { 29, "29"},\ + { 30, "30"},\ + { 31, "31"},\ + { 32, "ACK"},\ + { 33, "33"},\ +}; diff --git a/techpack/audio/asoc/codecs/tfa9874/tfa2_tfafieldnames_N1C.h b/techpack/audio/asoc/codecs/tfa9874/tfa2_tfafieldnames_N1C.h new file mode 100644 index 000000000000..ebbb86390dcf --- /dev/null +++ b/techpack/audio/asoc/codecs/tfa9874/tfa2_tfafieldnames_N1C.h @@ -0,0 +1,1522 @@ +/** Filename: Tfa98xx_TfaFieldnames.h + * This file was generated automatically on 09/01/15 at 09:40:28. + * Source file: TFA9888_N1C_I2C_regmap_V1.xlsx + */ +#define TFA9888_I2CVERSION 18 +typedef enum nxpTfa2BfEnumList { + TFA2_BF_PWDN = 0x0000, /*!< Powerdown selection */ + TFA2_BF_I2CR = 0x0010, /*!< I2C Reset - Auto clear */ + TFA2_BF_CFE = 0x0020, /*!< Enable CoolFlux */ + TFA2_BF_AMPE = 0x0030, /*!< Activate Amplifier */ + TFA2_BF_DCA = 0x0040, /*!< Activate DC-to-DC converter */ + TFA2_BF_SBSL = 0x0050, /*!< Coolflux configured */ + TFA2_BF_AMPC = 0x0060, /*!< CoolFlux controls amplifier */ + TFA2_BF_INTP = 0x0071, /*!< Interrupt config */ + TFA2_BF_FSSSEL= 0x0091, /*!< Audio sample reference */ + TFA2_BF_BYPOCP= 0x00b0, /*!< Bypass OCP */ + TFA2_BF_TSTOCP= 0x00c0, /*!< OCP testing control */ + TFA2_BF_AMPINSEL= 0x0101, /*!< Amplifier input selection */ + TFA2_BF_MANSCONF= 0x0120, /*!< I2C configured */ + TFA2_BF_MANCOLD= 0x0130, /*!< Execute cold start */ + TFA2_BF_MANAOOSC= 0x0140, /*!< Internal osc off at PWDN */ + TFA2_BF_MANROBOD= 0x0150, /*!< Reaction on BOD */ + TFA2_BF_BODE = 0x0160, /*!< BOD Enable */ + TFA2_BF_BODHYS= 0x0170, /*!< BOD Hysteresis */ + TFA2_BF_BODFILT= 0x0181, /*!< BOD filter */ + TFA2_BF_BODTHLVL= 0x01a1, /*!< BOD threshold */ + TFA2_BF_MUTETO= 0x01d0, /*!< Time out SB mute sequence */ + TFA2_BF_RCVNS = 0x01e0, /*!< Noise shaper selection */ + TFA2_BF_MANWDE= 0x01f0, /*!< Watchdog manager reaction */ + TFA2_BF_AUDFS = 0x0203, /*!< Sample rate (fs) */ + TFA2_BF_INPLEV= 0x0240, /*!< TDM output attenuation */ + TFA2_BF_FRACTDEL= 0x0255, /*!< V/I Fractional delay */ + TFA2_BF_BYPHVBF= 0x02b0, /*!< Bypass HVBAT filter */ + TFA2_BF_LDOBYP= 0x02c0, /*!< Receiver LDO bypass */ + TFA2_BF_REV = 0x030f, /*!< Revision info */ + TFA2_BF_REFCKEXT= 0x0401, /*!< PLL external ref clock */ + TFA2_BF_REFCKSEL= 0x0420, /*!< PLL internal ref clock */ + TFA2_BF_SSLEFTE= 0x0500, /*!< Enable left channel */ + TFA2_BF_SSRIGHTE= 0x0510, /*!< Enable right channel */ + TFA2_BF_VSLEFTE= 0x0520, /*!< Voltage sense left */ + TFA2_BF_VSRIGHTE= 0x0530, /*!< Voltage sense right */ + TFA2_BF_CSLEFTE= 0x0540, /*!< Current sense left */ + TFA2_BF_CSRIGHTE= 0x0550, /*!< Current sense right */ + TFA2_BF_SSPDME= 0x0560, /*!< Sub-system PDM */ + TFA2_BF_STGAIN= 0x0d18, /*!< Side tone gain */ + TFA2_BF_PDMSMUTE= 0x0da0, /*!< Side tone soft mute */ + TFA2_BF_SWVSTEP= 0x0e06, /*!< Register for the host SW to record the current active vstep */ + TFA2_BF_VDDS = 0x1000, /*!< POR */ + TFA2_BF_PLLS = 0x1010, /*!< PLL lock */ + TFA2_BF_OTDS = 0x1020, /*!< OTP alarm */ + TFA2_BF_OVDS = 0x1030, /*!< OVP alarm */ + TFA2_BF_UVDS = 0x1040, /*!< UVP alarm */ + TFA2_BF_CLKS = 0x1050, /*!< Clocks stable */ + TFA2_BF_MTPB = 0x1060, /*!< MTP busy */ + TFA2_BF_NOCLK = 0x1070, /*!< Lost clock */ + TFA2_BF_SPKS = 0x1080, /*!< Speaker error */ + TFA2_BF_ACS = 0x1090, /*!< Cold Start */ + TFA2_BF_SWS = 0x10a0, /*!< Amplifier engage */ + TFA2_BF_WDS = 0x10b0, /*!< Watchdog */ + TFA2_BF_AMPS = 0x10c0, /*!< Amplifier enable */ + TFA2_BF_AREFS = 0x10d0, /*!< References enable */ + TFA2_BF_ADCCR = 0x10e0, /*!< Control ADC */ + TFA2_BF_BODNOK= 0x10f0, /*!< BOD */ + TFA2_BF_DCIL = 0x1100, /*!< DCDC current limiting */ + TFA2_BF_DCDCA = 0x1110, /*!< DCDC active */ + TFA2_BF_DCOCPOK= 0x1120, /*!< DCDC OCP nmos */ + TFA2_BF_DCHVBAT= 0x1140, /*!< DCDC level 1x */ + TFA2_BF_DCH114= 0x1150, /*!< DCDC level 1.14x */ + TFA2_BF_DCH107= 0x1160, /*!< DCDC level 1.07x */ + TFA2_BF_STMUTEB= 0x1170, /*!< side tone (un)mute busy */ + TFA2_BF_STMUTE= 0x1180, /*!< side tone mute state */ + TFA2_BF_TDMLUTER= 0x1190, /*!< TDM LUT error */ + TFA2_BF_TDMSTAT= 0x11a2, /*!< TDM status bits */ + TFA2_BF_TDMERR= 0x11d0, /*!< TDM error */ + TFA2_BF_HAPTIC= 0x11e0, /*!< Status haptic driver */ + TFA2_BF_OCPOAPL= 0x1200, /*!< OCPOK pmos A left */ + TFA2_BF_OCPOANL= 0x1210, /*!< OCPOK nmos A left */ + TFA2_BF_OCPOBPL= 0x1220, /*!< OCPOK pmos B left */ + TFA2_BF_OCPOBNL= 0x1230, /*!< OCPOK nmos B left */ + TFA2_BF_CLIPAHL= 0x1240, /*!< Clipping A left to Vddp */ + TFA2_BF_CLIPALL= 0x1250, /*!< Clipping A left to gnd */ + TFA2_BF_CLIPBHL= 0x1260, /*!< Clipping B left to Vddp */ + TFA2_BF_CLIPBLL= 0x1270, /*!< Clipping B left to gnd */ + TFA2_BF_OCPOAPRC= 0x1280, /*!< OCPOK pmos A RCV */ + TFA2_BF_OCPOANRC= 0x1290, /*!< OCPOK nmos A RCV */ + TFA2_BF_OCPOBPRC= 0x12a0, /*!< OCPOK pmos B RCV */ + TFA2_BF_OCPOBNRC= 0x12b0, /*!< OCPOK nmos B RCV */ + TFA2_BF_RCVLDOR= 0x12c0, /*!< RCV LDO regulates */ + TFA2_BF_RCVLDOBR= 0x12d0, /*!< Receiver LDO ready */ + TFA2_BF_OCDSL = 0x12e0, /*!< OCP left amplifier */ + TFA2_BF_CLIPSL= 0x12f0, /*!< Amplifier left clipping */ + TFA2_BF_OCPOAPR= 0x1300, /*!< OCPOK pmos A right */ + TFA2_BF_OCPOANR= 0x1310, /*!< OCPOK nmos A right */ + TFA2_BF_OCPOBPR= 0x1320, /*!< OCPOK pmos B right */ + TFA2_BF_OCPOBNR= 0x1330, /*!< OCPOK nmos B right */ + TFA2_BF_CLIPAHR= 0x1340, /*!< Clipping A right to Vddp */ + TFA2_BF_CLIPALR= 0x1350, /*!< Clipping A right to gnd */ + TFA2_BF_CLIPBHR= 0x1360, /*!< Clipping B left to Vddp */ + TFA2_BF_CLIPBLR= 0x1370, /*!< Clipping B right to gnd */ + TFA2_BF_OCDSR = 0x1380, /*!< OCP right amplifier */ + TFA2_BF_CLIPSR= 0x1390, /*!< Amplifier right clipping */ + TFA2_BF_OCPOKMC= 0x13a0, /*!< OCPOK MICVDD */ + TFA2_BF_MANALARM= 0x13b0, /*!< Alarm state */ + TFA2_BF_MANWAIT1= 0x13c0, /*!< Wait HW I2C settings */ + TFA2_BF_MANWAIT2= 0x13d0, /*!< Wait CF config */ + TFA2_BF_MANMUTE= 0x13e0, /*!< Audio mute sequence */ + TFA2_BF_MANOPER= 0x13f0, /*!< Operating state */ + TFA2_BF_SPKSL = 0x1400, /*!< Left speaker status */ + TFA2_BF_SPKSR = 0x1410, /*!< Right speaker status */ + TFA2_BF_CLKOOR= 0x1420, /*!< External clock status */ + TFA2_BF_MANSTATE= 0x1433, /*!< Device manager status */ + TFA2_BF_BATS = 0x1509, /*!< Battery voltage (V) */ + TFA2_BF_TEMPS = 0x1608, /*!< IC Temperature (C) */ + TFA2_BF_TDMUC = 0x2003, /*!< Usecase setting */ + TFA2_BF_TDME = 0x2040, /*!< Enable interface */ + TFA2_BF_TDMMODE= 0x2050, /*!< Slave/master */ + TFA2_BF_TDMCLINV= 0x2060, /*!< Reception data to BCK clock */ + TFA2_BF_TDMFSLN= 0x2073, /*!< FS length (master mode only) */ + TFA2_BF_TDMFSPOL= 0x20b0, /*!< FS polarity */ + TFA2_BF_TDMNBCK= 0x20c3, /*!< N-BCK's in FS */ + TFA2_BF_TDMSLOTS= 0x2103, /*!< N-slots in Frame */ + TFA2_BF_TDMSLLN= 0x2144, /*!< N-bits in slot */ + TFA2_BF_TDMBRMG= 0x2194, /*!< N-bits remaining */ + TFA2_BF_TDMDEL= 0x21e0, /*!< data delay to FS */ + TFA2_BF_TDMADJ= 0x21f0, /*!< data adjustment */ + TFA2_BF_TDMOOMP= 0x2201, /*!< Received audio compression */ + TFA2_BF_TDMSSIZE= 0x2224, /*!< Sample size per slot */ + TFA2_BF_TDMTXDFO= 0x2271, /*!< Format unused bits */ + TFA2_BF_TDMTXUS0= 0x2291, /*!< Format unused slots GAINIO */ + TFA2_BF_TDMTXUS1= 0x22b1, /*!< Format unused slots DIO1 */ + TFA2_BF_TDMTXUS2= 0x22d1, /*!< Format unused slots DIO2 */ + TFA2_BF_TDMLE = 0x2310, /*!< Control audio left */ + TFA2_BF_TDMRE = 0x2320, /*!< Control audio right */ + TFA2_BF_TDMVSRE= 0x2340, /*!< Control voltage sense right */ + TFA2_BF_TDMCSRE= 0x2350, /*!< Control current sense right */ + TFA2_BF_TDMVSLE= 0x2360, /*!< Voltage sense left control */ + TFA2_BF_TDMCSLE= 0x2370, /*!< Current sense left control */ + TFA2_BF_TDMCFRE= 0x2380, /*!< DSP out right control */ + TFA2_BF_TDMCFLE= 0x2390, /*!< DSP out left control */ + TFA2_BF_TDMCF3E= 0x23a0, /*!< AEC ref left control */ + TFA2_BF_TDMCF4E= 0x23b0, /*!< AEC ref right control */ + TFA2_BF_TDMPD1E= 0x23c0, /*!< PDM 1 control */ + TFA2_BF_TDMPD2E= 0x23d0, /*!< PDM 2 control */ + TFA2_BF_TDMLIO= 0x2421, /*!< IO audio left */ + TFA2_BF_TDMRIO= 0x2441, /*!< IO audio right */ + TFA2_BF_TDMVSRIO= 0x2481, /*!< IO voltage sense right */ + TFA2_BF_TDMCSRIO= 0x24a1, /*!< IO current sense right */ + TFA2_BF_TDMVSLIO= 0x24c1, /*!< IO voltage sense left */ + TFA2_BF_TDMCSLIO= 0x24e1, /*!< IO current sense left */ + TFA2_BF_TDMCFRIO= 0x2501, /*!< IO dspout right */ + TFA2_BF_TDMCFLIO= 0x2521, /*!< IO dspout left */ + TFA2_BF_TDMCF3IO= 0x2541, /*!< IO AEC ref left control */ + TFA2_BF_TDMCF4IO= 0x2561, /*!< IO AEC ref right control */ + TFA2_BF_TDMPD1IO= 0x2581, /*!< IO pdm1 */ + TFA2_BF_TDMPD2IO= 0x25a1, /*!< IO pdm2 */ + TFA2_BF_TDMLS = 0x2643, /*!< Position audio left */ + TFA2_BF_TDMRS = 0x2683, /*!< Position audio right */ + TFA2_BF_TDMVSRS= 0x2703, /*!< Position voltage sense right */ + TFA2_BF_TDMCSRS= 0x2743, /*!< Position current sense right */ + TFA2_BF_TDMVSLS= 0x2783, /*!< Position voltage sense left */ + TFA2_BF_TDMCSLS= 0x27c3, /*!< Position current sense left */ + TFA2_BF_TDMCFRS= 0x2803, /*!< Position dspout right */ + TFA2_BF_TDMCFLS= 0x2843, /*!< Position dspout left */ + TFA2_BF_TDMCF3S= 0x2883, /*!< Position AEC ref left control */ + TFA2_BF_TDMCF4S= 0x28c3, /*!< Position AEC ref right control */ + TFA2_BF_TDMPD1S= 0x2903, /*!< Position pdm1 */ + TFA2_BF_TDMPD2S= 0x2943, /*!< Position pdm2 */ + TFA2_BF_PDMSM = 0x3100, /*!< PDM control */ + TFA2_BF_PDMSTSEL= 0x3111, /*!< Side tone input */ + TFA2_BF_PDMLSEL= 0x3130, /*!< PDM data selection for left channel during PDM direct mode */ + TFA2_BF_PDMRSEL= 0x3140, /*!< PDM data selection for right channel during PDM direct mode */ + TFA2_BF_MICVDDE= 0x3150, /*!< Enable MICVDD */ + TFA2_BF_PDMCLRAT= 0x3201, /*!< PDM BCK/Fs ratio */ + TFA2_BF_PDMGAIN= 0x3223, /*!< PDM gain */ + TFA2_BF_PDMOSEL= 0x3263, /*!< PDM output selection - RE/FE data combination */ + TFA2_BF_SELCFHAPD= 0x32a0, /*!< Select the source for haptic data output (not for customer) */ + TFA2_BF_HAPTIME= 0x3307, /*!< Duration (ms) */ + TFA2_BF_HAPLEVEL= 0x3387, /*!< DC value (FFS) */ + TFA2_BF_GPIODIN= 0x3403, /*!< Receiving value */ + TFA2_BF_GPIOCTRL= 0x3500, /*!< GPIO master control over GPIO1/2 ports (not for customer) */ + TFA2_BF_GPIOCONF= 0x3513, /*!< Configuration */ + TFA2_BF_GPIODOUT= 0x3553, /*!< Transmitting value */ + TFA2_BF_ISTVDDS= 0x4000, /*!< Status POR */ + TFA2_BF_ISTPLLS= 0x4010, /*!< Status PLL lock */ + TFA2_BF_ISTOTDS= 0x4020, /*!< Status OTP alarm */ + TFA2_BF_ISTOVDS= 0x4030, /*!< Status OVP alarm */ + TFA2_BF_ISTUVDS= 0x4040, /*!< Status UVP alarm */ + TFA2_BF_ISTCLKS= 0x4050, /*!< Status clocks stable */ + TFA2_BF_ISTMTPB= 0x4060, /*!< Status MTP busy */ + TFA2_BF_ISTNOCLK= 0x4070, /*!< Status lost clock */ + TFA2_BF_ISTSPKS= 0x4080, /*!< Status speaker error */ + TFA2_BF_ISTACS= 0x4090, /*!< Status cold start */ + TFA2_BF_ISTSWS= 0x40a0, /*!< Status amplifier engage */ + TFA2_BF_ISTWDS= 0x40b0, /*!< Status watchdog */ + TFA2_BF_ISTAMPS= 0x40c0, /*!< Status amplifier enable */ + TFA2_BF_ISTAREFS= 0x40d0, /*!< Status Ref enable */ + TFA2_BF_ISTADCCR= 0x40e0, /*!< Status Control ADC */ + TFA2_BF_ISTBODNOK= 0x40f0, /*!< Status BOD */ + TFA2_BF_ISTBSTCU= 0x4100, /*!< Status DCDC current limiting */ + TFA2_BF_ISTBSTHI= 0x4110, /*!< Status DCDC active */ + TFA2_BF_ISTBSTOC= 0x4120, /*!< Status DCDC OCP */ + TFA2_BF_ISTBSTPKCUR= 0x4130, /*!< Status bst peakcur */ + TFA2_BF_ISTBSTVC= 0x4140, /*!< Status DCDC level 1x */ + TFA2_BF_ISTBST86= 0x4150, /*!< Status DCDC level 1.14x */ + TFA2_BF_ISTBST93= 0x4160, /*!< Status DCDC level 1.07x */ + TFA2_BF_ISTRCVLD= 0x4170, /*!< Status rcvldop ready */ + TFA2_BF_ISTOCPL= 0x4180, /*!< Status ocp alarm left */ + TFA2_BF_ISTOCPR= 0x4190, /*!< Status ocp alarm right */ + TFA2_BF_ISTMWSRC= 0x41a0, /*!< Status Waits HW I2C settings */ + TFA2_BF_ISTMWCFC= 0x41b0, /*!< Status waits CF config */ + TFA2_BF_ISTMWSMU= 0x41c0, /*!< Status Audio mute sequence */ + TFA2_BF_ISTCFMER= 0x41d0, /*!< Status cfma error */ + TFA2_BF_ISTCFMAC= 0x41e0, /*!< Status cfma ack */ + TFA2_BF_ISTCLKOOR= 0x41f0, /*!< Status flag_clk_out_of_range */ + TFA2_BF_ISTTDMER= 0x4200, /*!< Status tdm error */ + TFA2_BF_ISTCLPL= 0x4210, /*!< Status clip left */ + TFA2_BF_ISTCLPR= 0x4220, /*!< Status clip right */ + TFA2_BF_ISTOCPM= 0x4230, /*!< Status mic ocpok */ + TFA2_BF_ICLVDDS= 0x4400, /*!< Clear POR */ + TFA2_BF_ICLPLLS= 0x4410, /*!< Clear PLL lock */ + TFA2_BF_ICLOTDS= 0x4420, /*!< Clear OTP alarm */ + TFA2_BF_ICLOVDS= 0x4430, /*!< Clear OVP alarm */ + TFA2_BF_ICLUVDS= 0x4440, /*!< Clear UVP alarm */ + TFA2_BF_ICLCLKS= 0x4450, /*!< Clear clocks stable */ + TFA2_BF_ICLMTPB= 0x4460, /*!< Clear mtp busy */ + TFA2_BF_ICLNOCLK= 0x4470, /*!< Clear lost clk */ + TFA2_BF_ICLSPKS= 0x4480, /*!< Clear speaker error */ + TFA2_BF_ICLACS= 0x4490, /*!< Clear cold started */ + TFA2_BF_ICLSWS= 0x44a0, /*!< Clear amplifier engage */ + TFA2_BF_ICLWDS= 0x44b0, /*!< Clear watchdog */ + TFA2_BF_ICLAMPS= 0x44c0, /*!< Clear enbl amp */ + TFA2_BF_ICLAREFS= 0x44d0, /*!< Clear ref enable */ + TFA2_BF_ICLADCCR= 0x44e0, /*!< Clear control ADC */ + TFA2_BF_ICLBODNOK= 0x44f0, /*!< Clear BOD */ + TFA2_BF_ICLBSTCU= 0x4500, /*!< Clear DCDC current limiting */ + TFA2_BF_ICLBSTHI= 0x4510, /*!< Clear DCDC active */ + TFA2_BF_ICLBSTOC= 0x4520, /*!< Clear DCDC OCP */ + TFA2_BF_ICLBSTPC= 0x4530, /*!< Clear bst peakcur */ + TFA2_BF_ICLBSTVC= 0x4540, /*!< Clear DCDC level 1x */ + TFA2_BF_ICLBST86= 0x4550, /*!< Clear DCDC level 1.14x */ + TFA2_BF_ICLBST93= 0x4560, /*!< Clear DCDC level 1.07x */ + TFA2_BF_ICLRCVLD= 0x4570, /*!< Clear rcvldop ready */ + TFA2_BF_ICLOCPL= 0x4580, /*!< Clear ocp alarm left */ + TFA2_BF_ICLOCPR= 0x4590, /*!< Clear ocp alarm right */ + TFA2_BF_ICLMWSRC= 0x45a0, /*!< Clear wait HW I2C settings */ + TFA2_BF_ICLMWCFC= 0x45b0, /*!< Clear wait cf config */ + TFA2_BF_ICLMWSMU= 0x45c0, /*!< Clear audio mute sequence */ + TFA2_BF_ICLCFMER= 0x45d0, /*!< Clear cfma err */ + TFA2_BF_ICLCFMAC= 0x45e0, /*!< Clear cfma ack */ + TFA2_BF_ICLCLKOOR= 0x45f0, /*!< Clear flag_clk_out_of_range */ + TFA2_BF_ICLTDMER= 0x4600, /*!< Clear tdm error */ + TFA2_BF_ICLCLPL= 0x4610, /*!< Clear clip left */ + TFA2_BF_ICLCLPR= 0x4620, /*!< Clear clip right */ + TFA2_BF_ICLOCPM= 0x4630, /*!< Clear mic ocpok */ + TFA2_BF_IEVDDS= 0x4800, /*!< Enable por */ + TFA2_BF_IEPLLS= 0x4810, /*!< Enable pll lock */ + TFA2_BF_IEOTDS= 0x4820, /*!< Enable OTP alarm */ + TFA2_BF_IEOVDS= 0x4830, /*!< Enable OVP alarm */ + TFA2_BF_IEUVDS= 0x4840, /*!< Enable UVP alarm */ + TFA2_BF_IECLKS= 0x4850, /*!< Enable clocks stable */ + TFA2_BF_IEMTPB= 0x4860, /*!< Enable mtp busy */ + TFA2_BF_IENOCLK= 0x4870, /*!< Enable lost clk */ + TFA2_BF_IESPKS= 0x4880, /*!< Enable speaker error */ + TFA2_BF_IEACS = 0x4890, /*!< Enable cold started */ + TFA2_BF_IESWS = 0x48a0, /*!< Enable amplifier engage */ + TFA2_BF_IEWDS = 0x48b0, /*!< Enable watchdog */ + TFA2_BF_IEAMPS= 0x48c0, /*!< Enable enbl amp */ + TFA2_BF_IEAREFS= 0x48d0, /*!< Enable ref enable */ + TFA2_BF_IEADCCR= 0x48e0, /*!< Enable Control ADC */ + TFA2_BF_IEBODNOK= 0x48f0, /*!< Enable BOD */ + TFA2_BF_IEBSTCU= 0x4900, /*!< Enable DCDC current limiting */ + TFA2_BF_IEBSTHI= 0x4910, /*!< Enable DCDC active */ + TFA2_BF_IEBSTOC= 0x4920, /*!< Enable DCDC OCP */ + TFA2_BF_IEBSTPC= 0x4930, /*!< Enable bst peakcur */ + TFA2_BF_IEBSTVC= 0x4940, /*!< Enable DCDC level 1x */ + TFA2_BF_IEBST86= 0x4950, /*!< Enable DCDC level 1.14x */ + TFA2_BF_IEBST93= 0x4960, /*!< Enable DCDC level 1.07x */ + TFA2_BF_IERCVLD= 0x4970, /*!< Enable rcvldop ready */ + TFA2_BF_IEOCPL= 0x4980, /*!< Enable ocp alarm left */ + TFA2_BF_IEOCPR= 0x4990, /*!< Enable ocp alarm right */ + TFA2_BF_IEMWSRC= 0x49a0, /*!< Enable waits HW I2C settings */ + TFA2_BF_IEMWCFC= 0x49b0, /*!< Enable man wait cf config */ + TFA2_BF_IEMWSMU= 0x49c0, /*!< Enable man Audio mute sequence */ + TFA2_BF_IECFMER= 0x49d0, /*!< Enable cfma err */ + TFA2_BF_IECFMAC= 0x49e0, /*!< Enable cfma ack */ + TFA2_BF_IECLKOOR= 0x49f0, /*!< Enable flag_clk_out_of_range */ + TFA2_BF_IETDMER= 0x4a00, /*!< Enable tdm error */ + TFA2_BF_IECLPL= 0x4a10, /*!< Enable clip left */ + TFA2_BF_IECLPR= 0x4a20, /*!< Enable clip right */ + TFA2_BF_IEOCPM1= 0x4a30, /*!< Enable mic ocpok */ + TFA2_BF_IPOVDDS= 0x4c00, /*!< Polarity por */ + TFA2_BF_IPOPLLS= 0x4c10, /*!< Polarity pll lock */ + TFA2_BF_IPOOTDS= 0x4c20, /*!< Polarity OTP alarm */ + TFA2_BF_IPOOVDS= 0x4c30, /*!< Polarity OVP alarm */ + TFA2_BF_IPOUVDS= 0x4c40, /*!< Polarity UVP alarm */ + TFA2_BF_IPOCLKS= 0x4c50, /*!< Polarity clocks stable */ + TFA2_BF_IPOMTPB= 0x4c60, /*!< Polarity mtp busy */ + TFA2_BF_IPONOCLK= 0x4c70, /*!< Polarity lost clk */ + TFA2_BF_IPOSPKS= 0x4c80, /*!< Polarity speaker error */ + TFA2_BF_IPOACS= 0x4c90, /*!< Polarity cold started */ + TFA2_BF_IPOSWS= 0x4ca0, /*!< Polarity amplifier engage */ + TFA2_BF_IPOWDS= 0x4cb0, /*!< Polarity watchdog */ + TFA2_BF_IPOAMPS= 0x4cc0, /*!< Polarity enbl amp */ + TFA2_BF_IPOAREFS= 0x4cd0, /*!< Polarity ref enable */ + TFA2_BF_IPOADCCR= 0x4ce0, /*!< Polarity Control ADC */ + TFA2_BF_IPOBODNOK= 0x4cf0, /*!< Polarity BOD */ + TFA2_BF_IPOBSTCU= 0x4d00, /*!< Polarity DCDC current limiting */ + TFA2_BF_IPOBSTHI= 0x4d10, /*!< Polarity DCDC active */ + TFA2_BF_IPOBSTOC= 0x4d20, /*!< Polarity DCDC OCP */ + TFA2_BF_IPOBSTPC= 0x4d30, /*!< Polarity bst peakcur */ + TFA2_BF_IPOBSTVC= 0x4d40, /*!< Polarity DCDC level 1x */ + TFA2_BF_IPOBST86= 0x4d50, /*!< Polarity DCDC level 1.14x */ + TFA2_BF_IPOBST93= 0x4d60, /*!< Polarity DCDC level 1.07x */ + TFA2_BF_IPORCVLD= 0x4d70, /*!< Polarity rcvldop ready */ + TFA2_BF_IPOOCPL= 0x4d80, /*!< Polarity ocp alarm left */ + TFA2_BF_IPOOCPR= 0x4d90, /*!< Polarity ocp alarm right */ + TFA2_BF_IPOMWSRC= 0x4da0, /*!< Polarity waits HW I2C settings */ + TFA2_BF_IPOMWCFC= 0x4db0, /*!< Polarity man wait cf config */ + TFA2_BF_IPOMWSMU= 0x4dc0, /*!< Polarity man audio mute sequence */ + TFA2_BF_IPOCFMER= 0x4dd0, /*!< Polarity cfma err */ + TFA2_BF_IPOCFMAC= 0x4de0, /*!< Polarity cfma ack */ + TFA2_BF_IPCLKOOR= 0x4df0, /*!< Polarity flag_clk_out_of_range */ + TFA2_BF_IPOTDMER= 0x4e00, /*!< Polarity tdm error */ + TFA2_BF_IPOCLPL= 0x4e10, /*!< Polarity clip left */ + TFA2_BF_IPOCLPR= 0x4e20, /*!< Polarity clip right */ + TFA2_BF_IPOOCPM= 0x4e30, /*!< Polarity mic ocpok */ + TFA2_BF_BSSCR = 0x5001, /*!< Battery protection attack Time */ + TFA2_BF_BSST = 0x5023, /*!< Battery protection threshold voltage level */ + TFA2_BF_BSSRL = 0x5061, /*!< Battery protection maximum reduction */ + TFA2_BF_BSSRR = 0x5082, /*!< Battery protection release time */ + TFA2_BF_BSSHY = 0x50b1, /*!< Battery protection hysteresis */ + TFA2_BF_BSSR = 0x50e0, /*!< Battery voltage read out */ + TFA2_BF_BSSBY = 0x50f0, /*!< Bypass HW clipper */ + TFA2_BF_BSSS = 0x5100, /*!< Vbat prot steepness */ + TFA2_BF_INTSMUTE= 0x5110, /*!< Soft mute HW */ + TFA2_BF_CFSML = 0x5120, /*!< Soft mute FW left */ + TFA2_BF_CFSMR = 0x5130, /*!< Soft mute FW right */ + TFA2_BF_HPFBYPL= 0x5140, /*!< Bypass HPF left */ + TFA2_BF_HPFBYPR= 0x5150, /*!< Bypass HPF right */ + TFA2_BF_DPSAL = 0x5160, /*!< Enable DPSA left */ + TFA2_BF_DPSAR = 0x5170, /*!< Enable DPSA right */ + TFA2_BF_VOL = 0x5187, /*!< FW volume control for primary audio channel */ + TFA2_BF_HNDSFRCV= 0x5200, /*!< Selection receiver */ + TFA2_BF_CLIPCTRL= 0x5222, /*!< Clip control setting */ + TFA2_BF_AMPGAIN= 0x5257, /*!< Amplifier gain */ + TFA2_BF_SLOPEE= 0x52d0, /*!< Enables slope control */ + TFA2_BF_SLOPESET= 0x52e1, /*!< Set slope */ + TFA2_BF_VOLSEC= 0x5a07, /*!< FW volume control for secondary audio channel */ + TFA2_BF_SWPROFIL= 0x5a87, /*!< Software profile data */ + TFA2_BF_DCVO = 0x7002, /*!< Boost voltage */ + TFA2_BF_DCMCC = 0x7033, /*!< Max coil current */ + TFA2_BF_DCCV = 0x7071, /*!< Coil Value */ + TFA2_BF_DCIE = 0x7090, /*!< Adaptive boost mode */ + TFA2_BF_DCSR = 0x70a0, /*!< Soft ramp up/down */ + TFA2_BF_DCSYNCP= 0x70b2, /*!< DCDC synchronization off + 7 positions */ + TFA2_BF_DCDIS = 0x70e0, /*!< DCDC on/off */ + TFA2_BF_RST = 0x9000, /*!< Reset */ + TFA2_BF_DMEM = 0x9011, /*!< Target memory */ + TFA2_BF_AIF = 0x9030, /*!< Auto increment */ + TFA2_BF_CFINT = 0x9040, /*!< Interrupt - auto clear */ + TFA2_BF_CFCGATE= 0x9050, /*!< Coolflux clock gating disabling control */ + TFA2_BF_REQ = 0x9087, /*!< request for access (8 channels) */ + TFA2_BF_REQCMD= 0x9080, /*!< Firmware event request rpc command */ + TFA2_BF_REQRST= 0x9090, /*!< Firmware event request reset restart */ + TFA2_BF_REQMIPS= 0x90a0, /*!< Firmware event request short on mips */ + TFA2_BF_REQMUTED= 0x90b0, /*!< Firmware event request mute sequence ready */ + TFA2_BF_REQVOL= 0x90c0, /*!< Firmware event request volume ready */ + TFA2_BF_REQDMG= 0x90d0, /*!< Firmware event request speaker damage detected */ + TFA2_BF_REQCAL= 0x90e0, /*!< Firmware event request calibration completed */ + TFA2_BF_REQRSV= 0x90f0, /*!< Firmware event request reserved */ + TFA2_BF_MADD = 0x910f, /*!< Memory address */ + TFA2_BF_MEMA = 0x920f, /*!< Activate memory access */ + TFA2_BF_ERR = 0x9307, /*!< Error flags */ + TFA2_BF_ACK = 0x9387, /*!< Acknowledge of requests */ + TFA2_BF_ACKCMD= 0x9380, /*!< Firmware event acknowledge rpc command */ + TFA2_BF_ACKRST= 0x9390, /*!< Firmware event acknowledge reset restart */ + TFA2_BF_ACKMIPS= 0x93a0, /*!< Firmware event acknowledge short on mips */ + TFA2_BF_ACKMUTED= 0x93b0, /*!< Firmware event acknowledge mute sequence ready */ + TFA2_BF_ACKVOL= 0x93c0, /*!< Firmware event acknowledge volume ready */ + TFA2_BF_ACKDMG= 0x93d0, /*!< Firmware event acknowledge speaker damage detected */ + TFA2_BF_ACKCAL= 0x93e0, /*!< Firmware event acknowledge calibration completed */ + TFA2_BF_ACKRSV= 0x93f0, /*!< Firmware event acknowledge reserved */ + TFA2_BF_MTPK = 0xa107, /*!< MTP KEY2 register */ + TFA2_BF_KEY1LOCKED= 0xa200, /*!< Indicates KEY1 is locked */ + TFA2_BF_KEY2LOCKED= 0xa210, /*!< Indicates KEY2 is locked */ + TFA2_BF_CIMTP = 0xa360, /*!< Start copying data from I2C mtp registers to mtp */ + TFA2_BF_MTPRDMSB= 0xa50f, /*!< MSB word of MTP manual read data */ + TFA2_BF_MTPRDLSB= 0xa60f, /*!< LSB word of MTP manual read data */ + TFA2_BF_EXTTS = 0xb108, /*!< External temperature (C) */ + TFA2_BF_TROS = 0xb190, /*!< Select temp Speaker calibration */ + TFA2_BF_MTPOTC= 0xf000, /*!< Calibration schedule */ + TFA2_BF_MTPEX = 0xf010, /*!< Calibration Ron executed */ + TFA2_BF_DCMCCAPI= 0xf020, /*!< Calibration current limit DCDC */ + TFA2_BF_DCMCCSB= 0xf030, /*!< Sign bit for delta calibration current limit DCDC */ + TFA2_BF_USERDEF= 0xf042, /*!< Calibration delta current limit DCDC */ + TFA2_BF_R25CL = 0xf40f, /*!< Ron resistance of left channel speaker coil */ + TFA2_BF_R25CR = 0xf50f, /*!< Ron resistance of right channel speaker coil */ +} nxpTfa2BfEnumList_t; +#define TFA2_NAMETABLE static tfaBfName_t Tfa2DatasheetNames[]= {\ + { 0x0, "PWDN"}, /* Powerdown selection , */\ + { 0x10, "I2CR"}, /* I2C Reset - Auto clear , */\ + { 0x20, "CFE"}, /* Enable CoolFlux , */\ + { 0x30, "AMPE"}, /* Activate Amplifier , */\ + { 0x40, "DCA"}, /* Activate DC-to-DC converter , */\ + { 0x50, "SBSL"}, /* Coolflux configured , */\ + { 0x60, "AMPC"}, /* CoolFlux controls amplifier , */\ + { 0x71, "INTP"}, /* Interrupt config , */\ + { 0x91, "FSSSEL"}, /* Audio sample reference , */\ + { 0xb0, "BYPOCP"}, /* Bypass OCP , */\ + { 0xc0, "TSTOCP"}, /* OCP testing control , */\ + { 0x101, "AMPINSEL"}, /* Amplifier input selection , */\ + { 0x120, "MANSCONF"}, /* I2C configured , */\ + { 0x130, "MANCOLD"}, /* Execute cold start , */\ + { 0x140, "MANAOOSC"}, /* Internal osc off at PWDN , */\ + { 0x150, "MANROBOD"}, /* Reaction on BOD , */\ + { 0x160, "BODE"}, /* BOD Enable , */\ + { 0x170, "BODHYS"}, /* BOD Hysteresis , */\ + { 0x181, "BODFILT"}, /* BOD filter , */\ + { 0x1a1, "BODTHLVL"}, /* BOD threshold , */\ + { 0x1d0, "MUTETO"}, /* Time out SB mute sequence , */\ + { 0x1e0, "RCVNS"}, /* Noise shaper selection , */\ + { 0x1f0, "MANWDE"}, /* Watchdog manager reaction , */\ + { 0x203, "AUDFS"}, /* Sample rate (fs) , */\ + { 0x240, "INPLEV"}, /* TDM output attenuation , */\ + { 0x255, "FRACTDEL"}, /* V/I Fractional delay , */\ + { 0x2b0, "BYPHVBF"}, /* Bypass HVBAT filter , */\ + { 0x2c0, "LDOBYP"}, /* Receiver LDO bypass , */\ + { 0x30f, "REV"}, /* Revision info , */\ + { 0x401, "REFCKEXT"}, /* PLL external ref clock , */\ + { 0x420, "REFCKSEL"}, /* PLL internal ref clock , */\ + { 0x500, "SSLEFTE"}, /* Enable left channel , */\ + { 0x510, "SSRIGHTE"}, /* Enable right channel , */\ + { 0x520, "VSLEFTE"}, /* Voltage sense left , */\ + { 0x530, "VSRIGHTE"}, /* Voltage sense right , */\ + { 0x540, "CSLEFTE"}, /* Current sense left , */\ + { 0x550, "CSRIGHTE"}, /* Current sense right , */\ + { 0x560, "SSPDME"}, /* Sub-system PDM , */\ + { 0xd18, "STGAIN"}, /* Side tone gain , */\ + { 0xda0, "PDMSMUTE"}, /* Side tone soft mute , */\ + { 0xe06, "SWVSTEP"}, /* Register for the host SW to record the current active vstep, */\ + { 0x1000, "VDDS"}, /* POR , */\ + { 0x1010, "PLLS"}, /* PLL lock , */\ + { 0x1020, "OTDS"}, /* OTP alarm , */\ + { 0x1030, "OVDS"}, /* OVP alarm , */\ + { 0x1040, "UVDS"}, /* UVP alarm , */\ + { 0x1050, "CLKS"}, /* Clocks stable , */\ + { 0x1060, "MTPB"}, /* MTP busy , */\ + { 0x1070, "NOCLK"}, /* Lost clock , */\ + { 0x1080, "SPKS"}, /* Speaker error , */\ + { 0x1090, "ACS"}, /* Cold Start , */\ + { 0x10a0, "SWS"}, /* Amplifier engage , */\ + { 0x10b0, "WDS"}, /* Watchdog , */\ + { 0x10c0, "AMPS"}, /* Amplifier enable , */\ + { 0x10d0, "AREFS"}, /* References enable , */\ + { 0x10e0, "ADCCR"}, /* Control ADC , */\ + { 0x10f0, "BODNOK"}, /* BOD , */\ + { 0x1100, "DCIL"}, /* DCDC current limiting , */\ + { 0x1110, "DCDCA"}, /* DCDC active , */\ + { 0x1120, "DCOCPOK"}, /* DCDC OCP nmos , */\ + { 0x1140, "DCHVBAT"}, /* DCDC level 1x , */\ + { 0x1150, "DCH114"}, /* DCDC level 1.14x , */\ + { 0x1160, "DCH107"}, /* DCDC level 1.07x , */\ + { 0x1170, "STMUTEB"}, /* side tone (un)mute busy , */\ + { 0x1180, "STMUTE"}, /* side tone mute state , */\ + { 0x1190, "TDMLUTER"}, /* TDM LUT error , */\ + { 0x11a2, "TDMSTAT"}, /* TDM status bits , */\ + { 0x11d0, "TDMERR"}, /* TDM error , */\ + { 0x11e0, "HAPTIC"}, /* Status haptic driver , */\ + { 0x1200, "OCPOAPL"}, /* OCPOK pmos A left , */\ + { 0x1210, "OCPOANL"}, /* OCPOK nmos A left , */\ + { 0x1220, "OCPOBPL"}, /* OCPOK pmos B left , */\ + { 0x1230, "OCPOBNL"}, /* OCPOK nmos B left , */\ + { 0x1240, "CLIPAHL"}, /* Clipping A left to Vddp , */\ + { 0x1250, "CLIPALL"}, /* Clipping A left to gnd , */\ + { 0x1260, "CLIPBHL"}, /* Clipping B left to Vddp , */\ + { 0x1270, "CLIPBLL"}, /* Clipping B left to gnd , */\ + { 0x1280, "OCPOAPRC"}, /* OCPOK pmos A RCV , */\ + { 0x1290, "OCPOANRC"}, /* OCPOK nmos A RCV , */\ + { 0x12a0, "OCPOBPRC"}, /* OCPOK pmos B RCV , */\ + { 0x12b0, "OCPOBNRC"}, /* OCPOK nmos B RCV , */\ + { 0x12c0, "RCVLDOR"}, /* RCV LDO regulates , */\ + { 0x12d0, "RCVLDOBR"}, /* Receiver LDO ready , */\ + { 0x12e0, "OCDSL"}, /* OCP left amplifier , */\ + { 0x12f0, "CLIPSL"}, /* Amplifier left clipping , */\ + { 0x1300, "OCPOAPR"}, /* OCPOK pmos A right , */\ + { 0x1310, "OCPOANR"}, /* OCPOK nmos A right , */\ + { 0x1320, "OCPOBPR"}, /* OCPOK pmos B right , */\ + { 0x1330, "OCPOBNR"}, /* OCPOK nmos B right , */\ + { 0x1340, "CLIPAHR"}, /* Clipping A right to Vddp , */\ + { 0x1350, "CLIPALR"}, /* Clipping A right to gnd , */\ + { 0x1360, "CLIPBHR"}, /* Clipping B left to Vddp , */\ + { 0x1370, "CLIPBLR"}, /* Clipping B right to gnd , */\ + { 0x1380, "OCDSR"}, /* OCP right amplifier , */\ + { 0x1390, "CLIPSR"}, /* Amplifier right clipping , */\ + { 0x13a0, "OCPOKMC"}, /* OCPOK MICVDD , */\ + { 0x13b0, "MANALARM"}, /* Alarm state , */\ + { 0x13c0, "MANWAIT1"}, /* Wait HW I2C settings , */\ + { 0x13d0, "MANWAIT2"}, /* Wait CF config , */\ + { 0x13e0, "MANMUTE"}, /* Audio mute sequence , */\ + { 0x13f0, "MANOPER"}, /* Operating state , */\ + { 0x1400, "SPKSL"}, /* Left speaker status , */\ + { 0x1410, "SPKSR"}, /* Right speaker status , */\ + { 0x1420, "CLKOOR"}, /* External clock status , */\ + { 0x1433, "MANSTATE"}, /* Device manager status , */\ + { 0x1509, "BATS"}, /* Battery voltage (V) , */\ + { 0x1608, "TEMPS"}, /* IC Temperature (C) , */\ + { 0x2003, "TDMUC"}, /* Usecase setting , */\ + { 0x2040, "TDME"}, /* Enable interface , */\ + { 0x2050, "TDMMODE"}, /* Slave/master , */\ + { 0x2060, "TDMCLINV"}, /* Reception data to BCK clock , */\ + { 0x2073, "TDMFSLN"}, /* FS length (master mode only) , */\ + { 0x20b0, "TDMFSPOL"}, /* FS polarity , */\ + { 0x20c3, "TDMNBCK"}, /* N-BCK's in FS , */\ + { 0x2103, "TDMSLOTS"}, /* N-slots in Frame , */\ + { 0x2144, "TDMSLLN"}, /* N-bits in slot , */\ + { 0x2194, "TDMBRMG"}, /* N-bits remaining , */\ + { 0x21e0, "TDMDEL"}, /* data delay to FS , */\ + { 0x21f0, "TDMADJ"}, /* data adjustment , */\ + { 0x2201, "TDMOOMP"}, /* Received audio compression , */\ + { 0x2224, "TDMSSIZE"}, /* Sample size per slot , */\ + { 0x2271, "TDMTXDFO"}, /* Format unused bits , */\ + { 0x2291, "TDMTXUS0"}, /* Format unused slots GAINIO , */\ + { 0x22b1, "TDMTXUS1"}, /* Format unused slots DIO1 , */\ + { 0x22d1, "TDMTXUS2"}, /* Format unused slots DIO2 , */\ + { 0x2310, "TDMLE"}, /* Control audio left , */\ + { 0x2320, "TDMRE"}, /* Control audio right , */\ + { 0x2340, "TDMVSRE"}, /* Control voltage sense right , */\ + { 0x2350, "TDMCSRE"}, /* Control current sense right , */\ + { 0x2360, "TDMVSLE"}, /* Voltage sense left control , */\ + { 0x2370, "TDMCSLE"}, /* Current sense left control , */\ + { 0x2380, "TDMCFRE"}, /* DSP out right control , */\ + { 0x2390, "TDMCFLE"}, /* DSP out left control , */\ + { 0x23a0, "TDMCF3E"}, /* AEC ref left control , */\ + { 0x23b0, "TDMCF4E"}, /* AEC ref right control , */\ + { 0x23c0, "TDMPD1E"}, /* PDM 1 control , */\ + { 0x23d0, "TDMPD2E"}, /* PDM 2 control , */\ + { 0x2421, "TDMLIO"}, /* IO audio left , */\ + { 0x2441, "TDMRIO"}, /* IO audio right , */\ + { 0x2481, "TDMVSRIO"}, /* IO voltage sense right , */\ + { 0x24a1, "TDMCSRIO"}, /* IO current sense right , */\ + { 0x24c1, "TDMVSLIO"}, /* IO voltage sense left , */\ + { 0x24e1, "TDMCSLIO"}, /* IO current sense left , */\ + { 0x2501, "TDMCFRIO"}, /* IO dspout right , */\ + { 0x2521, "TDMCFLIO"}, /* IO dspout left , */\ + { 0x2541, "TDMCF3IO"}, /* IO AEC ref left control , */\ + { 0x2561, "TDMCF4IO"}, /* IO AEC ref right control , */\ + { 0x2581, "TDMPD1IO"}, /* IO pdm1 , */\ + { 0x25a1, "TDMPD2IO"}, /* IO pdm2 , */\ + { 0x2643, "TDMLS"}, /* Position audio left , */\ + { 0x2683, "TDMRS"}, /* Position audio right , */\ + { 0x2703, "TDMVSRS"}, /* Position voltage sense right , */\ + { 0x2743, "TDMCSRS"}, /* Position current sense right , */\ + { 0x2783, "TDMVSLS"}, /* Position voltage sense left , */\ + { 0x27c3, "TDMCSLS"}, /* Position current sense left , */\ + { 0x2803, "TDMCFRS"}, /* Position dspout right , */\ + { 0x2843, "TDMCFLS"}, /* Position dspout left , */\ + { 0x2883, "TDMCF3S"}, /* Position AEC ref left control , */\ + { 0x28c3, "TDMCF4S"}, /* Position AEC ref right control , */\ + { 0x2903, "TDMPD1S"}, /* Position pdm1 , */\ + { 0x2943, "TDMPD2S"}, /* Position pdm2 , */\ + { 0x3100, "PDMSM"}, /* PDM control , */\ + { 0x3111, "PDMSTSEL"}, /* Side tone input , */\ + { 0x3130, "PDMLSEL"}, /* PDM data selection for left channel during PDM direct mode, */\ + { 0x3140, "PDMRSEL"}, /* PDM data selection for right channel during PDM direct mode, */\ + { 0x3150, "MICVDDE"}, /* Enable MICVDD , */\ + { 0x3201, "PDMCLRAT"}, /* PDM BCK/Fs ratio , */\ + { 0x3223, "PDMGAIN"}, /* PDM gain , */\ + { 0x3263, "PDMOSEL"}, /* PDM output selection - RE/FE data combination , */\ + { 0x32a0, "SELCFHAPD"}, /* Select the source for haptic data output (not for customer), */\ + { 0x3307, "HAPTIME"}, /* Duration (ms) , */\ + { 0x3387, "HAPLEVEL"}, /* DC value (FFS) , */\ + { 0x3403, "GPIODIN"}, /* Receiving value , */\ + { 0x3500, "GPIOCTRL"}, /* GPIO master control over GPIO1/2 ports (not for customer), */\ + { 0x3513, "GPIOCONF"}, /* Configuration , */\ + { 0x3553, "GPIODOUT"}, /* Transmitting value , */\ + { 0x4000, "ISTVDDS"}, /* Status POR , */\ + { 0x4010, "ISTPLLS"}, /* Status PLL lock , */\ + { 0x4020, "ISTOTDS"}, /* Status OTP alarm , */\ + { 0x4030, "ISTOVDS"}, /* Status OVP alarm , */\ + { 0x4040, "ISTUVDS"}, /* Status UVP alarm , */\ + { 0x4050, "ISTCLKS"}, /* Status clocks stable , */\ + { 0x4060, "ISTMTPB"}, /* Status MTP busy , */\ + { 0x4070, "ISTNOCLK"}, /* Status lost clock , */\ + { 0x4080, "ISTSPKS"}, /* Status speaker error , */\ + { 0x4090, "ISTACS"}, /* Status cold start , */\ + { 0x40a0, "ISTSWS"}, /* Status amplifier engage , */\ + { 0x40b0, "ISTWDS"}, /* Status watchdog , */\ + { 0x40c0, "ISTAMPS"}, /* Status amplifier enable , */\ + { 0x40d0, "ISTAREFS"}, /* Status Ref enable , */\ + { 0x40e0, "ISTADCCR"}, /* Status Control ADC , */\ + { 0x40f0, "ISTBODNOK"}, /* Status BOD , */\ + { 0x4100, "ISTBSTCU"}, /* Status DCDC current limiting , */\ + { 0x4110, "ISTBSTHI"}, /* Status DCDC active , */\ + { 0x4120, "ISTBSTOC"}, /* Status DCDC OCP , */\ + { 0x4130, "ISTBSTPKCUR"}, /* Status bst peakcur , */\ + { 0x4140, "ISTBSTVC"}, /* Status DCDC level 1x , */\ + { 0x4150, "ISTBST86"}, /* Status DCDC level 1.14x , */\ + { 0x4160, "ISTBST93"}, /* Status DCDC level 1.07x , */\ + { 0x4170, "ISTRCVLD"}, /* Status rcvldop ready , */\ + { 0x4180, "ISTOCPL"}, /* Status ocp alarm left , */\ + { 0x4190, "ISTOCPR"}, /* Status ocp alarm right , */\ + { 0x41a0, "ISTMWSRC"}, /* Status Waits HW I2C settings , */\ + { 0x41b0, "ISTMWCFC"}, /* Status waits CF config , */\ + { 0x41c0, "ISTMWSMU"}, /* Status Audio mute sequence , */\ + { 0x41d0, "ISTCFMER"}, /* Status cfma error , */\ + { 0x41e0, "ISTCFMAC"}, /* Status cfma ack , */\ + { 0x41f0, "ISTCLKOOR"}, /* Status flag_clk_out_of_range , */\ + { 0x4200, "ISTTDMER"}, /* Status tdm error , */\ + { 0x4210, "ISTCLPL"}, /* Status clip left , */\ + { 0x4220, "ISTCLPR"}, /* Status clip right , */\ + { 0x4230, "ISTOCPM"}, /* Status mic ocpok , */\ + { 0x4400, "ICLVDDS"}, /* Clear POR , */\ + { 0x4410, "ICLPLLS"}, /* Clear PLL lock , */\ + { 0x4420, "ICLOTDS"}, /* Clear OTP alarm , */\ + { 0x4430, "ICLOVDS"}, /* Clear OVP alarm , */\ + { 0x4440, "ICLUVDS"}, /* Clear UVP alarm , */\ + { 0x4450, "ICLCLKS"}, /* Clear clocks stable , */\ + { 0x4460, "ICLMTPB"}, /* Clear mtp busy , */\ + { 0x4470, "ICLNOCLK"}, /* Clear lost clk , */\ + { 0x4480, "ICLSPKS"}, /* Clear speaker error , */\ + { 0x4490, "ICLACS"}, /* Clear cold started , */\ + { 0x44a0, "ICLSWS"}, /* Clear amplifier engage , */\ + { 0x44b0, "ICLWDS"}, /* Clear watchdog , */\ + { 0x44c0, "ICLAMPS"}, /* Clear enbl amp , */\ + { 0x44d0, "ICLAREFS"}, /* Clear ref enable , */\ + { 0x44e0, "ICLADCCR"}, /* Clear control ADC , */\ + { 0x44f0, "ICLBODNOK"}, /* Clear BOD , */\ + { 0x4500, "ICLBSTCU"}, /* Clear DCDC current limiting , */\ + { 0x4510, "ICLBSTHI"}, /* Clear DCDC active , */\ + { 0x4520, "ICLBSTOC"}, /* Clear DCDC OCP , */\ + { 0x4530, "ICLBSTPC"}, /* Clear bst peakcur , */\ + { 0x4540, "ICLBSTVC"}, /* Clear DCDC level 1x , */\ + { 0x4550, "ICLBST86"}, /* Clear DCDC level 1.14x , */\ + { 0x4560, "ICLBST93"}, /* Clear DCDC level 1.07x , */\ + { 0x4570, "ICLRCVLD"}, /* Clear rcvldop ready , */\ + { 0x4580, "ICLOCPL"}, /* Clear ocp alarm left , */\ + { 0x4590, "ICLOCPR"}, /* Clear ocp alarm right , */\ + { 0x45a0, "ICLMWSRC"}, /* Clear wait HW I2C settings , */\ + { 0x45b0, "ICLMWCFC"}, /* Clear wait cf config , */\ + { 0x45c0, "ICLMWSMU"}, /* Clear audio mute sequence , */\ + { 0x45d0, "ICLCFMER"}, /* Clear cfma err , */\ + { 0x45e0, "ICLCFMAC"}, /* Clear cfma ack , */\ + { 0x45f0, "ICLCLKOOR"}, /* Clear flag_clk_out_of_range , */\ + { 0x4600, "ICLTDMER"}, /* Clear tdm error , */\ + { 0x4610, "ICLCLPL"}, /* Clear clip left , */\ + { 0x4620, "ICLCLPR"}, /* Clear clip right , */\ + { 0x4630, "ICLOCPM"}, /* Clear mic ocpok , */\ + { 0x4800, "IEVDDS"}, /* Enable por , */\ + { 0x4810, "IEPLLS"}, /* Enable pll lock , */\ + { 0x4820, "IEOTDS"}, /* Enable OTP alarm , */\ + { 0x4830, "IEOVDS"}, /* Enable OVP alarm , */\ + { 0x4840, "IEUVDS"}, /* Enable UVP alarm , */\ + { 0x4850, "IECLKS"}, /* Enable clocks stable , */\ + { 0x4860, "IEMTPB"}, /* Enable mtp busy , */\ + { 0x4870, "IENOCLK"}, /* Enable lost clk , */\ + { 0x4880, "IESPKS"}, /* Enable speaker error , */\ + { 0x4890, "IEACS"}, /* Enable cold started , */\ + { 0x48a0, "IESWS"}, /* Enable amplifier engage , */\ + { 0x48b0, "IEWDS"}, /* Enable watchdog , */\ + { 0x48c0, "IEAMPS"}, /* Enable enbl amp , */\ + { 0x48d0, "IEAREFS"}, /* Enable ref enable , */\ + { 0x48e0, "IEADCCR"}, /* Enable Control ADC , */\ + { 0x48f0, "IEBODNOK"}, /* Enable BOD , */\ + { 0x4900, "IEBSTCU"}, /* Enable DCDC current limiting , */\ + { 0x4910, "IEBSTHI"}, /* Enable DCDC active , */\ + { 0x4920, "IEBSTOC"}, /* Enable DCDC OCP , */\ + { 0x4930, "IEBSTPC"}, /* Enable bst peakcur , */\ + { 0x4940, "IEBSTVC"}, /* Enable DCDC level 1x , */\ + { 0x4950, "IEBST86"}, /* Enable DCDC level 1.14x , */\ + { 0x4960, "IEBST93"}, /* Enable DCDC level 1.07x , */\ + { 0x4970, "IERCVLD"}, /* Enable rcvldop ready , */\ + { 0x4980, "IEOCPL"}, /* Enable ocp alarm left , */\ + { 0x4990, "IEOCPR"}, /* Enable ocp alarm right , */\ + { 0x49a0, "IEMWSRC"}, /* Enable waits HW I2C settings , */\ + { 0x49b0, "IEMWCFC"}, /* Enable man wait cf config , */\ + { 0x49c0, "IEMWSMU"}, /* Enable man Audio mute sequence , */\ + { 0x49d0, "IECFMER"}, /* Enable cfma err , */\ + { 0x49e0, "IECFMAC"}, /* Enable cfma ack , */\ + { 0x49f0, "IECLKOOR"}, /* Enable flag_clk_out_of_range , */\ + { 0x4a00, "IETDMER"}, /* Enable tdm error , */\ + { 0x4a10, "IECLPL"}, /* Enable clip left , */\ + { 0x4a20, "IECLPR"}, /* Enable clip right , */\ + { 0x4a30, "IEOCPM1"}, /* Enable mic ocpok , */\ + { 0x4c00, "IPOVDDS"}, /* Polarity por , */\ + { 0x4c10, "IPOPLLS"}, /* Polarity pll lock , */\ + { 0x4c20, "IPOOTDS"}, /* Polarity OTP alarm , */\ + { 0x4c30, "IPOOVDS"}, /* Polarity OVP alarm , */\ + { 0x4c40, "IPOUVDS"}, /* Polarity UVP alarm , */\ + { 0x4c50, "IPOCLKS"}, /* Polarity clocks stable , */\ + { 0x4c60, "IPOMTPB"}, /* Polarity mtp busy , */\ + { 0x4c70, "IPONOCLK"}, /* Polarity lost clk , */\ + { 0x4c80, "IPOSPKS"}, /* Polarity speaker error , */\ + { 0x4c90, "IPOACS"}, /* Polarity cold started , */\ + { 0x4ca0, "IPOSWS"}, /* Polarity amplifier engage , */\ + { 0x4cb0, "IPOWDS"}, /* Polarity watchdog , */\ + { 0x4cc0, "IPOAMPS"}, /* Polarity enbl amp , */\ + { 0x4cd0, "IPOAREFS"}, /* Polarity ref enable , */\ + { 0x4ce0, "IPOADCCR"}, /* Polarity Control ADC , */\ + { 0x4cf0, "IPOBODNOK"}, /* Polarity BOD , */\ + { 0x4d00, "IPOBSTCU"}, /* Polarity DCDC current limiting , */\ + { 0x4d10, "IPOBSTHI"}, /* Polarity DCDC active , */\ + { 0x4d20, "IPOBSTOC"}, /* Polarity DCDC OCP , */\ + { 0x4d30, "IPOBSTPC"}, /* Polarity bst peakcur , */\ + { 0x4d40, "IPOBSTVC"}, /* Polarity DCDC level 1x , */\ + { 0x4d50, "IPOBST86"}, /* Polarity DCDC level 1.14x , */\ + { 0x4d60, "IPOBST93"}, /* Polarity DCDC level 1.07x , */\ + { 0x4d70, "IPORCVLD"}, /* Polarity rcvldop ready , */\ + { 0x4d80, "IPOOCPL"}, /* Polarity ocp alarm left , */\ + { 0x4d90, "IPOOCPR"}, /* Polarity ocp alarm right , */\ + { 0x4da0, "IPOMWSRC"}, /* Polarity waits HW I2C settings , */\ + { 0x4db0, "IPOMWCFC"}, /* Polarity man wait cf config , */\ + { 0x4dc0, "IPOMWSMU"}, /* Polarity man audio mute sequence , */\ + { 0x4dd0, "IPOCFMER"}, /* Polarity cfma err , */\ + { 0x4de0, "IPOCFMAC"}, /* Polarity cfma ack , */\ + { 0x4df0, "IPCLKOOR"}, /* Polarity flag_clk_out_of_range , */\ + { 0x4e00, "IPOTDMER"}, /* Polarity tdm error , */\ + { 0x4e10, "IPOCLPL"}, /* Polarity clip left , */\ + { 0x4e20, "IPOCLPR"}, /* Polarity clip right , */\ + { 0x4e30, "IPOOCPM"}, /* Polarity mic ocpok , */\ + { 0x5001, "BSSCR"}, /* Battery protection attack Time , */\ + { 0x5023, "BSST"}, /* Battery protection threshold voltage level , */\ + { 0x5061, "BSSRL"}, /* Battery protection maximum reduction , */\ + { 0x5082, "BSSRR"}, /* Battery protection release time , */\ + { 0x50b1, "BSSHY"}, /* Battery protection hysteresis , */\ + { 0x50e0, "BSSR"}, /* Battery voltage read out , */\ + { 0x50f0, "BSSBY"}, /* Bypass HW clipper , */\ + { 0x5100, "BSSS"}, /* Vbat prot steepness , */\ + { 0x5110, "INTSMUTE"}, /* Soft mute HW , */\ + { 0x5120, "CFSML"}, /* Soft mute FW left , */\ + { 0x5130, "CFSMR"}, /* Soft mute FW right , */\ + { 0x5140, "HPFBYPL"}, /* Bypass HPF left , */\ + { 0x5150, "HPFBYPR"}, /* Bypass HPF right , */\ + { 0x5160, "DPSAL"}, /* Enable DPSA left , */\ + { 0x5170, "DPSAR"}, /* Enable DPSA right , */\ + { 0x5187, "VOL"}, /* FW volume control for primary audio channel , */\ + { 0x5200, "HNDSFRCV"}, /* Selection receiver , */\ + { 0x5222, "CLIPCTRL"}, /* Clip control setting , */\ + { 0x5257, "AMPGAIN"}, /* Amplifier gain , */\ + { 0x52d0, "SLOPEE"}, /* Enables slope control , */\ + { 0x52e1, "SLOPESET"}, /* Set slope , */\ + { 0x5a07, "VOLSEC"}, /* FW volume control for secondary audio channel , */\ + { 0x5a87, "SWPROFIL"}, /* Software profile data , */\ + { 0x7002, "DCVO"}, /* Boost voltage , */\ + { 0x7033, "DCMCC"}, /* Max coil current , */\ + { 0x7071, "DCCV"}, /* Coil Value , */\ + { 0x7090, "DCIE"}, /* Adaptive boost mode , */\ + { 0x70a0, "DCSR"}, /* Soft ramp up/down , */\ + { 0x70b2, "DCSYNCP"}, /* DCDC synchronization off + 7 positions , */\ + { 0x70e0, "DCDIS"}, /* DCDC on/off , */\ + { 0x9000, "RST"}, /* Reset , */\ + { 0x9011, "DMEM"}, /* Target memory , */\ + { 0x9030, "AIF"}, /* Auto increment , */\ + { 0x9040, "CFINT"}, /* Interrupt - auto clear , */\ + { 0x9050, "CFCGATE"}, /* Coolflux clock gating disabling control , */\ + { 0x9080, "REQCMD"}, /* Firmware event request rpc command , */\ + { 0x9090, "REQRST"}, /* Firmware event request reset restart , */\ + { 0x90a0, "REQMIPS"}, /* Firmware event request short on mips , */\ + { 0x90b0, "REQMUTED"}, /* Firmware event request mute sequence ready , */\ + { 0x90c0, "REQVOL"}, /* Firmware event request volume ready , */\ + { 0x90d0, "REQDMG"}, /* Firmware event request speaker damage detected , */\ + { 0x90e0, "REQCAL"}, /* Firmware event request calibration completed , */\ + { 0x90f0, "REQRSV"}, /* Firmware event request reserved , */\ + { 0x910f, "MADD"}, /* Memory address , */\ + { 0x920f, "MEMA"}, /* Activate memory access , */\ + { 0x9307, "ERR"}, /* Error flags , */\ + { 0x9387, "ACK"}, /* Acknowledge of requests , */\ + { 0x9380, "ACKCMD"}, /* Firmware event acknowledge rpc command , */\ + { 0x9390, "ACKRST"}, /* Firmware event acknowledge reset restart , */\ + { 0x93a0, "ACKMIPS"}, /* Firmware event acknowledge short on mips , */\ + { 0x93b0, "ACKMUTED"}, /* Firmware event acknowledge mute sequence ready , */\ + { 0x93c0, "ACKVOL"}, /* Firmware event acknowledge volume ready , */\ + { 0x93d0, "ACKDMG"}, /* Firmware event acknowledge speaker damage detected, */\ + { 0x93e0, "ACKCAL"}, /* Firmware event acknowledge calibration completed , */\ + { 0x93f0, "ACKRSV"}, /* Firmware event acknowledge reserved , */\ + { 0xa107, "MTPK"}, /* MTP KEY2 register , */\ + { 0xa200, "KEY1LOCKED"}, /* Indicates KEY1 is locked , */\ + { 0xa210, "KEY2LOCKED"}, /* Indicates KEY2 is locked , */\ + { 0xa360, "CIMTP"}, /* Start copying data from I2C mtp registers to mtp , */\ + { 0xa50f, "MTPRDMSB"}, /* MSB word of MTP manual read data , */\ + { 0xa60f, "MTPRDLSB"}, /* LSB word of MTP manual read data , */\ + { 0xb108, "EXTTS"}, /* External temperature (C) , */\ + { 0xb190, "TROS"}, /* Select temp Speaker calibration , */\ + { 0xf000, "MTPOTC"}, /* Calibration schedule , */\ + { 0xf010, "MTPEX"}, /* Calibration Ron executed , */\ + { 0xf020, "DCMCCAPI"}, /* Calibration current limit DCDC , */\ + { 0xf030, "DCMCCSB"}, /* Sign bit for delta calibration current limit DCDC , */\ + { 0xf042, "USERDEF"}, /* Calibration delta current limit DCDC , */\ + { 0xf40f, "R25CL"}, /* Ron resistance of left channel speaker coil , */\ + { 0xf50f, "R25CR"}, /* Ron resistance of right channel speaker coil , */\ + { 0xffff,"Unknown bitfield enum" } /* not found */\ +}; + +#define TFA2_BITNAMETABLE static tfaBfName_t Tfa2BitNames[]= {\ + { 0x0, "powerdown"}, /* Powerdown selection , */\ + { 0x10, "reset"}, /* I2C Reset - Auto clear , */\ + { 0x20, "enbl_coolflux"}, /* Enable CoolFlux , */\ + { 0x30, "enbl_amplifier"}, /* Activate Amplifier , */\ + { 0x40, "enbl_boost"}, /* Activate DC-to-DC converter , */\ + { 0x50, "coolflux_configured"}, /* Coolflux configured , */\ + { 0x60, "sel_enbl_amplifier"}, /* CoolFlux controls amplifier , */\ + { 0x71, "int_pad_io"}, /* Interrupt config , */\ + { 0x91, "fs_pulse_sel"}, /* Audio sample reference , */\ + { 0xb0, "bypass_ocp"}, /* Bypass OCP , */\ + { 0xc0, "test_ocp"}, /* OCP testing control , */\ + { 0x101, "vamp_sel"}, /* Amplifier input selection , */\ + { 0x120, "src_set_configured"}, /* I2C configured , */\ + { 0x130, "execute_cold_start"}, /* Execute cold start , */\ + { 0x140, "enbl_osc1m_auto_off"}, /* Internal osc off at PWDN , */\ + { 0x150, "man_enbl_brown_out"}, /* Reaction on BOD , */\ + { 0x160, "enbl_bod"}, /* BOD Enable , */\ + { 0x170, "enbl_bod_hyst"}, /* BOD Hysteresis , */\ + { 0x181, "bod_delay"}, /* BOD filter , */\ + { 0x1a1, "bod_lvlsel"}, /* BOD threshold , */\ + { 0x1d0, "disable_mute_time_out"}, /* Time out SB mute sequence , */\ + { 0x1e0, "pwm_sel_rcv_ns"}, /* Noise shaper selection , */\ + { 0x1f0, "man_enbl_watchdog"}, /* Watchdog manager reaction , */\ + { 0x203, "audio_fs"}, /* Sample rate (fs) , */\ + { 0x240, "input_level"}, /* TDM output attenuation , */\ + { 0x255, "cs_frac_delay"}, /* V/I Fractional delay , */\ + { 0x2b0, "bypass_hvbat_filter"}, /* Bypass HVBAT filter , */\ + { 0x2c0, "ctrl_rcvldop_bypass"}, /* Receiver LDO bypass , */\ + { 0x30f, "device_rev"}, /* Revision info , */\ + { 0x401, "pll_clkin_sel"}, /* PLL external ref clock , */\ + { 0x420, "pll_clkin_sel_osc"}, /* PLL internal ref clock , */\ + { 0x500, "enbl_spkr_ss_left"}, /* Enable left channel , */\ + { 0x510, "enbl_spkr_ss_right"}, /* Enable right channel , */\ + { 0x520, "enbl_volsense_left"}, /* Voltage sense left , */\ + { 0x530, "enbl_volsense_right"}, /* Voltage sense right , */\ + { 0x540, "enbl_cursense_left"}, /* Current sense left , */\ + { 0x550, "enbl_cursense_right"}, /* Current sense right , */\ + { 0x560, "enbl_pdm_ss"}, /* Sub-system PDM , */\ + { 0xd00, "side_tone_gain_sel"}, /* PDM side tone gain selector , */\ + { 0xd18, "side_tone_gain"}, /* Side tone gain , */\ + { 0xda0, "mute_side_tone"}, /* Side tone soft mute , */\ + { 0xe06, "ctrl_digtoana"}, /* Register for the host SW to record the current active vstep, */\ + { 0xe70, "enbl_cmfb_left"}, /* Current sense common mode feedback control for left channel, */\ + { 0xf0f, "hidden_code"}, /* 5A6Bh, 23147d to access registers (default for engineering), */\ + { 0x1000, "flag_por"}, /* POR , */\ + { 0x1010, "flag_pll_lock"}, /* PLL lock , */\ + { 0x1020, "flag_otpok"}, /* OTP alarm , */\ + { 0x1030, "flag_ovpok"}, /* OVP alarm , */\ + { 0x1040, "flag_uvpok"}, /* UVP alarm , */\ + { 0x1050, "flag_clocks_stable"}, /* Clocks stable , */\ + { 0x1060, "flag_mtp_busy"}, /* MTP busy , */\ + { 0x1070, "flag_lost_clk"}, /* Lost clock , */\ + { 0x1080, "flag_cf_speakererror"}, /* Speaker error , */\ + { 0x1090, "flag_cold_started"}, /* Cold Start , */\ + { 0x10a0, "flag_engage"}, /* Amplifier engage , */\ + { 0x10b0, "flag_watchdog_reset"}, /* Watchdog , */\ + { 0x10c0, "flag_enbl_amp"}, /* Amplifier enable , */\ + { 0x10d0, "flag_enbl_ref"}, /* References enable , */\ + { 0x10e0, "flag_adc10_ready"}, /* Control ADC , */\ + { 0x10f0, "flag_bod_vddd_nok"}, /* BOD , */\ + { 0x1100, "flag_bst_bstcur"}, /* DCDC current limiting , */\ + { 0x1110, "flag_bst_hiz"}, /* DCDC active , */\ + { 0x1120, "flag_bst_ocpok"}, /* DCDC OCP nmos , */\ + { 0x1130, "flag_bst_peakcur"}, /* Indicates current is max in DC-to-DC converter , */\ + { 0x1140, "flag_bst_voutcomp"}, /* DCDC level 1x , */\ + { 0x1150, "flag_bst_voutcomp86"}, /* DCDC level 1.14x , */\ + { 0x1160, "flag_bst_voutcomp93"}, /* DCDC level 1.07x , */\ + { 0x1170, "flag_soft_mute_busy"}, /* side tone (un)mute busy , */\ + { 0x1180, "flag_soft_mute_state"}, /* side tone mute state , */\ + { 0x1190, "flag_tdm_lut_error"}, /* TDM LUT error , */\ + { 0x11a2, "flag_tdm_status"}, /* TDM status bits , */\ + { 0x11d0, "flag_tdm_error"}, /* TDM error , */\ + { 0x11e0, "flag_haptic_busy"}, /* Status haptic driver , */\ + { 0x1200, "flag_ocpokap_left"}, /* OCPOK pmos A left , */\ + { 0x1210, "flag_ocpokan_left"}, /* OCPOK nmos A left , */\ + { 0x1220, "flag_ocpokbp_left"}, /* OCPOK pmos B left , */\ + { 0x1230, "flag_ocpokbn_left"}, /* OCPOK nmos B left , */\ + { 0x1240, "flag_clipa_high_left"}, /* Clipping A left to Vddp , */\ + { 0x1250, "flag_clipa_low_left"}, /* Clipping A left to gnd , */\ + { 0x1260, "flag_clipb_high_left"}, /* Clipping B left to Vddp , */\ + { 0x1270, "flag_clipb_low_left"}, /* Clipping B left to gnd , */\ + { 0x1280, "flag_ocpokap_rcv"}, /* OCPOK pmos A RCV , */\ + { 0x1290, "flag_ocpokan_rcv"}, /* OCPOK nmos A RCV , */\ + { 0x12a0, "flag_ocpokbp_rcv"}, /* OCPOK pmos B RCV , */\ + { 0x12b0, "flag_ocpokbn_rcv"}, /* OCPOK nmos B RCV , */\ + { 0x12c0, "flag_rcvldop_ready"}, /* RCV LDO regulates , */\ + { 0x12d0, "flag_rcvldop_bypassready"}, /* Receiver LDO ready , */\ + { 0x12e0, "flag_ocp_alarm_left"}, /* OCP left amplifier , */\ + { 0x12f0, "flag_clip_left"}, /* Amplifier left clipping , */\ + { 0x1300, "flag_ocpokap_right"}, /* OCPOK pmos A right , */\ + { 0x1310, "flag_ocpokan_right"}, /* OCPOK nmos A right , */\ + { 0x1320, "flag_ocpokbp_right"}, /* OCPOK pmos B right , */\ + { 0x1330, "flag_ocpokbn_right"}, /* OCPOK nmos B right , */\ + { 0x1340, "flag_clipa_high_right"}, /* Clipping A right to Vddp , */\ + { 0x1350, "flag_clipa_low_right"}, /* Clipping A right to gnd , */\ + { 0x1360, "flag_clipb_high_right"}, /* Clipping B left to Vddp , */\ + { 0x1370, "flag_clipb_low_right"}, /* Clipping B right to gnd , */\ + { 0x1380, "flag_ocp_alarm_right"}, /* OCP right amplifier , */\ + { 0x1390, "flag_clip_right"}, /* Amplifier right clipping , */\ + { 0x13a0, "flag_mic_ocpok"}, /* OCPOK MICVDD , */\ + { 0x13b0, "flag_man_alarm_state"}, /* Alarm state , */\ + { 0x13c0, "flag_man_wait_src_settings"}, /* Wait HW I2C settings , */\ + { 0x13d0, "flag_man_wait_cf_config"}, /* Wait CF config , */\ + { 0x13e0, "flag_man_start_mute_audio"}, /* Audio mute sequence , */\ + { 0x13f0, "flag_man_operating_state"}, /* Operating state , */\ + { 0x1400, "flag_cf_speakererror_left"}, /* Left speaker status , */\ + { 0x1410, "flag_cf_speakererror_right"}, /* Right speaker status , */\ + { 0x1420, "flag_clk_out_of_range"}, /* External clock status , */\ + { 0x1433, "man_state"}, /* Device manager status , */\ + { 0x1509, "bat_adc"}, /* Battery voltage (V) , */\ + { 0x1608, "temp_adc"}, /* IC Temperature (C) , */\ + { 0x2003, "tdm_usecase"}, /* Usecase setting , */\ + { 0x2040, "tdm_enable"}, /* Enable interface , */\ + { 0x2050, "tdm_mode"}, /* Slave/master , */\ + { 0x2060, "tdm_clk_inversion"}, /* Reception data to BCK clock , */\ + { 0x2073, "tdm_fs_ws_length"}, /* FS length (master mode only) , */\ + { 0x20b0, "tdm_fs_ws_polarity"}, /* FS polarity , */\ + { 0x20c3, "tdm_nbck"}, /* N-BCK's in FS , */\ + { 0x2103, "tdm_nb_of_slots"}, /* N-slots in Frame , */\ + { 0x2144, "tdm_slot_length"}, /* N-bits in slot , */\ + { 0x2194, "tdm_bits_remaining"}, /* N-bits remaining , */\ + { 0x21e0, "tdm_data_delay"}, /* data delay to FS , */\ + { 0x21f0, "tdm_data_adjustment"}, /* data adjustment , */\ + { 0x2201, "tdm_audio_sample_compression"}, /* Received audio compression , */\ + { 0x2224, "tdm_sample_size"}, /* Sample size per slot , */\ + { 0x2271, "tdm_txdata_format"}, /* Format unused bits , */\ + { 0x2291, "tdm_txdata_format_unused_slot_sd0"}, /* Format unused slots GAINIO , */\ + { 0x22b1, "tdm_txdata_format_unused_slot_sd1"}, /* Format unused slots DIO1 , */\ + { 0x22d1, "tdm_txdata_format_unused_slot_sd2"}, /* Format unused slots DIO2 , */\ + { 0x2300, "tdm_sink0_enable"}, /* Control gainin (not used in DSP) , */\ + { 0x2310, "tdm_sink1_enable"}, /* Control audio left , */\ + { 0x2320, "tdm_sink2_enable"}, /* Control audio right , */\ + { 0x2330, "tdm_source0_enable"}, /* Control gainout (not used in DSP) , */\ + { 0x2340, "tdm_source1_enable"}, /* Control voltage sense right , */\ + { 0x2350, "tdm_source2_enable"}, /* Control current sense right , */\ + { 0x2360, "tdm_source3_enable"}, /* Voltage sense left control , */\ + { 0x2370, "tdm_source4_enable"}, /* Current sense left control , */\ + { 0x2380, "tdm_source5_enable"}, /* DSP out right control , */\ + { 0x2390, "tdm_source6_enable"}, /* DSP out left control , */\ + { 0x23a0, "tdm_source7_enable"}, /* AEC ref left control , */\ + { 0x23b0, "tdm_source8_enable"}, /* AEC ref right control , */\ + { 0x23c0, "tdm_source9_enable"}, /* PDM 1 control , */\ + { 0x23d0, "tdm_source10_enable"}, /* PDM 2 control , */\ + { 0x2401, "tdm_sink0_io"}, /* IO gainin (not used in DSP) , */\ + { 0x2421, "tdm_sink1_io"}, /* IO audio left , */\ + { 0x2441, "tdm_sink2_io"}, /* IO audio right , */\ + { 0x2461, "tdm_source0_io"}, /* IO gainout (not used in DSP) , */\ + { 0x2481, "tdm_source1_io"}, /* IO voltage sense right , */\ + { 0x24a1, "tdm_source2_io"}, /* IO current sense right , */\ + { 0x24c1, "tdm_source3_io"}, /* IO voltage sense left , */\ + { 0x24e1, "tdm_source4_io"}, /* IO current sense left , */\ + { 0x2501, "tdm_source5_io"}, /* IO dspout right , */\ + { 0x2521, "tdm_source6_io"}, /* IO dspout left , */\ + { 0x2541, "tdm_source7_io"}, /* IO AEC ref left control , */\ + { 0x2561, "tdm_source8_io"}, /* IO AEC ref right control , */\ + { 0x2581, "tdm_source9_io"}, /* IO pdm1 , */\ + { 0x25a1, "tdm_source10_io"}, /* IO pdm2 , */\ + { 0x2603, "tdm_sink0_slot"}, /* Position gainin (not used in DSP) , */\ + { 0x2643, "tdm_sink1_slot"}, /* Position audio left , */\ + { 0x2683, "tdm_sink2_slot"}, /* Position audio right , */\ + { 0x26c3, "tdm_source0_slot"}, /* Position gainout (not used in DSP) , */\ + { 0x2703, "tdm_source1_slot"}, /* Position voltage sense right , */\ + { 0x2743, "tdm_source2_slot"}, /* Position current sense right , */\ + { 0x2783, "tdm_source3_slot"}, /* Position voltage sense left , */\ + { 0x27c3, "tdm_source4_slot"}, /* Position current sense left , */\ + { 0x2803, "tdm_source5_slot"}, /* Position dspout right , */\ + { 0x2843, "tdm_source6_slot"}, /* Position dspout left , */\ + { 0x2883, "tdm_source7_slot"}, /* Position AEC ref left control , */\ + { 0x28c3, "tdm_source8_slot"}, /* Position AEC ref right control , */\ + { 0x2903, "tdm_source9_slot"}, /* Position pdm1 , */\ + { 0x2943, "tdm_source10_slot"}, /* Position pdm2 , */\ + { 0x3100, "pdm_mode"}, /* PDM control , */\ + { 0x3111, "pdm_side_tone_sel"}, /* Side tone input , */\ + { 0x3130, "pdm_left_sel"}, /* PDM data selection for left channel during PDM direct mode, */\ + { 0x3140, "pdm_right_sel"}, /* PDM data selection for right channel during PDM direct mode, */\ + { 0x3150, "enbl_micvdd"}, /* Enable MICVDD , */\ + { 0x3160, "bypass_micvdd_ocp"}, /* Bypass control for the MICVDD OCP flag processing , */\ + { 0x3201, "pdm_nbck"}, /* PDM BCK/Fs ratio , */\ + { 0x3223, "pdm_gain"}, /* PDM gain , */\ + { 0x3263, "sel_pdm_out_data"}, /* PDM output selection - RE/FE data combination , */\ + { 0x32a0, "sel_cf_haptic_data"}, /* Select the source for haptic data output (not for customer), */\ + { 0x3307, "haptic_duration"}, /* Duration (ms) , */\ + { 0x3387, "haptic_data"}, /* DC value (FFS) , */\ + { 0x3403, "gpio_datain"}, /* Receiving value , */\ + { 0x3500, "gpio_ctrl"}, /* GPIO master control over GPIO1/2 ports (not for customer), */\ + { 0x3513, "gpio_dir"}, /* Configuration , */\ + { 0x3553, "gpio_dataout"}, /* Transmitting value , */\ + { 0x4000, "int_out_flag_por"}, /* Status POR , */\ + { 0x4010, "int_out_flag_pll_lock"}, /* Status PLL lock , */\ + { 0x4020, "int_out_flag_otpok"}, /* Status OTP alarm , */\ + { 0x4030, "int_out_flag_ovpok"}, /* Status OVP alarm , */\ + { 0x4040, "int_out_flag_uvpok"}, /* Status UVP alarm , */\ + { 0x4050, "int_out_flag_clocks_stable"}, /* Status clocks stable , */\ + { 0x4060, "int_out_flag_mtp_busy"}, /* Status MTP busy , */\ + { 0x4070, "int_out_flag_lost_clk"}, /* Status lost clock , */\ + { 0x4080, "int_out_flag_cf_speakererror"}, /* Status speaker error , */\ + { 0x4090, "int_out_flag_cold_started"}, /* Status cold start , */\ + { 0x40a0, "int_out_flag_engage"}, /* Status amplifier engage , */\ + { 0x40b0, "int_out_flag_watchdog_reset"}, /* Status watchdog , */\ + { 0x40c0, "int_out_flag_enbl_amp"}, /* Status amplifier enable , */\ + { 0x40d0, "int_out_flag_enbl_ref"}, /* Status Ref enable , */\ + { 0x40e0, "int_out_flag_adc10_ready"}, /* Status Control ADC , */\ + { 0x40f0, "int_out_flag_bod_vddd_nok"}, /* Status BOD , */\ + { 0x4100, "int_out_flag_bst_bstcur"}, /* Status DCDC current limiting , */\ + { 0x4110, "int_out_flag_bst_hiz"}, /* Status DCDC active , */\ + { 0x4120, "int_out_flag_bst_ocpok"}, /* Status DCDC OCP , */\ + { 0x4130, "int_out_flag_bst_peakcur"}, /* Status bst peakcur , */\ + { 0x4140, "int_out_flag_bst_voutcomp"}, /* Status DCDC level 1x , */\ + { 0x4150, "int_out_flag_bst_voutcomp86"}, /* Status DCDC level 1.14x , */\ + { 0x4160, "int_out_flag_bst_voutcomp93"}, /* Status DCDC level 1.07x , */\ + { 0x4170, "int_out_flag_rcvldop_ready"}, /* Status rcvldop ready , */\ + { 0x4180, "int_out_flag_ocp_alarm_left"}, /* Status ocp alarm left , */\ + { 0x4190, "int_out_flag_ocp_alarm_right"}, /* Status ocp alarm right , */\ + { 0x41a0, "int_out_flag_man_wait_src_settings"}, /* Status Waits HW I2C settings , */\ + { 0x41b0, "int_out_flag_man_wait_cf_config"}, /* Status waits CF config , */\ + { 0x41c0, "int_out_flag_man_start_mute_audio"}, /* Status Audio mute sequence , */\ + { 0x41d0, "int_out_flag_cfma_err"}, /* Status cfma error , */\ + { 0x41e0, "int_out_flag_cfma_ack"}, /* Status cfma ack , */\ + { 0x41f0, "int_out_flag_clk_out_of_range"}, /* Status flag_clk_out_of_range , */\ + { 0x4200, "int_out_flag_tdm_error"}, /* Status tdm error , */\ + { 0x4210, "int_out_flag_clip_left"}, /* Status clip left , */\ + { 0x4220, "int_out_flag_clip_right"}, /* Status clip right , */\ + { 0x4230, "int_out_flag_mic_ocpok"}, /* Status mic ocpok , */\ + { 0x4400, "int_in_flag_por"}, /* Clear POR , */\ + { 0x4410, "int_in_flag_pll_lock"}, /* Clear PLL lock , */\ + { 0x4420, "int_in_flag_otpok"}, /* Clear OTP alarm , */\ + { 0x4430, "int_in_flag_ovpok"}, /* Clear OVP alarm , */\ + { 0x4440, "int_in_flag_uvpok"}, /* Clear UVP alarm , */\ + { 0x4450, "int_in_flag_clocks_stable"}, /* Clear clocks stable , */\ + { 0x4460, "int_in_flag_mtp_busy"}, /* Clear mtp busy , */\ + { 0x4470, "int_in_flag_lost_clk"}, /* Clear lost clk , */\ + { 0x4480, "int_in_flag_cf_speakererror"}, /* Clear speaker error , */\ + { 0x4490, "int_in_flag_cold_started"}, /* Clear cold started , */\ + { 0x44a0, "int_in_flag_engage"}, /* Clear amplifier engage , */\ + { 0x44b0, "int_in_flag_watchdog_reset"}, /* Clear watchdog , */\ + { 0x44c0, "int_in_flag_enbl_amp"}, /* Clear enbl amp , */\ + { 0x44d0, "int_in_flag_enbl_ref"}, /* Clear ref enable , */\ + { 0x44e0, "int_in_flag_adc10_ready"}, /* Clear control ADC , */\ + { 0x44f0, "int_in_flag_bod_vddd_nok"}, /* Clear BOD , */\ + { 0x4500, "int_in_flag_bst_bstcur"}, /* Clear DCDC current limiting , */\ + { 0x4510, "int_in_flag_bst_hiz"}, /* Clear DCDC active , */\ + { 0x4520, "int_in_flag_bst_ocpok"}, /* Clear DCDC OCP , */\ + { 0x4530, "int_in_flag_bst_peakcur"}, /* Clear bst peakcur , */\ + { 0x4540, "int_in_flag_bst_voutcomp"}, /* Clear DCDC level 1x , */\ + { 0x4550, "int_in_flag_bst_voutcomp86"}, /* Clear DCDC level 1.14x , */\ + { 0x4560, "int_in_flag_bst_voutcomp93"}, /* Clear DCDC level 1.07x , */\ + { 0x4570, "int_in_flag_rcvldop_ready"}, /* Clear rcvldop ready , */\ + { 0x4580, "int_in_flag_ocp_alarm_left"}, /* Clear ocp alarm left , */\ + { 0x4590, "int_in_flag_ocp_alarm_right"}, /* Clear ocp alarm right , */\ + { 0x45a0, "int_in_flag_man_wait_src_settings"}, /* Clear wait HW I2C settings , */\ + { 0x45b0, "int_in_flag_man_wait_cf_config"}, /* Clear wait cf config , */\ + { 0x45c0, "int_in_flag_man_start_mute_audio"}, /* Clear audio mute sequence , */\ + { 0x45d0, "int_in_flag_cfma_err"}, /* Clear cfma err , */\ + { 0x45e0, "int_in_flag_cfma_ack"}, /* Clear cfma ack , */\ + { 0x45f0, "int_in_flag_clk_out_of_range"}, /* Clear flag_clk_out_of_range , */\ + { 0x4600, "int_in_flag_tdm_error"}, /* Clear tdm error , */\ + { 0x4610, "int_in_flag_clip_left"}, /* Clear clip left , */\ + { 0x4620, "int_in_flag_clip_right"}, /* Clear clip right , */\ + { 0x4630, "int_in_flag_mic_ocpok"}, /* Clear mic ocpok , */\ + { 0x4800, "int_enable_flag_por"}, /* Enable por , */\ + { 0x4810, "int_enable_flag_pll_lock"}, /* Enable pll lock , */\ + { 0x4820, "int_enable_flag_otpok"}, /* Enable OTP alarm , */\ + { 0x4830, "int_enable_flag_ovpok"}, /* Enable OVP alarm , */\ + { 0x4840, "int_enable_flag_uvpok"}, /* Enable UVP alarm , */\ + { 0x4850, "int_enable_flag_clocks_stable"}, /* Enable clocks stable , */\ + { 0x4860, "int_enable_flag_mtp_busy"}, /* Enable mtp busy , */\ + { 0x4870, "int_enable_flag_lost_clk"}, /* Enable lost clk , */\ + { 0x4880, "int_enable_flag_cf_speakererror"}, /* Enable speaker error , */\ + { 0x4890, "int_enable_flag_cold_started"}, /* Enable cold started , */\ + { 0x48a0, "int_enable_flag_engage"}, /* Enable amplifier engage , */\ + { 0x48b0, "int_enable_flag_watchdog_reset"}, /* Enable watchdog , */\ + { 0x48c0, "int_enable_flag_enbl_amp"}, /* Enable enbl amp , */\ + { 0x48d0, "int_enable_flag_enbl_ref"}, /* Enable ref enable , */\ + { 0x48e0, "int_enable_flag_adc10_ready"}, /* Enable Control ADC , */\ + { 0x48f0, "int_enable_flag_bod_vddd_nok"}, /* Enable BOD , */\ + { 0x4900, "int_enable_flag_bst_bstcur"}, /* Enable DCDC current limiting , */\ + { 0x4910, "int_enable_flag_bst_hiz"}, /* Enable DCDC active , */\ + { 0x4920, "int_enable_flag_bst_ocpok"}, /* Enable DCDC OCP , */\ + { 0x4930, "int_enable_flag_bst_peakcur"}, /* Enable bst peakcur , */\ + { 0x4940, "int_enable_flag_bst_voutcomp"}, /* Enable DCDC level 1x , */\ + { 0x4950, "int_enable_flag_bst_voutcomp86"}, /* Enable DCDC level 1.14x , */\ + { 0x4960, "int_enable_flag_bst_voutcomp93"}, /* Enable DCDC level 1.07x , */\ + { 0x4970, "int_enable_flag_rcvldop_ready"}, /* Enable rcvldop ready , */\ + { 0x4980, "int_enable_flag_ocp_alarm_left"}, /* Enable ocp alarm left , */\ + { 0x4990, "int_enable_flag_ocp_alarm_right"}, /* Enable ocp alarm right , */\ + { 0x49a0, "int_enable_flag_man_wait_src_settings"}, /* Enable waits HW I2C settings , */\ + { 0x49b0, "int_enable_flag_man_wait_cf_config"}, /* Enable man wait cf config , */\ + { 0x49c0, "int_enable_flag_man_start_mute_audio"}, /* Enable man Audio mute sequence , */\ + { 0x49d0, "int_enable_flag_cfma_err"}, /* Enable cfma err , */\ + { 0x49e0, "int_enable_flag_cfma_ack"}, /* Enable cfma ack , */\ + { 0x49f0, "int_enable_flag_clk_out_of_range"}, /* Enable flag_clk_out_of_range , */\ + { 0x4a00, "int_enable_flag_tdm_error"}, /* Enable tdm error , */\ + { 0x4a10, "int_enable_flag_clip_left"}, /* Enable clip left , */\ + { 0x4a20, "int_enable_flag_clip_right"}, /* Enable clip right , */\ + { 0x4a30, "int_enable_flag_mic_ocpok"}, /* Enable mic ocpok , */\ + { 0x4c00, "int_polarity_flag_por"}, /* Polarity por , */\ + { 0x4c10, "int_polarity_flag_pll_lock"}, /* Polarity pll lock , */\ + { 0x4c20, "int_polarity_flag_otpok"}, /* Polarity OTP alarm , */\ + { 0x4c30, "int_polarity_flag_ovpok"}, /* Polarity OVP alarm , */\ + { 0x4c40, "int_polarity_flag_uvpok"}, /* Polarity UVP alarm , */\ + { 0x4c50, "int_polarity_flag_clocks_stable"}, /* Polarity clocks stable , */\ + { 0x4c60, "int_polarity_flag_mtp_busy"}, /* Polarity mtp busy , */\ + { 0x4c70, "int_polarity_flag_lost_clk"}, /* Polarity lost clk , */\ + { 0x4c80, "int_polarity_flag_cf_speakererror"}, /* Polarity speaker error , */\ + { 0x4c90, "int_polarity_flag_cold_started"}, /* Polarity cold started , */\ + { 0x4ca0, "int_polarity_flag_engage"}, /* Polarity amplifier engage , */\ + { 0x4cb0, "int_polarity_flag_watchdog_reset"}, /* Polarity watchdog , */\ + { 0x4cc0, "int_polarity_flag_enbl_amp"}, /* Polarity enbl amp , */\ + { 0x4cd0, "int_polarity_flag_enbl_ref"}, /* Polarity ref enable , */\ + { 0x4ce0, "int_polarity_flag_adc10_ready"}, /* Polarity Control ADC , */\ + { 0x4cf0, "int_polarity_flag_bod_vddd_nok"}, /* Polarity BOD , */\ + { 0x4d00, "int_polarity_flag_bst_bstcur"}, /* Polarity DCDC current limiting , */\ + { 0x4d10, "int_polarity_flag_bst_hiz"}, /* Polarity DCDC active , */\ + { 0x4d20, "int_polarity_flag_bst_ocpok"}, /* Polarity DCDC OCP , */\ + { 0x4d30, "int_polarity_flag_bst_peakcur"}, /* Polarity bst peakcur , */\ + { 0x4d40, "int_polarity_flag_bst_voutcomp"}, /* Polarity DCDC level 1x , */\ + { 0x4d50, "int_polarity_flag_bst_voutcomp86"}, /* Polarity DCDC level 1.14x , */\ + { 0x4d60, "int_polarity_flag_bst_voutcomp93"}, /* Polarity DCDC level 1.07x , */\ + { 0x4d70, "int_polarity_flag_rcvldop_ready"}, /* Polarity rcvldop ready , */\ + { 0x4d80, "int_polarity_flag_ocp_alarm_left"}, /* Polarity ocp alarm left , */\ + { 0x4d90, "int_polarity_flag_ocp_alarm_right"}, /* Polarity ocp alarm right , */\ + { 0x4da0, "int_polarity_flag_man_wait_src_settings"}, /* Polarity waits HW I2C settings , */\ + { 0x4db0, "int_polarity_flag_man_wait_cf_config"}, /* Polarity man wait cf config , */\ + { 0x4dc0, "int_polarity_flag_man_start_mute_audio"}, /* Polarity man audio mute sequence , */\ + { 0x4dd0, "int_polarity_flag_cfma_err"}, /* Polarity cfma err , */\ + { 0x4de0, "int_polarity_flag_cfma_ack"}, /* Polarity cfma ack , */\ + { 0x4df0, "int_polarity_flag_clk_out_of_range"}, /* Polarity flag_clk_out_of_range , */\ + { 0x4e00, "int_polarity_flag_tdm_error"}, /* Polarity tdm error , */\ + { 0x4e10, "int_polarity_flag_clip_left"}, /* Polarity clip left , */\ + { 0x4e20, "int_polarity_flag_clip_right"}, /* Polarity clip right , */\ + { 0x4e30, "int_polarity_flag_mic_ocpok"}, /* Polarity mic ocpok , */\ + { 0x5001, "vbat_prot_attack_time"}, /* Battery protection attack Time , */\ + { 0x5023, "vbat_prot_thlevel"}, /* Battery protection threshold voltage level , */\ + { 0x5061, "vbat_prot_max_reduct"}, /* Battery protection maximum reduction , */\ + { 0x5082, "vbat_prot_release_time"}, /* Battery protection release time , */\ + { 0x50b1, "vbat_prot_hysterese"}, /* Battery protection hysteresis , */\ + { 0x50d0, "rst_min_vbat"}, /* Reset clipper - Auto clear , */\ + { 0x50e0, "sel_vbat"}, /* Battery voltage read out , */\ + { 0x50f0, "bypass_clipper"}, /* Bypass HW clipper , */\ + { 0x5100, "batsense_steepness"}, /* Vbat prot steepness , */\ + { 0x5110, "soft_mute"}, /* Soft mute HW , */\ + { 0x5120, "cf_mute_left"}, /* Soft mute FW left , */\ + { 0x5130, "cf_mute_right"}, /* Soft mute FW right , */\ + { 0x5140, "bypass_hp_left"}, /* Bypass HPF left , */\ + { 0x5150, "bypass_hp_right"}, /* Bypass HPF right , */\ + { 0x5160, "enbl_dpsa_left"}, /* Enable DPSA left , */\ + { 0x5170, "enbl_dpsa_right"}, /* Enable DPSA right , */\ + { 0x5187, "cf_volume"}, /* FW volume control for primary audio channel , */\ + { 0x5200, "ctrl_rcv"}, /* Selection receiver , */\ + { 0x5210, "ctrl_rcv_fb_100k"}, /* Selection of feedback resistor for receiver mode (not for customer), */\ + { 0x5222, "ctrl_cc"}, /* Clip control setting , */\ + { 0x5257, "gain"}, /* Amplifier gain , */\ + { 0x52d0, "ctrl_slopectrl"}, /* Enables slope control , */\ + { 0x52e1, "ctrl_slope"}, /* Set slope , */\ + { 0x5301, "dpsa_level"}, /* DPSA threshold levels , */\ + { 0x5321, "dpsa_release"}, /* DPSA Release time , */\ + { 0x5340, "clipfast"}, /* Clock selection for HW clipper for battery protection, */\ + { 0x5350, "bypass_lp"}, /* Bypass the low power filter inside temperature sensor, */\ + { 0x5360, "enbl_low_latency"}, /* CF low latency outputs for add module , */\ + { 0x5400, "first_order_mode"}, /* Overrule to 1st order mode of control stage when clipping, */\ + { 0x5410, "bypass_ctrlloop"}, /* Switch amplifier into open loop configuration , */\ + { 0x5420, "fb_hz"}, /* Feedback resistor set to high ohmic , */\ + { 0x5430, "icomp_engage"}, /* Engage of icomp , */\ + { 0x5440, "ctrl_kickback"}, /* Prevent double pulses of output stage , */\ + { 0x5450, "icomp_engage_overrule"}, /* To overrule the functional icomp_engage signal during validation, */\ + { 0x5503, "ctrl_dem"}, /* Enable DEM icomp and DEM one bit dac , */\ + { 0x5543, "ctrl_dem_mismatch"}, /* Enable DEM icomp mismatch for testing , */\ + { 0x5581, "dpsa_drive"}, /* Control of the number of power stage sections, total of 4 sections. Each section is 1/4 of the total power stages., */\ + { 0x560a, "enbl_amp_left"}, /* Switch on the class-D power sections, each part of the analog sections can be switched on/off individually - Left channel, */\ + { 0x56b0, "enbl_engage_left"}, /* Enables/engage power stage and control loop - left channel, */\ + { 0x570a, "enbl_amp_right"}, /* Switch on the class-D power sections, each part of the analog sections can be switched on/off individually - Right channel, */\ + { 0x57b0, "enbl_engage_right"}, /* Enables/engage power stage and control loop - right channel, */\ + { 0x5800, "hard_mute_left"}, /* Hard mute - PWM module left , */\ + { 0x5810, "hard_mute_right"}, /* Hard mute - PWM module right , */\ + { 0x5820, "pwm_shape"}, /* PWM shape , */\ + { 0x5830, "pwm_bitlength"}, /* PWM bit length in noise shaper , */\ + { 0x5844, "pwm_delay"}, /* PWM delay bits to set the delay, clockd is 1/(k*2048*fs), */\ + { 0x5890, "reclock_pwm"}, /* Reclock the pwm signal inside analog , */\ + { 0x58a0, "reclock_voltsense"}, /* Reclock the voltage sense pwm signal , */\ + { 0x58b0, "enbl_pwm_phase_shift_left"}, /* Control for pwm phase shift, inverted function - left channel, */\ + { 0x58c0, "enbl_pwm_phase_shift_right"}, /* Control for pwm phase shift - right channel , */\ + { 0x5900, "ctrl_rcvldop_pulldown"}, /* Pulldown of LDO (2.7V) , */\ + { 0x5910, "ctrl_rcvldop_test_comp"}, /* Enable testing of LDO comparator , */\ + { 0x5920, "ctrl_rcvldop_test_loadedldo"}, /* Load connected to rcvldo , */\ + { 0x5930, "enbl_rcvldop"}, /* Enables the LDO (2.7) , */\ + { 0x5a07, "cf_volume_sec"}, /* FW volume control for secondary audio channel , */\ + { 0x5a87, "sw_profile"}, /* Software profile data , */\ + { 0x7002, "boost_volt"}, /* Boost voltage , */\ + { 0x7033, "boost_cur"}, /* Max coil current , */\ + { 0x7071, "bst_coil_value"}, /* Coil Value , */\ + { 0x7090, "boost_intel"}, /* Adaptive boost mode , */\ + { 0x70a0, "boost_speed"}, /* Soft ramp up/down , */\ + { 0x70b2, "dcdc_synchronisation"}, /* DCDC synchronization off + 7 positions , */\ + { 0x70e0, "dcdcoff_mode"}, /* DCDC on/off , */\ + { 0x7104, "bst_drive"}, /* Binary coded drive setting for boost converter power stage, */\ + { 0x7151, "bst_scalecur"}, /* For testing direct control scale current , */\ + { 0x7174, "bst_slopecur"}, /* For testing direct control slope current , */\ + { 0x71c1, "bst_slope"}, /* Boost slope speed , */\ + { 0x71e0, "bst_bypass_bstcur"}, /* Bypass control for boost current settings , */\ + { 0x71f0, "bst_bypass_bstfoldback"}, /* Bypass control for boost foldback , */\ + { 0x7200, "enbl_bst_engage"}, /* Enable power stage dcdc controller , */\ + { 0x7210, "enbl_bst_hizcom"}, /* Enable hiz comparator , */\ + { 0x7220, "enbl_bst_peak2avg"}, /* Enable boost peak2avg functionality , */\ + { 0x7230, "enbl_bst_peakcur"}, /* Enable peak current , */\ + { 0x7240, "enbl_bst_power"}, /* Enable line of the powerstage , */\ + { 0x7250, "enbl_bst_slopecur"}, /* Enable bit of max-current dac , */\ + { 0x7260, "enbl_bst_voutcomp"}, /* Enable vout comparators , */\ + { 0x7270, "enbl_bst_voutcomp86"}, /* Enable vout-86 comparators , */\ + { 0x7280, "enbl_bst_voutcomp93"}, /* Enable vout-93 comparators , */\ + { 0x7290, "enbl_bst_windac"}, /* Enable window dac , */\ + { 0x72a5, "bst_windac"}, /* for testing direct control windac , */\ + { 0x7300, "boost_alg"}, /* Control for boost adaptive loop gain , */\ + { 0x7311, "boost_loopgain"}, /* DCDC boost loopgain setting , */\ + { 0x7332, "bst_freq"}, /* DCDC bost frequency control , */\ + { 0x8001, "sel_clk_cs"}, /* Current sense clock duty cycle control , */\ + { 0x8021, "micadc_speed"}, /* Current sense clock for MiCADC selection - 32/44.1/48 KHz Fs band only, */\ + { 0x8040, "cs_dc_offset"}, /* Current sense decimator offset control , */\ + { 0x8050, "cs_gain_control"}, /* Current sense gain control , */\ + { 0x8060, "cs_bypass_gc"}, /* Bypasses the CS gain correction , */\ + { 0x8087, "cs_gain"}, /* Current sense gain , */\ + { 0x8110, "invertpwm_left"}, /* Current sense common mode feedback pwm invert control for left channel, */\ + { 0x8122, "cmfb_gain_left"}, /* Current sense common mode feedback control gain for left channel, */\ + { 0x8154, "cmfb_offset_left"}, /* Current sense common mode feedback control offset for left channel, */\ + { 0x8200, "enbl_cmfb_right"}, /* Current sense common mode feedback control for right channel, */\ + { 0x8210, "invertpwm_right"}, /* Current sense common mode feedback pwm invert control for right channel, */\ + { 0x8222, "cmfb_gain_right"}, /* Current sense common mode feedback control gain for right channel, */\ + { 0x8254, "cmfb_offset_right"}, /* Current sense common mode feedback control offset for right channel, */\ + { 0x8305, "cs_ktemp"}, /* Current sense temperature compensation trimming (1 - VALUE*TEMP)*signal, */\ + { 0x8400, "cs_adc_bsoinv"}, /* Bitstream inversion for current sense ADC , */\ + { 0x8421, "cs_adc_hifreq"}, /* Frequency mode current sense ADC , */\ + { 0x8440, "cs_adc_nortz"}, /* Return to zero for current sense ADC , */\ + { 0x8453, "cs_adc_offset"}, /* Micadc ADC offset setting , */\ + { 0x8490, "cs_adc_slowdel"}, /* Select delay for current sense ADC (internal decision circuitry), */\ + { 0x84a4, "cs_adc_gain"}, /* Gain setting for current sense ADC (two's complement), */\ + { 0x8500, "cs_resonator_enable"}, /* Enable for resonator to improve SRN , */\ + { 0x8510, "cs_classd_tran_skip"}, /* Skip current sense connection during a classD amplifier transition, */\ + { 0x8530, "cs_inn_short"}, /* Short current sense negative to common mode , */\ + { 0x8540, "cs_inp_short"}, /* Short current sense positive to common mode , */\ + { 0x8550, "cs_ldo_bypass"}, /* Bypass current sense LDO , */\ + { 0x8560, "cs_ldo_pulldown"}, /* Pull down current sense LDO, only valid if left_enbl_cs_ldo is high, */\ + { 0x8574, "cs_ldo_voset"}, /* Current sense LDO voltage level setting (two's complement), */\ + { 0x8600, "enbl_cs_adc_left"}, /* Enable current sense ADC , */\ + { 0x8610, "enbl_cs_inn1_left"}, /* Enable connection of current sense negative1 , */\ + { 0x8630, "enbl_cs_inp1_left"}, /* Enable connection of current sense positive1 , */\ + { 0x8650, "enbl_cs_ldo_left"}, /* Enable current sense LDO , */\ + { 0x8660, "enbl_cs_nofloating_n_left"}, /* Connect current sense negative to gnda at transitions of booster or classd amplifiers. Otherwise floating (0), */\ + { 0x8670, "enbl_cs_nofloating_p_left"}, /* Connect current sense positive to gnda at transitions of booster or classd amplifiers. Otherwise floating (0), */\ + { 0x8680, "enbl_cs_vbatldo_left"}, /* Enable of current sense LDO , */\ + { 0x8700, "enbl_cs_adc_right"}, /* Enable current sense ADC , */\ + { 0x8710, "enbl_cs_inn1_right"}, /* Enable connection of current sense negative1 , */\ + { 0x8730, "enbl_cs_inp1_right"}, /* Enable connection of current sense positive1 , */\ + { 0x8750, "enbl_cs_ldo_right"}, /* Enable current sense LDO , */\ + { 0x8760, "enbl_cs_nofloating_n_right"}, /* Connect current sense negative to gnda at transitions of booster or classd amplifiers. Otherwise floating (0), */\ + { 0x8770, "enbl_cs_nofloating_p_right"}, /* Connect current sense positive to gnda at transitions of booster or classd amplifiers. Otherwise floating (0), */\ + { 0x8780, "enbl_cs_vbatldo_right"}, /* Enable of current sense LDO , */\ + { 0x8800, "volsense_pwm_sel"}, /* Voltage sense PWM source selection control , */\ + { 0x8810, "volsense_dc_offset"}, /* Voltage sense decimator offset control , */\ + { 0x9000, "cf_rst_dsp"}, /* Reset , */\ + { 0x9011, "cf_dmem"}, /* Target memory , */\ + { 0x9030, "cf_aif"}, /* Auto increment , */\ + { 0x9040, "cf_int"}, /* Interrupt - auto clear , */\ + { 0x9050, "cf_cgate_off"}, /* Coolflux clock gating disabling control , */\ + { 0x9080, "cf_req_cmd"}, /* Firmware event request rpc command , */\ + { 0x9090, "cf_req_reset"}, /* Firmware event request reset restart , */\ + { 0x90a0, "cf_req_mips"}, /* Firmware event request short on mips , */\ + { 0x90b0, "cf_req_mute_ready"}, /* Firmware event request mute sequence ready , */\ + { 0x90c0, "cf_req_volume_ready"}, /* Firmware event request volume ready , */\ + { 0x90d0, "cf_req_damage"}, /* Firmware event request speaker damage detected , */\ + { 0x90e0, "cf_req_calibrate_ready"}, /* Firmware event request calibration completed , */\ + { 0x90f0, "cf_req_reserved"}, /* Firmware event request reserved , */\ + { 0x910f, "cf_madd"}, /* Memory address , */\ + { 0x920f, "cf_mema"}, /* Activate memory access , */\ + { 0x9307, "cf_err"}, /* Error flags , */\ + { 0x9387, "cf_ack"}, /* Acknowledge of requests , */\ + { 0x9380, "cf_ack_cmd"}, /* Firmware event acknowledge rpc command , */\ + { 0x9390, "cf_ack_reset"}, /* Firmware event acknowledge reset restart , */\ + { 0x93a0, "cf_ack_mips"}, /* Firmware event acknowledge short on mips , */\ + { 0x93b0, "cf_ack_mute_ready"}, /* Firmware event acknowledge mute sequence ready , */\ + { 0x93c0, "cf_ack_volume_ready"}, /* Firmware event acknowledge volume ready , */\ + { 0x93d0, "cf_ack_damage"}, /* Firmware event acknowledge speaker damage detected, */\ + { 0x93e0, "cf_ack_calibrate_ready"}, /* Firmware event acknowledge calibration completed , */\ + { 0x93f0, "cf_ack_reserved"}, /* Firmware event acknowledge reserved , */\ + { 0x980f, "ivt_addr0_msb"}, /* Coolflux interrupt vector table address0 MSB , */\ + { 0x990f, "ivt_addr0_lsb"}, /* Coolflux interrupt vector table address0 LSB , */\ + { 0x9a0f, "ivt_addr1_msb"}, /* Coolflux interrupt vector table address1 MSB , */\ + { 0x9b0f, "ivt_addr1_lsb"}, /* Coolflux interrupt vector table address1 LSB , */\ + { 0x9c0f, "ivt_addr2_msb"}, /* Coolflux interrupt vector table address2 MSB , */\ + { 0x9d0f, "ivt_addr2_lsb"}, /* Coolflux interrupt vector table address2 LSB , */\ + { 0x9e0f, "ivt_addr3_msb"}, /* Coolflux interrupt vector table address3 MSB , */\ + { 0x9f0f, "ivt_addr3_lsb"}, /* Coolflux interrupt vector table address3 LSB , */\ + { 0xa007, "mtpkey1"}, /* 5Ah, 90d To access KEY1_Protected registers (Default for engineering), */\ + { 0xa107, "mtpkey2"}, /* MTP KEY2 register , */\ + { 0xa200, "key01_locked"}, /* Indicates KEY1 is locked , */\ + { 0xa210, "key02_locked"}, /* Indicates KEY2 is locked , */\ + { 0xa302, "mtp_man_address_in"}, /* MTP address from I2C register for read/writing mtp in manual single word mode, */\ + { 0xa330, "man_copy_mtp_to_iic"}, /* Start copying single word from mtp to I2C mtp register, */\ + { 0xa340, "man_copy_iic_to_mtp"}, /* Start copying single word from I2C mtp register to mtp, */\ + { 0xa350, "auto_copy_mtp_to_iic"}, /* Start copying all the data from mtp to I2C mtp registers, */\ + { 0xa360, "auto_copy_iic_to_mtp"}, /* Start copying data from I2C mtp registers to mtp , */\ + { 0xa400, "faim_set_clkws"}, /* Sets the faim controller clock wait state register, */\ + { 0xa410, "faim_sel_evenrows"}, /* All even rows of the faim are selected, active high, */\ + { 0xa420, "faim_sel_oddrows"}, /* All odd rows of the faim are selected, all rows in combination with sel_evenrows, */\ + { 0xa430, "faim_program_only"}, /* Skip the erase access at wr_faim command (write-program-marginread), */\ + { 0xa440, "faim_erase_only"}, /* Skip the program access at wr_faim command (write-erase-marginread), */\ + { 0xa50f, "mtp_man_data_out_msb"}, /* MSB word of MTP manual read data , */\ + { 0xa60f, "mtp_man_data_out_lsb"}, /* LSB word of MTP manual read data , */\ + { 0xa70f, "mtp_man_data_in_msb"}, /* MSB word of write data for MTP manual write , */\ + { 0xa80f, "mtp_man_data_in_lsb"}, /* LSB word of write data for MTP manual write , */\ + { 0xb010, "bypass_ocpcounter"}, /* Bypass OCP Counter , */\ + { 0xb020, "bypass_glitchfilter"}, /* Bypass glitch filter , */\ + { 0xb030, "bypass_ovp"}, /* Bypass OVP , */\ + { 0xb040, "bypass_uvp"}, /* Bypass UVP , */\ + { 0xb050, "bypass_otp"}, /* Bypass OTP , */\ + { 0xb060, "bypass_lost_clk"}, /* Bypass lost clock detector , */\ + { 0xb070, "ctrl_vpalarm"}, /* vpalarm (uvp ovp handling) , */\ + { 0xb087, "ocp_threshold"}, /* OCP threshold level , */\ + { 0xb108, "ext_temp"}, /* External temperature (C) , */\ + { 0xb190, "ext_temp_sel"}, /* Select temp Speaker calibration , */\ + { 0xc000, "use_direct_ctrls"}, /* Direct control to overrule several functions for testing, */\ + { 0xc010, "rst_datapath"}, /* Direct control for datapath reset , */\ + { 0xc020, "rst_cgu"}, /* Direct control for cgu reset , */\ + { 0xc038, "enbl_ref"}, /* Switch on the analog references, each part of the references can be switched on/off individually, */\ + { 0xc0d0, "enbl_ringo"}, /* Enable the ring oscillator for test purpose , */\ + { 0xc0e0, "use_direct_clk_ctrl"}, /* Direct clock control to overrule several functions for testing, */\ + { 0xc0f0, "use_direct_pll_ctrl"}, /* Direct PLL control to overrule several functions for testing, */\ + { 0xc100, "enbl_tsense"}, /* Temperature sensor enable control - I2C direct mode, */\ + { 0xc110, "tsense_hibias"}, /* Bit to set the biasing in temp sensor to high , */\ + { 0xc120, "enbl_flag_vbg"}, /* Enable flagging of bandgap out of control , */\ + { 0xc20f, "abist_offset"}, /* Offset control for ABIST testing (two's complement), */\ + { 0xc300, "bypasslatch"}, /* Bypass latch , */\ + { 0xc311, "sourcea"}, /* Set OUTA to , */\ + { 0xc331, "sourceb"}, /* Set OUTB to , */\ + { 0xc350, "inverta"}, /* Invert pwma test signal , */\ + { 0xc360, "invertb"}, /* Invert pwmb test signal , */\ + { 0xc374, "pulselength"}, /* Pulse length setting test input for amplifier (clock d - k*2048*fs), */\ + { 0xc3c0, "tdm_enable_loopback"}, /* TDM loopback test , */\ + { 0xc3d0, "test_abistfft_enbl"}, /* FFT Coolflux , */\ + { 0xc3e0, "test_pwr_switch"}, /* Test mode for digital power switches core sw/mem sw/micvdd sw, */\ + { 0xc400, "bst_bypasslatch"}, /* Bypass latch in boost converter , */\ + { 0xc411, "bst_source"}, /* Sets the source of the pwmbst output to boost converter input for testing, */\ + { 0xc430, "bst_invertb"}, /* Invert pwmbst test signal , */\ + { 0xc444, "bst_pulselength"}, /* Pulse length setting test input for boost converter , */\ + { 0xc490, "test_bst_ctrlsthv"}, /* Test mode for boost control stage , */\ + { 0xc4a0, "test_bst_iddq"}, /* IDDQ testing in power stage of boost converter , */\ + { 0xc4b0, "test_bst_rdson"}, /* RDSON testing - boost power stage , */\ + { 0xc4c0, "test_bst_cvi"}, /* CVI testing - boost power stage , */\ + { 0xc4d0, "test_bst_ocp"}, /* Boost OCP. For old ocp (ctrl_reversebst is 0), For new ocp (ctrl_reversebst is 1), */\ + { 0xc4e0, "test_bst_sense"}, /* Test option for the sense NMOS in booster for current mode control., */\ + { 0xc500, "test_cvi"}, /* Analog BIST, switch choose which transistor will be used as current source (also cross coupled sources possible), */\ + { 0xc510, "test_discrete"}, /* Test function noise measurement , */\ + { 0xc520, "test_iddq"}, /* Set the power stages in iddq mode for gate stress., */\ + { 0xc540, "test_rdson"}, /* Analog BIST, switch to enable Rdson measurement , */\ + { 0xc550, "test_sdelta"}, /* Analog BIST, noise test , */\ + { 0xc570, "test_enbl_cs"}, /* Enable for digimux mode of current sense , */\ + { 0xc600, "enbl_pwm_dcc"}, /* Enables direct control of pwm duty cycle for DCDC power stage, */\ + { 0xc613, "pwm_dcc_cnt"}, /* Control pwm duty cycle when enbl_pwm_dcc is 1 , */\ + { 0xc650, "enbl_ldo_stress"}, /* Enable stress of internal supply voltages powerstages, */\ + { 0xc660, "bypass_diosw_ovp"}, /* Bypass ovp for memory switch diosw , */\ + { 0xc670, "enbl_powerswitch"}, /* Vddd core power switch control - overrules the manager control, */\ + { 0xc707, "digimuxa_sel"}, /* DigimuxA input selection control routed to GPIO1 (see Digimux list for details), */\ + { 0xc787, "digimuxb_sel"}, /* DigimuxB input selection control routed to GPIO2 (see Digimux list for details), */\ + { 0xc807, "digimuxc_sel"}, /* DigimuxC input selection control routed to GPIO3 (see Digimux list for details), */\ + { 0xc887, "digimuxd_sel"}, /* DigimuxD input selection control routed to GPIO4 (see Digimux list for details), */\ + { 0xc901, "dio1_ehs"}, /* Speed/load setting for DIO1 IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ + { 0xc921, "dio2_ehs"}, /* Speed/load setting for DIO2 IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ + { 0xc941, "gainio_ehs"}, /* Speed/load setting for GAINIO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ + { 0xc961, "pdmo_ehs"}, /* Speed/load setting for PDMO IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ + { 0xc981, "int_ehs"}, /* Speed/load setting for INT IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ + { 0xc9a1, "tdo_ehs"}, /* Speed/load setting for TDO IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ + { 0xc9c0, "hs_mode"}, /* I2C high speed mode control , */\ + { 0xca00, "enbl_anamux1"}, /* Enable anamux1 , */\ + { 0xca10, "enbl_anamux2"}, /* Enable anamux2 , */\ + { 0xca20, "enbl_anamux3"}, /* Enable anamux3 , */\ + { 0xca30, "enbl_anamux4"}, /* Enable anamux4 , */\ + { 0xca40, "enbl_anamux5"}, /* Enable anamux5 , */\ + { 0xca50, "enbl_anamux6"}, /* Enable anamux6 , */\ + { 0xca60, "enbl_anamux7"}, /* Enable anamux7 , */\ + { 0xca74, "anamux1"}, /* Anamux selection control - anamux on TEST1 , */\ + { 0xcb04, "anamux2"}, /* Anamux selection control - anamux on TEST2 , */\ + { 0xcb54, "anamux3"}, /* Anamux selection control - anamux on TEST3 , */\ + { 0xcba4, "anamux4"}, /* Anamux selection control - anamux on TEST4 , */\ + { 0xcc04, "anamux5"}, /* Anamux selection control - anamux on TEST5 , */\ + { 0xcc54, "anamux6"}, /* Anamux selection control - anamux on TEST6 , */\ + { 0xcca4, "anamux7"}, /* Anamux selection control - anamux on TEST7 , */\ + { 0xcd05, "pll_seli"}, /* PLL SELI - I2C direct PLL control mode only , */\ + { 0xcd64, "pll_selp"}, /* PLL SELP - I2C direct PLL control mode only , */\ + { 0xcdb3, "pll_selr"}, /* PLL SELR - I2C direct PLL control mode only , */\ + { 0xcdf0, "pll_frm"}, /* PLL free running mode control; 1 in TCB direct control mode, else this control bit, */\ + { 0xce09, "pll_ndec"}, /* PLL NDEC - I2C direct PLL control mode only , */\ + { 0xcea0, "pll_mdec_msb"}, /* MSB of pll_mdec - I2C direct PLL control mode only, */\ + { 0xceb0, "enbl_pll"}, /* Enables PLL in I2C direct PLL control mode only , */\ + { 0xcec0, "enbl_osc"}, /* Enables OSC1M in I2C direct control mode only , */\ + { 0xced0, "pll_bypass"}, /* PLL bypass control in I2C direct PLL control mode only, */\ + { 0xcee0, "pll_directi"}, /* PLL directi control in I2C direct PLL control mode only, */\ + { 0xcef0, "pll_directo"}, /* PLL directo control in I2C direct PLL control mode only, */\ + { 0xcf0f, "pll_mdec_lsb"}, /* Bits 15..0 of PLL MDEC are I2C direct PLL control mode only, */\ + { 0xd006, "pll_pdec"}, /* PLL PDEC - I2C direct PLL control mode only , */\ + { 0xd10f, "tsig_freq_lsb"}, /* Internal sinus test generator frequency control , */\ + { 0xd202, "tsig_freq_msb"}, /* Select internal sinus test generator, frequency control msb bits, */\ + { 0xd230, "inject_tsig"}, /* Control bit to switch to internal sinus test generator, */\ + { 0xd243, "tsig_gain_left"}, /* Test signal gain for left channel , */\ + { 0xd283, "tsig_gain_right"}, /* Test signal gain for right channel , */\ + { 0xd300, "adc10_reset"}, /* Reset for ADC10 - I2C direct control mode , */\ + { 0xd311, "adc10_test"}, /* Test mode selection signal for ADC10 - I2C direct control mode, */\ + { 0xd332, "adc10_sel"}, /* Select the input to convert for ADC10 - I2C direct control mode, */\ + { 0xd364, "adc10_prog_sample"}, /* ADC10 program sample setting - I2C direct control mode, */\ + { 0xd3b0, "adc10_enbl"}, /* Enable ADC10 - I2C direct control mode , */\ + { 0xd3c0, "bypass_lp_vbat"}, /* Bypass control for Low pass filter in batt sensor , */\ + { 0xd409, "data_adc10_tempbat"}, /* ADC 10 data output data for testing , */\ + { 0xd506, "ctrl_digtoana_hidden"}, /* Spare digital to analog control bits - Hidden , */\ + { 0xd570, "enbl_clk_out_of_range"}, /* Clock out of range , */\ + { 0xf000, "calibration_onetime"}, /* Calibration schedule , */\ + { 0xf010, "calibr_ron_done"}, /* Calibration Ron executed , */\ + { 0xf020, "calibr_dcdc_api_calibrate"}, /* Calibration current limit DCDC , */\ + { 0xf030, "calibr_dcdc_delta_sign"}, /* Sign bit for delta calibration current limit DCDC , */\ + { 0xf042, "calibr_dcdc_delta"}, /* Calibration delta current limit DCDC , */\ + { 0xf078, "calibr_speaker_info"}, /* Reserved space for allowing customer to store speaker information, */\ + { 0xf105, "calibr_vout_offset"}, /* DCDC offset calibration 2's complement (key1 protected), */\ + { 0xf163, "calibr_gain_left"}, /* HW gain module - left channel (2's complement) , */\ + { 0xf1a5, "calibr_offset_left"}, /* Offset for amplifier, HW gain module - left channel (2's complement), */\ + { 0xf203, "calibr_gain_right"}, /* HW gain module - right channel (2's complement) , */\ + { 0xf245, "calibr_offset_right"}, /* Offset for amplifier, HW gain module - right channel (2's complement), */\ + { 0xf2a3, "calibr_rcvldop_trim"}, /* Trimming of LDO (2.7V) , */\ + { 0xf307, "calibr_gain_cs_left"}, /* Current sense gain - left channel (signed two's complement format), */\ + { 0xf387, "calibr_gain_cs_right"}, /* Current sense gain - right channel (signed two's complement format), */\ + { 0xf40f, "calibr_R25C_L"}, /* Ron resistance of left channel speaker coil , */\ + { 0xf50f, "calibr_R25C_R"}, /* Ron resistance of right channel speaker coil , */\ + { 0xf606, "ctrl_offset_a_left"}, /* Offset of left amplifier level shifter A , */\ + { 0xf686, "ctrl_offset_b_left"}, /* Offset of left amplifier level shifter B , */\ + { 0xf706, "ctrl_offset_a_right"}, /* Offset of right amplifier level shifter A , */\ + { 0xf786, "ctrl_offset_b_right"}, /* Offset of right amplifier level shifter B , */\ + { 0xf806, "htol_iic_addr"}, /* 7-bit I2C address to be used during HTOL testing , */\ + { 0xf870, "htol_iic_addr_en"}, /* HTOL I2C address enable control , */\ + { 0xf884, "calibr_temp_offset"}, /* Temperature offset 2's compliment (key1 protected), */\ + { 0xf8d2, "calibr_temp_gain"}, /* Temperature gain 2's compliment (key1 protected) , */\ + { 0xf900, "mtp_lock_dcdcoff_mode"}, /* Disable function dcdcoff_mode , */\ + { 0xf910, "mtp_lock_enbl_coolflux"}, /* Disable function enbl_coolflux , */\ + { 0xf920, "mtp_lock_bypass_clipper"}, /* Disable function bypass_clipper , */\ + { 0xf930, "mtp_lock_max_dcdc_voltage"}, /* Disable programming of max dcdc boost voltage , */\ + { 0xf943, "calibr_vbg_trim"}, /* Bandgap trimming control , */\ + { 0xf987, "type_bits_fw"}, /* MTP-control FW - See Firmware I2C API document for details, */\ + { 0xfa0f, "mtpdataA"}, /* MTPdataA (key1 protected) , */\ + { 0xfb0f, "mtpdataB"}, /* MTPdataB (key1 protected) , */\ + { 0xfc0f, "mtpdataC"}, /* MTPdataC (key1 protected) , */\ + { 0xfd0f, "mtpdataD"}, /* MTPdataD (key1 protected) , */\ + { 0xfe0f, "mtpdataE"}, /* MTPdataE (key1 protected) , */\ + { 0xff05, "calibr_osc_delta_ndiv"}, /* Calibration data for OSC1M, signed number representation, */\ + { 0xffff,"Unknown bitfield enum" } /* not found */\ +}; + +enum tfa2_irq { + tfa2_irq_stvdds = 0, + tfa2_irq_stplls = 1, + tfa2_irq_stotds = 2, + tfa2_irq_stovds = 3, + tfa2_irq_stuvds = 4, + tfa2_irq_stclks = 5, + tfa2_irq_stmtpb = 6, + tfa2_irq_stnoclk = 7, + tfa2_irq_stspks = 8, + tfa2_irq_stacs = 9, + tfa2_irq_stsws = 10, + tfa2_irq_stwds = 11, + tfa2_irq_stamps = 12, + tfa2_irq_starefs = 13, + tfa2_irq_stadccr = 14, + tfa2_irq_stbodnok = 15, + tfa2_irq_stbstcu = 16, + tfa2_irq_stbsthi = 17, + tfa2_irq_stbstoc = 18, + tfa2_irq_stbstpkcur = 19, + tfa2_irq_stbstvc = 20, + tfa2_irq_stbst86 = 21, + tfa2_irq_stbst93 = 22, + tfa2_irq_strcvld = 23, + tfa2_irq_stocpl = 24, + tfa2_irq_stocpr = 25, + tfa2_irq_stmwsrc = 26, + tfa2_irq_stmwcfc = 27, + tfa2_irq_stmwsmu = 28, + tfa2_irq_stcfmer = 29, + tfa2_irq_stcfmac = 30, + tfa2_irq_stclkoor = 31, + tfa2_irq_sttdmer = 32, + tfa2_irq_stclpl = 33, + tfa2_irq_stclpr = 34, + tfa2_irq_stocpm = 35, + tfa2_irq_max = 36, + tfa2_irq_all = -1 /* all irqs */}; + +#define TFA2_IRQ_NAMETABLE static tfaIrqName_t Tfa2IrqNames[]= {\ + { 0, "STVDDS"},\ + { 1, "STPLLS"},\ + { 2, "STOTDS"},\ + { 3, "STOVDS"},\ + { 4, "STUVDS"},\ + { 5, "STCLKS"},\ + { 6, "STMTPB"},\ + { 7, "STNOCLK"},\ + { 8, "STSPKS"},\ + { 9, "STACS"},\ + { 10, "STSWS"},\ + { 11, "STWDS"},\ + { 12, "STAMPS"},\ + { 13, "STAREFS"},\ + { 14, "STADCCR"},\ + { 15, "STBODNOK"},\ + { 16, "STBSTCU"},\ + { 17, "STBSTHI"},\ + { 18, "STBSTOC"},\ + { 19, "STBSTPKCUR"},\ + { 20, "STBSTVC"},\ + { 21, "STBST86"},\ + { 22, "STBST93"},\ + { 23, "STRCVLD"},\ + { 24, "STOCPL"},\ + { 25, "STOCPR"},\ + { 26, "STMWSRC"},\ + { 27, "STMWCFC"},\ + { 28, "STMWSMU"},\ + { 29, "STCFMER"},\ + { 30, "STCFMAC"},\ + { 31, "STCLKOOR"},\ + { 32, "STTDMER"},\ + { 33, "STCLPL"},\ + { 34, "STCLPR"},\ + { 35, "STOCPM"},\ + { 36, "36"},\ +}; diff --git a/techpack/audio/asoc/codecs/tfa9874/tfa9872_device_genregs_POR.h b/techpack/audio/asoc/codecs/tfa9874/tfa9872_device_genregs_POR.h new file mode 100644 index 000000000000..df35f57996c1 --- /dev/null +++ b/techpack/audio/asoc/codecs/tfa9874/tfa9872_device_genregs_POR.h @@ -0,0 +1,121 @@ +/** Filename: Tfa98xx_device_genregs.h + * This file was generated automatically on 08/11/16 at 07:44:41. + * Source file: TFA9872N1B2_DefaultI2CSettings - V1.xlsx + */ + +#ifndef _TFA9872_DEVICE_GENREGS_H +#define _TFA9872_DEVICE_GENREGS_H + + +#define TFA9872_SYS_CONTROL0 0x00 +#define TFA9872_SYS_CONTROL1 0x01 +#define TFA9872_SYS_CONTROL2 0x02 +#define TFA9872_DEVICE_REVISION 0x03 +#define TFA9872_CLOCK_CONTROL 0x04 +#define TFA9872_CLOCK_GATING_CONTROL 0x05 +#define TFA9872_SIDE_TONE_CONFIG 0x0d +#define TFA9872_STATUS_FLAGS0 0x10 +#define TFA9872_STATUS_FLAGS1 0x11 +#define TFA9872_STATUS_FLAGS3 0x13 +#define TFA9872_STATUS_FLAGS4 0x14 +#define TFA9872_BATTERY_VOLTAGE 0x15 +#define TFA9872_TEMPERATURE 0x16 +#define TFA9872_VDDP_VOLTAGE 0x17 +#define TFA9872_TDM_CONFIG0 0x20 +#define TFA9872_TDM_CONFIG1 0x21 +#define TFA9872_TDM_CONFIG2 0x22 +#define TFA9872_TDM_CONFIG3 0x23 +#define TFA9872_TDM_CONFIG6 0x26 +#define TFA9872_TDM_CONFIG7 0x27 +#define TFA9872_PDM_CONFIG0 0x31 +#define TFA9872_INTERRUPT_OUT_REG1 0x40 +#define TFA9872_INTERRUPT_OUT_REG2 0x41 +#define TFA9872_INTERRUPT_OUT_REG3 0x42 +#define TFA9872_INTERRUPT_IN_REG1 0x44 +#define TFA9872_INTERRUPT_IN_REG2 0x45 +#define TFA9872_INTERRUPT_IN_REG3 0x46 +#define TFA9872_INTERRUPT_ENABLE_REG1 0x48 +#define TFA9872_INTERRUPT_ENABLE_REG2 0x49 +#define TFA9872_INTERRUPT_ENABLE_REG3 0x4a +#define TFA9872_STATUS_POLARITY_REG1 0x4c +#define TFA9872_STATUS_POLARITY_REG2 0x4d +#define TFA9872_STATUS_POLARITY_REG3 0x4e +#define TFA9872_BAT_PROT_CONFIG 0x50 +#define TFA9872_AUDIO_CONTROL 0x51 +#define TFA9872_AMPLIFIER_CONFIG 0x52 +#define TFA9872_PGA_CONTROL0 0x60 +#define TFA9872_GAIN_ATT 0x61 +#define TFA9872_TDM_SOURCE_CTRL 0x68 +#define TFA9872_SAM_CTRL 0x69 +#define TFA9872_STATUS_FLAGS5 0x6e +#define TFA9872_CURSENSE_COMP 0x6f +#define TFA9872_DCDC_CONTROL0 0x70 +#define TFA9872_DCDC_CONTROL4 0x74 +#define TFA9872_DCDC_CONTROL5 0x75 +#define TFA9872_MTPKEY2_REG 0xa1 +#define TFA9872_MTP_STATUS 0xa2 +#define TFA9872_KEY_PROTECTED_MTP_CONTROL 0xa3 +#define TFA9872_MTP_DATA_OUT_MSB 0xa5 +#define TFA9872_MTP_DATA_OUT_LSB 0xa6 +#define TFA9872_TEMP_SENSOR_CONFIG 0xb1 +#define TFA9872_SOFTWARE_PROFILE 0xee +#define TFA9872_SOFTWARE_VSTEP 0xef +#define TFA9872_KEY2_PROTECTED_MTP0 0xf0 +#define TFA9872_KEY2_PROTECTED_MTP5 0xf5 +#define TFA9872_SYS_CONTROL0_POR 0x0001 +#define TFA9872_SYS_CONTROL1_POR 0x0000 +#define TFA9872_SYS_CONTROL2_POR 0x2828 +#define TFA9872_DEVICE_REVISION_POR 0x3b72 +#define TFA9872_CLOCK_CONTROL_POR 0x0000 +#define TFA9872_CLOCK_GATING_CONTROL_POR 0x1f6a +#define TFA9872_SIDE_TONE_CONFIG_POR 0x0ebe +#define TFA9872_STATUS_FLAGS0_POR 0x001d +#define TFA9872_STATUS_FLAGS1_POR 0x0004 +#define TFA9872_STATUS_FLAGS3_POR 0x000f +#define TFA9872_STATUS_FLAGS4_POR 0x0000 +#define TFA9872_BATTERY_VOLTAGE_POR 0x03ff +#define TFA9872_TEMPERATURE_POR 0x0100 +#define TFA9872_VDDP_VOLTAGE_POR 0x0000 +#define TFA9872_TDM_CONFIG0_POR 0x2890 +#define TFA9872_TDM_CONFIG1_POR 0xc1f1 +#define TFA9872_TDM_CONFIG2_POR 0x045c +#define TFA9872_TDM_CONFIG3_POR 0x0003 +#define TFA9872_TDM_CONFIG6_POR 0x0010 +#define TFA9872_TDM_CONFIG7_POR 0x0001 +#define TFA9872_PDM_CONFIG0_POR 0x0000 +#define TFA9872_INTERRUPT_OUT_REG1_POR 0x0081 +#define TFA9872_INTERRUPT_OUT_REG2_POR 0x0000 +#define TFA9872_INTERRUPT_OUT_REG3_POR 0x0000 +#define TFA9872_INTERRUPT_IN_REG1_POR 0x0000 +#define TFA9872_INTERRUPT_IN_REG2_POR 0x0000 +#define TFA9872_INTERRUPT_IN_REG3_POR 0x0000 +#define TFA9872_INTERRUPT_ENABLE_REG1_POR 0x0001 +#define TFA9872_INTERRUPT_ENABLE_REG2_POR 0x0000 +#define TFA9872_INTERRUPT_ENABLE_REG3_POR 0x0000 +#define TFA9872_STATUS_POLARITY_REG1_POR 0x74e3 +#define TFA9872_STATUS_POLARITY_REG2_POR 0x967b +#define TFA9872_STATUS_POLARITY_REG3_POR 0x0085 +#define TFA9872_BAT_PROT_CONFIG_POR 0x8091 +#define TFA9872_AUDIO_CONTROL_POR 0x0080 +#define TFA9872_AMPLIFIER_CONFIG_POR 0x7a08 +#define TFA9872_PGA_CONTROL0_POR 0x0000 +#define TFA9872_GAIN_ATT_POR 0x0000 +#define TFA9872_TDM_SOURCE_CTRL_POR 0x0400 +#define TFA9872_SAM_CTRL_POR 0x0000 +#define TFA9872_STATUS_FLAGS5_POR 0x0007 +#define TFA9872_CURSENSE_COMP_POR 0x02e4 +#define TFA9872_DCDC_CONTROL0_POR 0x06e6 +#define TFA9872_DCDC_CONTROL4_POR 0xd913 +#define TFA9872_DCDC_CONTROL5_POR 0x118a +#define TFA9872_MTPKEY2_REG_POR 0x0000 +#define TFA9872_MTP_STATUS_POR 0x0003 +#define TFA9872_KEY_PROTECTED_MTP_CONTROL_POR 0x0000 +#define TFA9872_MTP_DATA_OUT_MSB_POR 0x0000 +#define TFA9872_MTP_DATA_OUT_LSB_POR 0x0000 +#define TFA9872_TEMP_SENSOR_CONFIG_POR 0x0000 +#define TFA9872_SOFTWARE_PROFILE_POR 0x0000 +#define TFA9872_SOFTWARE_VSTEP_POR 0x0000 +#define TFA9872_KEY2_PROTECTED_MTP0_POR 0x0000 +#define TFA9872_KEY2_PROTECTED_MTP5_POR 0x0000 + +#endif /* _TFA9872_DEVICE_GENREGS_H */ diff --git a/techpack/audio/asoc/codecs/tfa9874/tfa9872_tfafieldnames.h b/techpack/audio/asoc/codecs/tfa9874/tfa9872_tfafieldnames.h new file mode 100644 index 000000000000..23669d4c0011 --- /dev/null +++ b/techpack/audio/asoc/codecs/tfa9874/tfa9872_tfafieldnames.h @@ -0,0 +1,1219 @@ +/** Filename: Tfa9872_TfaFieldnames.h + * This file was generated automatically on 10/11/16 at 10:19:27. + * Source file: TFA9872N1B2_DefaultI2CSettings -v16.xlsx + */ + +#ifndef _TFA9872_TFAFIELDNAMES_H +#define _TFA9872_TFAFIELDNAMES_H + + +#define TFA9872_I2CVERSION_N1A 26 +#define TFA9872_I2CVERSION_N1B 29 +#define TFA9872_I2CVERSION_N1B2 21 + + +typedef enum nxpTfa9872BfEnumList { + TFA9872_BF_PWDN = 0x0000, /*!< Powerdown selection */ + TFA9872_BF_I2CR = 0x0010, /*!< I2C Reset - Auto clear */ + TFA9872_BF_AMPE = 0x0030, /*!< Activate Amplifier */ + TFA9872_BF_DCA = 0x0040, /*!< Activate DC-to-DC converter */ + TFA9872_BF_INTP = 0x0071, /*!< Interrupt config */ + TFA9872_BF_BYPOCP= 0x00b0, /*!< Bypass OCP */ + TFA9872_BF_TSTOCP= 0x00c0, /*!< OCP testing control */ + TFA9872_BF_MANSCONF= 0x0120, /*!< I2C configured */ + TFA9872_BF_MANAOOSC= 0x0140, /*!< Internal osc off at PWDN */ + TFA9872_BF_MUTETO= 0x01d0, /*!< Time out SB mute sequence */ + TFA9872_BF_RCVNS = 0x01e0, /*!< Noise shaper selection */ + TFA9872_BF_AUDFS = 0x0203, /*!< Sample rate (fs) */ + TFA9872_BF_INPLEV= 0x0240, /*!< TDM output attenuation */ + TFA9872_BF_FRACTDEL= 0x0255, /*!< V/I Fractional delay */ + TFA9872_BF_BYPHVBF= 0x02b0, /*!< Bypass HVBAT filter */ + TFA9872_BF_REV = 0x030f, /*!< Revision info */ + TFA9872_BF_REFCKEXT= 0x0401, /*!< PLL external ref clock */ + TFA9872_BF_REFCKSEL= 0x0420, /*!< PLL internal ref clock */ + TFA9872_BF_SSE = 0x0510, /*!< Enable speaker path */ + TFA9872_BF_VSE = 0x0530, /*!< Voltage sense */ + TFA9872_BF_CSE = 0x0550, /*!< Current sense */ + TFA9872_BF_SSPDME= 0x0560, /*!< Sub-system PDM */ + TFA9872_BF_PGAE = 0x0580, /*!< Enable PGA chop clock */ + TFA9872_BF_SSTDME= 0x0590, /*!< Sub-system TDM */ + TFA9872_BF_SSPBSTE= 0x05a0, /*!< Sub-system boost */ + TFA9872_BF_SSADCE= 0x05b0, /*!< Sub-system ADC */ + TFA9872_BF_SSFAIME= 0x05c0, /*!< Sub-system FAIM */ + TFA9872_BF_STGAIN= 0x0d18, /*!< Side tone gain */ + TFA9872_BF_STSMUTE= 0x0da0, /*!< Side tone soft mute */ + TFA9872_BF_ST1C = 0x0db0, /*!< side tone one s complement */ + TFA9872_BF_VDDS = 0x1000, /*!< POR */ + TFA9872_BF_PLLS = 0x1010, /*!< PLL lock */ + TFA9872_BF_OTDS = 0x1020, /*!< OTP alarm */ + TFA9872_BF_OVDS = 0x1030, /*!< OVP alarm */ + TFA9872_BF_UVDS = 0x1040, /*!< UVP alarm */ + TFA9872_BF_CLKS = 0x1050, /*!< Clocks stable */ + TFA9872_BF_MTPB = 0x1060, /*!< MTP busy */ + TFA9872_BF_NOCLK = 0x1070, /*!< Lost clock */ + TFA9872_BF_SWS = 0x10a0, /*!< Amplifier engage */ + TFA9872_BF_AMPS = 0x10c0, /*!< Amplifier enable */ + TFA9872_BF_AREFS = 0x10d0, /*!< References enable */ + TFA9872_BF_ADCCR = 0x10e0, /*!< Control ADC */ + TFA9872_BF_DCIL = 0x1100, /*!< DCDC current limiting */ + TFA9872_BF_DCDCA = 0x1110, /*!< DCDC active */ + TFA9872_BF_DCOCPOK= 0x1120, /*!< DCDC OCP nmos */ + TFA9872_BF_DCHVBAT= 0x1140, /*!< DCDC level 1x */ + TFA9872_BF_DCH114= 0x1150, /*!< DCDC level 1.14x */ + TFA9872_BF_DCH107= 0x1160, /*!< DCDC level 1.07x */ + TFA9872_BF_STMUTEB= 0x1170, /*!< side tone (un)mute busy */ + TFA9872_BF_STMUTE= 0x1180, /*!< side tone mute state */ + TFA9872_BF_TDMLUTER= 0x1190, /*!< TDM LUT error */ + TFA9872_BF_TDMSTAT= 0x11a2, /*!< TDM status bits */ + TFA9872_BF_TDMERR= 0x11d0, /*!< TDM error */ + TFA9872_BF_OCPOAP= 0x1300, /*!< OCPOK pmos A */ + TFA9872_BF_OCPOAN= 0x1310, /*!< OCPOK nmos A */ + TFA9872_BF_OCPOBP= 0x1320, /*!< OCPOK pmos B */ + TFA9872_BF_OCPOBN= 0x1330, /*!< OCPOK nmos B */ + TFA9872_BF_CLIPAH= 0x1340, /*!< Clipping A to Vddp */ + TFA9872_BF_CLIPAL= 0x1350, /*!< Clipping A to gnd */ + TFA9872_BF_CLIPBH= 0x1360, /*!< Clipping B to Vddp */ + TFA9872_BF_CLIPBL= 0x1370, /*!< Clipping B to gnd */ + TFA9872_BF_OCDS = 0x1380, /*!< OCP amplifier */ + TFA9872_BF_CLIPS = 0x1390, /*!< Amplifier clipping */ + TFA9872_BF_OCPOKMC= 0x13a0, /*!< OCPOK MICVDD */ + TFA9872_BF_MANALARM= 0x13b0, /*!< Alarm state */ + TFA9872_BF_MANWAIT1= 0x13c0, /*!< Wait HW I2C settings */ + TFA9872_BF_MANMUTE= 0x13e0, /*!< Audio mute sequence */ + TFA9872_BF_MANOPER= 0x13f0, /*!< Operating state */ + TFA9872_BF_CLKOOR= 0x1420, /*!< External clock status */ + TFA9872_BF_MANSTATE= 0x1433, /*!< Device manager status */ + TFA9872_BF_DCMODE= 0x1471, /*!< DCDC mode status bits */ + TFA9872_BF_BATS = 0x1509, /*!< Battery voltage (V) */ + TFA9872_BF_TEMPS = 0x1608, /*!< IC Temperature (C) */ + TFA9872_BF_VDDPS = 0x1709, /*!< IC VDDP voltage ( 1023*VDDP/9.5 V) */ + TFA9872_BF_TDME = 0x2040, /*!< Enable interface */ + TFA9872_BF_TDMMODE= 0x2050, /*!< Slave/master */ + TFA9872_BF_TDMCLINV= 0x2060, /*!< Reception data to BCK clock */ + TFA9872_BF_TDMFSLN= 0x2073, /*!< FS length (master mode only) */ + TFA9872_BF_TDMFSPOL= 0x20b0, /*!< FS polarity */ + TFA9872_BF_TDMNBCK= 0x20c3, /*!< N-BCK's in FS */ + TFA9872_BF_TDMSLOTS= 0x2103, /*!< N-slots in Frame */ + TFA9872_BF_TDMSLLN= 0x2144, /*!< N-bits in slot */ + TFA9872_BF_TDMBRMG= 0x2194, /*!< N-bits remaining */ + TFA9872_BF_TDMDEL= 0x21e0, /*!< data delay to FS */ + TFA9872_BF_TDMADJ= 0x21f0, /*!< data adjustment */ + TFA9872_BF_TDMOOMP= 0x2201, /*!< Received audio compression */ + TFA9872_BF_TDMSSIZE= 0x2224, /*!< Sample size per slot */ + TFA9872_BF_TDMTXDFO= 0x2271, /*!< Format unused bits */ + TFA9872_BF_TDMTXUS0= 0x2291, /*!< Format unused slots DATAO */ + TFA9872_BF_TDMSPKE= 0x2300, /*!< Control audio tdm channel in 0 (spkr + dcdc) */ + TFA9872_BF_TDMDCE= 0x2310, /*!< Control audio tdm channel in 1 (dcdc) */ + TFA9872_BF_TDMCSE= 0x2330, /*!< current sense vbat temperature and vddp feedback */ + TFA9872_BF_TDMVSE= 0x2340, /*!< Voltage sense vbat temperature and vddp feedback */ + TFA9872_BF_TDMSPKS= 0x2603, /*!< tdm slot for sink 0 (speaker + dcdc) */ + TFA9872_BF_TDMDCS= 0x2643, /*!< tdm slot for sink 1 (dcdc) */ + TFA9872_BF_TDMCSS= 0x26c3, /*!< Slot Position of current sense vbat temperature and vddp feedback */ + TFA9872_BF_TDMVSS= 0x2703, /*!< Slot Position of Voltage sense vbat temperature and vddp feedback */ + TFA9872_BF_PDMSTSEL= 0x3111, /*!< Side tone input */ + TFA9872_BF_ISTVDDS= 0x4000, /*!< Status POR */ + TFA9872_BF_ISTPLLS= 0x4010, /*!< Status PLL lock */ + TFA9872_BF_ISTOTDS= 0x4020, /*!< Status OTP alarm */ + TFA9872_BF_ISTOVDS= 0x4030, /*!< Status OVP alarm */ + TFA9872_BF_ISTUVDS= 0x4040, /*!< Status UVP alarm */ + TFA9872_BF_ISTCLKS= 0x4050, /*!< Status clocks stable */ + TFA9872_BF_ISTMTPB= 0x4060, /*!< Status MTP busy */ + TFA9872_BF_ISTNOCLK= 0x4070, /*!< Status lost clock */ + TFA9872_BF_ISTSWS= 0x40a0, /*!< Status amplifier engage */ + TFA9872_BF_ISTAMPS= 0x40c0, /*!< Status amplifier enable */ + TFA9872_BF_ISTAREFS= 0x40d0, /*!< Status Ref enable */ + TFA9872_BF_ISTADCCR= 0x40e0, /*!< Status Control ADC */ + TFA9872_BF_ISTBSTCU= 0x4100, /*!< Status DCDC current limiting */ + TFA9872_BF_ISTBSTHI= 0x4110, /*!< Status DCDC active */ + TFA9872_BF_ISTBSTOC= 0x4120, /*!< Status DCDC OCP */ + TFA9872_BF_ISTBSTPKCUR= 0x4130, /*!< Status bst peakcur */ + TFA9872_BF_ISTBSTVC= 0x4140, /*!< Status DCDC level 1x */ + TFA9872_BF_ISTBST86= 0x4150, /*!< Status DCDC level 1.14x */ + TFA9872_BF_ISTBST93= 0x4160, /*!< Status DCDC level 1.07x */ + TFA9872_BF_ISTOCPR= 0x4190, /*!< Status ocp alarm */ + TFA9872_BF_ISTMWSRC= 0x41a0, /*!< Status Waits HW I2C settings */ + TFA9872_BF_ISTMWSMU= 0x41c0, /*!< Status Audio mute sequence */ + TFA9872_BF_ISTCLKOOR= 0x41f0, /*!< Status flag_clk_out_of_range */ + TFA9872_BF_ISTTDMER= 0x4200, /*!< Status tdm error */ + TFA9872_BF_ISTCLPR= 0x4220, /*!< Status clip */ + TFA9872_BF_ISTLP0= 0x4240, /*!< Status low power mode0 */ + TFA9872_BF_ISTLP1= 0x4250, /*!< Status low power mode1 */ + TFA9872_BF_ISTLA = 0x4260, /*!< Status low noise detection */ + TFA9872_BF_ISTVDDPH= 0x4270, /*!< Status VDDP greater than VBAT */ + TFA9872_BF_ICLVDDS= 0x4400, /*!< Clear POR */ + TFA9872_BF_ICLPLLS= 0x4410, /*!< Clear PLL lock */ + TFA9872_BF_ICLOTDS= 0x4420, /*!< Clear OTP alarm */ + TFA9872_BF_ICLOVDS= 0x4430, /*!< Clear OVP alarm */ + TFA9872_BF_ICLUVDS= 0x4440, /*!< Clear UVP alarm */ + TFA9872_BF_ICLCLKS= 0x4450, /*!< Clear clocks stable */ + TFA9872_BF_ICLMTPB= 0x4460, /*!< Clear mtp busy */ + TFA9872_BF_ICLNOCLK= 0x4470, /*!< Clear lost clk */ + TFA9872_BF_ICLSWS= 0x44a0, /*!< Clear amplifier engage */ + TFA9872_BF_ICLAMPS= 0x44c0, /*!< Clear enbl amp */ + TFA9872_BF_ICLAREFS= 0x44d0, /*!< Clear ref enable */ + TFA9872_BF_ICLADCCR= 0x44e0, /*!< Clear control ADC */ + TFA9872_BF_ICLBSTCU= 0x4500, /*!< Clear DCDC current limiting */ + TFA9872_BF_ICLBSTHI= 0x4510, /*!< Clear DCDC active */ + TFA9872_BF_ICLBSTOC= 0x4520, /*!< Clear DCDC OCP */ + TFA9872_BF_ICLBSTPC= 0x4530, /*!< Clear bst peakcur */ + TFA9872_BF_ICLBSTVC= 0x4540, /*!< Clear DCDC level 1x */ + TFA9872_BF_ICLBST86= 0x4550, /*!< Clear DCDC level 1.14x */ + TFA9872_BF_ICLBST93= 0x4560, /*!< Clear DCDC level 1.07x */ + TFA9872_BF_ICLOCPR= 0x4590, /*!< Clear ocp alarm */ + TFA9872_BF_ICLMWSRC= 0x45a0, /*!< Clear wait HW I2C settings */ + TFA9872_BF_ICLMWSMU= 0x45c0, /*!< Clear audio mute sequence */ + TFA9872_BF_ICLCLKOOR= 0x45f0, /*!< Clear flag_clk_out_of_range */ + TFA9872_BF_ICLTDMER= 0x4600, /*!< Clear tdm error */ + TFA9872_BF_ICLCLPR= 0x4620, /*!< Clear clip */ + TFA9872_BF_ICLLP0= 0x4640, /*!< Clear low power mode0 */ + TFA9872_BF_ICLLP1= 0x4650, /*!< Clear low power mode1 */ + TFA9872_BF_ICLLA = 0x4660, /*!< Clear low noise detection */ + TFA9872_BF_ICLVDDPH= 0x4670, /*!< Clear VDDP greater then VBAT */ + TFA9872_BF_IEVDDS= 0x4800, /*!< Enable por */ + TFA9872_BF_IEPLLS= 0x4810, /*!< Enable pll lock */ + TFA9872_BF_IEOTDS= 0x4820, /*!< Enable OTP alarm */ + TFA9872_BF_IEOVDS= 0x4830, /*!< Enable OVP alarm */ + TFA9872_BF_IEUVDS= 0x4840, /*!< Enable UVP alarm */ + TFA9872_BF_IECLKS= 0x4850, /*!< Enable clocks stable */ + TFA9872_BF_IEMTPB= 0x4860, /*!< Enable mtp busy */ + TFA9872_BF_IENOCLK= 0x4870, /*!< Enable lost clk */ + TFA9872_BF_IESWS = 0x48a0, /*!< Enable amplifier engage */ + TFA9872_BF_IEAMPS= 0x48c0, /*!< Enable enbl amp */ + TFA9872_BF_IEAREFS= 0x48d0, /*!< Enable ref enable */ + TFA9872_BF_IEADCCR= 0x48e0, /*!< Enable Control ADC */ + TFA9872_BF_IEBSTCU= 0x4900, /*!< Enable DCDC current limiting */ + TFA9872_BF_IEBSTHI= 0x4910, /*!< Enable DCDC active */ + TFA9872_BF_IEBSTOC= 0x4920, /*!< Enable DCDC OCP */ + TFA9872_BF_IEBSTPC= 0x4930, /*!< Enable bst peakcur */ + TFA9872_BF_IEBSTVC= 0x4940, /*!< Enable DCDC level 1x */ + TFA9872_BF_IEBST86= 0x4950, /*!< Enable DCDC level 1.14x */ + TFA9872_BF_IEBST93= 0x4960, /*!< Enable DCDC level 1.07x */ + TFA9872_BF_IEOCPR= 0x4990, /*!< Enable ocp alarm */ + TFA9872_BF_IEMWSRC= 0x49a0, /*!< Enable waits HW I2C settings */ + TFA9872_BF_IEMWSMU= 0x49c0, /*!< Enable man Audio mute sequence */ + TFA9872_BF_IECLKOOR= 0x49f0, /*!< Enable flag_clk_out_of_range */ + TFA9872_BF_IETDMER= 0x4a00, /*!< Enable tdm error */ + TFA9872_BF_IECLPR= 0x4a20, /*!< Enable clip */ + TFA9872_BF_IELP0 = 0x4a40, /*!< Enable low power mode0 */ + TFA9872_BF_IELP1 = 0x4a50, /*!< Enable low power mode1 */ + TFA9872_BF_IELA = 0x4a60, /*!< Enable low noise detection */ + TFA9872_BF_IEVDDPH= 0x4a70, /*!< Enable VDDP greater tehn VBAT */ + TFA9872_BF_IPOVDDS= 0x4c00, /*!< Polarity por */ + TFA9872_BF_IPOPLLS= 0x4c10, /*!< Polarity pll lock */ + TFA9872_BF_IPOOTDS= 0x4c20, /*!< Polarity OTP alarm */ + TFA9872_BF_IPOOVDS= 0x4c30, /*!< Polarity OVP alarm */ + TFA9872_BF_IPOUVDS= 0x4c40, /*!< Polarity UVP alarm */ + TFA9872_BF_IPOCLKS= 0x4c50, /*!< Polarity clocks stable */ + TFA9872_BF_IPOMTPB= 0x4c60, /*!< Polarity mtp busy */ + TFA9872_BF_IPONOCLK= 0x4c70, /*!< Polarity lost clk */ + TFA9872_BF_IPOSWS= 0x4ca0, /*!< Polarity amplifier engage */ + TFA9872_BF_IPOAMPS= 0x4cc0, /*!< Polarity enbl amp */ + TFA9872_BF_IPOAREFS= 0x4cd0, /*!< Polarity ref enable */ + TFA9872_BF_IPOADCCR= 0x4ce0, /*!< Polarity Control ADC */ + TFA9872_BF_IPOBSTCU= 0x4d00, /*!< Polarity DCDC current limiting */ + TFA9872_BF_IPOBSTHI= 0x4d10, /*!< Polarity DCDC active */ + TFA9872_BF_IPOBSTOC= 0x4d20, /*!< Polarity DCDC OCP */ + TFA9872_BF_IPOBSTPC= 0x4d30, /*!< Polarity bst peakcur */ + TFA9872_BF_IPOBSTVC= 0x4d40, /*!< Polarity DCDC level 1x */ + TFA9872_BF_IPOBST86= 0x4d50, /*!< Polarity DCDC level 1.14x */ + TFA9872_BF_IPOBST93= 0x4d60, /*!< Polarity DCDC level 1.07x */ + TFA9872_BF_IPOOCPR= 0x4d90, /*!< Polarity ocp alarm */ + TFA9872_BF_IPOMWSRC= 0x4da0, /*!< Polarity waits HW I2C settings */ + TFA9872_BF_IPOMWSMU= 0x4dc0, /*!< Polarity man audio mute sequence */ + TFA9872_BF_IPCLKOOR= 0x4df0, /*!< Polarity flag_clk_out_of_range */ + TFA9872_BF_IPOTDMER= 0x4e00, /*!< Polarity tdm error */ + TFA9872_BF_IPOCLPR= 0x4e20, /*!< Polarity clip right */ + TFA9872_BF_IPOLP0= 0x4e40, /*!< Polarity low power mode0 */ + TFA9872_BF_IPOLP1= 0x4e50, /*!< Polarity low power mode1 */ + TFA9872_BF_IPOLA = 0x4e60, /*!< Polarity low noise mode */ + TFA9872_BF_IPOVDDPH= 0x4e70, /*!< Polarity VDDP greater than VBAT */ + TFA9872_BF_BSSCR = 0x5001, /*!< Battery Safeguard attack time */ + TFA9872_BF_BSST = 0x5023, /*!< Battery Safeguard threshold voltage level */ + TFA9872_BF_BSSRL = 0x5061, /*!< Battery Safeguard maximum reduction */ + TFA9872_BF_BSSR = 0x50e0, /*!< Battery voltage read out */ + TFA9872_BF_BSSBY = 0x50f0, /*!< Bypass battery safeguard */ + TFA9872_BF_BSSS = 0x5100, /*!< Vbat prot steepness */ + TFA9872_BF_INTSMUTE= 0x5110, /*!< Soft mute HW */ + TFA9872_BF_HPFBYP= 0x5150, /*!< Bypass HPF */ + TFA9872_BF_DPSA = 0x5170, /*!< Enable DPSA */ + TFA9872_BF_CLIPCTRL= 0x5222, /*!< Clip control setting */ + TFA9872_BF_AMPGAIN= 0x5257, /*!< Amplifier gain */ + TFA9872_BF_SLOPEE= 0x52d0, /*!< Enables slope control */ + TFA9872_BF_SLOPESET= 0x52e0, /*!< Slope speed setting (bin. coded) */ + TFA9872_BF_PGAGAIN= 0x6081, /*!< PGA gain selection */ + TFA9872_BF_PGALPE= 0x60b0, /*!< Lowpass enable */ + TFA9872_BF_LPM0BYP= 0x6110, /*!< bypass low power idle mode */ + TFA9872_BF_TDMDCG= 0x6123, /*!< Second channel gain in case of stereo using a single coil. (Total gain depending on INPLEV). (In case of mono OR stereo using 2 separate DCDC channel 1 should be disabled using TDMDCE) */ + TFA9872_BF_TDMSPKG= 0x6163, /*!< Total gain depending on INPLEV setting (channel 0) */ + TFA9872_BF_STIDLEEN= 0x61b0, /*!< enable idle feature for channel 1 */ + TFA9872_BF_LNMODE= 0x62e1, /*!< ctrl select mode */ + TFA9872_BF_LPM1MODE= 0x64e1, /*!< low power mode control */ + TFA9872_BF_LPM1DIS= 0x65c0, /*!< low power mode1 detector control */ + TFA9872_BF_TDMSRCMAP= 0x6801, /*!< tdm source mapping */ + TFA9872_BF_TDMSRCAS= 0x6821, /*!< Sensed value A */ + TFA9872_BF_TDMSRCBS= 0x6841, /*!< Sensed value B */ + TFA9872_BF_ANCSEL= 0x6881, /*!< anc input */ + TFA9872_BF_ANC1C = 0x68a0, /*!< ANC one s complement */ + TFA9872_BF_SAMMODE= 0x6901, /*!< sam enable */ + TFA9872_BF_SAMSEL= 0x6920, /*!< sam source */ + TFA9872_BF_PDMOSELH= 0x6931, /*!< pdm out value when pdm_clk is higth */ + TFA9872_BF_PDMOSELL= 0x6951, /*!< pdm out value when pdm_clk is low */ + TFA9872_BF_SAMOSEL= 0x6970, /*!< ram output on mode sam and audio */ + TFA9872_BF_LP0 = 0x6e00, /*!< low power mode 0 detection */ + TFA9872_BF_LP1 = 0x6e10, /*!< low power mode 1 detection */ + TFA9872_BF_LA = 0x6e20, /*!< low amplitude detection */ + TFA9872_BF_VDDPH = 0x6e30, /*!< vddp greater than vbat */ + TFA9872_BF_DELCURCOMP= 0x6f02, /*!< delay to allign compensation signal with current sense signal */ + TFA9872_BF_SIGCURCOMP= 0x6f40, /*!< polarity of compensation for current sense */ + TFA9872_BF_ENCURCOMP= 0x6f50, /*!< enable current sense compensation */ + TFA9872_BF_SELCLPPWM= 0x6f60, /*!< Select pwm clip flag */ + TFA9872_BF_LVLCLPPWM= 0x6f72, /*!< set the amount of pwm pulse that may be skipped before clip-flag is triggered */ + TFA9872_BF_DCVOS = 0x7002, /*!< Second boost voltage level */ + TFA9872_BF_DCMCC = 0x7033, /*!< Max coil current */ + TFA9872_BF_DCCV = 0x7071, /*!< Slope compensation current, represents LxF (inductance x frequency) value */ + TFA9872_BF_DCIE = 0x7090, /*!< Adaptive boost mode */ + TFA9872_BF_DCSR = 0x70a0, /*!< Soft ramp up/down */ + TFA9872_BF_DCDIS = 0x70e0, /*!< DCDC on/off */ + TFA9872_BF_DCPWM = 0x70f0, /*!< DCDC PWM only mode */ + TFA9872_BF_DCVOF = 0x7402, /*!< 1st boost voltage level */ + TFA9872_BF_DCTRACK= 0x7430, /*!< Boost algorithm selection, effective only when boost_intelligent is set to 1 */ + TFA9872_BF_DCTRIP= 0x7444, /*!< 1st Adaptive boost trip levels, effective only when DCIE is set to 1 */ + TFA9872_BF_DCHOLD= 0x7494, /*!< Hold time for DCDC booster, effective only when boost_intelligent is set to 1 */ + TFA9872_BF_DCTRIP2= 0x7534, /*!< 2nd Adaptive boost trip levels, effective only when DCIE is set to 1 */ + TFA9872_BF_DCTRIPT= 0x7584, /*!< Track Adaptive boost trip levels, effective only when boost_intelligent is set to 1 */ + TFA9872_BF_MTPK = 0xa107, /*!< MTP KEY2 register */ + TFA9872_BF_KEY1LOCKED= 0xa200, /*!< Indicates KEY1 is locked */ + TFA9872_BF_KEY2LOCKED= 0xa210, /*!< Indicates KEY2 is locked */ + TFA9872_BF_CMTPI = 0xa350, /*!< Start copying all the data from mtp to I2C mtp registers */ + TFA9872_BF_CIMTP = 0xa360, /*!< Start copying data from I2C mtp registers to mtp */ + TFA9872_BF_MTPRDMSB= 0xa50f, /*!< MSB word of MTP manual read data */ + TFA9872_BF_MTPRDLSB= 0xa60f, /*!< LSB word of MTP manual read data */ + TFA9872_BF_EXTTS = 0xb108, /*!< External temperature (C) */ + TFA9872_BF_TROS = 0xb190, /*!< Select temp Speaker calibration */ + TFA9872_BF_SWPROFIL= 0xee0f, /*!< Software profile data */ + TFA9872_BF_SWVSTEP= 0xef0f, /*!< Software vstep information */ + TFA9872_BF_MTPOTC= 0xf000, /*!< Calibration schedule */ + TFA9872_BF_MTPEX = 0xf010, /*!< Calibration Ron executed */ + TFA9872_BF_DCMCCAPI= 0xf020, /*!< Calibration current limit DCDC */ + TFA9872_BF_DCMCCSB= 0xf030, /*!< Sign bit for delta calibration current limit DCDC */ + TFA9872_BF_USERDEF= 0xf042, /*!< Calibration delta current limit DCDC */ + TFA9872_BF_CUSTINFO= 0xf078, /*!< Reserved space for allowing customer to store speaker information */ + TFA9872_BF_R25C = 0xf50f, /*!< Ron resistance of speaker coil */ +} nxpTfa9872BfEnumList_t; +#define TFA9872_NAMETABLE static tfaBfName_t Tfa9872DatasheetNames[]= {\ + { 0x0, "PWDN"}, /* Powerdown selection , */\ + { 0x10, "I2CR"}, /* I2C Reset - Auto clear , */\ + { 0x30, "AMPE"}, /* Activate Amplifier , */\ + { 0x40, "DCA"}, /* Activate DC-to-DC converter , */\ + { 0x71, "INTP"}, /* Interrupt config , */\ + { 0xb0, "BYPOCP"}, /* Bypass OCP , */\ + { 0xc0, "TSTOCP"}, /* OCP testing control , */\ + { 0x120, "MANSCONF"}, /* I2C configured , */\ + { 0x140, "MANAOOSC"}, /* Internal osc off at PWDN , */\ + { 0x1d0, "MUTETO"}, /* Time out SB mute sequence , */\ + { 0x1e0, "RCVNS"}, /* Noise shaper selection , */\ + { 0x203, "AUDFS"}, /* Sample rate (fs) , */\ + { 0x240, "INPLEV"}, /* TDM output attenuation , */\ + { 0x255, "FRACTDEL"}, /* V/I Fractional delay , */\ + { 0x2b0, "BYPHVBF"}, /* Bypass HVBAT filter , */\ + { 0x30f, "REV"}, /* Revision info , */\ + { 0x401, "REFCKEXT"}, /* PLL external ref clock , */\ + { 0x420, "REFCKSEL"}, /* PLL internal ref clock , */\ + { 0x510, "SSE"}, /* Enable speaker path , */\ + { 0x530, "VSE"}, /* Voltage sense , */\ + { 0x550, "CSE"}, /* Current sense , */\ + { 0x560, "SSPDME"}, /* Sub-system PDM , */\ + { 0x580, "PGAE"}, /* Enable PGA chop clock , */\ + { 0x590, "SSTDME"}, /* Sub-system TDM , */\ + { 0x5a0, "SSPBSTE"}, /* Sub-system boost , */\ + { 0x5b0, "SSADCE"}, /* Sub-system ADC , */\ + { 0x5c0, "SSFAIME"}, /* Sub-system FAIM , */\ + { 0xd18, "STGAIN"}, /* Side tone gain , */\ + { 0xda0, "STSMUTE"}, /* Side tone soft mute , */\ + { 0xdb0, "ST1C"}, /* side tone one s complement , */\ + { 0x1000, "VDDS"}, /* POR , */\ + { 0x1010, "PLLS"}, /* PLL lock , */\ + { 0x1020, "OTDS"}, /* OTP alarm , */\ + { 0x1030, "OVDS"}, /* OVP alarm , */\ + { 0x1040, "UVDS"}, /* UVP alarm , */\ + { 0x1050, "CLKS"}, /* Clocks stable , */\ + { 0x1060, "MTPB"}, /* MTP busy , */\ + { 0x1070, "NOCLK"}, /* Lost clock , */\ + { 0x10a0, "SWS"}, /* Amplifier engage , */\ + { 0x10c0, "AMPS"}, /* Amplifier enable , */\ + { 0x10d0, "AREFS"}, /* References enable , */\ + { 0x10e0, "ADCCR"}, /* Control ADC , */\ + { 0x1100, "DCIL"}, /* DCDC current limiting , */\ + { 0x1110, "DCDCA"}, /* DCDC active , */\ + { 0x1120, "DCOCPOK"}, /* DCDC OCP nmos , */\ + { 0x1140, "DCHVBAT"}, /* DCDC level 1x , */\ + { 0x1150, "DCH114"}, /* DCDC level 1.14x , */\ + { 0x1160, "DCH107"}, /* DCDC level 1.07x , */\ + { 0x1170, "STMUTEB"}, /* side tone (un)mute busy , */\ + { 0x1180, "STMUTE"}, /* side tone mute state , */\ + { 0x1190, "TDMLUTER"}, /* TDM LUT error , */\ + { 0x11a2, "TDMSTAT"}, /* TDM status bits , */\ + { 0x11d0, "TDMERR"}, /* TDM error , */\ + { 0x1300, "OCPOAP"}, /* OCPOK pmos A , */\ + { 0x1310, "OCPOAN"}, /* OCPOK nmos A , */\ + { 0x1320, "OCPOBP"}, /* OCPOK pmos B , */\ + { 0x1330, "OCPOBN"}, /* OCPOK nmos B , */\ + { 0x1340, "CLIPAH"}, /* Clipping A to Vddp , */\ + { 0x1350, "CLIPAL"}, /* Clipping A to gnd , */\ + { 0x1360, "CLIPBH"}, /* Clipping B to Vddp , */\ + { 0x1370, "CLIPBL"}, /* Clipping B to gnd , */\ + { 0x1380, "OCDS"}, /* OCP amplifier , */\ + { 0x1390, "CLIPS"}, /* Amplifier clipping , */\ + { 0x13a0, "OCPOKMC"}, /* OCPOK MICVDD , */\ + { 0x13b0, "MANALARM"}, /* Alarm state , */\ + { 0x13c0, "MANWAIT1"}, /* Wait HW I2C settings , */\ + { 0x13e0, "MANMUTE"}, /* Audio mute sequence , */\ + { 0x13f0, "MANOPER"}, /* Operating state , */\ + { 0x1420, "CLKOOR"}, /* External clock status , */\ + { 0x1433, "MANSTATE"}, /* Device manager status , */\ + { 0x1471, "DCMODE"}, /* DCDC mode status bits , */\ + { 0x1509, "BATS"}, /* Battery voltage (V) , */\ + { 0x1608, "TEMPS"}, /* IC Temperature (C) , */\ + { 0x1709, "VDDPS"}, /* IC VDDP voltage ( 1023*VDDP/9.5 V) , */\ + { 0x2040, "TDME"}, /* Enable interface , */\ + { 0x2050, "TDMMODE"}, /* Slave/master , */\ + { 0x2060, "TDMCLINV"}, /* Reception data to BCK clock , */\ + { 0x2073, "TDMFSLN"}, /* FS length (master mode only) , */\ + { 0x20b0, "TDMFSPOL"}, /* FS polarity , */\ + { 0x20c3, "TDMNBCK"}, /* N-BCK's in FS , */\ + { 0x2103, "TDMSLOTS"}, /* N-slots in Frame , */\ + { 0x2144, "TDMSLLN"}, /* N-bits in slot , */\ + { 0x2194, "TDMBRMG"}, /* N-bits remaining , */\ + { 0x21e0, "TDMDEL"}, /* data delay to FS , */\ + { 0x21f0, "TDMADJ"}, /* data adjustment , */\ + { 0x2201, "TDMOOMP"}, /* Received audio compression , */\ + { 0x2224, "TDMSSIZE"}, /* Sample size per slot , */\ + { 0x2271, "TDMTXDFO"}, /* Format unused bits , */\ + { 0x2291, "TDMTXUS0"}, /* Format unused slots DATAO , */\ + { 0x2300, "TDMSPKE"}, /* Control audio tdm channel in 0 (spkr + dcdc) , */\ + { 0x2310, "TDMDCE"}, /* Control audio tdm channel in 1 (dcdc) , */\ + { 0x2330, "TDMCSE"}, /* current sense vbat temperature and vddp feedback , */\ + { 0x2340, "TDMVSE"}, /* Voltage sense vbat temperature and vddp feedback , */\ + { 0x2603, "TDMSPKS"}, /* tdm slot for sink 0 (speaker + dcdc) , */\ + { 0x2643, "TDMDCS"}, /* tdm slot for sink 1 (dcdc) , */\ + { 0x26c3, "TDMCSS"}, /* Slot Position of current sense vbat temperature and vddp feedback, */\ + { 0x2703, "TDMVSS"}, /* Slot Position of Voltage sense vbat temperature and vddp feedback, */\ + { 0x3111, "PDMSTSEL"}, /* Side tone input , */\ + { 0x4000, "ISTVDDS"}, /* Status POR , */\ + { 0x4010, "ISTPLLS"}, /* Status PLL lock , */\ + { 0x4020, "ISTOTDS"}, /* Status OTP alarm , */\ + { 0x4030, "ISTOVDS"}, /* Status OVP alarm , */\ + { 0x4040, "ISTUVDS"}, /* Status UVP alarm , */\ + { 0x4050, "ISTCLKS"}, /* Status clocks stable , */\ + { 0x4060, "ISTMTPB"}, /* Status MTP busy , */\ + { 0x4070, "ISTNOCLK"}, /* Status lost clock , */\ + { 0x40a0, "ISTSWS"}, /* Status amplifier engage , */\ + { 0x40c0, "ISTAMPS"}, /* Status amplifier enable , */\ + { 0x40d0, "ISTAREFS"}, /* Status Ref enable , */\ + { 0x40e0, "ISTADCCR"}, /* Status Control ADC , */\ + { 0x4100, "ISTBSTCU"}, /* Status DCDC current limiting , */\ + { 0x4110, "ISTBSTHI"}, /* Status DCDC active , */\ + { 0x4120, "ISTBSTOC"}, /* Status DCDC OCP , */\ + { 0x4130, "ISTBSTPKCUR"}, /* Status bst peakcur , */\ + { 0x4140, "ISTBSTVC"}, /* Status DCDC level 1x , */\ + { 0x4150, "ISTBST86"}, /* Status DCDC level 1.14x , */\ + { 0x4160, "ISTBST93"}, /* Status DCDC level 1.07x , */\ + { 0x4190, "ISTOCPR"}, /* Status ocp alarm , */\ + { 0x41a0, "ISTMWSRC"}, /* Status Waits HW I2C settings , */\ + { 0x41c0, "ISTMWSMU"}, /* Status Audio mute sequence , */\ + { 0x41f0, "ISTCLKOOR"}, /* Status flag_clk_out_of_range , */\ + { 0x4200, "ISTTDMER"}, /* Status tdm error , */\ + { 0x4220, "ISTCLPR"}, /* Status clip , */\ + { 0x4240, "ISTLP0"}, /* Status low power mode0 , */\ + { 0x4250, "ISTLP1"}, /* Status low power mode1 , */\ + { 0x4260, "ISTLA"}, /* Status low noise detection , */\ + { 0x4270, "ISTVDDPH"}, /* Status VDDP greater than VBAT , */\ + { 0x4400, "ICLVDDS"}, /* Clear POR , */\ + { 0x4410, "ICLPLLS"}, /* Clear PLL lock , */\ + { 0x4420, "ICLOTDS"}, /* Clear OTP alarm , */\ + { 0x4430, "ICLOVDS"}, /* Clear OVP alarm , */\ + { 0x4440, "ICLUVDS"}, /* Clear UVP alarm , */\ + { 0x4450, "ICLCLKS"}, /* Clear clocks stable , */\ + { 0x4460, "ICLMTPB"}, /* Clear mtp busy , */\ + { 0x4470, "ICLNOCLK"}, /* Clear lost clk , */\ + { 0x44a0, "ICLSWS"}, /* Clear amplifier engage , */\ + { 0x44c0, "ICLAMPS"}, /* Clear enbl amp , */\ + { 0x44d0, "ICLAREFS"}, /* Clear ref enable , */\ + { 0x44e0, "ICLADCCR"}, /* Clear control ADC , */\ + { 0x4500, "ICLBSTCU"}, /* Clear DCDC current limiting , */\ + { 0x4510, "ICLBSTHI"}, /* Clear DCDC active , */\ + { 0x4520, "ICLBSTOC"}, /* Clear DCDC OCP , */\ + { 0x4530, "ICLBSTPC"}, /* Clear bst peakcur , */\ + { 0x4540, "ICLBSTVC"}, /* Clear DCDC level 1x , */\ + { 0x4550, "ICLBST86"}, /* Clear DCDC level 1.14x , */\ + { 0x4560, "ICLBST93"}, /* Clear DCDC level 1.07x , */\ + { 0x4590, "ICLOCPR"}, /* Clear ocp alarm , */\ + { 0x45a0, "ICLMWSRC"}, /* Clear wait HW I2C settings , */\ + { 0x45c0, "ICLMWSMU"}, /* Clear audio mute sequence , */\ + { 0x45f0, "ICLCLKOOR"}, /* Clear flag_clk_out_of_range , */\ + { 0x4600, "ICLTDMER"}, /* Clear tdm error , */\ + { 0x4620, "ICLCLPR"}, /* Clear clip , */\ + { 0x4640, "ICLLP0"}, /* Clear low power mode0 , */\ + { 0x4650, "ICLLP1"}, /* Clear low power mode1 , */\ + { 0x4660, "ICLLA"}, /* Clear low noise detection , */\ + { 0x4670, "ICLVDDPH"}, /* Clear VDDP greater then VBAT , */\ + { 0x4800, "IEVDDS"}, /* Enable por , */\ + { 0x4810, "IEPLLS"}, /* Enable pll lock , */\ + { 0x4820, "IEOTDS"}, /* Enable OTP alarm , */\ + { 0x4830, "IEOVDS"}, /* Enable OVP alarm , */\ + { 0x4840, "IEUVDS"}, /* Enable UVP alarm , */\ + { 0x4850, "IECLKS"}, /* Enable clocks stable , */\ + { 0x4860, "IEMTPB"}, /* Enable mtp busy , */\ + { 0x4870, "IENOCLK"}, /* Enable lost clk , */\ + { 0x48a0, "IESWS"}, /* Enable amplifier engage , */\ + { 0x48c0, "IEAMPS"}, /* Enable enbl amp , */\ + { 0x48d0, "IEAREFS"}, /* Enable ref enable , */\ + { 0x48e0, "IEADCCR"}, /* Enable Control ADC , */\ + { 0x4900, "IEBSTCU"}, /* Enable DCDC current limiting , */\ + { 0x4910, "IEBSTHI"}, /* Enable DCDC active , */\ + { 0x4920, "IEBSTOC"}, /* Enable DCDC OCP , */\ + { 0x4930, "IEBSTPC"}, /* Enable bst peakcur , */\ + { 0x4940, "IEBSTVC"}, /* Enable DCDC level 1x , */\ + { 0x4950, "IEBST86"}, /* Enable DCDC level 1.14x , */\ + { 0x4960, "IEBST93"}, /* Enable DCDC level 1.07x , */\ + { 0x4990, "IEOCPR"}, /* Enable ocp alarm , */\ + { 0x49a0, "IEMWSRC"}, /* Enable waits HW I2C settings , */\ + { 0x49c0, "IEMWSMU"}, /* Enable man Audio mute sequence , */\ + { 0x49f0, "IECLKOOR"}, /* Enable flag_clk_out_of_range , */\ + { 0x4a00, "IETDMER"}, /* Enable tdm error , */\ + { 0x4a20, "IECLPR"}, /* Enable clip , */\ + { 0x4a40, "IELP0"}, /* Enable low power mode0 , */\ + { 0x4a50, "IELP1"}, /* Enable low power mode1 , */\ + { 0x4a60, "IELA"}, /* Enable low noise detection , */\ + { 0x4a70, "IEVDDPH"}, /* Enable VDDP greater tehn VBAT , */\ + { 0x4c00, "IPOVDDS"}, /* Polarity por , */\ + { 0x4c10, "IPOPLLS"}, /* Polarity pll lock , */\ + { 0x4c20, "IPOOTDS"}, /* Polarity OTP alarm , */\ + { 0x4c30, "IPOOVDS"}, /* Polarity OVP alarm , */\ + { 0x4c40, "IPOUVDS"}, /* Polarity UVP alarm , */\ + { 0x4c50, "IPOCLKS"}, /* Polarity clocks stable , */\ + { 0x4c60, "IPOMTPB"}, /* Polarity mtp busy , */\ + { 0x4c70, "IPONOCLK"}, /* Polarity lost clk , */\ + { 0x4ca0, "IPOSWS"}, /* Polarity amplifier engage , */\ + { 0x4cc0, "IPOAMPS"}, /* Polarity enbl amp , */\ + { 0x4cd0, "IPOAREFS"}, /* Polarity ref enable , */\ + { 0x4ce0, "IPOADCCR"}, /* Polarity Control ADC , */\ + { 0x4d00, "IPOBSTCU"}, /* Polarity DCDC current limiting , */\ + { 0x4d10, "IPOBSTHI"}, /* Polarity DCDC active , */\ + { 0x4d20, "IPOBSTOC"}, /* Polarity DCDC OCP , */\ + { 0x4d30, "IPOBSTPC"}, /* Polarity bst peakcur , */\ + { 0x4d40, "IPOBSTVC"}, /* Polarity DCDC level 1x , */\ + { 0x4d50, "IPOBST86"}, /* Polarity DCDC level 1.14x , */\ + { 0x4d60, "IPOBST93"}, /* Polarity DCDC level 1.07x , */\ + { 0x4d90, "IPOOCPR"}, /* Polarity ocp alarm , */\ + { 0x4da0, "IPOMWSRC"}, /* Polarity waits HW I2C settings , */\ + { 0x4dc0, "IPOMWSMU"}, /* Polarity man audio mute sequence , */\ + { 0x4df0, "IPCLKOOR"}, /* Polarity flag_clk_out_of_range , */\ + { 0x4e00, "IPOTDMER"}, /* Polarity tdm error , */\ + { 0x4e20, "IPOCLPR"}, /* Polarity clip right , */\ + { 0x4e40, "IPOLP0"}, /* Polarity low power mode0 , */\ + { 0x4e50, "IPOLP1"}, /* Polarity low power mode1 , */\ + { 0x4e60, "IPOLA"}, /* Polarity low noise mode , */\ + { 0x4e70, "IPOVDDPH"}, /* Polarity VDDP greater than VBAT , */\ + { 0x5001, "BSSCR"}, /* Battery Safeguard attack time , */\ + { 0x5023, "BSST"}, /* Battery Safeguard threshold voltage level , */\ + { 0x5061, "BSSRL"}, /* Battery Safeguard maximum reduction , */\ + { 0x50e0, "BSSR"}, /* Battery voltage read out , */\ + { 0x50f0, "BSSBY"}, /* Bypass battery safeguard , */\ + { 0x5100, "BSSS"}, /* Vbat prot steepness , */\ + { 0x5110, "INTSMUTE"}, /* Soft mute HW , */\ + { 0x5150, "HPFBYP"}, /* Bypass HPF , */\ + { 0x5170, "DPSA"}, /* Enable DPSA , */\ + { 0x5222, "CLIPCTRL"}, /* Clip control setting , */\ + { 0x5257, "AMPGAIN"}, /* Amplifier gain , */\ + { 0x52d0, "SLOPEE"}, /* Enables slope control , */\ + { 0x52e0, "SLOPESET"}, /* Slope speed setting (bin. coded) , */\ + { 0x6081, "PGAGAIN"}, /* PGA gain selection , */\ + { 0x60b0, "PGALPE"}, /* Lowpass enable , */\ + { 0x6110, "LPM0BYP"}, /* bypass low power idle mode , */\ + { 0x6123, "TDMDCG"}, /* Second channel gain in case of stereo using a single coil. (Total gain depending on INPLEV). (In case of mono OR stereo using 2 separate DCDC channel 1 should be disabled using TDMDCE), */\ + { 0x6163, "TDMSPKG"}, /* Total gain depending on INPLEV setting (channel 0), */\ + { 0x61b0, "STIDLEEN"}, /* enable idle feature for channel 1 , */\ + { 0x62e1, "LNMODE"}, /* ctrl select mode , */\ + { 0x64e1, "LPM1MODE"}, /* low power mode control , */\ + { 0x65c0, "LPM1DIS"}, /* low power mode1 detector control , */\ + { 0x6801, "TDMSRCMAP"}, /* tdm source mapping , */\ + { 0x6821, "TDMSRCAS"}, /* Sensed value A , */\ + { 0x6841, "TDMSRCBS"}, /* Sensed value B , */\ + { 0x6881, "ANCSEL"}, /* anc input , */\ + { 0x68a0, "ANC1C"}, /* ANC one s complement , */\ + { 0x6901, "SAMMODE"}, /* sam enable , */\ + { 0x6920, "SAMSEL"}, /* sam source , */\ + { 0x6931, "PDMOSELH"}, /* pdm out value when pdm_clk is higth , */\ + { 0x6951, "PDMOSELL"}, /* pdm out value when pdm_clk is low , */\ + { 0x6970, "SAMOSEL"}, /* ram output on mode sam and audio , */\ + { 0x6e00, "LP0"}, /* low power mode 0 detection , */\ + { 0x6e10, "LP1"}, /* low power mode 1 detection , */\ + { 0x6e20, "LA"}, /* low amplitude detection , */\ + { 0x6e30, "VDDPH"}, /* vddp greater than vbat , */\ + { 0x6f02, "DELCURCOMP"}, /* delay to allign compensation signal with current sense signal, */\ + { 0x6f40, "SIGCURCOMP"}, /* polarity of compensation for current sense , */\ + { 0x6f50, "ENCURCOMP"}, /* enable current sense compensation , */\ + { 0x6f60, "SELCLPPWM"}, /* Select pwm clip flag , */\ + { 0x6f72, "LVLCLPPWM"}, /* set the amount of pwm pulse that may be skipped before clip-flag is triggered, */\ + { 0x7002, "DCVOS"}, /* Second boost voltage level , */\ + { 0x7033, "DCMCC"}, /* Max coil current , */\ + { 0x7071, "DCCV"}, /* Slope compensation current, represents LxF (inductance x frequency) value , */\ + { 0x7090, "DCIE"}, /* Adaptive boost mode , */\ + { 0x70a0, "DCSR"}, /* Soft ramp up/down , */\ + { 0x70e0, "DCDIS"}, /* DCDC on/off , */\ + { 0x70f0, "DCPWM"}, /* DCDC PWM only mode , */\ + { 0x7402, "DCVOF"}, /* 1st boost voltage level , */\ + { 0x7430, "DCTRACK"}, /* Boost algorithm selection, effective only when boost_intelligent is set to 1, */\ + { 0x7444, "DCTRIP"}, /* 1st Adaptive boost trip levels, effective only when DCIE is set to 1, */\ + { 0x7494, "DCHOLD"}, /* Hold time for DCDC booster, effective only when boost_intelligent is set to 1, */\ + { 0x7534, "DCTRIP2"}, /* 2nd Adaptive boost trip levels, effective only when DCIE is set to 1, */\ + { 0x7584, "DCTRIPT"}, /* Track Adaptive boost trip levels, effective only when boost_intelligent is set to 1, */\ + { 0xa107, "MTPK"}, /* MTP KEY2 register , */\ + { 0xa200, "KEY1LOCKED"}, /* Indicates KEY1 is locked , */\ + { 0xa210, "KEY2LOCKED"}, /* Indicates KEY2 is locked , */\ + { 0xa350, "CMTPI"}, /* Start copying all the data from mtp to I2C mtp registers, */\ + { 0xa360, "CIMTP"}, /* Start copying data from I2C mtp registers to mtp , */\ + { 0xa50f, "MTPRDMSB"}, /* MSB word of MTP manual read data , */\ + { 0xa60f, "MTPRDLSB"}, /* LSB word of MTP manual read data , */\ + { 0xb108, "EXTTS"}, /* External temperature (C) , */\ + { 0xb190, "TROS"}, /* Select temp Speaker calibration , */\ + { 0xee0f, "SWPROFIL"}, /* Software profile data , */\ + { 0xef0f, "SWVSTEP"}, /* Software vstep information , */\ + { 0xf000, "MTPOTC"}, /* Calibration schedule , */\ + { 0xf010, "MTPEX"}, /* Calibration Ron executed , */\ + { 0xf020, "DCMCCAPI"}, /* Calibration current limit DCDC , */\ + { 0xf030, "DCMCCSB"}, /* Sign bit for delta calibration current limit DCDC , */\ + { 0xf042, "USERDEF"}, /* Calibration delta current limit DCDC , */\ + { 0xf078, "CUSTINFO"}, /* Reserved space for allowing customer to store speaker information, */\ + { 0xf50f, "R25C"}, /* Ron resistance of speaker coil , */\ + { 0xffff,"Unknown bitfield enum" } /* not found */\ +}; + +#define TFA9872_BITNAMETABLE static tfaBfName_t Tfa9872BitNames[]= {\ + { 0x0, "powerdown"}, /* Powerdown selection , */\ + { 0x10, "reset"}, /* I2C Reset - Auto clear , */\ + { 0x30, "enbl_amplifier"}, /* Activate Amplifier , */\ + { 0x40, "enbl_boost"}, /* Activate DC-to-DC converter , */\ + { 0x71, "int_pad_io"}, /* Interrupt config , */\ + { 0xb0, "bypass_ocp"}, /* Bypass OCP , */\ + { 0xc0, "test_ocp"}, /* OCP testing control , */\ + { 0x120, "src_set_configured"}, /* I2C configured , */\ + { 0x140, "enbl_osc1m_auto_off"}, /* Internal osc off at PWDN , */\ + { 0x1d0, "disable_mute_time_out"}, /* Time out SB mute sequence , */\ + { 0x203, "audio_fs"}, /* Sample rate (fs) , */\ + { 0x240, "input_level"}, /* TDM output attenuation , */\ + { 0x255, "cs_frac_delay"}, /* V/I Fractional delay , */\ + { 0x2b0, "bypass_hvbat_filter"}, /* Bypass HVBAT filter , */\ + { 0x2d0, "sel_hysteresis"}, /* Select hysteresis for clock range detector , */\ + { 0x30f, "device_rev"}, /* Revision info , */\ + { 0x401, "pll_clkin_sel"}, /* PLL external ref clock , */\ + { 0x420, "pll_clkin_sel_osc"}, /* PLL internal ref clock , */\ + { 0x510, "enbl_spkr_ss"}, /* Enable speaker path , */\ + { 0x530, "enbl_volsense"}, /* Voltage sense , */\ + { 0x550, "enbl_cursense"}, /* Current sense , */\ + { 0x560, "enbl_pdm_ss"}, /* Sub-system PDM , */\ + { 0x580, "enbl_pga_chop"}, /* Enable PGA chop clock , */\ + { 0x590, "enbl_tdm_ss"}, /* Sub-system TDM , */\ + { 0x5a0, "enbl_bst_ss"}, /* Sub-system boost , */\ + { 0x5b0, "enbl_adc_ss"}, /* Sub-system ADC , */\ + { 0x5c0, "enbl_faim_ss"}, /* Sub-system FAIM , */\ + { 0xd18, "side_tone_gain"}, /* Side tone gain , */\ + { 0xda0, "mute_side_tone"}, /* Side tone soft mute , */\ + { 0xdb0, "side_tone_1scomplement"}, /* side tone one s complement , */\ + { 0xe07, "ctrl_digtoana"}, /* Spare control from digital to analog , */\ + { 0xf0f, "hidden_code"}, /* 5A6Bh, 23147d to access registers (default for engineering), */\ + { 0x1000, "flag_por"}, /* POR , */\ + { 0x1010, "flag_pll_lock"}, /* PLL lock , */\ + { 0x1020, "flag_otpok"}, /* OTP alarm , */\ + { 0x1030, "flag_ovpok"}, /* OVP alarm , */\ + { 0x1040, "flag_uvpok"}, /* UVP alarm , */\ + { 0x1050, "flag_clocks_stable"}, /* Clocks stable , */\ + { 0x1060, "flag_mtp_busy"}, /* MTP busy , */\ + { 0x1070, "flag_lost_clk"}, /* Lost clock , */\ + { 0x10a0, "flag_engage"}, /* Amplifier engage , */\ + { 0x10c0, "flag_enbl_amp"}, /* Amplifier enable , */\ + { 0x10d0, "flag_enbl_ref"}, /* References enable , */\ + { 0x10e0, "flag_adc10_ready"}, /* Control ADC , */\ + { 0x1100, "flag_bst_bstcur"}, /* DCDC current limiting , */\ + { 0x1110, "flag_bst_hiz"}, /* DCDC active , */\ + { 0x1120, "flag_bst_ocpok"}, /* DCDC OCP nmos , */\ + { 0x1130, "flag_bst_peakcur"}, /* Indicates current is max in DC-to-DC converter , */\ + { 0x1140, "flag_bst_voutcomp"}, /* DCDC level 1x , */\ + { 0x1150, "flag_bst_voutcomp86"}, /* DCDC level 1.14x , */\ + { 0x1160, "flag_bst_voutcomp93"}, /* DCDC level 1.07x , */\ + { 0x1170, "flag_soft_mute_busy"}, /* side tone (un)mute busy , */\ + { 0x1180, "flag_soft_mute_state"}, /* side tone mute state , */\ + { 0x1190, "flag_tdm_lut_error"}, /* TDM LUT error , */\ + { 0x11a2, "flag_tdm_status"}, /* TDM status bits , */\ + { 0x11d0, "flag_tdm_error"}, /* TDM error , */\ + { 0x1300, "flag_ocpokap"}, /* OCPOK pmos A , */\ + { 0x1310, "flag_ocpokan"}, /* OCPOK nmos A , */\ + { 0x1320, "flag_ocpokbp"}, /* OCPOK pmos B , */\ + { 0x1330, "flag_ocpokbn"}, /* OCPOK nmos B , */\ + { 0x1340, "flag_clipa_high"}, /* Clipping A to Vddp , */\ + { 0x1350, "flag_clipa_low"}, /* Clipping A to gnd , */\ + { 0x1360, "flag_clipb_high"}, /* Clipping B to Vddp , */\ + { 0x1370, "flag_clipb_low"}, /* Clipping B to gnd , */\ + { 0x1380, "flag_ocp_alarm"}, /* OCP amplifier , */\ + { 0x1390, "flag_clip"}, /* Amplifier clipping , */\ + { 0x13b0, "flag_man_alarm_state"}, /* Alarm state , */\ + { 0x13c0, "flag_man_wait_src_settings"}, /* Wait HW I2C settings , */\ + { 0x13e0, "flag_man_start_mute_audio"}, /* Audio mute sequence , */\ + { 0x13f0, "flag_man_operating_state"}, /* Operating state , */\ + { 0x1420, "flag_clk_out_of_range"}, /* External clock status , */\ + { 0x1433, "man_state"}, /* Device manager status , */\ + { 0x1471, "status_bst_mode"}, /* DCDC mode status bits , */\ + { 0x1509, "bat_adc"}, /* Battery voltage (V) , */\ + { 0x1608, "temp_adc"}, /* IC Temperature (C) , */\ + { 0x1709, "vddp_adc"}, /* IC VDDP voltage ( 1023*VDDP/9.5 V) , */\ + { 0x2040, "tdm_enable"}, /* Enable interface , */\ + { 0x2050, "tdm_mode"}, /* Slave/master , */\ + { 0x2060, "tdm_clk_inversion"}, /* Reception data to BCK clock , */\ + { 0x2073, "tdm_fs_ws_length"}, /* FS length (master mode only) , */\ + { 0x20b0, "tdm_fs_ws_polarity"}, /* FS polarity , */\ + { 0x20c3, "tdm_nbck"}, /* N-BCK's in FS , */\ + { 0x2103, "tdm_nb_of_slots"}, /* N-slots in Frame , */\ + { 0x2144, "tdm_slot_length"}, /* N-bits in slot , */\ + { 0x2194, "tdm_bits_remaining"}, /* N-bits remaining , */\ + { 0x21e0, "tdm_data_delay"}, /* data delay to FS , */\ + { 0x21f0, "tdm_data_adjustment"}, /* data adjustment , */\ + { 0x2201, "tdm_audio_sample_compression"}, /* Received audio compression , */\ + { 0x2224, "tdm_sample_size"}, /* Sample size per slot , */\ + { 0x2271, "tdm_txdata_format"}, /* Format unused bits , */\ + { 0x2291, "tdm_txdata_format_unused_slot_sd0"}, /* Format unused slots DATAO , */\ + { 0x2300, "tdm_sink0_enable"}, /* Control audio tdm channel in 0 (spkr + dcdc) , */\ + { 0x2310, "tdm_sink1_enable"}, /* Control audio tdm channel in 1 (dcdc) , */\ + { 0x2330, "tdm_source0_enable"}, /* current sense vbat temperature and vddp feedback , */\ + { 0x2340, "tdm_source1_enable"}, /* Voltage sense vbat temperature and vddp feedback , */\ + { 0x2603, "tdm_sink0_slot"}, /* tdm slot for sink 0 (speaker + dcdc) , */\ + { 0x2643, "tdm_sink1_slot"}, /* tdm slot for sink 1 (dcdc) , */\ + { 0x26c3, "tdm_source0_slot"}, /* Slot Position of current sense vbat temperature and vddp feedback, */\ + { 0x2703, "tdm_source1_slot"}, /* Slot Position of Voltage sense vbat temperature and vddp feedback, */\ + { 0x3111, "pdm_side_tone_sel"}, /* Side tone input , */\ + { 0x3201, "pdm_nbck"}, /* PDM BCK/Fs ratio , */\ + { 0x4000, "int_out_flag_por"}, /* Status POR , */\ + { 0x4010, "int_out_flag_pll_lock"}, /* Status PLL lock , */\ + { 0x4020, "int_out_flag_otpok"}, /* Status OTP alarm , */\ + { 0x4030, "int_out_flag_ovpok"}, /* Status OVP alarm , */\ + { 0x4040, "int_out_flag_uvpok"}, /* Status UVP alarm , */\ + { 0x4050, "int_out_flag_clocks_stable"}, /* Status clocks stable , */\ + { 0x4060, "int_out_flag_mtp_busy"}, /* Status MTP busy , */\ + { 0x4070, "int_out_flag_lost_clk"}, /* Status lost clock , */\ + { 0x40a0, "int_out_flag_engage"}, /* Status amplifier engage , */\ + { 0x40c0, "int_out_flag_enbl_amp"}, /* Status amplifier enable , */\ + { 0x40d0, "int_out_flag_enbl_ref"}, /* Status Ref enable , */\ + { 0x40e0, "int_out_flag_adc10_ready"}, /* Status Control ADC , */\ + { 0x4100, "int_out_flag_bst_bstcur"}, /* Status DCDC current limiting , */\ + { 0x4110, "int_out_flag_bst_hiz"}, /* Status DCDC active , */\ + { 0x4120, "int_out_flag_bst_ocpok"}, /* Status DCDC OCP , */\ + { 0x4130, "int_out_flag_bst_peakcur"}, /* Status bst peakcur , */\ + { 0x4140, "int_out_flag_bst_voutcomp"}, /* Status DCDC level 1x , */\ + { 0x4150, "int_out_flag_bst_voutcomp86"}, /* Status DCDC level 1.14x , */\ + { 0x4160, "int_out_flag_bst_voutcomp93"}, /* Status DCDC level 1.07x , */\ + { 0x4190, "int_out_flag_ocp_alarm"}, /* Status ocp alarm , */\ + { 0x41a0, "int_out_flag_man_wait_src_settings"}, /* Status Waits HW I2C settings , */\ + { 0x41c0, "int_out_flag_man_start_mute_audio"}, /* Status Audio mute sequence , */\ + { 0x41f0, "int_out_flag_clk_out_of_range"}, /* Status flag_clk_out_of_range , */\ + { 0x4200, "int_out_flag_tdm_error"}, /* Status tdm error , */\ + { 0x4220, "int_out_flag_clip"}, /* Status clip , */\ + { 0x4240, "int_out_flag_lp_detect_mode0"}, /* Status low power mode0 , */\ + { 0x4250, "int_out_flag_lp_detect_mode1"}, /* Status low power mode1 , */\ + { 0x4260, "int_out_flag_low_amplitude"}, /* Status low noise detection , */\ + { 0x4270, "int_out_flag_vddp_gt_vbat"}, /* Status VDDP greater than VBAT , */\ + { 0x4400, "int_in_flag_por"}, /* Clear POR , */\ + { 0x4410, "int_in_flag_pll_lock"}, /* Clear PLL lock , */\ + { 0x4420, "int_in_flag_otpok"}, /* Clear OTP alarm , */\ + { 0x4430, "int_in_flag_ovpok"}, /* Clear OVP alarm , */\ + { 0x4440, "int_in_flag_uvpok"}, /* Clear UVP alarm , */\ + { 0x4450, "int_in_flag_clocks_stable"}, /* Clear clocks stable , */\ + { 0x4460, "int_in_flag_mtp_busy"}, /* Clear mtp busy , */\ + { 0x4470, "int_in_flag_lost_clk"}, /* Clear lost clk , */\ + { 0x44a0, "int_in_flag_engage"}, /* Clear amplifier engage , */\ + { 0x44c0, "int_in_flag_enbl_amp"}, /* Clear enbl amp , */\ + { 0x44d0, "int_in_flag_enbl_ref"}, /* Clear ref enable , */\ + { 0x44e0, "int_in_flag_adc10_ready"}, /* Clear control ADC , */\ + { 0x4500, "int_in_flag_bst_bstcur"}, /* Clear DCDC current limiting , */\ + { 0x4510, "int_in_flag_bst_hiz"}, /* Clear DCDC active , */\ + { 0x4520, "int_in_flag_bst_ocpok"}, /* Clear DCDC OCP , */\ + { 0x4530, "int_in_flag_bst_peakcur"}, /* Clear bst peakcur , */\ + { 0x4540, "int_in_flag_bst_voutcomp"}, /* Clear DCDC level 1x , */\ + { 0x4550, "int_in_flag_bst_voutcomp86"}, /* Clear DCDC level 1.14x , */\ + { 0x4560, "int_in_flag_bst_voutcomp93"}, /* Clear DCDC level 1.07x , */\ + { 0x4590, "int_in_flag_ocp_alarm"}, /* Clear ocp alarm , */\ + { 0x45a0, "int_in_flag_man_wait_src_settings"}, /* Clear wait HW I2C settings , */\ + { 0x45c0, "int_in_flag_man_start_mute_audio"}, /* Clear audio mute sequence , */\ + { 0x45f0, "int_in_flag_clk_out_of_range"}, /* Clear flag_clk_out_of_range , */\ + { 0x4600, "int_in_flag_tdm_error"}, /* Clear tdm error , */\ + { 0x4620, "int_in_flag_clip"}, /* Clear clip , */\ + { 0x4640, "int_in_flag_lp_detect_mode0"}, /* Clear low power mode0 , */\ + { 0x4650, "int_in_flag_lp_detect_mode1"}, /* Clear low power mode1 , */\ + { 0x4660, "int_in_flag_low_amplitude"}, /* Clear low noise detection , */\ + { 0x4670, "int_in_flag_vddp_gt_vbat"}, /* Clear VDDP greater then VBAT , */\ + { 0x4800, "int_enable_flag_por"}, /* Enable por , */\ + { 0x4810, "int_enable_flag_pll_lock"}, /* Enable pll lock , */\ + { 0x4820, "int_enable_flag_otpok"}, /* Enable OTP alarm , */\ + { 0x4830, "int_enable_flag_ovpok"}, /* Enable OVP alarm , */\ + { 0x4840, "int_enable_flag_uvpok"}, /* Enable UVP alarm , */\ + { 0x4850, "int_enable_flag_clocks_stable"}, /* Enable clocks stable , */\ + { 0x4860, "int_enable_flag_mtp_busy"}, /* Enable mtp busy , */\ + { 0x4870, "int_enable_flag_lost_clk"}, /* Enable lost clk , */\ + { 0x48a0, "int_enable_flag_engage"}, /* Enable amplifier engage , */\ + { 0x48c0, "int_enable_flag_enbl_amp"}, /* Enable enbl amp , */\ + { 0x48d0, "int_enable_flag_enbl_ref"}, /* Enable ref enable , */\ + { 0x48e0, "int_enable_flag_adc10_ready"}, /* Enable Control ADC , */\ + { 0x4900, "int_enable_flag_bst_bstcur"}, /* Enable DCDC current limiting , */\ + { 0x4910, "int_enable_flag_bst_hiz"}, /* Enable DCDC active , */\ + { 0x4920, "int_enable_flag_bst_ocpok"}, /* Enable DCDC OCP , */\ + { 0x4930, "int_enable_flag_bst_peakcur"}, /* Enable bst peakcur , */\ + { 0x4940, "int_enable_flag_bst_voutcomp"}, /* Enable DCDC level 1x , */\ + { 0x4950, "int_enable_flag_bst_voutcomp86"}, /* Enable DCDC level 1.14x , */\ + { 0x4960, "int_enable_flag_bst_voutcomp93"}, /* Enable DCDC level 1.07x , */\ + { 0x4990, "int_enable_flag_ocp_alarm"}, /* Enable ocp alarm , */\ + { 0x49a0, "int_enable_flag_man_wait_src_settings"}, /* Enable waits HW I2C settings , */\ + { 0x49c0, "int_enable_flag_man_start_mute_audio"}, /* Enable man Audio mute sequence , */\ + { 0x49f0, "int_enable_flag_clk_out_of_range"}, /* Enable flag_clk_out_of_range , */\ + { 0x4a00, "int_enable_flag_tdm_error"}, /* Enable tdm error , */\ + { 0x4a20, "int_enable_flag_clip"}, /* Enable clip , */\ + { 0x4a40, "int_enable_flag_lp_detect_mode0"}, /* Enable low power mode0 , */\ + { 0x4a50, "int_enable_flag_lp_detect_mode1"}, /* Enable low power mode1 , */\ + { 0x4a60, "int_enable_flag_low_amplitude"}, /* Enable low noise detection , */\ + { 0x4a70, "int_enable_flag_vddp_gt_vbat"}, /* Enable VDDP greater tehn VBAT , */\ + { 0x4c00, "int_polarity_flag_por"}, /* Polarity por , */\ + { 0x4c10, "int_polarity_flag_pll_lock"}, /* Polarity pll lock , */\ + { 0x4c20, "int_polarity_flag_otpok"}, /* Polarity OTP alarm , */\ + { 0x4c30, "int_polarity_flag_ovpok"}, /* Polarity OVP alarm , */\ + { 0x4c40, "int_polarity_flag_uvpok"}, /* Polarity UVP alarm , */\ + { 0x4c50, "int_polarity_flag_clocks_stable"}, /* Polarity clocks stable , */\ + { 0x4c60, "int_polarity_flag_mtp_busy"}, /* Polarity mtp busy , */\ + { 0x4c70, "int_polarity_flag_lost_clk"}, /* Polarity lost clk , */\ + { 0x4ca0, "int_polarity_flag_engage"}, /* Polarity amplifier engage , */\ + { 0x4cc0, "int_polarity_flag_enbl_amp"}, /* Polarity enbl amp , */\ + { 0x4cd0, "int_polarity_flag_enbl_ref"}, /* Polarity ref enable , */\ + { 0x4ce0, "int_polarity_flag_adc10_ready"}, /* Polarity Control ADC , */\ + { 0x4d00, "int_polarity_flag_bst_bstcur"}, /* Polarity DCDC current limiting , */\ + { 0x4d10, "int_polarity_flag_bst_hiz"}, /* Polarity DCDC active , */\ + { 0x4d20, "int_polarity_flag_bst_ocpok"}, /* Polarity DCDC OCP , */\ + { 0x4d30, "int_polarity_flag_bst_peakcur"}, /* Polarity bst peakcur , */\ + { 0x4d40, "int_polarity_flag_bst_voutcomp"}, /* Polarity DCDC level 1x , */\ + { 0x4d50, "int_polarity_flag_bst_voutcomp86"}, /* Polarity DCDC level 1.14x , */\ + { 0x4d60, "int_polarity_flag_bst_voutcomp93"}, /* Polarity DCDC level 1.07x , */\ + { 0x4d90, "int_polarity_flag_ocp_alarm"}, /* Polarity ocp alarm , */\ + { 0x4da0, "int_polarity_flag_man_wait_src_settings"}, /* Polarity waits HW I2C settings , */\ + { 0x4dc0, "int_polarity_flag_man_start_mute_audio"}, /* Polarity man audio mute sequence , */\ + { 0x4df0, "int_polarity_flag_clk_out_of_range"}, /* Polarity flag_clk_out_of_range , */\ + { 0x4e00, "int_polarity_flag_tdm_error"}, /* Polarity tdm error , */\ + { 0x4e20, "int_polarity_flag_clip"}, /* Polarity clip right , */\ + { 0x4e40, "int_polarity_flag_lp_detect_mode0"}, /* Polarity low power mode0 , */\ + { 0x4e50, "int_polarity_flag_lp_detect_mode1"}, /* Polarity low power mode1 , */\ + { 0x4e60, "int_polarity_flag_low_amplitude"}, /* Polarity low noise mode , */\ + { 0x4e70, "int_polarity_flag_vddp_gt_vbat"}, /* Polarity VDDP greater than VBAT , */\ + { 0x5001, "vbat_prot_attack_time"}, /* Battery Safeguard attack time , */\ + { 0x5023, "vbat_prot_thlevel"}, /* Battery Safeguard threshold voltage level , */\ + { 0x5061, "vbat_prot_max_reduct"}, /* Battery Safeguard maximum reduction , */\ + { 0x50d0, "rst_min_vbat"}, /* Reset clipper - Auto clear , */\ + { 0x50e0, "sel_vbat"}, /* Battery voltage read out , */\ + { 0x50f0, "bypass_clipper"}, /* Bypass battery safeguard , */\ + { 0x5100, "batsense_steepness"}, /* Vbat prot steepness , */\ + { 0x5110, "soft_mute"}, /* Soft mute HW , */\ + { 0x5150, "bypass_hp"}, /* Bypass HPF , */\ + { 0x5170, "enbl_dpsa"}, /* Enable DPSA , */\ + { 0x5222, "ctrl_cc"}, /* Clip control setting , */\ + { 0x5257, "gain"}, /* Amplifier gain , */\ + { 0x52d0, "ctrl_slopectrl"}, /* Enables slope control , */\ + { 0x52e0, "ctrl_slope"}, /* Slope speed setting (bin. coded) , */\ + { 0x5301, "dpsa_level"}, /* DPSA threshold levels , */\ + { 0x5321, "dpsa_release"}, /* DPSA Release time , */\ + { 0x5340, "clipfast"}, /* Clock selection for HW clipper for Battery Safeguard, */\ + { 0x5350, "bypass_lp"}, /* Bypass the low power filter inside temperature sensor, */\ + { 0x5400, "first_order_mode"}, /* Overrule to 1st order mode of control stage when clipping, */\ + { 0x5410, "bypass_ctrlloop"}, /* Switch amplifier into open loop configuration , */\ + { 0x5420, "fb_hz"}, /* Feedback resistor set to high ohmic , */\ + { 0x5430, "icomp_engage"}, /* Engage of icomp , */\ + { 0x5440, "ctrl_kickback"}, /* Prevent double pulses of output stage , */\ + { 0x5450, "icomp_engage_overrule"}, /* To overrule the functional icomp_engage signal during validation, */\ + { 0x5503, "ctrl_dem"}, /* Enable DEM icomp and DEM one bit dac , */\ + { 0x5543, "ctrl_dem_mismatch"}, /* Enable DEM icomp mismatch for testing , */\ + { 0x5582, "dpsa_drive"}, /* Drive setting (bin. coded) , */\ + { 0x570a, "enbl_amp"}, /* Switch on the class-D power sections, each part of the analog sections can be switched on/off individually, */\ + { 0x57b0, "enbl_engage"}, /* Enables/engage power stage and control loop , */\ + { 0x57c0, "enbl_engage_pst"}, /* Enables/engage power stage and control loop , */\ + { 0x5810, "hard_mute"}, /* Hard mute - PWM , */\ + { 0x5820, "pwm_shape"}, /* PWM shape , */\ + { 0x5844, "pwm_delay"}, /* PWM delay bits to set the delay, clockd is 1/(k*2048*fs), */\ + { 0x5890, "reclock_pwm"}, /* Reclock the pwm signal inside analog , */\ + { 0x58a0, "reclock_voltsense"}, /* Reclock the voltage sense pwm signal , */\ + { 0x58c0, "enbl_pwm_phase_shift"}, /* Control for pwm phase shift , */\ + { 0x6081, "pga_gain_set"}, /* PGA gain selection , */\ + { 0x60b0, "pga_lowpass_enable"}, /* Lowpass enable , */\ + { 0x60c0, "pga_pwr_enable"}, /* Power enable, directcontrol mode only , */\ + { 0x60d0, "pga_switch_enable"}, /* Switch enable, directcontrol mode only , */\ + { 0x60e0, "pga_switch_aux_enable"}, /* Switch enable aux, directcontrol mode only , */\ + { 0x6100, "force_idle"}, /* force low power in idle mode , */\ + { 0x6110, "bypass_idle"}, /* bypass low power idle mode , */\ + { 0x6123, "ctrl_attl"}, /* Second channel gain in case of stereo using a single coil. (Total gain depending on INPLEV). (In case of mono OR stereo using 2 separate DCDC channel 1 should be disabled using TDMDCE), */\ + { 0x6163, "ctrl_attr"}, /* Total gain depending on INPLEV setting (channel 0), */\ + { 0x61a0, "idle_cnt"}, /* idle counter , */\ + { 0x61b0, "enbl_idle_ch1"}, /* enable idle feature for channel 1 , */\ + { 0x6265, "zero_lvl"}, /* low noise gain switch zero trigger level , */\ + { 0x62c1, "ctrl_fb_classd"}, /* class D gain ctrl_fb_50k ctrl_fb_100k , */\ + { 0x62e1, "lownoisegain_mode"}, /* ctrl select mode , */\ + { 0x6305, "threshold_lvl"}, /* low noise gain switch trigger level , */\ + { 0x6365, "hold_time"}, /* ctrl hold time before low audio is reckoned to be low audio, */\ + { 0x6405, "lpm1_cal_offset"}, /* low power mode1 detector ctrl cal_offset from gain module , */\ + { 0x6465, "lpm1_zero_lvl"}, /* low power mode1 zero crossing detection level , */\ + { 0x64e1, "lpm1_mode"}, /* low power mode control , */\ + { 0x6505, "lpm1_threshold_lvl"}, /* low power mode1 amplitude trigger level , */\ + { 0x6565, "lpm1_hold_time"}, /* low power mode1 detector ctrl hold time before low audio is reckoned to be low audio, */\ + { 0x65c0, "disable_low_power_mode"}, /* low power mode1 detector control , */\ + { 0x6600, "dcdc_pfm20khz_limit"}, /* DCDC in PFM mode pwm mode is activated each 50us to force a pwm pulse, */\ + { 0x6611, "dcdc_ctrl_maxzercnt"}, /* DCDC. Number of zero current flags to count before going to pfm mode, */\ + { 0x6656, "dcdc_vbat_delta_detect"}, /* Threshold before booster is reacting on a delta Vbat (in PFM mode) by temporarily switching to PWM mode, */\ + { 0x66c0, "dcdc_ignore_vbat"}, /* Ignore an increase on Vbat , */\ + { 0x6700, "enbl_minion"}, /* Enables minion (small) power stage , */\ + { 0x6713, "vth_vddpvbat"}, /* select vddp-vbat thres signal , */\ + { 0x6750, "lpen_vddpvbat"}, /* select vddp-vbat filtred vs unfiltered compare , */\ + { 0x6801, "tdm_source_mapping"}, /* tdm source mapping , */\ + { 0x6821, "tdm_sourcea_frame_sel"}, /* Sensed value A , */\ + { 0x6841, "tdm_sourceb_frame_sel"}, /* Sensed value B , */\ + { 0x6881, "pdm_anc_sel"}, /* anc input , */\ + { 0x68a0, "anc_1scomplement"}, /* ANC one s complement , */\ + { 0x6901, "sam_mode"}, /* sam enable , */\ + { 0x6920, "sam_src"}, /* sam source , */\ + { 0x6931, "pdmdat_h_sel"}, /* pdm out value when pdm_clk is higth , */\ + { 0x6951, "pdmdat_l_sel"}, /* pdm out value when pdm_clk is low , */\ + { 0x6970, "sam_spkr_sel"}, /* ram output on mode sam and audio , */\ + { 0x6a02, "rst_min_vbat_delay"}, /* rst_min_vbat delay (nb fs) , */\ + { 0x6b00, "disable_auto_engage"}, /* disable auto engange , */\ + { 0x6b10, "sel_tdm_data_valid"}, /* select tdm valid for speaker subsystem , */\ + { 0x6c02, "ns_hp2ln_criterion"}, /* 0..7 zeroes at ns as threshold to swap from high_power to low_noise, */\ + { 0x6c32, "ns_ln2hp_criterion"}, /* 0..7 zeroes at ns as threshold to swap from low_noise to high_power, */\ + { 0x6c69, "spare_out"}, /* spare_out , */\ + { 0x6d0f, "spare_in"}, /* spare_in , */\ + { 0x6e00, "flag_lp_detect_mode0"}, /* low power mode 0 detection , */\ + { 0x6e10, "flag_lp_detect_mode1"}, /* low power mode 1 detection , */\ + { 0x6e20, "flag_low_amplitude"}, /* low amplitude detection , */\ + { 0x6e30, "flag_vddp_gt_vbat"}, /* vddp greater than vbat , */\ + { 0x6f02, "cursense_comp_delay"}, /* delay to allign compensation signal with current sense signal, */\ + { 0x6f40, "cursense_comp_sign"}, /* polarity of compensation for current sense , */\ + { 0x6f50, "enbl_cursense_comp"}, /* enable current sense compensation , */\ + { 0x6f60, "sel_clip_pwms"}, /* Select pwm clip flag , */\ + { 0x6f72, "pwms_clip_lvl"}, /* set the amount of pwm pulse that may be skipped before clip-flag is triggered, */\ + { 0x7002, "scnd_boost_voltage"}, /* Second boost voltage level , */\ + { 0x7033, "boost_cur"}, /* Max coil current , */\ + { 0x7071, "bst_slpcmplvl"}, /* Slope compensation current, represents LxF (inductance x frequency) value , */\ + { 0x7090, "boost_intel"}, /* Adaptive boost mode , */\ + { 0x70a0, "boost_speed"}, /* Soft ramp up/down , */\ + { 0x70e0, "dcdcoff_mode"}, /* DCDC on/off , */\ + { 0x70f0, "dcdc_pwmonly"}, /* DCDC PWM only mode , */\ + { 0x7104, "bst_drive"}, /* Binary coded drive setting for boost converter power stage, */\ + { 0x7151, "bst_scalecur"}, /* For testing direct control scale current , */\ + { 0x7174, "bst_slopecur"}, /* For testing direct control slope current , */\ + { 0x71c1, "bst_slope"}, /* Boost slope speed , */\ + { 0x71e0, "bst_bypass_bstcur"}, /* Bypass control for boost current settings , */\ + { 0x71f0, "bst_bypass_bstfoldback"}, /* Bypass control for boost foldback , */\ + { 0x7200, "enbl_bst_engage"}, /* Enable power stage dcdc controller , */\ + { 0x7210, "enbl_bst_hizcom"}, /* Enable hiz comparator , */\ + { 0x7220, "enbl_bst_peak2avg"}, /* Enable boost peak2avg functionality , */\ + { 0x7230, "enbl_bst_peakcur"}, /* Enable peak current , */\ + { 0x7240, "enbl_bst_power"}, /* Enable line of the powerstage , */\ + { 0x7250, "enbl_bst_slopecur"}, /* Enable bit of max-current dac , */\ + { 0x7260, "enbl_bst_voutcomp"}, /* Enable vout comparators , */\ + { 0x7270, "enbl_bst_voutcomp86"}, /* Enable vout-86 comparators , */\ + { 0x7280, "enbl_bst_voutcomp93"}, /* Enable vout-93 comparators , */\ + { 0x7290, "enbl_bst_windac"}, /* Enable window dac , */\ + { 0x72a5, "bst_windac"}, /* for testing direct control windac , */\ + { 0x7300, "boost_alg"}, /* Control for boost adaptive loop gain , */\ + { 0x7311, "boost_loopgain"}, /* DCDC boost loopgain setting , */\ + { 0x7331, "bst_freq"}, /* DCDC boost frequency control , */\ + { 0x7402, "frst_boost_voltage"}, /* 1st boost voltage level , */\ + { 0x7430, "boost_track"}, /* Boost algorithm selection, effective only when boost_intelligent is set to 1, */\ + { 0x7444, "boost_trip_lvl_1st"}, /* 1st Adaptive boost trip levels, effective only when DCIE is set to 1, */\ + { 0x7494, "boost_hold_time"}, /* Hold time for DCDC booster, effective only when boost_intelligent is set to 1, */\ + { 0x74e0, "sel_dcdc_envelope_8fs"}, /* Selection of data for adaptive boost algorithm, effective only when boost_intelligent is set to 1, */\ + { 0x74f0, "ignore_flag_voutcomp86"}, /* Ignore flag_voutcomp86 , */\ + { 0x7502, "track_decay"}, /* DCDC Boost decay speed after a peak value, effective only when boost_track is set to 1, */\ + { 0x7534, "boost_trip_lvl_2nd"}, /* 2nd Adaptive boost trip levels, effective only when DCIE is set to 1, */\ + { 0x7584, "boost_trip_lvl_track"}, /* Track Adaptive boost trip levels, effective only when boost_intelligent is set to 1, */\ + { 0x7620, "pga_test_ldo_bypass"}, /* bypass internal PGA LDO , */\ + { 0x8001, "sel_clk_cs"}, /* Current sense clock duty cycle control , */\ + { 0x8021, "micadc_speed"}, /* Current sense clock for MiCADC selection - 32/44.1/48 KHz Fs band only, */\ + { 0x8050, "cs_gain_control"}, /* Current sense gain control , */\ + { 0x8060, "cs_bypass_gc"}, /* Bypasses the CS gain correction , */\ + { 0x8087, "cs_gain"}, /* Current sense gain , */\ + { 0x8200, "enbl_cmfb"}, /* Current sense common mode feedback control , */\ + { 0x8210, "invertpwm"}, /* Current sense common mode feedback pwm invert control, */\ + { 0x8222, "cmfb_gain"}, /* Current sense common mode feedback control gain , */\ + { 0x8254, "cmfb_offset"}, /* Current sense common mode feedback control offset , */\ + { 0x82a0, "cs_sam_set"}, /* Enable SAM input for current sense , */\ + { 0x8305, "cs_ktemp"}, /* Current sense temperature compensation trimming (1 - VALUE*TEMP)*signal, */\ + { 0x8400, "cs_adc_bsoinv"}, /* Bitstream inversion for current sense ADC , */\ + { 0x8421, "cs_adc_hifreq"}, /* Frequency mode current sense ADC , */\ + { 0x8440, "cs_adc_nortz"}, /* Return to zero for current sense ADC , */\ + { 0x8453, "cs_adc_offset"}, /* Micadc ADC offset setting , */\ + { 0x8490, "cs_adc_slowdel"}, /* Select delay for current sense ADC (internal decision circuitry), */\ + { 0x84a4, "cs_adc_gain"}, /* Gain setting for current sense ADC (two's complement), */\ + { 0x8500, "cs_resonator_enable"}, /* Enable for resonator to improve SRN , */\ + { 0x8510, "cs_classd_tran_skip"}, /* Skip current sense connection during a classD amplifier transition, */\ + { 0x8530, "cs_inn_short"}, /* Short current sense negative to common mode , */\ + { 0x8540, "cs_inp_short"}, /* Short current sense positive to common mode , */\ + { 0x8550, "cs_ldo_bypass"}, /* Bypass current sense LDO , */\ + { 0x8560, "cs_ldo_pulldown"}, /* Pull down current sense LDO, only valid if left_enbl_cs_ldo is high, */\ + { 0x8574, "cs_ldo_voset"}, /* Current sense LDO voltage level setting (two's complement), */\ + { 0x8700, "enbl_cs_adc"}, /* Enable current sense ADC , */\ + { 0x8710, "enbl_cs_inn1"}, /* Enable connection of current sense negative1 , */\ + { 0x8720, "enbl_cs_inn2"}, /* Enable connection of current sense negative2 , */\ + { 0x8730, "enbl_cs_inp1"}, /* Enable connection of current sense positive1 , */\ + { 0x8740, "enbl_cs_inp2"}, /* Enable connection of current sense positive2 , */\ + { 0x8750, "enbl_cs_ldo"}, /* Enable current sense LDO , */\ + { 0x8760, "enbl_cs_nofloating_n"}, /* Connect current sense negative to gnda at transitions of booster or classd amplifiers. Otherwise floating (0), */\ + { 0x8770, "enbl_cs_nofloating_p"}, /* Connect current sense positive to gnda at transitions of booster or classd amplifiers. Otherwise floating (0), */\ + { 0x8780, "enbl_cs_vbatldo"}, /* Enable of current sense LDO , */\ + { 0x8800, "volsense_pwm_sel"}, /* Voltage sense PWM source selection control , */\ + { 0x8810, "vol_cur_sense_dc_offset"}, /* voltage and current sense decimator offset control, */\ + { 0xa007, "mtpkey1"}, /* 5Ah, 90d To access KEY1_Protected registers (Default for engineering), */\ + { 0xa107, "mtpkey2"}, /* MTP KEY2 register , */\ + { 0xa200, "key01_locked"}, /* Indicates KEY1 is locked , */\ + { 0xa210, "key02_locked"}, /* Indicates KEY2 is locked , */\ + { 0xa302, "mtp_man_address_in"}, /* MTP address from I2C register for read/writing mtp in manual single word mode, */\ + { 0xa330, "man_copy_mtp_to_iic"}, /* Start copying single word from mtp to I2C mtp register, */\ + { 0xa340, "man_copy_iic_to_mtp"}, /* Start copying single word from I2C mtp register to mtp, */\ + { 0xa350, "auto_copy_mtp_to_iic"}, /* Start copying all the data from mtp to I2C mtp registers, */\ + { 0xa360, "auto_copy_iic_to_mtp"}, /* Start copying data from I2C mtp registers to mtp , */\ + { 0xa400, "faim_set_clkws"}, /* Sets the faim controller clock wait state register, */\ + { 0xa410, "faim_sel_evenrows"}, /* All even rows of the faim are selected, active high, */\ + { 0xa420, "faim_sel_oddrows"}, /* All odd rows of the faim are selected, all rows in combination with sel_evenrows, */\ + { 0xa430, "faim_program_only"}, /* Skip the erase access at wr_faim command (write-program-marginread), */\ + { 0xa440, "faim_erase_only"}, /* Skip the program access at wr_faim command (write-erase-marginread), */\ + { 0xa50f, "mtp_man_data_out_msb"}, /* MSB word of MTP manual read data , */\ + { 0xa60f, "mtp_man_data_out_lsb"}, /* LSB word of MTP manual read data , */\ + { 0xa70f, "mtp_man_data_in_msb"}, /* MSB word of write data for MTP manual write , */\ + { 0xa80f, "mtp_man_data_in_lsb"}, /* LSB word of write data for MTP manual write , */\ + { 0xb010, "bypass_ocpcounter"}, /* Bypass OCP Counter , */\ + { 0xb020, "bypass_glitchfilter"}, /* Bypass glitch filter , */\ + { 0xb030, "bypass_ovp"}, /* Bypass OVP , */\ + { 0xb040, "bypass_uvp"}, /* Bypass UVP , */\ + { 0xb050, "bypass_otp"}, /* Bypass OTP , */\ + { 0xb060, "bypass_lost_clk"}, /* Bypass lost clock detector , */\ + { 0xb070, "ctrl_vpalarm"}, /* vpalarm (uvp ovp handling) , */\ + { 0xb087, "ocp_threshold"}, /* OCP threshold level , */\ + { 0xb108, "ext_temp"}, /* External temperature (C) , */\ + { 0xb190, "ext_temp_sel"}, /* Select temp Speaker calibration , */\ + { 0xc000, "use_direct_ctrls"}, /* Direct control to overrule several functions for testing, */\ + { 0xc010, "rst_datapath"}, /* Direct control for datapath reset , */\ + { 0xc020, "rst_cgu"}, /* Direct control for cgu reset , */\ + { 0xc038, "enbl_ref"}, /* Switch on the analog references, each part of the references can be switched on/off individually, */\ + { 0xc0d0, "enbl_ringo"}, /* Enable the ring oscillator for test purpose , */\ + { 0xc0e0, "use_direct_clk_ctrl"}, /* Direct clock control to overrule several functions for testing, */\ + { 0xc0f0, "use_direct_pll_ctrl"}, /* Direct PLL control to overrule several functions for testing, */\ + { 0xc100, "enbl_tsense"}, /* Temperature sensor enable control - I2C direct mode, */\ + { 0xc110, "tsense_hibias"}, /* Bit to set the biasing in temp sensor to high , */\ + { 0xc120, "enbl_flag_vbg"}, /* Enable flagging of bandgap out of control , */\ + { 0xc20f, "abist_offset"}, /* Offset control for ABIST testing (two's complement), */\ + { 0xc300, "bypasslatch"}, /* Bypass latch , */\ + { 0xc311, "sourcea"}, /* Set OUTA to , */\ + { 0xc331, "sourceb"}, /* Set OUTB to , */\ + { 0xc350, "inverta"}, /* Invert pwma test signal , */\ + { 0xc360, "invertb"}, /* Invert pwmb test signal , */\ + { 0xc374, "pulselength"}, /* Pulse length setting test input for amplifier (clock d - k*2048*fs), */\ + { 0xc3c0, "tdm_enable_loopback"}, /* TDM loopback test , */\ + { 0xc400, "bst_bypasslatch"}, /* Bypass latch in boost converter , */\ + { 0xc411, "bst_source"}, /* Sets the source of the pwmbst output to boost converter input for testing, */\ + { 0xc430, "bst_invertb"}, /* Invert pwmbst test signal , */\ + { 0xc444, "bst_pulselength"}, /* Pulse length setting test input for boost converter , */\ + { 0xc490, "test_bst_ctrlsthv"}, /* Test mode for boost control stage , */\ + { 0xc4a0, "test_bst_iddq"}, /* IDDQ testing in power stage of boost converter , */\ + { 0xc4b0, "test_bst_rdson"}, /* RDSON testing - boost power stage , */\ + { 0xc4c0, "test_bst_cvi"}, /* CVI testing - boost power stage , */\ + { 0xc4d0, "test_bst_ocp"}, /* Boost OCP. For old ocp (ctrl_reversebst is 0), For new ocp (ctrl_reversebst is 1), */\ + { 0xc4e0, "test_bst_sense"}, /* Test option for the sense NMOS in booster for current mode control., */\ + { 0xc500, "test_cvi"}, /* Analog BIST, switch choose which transistor will be used as current source (also cross coupled sources possible), */\ + { 0xc510, "test_discrete"}, /* Test function noise measurement , */\ + { 0xc520, "test_iddq"}, /* Set the power stages in iddq mode for gate stress., */\ + { 0xc540, "test_rdson"}, /* Analog BIST, switch to enable Rdson measurement , */\ + { 0xc550, "test_sdelta"}, /* Analog BIST, noise test , */\ + { 0xc570, "test_enbl_cs"}, /* Enable for digimux mode of current sense , */\ + { 0xc5b0, "pga_test_enable"}, /* Enable PGA test mode , */\ + { 0xc5c0, "pga_test_offset_enable"}, /* Enable PGA test offset , */\ + { 0xc5d0, "pga_test_shortinput_enable"}, /* Enable PGA test shortinput , */\ + { 0xc600, "enbl_pwm_dcc"}, /* Enables direct control of pwm duty cycle for DCDC power stage, */\ + { 0xc613, "pwm_dcc_cnt"}, /* Control pwm duty cycle when enbl_pwm_dcc is 1 , */\ + { 0xc650, "enbl_ldo_stress"}, /* Enable stress of internal supply voltages powerstages, */\ + { 0xc707, "digimuxa_sel"}, /* DigimuxA input selection control routed to DATAO (see Digimux list for details), */\ + { 0xc787, "digimuxb_sel"}, /* DigimuxB input selection control routed to INT (see Digimux list for details), */\ + { 0xc807, "digimuxc_sel"}, /* DigimuxC input selection control routed to PDMDAT (see Digimux list for details), */\ + { 0xc981, "int_ehs"}, /* Speed/load setting for INT IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ + { 0xc9c0, "hs_mode"}, /* I2C high speed mode control , */\ + { 0xca00, "enbl_anamux1"}, /* Enable anamux1 , */\ + { 0xca10, "enbl_anamux2"}, /* Enable anamux2 , */\ + { 0xca20, "enbl_anamux3"}, /* Enable anamux3 , */\ + { 0xca30, "enbl_anamux4"}, /* Enable anamux4 , */\ + { 0xca74, "anamux1"}, /* Anamux selection control - anamux on TEST1 , */\ + { 0xcb04, "anamux2"}, /* Anamux selection control - anamux on TEST2 , */\ + { 0xcb54, "anamux3"}, /* Anamux selection control - anamux on TEST3 , */\ + { 0xcba4, "anamux4"}, /* Anamux selection control - anamux on TEST4 , */\ + { 0xcd05, "pll_seli"}, /* PLL SELI - I2C direct PLL control mode only , */\ + { 0xcd64, "pll_selp"}, /* PLL SELP - I2C direct PLL control mode only , */\ + { 0xcdb3, "pll_selr"}, /* PLL SELR - I2C direct PLL control mode only , */\ + { 0xcdf0, "pll_frm"}, /* PLL free running mode control; 1 in TCB direct control mode, else this control bit, */\ + { 0xce09, "pll_ndec"}, /* PLL NDEC - I2C direct PLL control mode only , */\ + { 0xcea0, "pll_mdec_msb"}, /* MSB of pll_mdec - I2C direct PLL control mode only, */\ + { 0xceb0, "enbl_pll"}, /* Enables PLL in I2C direct PLL control mode only , */\ + { 0xcec0, "enbl_osc"}, /* Enables OSC1M in I2C direct control mode only , */\ + { 0xced0, "pll_bypass"}, /* PLL bypass control in I2C direct PLL control mode only, */\ + { 0xcee0, "pll_directi"}, /* PLL directi control in I2C direct PLL control mode only, */\ + { 0xcef0, "pll_directo"}, /* PLL directo control in I2C direct PLL control mode only, */\ + { 0xcf0f, "pll_mdec_lsb"}, /* Bits 15..0 of PLL MDEC are I2C direct PLL control mode only, */\ + { 0xd006, "pll_pdec"}, /* PLL PDEC - I2C direct PLL control mode only , */\ + { 0xd10f, "tsig_freq_lsb"}, /* Internal sinus test generator frequency control , */\ + { 0xd202, "tsig_freq_msb"}, /* Select internal sinus test generator, frequency control msb bits, */\ + { 0xd230, "inject_tsig"}, /* Control bit to switch to internal sinus test generator, */\ + { 0xd283, "tsig_gain"}, /* Test signal gain , */\ + { 0xd300, "adc10_reset"}, /* Reset for ADC10 - I2C direct control mode , */\ + { 0xd311, "adc10_test"}, /* Test mode selection signal for ADC10 - I2C direct control mode, */\ + { 0xd332, "adc10_sel"}, /* Select the input to convert for ADC10 - I2C direct control mode, */\ + { 0xd364, "adc10_prog_sample"}, /* ADC10 program sample setting - I2C direct control mode, */\ + { 0xd3b0, "adc10_enbl"}, /* Enable ADC10 - I2C direct control mode , */\ + { 0xd3c0, "bypass_lp_vbat"}, /* Bypass control for Low pass filter in batt sensor , */\ + { 0xd409, "data_adc10_tempbat"}, /* ADC 10 data output data for testing , */\ + { 0xd507, "ctrl_digtoana_hidden"}, /* Spare digital to analog control bits - Hidden , */\ + { 0xd580, "enbl_clk_out_of_range"}, /* Clock out of range , */\ + { 0xd621, "clkdiv_audio_sel"}, /* Audio clock divider selection in direct clock control mode, */\ + { 0xd641, "clkdiv_muxa_sel"}, /* DCDC MUXA clock divider selection in direct clock control mode, */\ + { 0xd661, "clkdiv_muxb_sel"}, /* DCDC MUXB clock divider selection in direct clock control mode, */\ + { 0xd701, "pdmdat_ehs"}, /* Speed/load setting for PDMDAT IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ + { 0xd721, "datao_ehs"}, /* Speed/load setting for DATAO IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ + { 0xd740, "bck_ehs"}, /* Speed/load setting for DATAO IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ + { 0xd750, "datai_ehs"}, /* Speed/load setting for DATAO IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ + { 0xd760, "pdmclk_ehs"}, /* Speed/load setting for DATAO IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ + { 0xd800, "source_in_testmode"}, /* tdm source in test mode (return only current and voltage sense), */\ + { 0xd810, "gainatt_feedback"}, /* gainatt feedback to tdm , */\ + { 0xd822, "test_parametric_io"}, /* test io parametric , */\ + { 0xd850, "ctrl_bst_clk_lp1"}, /* boost clock control in low power mode1 , */\ + { 0xd861, "test_spare_out1"}, /* test spare out 1 , */\ + { 0xd880, "bst_dcmbst"}, /* dcm boost , */\ + { 0xd890, "pdm_loopback"}, /* pdm loop back to tdm , */\ + { 0xd8a1, "force_pga_clock"}, /* force pga clock , */\ + { 0xd8c3, "test_spare_out2"}, /* test spare out 1 , */\ + { 0xee0f, "sw_profile"}, /* Software profile data , */\ + { 0xef0f, "sw_vstep"}, /* Software vstep information , */\ + { 0xf000, "calibration_onetime"}, /* Calibration schedule , */\ + { 0xf010, "calibr_ron_done"}, /* Calibration Ron executed , */\ + { 0xf020, "calibr_dcdc_api_calibrate"}, /* Calibration current limit DCDC , */\ + { 0xf030, "calibr_dcdc_delta_sign"}, /* Sign bit for delta calibration current limit DCDC , */\ + { 0xf042, "calibr_dcdc_delta"}, /* Calibration delta current limit DCDC , */\ + { 0xf078, "calibr_speaker_info"}, /* Reserved space for allowing customer to store speaker information, */\ + { 0xf105, "calibr_vout_offset"}, /* DCDC offset calibration 2's complement (key1 protected), */\ + { 0xf163, "spare_mpt1_9_6"}, /* HW gain module - left channel (2's complement) , */\ + { 0xf1a5, "spare_mpt1_15_10"}, /* Offset for amplifier, HW gain module - left channel (2's complement), */\ + { 0xf203, "calibr_gain"}, /* HW gain module (2's complement) , */\ + { 0xf245, "calibr_offset"}, /* Offset for amplifier, HW gain module (2's complement), */\ + { 0xf2a3, "spare_mpt2_13_10"}, /* Trimming of LDO (2.7V) , */\ + { 0xf307, "spare_mpt3_7_0"}, /* SPARE , */\ + { 0xf387, "calibr_gain_cs"}, /* Current sense gain (signed two's complement format), */\ + { 0xf40f, "spare_mtp4_15_0"}, /* SPARE , */\ + { 0xf50f, "calibr_R25C_R"}, /* Ron resistance of speaker coil , */\ + { 0xf606, "spare_mpt6_6_0"}, /* SPARE , */\ + { 0xf686, "spare_mpt6_14_8"}, /* Offset of left amplifier level shifter B , */\ + { 0xf706, "ctrl_offset_a"}, /* Offset of level shifter A , */\ + { 0xf786, "ctrl_offset_b"}, /* Offset of amplifier level shifter B , */\ + { 0xf806, "htol_iic_addr"}, /* 7-bit I2C address to be used during HTOL testing , */\ + { 0xf870, "htol_iic_addr_en"}, /* HTOL I2C address enable control , */\ + { 0xf884, "calibr_temp_offset"}, /* Temperature offset 2's compliment (key1 protected), */\ + { 0xf8d2, "calibr_temp_gain"}, /* Temperature gain 2's compliment (key1 protected) , */\ + { 0xf900, "mtp_lock_dcdcoff_mode"}, /* Disable function dcdcoff_mode , */\ + { 0xf910, "disable_sam_mode"}, /* Disable same mode , */\ + { 0xf920, "mtp_lock_bypass_clipper"}, /* Disable function bypass_clipper , */\ + { 0xf930, "mtp_lock_max_dcdc_voltage"}, /* Disable programming of max dcdc boost voltage , */\ + { 0xf943, "calibr_vbg_trim"}, /* Bandgap trimming control , */\ + { 0xf980, "mtp_enbl_amp_in_state_alarm"}, /* Enbl_amp in alarm state , */\ + { 0xf990, "mtp_enbl_pwm_delay_clock_gating"}, /* pwm delay clock auto gating , */\ + { 0xf9a0, "mtp_enbl_ocp_clock_gating"}, /* ocpclock auto gating , */\ + { 0xf9b0, "mtp_gate_cgu_clock_for_test"}, /* cgu test clock control , */\ + { 0xf9c3, "spare_mtp9_15_12"}, /* MTP-control FW - See Firmware I2C API document for details, */\ + { 0xfa0f, "mtpdataA"}, /* MTPdataA (key1 protected) , */\ + { 0xfb0f, "mtpdataB"}, /* MTPdataB (key1 protected) , */\ + { 0xfc0f, "mtpdataC"}, /* MTPdataC (key1 protected) , */\ + { 0xfd0f, "mtpdataD"}, /* MTPdataD (key1 protected) , */\ + { 0xfe0f, "mtpdataE"}, /* MTPdataE (key1 protected) , */\ + { 0xff07, "calibr_osc_delta_ndiv"}, /* Calibration data for OSC1M, signed number representation, */\ + { 0xffff,"Unknown bitfield enum" } /* not found */\ +}; + +enum TFA9872_irq { + TFA9872_irq_stvdds = 0, + TFA9872_irq_stplls = 1, + TFA9872_irq_stotds = 2, + TFA9872_irq_stovds = 3, + TFA9872_irq_stuvds = 4, + TFA9872_irq_stclks = 5, + TFA9872_irq_stmtpb = 6, + TFA9872_irq_stnoclk = 7, + TFA9872_irq_stsws = 10, + TFA9872_irq_stamps = 12, + TFA9872_irq_starefs = 13, + TFA9872_irq_stadccr = 14, + TFA9872_irq_stbstcu = 16, + TFA9872_irq_stbsthi = 17, + TFA9872_irq_stbstoc = 18, + TFA9872_irq_stbstpkcur = 19, + TFA9872_irq_stbstvc = 20, + TFA9872_irq_stbst86 = 21, + TFA9872_irq_stbst93 = 22, + TFA9872_irq_stocpr = 25, + TFA9872_irq_stmwsrc = 26, + TFA9872_irq_stmwsmu = 28, + TFA9872_irq_stclkoor = 31, + TFA9872_irq_sttdmer = 32, + TFA9872_irq_stclpr = 34, + TFA9872_irq_stlp0 = 36, + TFA9872_irq_stlp1 = 37, + TFA9872_irq_stla = 38, + TFA9872_irq_stvddph = 39, + TFA9872_irq_max = 40, + TFA9872_irq_all = -1 /* all irqs */}; + +#define TFA9872_IRQ_NAMETABLE static tfaIrqName_t Tfa9872IrqNames[]= {\ + { 0, "STVDDS"},\ + { 1, "STPLLS"},\ + { 2, "STOTDS"},\ + { 3, "STOVDS"},\ + { 4, "STUVDS"},\ + { 5, "STCLKS"},\ + { 6, "STMTPB"},\ + { 7, "STNOCLK"},\ + { 8, "8"},\ + { 9, "9"},\ + { 10, "STSWS"},\ + { 11, "11"},\ + { 12, "STAMPS"},\ + { 13, "STAREFS"},\ + { 14, "STADCCR"},\ + { 15, "15"},\ + { 16, "STBSTCU"},\ + { 17, "STBSTHI"},\ + { 18, "STBSTOC"},\ + { 19, "STBSTPKCUR"},\ + { 20, "STBSTVC"},\ + { 21, "STBST86"},\ + { 22, "STBST93"},\ + { 23, "23"},\ + { 24, "24"},\ + { 25, "STOCPR"},\ + { 26, "STMWSRC"},\ + { 27, "27"},\ + { 28, "STMWSMU"},\ + { 29, "29"},\ + { 30, "30"},\ + { 31, "STCLKOOR"},\ + { 32, "STTDMER"},\ + { 33, "33"},\ + { 34, "STCLPR"},\ + { 35, "35"},\ + { 36, "STLP0"},\ + { 37, "STLP1"},\ + { 38, "STLA"},\ + { 39, "STVDDPH"},\ + { 40, "40"},\ +}; +#endif /* _TFA9872_TFAFIELDNAMES_H */ diff --git a/techpack/audio/asoc/codecs/tfa9874/tfa9874_tfafieldnames.h b/techpack/audio/asoc/codecs/tfa9874/tfa9874_tfafieldnames.h new file mode 100644 index 000000000000..72c155418810 --- /dev/null +++ b/techpack/audio/asoc/codecs/tfa9874/tfa9874_tfafieldnames.h @@ -0,0 +1,830 @@ +/** Filename: tfa9874_tfafieldnames.h + * This file was generated automatically on 08/22/17 at 13:43:43. + * Source file: TFA9874N1C0_DefaultI2CSettings.xlsx + */ + +#ifndef _TFA9874_TFAFIELDNAMES_H +#define _TFA9874_TFAFIELDNAMES_H + + +#define TFA9874_I2CVERSION 1 + +typedef enum nxpTfa9874BfEnumList { + TFA9874_BF_PWDN = 0x0000, /*!< Powerdown selection */ + TFA9874_BF_I2CR = 0x0010, /*!< I2C Reset - Auto clear */ + TFA9874_BF_AMPE = 0x0030, /*!< Activate Amplifier */ + TFA9874_BF_DCA = 0x0040, /*!< Activate DC-to-DC converter */ + TFA9874_BF_INTP = 0x0071, /*!< Interrupt config */ + TFA9874_BF_BYPOCP= 0x00b0, /*!< Bypass OCP */ + TFA9874_BF_TSTOCP= 0x00c0, /*!< OCP testing control */ + TFA9874_BF_MANSCONF= 0x0120, /*!< I2C configured */ + TFA9874_BF_MANAOOSC= 0x0140, /*!< Internal osc off at PWDN */ + TFA9874_BF_MUTETO= 0x01d0, /*!< Time out SB mute sequence */ + TFA9874_BF_OPENMTP= 0x01e0, /*!< Control for FAIM protection */ + TFA9874_BF_AUDFS = 0x0203, /*!< Sample rate (fs) */ + TFA9874_BF_INPLEV= 0x0240, /*!< TDM output attenuation */ + TFA9874_BF_FRACTDEL= 0x0255, /*!< V/I Fractional delay */ + TFA9874_BF_REV = 0x030f, /*!< Revision info */ + TFA9874_BF_REFCKEXT= 0x0401, /*!< PLL external ref clock */ + TFA9874_BF_REFCKSEL= 0x0420, /*!< PLL internal ref clock */ + TFA9874_BF_SSFAIME= 0x05c0, /*!< Sub-system FAIM */ + TFA9874_BF_AMPOCRT= 0x0802, /*!< Amplifier on-off criteria for shutdown */ + TFA9874_BF_VDDS = 0x1000, /*!< POR */ + TFA9874_BF_DCOCPOK= 0x1010, /*!< DCDC OCP nmos (sticky register , clear on read) */ + TFA9874_BF_OTDS = 0x1020, /*!< OTP alarm (sticky register , clear on read) */ + TFA9874_BF_OCDS = 0x1030, /*!< OCP amplifier (sticky register , clear on read) */ + TFA9874_BF_UVDS = 0x1040, /*!< UVP alarm (sticky register , clear on read) */ + TFA9874_BF_MANALARM= 0x1050, /*!< Alarm state */ + TFA9874_BF_TDMERR= 0x1060, /*!< TDM error */ + TFA9874_BF_NOCLK = 0x1070, /*!< Lost clock (sticky register , clear on read) */ + TFA9874_BF_DCIL = 0x1100, /*!< DCDC current limiting */ + TFA9874_BF_DCDCA = 0x1110, /*!< DCDC active (sticky register , clear on read) */ + TFA9874_BF_DCHVBAT= 0x1130, /*!< DCDC level 1x */ + TFA9874_BF_DCH114= 0x1140, /*!< DCDC level 1.14x */ + TFA9874_BF_DCH107= 0x1150, /*!< DCDC level 1.07x */ + TFA9874_BF_PLLS = 0x1160, /*!< PLL lock */ + TFA9874_BF_CLKS = 0x1170, /*!< Clocks stable */ + TFA9874_BF_TDMLUTER= 0x1180, /*!< TDM LUT error */ + TFA9874_BF_TDMSTAT= 0x1192, /*!< TDM status bits */ + TFA9874_BF_MTPB = 0x11c0, /*!< MTP busy */ + TFA9874_BF_SWS = 0x11d0, /*!< Amplifier engage */ + TFA9874_BF_AMPS = 0x11e0, /*!< Amplifier enable */ + TFA9874_BF_AREFS = 0x11f0, /*!< References enable */ + TFA9874_BF_OCPOAP= 0x1300, /*!< OCPOK pmos A */ + TFA9874_BF_OCPOAN= 0x1310, /*!< OCPOK nmos A */ + TFA9874_BF_OCPOBP= 0x1320, /*!< OCPOK pmos B */ + TFA9874_BF_OCPOBN= 0x1330, /*!< OCPOK nmos B */ + TFA9874_BF_OVDS = 0x1380, /*!< OVP alarm */ + TFA9874_BF_CLIPS = 0x1390, /*!< Amplifier clipping */ + TFA9874_BF_ADCCR = 0x13a0, /*!< Control ADC */ + TFA9874_BF_MANWAIT1= 0x13c0, /*!< Wait HW I2C settings */ + TFA9874_BF_MANMUTE= 0x13e0, /*!< Audio mute sequence */ + TFA9874_BF_MANOPER= 0x13f0, /*!< Operating state */ + TFA9874_BF_CLKOOR= 0x1420, /*!< External clock status */ + TFA9874_BF_MANSTATE= 0x1433, /*!< Device manager status */ + TFA9874_BF_DCMODE= 0x1471, /*!< DCDC mode status bits */ + TFA9874_BF_BATS = 0x1509, /*!< Battery voltage (V) */ + TFA9874_BF_TEMPS = 0x1608, /*!< IC Temperature (C) */ + TFA9874_BF_VDDPS = 0x1709, /*!< IC VDDP voltage ( 1023*VDDP/13 V) */ + TFA9874_BF_TDME = 0x2040, /*!< Enable interface */ + TFA9874_BF_TDMMODE= 0x2050, /*!< Slave/master */ + TFA9874_BF_TDMCLINV= 0x2060, /*!< Reception data to BCK clock */ + TFA9874_BF_TDMFSLN= 0x2073, /*!< FS length (master mode only) */ + TFA9874_BF_TDMFSPOL= 0x20b0, /*!< FS polarity */ + TFA9874_BF_TDMNBCK= 0x20c3, /*!< N-BCK's in FS */ + TFA9874_BF_TDMSLOTS= 0x2103, /*!< N-slots in Frame */ + TFA9874_BF_TDMSLLN= 0x2144, /*!< N-bits in slot */ + TFA9874_BF_TDMBRMG= 0x2194, /*!< N-bits remaining */ + TFA9874_BF_TDMDEL= 0x21e0, /*!< data delay to FS */ + TFA9874_BF_TDMADJ= 0x21f0, /*!< data adjustment */ + TFA9874_BF_TDMOOMP= 0x2201, /*!< Received audio compression */ + TFA9874_BF_TDMSSIZE= 0x2224, /*!< Sample size per slot */ + TFA9874_BF_TDMTXDFO= 0x2271, /*!< Format unused bits */ + TFA9874_BF_TDMTXUS0= 0x2291, /*!< Format unused slots DATAO */ + TFA9874_BF_TDMSPKE= 0x2300, /*!< Control audio tdm channel in 0 (spkr + dcdc) */ + TFA9874_BF_TDMDCE= 0x2310, /*!< Control audio tdm channel in 1 (dcdc) */ + TFA9874_BF_TDMCSE= 0x2330, /*!< current sense vbat temperature and vddp feedback */ + TFA9874_BF_TDMVSE= 0x2340, /*!< Voltage sense vbat temperature and vddp feedback */ + TFA9874_BF_TDMSPKS= 0x2603, /*!< tdm slot for sink 0 (speaker + dcdc) */ + TFA9874_BF_TDMDCS= 0x2643, /*!< tdm slot for sink 1 (dcdc) */ + TFA9874_BF_TDMCSS= 0x26c3, /*!< Slot Position of current sense vbat temperature and vddp feedback */ + TFA9874_BF_TDMVSS= 0x2703, /*!< Slot Position of Voltage sense vbat temperature and vddp feedback */ + TFA9874_BF_ISTVDDS= 0x4000, /*!< Status POR */ + TFA9874_BF_ISTBSTOC= 0x4010, /*!< Status DCDC OCP */ + TFA9874_BF_ISTOTDS= 0x4020, /*!< Status OTP alarm */ + TFA9874_BF_ISTOCPR= 0x4030, /*!< Status ocp alarm */ + TFA9874_BF_ISTUVDS= 0x4040, /*!< Status UVP alarm */ + TFA9874_BF_ISTMANALARM= 0x4050, /*!< Status nanager Alarm state */ + TFA9874_BF_ISTTDMER= 0x4060, /*!< Status tdm error */ + TFA9874_BF_ISTNOCLK= 0x4070, /*!< Status lost clock */ + TFA9874_BF_ICLVDDS= 0x4400, /*!< Clear POR */ + TFA9874_BF_ICLBSTOC= 0x4410, /*!< Clear DCDC OCP */ + TFA9874_BF_ICLOTDS= 0x4420, /*!< Clear OTP alarm */ + TFA9874_BF_ICLOCPR= 0x4430, /*!< Clear ocp alarm */ + TFA9874_BF_ICLUVDS= 0x4440, /*!< Clear UVP alarm */ + TFA9874_BF_ICLMANALARM= 0x4450, /*!< clear nanager Alarm state */ + TFA9874_BF_ICLTDMER= 0x4460, /*!< Clear tdm error */ + TFA9874_BF_ICLNOCLK= 0x4470, /*!< Clear lost clk */ + TFA9874_BF_IEVDDS= 0x4800, /*!< Enable por */ + TFA9874_BF_IEBSTOC= 0x4810, /*!< Enable DCDC OCP */ + TFA9874_BF_IEOTDS= 0x4820, /*!< Enable OTP alarm */ + TFA9874_BF_IEOCPR= 0x4830, /*!< Enable ocp alarm */ + TFA9874_BF_IEUVDS= 0x4840, /*!< Enable UVP alarm */ + TFA9874_BF_IEMANALARM= 0x4850, /*!< Enable nanager Alarm state */ + TFA9874_BF_IETDMER= 0x4860, /*!< Enable tdm error */ + TFA9874_BF_IENOCLK= 0x4870, /*!< Enable lost clk */ + TFA9874_BF_IPOVDDS= 0x4c00, /*!< Polarity por */ + TFA9874_BF_IPOBSTOC= 0x4c10, /*!< Polarity DCDC OCP */ + TFA9874_BF_IPOOTDS= 0x4c20, /*!< Polarity OTP alarm */ + TFA9874_BF_IPOOCPR= 0x4c30, /*!< Polarity ocp alarm */ + TFA9874_BF_IPOUVDS= 0x4c40, /*!< Polarity UVP alarm */ + TFA9874_BF_IPOMANALARM= 0x4c50, /*!< Polarity nanager Alarm state */ + TFA9874_BF_IPOTDMER= 0x4c60, /*!< Polarity tdm error */ + TFA9874_BF_IPONOCLK= 0x4c70, /*!< Polarity lost clk */ + TFA9874_BF_BSSCR = 0x5001, /*!< Battery Safeguard attack time */ + TFA9874_BF_BSST = 0x5023, /*!< Battery Safeguard threshold voltage level */ + TFA9874_BF_BSSRL = 0x5061, /*!< Battery Safeguard maximum reduction */ + TFA9874_BF_VBATFLTL= 0x5080, /*!< vbat filter limit */ + TFA9874_BF_BSSR = 0x50e0, /*!< Battery voltage read out */ + TFA9874_BF_BSSBY = 0x50f0, /*!< Bypass battery safeguard */ + TFA9874_BF_BSSS = 0x5100, /*!< Vbat prot steepness */ + TFA9874_BF_HPFBYP= 0x5150, /*!< Bypass HPF */ + TFA9874_BF_DPSA = 0x5170, /*!< Enable DPSA */ + TFA9874_BF_CLIPCTRL= 0x5222, /*!< Clip control setting */ + TFA9874_BF_AMPGAIN= 0x5257, /*!< Amplifier gain */ + TFA9874_BF_SLOPEE= 0x52d0, /*!< Enables slope control */ + TFA9874_BF_SLOPESET= 0x52e0, /*!< Slope speed setting (bin. coded) */ + TFA9874_BF_TDMDCG= 0x6123, /*!< Second channel gain in case of stereo using a single coil. (Total gain depending on INPLEV). (In case of mono OR stereo using 2 separate DCDC channel 1 should be disabled using TDMDCE) */ + TFA9874_BF_TDMSPKG= 0x6163, /*!< Total gain depending on INPLEV setting (channel 0) */ + TFA9874_BF_LNMODE= 0x62e1, /*!< ctrl select mode */ + TFA9874_BF_LPM1MODE= 0x64e1, /*!< low power mode control */ + TFA9874_BF_TDMSRCMAP= 0x6802, /*!< tdm source mapping */ + TFA9874_BF_TDMSRCAS= 0x6831, /*!< Sensed value A */ + TFA9874_BF_TDMSRCBS= 0x6851, /*!< Sensed value B */ + TFA9874_BF_TDMSRCACLIP= 0x6871, /*!< clip information (analog /digital) for source0 */ + TFA9874_BF_TDMSRCBCLIP= 0x6891, /*!< clip information (analog /digital) for source1 */ + TFA9874_BF_LP1 = 0x6e10, /*!< low power mode 1 detection */ + TFA9874_BF_LA = 0x6e20, /*!< low amplitude detection */ + TFA9874_BF_VDDPH = 0x6e30, /*!< vddp greater than vbat */ + TFA9874_BF_DELCURCOMP= 0x6f02, /*!< delay to allign compensation signal with current sense signal */ + TFA9874_BF_SIGCURCOMP= 0x6f40, /*!< polarity of compensation for current sense */ + TFA9874_BF_ENCURCOMP= 0x6f50, /*!< enable current sense compensation */ + TFA9874_BF_LVLCLPPWM= 0x6f72, /*!< set the amount of pwm pulse that may be skipped before clip-flag is triggered */ + TFA9874_BF_DCMCC = 0x7033, /*!< Max coil current */ + TFA9874_BF_DCCV = 0x7071, /*!< Slope compensation current, represents LxF (inductance x frequency) value */ + TFA9874_BF_DCIE = 0x7090, /*!< Adaptive boost mode */ + TFA9874_BF_DCSR = 0x70a0, /*!< Soft ramp up/down */ + TFA9874_BF_DCDIS = 0x70e0, /*!< DCDC on/off */ + TFA9874_BF_DCPWM = 0x70f0, /*!< DCDC PWM only mode */ + TFA9874_BF_DCTRACK= 0x7430, /*!< Boost algorithm selection, effective only when boost_intelligent is set to 1 */ + TFA9874_BF_DCTRIP= 0x7444, /*!< 1st Adaptive boost trip levels, effective only when DCIE is set to 1 */ + TFA9874_BF_DCHOLD= 0x7494, /*!< Hold time for DCDC booster, effective only when boost_intelligent is set to 1 */ + TFA9874_BF_DCTRIP2= 0x7534, /*!< 2nd Adaptive boost trip levels, effective only when DCIE is set to 1 */ + TFA9874_BF_DCTRIPT= 0x7584, /*!< Track Adaptive boost trip levels, effective only when boost_intelligent is set to 1 */ + TFA9874_BF_DCTRIPHYSTE= 0x75f0, /*!< Enable hysteresis on booster trip levels */ + TFA9874_BF_DCVOF = 0x7635, /*!< First boost voltage level */ + TFA9874_BF_DCVOS = 0x7695, /*!< Second boost voltage level */ + TFA9874_BF_MTPK = 0xa107, /*!< MTP KEY2 register */ + TFA9874_BF_KEY1LOCKED= 0xa200, /*!< Indicates KEY1 is locked */ + TFA9874_BF_KEY2LOCKED= 0xa210, /*!< Indicates KEY2 is locked */ + TFA9874_BF_CIMTP = 0xa360, /*!< Start copying data from I2C mtp registers to mtp */ + TFA9874_BF_MTPRDMSB= 0xa50f, /*!< MSB word of MTP manual read data */ + TFA9874_BF_MTPRDLSB= 0xa60f, /*!< LSB word of MTP manual read data */ + TFA9874_BF_EXTTS = 0xb108, /*!< External temperature (C) */ + TFA9874_BF_TROS = 0xb190, /*!< Select temp Speaker calibration */ + TFA9874_BF_SWPROFIL= 0xee0f, /*!< Software profile data */ + TFA9874_BF_SWVSTEP= 0xef0f, /*!< Software vstep information */ + TFA9874_BF_MTPOTC= 0xf000, /*!< Calibration schedule */ + TFA9874_BF_MTPEX = 0xf010, /*!< Calibration Ron executed */ + TFA9874_BF_DCMCCAPI= 0xf020, /*!< Calibration current limit DCDC */ + TFA9874_BF_DCMCCSB= 0xf030, /*!< Sign bit for delta calibration current limit DCDC */ + TFA9874_BF_USERDEF= 0xf042, /*!< Calibration delta current limit DCDC */ + TFA9874_BF_CUSTINFO= 0xf078, /*!< Reserved space for allowing customer to store speaker information */ + TFA9874_BF_R25C = 0xf50f, /*!< Ron resistance of speaker coil */ +} nxpTfa9874BfEnumList_t; +#define TFA9874_NAMETABLE static tfaBfName_t Tfa9874DatasheetNames[]= {\ + { 0x0, "PWDN"}, /* Powerdown selection , */\ + { 0x10, "I2CR"}, /* I2C Reset - Auto clear , */\ + { 0x30, "AMPE"}, /* Activate Amplifier , */\ + { 0x40, "DCA"}, /* Activate DC-to-DC converter , */\ + { 0x71, "INTP"}, /* Interrupt config , */\ + { 0xb0, "BYPOCP"}, /* Bypass OCP , */\ + { 0xc0, "TSTOCP"}, /* OCP testing control , */\ + { 0x120, "MANSCONF"}, /* I2C configured , */\ + { 0x140, "MANAOOSC"}, /* Internal osc off at PWDN , */\ + { 0x1d0, "MUTETO"}, /* Time out SB mute sequence , */\ + { 0x1e0, "OPENMTP"}, /* Control for FAIM protection , */\ + { 0x203, "AUDFS"}, /* Sample rate (fs) , */\ + { 0x240, "INPLEV"}, /* TDM output attenuation , */\ + { 0x255, "FRACTDEL"}, /* V/I Fractional delay , */\ + { 0x30f, "REV"}, /* Revision info , */\ + { 0x401, "REFCKEXT"}, /* PLL external ref clock , */\ + { 0x420, "REFCKSEL"}, /* PLL internal ref clock , */\ + { 0x5c0, "SSFAIME"}, /* Sub-system FAIM , */\ + { 0x802, "AMPOCRT"}, /* Amplifier on-off criteria for shutdown , */\ + { 0x1000, "VDDS"}, /* POR , */\ + { 0x1010, "DCOCPOK"}, /* DCDC OCP nmos (sticky register , clear on read) , */\ + { 0x1020, "OTDS"}, /* OTP alarm (sticky register , clear on read) , */\ + { 0x1030, "OCDS"}, /* OCP amplifier (sticky register , clear on read), */\ + { 0x1040, "UVDS"}, /* UVP alarm (sticky register , clear on read) , */\ + { 0x1050, "MANALARM"}, /* Alarm state , */\ + { 0x1060, "TDMERR"}, /* TDM error , */\ + { 0x1070, "NOCLK"}, /* Lost clock (sticky register , clear on read) , */\ + { 0x1100, "DCIL"}, /* DCDC current limiting , */\ + { 0x1110, "DCDCA"}, /* DCDC active (sticky register , clear on read) , */\ + { 0x1130, "DCHVBAT"}, /* DCDC level 1x , */\ + { 0x1140, "DCH114"}, /* DCDC level 1.14x , */\ + { 0x1150, "DCH107"}, /* DCDC level 1.07x , */\ + { 0x1160, "PLLS"}, /* PLL lock , */\ + { 0x1170, "CLKS"}, /* Clocks stable , */\ + { 0x1180, "TDMLUTER"}, /* TDM LUT error , */\ + { 0x1192, "TDMSTAT"}, /* TDM status bits , */\ + { 0x11c0, "MTPB"}, /* MTP busy , */\ + { 0x11d0, "SWS"}, /* Amplifier engage , */\ + { 0x11e0, "AMPS"}, /* Amplifier enable , */\ + { 0x11f0, "AREFS"}, /* References enable , */\ + { 0x1300, "OCPOAP"}, /* OCPOK pmos A , */\ + { 0x1310, "OCPOAN"}, /* OCPOK nmos A , */\ + { 0x1320, "OCPOBP"}, /* OCPOK pmos B , */\ + { 0x1330, "OCPOBN"}, /* OCPOK nmos B , */\ + { 0x1380, "OVDS"}, /* OVP alarm , */\ + { 0x1390, "CLIPS"}, /* Amplifier clipping , */\ + { 0x13a0, "ADCCR"}, /* Control ADC , */\ + { 0x13c0, "MANWAIT1"}, /* Wait HW I2C settings , */\ + { 0x13e0, "MANMUTE"}, /* Audio mute sequence , */\ + { 0x13f0, "MANOPER"}, /* Operating state , */\ + { 0x1420, "CLKOOR"}, /* External clock status , */\ + { 0x1433, "MANSTATE"}, /* Device manager status , */\ + { 0x1471, "DCMODE"}, /* DCDC mode status bits , */\ + { 0x1509, "BATS"}, /* Battery voltage (V) , */\ + { 0x1608, "TEMPS"}, /* IC Temperature (C) , */\ + { 0x1709, "VDDPS"}, /* IC VDDP voltage ( 1023*VDDP/13 V) , */\ + { 0x2040, "TDME"}, /* Enable interface , */\ + { 0x2050, "TDMMODE"}, /* Slave/master , */\ + { 0x2060, "TDMCLINV"}, /* Reception data to BCK clock , */\ + { 0x2073, "TDMFSLN"}, /* FS length (master mode only) , */\ + { 0x20b0, "TDMFSPOL"}, /* FS polarity , */\ + { 0x20c3, "TDMNBCK"}, /* N-BCK's in FS , */\ + { 0x2103, "TDMSLOTS"}, /* N-slots in Frame , */\ + { 0x2144, "TDMSLLN"}, /* N-bits in slot , */\ + { 0x2194, "TDMBRMG"}, /* N-bits remaining , */\ + { 0x21e0, "TDMDEL"}, /* data delay to FS , */\ + { 0x21f0, "TDMADJ"}, /* data adjustment , */\ + { 0x2201, "TDMOOMP"}, /* Received audio compression , */\ + { 0x2224, "TDMSSIZE"}, /* Sample size per slot , */\ + { 0x2271, "TDMTXDFO"}, /* Format unused bits , */\ + { 0x2291, "TDMTXUS0"}, /* Format unused slots DATAO , */\ + { 0x2300, "TDMSPKE"}, /* Control audio tdm channel in 0 (spkr + dcdc) , */\ + { 0x2310, "TDMDCE"}, /* Control audio tdm channel in 1 (dcdc) , */\ + { 0x2330, "TDMCSE"}, /* current sense vbat temperature and vddp feedback , */\ + { 0x2340, "TDMVSE"}, /* Voltage sense vbat temperature and vddp feedback , */\ + { 0x2603, "TDMSPKS"}, /* tdm slot for sink 0 (speaker + dcdc) , */\ + { 0x2643, "TDMDCS"}, /* tdm slot for sink 1 (dcdc) , */\ + { 0x26c3, "TDMCSS"}, /* Slot Position of current sense vbat temperature and vddp feedback, */\ + { 0x2703, "TDMVSS"}, /* Slot Position of Voltage sense vbat temperature and vddp feedback, */\ + { 0x4000, "ISTVDDS"}, /* Status POR , */\ + { 0x4010, "ISTBSTOC"}, /* Status DCDC OCP , */\ + { 0x4020, "ISTOTDS"}, /* Status OTP alarm , */\ + { 0x4030, "ISTOCPR"}, /* Status ocp alarm , */\ + { 0x4040, "ISTUVDS"}, /* Status UVP alarm , */\ + { 0x4050, "ISTMANALARM"}, /* Status nanager Alarm state , */\ + { 0x4060, "ISTTDMER"}, /* Status tdm error , */\ + { 0x4070, "ISTNOCLK"}, /* Status lost clock , */\ + { 0x4400, "ICLVDDS"}, /* Clear POR , */\ + { 0x4410, "ICLBSTOC"}, /* Clear DCDC OCP , */\ + { 0x4420, "ICLOTDS"}, /* Clear OTP alarm , */\ + { 0x4430, "ICLOCPR"}, /* Clear ocp alarm , */\ + { 0x4440, "ICLUVDS"}, /* Clear UVP alarm , */\ + { 0x4450, "ICLMANALARM"}, /* clear nanager Alarm state , */\ + { 0x4460, "ICLTDMER"}, /* Clear tdm error , */\ + { 0x4470, "ICLNOCLK"}, /* Clear lost clk , */\ + { 0x4800, "IEVDDS"}, /* Enable por , */\ + { 0x4810, "IEBSTOC"}, /* Enable DCDC OCP , */\ + { 0x4820, "IEOTDS"}, /* Enable OTP alarm , */\ + { 0x4830, "IEOCPR"}, /* Enable ocp alarm , */\ + { 0x4840, "IEUVDS"}, /* Enable UVP alarm , */\ + { 0x4850, "IEMANALARM"}, /* Enable nanager Alarm state , */\ + { 0x4860, "IETDMER"}, /* Enable tdm error , */\ + { 0x4870, "IENOCLK"}, /* Enable lost clk , */\ + { 0x4c00, "IPOVDDS"}, /* Polarity por , */\ + { 0x4c10, "IPOBSTOC"}, /* Polarity DCDC OCP , */\ + { 0x4c20, "IPOOTDS"}, /* Polarity OTP alarm , */\ + { 0x4c30, "IPOOCPR"}, /* Polarity ocp alarm , */\ + { 0x4c40, "IPOUVDS"}, /* Polarity UVP alarm , */\ + { 0x4c50, "IPOMANALARM"}, /* Polarity nanager Alarm state , */\ + { 0x4c60, "IPOTDMER"}, /* Polarity tdm error , */\ + { 0x4c70, "IPONOCLK"}, /* Polarity lost clk , */\ + { 0x5001, "BSSCR"}, /* Battery Safeguard attack time , */\ + { 0x5023, "BSST"}, /* Battery Safeguard threshold voltage level , */\ + { 0x5061, "BSSRL"}, /* Battery Safeguard maximum reduction , */\ + { 0x5080, "VBATFLTL"}, /* vbat filter limit , */\ + { 0x50e0, "BSSR"}, /* Battery voltage read out , */\ + { 0x50f0, "BSSBY"}, /* Bypass battery safeguard , */\ + { 0x5100, "BSSS"}, /* Vbat prot steepness , */\ + { 0x5150, "HPFBYP"}, /* Bypass HPF , */\ + { 0x5170, "DPSA"}, /* Enable DPSA , */\ + { 0x5222, "CLIPCTRL"}, /* Clip control setting , */\ + { 0x5257, "AMPGAIN"}, /* Amplifier gain , */\ + { 0x52d0, "SLOPEE"}, /* Enables slope control , */\ + { 0x52e0, "SLOPESET"}, /* Slope speed setting (bin. coded) , */\ + { 0x6123, "TDMDCG"}, /* Second channel gain in case of stereo using a single coil. (Total gain depending on INPLEV). (In case of mono OR stereo using 2 separate DCDC channel 1 should be disabled using TDMDCE), */\ + { 0x6163, "TDMSPKG"}, /* Total gain depending on INPLEV setting (channel 0), */\ + { 0x62e1, "LNMODE"}, /* ctrl select mode , */\ + { 0x64e1, "LPM1MODE"}, /* low power mode control , */\ + { 0x6802, "TDMSRCMAP"}, /* tdm source mapping , */\ + { 0x6831, "TDMSRCAS"}, /* Sensed value A , */\ + { 0x6851, "TDMSRCBS"}, /* Sensed value B , */\ + { 0x6871, "TDMSRCACLIP"}, /* clip information (analog /digital) for source0 , */\ + { 0x6891, "TDMSRCBCLIP"}, /* clip information (analog /digital) for source1 , */\ + { 0x6e10, "LP1"}, /* low power mode 1 detection , */\ + { 0x6e20, "LA"}, /* low amplitude detection , */\ + { 0x6e30, "VDDPH"}, /* vddp greater than vbat , */\ + { 0x6f02, "DELCURCOMP"}, /* delay to allign compensation signal with current sense signal, */\ + { 0x6f40, "SIGCURCOMP"}, /* polarity of compensation for current sense , */\ + { 0x6f50, "ENCURCOMP"}, /* enable current sense compensation , */\ + { 0x6f72, "LVLCLPPWM"}, /* set the amount of pwm pulse that may be skipped before clip-flag is triggered, */\ + { 0x7033, "DCMCC"}, /* Max coil current , */\ + { 0x7071, "DCCV"}, /* Slope compensation current, represents LxF (inductance x frequency) value , */\ + { 0x7090, "DCIE"}, /* Adaptive boost mode , */\ + { 0x70a0, "DCSR"}, /* Soft ramp up/down , */\ + { 0x70e0, "DCDIS"}, /* DCDC on/off , */\ + { 0x70f0, "DCPWM"}, /* DCDC PWM only mode , */\ + { 0x7430, "DCTRACK"}, /* Boost algorithm selection, effective only when boost_intelligent is set to 1, */\ + { 0x7444, "DCTRIP"}, /* 1st Adaptive boost trip levels, effective only when DCIE is set to 1, */\ + { 0x7494, "DCHOLD"}, /* Hold time for DCDC booster, effective only when boost_intelligent is set to 1, */\ + { 0x7534, "DCTRIP2"}, /* 2nd Adaptive boost trip levels, effective only when DCIE is set to 1, */\ + { 0x7584, "DCTRIPT"}, /* Track Adaptive boost trip levels, effective only when boost_intelligent is set to 1, */\ + { 0x75f0, "DCTRIPHYSTE"}, /* Enable hysteresis on booster trip levels , */\ + { 0x7635, "DCVOF"}, /* First boost voltage level , */\ + { 0x7695, "DCVOS"}, /* Second boost voltage level , */\ + { 0xa107, "MTPK"}, /* MTP KEY2 register , */\ + { 0xa200, "KEY1LOCKED"}, /* Indicates KEY1 is locked , */\ + { 0xa210, "KEY2LOCKED"}, /* Indicates KEY2 is locked , */\ + { 0xa360, "CIMTP"}, /* Start copying data from I2C mtp registers to mtp , */\ + { 0xa50f, "MTPRDMSB"}, /* MSB word of MTP manual read data , */\ + { 0xa60f, "MTPRDLSB"}, /* LSB word of MTP manual read data , */\ + { 0xb108, "EXTTS"}, /* External temperature (C) , */\ + { 0xb190, "TROS"}, /* Select temp Speaker calibration , */\ + { 0xee0f, "SWPROFIL"}, /* Software profile data , */\ + { 0xef0f, "SWVSTEP"}, /* Software vstep information , */\ + { 0xf000, "MTPOTC"}, /* Calibration schedule , */\ + { 0xf010, "MTPEX"}, /* Calibration Ron executed , */\ + { 0xf020, "DCMCCAPI"}, /* Calibration current limit DCDC , */\ + { 0xf030, "DCMCCSB"}, /* Sign bit for delta calibration current limit DCDC , */\ + { 0xf042, "USERDEF"}, /* Calibration delta current limit DCDC , */\ + { 0xf078, "CUSTINFO"}, /* Reserved space for allowing customer to store speaker information, */\ + { 0xf50f, "R25C"}, /* Ron resistance of speaker coil , */\ + { 0xffff,"Unknown bitfield enum" } /* not found */\ +}; + +#define TFA9874_BITNAMETABLE static tfaBfName_t Tfa9874BitNames[]= {\ + { 0x0, "powerdown"}, /* Powerdown selection , */\ + { 0x10, "reset"}, /* I2C Reset - Auto clear , */\ + { 0x30, "enbl_amplifier"}, /* Activate Amplifier , */\ + { 0x40, "enbl_boost"}, /* Activate DC-to-DC converter , */\ + { 0x71, "int_pad_io"}, /* Interrupt config , */\ + { 0xb0, "bypass_ocp"}, /* Bypass OCP , */\ + { 0xc0, "test_ocp"}, /* OCP testing control , */\ + { 0x120, "src_set_configured"}, /* I2C configured , */\ + { 0x140, "enbl_osc1m_auto_off"}, /* Internal osc off at PWDN , */\ + { 0x1d0, "disable_mute_time_out"}, /* Time out SB mute sequence , */\ + { 0x1e0, "unprotect_faim"}, /* Control for FAIM protection , */\ + { 0x203, "audio_fs"}, /* Sample rate (fs) , */\ + { 0x240, "input_level"}, /* TDM output attenuation , */\ + { 0x255, "cs_frac_delay"}, /* V/I Fractional delay , */\ + { 0x2d0, "sel_hysteresis"}, /* Select hysteresis for clock range detector , */\ + { 0x30f, "device_rev"}, /* Revision info , */\ + { 0x401, "pll_clkin_sel"}, /* PLL external ref clock , */\ + { 0x420, "pll_clkin_sel_osc"}, /* PLL internal ref clock , */\ + { 0x5c0, "enbl_faim_ss"}, /* Sub-system FAIM , */\ + { 0x802, "ctrl_on2off_criterion"}, /* Amplifier on-off criteria for shutdown , */\ + { 0xe07, "ctrl_digtoana"}, /* Spare control from digital to analog , */\ + { 0xf0f, "hidden_code"}, /* 5A6Bh, 23147d to access registers (default for engineering), */\ + { 0x1000, "flag_por"}, /* POR , */\ + { 0x1010, "flag_bst_ocpok"}, /* DCDC OCP nmos (sticky register , clear on read) , */\ + { 0x1020, "flag_otpok"}, /* OTP alarm (sticky register , clear on read) , */\ + { 0x1030, "flag_ocp_alarm"}, /* OCP amplifier (sticky register , clear on read), */\ + { 0x1040, "flag_uvpok"}, /* UVP alarm (sticky register , clear on read) , */\ + { 0x1050, "flag_man_alarm_state"}, /* Alarm state , */\ + { 0x1060, "flag_tdm_error"}, /* TDM error , */\ + { 0x1070, "flag_lost_clk"}, /* Lost clock (sticky register , clear on read) , */\ + { 0x1100, "flag_bst_bstcur"}, /* DCDC current limiting , */\ + { 0x1110, "flag_bst_hiz"}, /* DCDC active (sticky register , clear on read) , */\ + { 0x1120, "flag_bst_peakcur"}, /* Indicates current is max in DC-to-DC converter , */\ + { 0x1130, "flag_bst_voutcomp"}, /* DCDC level 1x , */\ + { 0x1140, "flag_bst_voutcomp86"}, /* DCDC level 1.14x , */\ + { 0x1150, "flag_bst_voutcomp93"}, /* DCDC level 1.07x , */\ + { 0x1160, "flag_pll_lock"}, /* PLL lock , */\ + { 0x1170, "flag_clocks_stable"}, /* Clocks stable , */\ + { 0x1180, "flag_tdm_lut_error"}, /* TDM LUT error , */\ + { 0x1192, "flag_tdm_status"}, /* TDM status bits , */\ + { 0x11c0, "flag_mtp_busy"}, /* MTP busy , */\ + { 0x11d0, "flag_engage"}, /* Amplifier engage , */\ + { 0x11e0, "flag_enbl_amp"}, /* Amplifier enable , */\ + { 0x11f0, "flag_enbl_ref"}, /* References enable , */\ + { 0x1300, "flag_ocpokap"}, /* OCPOK pmos A , */\ + { 0x1310, "flag_ocpokan"}, /* OCPOK nmos A , */\ + { 0x1320, "flag_ocpokbp"}, /* OCPOK pmos B , */\ + { 0x1330, "flag_ocpokbn"}, /* OCPOK nmos B , */\ + { 0x1380, "flag_ovpok"}, /* OVP alarm , */\ + { 0x1390, "flag_clip"}, /* Amplifier clipping , */\ + { 0x13a0, "flag_adc10_ready"}, /* Control ADC , */\ + { 0x13c0, "flag_man_wait_src_settings"}, /* Wait HW I2C settings , */\ + { 0x13e0, "flag_man_start_mute_audio"}, /* Audio mute sequence , */\ + { 0x13f0, "flag_man_operating_state"}, /* Operating state , */\ + { 0x1420, "flag_clk_out_of_range"}, /* External clock status , */\ + { 0x1433, "man_state"}, /* Device manager status , */\ + { 0x1471, "status_bst_mode"}, /* DCDC mode status bits , */\ + { 0x1509, "bat_adc"}, /* Battery voltage (V) , */\ + { 0x1608, "temp_adc"}, /* IC Temperature (C) , */\ + { 0x1709, "vddp_adc"}, /* IC VDDP voltage ( 1023*VDDP/13 V) , */\ + { 0x2040, "tdm_enable"}, /* Enable interface , */\ + { 0x2050, "tdm_mode"}, /* Slave/master , */\ + { 0x2060, "tdm_clk_inversion"}, /* Reception data to BCK clock , */\ + { 0x2073, "tdm_fs_ws_length"}, /* FS length (master mode only) , */\ + { 0x20b0, "tdm_fs_ws_polarity"}, /* FS polarity , */\ + { 0x20c3, "tdm_nbck"}, /* N-BCK's in FS , */\ + { 0x2103, "tdm_nb_of_slots"}, /* N-slots in Frame , */\ + { 0x2144, "tdm_slot_length"}, /* N-bits in slot , */\ + { 0x2194, "tdm_bits_remaining"}, /* N-bits remaining , */\ + { 0x21e0, "tdm_data_delay"}, /* data delay to FS , */\ + { 0x21f0, "tdm_data_adjustment"}, /* data adjustment , */\ + { 0x2201, "tdm_audio_sample_compression"}, /* Received audio compression , */\ + { 0x2224, "tdm_sample_size"}, /* Sample size per slot , */\ + { 0x2271, "tdm_txdata_format"}, /* Format unused bits , */\ + { 0x2291, "tdm_txdata_format_unused_slot_sd0"}, /* Format unused slots DATAO , */\ + { 0x2300, "tdm_sink0_enable"}, /* Control audio tdm channel in 0 (spkr + dcdc) , */\ + { 0x2310, "tdm_sink1_enable"}, /* Control audio tdm channel in 1 (dcdc) , */\ + { 0x2330, "tdm_source0_enable"}, /* current sense vbat temperature and vddp feedback , */\ + { 0x2340, "tdm_source1_enable"}, /* Voltage sense vbat temperature and vddp feedback , */\ + { 0x2603, "tdm_sink0_slot"}, /* tdm slot for sink 0 (speaker + dcdc) , */\ + { 0x2643, "tdm_sink1_slot"}, /* tdm slot for sink 1 (dcdc) , */\ + { 0x26c3, "tdm_source0_slot"}, /* Slot Position of current sense vbat temperature and vddp feedback, */\ + { 0x2703, "tdm_source1_slot"}, /* Slot Position of Voltage sense vbat temperature and vddp feedback, */\ + { 0x4000, "int_out_flag_por"}, /* Status POR , */\ + { 0x4010, "int_out_flag_bst_ocpok"}, /* Status DCDC OCP , */\ + { 0x4020, "int_out_flag_otpok"}, /* Status OTP alarm , */\ + { 0x4030, "int_out_flag_ocp_alarm"}, /* Status ocp alarm , */\ + { 0x4040, "int_out_flag_uvpok"}, /* Status UVP alarm , */\ + { 0x4050, "int_out_flag_man_alarm_state"}, /* Status nanager Alarm state , */\ + { 0x4060, "int_out_flag_tdm_error"}, /* Status tdm error , */\ + { 0x4070, "int_out_flag_lost_clk"}, /* Status lost clock , */\ + { 0x4400, "int_in_flag_por"}, /* Clear POR , */\ + { 0x4410, "int_in_flag_bst_ocpok"}, /* Clear DCDC OCP , */\ + { 0x4420, "int_in_flag_otpok"}, /* Clear OTP alarm , */\ + { 0x4430, "int_in_flag_ocp_alarm"}, /* Clear ocp alarm , */\ + { 0x4440, "int_in_flag_uvpok"}, /* Clear UVP alarm , */\ + { 0x4450, "int_in_flag_man_alarm_state"}, /* clear nanager Alarm state , */\ + { 0x4460, "int_in_flag_tdm_error"}, /* Clear tdm error , */\ + { 0x4470, "int_in_flag_lost_clk"}, /* Clear lost clk , */\ + { 0x4800, "int_enable_flag_por"}, /* Enable por , */\ + { 0x4810, "int_enable_flag_bst_ocpok"}, /* Enable DCDC OCP , */\ + { 0x4820, "int_enable_flag_otpok"}, /* Enable OTP alarm , */\ + { 0x4830, "int_enable_flag_ocp_alarm"}, /* Enable ocp alarm , */\ + { 0x4840, "int_enable_flag_uvpok"}, /* Enable UVP alarm , */\ + { 0x4850, "int_enable_flag_man_alarm_state"}, /* Enable nanager Alarm state , */\ + { 0x4860, "int_enable_flag_tdm_error"}, /* Enable tdm error , */\ + { 0x4870, "int_enable_flag_lost_clk"}, /* Enable lost clk , */\ + { 0x4c00, "int_polarity_flag_por"}, /* Polarity por , */\ + { 0x4c10, "int_polarity_flag_bst_ocpok"}, /* Polarity DCDC OCP , */\ + { 0x4c20, "int_polarity_flag_otpok"}, /* Polarity OTP alarm , */\ + { 0x4c30, "int_polarity_flag_ocp_alarm"}, /* Polarity ocp alarm , */\ + { 0x4c40, "int_polarity_flag_uvpok"}, /* Polarity UVP alarm , */\ + { 0x4c50, "int_polarity_flag_man_alarm_state"}, /* Polarity nanager Alarm state , */\ + { 0x4c60, "int_polarity_flag_tdm_error"}, /* Polarity tdm error , */\ + { 0x4c70, "int_polarity_flag_lost_clk"}, /* Polarity lost clk , */\ + { 0x5001, "vbat_prot_attack_time"}, /* Battery Safeguard attack time , */\ + { 0x5023, "vbat_prot_thlevel"}, /* Battery Safeguard threshold voltage level , */\ + { 0x5061, "vbat_prot_max_reduct"}, /* Battery Safeguard maximum reduction , */\ + { 0x5080, "vbat_flt_limit"}, /* vbat filter limit , */\ + { 0x50d0, "rst_min_vbat"}, /* Reset clipper - Auto clear , */\ + { 0x50e0, "sel_vbat"}, /* Battery voltage read out , */\ + { 0x50f0, "bypass_clipper"}, /* Bypass battery safeguard , */\ + { 0x5100, "batsense_steepness"}, /* Vbat prot steepness , */\ + { 0x5150, "bypass_hp"}, /* Bypass HPF , */\ + { 0x5170, "enbl_dpsa"}, /* Enable DPSA , */\ + { 0x5222, "ctrl_cc"}, /* Clip control setting , */\ + { 0x5257, "gain"}, /* Amplifier gain , */\ + { 0x52d0, "ctrl_slopectrl"}, /* Enables slope control , */\ + { 0x52e0, "ctrl_slope"}, /* Slope speed setting (bin. coded) , */\ + { 0x5301, "dpsa_level"}, /* DPSA threshold levels , */\ + { 0x5321, "dpsa_release"}, /* DPSA Release time , */\ + { 0x5340, "clipfast"}, /* Clock selection for HW clipper for Battery Safeguard, */\ + { 0x5350, "bypass_lp"}, /* Bypass the low power filter inside temperature sensor, */\ + { 0x5400, "first_order_mode"}, /* Overrule to 1st order mode of control stage when clipping, */\ + { 0x5410, "bypass_ctrlloop"}, /* Switch amplifier into open loop configuration , */\ + { 0x5430, "icomp_engage"}, /* Engage of icomp , */\ + { 0x5440, "ctrl_kickback"}, /* Prevent double pulses of output stage , */\ + { 0x5450, "icomp_engage_overrule"}, /* To overrule the functional icomp_engage signal during validation, */\ + { 0x5503, "ctrl_dem"}, /* Enable DEM icomp and DEM one bit dac , */\ + { 0x5543, "ctrl_dem_mismatch"}, /* Enable DEM icomp mismatch for testing , */\ + { 0x5582, "dpsa_drive"}, /* Drive setting (bin. coded) , */\ + { 0x5690, "sel_pwm_delay_src"}, /* Control for selection for PWM delay line source , */\ + { 0x56a1, "enbl_odd_up_even_down"}, /* Control for PWM reference sawtooth generartion , */\ + { 0x570a, "enbl_amp"}, /* Switch on the class-D power sections, each part of the analog sections can be switched on/off individually, */\ + { 0x57b0, "enbl_engage"}, /* Enables/engage power stage and control loop , */\ + { 0x57c0, "enbl_engage_pst"}, /* Enables/engage power stage and control loop , */\ + { 0x5810, "hard_mute"}, /* Hard mute - PWM , */\ + { 0x5820, "pwm_shape"}, /* PWM shape , */\ + { 0x5844, "pwm_delay"}, /* PWM delay bits to set the delay, clockd is 1/(k*2048*fs), */\ + { 0x5890, "reclock_pwm"}, /* Reclock the pwm signal inside analog , */\ + { 0x58a0, "reclock_voltsense"}, /* Reclock the voltage sense pwm signal , */\ + { 0x58c0, "enbl_pwm_phase_shift"}, /* Control for pwm phase shift , */\ + { 0x6123, "ctrl_attl"}, /* Second channel gain in case of stereo using a single coil. (Total gain depending on INPLEV). (In case of mono OR stereo using 2 separate DCDC channel 1 should be disabled using TDMDCE), */\ + { 0x6163, "ctrl_attr"}, /* Total gain depending on INPLEV setting (channel 0), */\ + { 0x6265, "zero_lvl"}, /* low noise gain switch zero trigger level , */\ + { 0x62c1, "ctrl_fb_resistor"}, /* Select amplifier feedback resistor connection , */\ + { 0x62e1, "lownoisegain_mode"}, /* ctrl select mode , */\ + { 0x6305, "threshold_lvl"}, /* low noise gain switch trigger level , */\ + { 0x6365, "hold_time"}, /* ctrl hold time before low audio is reckoned to be low audio, */\ + { 0x6405, "lpm1_cal_offset"}, /* low power mode1 detector ctrl cal_offset from gain module , */\ + { 0x6465, "lpm1_zero_lvl"}, /* low power mode1 zero crossing detection level , */\ + { 0x64e1, "lpm1_mode"}, /* low power mode control , */\ + { 0x6505, "lpm1_threshold_lvl"}, /* low power mode1 amplitude trigger level , */\ + { 0x6565, "lpm1_hold_time"}, /* low power mode1 detector ctrl hold time before low audio is reckoned to be low audio, */\ + { 0x65c0, "disable_low_power_mode"}, /* low power mode1 detector control , */\ + { 0x6600, "dcdc_pfm20khz_limit"}, /* DCDC in PFM mode pwm mode is activated each 50us to force a pwm pulse, */\ + { 0x6611, "dcdc_ctrl_maxzercnt"}, /* DCDC. Number of zero current flags to count before going to pfm mode, */\ + { 0x6656, "dcdc_vbat_delta_detect"}, /* Threshold before booster is reacting on a delta Vbat (in PFM mode) by temporarily switching to PWM mode, */\ + { 0x66c0, "dcdc_ignore_vbat"}, /* Ignore an increase on Vbat , */\ + { 0x6700, "enbl_minion"}, /* Enables minion (small) power stage , */\ + { 0x6713, "vth_vddpvbat"}, /* select vddp-vbat thres signal , */\ + { 0x6750, "lpen_vddpvbat"}, /* select vddp-vbat filtred vs unfiltered compare , */\ + { 0x6761, "ctrl_rfb"}, /* Feedback resistor selection - I2C direct mode , */\ + { 0x6802, "tdm_source_mapping"}, /* tdm source mapping , */\ + { 0x6831, "tdm_sourcea_frame_sel"}, /* Sensed value A , */\ + { 0x6851, "tdm_sourceb_frame_sel"}, /* Sensed value B , */\ + { 0x6871, "tdm_source0_clip_sel"}, /* clip information (analog /digital) for source0 , */\ + { 0x6891, "tdm_source1_clip_sel"}, /* clip information (analog /digital) for source1 , */\ + { 0x6a02, "rst_min_vbat_delay"}, /* rst_min_vbat delay (nb fs) , */\ + { 0x6b00, "disable_auto_engage"}, /* disable auto engange , */\ + { 0x6b10, "disable_engage"}, /* disable engange , */\ + { 0x6c02, "ns_hp2ln_criterion"}, /* 0..7 zeroes at ns as threshold to swap from high_power to low_noise, */\ + { 0x6c32, "ns_ln2hp_criterion"}, /* 0..7 zeroes at ns as threshold to swap from low_noise to high_power, */\ + { 0x6c69, "spare_out"}, /* spare_out , */\ + { 0x6d0f, "spare_in"}, /* spare_in , */\ + { 0x6e10, "flag_lp_detect_mode1"}, /* low power mode 1 detection , */\ + { 0x6e20, "flag_low_amplitude"}, /* low amplitude detection , */\ + { 0x6e30, "flag_vddp_gt_vbat"}, /* vddp greater than vbat , */\ + { 0x6f02, "cursense_comp_delay"}, /* delay to allign compensation signal with current sense signal, */\ + { 0x6f40, "cursense_comp_sign"}, /* polarity of compensation for current sense , */\ + { 0x6f50, "enbl_cursense_comp"}, /* enable current sense compensation , */\ + { 0x6f72, "pwms_clip_lvl"}, /* set the amount of pwm pulse that may be skipped before clip-flag is triggered, */\ + { 0x7033, "boost_cur"}, /* Max coil current , */\ + { 0x7071, "bst_slpcmplvl"}, /* Slope compensation current, represents LxF (inductance x frequency) value , */\ + { 0x7090, "boost_intel"}, /* Adaptive boost mode , */\ + { 0x70a0, "boost_speed"}, /* Soft ramp up/down , */\ + { 0x70e0, "dcdcoff_mode"}, /* DCDC on/off , */\ + { 0x70f0, "dcdc_pwmonly"}, /* DCDC PWM only mode , */\ + { 0x7104, "bst_drive"}, /* Binary coded drive setting for boost converter power stage, */\ + { 0x7151, "bst_scalecur"}, /* For testing direct control scale current , */\ + { 0x7174, "bst_slopecur"}, /* For testing direct control slope current , */\ + { 0x71c1, "bst_slope"}, /* Boost slope speed , */\ + { 0x71e0, "bst_bypass_bstcur"}, /* Bypass control for boost current settings , */\ + { 0x71f0, "bst_bypass_bstfoldback"}, /* Bypass control for boost foldback , */\ + { 0x7200, "enbl_bst_engage"}, /* Enable power stage dcdc controller , */\ + { 0x7210, "enbl_bst_hizcom"}, /* Enable hiz comparator , */\ + { 0x7220, "enbl_bst_peak2avg"}, /* Enable boost peak2avg functionality , */\ + { 0x7230, "enbl_bst_peakcur"}, /* Enable peak current , */\ + { 0x7240, "enbl_bst_power"}, /* Enable line of the powerstage , */\ + { 0x7250, "enbl_bst_slopecur"}, /* Enable bit of max-current dac , */\ + { 0x7260, "enbl_bst_voutcomp"}, /* Enable vout comparators , */\ + { 0x7270, "enbl_bst_voutcomp86"}, /* Enable vout-86 comparators , */\ + { 0x7280, "enbl_bst_voutcomp93"}, /* Enable vout-93 comparators , */\ + { 0x7290, "enbl_bst_windac"}, /* Enable window dac , */\ + { 0x72a5, "bst_windac"}, /* for testing direct control windac , */\ + { 0x7300, "boost_alg"}, /* Control for boost adaptive loop gain , */\ + { 0x7311, "boost_loopgain"}, /* DCDC boost loopgain setting , */\ + { 0x7331, "bst_freq"}, /* DCDC boost frequency control , */\ + { 0x7360, "bst_use_new_zercur_detect"}, /* Enable new zero current detection for boost control, */\ + { 0x7430, "boost_track"}, /* Boost algorithm selection, effective only when boost_intelligent is set to 1, */\ + { 0x7444, "boost_trip_lvl_1st"}, /* 1st Adaptive boost trip levels, effective only when DCIE is set to 1, */\ + { 0x7494, "boost_hold_time"}, /* Hold time for DCDC booster, effective only when boost_intelligent is set to 1, */\ + { 0x74e0, "sel_dcdc_envelope_8fs"}, /* Selection of data for adaptive boost algorithm, effective only when boost_intelligent is set to 1, */\ + { 0x74f0, "ignore_flag_voutcomp86"}, /* Determines the maximum PWM frequency be the most efficient in relation to the Booster inductor value, */\ + { 0x7534, "boost_trip_lvl_2nd"}, /* 2nd Adaptive boost trip levels, effective only when DCIE is set to 1, */\ + { 0x7584, "boost_trip_lvl_track"}, /* Track Adaptive boost trip levels, effective only when boost_intelligent is set to 1, */\ + { 0x75f0, "enbl_trip_hyst"}, /* Enable hysteresis on booster trip levels , */\ + { 0x7635, "frst_boost_voltage"}, /* First boost voltage level , */\ + { 0x7695, "scnd_boost_voltage"}, /* Second boost voltage level , */\ + { 0x8001, "sel_clk_cs"}, /* Current sense clock duty cycle control , */\ + { 0x8021, "micadc_speed"}, /* Current sense clock for MiCADC selection - 32/44.1/48 KHz Fs band only, */\ + { 0x8050, "cs_gain_control"}, /* Current sense gain control , */\ + { 0x8060, "cs_bypass_gc"}, /* Bypasses the CS gain correction , */\ + { 0x8087, "cs_gain"}, /* Current sense gain , */\ + { 0x8210, "invertpwm"}, /* Current sense common mode feedback pwm invert control, */\ + { 0x8305, "cs_ktemp"}, /* Current sense temperature compensation trimming (1 - VALUE*TEMP)*signal, */\ + { 0x8364, "cs_ktemp2"}, /* Second order temperature compensation coefficient , */\ + { 0x8400, "cs_adc_bsoinv"}, /* Bitstream inversion for current sense ADC , */\ + { 0x8421, "cs_adc_hifreq"}, /* Frequency mode current sense ADC , */\ + { 0x8440, "cs_adc_nortz"}, /* Return to zero for current sense ADC , */\ + { 0x8453, "cs_adc_offset"}, /* Micadc ADC offset setting , */\ + { 0x8490, "cs_adc_slowdel"}, /* Select delay for current sense ADC (internal decision circuitry), */\ + { 0x84a4, "cs_adc_gain"}, /* Gain setting for current sense ADC (two's complement), */\ + { 0x8500, "cs_resonator_enable"}, /* Enable for resonator to improve SRN , */\ + { 0x8510, "cs_classd_tran_skip"}, /* Skip current sense connection during a classD amplifier transition, */\ + { 0x8530, "cs_inn_short"}, /* Short current sense negative to common mode , */\ + { 0x8540, "cs_inp_short"}, /* Short current sense positive to common mode , */\ + { 0x8550, "cs_ldo_bypass"}, /* Bypass current sense LDO , */\ + { 0x8560, "cs_ldo_pulldown"}, /* Pull down current sense LDO, only valid if left_enbl_cs_ldo is high, */\ + { 0x8574, "cs_ldo_voset"}, /* Current sense LDO voltage level setting (two's complement), */\ + { 0x8700, "enbl_cs_adc"}, /* Enable current sense ADC , */\ + { 0x8710, "enbl_cs_inn1"}, /* Enable connection of current sense negative1 , */\ + { 0x8720, "enbl_cs_inn2"}, /* Enable connection of current sense negative2 , */\ + { 0x8730, "enbl_cs_inp1"}, /* Enable connection of current sense positive1 , */\ + { 0x8740, "enbl_cs_inp2"}, /* Enable connection of current sense positive2 , */\ + { 0x8750, "enbl_cs_ldo"}, /* Enable current sense LDO , */\ + { 0x8780, "enbl_cs_vbatldo"}, /* Enable of current sense LDO , */\ + { 0x8790, "enbl_dc_filter"}, /* Control for enabling the DC blocking filter for voltage and current sense, */\ + { 0x8801, "volsense_pwm_sel"}, /* Voltage sense source selection control , */\ + { 0x8850, "vs_gain_control"}, /* Voltage sense gain control , */\ + { 0x8860, "vs_bypass_gc"}, /* Bypasses the VS gain correction , */\ + { 0x8870, "vs_igen_supply"}, /* Switch internal supply of current generator , */\ + { 0x8887, "vs_gain"}, /* voltage sense gain , */\ + { 0x8c00, "vs_adc_bsoinv"}, /* Bitstream inversion for voltage sense ADC , */\ + { 0x8c40, "vs_adc_nortz"}, /* Return to zero for voltage sense ADC , */\ + { 0x8c90, "vs_adc_slowdel"}, /* Select delay for voltage sense ADC (internal decision circuitry), */\ + { 0x8d10, "vs_classd_tran_skip"}, /* Skip voltage sense connection during a classD amplifier transition, */\ + { 0x8d30, "vs_inn_short"}, /* Short voltage sense negative to common mode , */\ + { 0x8d40, "vs_inp_short"}, /* Short voltage sense positive to common mode , */\ + { 0x8d50, "vs_ldo_bypass"}, /* Bypass voltage sense LDO , */\ + { 0x8d60, "vs_ldo_pulldown"}, /* Pull down voltage sense LDO, only valid if left_enbl_cs_ldo is high, */\ + { 0x8d74, "vs_ldo_voset"}, /* Voltage sense LDO voltage level setting (two's complement), */\ + { 0x8f00, "enbl_vs_adc"}, /* Enable voltage sense ADC (Direct Control only only others done by manager), */\ + { 0x8f10, "enbl_vs_inn1"}, /* Enable connection of voltage sense negative1 , */\ + { 0x8f20, "enbl_vs_inn2"}, /* Enable connection of voltage sense negative2 , */\ + { 0x8f30, "enbl_vs_inp1"}, /* Enable connection of voltage sense positive1 , */\ + { 0x8f40, "enbl_vs_inp2"}, /* Enable connection of voltage sense positive2 , */\ + { 0x8f50, "enbl_vs_ldo"}, /* Enable voltage sense LDO (Direct Control only only others done by manager), */\ + { 0x8f80, "enbl_vs_vbatldo"}, /* Enable of voltage sense LDO (Direct Control only others done by manager), */\ + { 0xa007, "mtpkey1"}, /* 5Ah, 90d To access KEY1_Protected registers (Default for engineering), */\ + { 0xa107, "mtpkey2"}, /* MTP KEY2 register , */\ + { 0xa200, "key01_locked"}, /* Indicates KEY1 is locked , */\ + { 0xa210, "key02_locked"}, /* Indicates KEY2 is locked , */\ + { 0xa302, "mtp_man_address_in"}, /* MTP address from I2C register for read/writing mtp in manual single word mode, */\ + { 0xa330, "man_copy_mtp_to_iic"}, /* Start copying single word from mtp to I2C mtp register, */\ + { 0xa340, "man_copy_iic_to_mtp"}, /* Start copying single word from I2C mtp register to mtp, */\ + { 0xa350, "auto_copy_mtp_to_iic"}, /* Start copying all the data from mtp to I2C mtp registers, */\ + { 0xa360, "auto_copy_iic_to_mtp"}, /* Start copying data from I2C mtp registers to mtp , */\ + { 0xa400, "faim_set_clkws"}, /* Sets the faim controller clock wait state register, */\ + { 0xa410, "faim_sel_evenrows"}, /* All even rows of the faim are selected, active high, */\ + { 0xa420, "faim_sel_oddrows"}, /* All odd rows of the faim are selected, all rows in combination with sel_evenrows, */\ + { 0xa430, "faim_program_only"}, /* Skip the erase access at wr_faim command (write-program-marginread), */\ + { 0xa440, "faim_erase_only"}, /* Skip the program access at wr_faim command (write-erase-marginread), */\ + { 0xa50f, "mtp_man_data_out_msb"}, /* MSB word of MTP manual read data , */\ + { 0xa60f, "mtp_man_data_out_lsb"}, /* LSB word of MTP manual read data , */\ + { 0xa70f, "mtp_man_data_in_msb"}, /* MSB word of write data for MTP manual write , */\ + { 0xa80f, "mtp_man_data_in_lsb"}, /* LSB word of write data for MTP manual write , */\ + { 0xb010, "bypass_ocpcounter"}, /* Bypass OCP Counter , */\ + { 0xb020, "bypass_glitchfilter"}, /* Bypass glitch filter , */\ + { 0xb030, "bypass_ovp"}, /* Bypass OVP , */\ + { 0xb040, "bypass_uvp"}, /* Bypass UVP , */\ + { 0xb050, "bypass_otp"}, /* Bypass OTP , */\ + { 0xb060, "bypass_lost_clk"}, /* Bypass lost clock detector , */\ + { 0xb070, "ctrl_vpalarm"}, /* vpalarm (uvp ovp handling) , */\ + { 0xb087, "ocp_threshold"}, /* OCP threshold level , */\ + { 0xb108, "ext_temp"}, /* External temperature (C) , */\ + { 0xb190, "ext_temp_sel"}, /* Select temp Speaker calibration , */\ + { 0xc000, "use_direct_ctrls"}, /* Direct control to overrule several functions for testing, */\ + { 0xc010, "rst_datapath"}, /* Direct control for datapath reset , */\ + { 0xc020, "rst_cgu"}, /* Direct control for cgu reset , */\ + { 0xc038, "enbl_ref"}, /* Switch on the analog references, each part of the references can be switched on/off individually, */\ + { 0xc0c0, "use_direct_vs_ctrls"}, /* voltage sense Direct control to overrule several functions for testing, */\ + { 0xc0d0, "enbl_ringo"}, /* Enable the ring oscillator for test purpose , */\ + { 0xc0e0, "use_direct_clk_ctrl"}, /* Direct clock control to overrule several functions for testing, */\ + { 0xc0f0, "use_direct_pll_ctrl"}, /* Direct PLL control to overrule several functions for testing, */\ + { 0xc100, "enbl_tsense"}, /* Temperature sensor enable control - I2C direct mode, */\ + { 0xc110, "tsense_hibias"}, /* Bit to set the biasing in temp sensor to high , */\ + { 0xc120, "enbl_flag_vbg"}, /* Enable flagging of bandgap out of control , */\ + { 0xc20f, "abist_offset"}, /* Offset control for ABIST testing (two's complement), */\ + { 0xc300, "bypasslatch"}, /* Bypass latch , */\ + { 0xc311, "sourcea"}, /* Set OUTA to , */\ + { 0xc331, "sourceb"}, /* Set OUTB to , */\ + { 0xc350, "inverta"}, /* Invert pwma test signal , */\ + { 0xc360, "invertb"}, /* Invert pwmb test signal , */\ + { 0xc374, "pulselength"}, /* Pulse length setting test input for amplifier (clock d - k*2048*fs), */\ + { 0xc3c0, "tdm_enable_loopback"}, /* TDM loopback test , */\ + { 0xc400, "bst_bypasslatch"}, /* Bypass latch in boost converter , */\ + { 0xc411, "bst_source"}, /* Sets the source of the pwmbst output to boost converter input for testing, */\ + { 0xc430, "bst_invertb"}, /* Invert pwmbst test signal , */\ + { 0xc444, "bst_pulselength"}, /* Pulse length setting test input for boost converter , */\ + { 0xc490, "test_bst_ctrlsthv"}, /* Test mode for boost control stage , */\ + { 0xc4a0, "test_bst_iddq"}, /* IDDQ testing in power stage of boost converter , */\ + { 0xc4b0, "test_bst_rdson"}, /* RDSON testing - boost power stage , */\ + { 0xc4c0, "test_bst_cvi"}, /* CVI testing - boost power stage , */\ + { 0xc4d0, "test_bst_ocp"}, /* Boost OCP. For old ocp (ctrl_reversebst is 0), For new ocp (ctrl_reversebst is 1), */\ + { 0xc4e0, "test_bst_sense"}, /* Test option for the sense NMOS in booster for current mode control., */\ + { 0xc500, "test_cvi"}, /* Analog BIST, switch choose which transistor will be used as current source (also cross coupled sources possible), */\ + { 0xc510, "test_discrete"}, /* Test function noise measurement , */\ + { 0xc520, "test_iddq"}, /* Set the power stages in iddq mode for gate stress., */\ + { 0xc540, "test_rdson"}, /* Analog BIST, switch to enable Rdson measurement , */\ + { 0xc550, "test_sdelta"}, /* Analog BIST, noise test , */\ + { 0xc570, "test_enbl_cs"}, /* Enable for digimux mode of current sense , */\ + { 0xc580, "test_enbl_vs"}, /* Enable for digimux mode of voltage sense , */\ + { 0xc600, "enbl_pwm_dcc"}, /* Enables direct control of pwm duty cycle for DCDC power stage, */\ + { 0xc613, "pwm_dcc_cnt"}, /* Control pwm duty cycle when enbl_pwm_dcc is 1 , */\ + { 0xc650, "enbl_ldo_stress"}, /* Enable stress of internal supply voltages powerstages, */\ + { 0xc707, "digimuxa_sel"}, /* DigimuxA input selection control routed to DATAO (see Digimux list for details), */\ + { 0xc787, "digimuxb_sel"}, /* DigimuxB input selection control routed to INT (see Digimux list for details), */\ + { 0xc807, "digimuxc_sel"}, /* DigimuxC input selection control routed to PDMDAT (see Digimux list for details), */\ + { 0xc981, "int_ehs"}, /* Speed/load setting for INT IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ + { 0xc9c0, "hs_mode"}, /* I2C high speed mode control , */\ + { 0xca00, "enbl_anamux1"}, /* Enable anamux1 , */\ + { 0xca10, "enbl_anamux2"}, /* Enable anamux2 , */\ + { 0xca20, "enbl_anamux3"}, /* Enable anamux3 , */\ + { 0xca30, "enbl_anamux4"}, /* Enable anamux4 , */\ + { 0xca74, "anamux1"}, /* Anamux selection control - anamux on TEST1 , */\ + { 0xcb04, "anamux2"}, /* Anamux selection control - anamux on TEST2 , */\ + { 0xcb53, "anamux3"}, /* Anamux selection control - anamux on TEST3 , */\ + { 0xcba3, "anamux4"}, /* Anamux selection control - anamux on TEST4 , */\ + { 0xcd05, "pll_seli"}, /* PLL SELI - I2C direct PLL control mode only , */\ + { 0xcd64, "pll_selp"}, /* PLL SELP - I2C direct PLL control mode only , */\ + { 0xcdb3, "pll_selr"}, /* PLL SELR - I2C direct PLL control mode only , */\ + { 0xcdf0, "pll_frm"}, /* PLL free running mode control; 1 in TCB direct control mode, else this control bit, */\ + { 0xce09, "pll_ndec"}, /* PLL NDEC - I2C direct PLL control mode only , */\ + { 0xcea0, "pll_mdec_msb"}, /* MSB of pll_mdec - I2C direct PLL control mode only, */\ + { 0xceb0, "enbl_pll"}, /* Enables PLL in I2C direct PLL control mode only , */\ + { 0xcec0, "enbl_osc"}, /* Enables OSC1M in I2C direct control mode only , */\ + { 0xced0, "pll_bypass"}, /* PLL bypass control in I2C direct PLL control mode only, */\ + { 0xcee0, "pll_directi"}, /* PLL directi control in I2C direct PLL control mode only, */\ + { 0xcef0, "pll_directo"}, /* PLL directo control in I2C direct PLL control mode only, */\ + { 0xcf0f, "pll_mdec_lsb"}, /* Bits 15..0 of PLL MDEC are I2C direct PLL control mode only, */\ + { 0xd006, "pll_pdec"}, /* PLL PDEC - I2C direct PLL control mode only , */\ + { 0xd10f, "tsig_freq_lsb"}, /* Internal sinus test generator frequency control , */\ + { 0xd202, "tsig_freq_msb"}, /* Select internal sinus test generator, frequency control msb bits, */\ + { 0xd230, "inject_tsig"}, /* Control bit to switch to internal sinus test generator, */\ + { 0xd283, "tsig_gain"}, /* Test signal gain , */\ + { 0xd300, "adc10_reset"}, /* Reset for ADC10 - I2C direct control mode , */\ + { 0xd311, "adc10_test"}, /* Test mode selection signal for ADC10 - I2C direct control mode, */\ + { 0xd332, "adc10_sel"}, /* Select the input to convert for ADC10 - I2C direct control mode, */\ + { 0xd364, "adc10_prog_sample"}, /* ADC10 program sample setting - I2C direct control mode, */\ + { 0xd3b0, "adc10_enbl"}, /* Enable ADC10 - I2C direct control mode , */\ + { 0xd3c0, "bypass_lp_vbat"}, /* Bypass control for Low pass filter in batt sensor , */\ + { 0xd409, "data_adc10_tempbat"}, /* ADC 10 data output data for testing , */\ + { 0xd507, "ctrl_digtoana_hidden"}, /* Spare digital to analog control bits - Hidden , */\ + { 0xd580, "enbl_clk_out_of_range"}, /* Clock out of range , */\ + { 0xd621, "clkdiv_audio_sel"}, /* Audio clock divider selection in direct clock control mode, */\ + { 0xd641, "clkdiv_muxa_sel"}, /* DCDC MUXA clock divider selection in direct clock control mode, */\ + { 0xd661, "clkdiv_muxb_sel"}, /* DCDC MUXB clock divider selection in direct clock control mode, */\ + { 0xd721, "datao_ehs"}, /* Speed/load setting for DATAO IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ + { 0xd740, "bck_ehs"}, /* High-speed and standard/fast mode selection for BCK IO cell (see IIC3V3 IO cell datasheet), */\ + { 0xd750, "datai_ehs"}, /* High-speed and standard/fast mode selection for DATAI IO cell (see IIC3V3 IO cell datasheet), */\ + { 0xd800, "source_in_testmode"}, /* tdm source in test mode (return only current and voltage sense), */\ + { 0xd810, "gainatt_feedback"}, /* gainatt feedback to tdm , */\ + { 0xd822, "test_parametric_io"}, /* test io parametric , */\ + { 0xd850, "ctrl_bst_clk_lp1"}, /* boost clock control in low power mode1 , */\ + { 0xd861, "test_spare_out1"}, /* test spare out 1 , */\ + { 0xd880, "bst_dcmbst"}, /* dcm boost , */\ + { 0xd8c3, "test_spare_out2"}, /* test spare out 1 , */\ + { 0xee0f, "sw_profile"}, /* Software profile data , */\ + { 0xef0f, "sw_vstep"}, /* Software vstep information , */\ + { 0xf000, "calibration_onetime"}, /* Calibration schedule , */\ + { 0xf010, "calibr_ron_done"}, /* Calibration Ron executed , */\ + { 0xf020, "calibr_dcdc_api_calibrate"}, /* Calibration current limit DCDC , */\ + { 0xf030, "calibr_dcdc_delta_sign"}, /* Sign bit for delta calibration current limit DCDC , */\ + { 0xf042, "calibr_dcdc_delta"}, /* Calibration delta current limit DCDC , */\ + { 0xf078, "calibr_speaker_info"}, /* Reserved space for allowing customer to store speaker information, */\ + { 0xf105, "calibr_vout_offset"}, /* DCDC offset calibration 2's complement (key1 protected), */\ + { 0xf169, "spare_mpt1_15_6"}, /* SPARE , */\ + { 0xf203, "calibr_gain"}, /* HW gain module (2's complement) , */\ + { 0xf245, "calibr_offset"}, /* Offset for amplifier, HW gain module (2's complement), */\ + { 0xf2a5, "spare_mtp2_15_10"}, /* SPARE , */\ + { 0xf307, "calibr_gain_vs"}, /* Voltage sense gain , */\ + { 0xf387, "calibr_gain_cs"}, /* Current sense gain (signed two's complement format), */\ + { 0xf407, "spare_mtp4_15_0"}, /* SPARE , */\ + { 0xf487, "vs_trim"}, /* VS Trimming , */\ + { 0xf50f, "calibr_R25C_R"}, /* Ron resistance of speaker coil , */\ + { 0xf60f, "spare_mpt6_6_0"}, /* SPARE , */\ + { 0xf706, "ctrl_offset_a"}, /* Offset of level shifter A , */\ + { 0xf770, "spare_mtp7_07"}, /* SPARE , */\ + { 0xf786, "ctrl_offset_b"}, /* Offset of amplifier level shifter B , */\ + { 0xf7f0, "spare_mtp7_15"}, /* SPARE , */\ + { 0xf806, "htol_iic_addr"}, /* 7-bit I2C address to be used during HTOL testing , */\ + { 0xf870, "htol_iic_addr_en"}, /* HTOL I2C address enable control , */\ + { 0xf884, "calibr_temp_offset"}, /* Temperature offset 2's compliment (key1 protected), */\ + { 0xf8d2, "calibr_temp_gain"}, /* Temperature gain 2's compliment (key1 protected) , */\ + { 0xf900, "mtp_lock_dcdcoff_mode"}, /* Disable function dcdcoff_mode , */\ + { 0xf910, "spare_mtp9_1"}, /* SPARE , */\ + { 0xf920, "mtp_lock_bypass_clipper"}, /* Disable function bypass_clipper , */\ + { 0xf930, "mtp_lock_max_dcdc_voltage"}, /* Force Boost in follower mode , */\ + { 0xf943, "calibr_vbg_trim"}, /* Bandgap trimming control , */\ + { 0xf980, "spare_mtp9_8"}, /* SPARE , */\ + { 0xf990, "mtp_enbl_pwm_delay_clock_gating"}, /* pwm delay clock auto gating , */\ + { 0xf9a0, "mtp_enbl_ocp_clock_gating"}, /* ocpclock auto gating , */\ + { 0xf9b0, "mtp_gate_cgu_clock_for_test"}, /* cgu test clock control , */\ + { 0xf9c0, "mtp_tdm_pad_sel"}, /* tdm pad selection , */\ + { 0xf9d2, "spare_mtp9_15_12"}, /* MTP-control FW - See Firmware I2C API document for details, */\ + { 0xfa0f, "mtpdataA"}, /* MTPdataA (key1 protected) , */\ + { 0xfb0f, "mtpdataB"}, /* MTPdataB (key1 protected) , */\ + { 0xfc0f, "mtpdataC"}, /* MTPdataC (key1 protected) , */\ + { 0xfd0f, "mtpdataD"}, /* MTPdataD (key1 protected) , */\ + { 0xfe0f, "mtpdataE"}, /* MTPdataE (key1 protected) , */\ + { 0xff07, "calibr_osc_delta_ndiv"}, /* Calibration data for OSC1M, signed number representation, */\ + { 0xff87, "spare_mtp7_15_08"}, /* SPARE , */\ + { 0xffff,"Unknown bitfield enum" } /* not found */\ +}; + +enum tfa9874_irq { + tfa9874_irq_stvdds = 0, + tfa9874_irq_stbstoc = 1, + tfa9874_irq_stotds = 2, + tfa9874_irq_stocpr = 3, + tfa9874_irq_stuvds = 4, + tfa9874_irq_stmanalarm = 5, + tfa9874_irq_sttdmer = 6, + tfa9874_irq_stnoclk = 7, + tfa9874_irq_max = 8, + tfa9874_irq_all = -1 /* all irqs */}; + +#define TFA9874_IRQ_NAMETABLE static tfaIrqName_t Tfa9874IrqNames[]= {\ + { 0, "STVDDS"},\ + { 1, "STBSTOC"},\ + { 2, "STOTDS"},\ + { 3, "STOCPR"},\ + { 4, "STUVDS"},\ + { 5, "STMANALARM"},\ + { 6, "STTDMER"},\ + { 7, "STNOCLK"},\ + { 8, "8"},\ +}; +#endif /* _TFA9874_TFAFIELDNAMES_H */ diff --git a/techpack/audio/asoc/codecs/tfa9874/tfa9887_tfafieldnames.h b/techpack/audio/asoc/codecs/tfa9874/tfa9887_tfafieldnames.h new file mode 100644 index 000000000000..515b6bc5e0fe --- /dev/null +++ b/techpack/audio/asoc/codecs/tfa9874/tfa9887_tfafieldnames.h @@ -0,0 +1,61 @@ +/** Filename: Tfa9887_TfaFieldnames.h + * This file was generated automatically on 04/14/15 at 10:23:40. + * Source file: TFA9897N1B_I2C_list_URT_source_v34_87Only.xls + */ +#define TFA9887_I2CVERSION 34 +#define TFA9895_I2CVERSION 34 +#define TFA9887_NAMETABLE static tfaBfName_t Tfa9887DatasheetNames[]= {\ + { 0x402, "I2SF"}, /* I2SFormat data 1 input: , */\ + { 0x431, "CHS12"}, /* ChannelSelection data1 input (In CoolFlux) , */\ + { 0x450, "CHS3"}, /* ChannelSelection data 2 input (coolflux input, the DCDC converter gets the other signal), */\ + { 0x461, "CHSA"}, /* Input selection for amplifier , */\ + { 0x4b0, "I2SDOE"}, /* Enable data output , */\ + { 0x4c3, "I2SSR"}, /* sample rate setting , */\ + { 0x500, "BSSBY"}, /* , */\ + { 0x511, "BSSCR"}, /* 00 = 0.56 dB/Sample , */\ + { 0x532, "BSST"}, /* 000 = 2.92V , */\ + { 0x5f0, "I2SDOC"}, /* selection data out , */\ + { 0xa02, "DOLS"}, /* Output selection dataout left channel , */\ + { 0xa32, "DORS"}, /* Output selection dataout right channel , */\ + { 0xa62, "SPKL"}, /* Selection speaker induction , */\ + { 0xa91, "SPKR"}, /* Selection speaker impedance , */\ + { 0xab3, "DCFG"}, /* DCDC speaker current compensation gain , */\ + { 0x4134, "PWMDEL"}, /* PWM DelayBits to set the delay , */\ + { 0x4180, "PWMSH"}, /* PWM Shape , */\ + { 0x4190, "PWMRE"}, /* PWM Bitlength in noise shaper , */\ + { 0x48e1, "TCC"}, /* sample & hold track time: , */\ + { 0xffff,"Unknown bitfield enum" } /* not found */\ +}; + +#define TFA9887_BITNAMETABLE static tfaBfName_t Tfa9887BitNames[]= {\ + { 0x402, "i2s_seti"}, /* I2SFormat data 1 input: , */\ + { 0x431, "chan_sel1"}, /* ChannelSelection data1 input (In CoolFlux) , */\ + { 0x450, "lr_sw_i2si2"}, /* ChannelSelection data 2 input (coolflux input, the DCDC converter gets the other signal), */\ + { 0x461, "input_sel"}, /* Input selection for amplifier , */\ + { 0x4b0, "enbl_datao"}, /* Enable data output , */\ + { 0x4c3, "i2s_fs"}, /* sample rate setting , */\ + { 0x500, "bypass_clipper"}, /* , */\ + { 0x511, "vbat_prot_attacktime[1:0]"}, /* 00 = 0.56 dB/Sample , */\ + { 0x532, "vbat_prot_thlevel[2:0]"}, /* 000 = 2.92V , */\ + { 0x5d0, "reset_min_vbat"}, /* to reset the clipper via I2C in case the CF is bypassed, */\ + { 0x5f0, "datao_sel"}, /* selection data out , */\ + { 0xa02, "sel_i2so_l"}, /* Output selection dataout left channel , */\ + { 0xa32, "sel_i2so_r"}, /* Output selection dataout right channel , */\ + { 0xa62, "ctrl_spkr_coil"}, /* Selection speaker induction , */\ + { 0xa91, "ctrl_spr_res"}, /* Selection speaker impedance , */\ + { 0xab3, "ctrl_dcdc_spkr_i_comp_gain"}, /* DCDC speaker current compensation gain , */\ + { 0xaf0, "ctrl_dcdc_spkr_i_comp_sign"}, /* DCDC speaker current compensation sign , */\ + { 0x4100, "bypass_hp"}, /* bypass_hp, to bypass the hp filter byhind the CoolFlux, */\ + { 0x4110, "hard_mute"}, /* hard mute setting in HW , */\ + { 0x4120, "soft_mute"}, /* Soft mute setting in HW , */\ + { 0x4134, "PWM_Delay[4:0]"}, /* PWM DelayBits to set the delay , */\ + { 0x4180, "PWM_Shape"}, /* PWM Shape , */\ + { 0x4190, "PWM_BitLength"}, /* PWM Bitlength in noise shaper , */\ + { 0x4800, "ctrl_negin"}, /* , */\ + { 0x4810, "ctrl_cs_sein"}, /* , */\ + { 0x4820, "ctrl_coincidencecs"}, /* HIGH => Prevent dcdc switching during clk_cs_clksh, */\ + { 0x4876, "delay_se_neg[6:0]"}, /* delayshiftse2 , */\ + { 0x48e1, "ctrl_cs_ttrack[1:0]"}, /* sample & hold track time: , */\ + { 0xffff,"Unknown bitfield enum" } /* not found */\ +}; + diff --git a/techpack/audio/asoc/codecs/tfa9874/tfa9890_tfafieldnames.h b/techpack/audio/asoc/codecs/tfa9874/tfa9890_tfafieldnames.h new file mode 100644 index 000000000000..e6f0e0228bb6 --- /dev/null +++ b/techpack/audio/asoc/codecs/tfa9874/tfa9890_tfafieldnames.h @@ -0,0 +1,76 @@ +/** Filename: Tfa9890_TfaFieldnames.h + * This file was generated automatically on 04/07/15 at 14:46:37. + * Source file: TFA9897N1B_I2C_list_URT_source_v34_90Only.xls + */ +#define TFA9890_I2CVERSION 34 +#define TFA9890_NAMETABLE static tfaBfName_t Tfa9890DatasheetNames[]= {\ + { 0x402, "I2SF"}, /* I2SFormat data 1 input: , */\ + { 0x431, "CHS12"}, /* ChannelSelection data1 input (In CoolFlux) , */\ + { 0x450, "CHS3"}, /* ChannelSelection data 2 input (coolflux input, the DCDC converter gets the other signal), */\ + { 0x461, "CHSA"}, /* Input selection for amplifier , */\ + { 0x481, "I2SDOC"}, /* selection data out , */\ + { 0x4a0, "DISP"}, /* idp protection , */\ + { 0x4b0, "I2SDOE"}, /* Enable data output , */\ + { 0x4c3, "I2SSR"}, /* sample rate setting , */\ + { 0x732, "DCMCC"}, /* Max boost coil current - step of 500 mA , */\ + { 0x9c0, "CCFD"}, /* Selection CoolFlux Clock , */\ + { 0x9d0, "ISEL"}, /* selection input 1 or 2 , */\ + { 0xa02, "DOLS"}, /* Output selection dataout left channel , */\ + { 0xa32, "DORS"}, /* Output selection dataout right channel , */\ + { 0xa62, "SPKL"}, /* Selection speaker induction , */\ + { 0xa91, "SPKR"}, /* Selection speaker impedance , */\ + { 0xab3, "DCFG"}, /* DCDC speaker current compensation gain , */\ + { 0xf00, "VDDD"}, /* mask flag_por for interupt generation , */\ + { 0xf10, "OTDD"}, /* mask flag_otpok for interupt generation , */\ + { 0xf20, "OVDD"}, /* mask flag_ovpok for interupt generation , */\ + { 0xf30, "UVDD"}, /* mask flag_uvpok for interupt generation , */\ + { 0xf40, "OCDD"}, /* mask flag_ocp_alarm for interupt generation , */\ + { 0xf50, "CLKD"}, /* mask flag_clocks_stable for interupt generation , */\ + { 0xf60, "DCCD"}, /* mask flag_pwrokbst for interupt generation , */\ + { 0xf70, "SPKD"}, /* mask flag_cf_speakererror for interupt generation , */\ + { 0xf80, "WDD"}, /* mask flag_watchdog_reset for interupt generation , */\ + { 0xf90, "LCLK"}, /* mask flag_lost_clk for interupt generation , */\ + { 0xfe0, "INT"}, /* enabling interrupt , */\ + { 0xff0, "INTP"}, /* Setting polarity interupt , */\ + { 0x8f0f, "VERSION"}, /* (key1 protected) , */\ + { 0xffff,"Unknown bitfield enum" } /* not found */\ +}; + +#define TFA9890_BITNAMETABLE static tfaBfName_t Tfa9890BitNames[]= {\ + { 0x402, "i2s_seti"}, /* I2SFormat data 1 input: , */\ + { 0x431, "chan_sel1"}, /* ChannelSelection data1 input (In CoolFlux) , */\ + { 0x450, "lr_sw_i2si2"}, /* ChannelSelection data 2 input (coolflux input, the DCDC converter gets the other signal), */\ + { 0x461, "input_sel"}, /* Input selection for amplifier , */\ + { 0x481, "datao_sel"}, /* selection data out , */\ + { 0x4a0, "disable_idp"}, /* idp protection , */\ + { 0x4b0, "enbl_datao"}, /* Enable data output , */\ + { 0x4c3, "i2s_fs"}, /* sample rate setting , */\ + { 0x732, "ctrl_bstcur"}, /* Max boost coil current - step of 500 mA , */\ + { 0x9c0, "sel_cf_clk"}, /* Selection CoolFlux Clock , */\ + { 0x9d0, "intf_sel"}, /* selection input 1 or 2 , */\ + { 0xa02, "sel_i2so_l"}, /* Output selection dataout left channel , */\ + { 0xa32, "sel_i2so_r"}, /* Output selection dataout right channel , */\ + { 0xa62, "ctrl_spkr_coil"}, /* Selection speaker induction , */\ + { 0xa91, "ctrl_spr_res"}, /* Selection speaker impedance , */\ + { 0xab3, "ctrl_dcdc_spkr_i_comp_gain"}, /* DCDC speaker current compensation gain , */\ + { 0xaf0, "ctrl_dcdc_spkr_i_comp_sign"}, /* DCDC speaker current compensation sign , */\ + { 0xf00, "flag_por_mask"}, /* mask flag_por for interupt generation , */\ + { 0xf10, "flag_otpok_mask"}, /* mask flag_otpok for interupt generation , */\ + { 0xf20, "flag_ovpok_mask"}, /* mask flag_ovpok for interupt generation , */\ + { 0xf30, "flag_uvpok_mask"}, /* mask flag_uvpok for interupt generation , */\ + { 0xf40, "flag_ocp_alarm_mask"}, /* mask flag_ocp_alarm for interupt generation , */\ + { 0xf50, "flag_clocks_stable_mask"}, /* mask flag_clocks_stable for interupt generation , */\ + { 0xf60, "flag_pwrokbst_mask"}, /* mask flag_pwrokbst for interupt generation , */\ + { 0xf70, "flag_cf_speakererror_mask"}, /* mask flag_cf_speakererror for interupt generation , */\ + { 0xf80, "flag_watchdog_reset_mask"}, /* mask flag_watchdog_reset for interupt generation , */\ + { 0xf90, "flag_lost_clk_mask"}, /* mask flag_lost_clk for interupt generation , */\ + { 0xfe0, "enable_interrupt"}, /* enabling interrupt , */\ + { 0xff0, "invert_int_polarity"}, /* Setting polarity interupt , */\ + { 0x4700, "switch_fb"}, /* switch_fb , */\ + { 0x4713, "se_hyst"}, /* se_hyst , */\ + { 0x4754, "se_level"}, /* se_level , */\ + { 0x47a5, "ktemp"}, /* temperature compensation trimming , */\ + { 0x8f0f, "production_data6"}, /* (key1 protected) , */\ + { 0xffff,"Unknown bitfield enum" } /* not found */\ +}; + diff --git a/techpack/audio/asoc/codecs/tfa9874/tfa9891_genregs.h b/techpack/audio/asoc/codecs/tfa9874/tfa9891_genregs.h new file mode 100644 index 000000000000..14f75afc7852 --- /dev/null +++ b/techpack/audio/asoc/codecs/tfa9874/tfa9891_genregs.h @@ -0,0 +1,1125 @@ +/** Filename: Tfa98xx_genregs.h + * This file was generated automatically on 07/01/15 at 10:25:08. + * Source file: TFA9891_I2C_list_V11.xls + */ + +#ifndef TFA9891_GENREGS_H +#define TFA9891_GENREGS_H + + +#define TFA98XX_STATUSREG 0x00 +#define TFA98XX_BATTERYVOLTAGE 0x01 +#define TFA9891_TEMPERATURE 0x02 +#define TFA98XX_REVISIONNUMBER 0x03 +#define TFA98XX_I2SREG 0x04 +#define TFA98XX_BAT_PROT 0x05 +#define TFA98XX_AUDIO_CTR 0x06 +#define TFA98XX_DCDCBOOST 0x07 +#define TFA98XX_SPKR_CALIBRATION 0x08 +#define TFA98XX_SYS_CTRL 0x09 +#define TFA98XX_I2S_SEL_REG 0x0a +#define TFA98XX_HIDDEN_MTP_KEY2 0x0b +#define TFA98XX_INTERRUPT_REG 0x0f +#define TFA98XX_PDM_CTRL 0x10 +#define TFA98XX_PDM_OUT_CTRL 0x11 +#define TFA98XX_PDM_DS4_R 0x12 +#define TFA98XX_PDM_DS4_L 0x13 +#define TFA98XX_CTRL_SAAM_PGA 0x22 +#define TFA98XX_MISC_CTRL 0x25 +#define TFA98XX_CURRENTSENSE1 0x46 +#define TFA98XX_CURRENTSENSE4 0x49 +#define TFA98XX_HIDDEN_MTP_CTRL_REG3 0x62 +#define TFA9891_CF_CONTROLS 0x70 +#define TFA9891_CF_MAD 0x71 +#define TFA9891_CF_MEM 0x72 +#define TFA9891_CF_STATUS 0x73 +#define TFA98XX_KEY2PROTECTED_SPKR_CAL_MTP 0x80 + +/* + * (0x00)-StatusReg + */ + +/* + * POR + */ +#define TFA98XX_STATUSREG_VDDS (0x1<<0) +#define TFA98XX_STATUSREG_VDDS_POS 0 +#define TFA98XX_STATUSREG_VDDS_LEN 1 +#define TFA98XX_STATUSREG_VDDS_MAX 1 +#define TFA98XX_STATUSREG_VDDS_MSK 0x1 + +/* + * PLL_LOCK + */ +#define TFA98XX_STATUSREG_PLLS (0x1<<1) +#define TFA98XX_STATUSREG_PLLS_POS 1 +#define TFA98XX_STATUSREG_PLLS_LEN 1 +#define TFA98XX_STATUSREG_PLLS_MAX 1 +#define TFA98XX_STATUSREG_PLLS_MSK 0x2 + +/* + * flag_otpok + */ +#define TFA98XX_STATUSREG_OTDS (0x1<<2) +#define TFA98XX_STATUSREG_OTDS_POS 2 +#define TFA98XX_STATUSREG_OTDS_LEN 1 +#define TFA98XX_STATUSREG_OTDS_MAX 1 +#define TFA98XX_STATUSREG_OTDS_MSK 0x4 + +/* + * flag_ovpok + */ +#define TFA98XX_STATUSREG_OVDS (0x1<<3) +#define TFA98XX_STATUSREG_OVDS_POS 3 +#define TFA98XX_STATUSREG_OVDS_LEN 1 +#define TFA98XX_STATUSREG_OVDS_MAX 1 +#define TFA98XX_STATUSREG_OVDS_MSK 0x8 + +/* + * flag_uvpok + */ +#define TFA98XX_STATUSREG_UVDS (0x1<<4) +#define TFA98XX_STATUSREG_UVDS_POS 4 +#define TFA98XX_STATUSREG_UVDS_LEN 1 +#define TFA98XX_STATUSREG_UVDS_MAX 1 +#define TFA98XX_STATUSREG_UVDS_MSK 0x10 + +/* + * flag_OCP_alarm + */ +#define TFA98XX_STATUSREG_OCDS (0x1<<5) +#define TFA98XX_STATUSREG_OCDS_POS 5 +#define TFA98XX_STATUSREG_OCDS_LEN 1 +#define TFA98XX_STATUSREG_OCDS_MAX 1 +#define TFA98XX_STATUSREG_OCDS_MSK 0x20 + +/* + * flag_clocks_stable + */ +#define TFA98XX_STATUSREG_CLKS (0x1<<6) +#define TFA98XX_STATUSREG_CLKS_POS 6 +#define TFA98XX_STATUSREG_CLKS_LEN 1 +#define TFA98XX_STATUSREG_CLKS_MAX 1 +#define TFA98XX_STATUSREG_CLKS_MSK 0x40 + +/* + * CLIP + */ +#define TFA98XX_STATUSREG_CLIPS (0x1<<7) +#define TFA98XX_STATUSREG_CLIPS_POS 7 +#define TFA98XX_STATUSREG_CLIPS_LEN 1 +#define TFA98XX_STATUSREG_CLIPS_MAX 1 +#define TFA98XX_STATUSREG_CLIPS_MSK 0x80 + +/* + * mtp_busy + */ +#define TFA98XX_STATUSREG_MTPB (0x1<<8) +#define TFA98XX_STATUSREG_MTPB_POS 8 +#define TFA98XX_STATUSREG_MTPB_LEN 1 +#define TFA98XX_STATUSREG_MTPB_MAX 1 +#define TFA98XX_STATUSREG_MTPB_MSK 0x100 + +/* + * flag_pwrokbst + */ +#define TFA98XX_STATUSREG_DCCS (0x1<<9) +#define TFA98XX_STATUSREG_DCCS_POS 9 +#define TFA98XX_STATUSREG_DCCS_LEN 1 +#define TFA98XX_STATUSREG_DCCS_MAX 1 +#define TFA98XX_STATUSREG_DCCS_MSK 0x200 + +/* + * flag_cf_speakererror + */ +#define TFA98XX_STATUSREG_SPKS (0x1<<10) +#define TFA98XX_STATUSREG_SPKS_POS 10 +#define TFA98XX_STATUSREG_SPKS_LEN 1 +#define TFA98XX_STATUSREG_SPKS_MAX 1 +#define TFA98XX_STATUSREG_SPKS_MSK 0x400 + +/* + * flag_cold_started + */ +#define TFA98XX_STATUSREG_ACS (0x1<<11) +#define TFA98XX_STATUSREG_ACS_POS 11 +#define TFA98XX_STATUSREG_ACS_LEN 1 +#define TFA98XX_STATUSREG_ACS_MAX 1 +#define TFA98XX_STATUSREG_ACS_MSK 0x800 + +/* + * flag_engage + */ +#define TFA98XX_STATUSREG_SWS (0x1<<12) +#define TFA98XX_STATUSREG_SWS_POS 12 +#define TFA98XX_STATUSREG_SWS_LEN 1 +#define TFA98XX_STATUSREG_SWS_MAX 1 +#define TFA98XX_STATUSREG_SWS_MSK 0x1000 + +/* + * flag_watchdog_reset + */ +#define TFA98XX_STATUSREG_WDS (0x1<<13) +#define TFA98XX_STATUSREG_WDS_POS 13 +#define TFA98XX_STATUSREG_WDS_LEN 1 +#define TFA98XX_STATUSREG_WDS_MAX 1 +#define TFA98XX_STATUSREG_WDS_MSK 0x2000 + +/* + * flag_enbl_amp + */ +#define TFA98XX_STATUSREG_AMPS (0x1<<14) +#define TFA98XX_STATUSREG_AMPS_POS 14 +#define TFA98XX_STATUSREG_AMPS_LEN 1 +#define TFA98XX_STATUSREG_AMPS_MAX 1 +#define TFA98XX_STATUSREG_AMPS_MSK 0x4000 + +/* + * flag_enbl_ref + */ +#define TFA98XX_STATUSREG_AREFS (0x1<<15) +#define TFA98XX_STATUSREG_AREFS_POS 15 +#define TFA98XX_STATUSREG_AREFS_LEN 1 +#define TFA98XX_STATUSREG_AREFS_MAX 1 +#define TFA98XX_STATUSREG_AREFS_MSK 0x8000 + +/* + * (0x01)-BatteryVoltage + */ + +/* + * bat_adc + */ +#define TFA98XX_BATTERYVOLTAGE_BATS (0x3ff<<0) +#define TFA98XX_BATTERYVOLTAGE_BATS_POS 0 +#define TFA98XX_BATTERYVOLTAGE_BATS_LEN 10 +#define TFA98XX_BATTERYVOLTAGE_BATS_MAX 1023 +#define TFA98XX_BATTERYVOLTAGE_BATS_MSK 0x3ff + + +/* + * (0x02)-Temperature + */ + +/* + * temp_adc + */ +#define TFA9891_TEMPERATURE_TEMPS (0x1ff<<0) +#define TFA9891_TEMPERATURE_TEMPS_POS 0 +#define TFA9891_TEMPERATURE_TEMPS_LEN 9 +#define TFA9891_TEMPERATURE_TEMPS_MAX 511 +#define TFA9891_TEMPERATURE_TEMPS_MSK 0x1ff + + +/* + * (0x03)-RevisionNumber + */ + +/* + * rev_reg + */ +#define TFA98XX_REVISIONNUMBER_REV (0xff<<0) +#define TFA98XX_REVISIONNUMBER_REV_POS 0 +#define TFA98XX_REVISIONNUMBER_REV_LEN 8 +#define TFA98XX_REVISIONNUMBER_REV_MAX 255 +#define TFA98XX_REVISIONNUMBER_REV_MSK 0xff + + +/* + * (0x04)-I2SReg + */ + +/* + * i2s_seti + */ +#define TFA98XX_I2SREG_I2SF (0x7<<0) +#define TFA98XX_I2SREG_I2SF_POS 0 +#define TFA98XX_I2SREG_I2SF_LEN 3 +#define TFA98XX_I2SREG_I2SF_MAX 7 +#define TFA98XX_I2SREG_I2SF_MSK 0x7 + +/* + * chan_sel1 + */ +#define TFA98XX_I2SREG_CHS12 (0x3<<3) +#define TFA98XX_I2SREG_CHS12_POS 3 +#define TFA98XX_I2SREG_CHS12_LEN 2 +#define TFA98XX_I2SREG_CHS12_MAX 3 +#define TFA98XX_I2SREG_CHS12_MSK 0x18 + +/* + * lr_sw_i2si2 + */ +#define TFA98XX_I2SREG_CHS3 (0x1<<5) +#define TFA98XX_I2SREG_CHS3_POS 5 +#define TFA98XX_I2SREG_CHS3_LEN 1 +#define TFA98XX_I2SREG_CHS3_MAX 1 +#define TFA98XX_I2SREG_CHS3_MSK 0x20 + +/* + * input_sel + */ +#define TFA98XX_I2SREG_CHSA (0x3<<6) +#define TFA98XX_I2SREG_CHSA_POS 6 +#define TFA98XX_I2SREG_CHSA_LEN 2 +#define TFA98XX_I2SREG_CHSA_MAX 3 +#define TFA98XX_I2SREG_CHSA_MSK 0xc0 + +/* + * datao_sel + */ +#define TFA98XX_I2SREG_I2SDOC (0x3<<8) +#define TFA98XX_I2SREG_I2SDOC_POS 8 +#define TFA98XX_I2SREG_I2SDOC_LEN 2 +#define TFA98XX_I2SREG_I2SDOC_MAX 3 +#define TFA98XX_I2SREG_I2SDOC_MSK 0x300 + +/* + * disable_idp + */ +#define TFA98XX_I2SREG_DISP (0x1<<10) +#define TFA98XX_I2SREG_DISP_POS 10 +#define TFA98XX_I2SREG_DISP_LEN 1 +#define TFA98XX_I2SREG_DISP_MAX 1 +#define TFA98XX_I2SREG_DISP_MSK 0x400 + +/* + * enbl_datao + */ +#define TFA98XX_I2SREG_I2SDOE (0x1<<11) +#define TFA98XX_I2SREG_I2SDOE_POS 11 +#define TFA98XX_I2SREG_I2SDOE_LEN 1 +#define TFA98XX_I2SREG_I2SDOE_MAX 1 +#define TFA98XX_I2SREG_I2SDOE_MSK 0x800 + +/* + * i2s_fs + */ +#define TFA98XX_I2SREG_I2SSR (0xf<<12) +#define TFA98XX_I2SREG_I2SSR_POS 12 +#define TFA98XX_I2SREG_I2SSR_LEN 4 +#define TFA98XX_I2SREG_I2SSR_MAX 15 +#define TFA98XX_I2SREG_I2SSR_MSK 0xf000 + + +/* + * (0x05)-bat_prot + */ + +/* + * vbat_prot_attacktime + */ +#define TFA98XX_BAT_PROT_BSSCR (0x3<<0) +#define TFA98XX_BAT_PROT_BSSCR_POS 0 +#define TFA98XX_BAT_PROT_BSSCR_LEN 2 +#define TFA98XX_BAT_PROT_BSSCR_MAX 3 +#define TFA98XX_BAT_PROT_BSSCR_MSK 0x3 + +/* + * vbat_prot_thlevel + */ +#define TFA98XX_BAT_PROT_BSST (0xf<<2) +#define TFA98XX_BAT_PROT_BSST_POS 2 +#define TFA98XX_BAT_PROT_BSST_LEN 4 +#define TFA98XX_BAT_PROT_BSST_MAX 15 +#define TFA98XX_BAT_PROT_BSST_MSK 0x3c + +/* + * vbat_prot_max_reduct + */ +#define TFA98XX_BAT_PROT_BSSRL (0x3<<6) +#define TFA98XX_BAT_PROT_BSSRL_POS 6 +#define TFA98XX_BAT_PROT_BSSRL_LEN 2 +#define TFA98XX_BAT_PROT_BSSRL_MAX 3 +#define TFA98XX_BAT_PROT_BSSRL_MSK 0xc0 + +/* + * vbat_prot_release_t + */ +#define TFA98XX_BAT_PROT_BSSRR (0x7<<8) +#define TFA98XX_BAT_PROT_BSSRR_POS 8 +#define TFA98XX_BAT_PROT_BSSRR_LEN 3 +#define TFA98XX_BAT_PROT_BSSRR_MAX 7 +#define TFA98XX_BAT_PROT_BSSRR_MSK 0x700 + +/* + * vbat_prot_hysterese + */ +#define TFA98XX_BAT_PROT_BSSHY (0x3<<11) +#define TFA98XX_BAT_PROT_BSSHY_POS 11 +#define TFA98XX_BAT_PROT_BSSHY_LEN 2 +#define TFA98XX_BAT_PROT_BSSHY_MAX 3 +#define TFA98XX_BAT_PROT_BSSHY_MSK 0x1800 + +/* + * sel_vbat + */ +#define TFA98XX_BAT_PROT_BSSR (0x1<<14) +#define TFA98XX_BAT_PROT_BSSR_POS 14 +#define TFA98XX_BAT_PROT_BSSR_LEN 1 +#define TFA98XX_BAT_PROT_BSSR_MAX 1 +#define TFA98XX_BAT_PROT_BSSR_MSK 0x4000 + +/* + * bypass_clipper + */ +#define TFA98XX_BAT_PROT_BSSBY (0x1<<15) +#define TFA98XX_BAT_PROT_BSSBY_POS 15 +#define TFA98XX_BAT_PROT_BSSBY_LEN 1 +#define TFA98XX_BAT_PROT_BSSBY_MAX 1 +#define TFA98XX_BAT_PROT_BSSBY_MSK 0x8000 + + +/* + * (0x06)-audio_ctr + */ + +/* + * dpsa + */ +#define TFA98XX_AUDIO_CTR_DPSA (0x1<<0) +#define TFA98XX_AUDIO_CTR_DPSA_POS 0 +#define TFA98XX_AUDIO_CTR_DPSA_LEN 1 +#define TFA98XX_AUDIO_CTR_DPSA_MAX 1 +#define TFA98XX_AUDIO_CTR_DPSA_MSK 0x1 + +/* + * ctrl_slope + */ +#define TFA98XX_AUDIO_CTR_AMPSL (0xf<<1) +#define TFA98XX_AUDIO_CTR_AMPSL_POS 1 +#define TFA98XX_AUDIO_CTR_AMPSL_LEN 4 +#define TFA98XX_AUDIO_CTR_AMPSL_MAX 15 +#define TFA98XX_AUDIO_CTR_AMPSL_MSK 0x1e + +/* + * cf_mute + */ +#define TFA98XX_AUDIO_CTR_CFSM (0x1<<5) +#define TFA98XX_AUDIO_CTR_CFSM_POS 5 +#define TFA98XX_AUDIO_CTR_CFSM_LEN 1 +#define TFA98XX_AUDIO_CTR_CFSM_MAX 1 +#define TFA98XX_AUDIO_CTR_CFSM_MSK 0x20 + +/* + * ctrl_batsensesteepness + */ +#define TFA98XX_AUDIO_CTR_BSSS (0x1<<7) +#define TFA98XX_AUDIO_CTR_BSSS_POS 7 +#define TFA98XX_AUDIO_CTR_BSSS_LEN 1 +#define TFA98XX_AUDIO_CTR_BSSS_MAX 1 +#define TFA98XX_AUDIO_CTR_BSSS_MSK 0x80 + +/* + * vol + */ +#define TFA98XX_AUDIO_CTR_VOL (0xff<<8) +#define TFA98XX_AUDIO_CTR_VOL_POS 8 +#define TFA98XX_AUDIO_CTR_VOL_LEN 8 +#define TFA98XX_AUDIO_CTR_VOL_MAX 255 +#define TFA98XX_AUDIO_CTR_VOL_MSK 0xff00 + + +/* + * (0x07)-DCDCboost + */ + +/* + * ctrl_bstvolt + */ +#define TFA98XX_DCDCBOOST_DCVO (0x7<<0) +#define TFA98XX_DCDCBOOST_DCVO_POS 0 +#define TFA98XX_DCDCBOOST_DCVO_LEN 3 +#define TFA98XX_DCDCBOOST_DCVO_MAX 7 +#define TFA98XX_DCDCBOOST_DCVO_MSK 0x7 + +/* + * ctrl_bstcur + */ +#define TFA98XX_DCDCBOOST_DCMCC (0x7<<3) +#define TFA98XX_DCDCBOOST_DCMCC_POS 3 +#define TFA98XX_DCDCBOOST_DCMCC_LEN 3 +#define TFA98XX_DCDCBOOST_DCMCC_MAX 7 +#define TFA98XX_DCDCBOOST_DCMCC_MSK 0x38 + +/* + * boost_intel + */ +#define TFA98XX_DCDCBOOST_DCIE (0x1<<10) +#define TFA98XX_DCDCBOOST_DCIE_POS 10 +#define TFA98XX_DCDCBOOST_DCIE_LEN 1 +#define TFA98XX_DCDCBOOST_DCIE_MAX 1 +#define TFA98XX_DCDCBOOST_DCIE_MSK 0x400 + +/* + * boost_speed + */ +#define TFA98XX_DCDCBOOST_DCSR (0x1<<11) +#define TFA98XX_DCDCBOOST_DCSR_POS 11 +#define TFA98XX_DCDCBOOST_DCSR_LEN 1 +#define TFA98XX_DCDCBOOST_DCSR_MAX 1 +#define TFA98XX_DCDCBOOST_DCSR_MSK 0x800 + + +/* + * (0x08)-spkr_calibration + */ + +/* + * ext_temp_sel + */ +#define TFA98XX_SPKR_CALIBRATION_TROS (0x1<<0) +#define TFA98XX_SPKR_CALIBRATION_TROS_POS 0 +#define TFA98XX_SPKR_CALIBRATION_TROS_LEN 1 +#define TFA98XX_SPKR_CALIBRATION_TROS_MAX 1 +#define TFA98XX_SPKR_CALIBRATION_TROS_MSK 0x1 + +/* + * ext_temp + */ +#define TFA98XX_SPKR_CALIBRATION_EXTTS (0x1ff<<1) +#define TFA98XX_SPKR_CALIBRATION_EXTTS_POS 1 +#define TFA98XX_SPKR_CALIBRATION_EXTTS_LEN 9 +#define TFA98XX_SPKR_CALIBRATION_EXTTS_MAX 511 +#define TFA98XX_SPKR_CALIBRATION_EXTTS_MSK 0x3fe + + +/* + * (0x09)-sys_ctrl + */ + +/* + * PowerDown + */ +#define TFA98XX_SYS_CTRL_PWDN (0x1<<0) +#define TFA98XX_SYS_CTRL_PWDN_POS 0 +#define TFA98XX_SYS_CTRL_PWDN_LEN 1 +#define TFA98XX_SYS_CTRL_PWDN_MAX 1 +#define TFA98XX_SYS_CTRL_PWDN_MSK 0x1 + +/* + * reset + */ +#define TFA98XX_SYS_CTRL_I2CR (0x1<<1) +#define TFA98XX_SYS_CTRL_I2CR_POS 1 +#define TFA98XX_SYS_CTRL_I2CR_LEN 1 +#define TFA98XX_SYS_CTRL_I2CR_MAX 1 +#define TFA98XX_SYS_CTRL_I2CR_MSK 0x2 + +/* + * enbl_coolflux + */ +#define TFA98XX_SYS_CTRL_CFE (0x1<<2) +#define TFA98XX_SYS_CTRL_CFE_POS 2 +#define TFA98XX_SYS_CTRL_CFE_LEN 1 +#define TFA98XX_SYS_CTRL_CFE_MAX 1 +#define TFA98XX_SYS_CTRL_CFE_MSK 0x4 + +/* + * enbl_amplifier + */ +#define TFA98XX_SYS_CTRL_AMPE (0x1<<3) +#define TFA98XX_SYS_CTRL_AMPE_POS 3 +#define TFA98XX_SYS_CTRL_AMPE_LEN 1 +#define TFA98XX_SYS_CTRL_AMPE_MAX 1 +#define TFA98XX_SYS_CTRL_AMPE_MSK 0x8 + +/* + * enbl_boost + */ +#define TFA98XX_SYS_CTRL_DCA (0x1<<4) +#define TFA98XX_SYS_CTRL_DCA_POS 4 +#define TFA98XX_SYS_CTRL_DCA_LEN 1 +#define TFA98XX_SYS_CTRL_DCA_MAX 1 +#define TFA98XX_SYS_CTRL_DCA_MSK 0x10 + +/* + * cf_configured + */ +#define TFA98XX_SYS_CTRL_SBSL (0x1<<5) +#define TFA98XX_SYS_CTRL_SBSL_POS 5 +#define TFA98XX_SYS_CTRL_SBSL_LEN 1 +#define TFA98XX_SYS_CTRL_SBSL_MAX 1 +#define TFA98XX_SYS_CTRL_SBSL_MSK 0x20 + +/* + * sel_enbl_amplifier + */ +#define TFA98XX_SYS_CTRL_AMPC (0x1<<6) +#define TFA98XX_SYS_CTRL_AMPC_POS 6 +#define TFA98XX_SYS_CTRL_AMPC_LEN 1 +#define TFA98XX_SYS_CTRL_AMPC_MAX 1 +#define TFA98XX_SYS_CTRL_AMPC_MSK 0x40 + +/* + * dcdcoff_mode + */ +#define TFA98XX_SYS_CTRL_DCDIS (0x1<<7) +#define TFA98XX_SYS_CTRL_DCDIS_POS 7 +#define TFA98XX_SYS_CTRL_DCDIS_LEN 1 +#define TFA98XX_SYS_CTRL_DCDIS_MAX 1 +#define TFA98XX_SYS_CTRL_DCDIS_MSK 0x80 + +/* + * cttr_iddqtest + */ +#define TFA98XX_SYS_CTRL_PSDR (0x1<<8) +#define TFA98XX_SYS_CTRL_PSDR_POS 8 +#define TFA98XX_SYS_CTRL_PSDR_LEN 1 +#define TFA98XX_SYS_CTRL_PSDR_MAX 1 +#define TFA98XX_SYS_CTRL_PSDR_MSK 0x100 + +/* + * ctrl_coil_value + */ +#define TFA98XX_SYS_CTRL_DCCV (0x3<<9) +#define TFA98XX_SYS_CTRL_DCCV_POS 9 +#define TFA98XX_SYS_CTRL_DCCV_LEN 2 +#define TFA98XX_SYS_CTRL_DCCV_MAX 3 +#define TFA98XX_SYS_CTRL_DCCV_MSK 0x600 + +/* + * ctrl_sel_cf_clock + */ +#define TFA98XX_SYS_CTRL_CCFD (0x3<<11) +#define TFA98XX_SYS_CTRL_CCFD_POS 11 +#define TFA98XX_SYS_CTRL_CCFD_LEN 2 +#define TFA98XX_SYS_CTRL_CCFD_MAX 3 +#define TFA98XX_SYS_CTRL_CCFD_MSK 0x1800 + +/* + * intf_sel + */ +#define TFA98XX_SYS_CTRL_ISEL (0x1<<13) +#define TFA98XX_SYS_CTRL_ISEL_POS 13 +#define TFA98XX_SYS_CTRL_ISEL_LEN 1 +#define TFA98XX_SYS_CTRL_ISEL_MAX 1 +#define TFA98XX_SYS_CTRL_ISEL_MSK 0x2000 + +/* + * sel_ws_bck + */ +#define TFA98XX_SYS_CTRL_IPLL (0x1<<14) +#define TFA98XX_SYS_CTRL_IPLL_POS 14 +#define TFA98XX_SYS_CTRL_IPLL_LEN 1 +#define TFA98XX_SYS_CTRL_IPLL_MAX 1 +#define TFA98XX_SYS_CTRL_IPLL_MSK 0x4000 + + +/* + * (0x0a)-I2S_sel_reg + */ + +/* + * sel_i2so_l + */ +#define TFA98XX_I2S_SEL_REG_DOLS (0x7<<0) +#define TFA98XX_I2S_SEL_REG_DOLS_POS 0 +#define TFA98XX_I2S_SEL_REG_DOLS_LEN 3 +#define TFA98XX_I2S_SEL_REG_DOLS_MAX 7 +#define TFA98XX_I2S_SEL_REG_DOLS_MSK 0x7 + +/* + * sel_i2so_r + */ +#define TFA98XX_I2S_SEL_REG_DORS (0x7<<3) +#define TFA98XX_I2S_SEL_REG_DORS_POS 3 +#define TFA98XX_I2S_SEL_REG_DORS_LEN 3 +#define TFA98XX_I2S_SEL_REG_DORS_MAX 7 +#define TFA98XX_I2S_SEL_REG_DORS_MSK 0x38 + +/* + * ctrl_spkr_coil + */ +#define TFA98XX_I2S_SEL_REG_SPKL (0x7<<6) +#define TFA98XX_I2S_SEL_REG_SPKL_POS 6 +#define TFA98XX_I2S_SEL_REG_SPKL_LEN 3 +#define TFA98XX_I2S_SEL_REG_SPKL_MAX 7 +#define TFA98XX_I2S_SEL_REG_SPKL_MSK 0x1c0 + +/* + * ctrl_spr_res + */ +#define TFA98XX_I2S_SEL_REG_SPKR (0x3<<9) +#define TFA98XX_I2S_SEL_REG_SPKR_POS 9 +#define TFA98XX_I2S_SEL_REG_SPKR_LEN 2 +#define TFA98XX_I2S_SEL_REG_SPKR_MAX 3 +#define TFA98XX_I2S_SEL_REG_SPKR_MSK 0x600 + +/* + * ctrl_dcdc_spkr_i_comp_gain + */ +#define TFA98XX_I2S_SEL_REG_DCFG (0xf<<11) +#define TFA98XX_I2S_SEL_REG_DCFG_POS 11 +#define TFA98XX_I2S_SEL_REG_DCFG_LEN 4 +#define TFA98XX_I2S_SEL_REG_DCFG_MAX 15 +#define TFA98XX_I2S_SEL_REG_DCFG_MSK 0x7800 + + +/* + * (0x0b)-Hidden_mtp_key2 + */ + +/* + * MTP_key2 + */ +#define TFA98XX_HIDDEN_MTP_KEY2_MTPK (0xff<<0) +#define TFA98XX_HIDDEN_MTP_KEY2_MTPK_POS 0 +#define TFA98XX_HIDDEN_MTP_KEY2_MTPK_LEN 8 +#define TFA98XX_HIDDEN_MTP_KEY2_MTPK_MAX 255 +#define TFA98XX_HIDDEN_MTP_KEY2_MTPK_MSK 0xff + + +/* + * (0x0f)-interrupt_reg + */ + +/* + * flag_por_mask + */ +#define TFA98XX_INTERRUPT_REG_VDDD (0x1<<0) +#define TFA98XX_INTERRUPT_REG_VDDD_POS 0 +#define TFA98XX_INTERRUPT_REG_VDDD_LEN 1 +#define TFA98XX_INTERRUPT_REG_VDDD_MAX 1 +#define TFA98XX_INTERRUPT_REG_VDDD_MSK 0x1 + +/* + * flag_otpok_mask + */ +#define TFA98XX_INTERRUPT_REG_OTDD (0x1<<1) +#define TFA98XX_INTERRUPT_REG_OTDD_POS 1 +#define TFA98XX_INTERRUPT_REG_OTDD_LEN 1 +#define TFA98XX_INTERRUPT_REG_OTDD_MAX 1 +#define TFA98XX_INTERRUPT_REG_OTDD_MSK 0x2 + +/* + * flag_ovpok_mask + */ +#define TFA98XX_INTERRUPT_REG_OVDD (0x1<<2) +#define TFA98XX_INTERRUPT_REG_OVDD_POS 2 +#define TFA98XX_INTERRUPT_REG_OVDD_LEN 1 +#define TFA98XX_INTERRUPT_REG_OVDD_MAX 1 +#define TFA98XX_INTERRUPT_REG_OVDD_MSK 0x4 + +/* + * flag_uvpok_mask + */ +#define TFA98XX_INTERRUPT_REG_UVDD (0x1<<3) +#define TFA98XX_INTERRUPT_REG_UVDD_POS 3 +#define TFA98XX_INTERRUPT_REG_UVDD_LEN 1 +#define TFA98XX_INTERRUPT_REG_UVDD_MAX 1 +#define TFA98XX_INTERRUPT_REG_UVDD_MSK 0x8 + +/* + * flag_ocp_alarm_mask + */ +#define TFA98XX_INTERRUPT_REG_OCDD (0x1<<4) +#define TFA98XX_INTERRUPT_REG_OCDD_POS 4 +#define TFA98XX_INTERRUPT_REG_OCDD_LEN 1 +#define TFA98XX_INTERRUPT_REG_OCDD_MAX 1 +#define TFA98XX_INTERRUPT_REG_OCDD_MSK 0x10 + +/* + * flag_clocks_stable_mask + */ +#define TFA98XX_INTERRUPT_REG_CLKD (0x1<<5) +#define TFA98XX_INTERRUPT_REG_CLKD_POS 5 +#define TFA98XX_INTERRUPT_REG_CLKD_LEN 1 +#define TFA98XX_INTERRUPT_REG_CLKD_MAX 1 +#define TFA98XX_INTERRUPT_REG_CLKD_MSK 0x20 + +/* + * flag_pwrokbst_mask + */ +#define TFA98XX_INTERRUPT_REG_DCCD (0x1<<6) +#define TFA98XX_INTERRUPT_REG_DCCD_POS 6 +#define TFA98XX_INTERRUPT_REG_DCCD_LEN 1 +#define TFA98XX_INTERRUPT_REG_DCCD_MAX 1 +#define TFA98XX_INTERRUPT_REG_DCCD_MSK 0x40 + +/* + * flag_cf_speakererror_mask + */ +#define TFA98XX_INTERRUPT_REG_SPKD (0x1<<7) +#define TFA98XX_INTERRUPT_REG_SPKD_POS 7 +#define TFA98XX_INTERRUPT_REG_SPKD_LEN 1 +#define TFA98XX_INTERRUPT_REG_SPKD_MAX 1 +#define TFA98XX_INTERRUPT_REG_SPKD_MSK 0x80 + +/* + * flag_watchdog_reset_mask + */ +#define TFA98XX_INTERRUPT_REG_WDD (0x1<<8) +#define TFA98XX_INTERRUPT_REG_WDD_POS 8 +#define TFA98XX_INTERRUPT_REG_WDD_LEN 1 +#define TFA98XX_INTERRUPT_REG_WDD_MAX 1 +#define TFA98XX_INTERRUPT_REG_WDD_MSK 0x100 + +/* + * enable_interrupt + */ +#define TFA98XX_INTERRUPT_REG_INT (0x1<<14) +#define TFA98XX_INTERRUPT_REG_INT_POS 14 +#define TFA98XX_INTERRUPT_REG_INT_LEN 1 +#define TFA98XX_INTERRUPT_REG_INT_MAX 1 +#define TFA98XX_INTERRUPT_REG_INT_MSK 0x4000 + +/* + * invert_int_polarity + */ +#define TFA98XX_INTERRUPT_REG_INTP (0x1<<15) +#define TFA98XX_INTERRUPT_REG_INTP_POS 15 +#define TFA98XX_INTERRUPT_REG_INTP_LEN 1 +#define TFA98XX_INTERRUPT_REG_INTP_MAX 1 +#define TFA98XX_INTERRUPT_REG_INTP_MSK 0x8000 + + +/* + * (0x10)-pdm_ctrl + */ + +/* + * pdm_i2s_input + */ +#define TFA98XX_PDM_CTRL_PDMSEL (0x1<<0) +#define TFA98XX_PDM_CTRL_PDMSEL_POS 0 +#define TFA98XX_PDM_CTRL_PDMSEL_LEN 1 +#define TFA98XX_PDM_CTRL_PDMSEL_MAX 1 +#define TFA98XX_PDM_CTRL_PDMSEL_MSK 0x1 + +/* + * I2S_master_ena + */ +#define TFA98XX_PDM_CTRL_I2SMOUTEN (0x1<<1) +#define TFA98XX_PDM_CTRL_I2SMOUTEN_POS 1 +#define TFA98XX_PDM_CTRL_I2SMOUTEN_LEN 1 +#define TFA98XX_PDM_CTRL_I2SMOUTEN_MAX 1 +#define TFA98XX_PDM_CTRL_I2SMOUTEN_MSK 0x2 + +/* + * pdm_out_sel_r + */ +#define TFA98XX_PDM_CTRL_PDMORSEL (0x3<<2) +#define TFA98XX_PDM_CTRL_PDMORSEL_POS 2 +#define TFA98XX_PDM_CTRL_PDMORSEL_LEN 2 +#define TFA98XX_PDM_CTRL_PDMORSEL_MAX 3 +#define TFA98XX_PDM_CTRL_PDMORSEL_MSK 0xc + +/* + * pdm_out_sel_l + */ +#define TFA98XX_PDM_CTRL_PDMOLSEL (0x3<<4) +#define TFA98XX_PDM_CTRL_PDMOLSEL_POS 4 +#define TFA98XX_PDM_CTRL_PDMOLSEL_LEN 2 +#define TFA98XX_PDM_CTRL_PDMOLSEL_MAX 3 +#define TFA98XX_PDM_CTRL_PDMOLSEL_MSK 0x30 + +/* + * micdat_out_sel + */ +#define TFA98XX_PDM_CTRL_PADSEL (0x3<<6) +#define TFA98XX_PDM_CTRL_PADSEL_POS 6 +#define TFA98XX_PDM_CTRL_PADSEL_LEN 2 +#define TFA98XX_PDM_CTRL_PADSEL_MAX 3 +#define TFA98XX_PDM_CTRL_PADSEL_MSK 0xc0 + + +/* + * (0x11)-pdm_out_ctrl + */ + +/* + * secure_dly + */ +#define TFA98XX_PDM_OUT_CTRL_PDMOSDEN (0x1<<0) +#define TFA98XX_PDM_OUT_CTRL_PDMOSDEN_POS 0 +#define TFA98XX_PDM_OUT_CTRL_PDMOSDEN_LEN 1 +#define TFA98XX_PDM_OUT_CTRL_PDMOSDEN_MAX 1 +#define TFA98XX_PDM_OUT_CTRL_PDMOSDEN_MSK 0x1 + +/* + * d_out_valid_rf_mux + */ +#define TFA98XX_PDM_OUT_CTRL_PDMOSDCF (0x1<<1) +#define TFA98XX_PDM_OUT_CTRL_PDMOSDCF_POS 1 +#define TFA98XX_PDM_OUT_CTRL_PDMOSDCF_LEN 1 +#define TFA98XX_PDM_OUT_CTRL_PDMOSDCF_MAX 1 +#define TFA98XX_PDM_OUT_CTRL_PDMOSDCF_MSK 0x2 + +/* + * Speak_As_Mic_en + */ +#define TFA98XX_PDM_OUT_CTRL_SAAMEN (0x1<<4) +#define TFA98XX_PDM_OUT_CTRL_SAAMEN_POS 4 +#define TFA98XX_PDM_OUT_CTRL_SAAMEN_LEN 1 +#define TFA98XX_PDM_OUT_CTRL_SAAMEN_MAX 1 +#define TFA98XX_PDM_OUT_CTRL_SAAMEN_MSK 0x10 + +/* + * speak_as_mic_lp_mode + */ +#define TFA98XX_PDM_OUT_CTRL_SAAMLPEN (0x1<<5) +#define TFA98XX_PDM_OUT_CTRL_SAAMLPEN_POS 5 +#define TFA98XX_PDM_OUT_CTRL_SAAMLPEN_LEN 1 +#define TFA98XX_PDM_OUT_CTRL_SAAMLPEN_MAX 1 +#define TFA98XX_PDM_OUT_CTRL_SAAMLPEN_MSK 0x20 + +/* + * pdm_out_rate + */ +#define TFA98XX_PDM_OUT_CTRL_PDMOINTEN (0x1<<6) +#define TFA98XX_PDM_OUT_CTRL_PDMOINTEN_POS 6 +#define TFA98XX_PDM_OUT_CTRL_PDMOINTEN_LEN 1 +#define TFA98XX_PDM_OUT_CTRL_PDMOINTEN_MAX 1 +#define TFA98XX_PDM_OUT_CTRL_PDMOINTEN_MSK 0x40 + + +/* + * (0x12)-pdm_ds4_r + */ + +/* + * ds4_g1_r + */ +#define TFA98XX_PDM_DS4_R_PDMORG1 (0xf<<0) +#define TFA98XX_PDM_DS4_R_PDMORG1_POS 0 +#define TFA98XX_PDM_DS4_R_PDMORG1_LEN 4 +#define TFA98XX_PDM_DS4_R_PDMORG1_MAX 15 +#define TFA98XX_PDM_DS4_R_PDMORG1_MSK 0xf + +/* + * ds4_g2_r + */ +#define TFA98XX_PDM_DS4_R_PDMORG2 (0xf<<4) +#define TFA98XX_PDM_DS4_R_PDMORG2_POS 4 +#define TFA98XX_PDM_DS4_R_PDMORG2_LEN 4 +#define TFA98XX_PDM_DS4_R_PDMORG2_MAX 15 +#define TFA98XX_PDM_DS4_R_PDMORG2_MSK 0xf0 + + +/* + * (0x13)-pdm_ds4_l + */ + +/* + * ds4_g1_l + */ +#define TFA98XX_PDM_DS4_L_PDMOLG1 (0xf<<0) +#define TFA98XX_PDM_DS4_L_PDMOLG1_POS 0 +#define TFA98XX_PDM_DS4_L_PDMOLG1_LEN 4 +#define TFA98XX_PDM_DS4_L_PDMOLG1_MAX 15 +#define TFA98XX_PDM_DS4_L_PDMOLG1_MSK 0xf + +/* + * ds4_g2_l + */ +#define TFA98XX_PDM_DS4_L_PDMOLG2 (0xf<<4) +#define TFA98XX_PDM_DS4_L_PDMOLG2_POS 4 +#define TFA98XX_PDM_DS4_L_PDMOLG2_LEN 4 +#define TFA98XX_PDM_DS4_L_PDMOLG2_MAX 15 +#define TFA98XX_PDM_DS4_L_PDMOLG2_MSK 0xf0 + + +/* + * (0x22)-ctrl_saam_pga + */ + +/* + * Ctrl_saam_pga_gain + */ +#define TFA98XX_CTRL_SAAM_PGA_SAAMGAIN (0x7<<0) +#define TFA98XX_CTRL_SAAM_PGA_SAAMGAIN_POS 0 +#define TFA98XX_CTRL_SAAM_PGA_SAAMGAIN_LEN 3 +#define TFA98XX_CTRL_SAAM_PGA_SAAMGAIN_MAX 7 +#define TFA98XX_CTRL_SAAM_PGA_SAAMGAIN_MSK 0x7 + +/* + * ctrl_saam_pga_src + */ +#define TFA98XX_CTRL_SAAM_PGA_SAAMPGACTRL (0x1<<5) +#define TFA98XX_CTRL_SAAM_PGA_SAAMPGACTRL_POS 5 +#define TFA98XX_CTRL_SAAM_PGA_SAAMPGACTRL_LEN 1 +#define TFA98XX_CTRL_SAAM_PGA_SAAMPGACTRL_MAX 1 +#define TFA98XX_CTRL_SAAM_PGA_SAAMPGACTRL_MSK 0x20 + + +/* + * (0x25)-misc_ctrl + */ + +/* + * pll_fcco + */ +#define TFA98XX_MISC_CTRL_PLLCCOSEL (0x1<<0) +#define TFA98XX_MISC_CTRL_PLLCCOSEL_POS 0 +#define TFA98XX_MISC_CTRL_PLLCCOSEL_LEN 1 +#define TFA98XX_MISC_CTRL_PLLCCOSEL_MAX 1 +#define TFA98XX_MISC_CTRL_PLLCCOSEL_MSK 0x1 + + +/* + * (0x46)-CurrentSense1 + */ + +/* + * bypass_gc + */ +#define TFA98XX_CURRENTSENSE1_CSBYPGC (0x1<<0) +#define TFA98XX_CURRENTSENSE1_CSBYPGC_POS 0 +#define TFA98XX_CURRENTSENSE1_CSBYPGC_LEN 1 +#define TFA98XX_CURRENTSENSE1_CSBYPGC_MAX 1 +#define TFA98XX_CURRENTSENSE1_CSBYPGC_MSK 0x1 + + +/* + * (0x49)-CurrentSense4 + */ + +/* + * ctrl_bypassclip + */ +#define TFA98XX_CURRENTSENSE4_CLIP (0x1<<0) +#define TFA98XX_CURRENTSENSE4_CLIP_POS 0 +#define TFA98XX_CURRENTSENSE4_CLIP_LEN 1 +#define TFA98XX_CURRENTSENSE4_CLIP_MAX 1 +#define TFA98XX_CURRENTSENSE4_CLIP_MSK 0x1 + +/* + * ctrl_bypassclip2 + */ +#define TFA98XX_CURRENTSENSE4_CLIP2 (0x1<<1) +#define TFA98XX_CURRENTSENSE4_CLIP2_POS 1 +#define TFA98XX_CURRENTSENSE4_CLIP2_LEN 1 +#define TFA98XX_CURRENTSENSE4_CLIP2_MAX 1 +#define TFA98XX_CURRENTSENSE4_CLIP2_MSK 0x2 + + +/* + * (0x62)-Hidden_mtp_ctrl_reg3 + */ + + +/* + * (0x70)-cf_controls + */ + +/* + * cf_rst_dsp + */ +#define TFA98XX_CF_CONTROLS_RST (0x1<<0) +#define TFA98XX_CF_CONTROLS_RST_POS 0 +#define TFA98XX_CF_CONTROLS_RST_LEN 1 +#define TFA98XX_CF_CONTROLS_RST_MAX 1 +#define TFA98XX_CF_CONTROLS_RST_MSK 0x1 + +/* + * cf_dmem + */ +#define TFA98XX_CF_CONTROLS_DMEM (0x3<<1) +#define TFA98XX_CF_CONTROLS_DMEM_POS 1 +#define TFA98XX_CF_CONTROLS_DMEM_LEN 2 +#define TFA98XX_CF_CONTROLS_DMEM_MAX 3 +#define TFA98XX_CF_CONTROLS_DMEM_MSK 0x6 + +/* + * cf_aif + */ +#define TFA98XX_CF_CONTROLS_AIF (0x1<<3) +#define TFA98XX_CF_CONTROLS_AIF_POS 3 +#define TFA98XX_CF_CONTROLS_AIF_LEN 1 +#define TFA98XX_CF_CONTROLS_AIF_MAX 1 +#define TFA98XX_CF_CONTROLS_AIF_MSK 0x8 + +/* + * cf_int + */ +#define TFA98XX_CF_CONTROLS_CFINT (0x1<<4) +#define TFA98XX_CF_CONTROLS_CFINT_POS 4 +#define TFA98XX_CF_CONTROLS_CFINT_LEN 1 +#define TFA98XX_CF_CONTROLS_CFINT_MAX 1 +#define TFA98XX_CF_CONTROLS_CFINT_MSK 0x10 + +/* + * cf_req + */ +#define TFA98XX_CF_CONTROLS_REQ (0xff<<8) +#define TFA98XX_CF_CONTROLS_REQ_POS 8 +#define TFA98XX_CF_CONTROLS_REQ_LEN 8 +#define TFA98XX_CF_CONTROLS_REQ_MAX 255 +#define TFA98XX_CF_CONTROLS_REQ_MSK 0xff00 + + +/* + * (0x71)-cf_mad + */ + +/* + * cf_madd + */ +#define TFA9891_CF_MAD_MADD (0xffff<<0) +#define TFA9891_CF_MAD_MADD_POS 0 +#define TFA9891_CF_MAD_MADD_LEN 16 +#define TFA9891_CF_MAD_MADD_MAX 65535 +#define TFA9891_CF_MAD_MADD_MSK 0xffff + + +/* + * (0x72)-cf_mem + */ + +/* + * cf_mema + */ +#define TFA9891_CF_MEM_MEMA (0xffff<<0) +#define TFA9891_CF_MEM_MEMA_POS 0 +#define TFA9891_CF_MEM_MEMA_LEN 16 +#define TFA9891_CF_MEM_MEMA_MAX 65535 +#define TFA9891_CF_MEM_MEMA_MSK 0xffff + + +/* + * (0x73)-cf_status + */ + +/* + * cf_err + */ +#define TFA9891_CF_STATUS_ERR (0xff<<0) +#define TFA9891_CF_STATUS_ERR_POS 0 +#define TFA9891_CF_STATUS_ERR_LEN 8 +#define TFA9891_CF_STATUS_ERR_MAX 255 +#define TFA9891_CF_STATUS_ERR_MSK 0xff + +/* + * cf_ack + */ +#define TFA9891_CF_STATUS_ACK (0xff<<8) +#define TFA9891_CF_STATUS_ACK_POS 8 +#define TFA9891_CF_STATUS_ACK_LEN 8 +#define TFA9891_CF_STATUS_ACK_MAX 255 +#define TFA9891_CF_STATUS_ACK_MSK 0xff00 + + +/* + * (0x80)-Key2Protected_spkr_cal_mtp + */ + +/* + * calibration_onetime + */ +#define TFA98XX_KEY2PROTECTED_SPKR_CAL_MTP_MTPOTC (0x1<<0) +#define TFA98XX_KEY2PROTECTED_SPKR_CAL_MTP_MTPOTC_POS 0 +#define TFA98XX_KEY2PROTECTED_SPKR_CAL_MTP_MTPOTC_LEN 1 +#define TFA98XX_KEY2PROTECTED_SPKR_CAL_MTP_MTPOTC_MAX 1 +#define TFA98XX_KEY2PROTECTED_SPKR_CAL_MTP_MTPOTC_MSK 0x1 + +/* + * calibr_ron_done + */ +#define TFA98XX_KEY2PROTECTED_SPKR_CAL_MTP_MTPEX (0x1<<1) +#define TFA98XX_KEY2PROTECTED_SPKR_CAL_MTP_MTPEX_POS 1 +#define TFA98XX_KEY2PROTECTED_SPKR_CAL_MTP_MTPEX_LEN 1 +#define TFA98XX_KEY2PROTECTED_SPKR_CAL_MTP_MTPEX_MAX 1 +#define TFA98XX_KEY2PROTECTED_SPKR_CAL_MTP_MTPEX_MSK 0x2 + +#endif /* TFA9891_GENREGS_H */ diff --git a/techpack/audio/asoc/codecs/tfa9874/tfa9891_tfafieldnames.h b/techpack/audio/asoc/codecs/tfa9874/tfa9891_tfafieldnames.h new file mode 100644 index 000000000000..563eee830344 --- /dev/null +++ b/techpack/audio/asoc/codecs/tfa9874/tfa9891_tfafieldnames.h @@ -0,0 +1,515 @@ +/* + * tfa9891_tfafieldnames.h + * + * Created on: Jul 16, 2015 + * Author: wim + */ + +#ifndef TFA_INC_TFA9891_TFAFIELDNAMES_H_ +#define TFA_INC_TFA9891_TFAFIELDNAMES_H_ + +/** Filename: Tfa9891_TfaFieldnames.h + * This file was generated automatically on 07/16/15 at 15:00:02. + * Source file: TFA9891_I2C_list_V13.xls + */ + +#define TFA9891_I2CVERSION 13 + + +#define TFA9891_NAMETABLE static tfaBfName_t Tfa9891DatasheetNames[]= {\ + { 0x0, "VDDS"}, /* POR , */\ + { 0x10, "PLLS"}, /* PLL , */\ + { 0x20, "OTDS"}, /* OTP , */\ + { 0x30, "OVDS"}, /* OVP , */\ + { 0x40, "UVDS"}, /* UVP , */\ + { 0x50, "OCDS"}, /* OCP , */\ + { 0x60, "CLKS"}, /* Clocks , */\ + { 0x70, "CLIPS"}, /* CLIP , */\ + { 0x80, "MTPB"}, /* MTP , */\ + { 0x90, "DCCS"}, /* BOOST , */\ + { 0xa0, "SPKS"}, /* Speaker , */\ + { 0xb0, "ACS"}, /* cold start flag , */\ + { 0xc0, "SWS"}, /* flag engage , */\ + { 0xd0, "WDS"}, /* flag watchdog reset , */\ + { 0xe0, "AMPS"}, /* amplifier is enabled by manager , */\ + { 0xf0, "AREFS"}, /* references are enabled by manager , */\ + { 0x109, "BATS"}, /* Battery voltage readout; 0[V]..5.5[V] , */\ + { 0x208, "TEMPS"}, /* Temperature readout , */\ + { 0x307, "REV"}, /* Device Revision , */\ + { 0x402, "I2SF"}, /* I2SFormat data 1 input , */\ + { 0x431, "CHS12"}, /* ChannelSelection data1 input (In CoolFlux) , */\ + { 0x450, "CHS3"}, /* Channel Selection data 2 input (coolflux input, the DCDC converter gets the other signal), */\ + { 0x461, "CHSA"}, /* Input selection for amplifier , */\ + { 0x481, "I2SDOC"}, /* Selection for I2S data out , */\ + { 0x4a0, "DISP"}, /* idp protection , */\ + { 0x4b0, "I2SDOE"}, /* Enable data output , */\ + { 0x4c3, "I2SSR"}, /* sample rate setting , */\ + { 0x501, "BSSCR"}, /* ProtectionAttackTime , */\ + { 0x523, "BSST"}, /* ProtectionThreshold , */\ + { 0x561, "BSSRL"}, /* ProtectionMaximumReduction , */\ + { 0x582, "BSSRR"}, /* Protection Release Timer , */\ + { 0x5b1, "BSSHY"}, /* ProtectionHysterese , */\ + { 0x5e0, "BSSR"}, /* battery voltage for I2C read out only , */\ + { 0x5f0, "BSSBY"}, /* bypass clipper battery protection , */\ + { 0x600, "DPSA"}, /* Enable dynamic powerstage activation , */\ + { 0x613, "AMPSL"}, /* control slope , */\ + { 0x650, "CFSM"}, /* Soft mute in CoolFlux , */\ + { 0x670, "BSSS"}, /* batsensesteepness , */\ + { 0x687, "VOL"}, /* volume control (in CoolFlux) , */\ + { 0x702, "DCVO"}, /* Boost voltage , */\ + { 0x732, "DCMCC"}, /* Max boost coil current , */\ + { 0x7a0, "DCIE"}, /* Adaptive boost mode , */\ + { 0x7b0, "DCSR"}, /* Soft RampUp/Down mode for DCDC controller , */\ + { 0x800, "TROS"}, /* select external temperature also the ext_temp will be put on the temp read out , */\ + { 0x818, "EXTTS"}, /* external temperature setting to be given by host , */\ + { 0x900, "PWDN"}, /* ON/OFF , */\ + { 0x910, "I2CR"}, /* I2CReset , */\ + { 0x920, "CFE"}, /* EnableCoolFlux , */\ + { 0x930, "AMPE"}, /* EnableAmplifier , */\ + { 0x940, "DCA"}, /* EnableBoost , */\ + { 0x950, "SBSL"}, /* Coolflux configured , */\ + { 0x960, "AMPC"}, /* Selection on how AmplifierEnabling , */\ + { 0x970, "DCDIS"}, /* DCDC not connected , */\ + { 0x980, "PSDR"}, /* Iddq test amplifier , */\ + { 0x991, "DCCV"}, /* Coil Value , */\ + { 0x9b1, "CCFD"}, /* Selection CoolFluxClock , */\ + { 0x9d0, "ISEL"}, /* Interface Selection , */\ + { 0x9e0, "IPLL"}, /* selection input PLL for lock , */\ + { 0xa02, "DOLS"}, /* Output selection dataout left channel , */\ + { 0xa32, "DORS"}, /* Output selection dataout right channel , */\ + { 0xa62, "SPKL"}, /* Selection speaker induction , */\ + { 0xa91, "SPKR"}, /* Selection speaker impedance , */\ + { 0xab3, "DCFG"}, /* DCDC speaker current compensation gain , */\ + { 0xb07, "MTPK"}, /* MTP KEY2 register , */\ + { 0xf00, "VDDD"}, /* mask flag_por for interupt generation , */\ + { 0xf10, "OTDD"}, /* mask flag_otpok for interupt generation , */\ + { 0xf20, "OVDD"}, /* mask flag_ovpok for interupt generation , */\ + { 0xf30, "UVDD"}, /* mask flag_uvpok for interupt generation , */\ + { 0xf40, "OCDD"}, /* mask flag_ocp_alarm for interupt generation , */\ + { 0xf50, "CLKD"}, /* mask flag_clocks_stable for interupt generation , */\ + { 0xf60, "DCCD"}, /* mask flag_pwrokbst for interupt generation , */\ + { 0xf70, "SPKD"}, /* mask flag_cf_speakererror for interupt generation , */\ + { 0xf80, "WDD"}, /* mask flag_watchdog_reset for interupt generation , */\ + { 0xfe0, "INT"}, /* enabling interrupt , */\ + { 0xff0, "INTP"}, /* Setting polarity interupt , */\ + { 0x1000, "PDMSEL"}, /* Audio input interface mode , */\ + { 0x1010, "I2SMOUTEN"}, /* I2S Master enable (CLK and WS pads) , */\ + { 0x1021, "PDMORSEL"}, /* PDM Output right channel source selection , */\ + { 0x1041, "PDMOLSEL"}, /* PDM Output Left/Mono channel source selection , */\ + { 0x1061, "PADSEL"}, /* Output interface mode and ball selection , */\ + { 0x1100, "PDMOSDEN"}, /* Secure delay Cell , */\ + { 0x1110, "PDMOSDCF"}, /* Rising Falling Resync control Mux , */\ + { 0x1140, "SAAMEN"}, /* Speaker As a Mic feature ON/OFF , */\ + { 0x1150, "SAAMLPEN"}, /* speaker_as_mic low power mode (only in PDM_out mode), */\ + { 0x1160, "PDMOINTEN"}, /* PDM output interpolation ratio , */\ + { 0x1203, "PDMORG1"}, /* PDM Interpolator Right Channel DS4 G1 Gain Value , */\ + { 0x1243, "PDMORG2"}, /* PDM Interpolator Right Channel DS4 G2 Gain Value , */\ + { 0x1303, "PDMOLG1"}, /* PDM Interpolator Left Channel DS4 G1 Gain Value , */\ + { 0x1343, "PDMOLG2"}, /* PDM Interpolator Left Channel DS4 G2 Gain Value , */\ + { 0x2202, "SAAMGAIN"}, /* pga gain , */\ + { 0x2250, "SAAMPGACTRL"}, /* 0 = active input common mode voltage source at the attenuator/PGA level, */\ + { 0x2500, "PLLCCOSEL"}, /* pll cco frequency , */\ + { 0x4600, "CSBYPGC"}, /* bypass_gc, bypasses the CS gain correction , */\ + { 0x4900, "CLIP"}, /* Bypass clip control (function depending on digimux clip_x), */\ + { 0x4910, "CLIP2"}, /* Bypass clip control (function depending on digimux clip_x), */\ + { 0x62b0, "CIMTP"}, /* start copying all the data from i2cregs_mtp to mtp [Key 2 protected], */\ + { 0x7000, "RST"}, /* Reset CoolFlux DSP , */\ + { 0x7011, "DMEM"}, /* Target memory for access , */\ + { 0x7030, "AIF"}, /* Autoincrement-flag for memory-address , */\ + { 0x7040, "CFINT"}, /* Interrupt CoolFlux DSP , */\ + { 0x7087, "REQ"}, /* request for access (8 channels) , */\ + { 0x710f, "MADD"}, /* memory-address to be accessed , */\ + { 0x720f, "MEMA"}, /* activate memory access (24- or 32-bits data is written/read to/from memory, */\ + { 0x7307, "ERR"}, /* cf error Flags , */\ + { 0x7387, "ACK"}, /* acknowledge of requests (8 channels")" , */\ + { 0x8000, "MTPOTC"}, /* Calibration schedule (key2 protected) , */\ + { 0x8010, "MTPEX"}, /* (key2 protected) calibration of Ron has been executed, */\ + { 0x8045, "SWPROFIL" },\ + { 0x80a5, "SWVSTEP" },\ + { 0xffff,"Unknown bitfield enum" } /* not found */\ +}; + +#define TFA9891_BITNAMETABLE static tfaBfName_t Tfa9891BitNames[]= {\ + { 0x0, "POR"}, /* POR , */\ + { 0x10, "PLL_LOCK"}, /* PLL , */\ + { 0x20, "flag_otpok"}, /* OTP , */\ + { 0x30, "flag_ovpok"}, /* OVP , */\ + { 0x40, "flag_uvpok"}, /* UVP , */\ + { 0x50, "flag_OCP_alarm"}, /* OCP , */\ + { 0x60, "flag_clocks_stable"}, /* Clocks , */\ + { 0x70, "CLIP"}, /* CLIP , */\ + { 0x80, "mtp_busy"}, /* MTP , */\ + { 0x90, "flag_pwrokbst"}, /* BOOST , */\ + { 0xa0, "flag_cf_speakererror"}, /* Speaker , */\ + { 0xb0, "flag_cold_started"}, /* cold start flag , */\ + { 0xc0, "flag_engage"}, /* flag engage , */\ + { 0xd0, "flag_watchdog_reset"}, /* flag watchdog reset , */\ + { 0xe0, "flag_enbl_amp"}, /* amplifier is enabled by manager , */\ + { 0xf0, "flag_enbl_ref"}, /* references are enabled by manager , */\ + { 0x109, "bat_adc"}, /* Battery voltage readout; 0[V]..5.5[V] , */\ + { 0x208, "temp_adc"}, /* Temperature readout , */\ + { 0x307, "rev_reg"}, /* Device Revision , */\ + { 0x402, "i2s_seti"}, /* I2SFormat data 1 input , */\ + { 0x431, "chan_sel1"}, /* ChannelSelection data1 input (In CoolFlux) , */\ + { 0x450, "lr_sw_i2si2"}, /* Channel Selection data 2 input (coolflux input, the DCDC converter gets the other signal), */\ + { 0x461, "input_sel"}, /* Input selection for amplifier , */\ + { 0x481, "datao_sel"}, /* Selection for I2S data out , */\ + { 0x4a0, "disable_idp"}, /* idp protection , */\ + { 0x4b0, "enbl_datao"}, /* Enable data output , */\ + { 0x4c3, "i2s_fs"}, /* sample rate setting , */\ + { 0x501, "vbat_prot_attacktime"}, /* ProtectionAttackTime , */\ + { 0x523, "vbat_prot_thlevel"}, /* ProtectionThreshold , */\ + { 0x561, "vbat_prot_max_reduct"}, /* ProtectionMaximumReduction , */\ + { 0x582, "vbat_prot_release_t"}, /* Protection Release Timer , */\ + { 0x5b1, "vbat_prot_hysterese"}, /* ProtectionHysterese , */\ + { 0x5d0, "reset_min_vbat"}, /* reset clipper , */\ + { 0x5e0, "sel_vbat"}, /* battery voltage for I2C read out only , */\ + { 0x5f0, "bypass_clipper"}, /* bypass clipper battery protection , */\ + { 0x600, "dpsa"}, /* Enable dynamic powerstage activation , */\ + { 0x613, "ctrl_slope"}, /* control slope , */\ + { 0x650, "cf_mute"}, /* Soft mute in CoolFlux , */\ + { 0x660, "sel_other_vamp"}, /* Input selection for the second channel of the DCDC inteligent mode detector, */\ + { 0x670, "ctrl_batsensesteepness"}, /* batsensesteepness , */\ + { 0x687, "vol"}, /* volume control (in CoolFlux) , */\ + { 0x702, "ctrl_bstvolt"}, /* Boost voltage , */\ + { 0x732, "ctrl_bstcur"}, /* Max boost coil current , */\ + { 0x761, "ctrl_slopebst_1_0"}, /* Setting for the slope of the boost converter power stage, */\ + { 0x781, "ctrl_slopebst_3_2"}, /* Setting for the part of the power transistor voltage to be used in peak current mode control, */\ + { 0x7a0, "boost_intel"}, /* Adaptive boost mode , */\ + { 0x7b0, "boost_speed"}, /* Soft RampUp/Down mode for DCDC controller , */\ + { 0x7c1, "ctrl_delay_comp_dcdc"}, /* delay compensation in current patg compared to delay in the audio path (relative) , */\ + { 0x7e0, "boost_input"}, /* Selection intelligent boost detector input , */\ + { 0x7f0, "ctrl_supplysense"}, /* ADC10 input selection , */\ + { 0x800, "ext_temp_sel"}, /* select external temperature also the ext_temp will be put on the temp read out , */\ + { 0x818, "ext_temp"}, /* external temperature setting to be given by host , */\ + { 0x8a0, "ctrl_spk_coilpvp_bst"}, /* Peak voltage protection boost converter , */\ + { 0x8b2, "ctrl_dcdc_synchronisation"}, /* DCDC synchronisation off + 7 positions , */\ + { 0x8e0, "ctrl_cs_samplevalid"}, /* sample valid moment for CS in single sample moment mode, */\ + { 0x900, "PowerDown"}, /* ON/OFF , */\ + { 0x910, "reset"}, /* I2CReset , */\ + { 0x920, "enbl_coolflux"}, /* EnableCoolFlux , */\ + { 0x930, "enbl_amplifier"}, /* EnableAmplifier , */\ + { 0x940, "enbl_boost"}, /* EnableBoost , */\ + { 0x950, "cf_configured"}, /* Coolflux configured , */\ + { 0x960, "sel_enbl_amplifier"}, /* Selection on how AmplifierEnabling , */\ + { 0x970, "dcdcoff_mode"}, /* DCDC not connected , */\ + { 0x980, "cttr_iddqtest"}, /* Iddq test amplifier , */\ + { 0x991, "ctrl_coil_value"}, /* Coil Value , */\ + { 0x9b1, "ctrl_sel_cf_clock"}, /* Selection CoolFluxClock , */\ + { 0x9d0, "intf_sel"}, /* Interface Selection , */\ + { 0x9e0, "sel_ws_bck"}, /* selection input PLL for lock , */\ + { 0xa02, "sel_i2so_l"}, /* Output selection dataout left channel , */\ + { 0xa32, "sel_i2so_r"}, /* Output selection dataout right channel , */\ + { 0xa62, "ctrl_spkr_coil"}, /* Selection speaker induction , */\ + { 0xa91, "ctrl_spr_res"}, /* Selection speaker impedance , */\ + { 0xab3, "ctrl_dcdc_spkr_i_comp_gain"}, /* DCDC speaker current compensation gain , */\ + { 0xaf0, "ctrl_dcdc_spkr_i_comp_sign"}, /* DCDC speaker current compensation sign , */\ + { 0xb07, "MTP_key2"}, /* MTP KEY2 register , */\ + { 0xc0c, "clk_sync_delay"}, /* Delay count for clock synchronisation , */\ + { 0xcf0, "enbl_clk_sync"}, /* Enable CGU clock synchronisation , */\ + { 0xd0c, "adc_sync_delay"}, /* Delay count for ADC synchronisation , */\ + { 0xdf0, "enable_adc_sync"}, /* Enable ADC synchronisation , */\ + { 0xe00, "bypass_dcdc_curr_prot"}, /* to switch off dcdc reduction with bat prot , */\ + { 0xe24, "ctrl_digtoana6_2"}, /* for extra connections digital to analog , */\ + { 0xe70, "switch_on_icomp"}, /* icomp dem switch , */\ + { 0xe87, "reserve_reg_1_7_0"}, /* reserved , */\ + { 0xf00, "flag_por_mask"}, /* mask flag_por for interupt generation , */\ + { 0xf10, "flag_otpok_mask"}, /* mask flag_otpok for interupt generation , */\ + { 0xf20, "flag_ovpok_mask"}, /* mask flag_ovpok for interupt generation , */\ + { 0xf30, "flag_uvpok_mask"}, /* mask flag_uvpok for interupt generation , */\ + { 0xf40, "flag_ocp_alarm_mask"}, /* mask flag_ocp_alarm for interupt generation , */\ + { 0xf50, "flag_clocks_stable_mask"}, /* mask flag_clocks_stable for interupt generation , */\ + { 0xf60, "flag_pwrokbst_mask"}, /* mask flag_pwrokbst for interupt generation , */\ + { 0xf70, "flag_cf_speakererror_mask"}, /* mask flag_cf_speakererror for interupt generation , */\ + { 0xf80, "flag_watchdog_reset_mask"}, /* mask flag_watchdog_reset for interupt generation , */\ + { 0xf90, "flag_lost_clk_mask"}, /* mask flag_lost_clk for interupt generation , */\ + { 0xfe0, "enable_interrupt"}, /* enabling interrupt , */\ + { 0xff0, "invert_int_polarity"}, /* Setting polarity interupt , */\ + { 0x1000, "pdm_i2s_input"}, /* Audio input interface mode , */\ + { 0x1010, "I2S_master_ena"}, /* I2S Master enable (CLK and WS pads) , */\ + { 0x1021, "pdm_out_sel_r"}, /* PDM Output right channel source selection , */\ + { 0x1041, "pdm_out_sel_l"}, /* PDM Output Left/Mono channel source selection , */\ + { 0x1061, "micdat_out_sel"}, /* Output interface mode and ball selection , */\ + { 0x1100, "secure_dly"}, /* Secure delay Cell , */\ + { 0x1110, "d_out_valid_rf_mux"}, /* Rising Falling Resync control Mux , */\ + { 0x1140, "Speak_As_Mic_en"}, /* Speaker As a Mic feature ON/OFF , */\ + { 0x1150, "speak_as_mic_lp_mode"}, /* speaker_as_mic low power mode (only in PDM_out mode), */\ + { 0x1160, "pdm_out_rate"}, /* PDM output interpolation ratio , */\ + { 0x1203, "ds4_g1_r"}, /* PDM Interpolator Right Channel DS4 G1 Gain Value , */\ + { 0x1243, "ds4_g2_r"}, /* PDM Interpolator Right Channel DS4 G2 Gain Value , */\ + { 0x1303, "ds4_g1_l"}, /* PDM Interpolator Left Channel DS4 G1 Gain Value , */\ + { 0x1343, "ds4_g2_l"}, /* PDM Interpolator Left Channel DS4 G2 Gain Value , */\ + { 0x1400, "clk_secure_dly"}, /* Secure delay Cell on clock path , */\ + { 0x1410, "data_secure_dly"}, /* Secure delay Cell enable on PDM data path , */\ + { 0x2202, "Ctrl_saam_pga_gain"}, /* pga gain , */\ + { 0x2250, "ctrl_saam_pga_src"}, /* 0 = active input common mode voltage source at the attenuator/PGA level, */\ + { 0x2300, "flag_saam_spare"}, /* spare flag , */\ + { 0x2400, "ctrl_saam_pga_tm"}, /* enables PGA test mode , */\ + { 0x2500, "pll_fcco"}, /* pll cco frequency , */\ + { 0x3000, "flag_hi_small"}, /* positive small window dcdc converter , */\ + { 0x3010, "flag_hi_large"}, /* positive large window dcdc converter , */\ + { 0x3020, "flag_lo_small"}, /* negative small window dcdc converter , */\ + { 0x3030, "flag_lo_large"}, /* negative large window dcdc converter , */\ + { 0x3040, "flag_voutcomp"}, /* flag_voutcomp, indication Vset is larger than Vbat, */\ + { 0x3050, "flag_voutcomp93"}, /* flag_voutcomp93, indication Vset is larger than 1.07* Vbat , */\ + { 0x3060, "flag_voutcomp86"}, /* flag_voutcomp86, indication Vset is larger than 1.14* Vbat , */\ + { 0x3070, "flag_hiz"}, /* flag_hiz, indication Vbst is larger than Vbat , */\ + { 0x3080, "flag_hi_peak"}, /* flag_hi_peak, indication hi_peak , */\ + { 0x3090, "flag_ocpokbst"}, /* flag_ocpokbst, indication no over current in boost converter pmos switch, */\ + { 0x30a0, "flag_peakcur"}, /* flag_peakcur, indication current is max in dcdc converter, */\ + { 0x30b0, "flag_ocpokap"}, /* flag_ocpokap, indication no over current in amplifier "a" pmos output stage, */\ + { 0x30c0, "flag_ocpokan"}, /* flag_ocpokan, indication no over current in amplifier "a" nmos output stage, */\ + { 0x30d0, "flag_ocpokbp"}, /* flag_ocpokbp, indication no over current in amplifier "b" pmos output stage, */\ + { 0x30e0, "flag_ocpokbn"}, /* flag_ocpokbn, indication no over current in amplifier"b" nmos output stage, */\ + { 0x30f0, "lost_clk"}, /* lost_clk, lost clock indication CGU , */\ + { 0x310f, "mtp_man_data_out"}, /* single word read from MTP (manual copy) , */\ + { 0x3200, "key01_locked"}, /* key01_locked, indication key 1 is locked , */\ + { 0x3210, "key02_locked"}, /* key02_locked, indication key 2 is locked , */\ + { 0x3225, "mtp_ecc_tcout"}, /* mtp_ecc_tcout , */\ + { 0x3280, "mtpctrl_valid_test_rd"}, /* mtp test readout for read , */\ + { 0x3290, "mtpctrl_valid_test_wr"}, /* mtp test readout for write , */\ + { 0x32a0, "flag_in_alarm_state"}, /* alarm state , */\ + { 0x32b0, "mtp_ecc_err2"}, /* two or more bit errors detected in MTP, can not reconstruct value, */\ + { 0x32c0, "mtp_ecc_err1"}, /* one bit error detected in MTP, reconstructed value, */\ + { 0x32d0, "mtp_mtp_hvf"}, /* high voltage ready flag for MTP , */\ + { 0x32f0, "mtp_zero_check_fail"}, /* zero check failed (tbd) for MTP , */\ + { 0x3300, "flag_adc10_ready"}, /* flag_adc10_ready, indication adc10 is ready , */\ + { 0x3310, "flag_clipa_high"}, /* flag_clipa_high, indication pmos amplifier "a" is clipping, */\ + { 0x3320, "flag_clipa_low"}, /* flag_clipa_low, indication nmos amplifier "a" is clipping, */\ + { 0x3330, "flag_clipb_high"}, /* flag_clipb_high, indication pmos amplifier "b" is clipping, */\ + { 0x3340, "flag_clipb_low"}, /* flag_clipb_low, indication nmos amplifier "b" is clipping, */\ + { 0x3359, "data_adc10_tempbat"}, /* adc 10 data output for testing , */\ + { 0x33f0, "flag_vddd_comp_nok"}, /* power switch flag 2 for testing , */\ + { 0x400f, "hid_code"}, /* hidden code , */\ + { 0x4100, "bypass_hp"}, /* Bypass_High Pass Filter , */\ + { 0x4110, "hard_mute"}, /* Hard Mute , */\ + { 0x4120, "soft_mute"}, /* Soft Mute , */\ + { 0x4134, "PWM_Delay"}, /* PWM DelayBits to set the delay , */\ + { 0x4180, "PWM_Shape"}, /* PWM Shape , */\ + { 0x4190, "PWM_BitLength"}, /* PWM Bitlength in noise shaper , */\ + { 0x4207, "ctrl_drive"}, /* drive bits to select amount of power stages amplifier, */\ + { 0x4281, "dpsalevel"}, /* DPSA Threshold level , */\ + { 0x42a1, "dpsa_release"}, /* DPSA Release time , */\ + { 0x42c0, "ctrl_coincidence"}, /* Prevent simultaneously switching of output stage , */\ + { 0x42d0, "ctrl_kickback"}, /* Prevent double pulses of output stage , */\ + { 0x42e0, "ctrl_test_sdeltaoffset"}, /* ctrl_test_sdeltaoffset , */\ + { 0x42f0, "ctrl_test_sdeltaclk"}, /* ctrl_test_sdeltaclk , */\ + { 0x4309, "ctrl_drivebst"}, /* Drive bits to select the powertransistor sections boost converter, */\ + { 0x43a0, "ctrl_ocptestbst"}, /* Boost OCP. , */\ + { 0x43c0, "enbl_hi_peak"}, /* enable for high peak comparator , */\ + { 0x43d0, "test_abistfft_enbl"}, /* FFT coolflux , */\ + { 0x43e0, "ctrl_sensetest_amp"}, /* sensetest amplifier , */\ + { 0x43f0, "test_bcontrol"}, /* test _bcontrol , */\ + { 0x4400, "ctrl_reversebst"}, /* OverCurrent Protection selection of power stage boost converter, */\ + { 0x4410, "ctrl_sensetest"}, /* Test option for the sense NMOS in booster for current mode control., */\ + { 0x4420, "enbl_engagebst"}, /* Enable power stage dcdc controller , */\ + { 0x4430, "enbl_hi_small"}, /* Enable bit of hi (small) comparator , */\ + { 0x4440, "enbl_hi_large"}, /* Enable bit of hi (large) comparator , */\ + { 0x4450, "enbl_lo_small"}, /* Enable bit of lo (small) comparator , */\ + { 0x4460, "enbl_lo_large"}, /* Enable bit of lo (large) comparator , */\ + { 0x4470, "enbl_slopecur"}, /* Enable bit of max-current dac , */\ + { 0x4480, "enbl_voutcomp"}, /* Enable vout comparators , */\ + { 0x4490, "enbl_voutcomp93"}, /* Enable vout-93 comparators , */\ + { 0x44a0, "enbl_voutcomp86"}, /* Enable vout-86 comparators , */\ + { 0x44b0, "enbl_hizcom"}, /* Enable hiz comparator , */\ + { 0x44c0, "enbl_pcdac"}, /* Enable peak current dac , */\ + { 0x44d0, "enbl_pccomp"}, /* Enable peak current comparator , */\ + { 0x44e0, "enbl_windac"}, /* Enable window dac , */\ + { 0x44f0, "enbl_powerbst"}, /* Enable line of the powerstage , */\ + { 0x4507, "ocp_thr"}, /* ocp_thr threshold level for OCP , */\ + { 0x4580, "bypass_glitchfilter"}, /* Bypass glitchfilter , */\ + { 0x4590, "bypass_ovp"}, /* Bypass OVP , */\ + { 0x45a0, "bypass_uvp"}, /* Bypass UVP , */\ + { 0x45b0, "bypass_otp"}, /* Bypass OTP , */\ + { 0x45c0, "bypass_ocp"}, /* Bypass OCP , */\ + { 0x45d0, "bypass_ocpcounter"}, /* BypassOCPCounter , */\ + { 0x45e0, "bypass_lost_clk"}, /* Bypasslost_clk detector , */\ + { 0x45f0, "vpalarm"}, /* vpalarm (uvp ovp handling) , */\ + { 0x4600, "bypass_gc"}, /* bypass_gc, bypasses the CS gain correction , */\ + { 0x4610, "cs_gain_control"}, /* gain control by means of MTP or i2c , */\ + { 0x4627, "cs_gain"}, /* + / - 128 steps in steps of 1/4 % 2's compliment , */\ + { 0x46a0, "bypass_lp"}, /* bypass Low-Pass filter in temperature sensor , */\ + { 0x46b0, "bypass_pwmcounter"}, /* bypass_pwmcounter , */\ + { 0x46c0, "ctrl_cs_negfixed"}, /* does not switch to neg , */\ + { 0x46d2, "ctrl_cs_neghyst"}, /* switches to neg depending on level , */\ + { 0x4700, "switch_fb"}, /* switch_fb , */\ + { 0x4713, "se_hyst"}, /* se_hyst , */\ + { 0x4754, "se_level"}, /* se_level , */\ + { 0x47a5, "ktemp"}, /* temperature compensation trimming , */\ + { 0x4800, "ctrl_negin"}, /* negin , */\ + { 0x4810, "ctrl_cs_sein"}, /* cs_sein , */\ + { 0x4820, "ctrl_coincidencecs"}, /* Coincidence current sense , */\ + { 0x4830, "ctrl_iddqtestbst"}, /* for iddq testing in powerstage of boost convertor , */\ + { 0x4840, "ctrl_coincidencebst"}, /* Switch protection on to prevent simultaniously switching power stages bst and amp, */\ + { 0x4851, "clock_sh_sel"}, /* Clock SH selection , */\ + { 0x4876, "delay_se_neg"}, /* delay of se and neg , */\ + { 0x48e1, "ctrl_cs_ttrack"}, /* sample & hold track time , */\ + { 0x4900, "ctrl_bypassclip"}, /* Bypass clip control (function depending on digimux clip_x), */\ + { 0x4910, "ctrl_bypassclip2"}, /* Bypass clip control (function depending on digimux clip_x), */\ + { 0x4920, "ctrl_clkgateCFoff"}, /* to disable clock gating in the coolflux , */\ + { 0x4930, "ctrl_testabst"}, /* testabst , */\ + { 0x4940, "ctrl_clipfast"}, /* clock switch for battery protection clipper, it switches back to old frequency, */\ + { 0x4950, "ctrl_cs_8ohm"}, /* 8 ohm mode for current sense (gain mode) , */\ + { 0x4960, "reserved"}, /* reserved , */\ + { 0x4974, "delay_clock_sh"}, /* delay_sh, tunes S7H delay , */\ + { 0x49c0, "inv_clksh"}, /* Invert the sample/hold clock for current sense ADC, */\ + { 0x49d0, "inv_neg"}, /* Invert neg signal , */\ + { 0x49e0, "inv_se"}, /* Invert se signal , */\ + { 0x49f0, "setse"}, /* switches between Single Ende and differentail mode, */\ + { 0x4a12, "ctrl_adc10_sel"}, /* select the input to convert the 10b ADC , */\ + { 0x4a60, "ctrl_adc10_reset"}, /* Global asynchronous reset (active HIGH) 10 bit ADC, */\ + { 0x4a81, "ctrl_adc10_test"}, /* Test mode selection signal 10 bit ADC , */\ + { 0x4aa0, "ctrl_bypass_lp_vbat"}, /* lp filter in batt sensor , */\ + { 0x4ae0, "ctrl_dc_offset"}, /* switch offset control on/off, is decimator offset control, */\ + { 0x4af0, "ctrl_tsense_hibias"}, /* bit to set the biasing in temp sensor to high , */\ + { 0x4b00, "ctrl_adc13_iset"}, /* Micadc Setting of current consumption. Debug use only, */\ + { 0x4b14, "ctrl_adc13_gain"}, /* Micadc gain setting (2-compl) , */\ + { 0x4b61, "ctrl_adc13_slowdel"}, /* Micadc Delay setting for internal clock. Debug use only, */\ + { 0x4b83, "ctrl_adc13_offset"}, /* Micadc ADC offset setting , */\ + { 0x4bc0, "ctrl_adc13_bsoinv"}, /* Micadc bit stream output invert mode for test , */\ + { 0x4bd0, "ctrl_adc13_resonator_enable"}, /* Micadc Give extra SNR with less stability. Debug use only, */\ + { 0x4be0, "ctrl_testmicadc"}, /* Mux at input of MICADC for test purpose , */\ + { 0x4c0f, "ctrl_offset"}, /* offset control for ABIST testing , */\ + { 0x4d05, "ctrl_windac"}, /* for testing direct control windac , */\ + { 0x4d65, "ctrl_peakcur"}, /* Control peakcur , */\ + { 0x4dc3, "pwm_dcc_cnt"}, /* control pwm duty cycle when enbl_pwm_dcc is 1 , */\ + { 0x4e04, "ctrl_slopecur"}, /* for testing direct control slopecur , */\ + { 0x4e53, "ctrl_dem"}, /* dyn element matching control, rest of codes are optional, */\ + { 0x4e93, "ctrl_demmismatch"}, /* dyn element matching add offset , */\ + { 0x4ed0, "enbl_pwm_dcc"}, /* to enable direct control of pwm duty cycle , */\ + { 0x5007, "gain"}, /* gain setting of the gain multiplier gain need to increase with factor 1.41 (3dB), */\ + { 0x5081, "ctrl_sourceb"}, /* Set OUTB to , */\ + { 0x50a1, "ctrl_sourcea"}, /* Set OUTA to , */\ + { 0x50c1, "ctrl_sourcebst"}, /* Sets the source of the pwmbst output to boost converter input for testing, */\ + { 0x50e1, "ctrl_test_mono"}, /* ABIST mode to add both amplifier halfs as stereo or one amplifier half as mono, */\ + { 0x5104, "pulselengthbst"}, /* pulselength setting test input for boost converter , */\ + { 0x5150, "ctrl_bypasslatchbst"}, /* bypass_latch in boost converter , */\ + { 0x5160, "invertbst"}, /* invert pwmbst test signal , */\ + { 0x5174, "pulselength"}, /* pulselength setting test input for amplifier , */\ + { 0x51c0, "ctrl_bypasslatch"}, /* bypass_latch in boost convert , */\ + { 0x51d0, "invertb"}, /* invert pwmb test signal , */\ + { 0x51e0, "inverta"}, /* invert pwma test signal , */\ + { 0x51f0, "ctrl_bypass_ctrlloop"}, /* bypass_ctrlloop bypasses the control loop of the amplifier, */\ + { 0x5200, "ctrl_test_discrete"}, /* tbd for rdson testing , */\ + { 0x5210, "ctrl_test_rdsona"}, /* tbd for rdson testing , */\ + { 0x5220, "ctrl_test_rdsonb"}, /* tbd for rdson testing , */\ + { 0x5230, "ctrl_test_rdsonbst"}, /* tbd for rdson testing , */\ + { 0x5240, "ctrl_test_cvia"}, /* tbd for rdson testing , */\ + { 0x5250, "ctrl_test_cvib"}, /* tbd for rdson testing , */\ + { 0x5260, "ctrl_test_cvibst"}, /* tbd for rdson testing , */\ + { 0x5290, "test_bypass_pwmdiscretea"}, /* for testing ( ABIST) , */\ + { 0x52a0, "test_bypass_pwmdiscreteb"}, /* for testing ( ABIST) , */\ + { 0x52b0, "ctrl_clipc_forcehigh"}, /* test signal for clipcontrol , */\ + { 0x52c0, "ctrl_clipc_forcelow"}, /* test signal for clipcontrol , */\ + { 0x52d0, "ctrl_test_sdelta"}, /* for testing ( ABIST) , */\ + { 0x52e0, "ctrl_test_swhvp"}, /* for testing ( ABIST) , */\ + { 0x52f0, "test_gain_reduction"}, /* test gain reduction , */\ + { 0x5303, "ctrl_digimux_out_test1"}, /* Digimux TEST1 out , */\ + { 0x5343, "ctrl_digimux_out_test2"}, /* Digimux TEST2 out. output flag_clipa_low depending on cntr_bypassclip setting, */\ + { 0x5383, "ctrl_digimux_out_data1"}, /* Digimux DATA1 out (output flag_clipb_high depending on cntr_bypassclip setting), */\ + { 0x53c3, "ctrl_digimux_out_data3"}, /* Digimux DATA3 out (output flag_clipx_x depending on cntr_bypassclip setting), */\ + { 0x5400, "hs_mode"}, /* hs_mode, high speed mode I2C bus , */\ + { 0x5412, "test_parametric_io"}, /* test_parametric_io for testing pads , */\ + { 0x5440, "enbl_ringo"}, /* enbl_ringo, for test purpose to check with ringo , */\ + { 0x5480, "ctrl_cliplevel"}, /* Clip level , */\ + { 0x5491, "ctrl_anamux_sel"}, /* anamux selection , */\ + { 0x54b0, "test_vdddsw_dio"}, /* to overrule the power switches for memory , */\ + { 0x54c0, "ctrl_bypass_diosw_ovp"}, /* To disable the overvoltage protection of vddd_dio_sw, */\ + { 0x54d0, "test_vddd_sw"}, /* test vdd sw , */\ + { 0x54e0, "test_vddd_sw_comp"}, /* test vdd sw comp , */\ + { 0x550e, "enbl_amp"}, /* enbl_amp for testing to enable all analoge blocks in amplifier, */\ + { 0x55f0, "fr_fsp"}, /* extr free running clock mode for testing , */\ + { 0x5600, "use_direct_ctrls"}, /* use_direct_ctrls, to overrule several functions direct for testing, */\ + { 0x5610, "rst_datapath"}, /* rst_datapath, datapath reset , */\ + { 0x5620, "rst_cgu"}, /* rst_cgu, cgu reset , */\ + { 0x5637, "enbl_ref"}, /* for testing to enable all analoge blocks in references, */\ + { 0x56b0, "enbl_engage"}, /* Enable output stage amplifier , */\ + { 0x56c0, "use_direct_clk_ctrl"}, /* use_direct_clk_ctrl, to overrule several functions direct for testing, */\ + { 0x56d0, "use_direct_pll_ctrl"}, /* use_direct_pll_ctrl, to overrule several functions direct for test, */\ + { 0x56e0, "use_direct_ctrls_2"}, /* use_direct_sourseamp_ctrls, to overrule several functions direct for testing, */\ + { 0x5707, "ctrl_anamux_out_test1"}, /* Anamux control , */\ + { 0x5782, "ctrl_zero"}, /* Bandwith control feedbackloop , */\ + { 0x57b0, "enbl_ldo_stress"}, /* LDO stress function frinch capacitors , */\ + { 0x57c0, "ctrl_ocptest"}, /* ctrl_ocptest, deactivates the over current protection in the power stages of the amplifier. The ocp flag signals stay active., */\ + { 0x57e0, "ctrl_otptest"}, /* otptest, test mode otp amplifier , */\ + { 0x57f0, "ctrl_reverse"}, /* CTRL revers , */\ + { 0x5802, "pll_mdec_msb"}, /* most significant bits pll_mdec , */\ + { 0x5833, "pll_selr"}, /* pll_selr , */\ + { 0x5874, "pll_selp"}, /* pll_selp , */\ + { 0x58c3, "pll_seli"}, /* pll_seli , */\ + { 0x5900, "pll_psel"}, /* pll_psel , */\ + { 0x5910, "use_direct_pll_psel"}, /* use_direct_pll_psel , */\ + { 0x5923, "nbck"}, /* NBCK , */\ + { 0x5960, "auto_nbck"}, /* AUTO_NBCK , */\ + { 0x5970, "pll_frm"}, /* pll_frm , */\ + { 0x5980, "pll_directi"}, /* pll_directi , */\ + { 0x5990, "pll_directo"}, /* pll_directo , */\ + { 0x59a0, "enbl_PLL"}, /* enbl_PLL , */\ + { 0x59b0, "sel_clkout"}, /* SEL_CLKOUT , */\ + { 0x59e0, "fr_lost_clk"}, /* fr_lost_clk , */\ + { 0x59f0, "pll_bypass"}, /* pll_bypass , */\ + { 0x5a0f, "tsig_freq"}, /* tsig_freq, internal sinus test generator, frequency control, */\ + { 0x5b02, "tsig_freq_msb"}, /* select internal sinus test generator, frequency control msb bits, */\ + { 0x5b30, "inject_tsig"}, /* inject_tsig, control bit to switch to internal sinus test generator, */\ + { 0x5b44, "ctrl_adc10_prog_sample"}, /* control ADC10 , */\ + { 0x5c01, "pll_ndec_msb"}, /* most significant bits of pll_ndec , */\ + { 0x5c2d, "pll_mdec"}, /* bits 13..0 of pll_mdec , */\ + { 0x5d06, "pll_pdec"}, /* pll_pdec , */\ + { 0x5d87, "pll_ndec"}, /* bits 7..0 of pll_ndec , */\ + { 0x5e00, "pdm_ch_sel_reg"}, /* PDM channel selection , */\ + { 0x5e10, "pdm_iis_rst_reg"}, /* PDM Interface reset , */\ + { 0x5e20, "clk_src_sel_reg"}, /* WS Source Selection , */\ + { 0x5e70, "pdm_resync_bypass"}, /* PDM resynchronization bypass , */\ + { 0x6007, "MTP_key1"}, /* MTP Key1 , */\ + { 0x6185, "mtp_ecc_tcin"}, /* Mtp_ecc_tcin , */\ + { 0x6203, "mtp_man_address_in"}, /* address from i2cregs for writing one word single mtp, */\ + { 0x6260, "mtp_ecc_eeb"}, /* enable code bit generation (active low!) , */\ + { 0x6270, "mtp_ecc_ecb"}, /* enable correction signal (active low!) , */\ + { 0x6280, "man_copy_mtp_to_iic"}, /* start copying single word from mtp to i2cregs_mtp , */\ + { 0x6290, "man_copy_iic_to_mtp"}, /* start copying single word from i2cregs_mtp to mtp [Key 1 protected], */\ + { 0x62a0, "auto_copy_mtp_to_iic"}, /* start copying all the data from mtp to i2cregs_mtp, */\ + { 0x62b0, "auto_copy_iic_to_mtp"}, /* start copying all the data from i2cregs_mtp to mtp [Key 2 protected], */\ + { 0x62d2, "mtp_speed_mode"}, /* Speed mode , */\ + { 0x6340, "mtp_dircet_enable"}, /* mtp_direct_enable (key1 protected) , */\ + { 0x6350, "mtp_direct_wr"}, /* mtp_direct_wr (key1 protected) direct value for mtp pin wr. To be enabled via iic2mtp_mtp_direct_enable, */\ + { 0x6360, "mtp_direct_rd"}, /* mtp_direct_rd (key1 protected) direct value for mtp pin rd. To be enabled via iic2mtp_mtp_direct_enable, */\ + { 0x6370, "mtp_direct_rst"}, /* mtp_direct_rst (key1 protected) direct value for mtp pin rst. To be enabled via iic2mtp_mtp_direct_enable, */\ + { 0x6380, "mtp_direct_ers"}, /* mtp_direct_ers (key1 protected) direct value for mtp pin ers. To be enabled via iic2mtp_mtp_direct_enable, */\ + { 0x6390, "mtp_direct_prg"}, /* mtp_direct_prg (key1 protected) direct value for mtp pin prg. To be enabled via iic2mtp_mtp_direct_enable, */\ + { 0x63a0, "mtp_direct_epp"}, /* mtp_direct_epp (key1 protected) direct value for mtp pin epp. To be enabled via iic2mtp_mtp_direct_enable, */\ + { 0x63b4, "mtp_direct_test"}, /* mtp_direct_test (key1 protected) , */\ + { 0x640f, "mtp_man_data_in"}, /* single wordt be written to MTP (manual copy) , */\ + { 0x7000, "cf_rst_dsp"}, /* Reset CoolFlux DSP , */\ + { 0x7011, "cf_dmem"}, /* Target memory for access , */\ + { 0x7030, "cf_aif"}, /* Autoincrement-flag for memory-address , */\ + { 0x7040, "cf_int"}, /* Interrupt CoolFlux DSP , */\ + { 0x7087, "cf_req"}, /* request for access (8 channels) , */\ + { 0x710f, "cf_madd"}, /* memory-address to be accessed , */\ + { 0x720f, "cf_mema"}, /* activate memory access (24- or 32-bits data is written/read to/from memory, */\ + { 0x7307, "cf_err"}, /* cf error Flags , */\ + { 0x7387, "cf_ack"}, /* acknowledge of requests (8 channels")" , */\ + { 0x8000, "calibration_onetime"}, /* Calibration schedule (key2 protected) , */\ + { 0x8010, "calibr_ron_done"}, /* (key2 protected) calibration of Ron has been executed, */\ + { 0x8105, "calibr_vout_offset"}, /* calibr_vout_offset (DCDCoffset) 2's compliment (key1 protected), */\ + { 0x8163, "calibr_delta_gain"}, /* delta gain for vamp (alpha) 2's compliment (key1 protected), */\ + { 0x81a5, "calibr_offs_amp"}, /* offset for vamp (Ampoffset) 2's compliment (key1 protected), */\ + { 0x8207, "calibr_gain_cs"}, /* gain current sense (Imeasalpha) 2's compliment (key1 protected), */\ + { 0x8284, "calibr_temp_offset"}, /* temperature offset 2's compliment (key1 protected), */\ + { 0x82d2, "calibr_temp_gain"}, /* temperature gain 2's compliment (key1 protected) , */\ + { 0x830f, "calibr_ron"}, /* Ron resistance of coil (key1 protected) , */\ + { 0x8406, "ctrl_offset_a"}, /* Offset of amplifier level shifter , */\ + { 0x8486, "ctrl_offset_b"}, /* Offset of amplifier level shifter , */\ + { 0x850f, "type_bits_HW"}, /* HW Bits , */\ + { 0x860f, "type_bits1_SW"}, /* MTP-control SW1 , */\ + { 0x870f, "type_bits2_SW"}, /* MTP-control SW2 , */\ + { 0x8a0f, "production_data1"}, /* (key1 protected) , */\ + { 0x8b0f, "production_data2"}, /* (key1 protected) , */\ + { 0x8c0f, "production_data3"}, /* (key1 protected) , */\ + { 0x8d0f, "production_data4"}, /* (key1 protected) , */\ + { 0x8e0f, "production_data5"}, /* (key1 protected) , */\ + { 0x8f0f, "production_data6"}, /* (key1 protected) , */\ + { 0xffff,"Unknown bitfield enum" } /* not found */\ +}; + + +#endif /* TFA_INC_TFA9891_TFAFIELDNAMES_H_ */ diff --git a/techpack/audio/asoc/codecs/tfa9874/tfa9894_tfafieldnames.h b/techpack/audio/asoc/codecs/tfa9874/tfa9894_tfafieldnames.h new file mode 100644 index 000000000000..25c55cd8ce74 --- /dev/null +++ b/techpack/audio/asoc/codecs/tfa9874/tfa9894_tfafieldnames.h @@ -0,0 +1,1065 @@ +/** Filename: tfa9894_tfaFieldnames.h + * This file was generated automatically on 09/06/17 at 14:51:37. + * Source file: TFA9894_N1A1_I2C_RegisterMap.xlsx + */ + +#ifndef _TFA9894_TFAFIELDNAMES_H +#define _TFA9894_TFAFIELDNAMES_H + +#define TFA9894_I2CVERSION 7 + +typedef enum nxpTfa9894BfEnumList { + TFA9894_BF_PWDN = 0x0000, /*!< Powerdown control */ + TFA9894_BF_I2CR = 0x0010, /*!< I2C Reset - Auto clear */ + TFA9894_BF_CFE = 0x0020, /*!< Enable CoolFlux DSP */ + TFA9894_BF_AMPE = 0x0030, /*!< Enable Amplifier */ + TFA9894_BF_DCA = 0x0040, /*!< Enable DCDC Boost converter */ + TFA9894_BF_SBSL = 0x0050, /*!< Coolflux configured */ + TFA9894_BF_AMPC = 0x0060, /*!< CoolFlux control over amplifier */ + TFA9894_BF_INTP = 0x0071, /*!< Interrupt config */ + TFA9894_BF_FSSSEL= 0x0090, /*!< Audio sample reference */ + TFA9894_BF_BYPOCP= 0x00a0, /*!< Bypass OCP */ + TFA9894_BF_TSTOCP= 0x00b0, /*!< OCP testing control */ + TFA9894_BF_BSSS = 0x00c0, /*!< Vbat protection steepness */ + TFA9894_BF_HPFBYP= 0x00d0, /*!< Bypass High Pass Filter */ + TFA9894_BF_DPSA = 0x00e0, /*!< Enable DPSA */ + TFA9894_BF_AMPINSEL= 0x0101, /*!< Amplifier input selection */ + TFA9894_BF_MANSCONF= 0x0120, /*!< Device I2C settings configured */ + TFA9894_BF_MANCOLD= 0x0130, /*!< Execute cold start */ + TFA9894_BF_MANROBOD= 0x0140, /*!< Reaction on BOD */ + TFA9894_BF_BODE = 0x0150, /*!< Enable BOD (only in direct control mode) */ + TFA9894_BF_BODHYS= 0x0160, /*!< Enable Hysteresis of BOD */ + TFA9894_BF_BODFILT= 0x0171, /*!< BOD filter */ + TFA9894_BF_BODTHLVL= 0x0191, /*!< BOD threshold */ + TFA9894_BF_MUTETO= 0x01b0, /*!< Time out SB mute sequence */ + TFA9894_BF_MANWDE= 0x01c0, /*!< Watchdog enable */ + TFA9894_BF_OPENMTP= 0x01e0, /*!< Control for FAIM protection */ + TFA9894_BF_FAIMVBGOVRRL= 0x01f0, /*!< Overrule the enabling of VBG for faim erase/write access */ + TFA9894_BF_AUDFS = 0x0203, /*!< Audio sample rate Fs */ + TFA9894_BF_INPLEV= 0x0240, /*!< TDM output attenuation */ + TFA9894_BF_FRACTDEL= 0x0255, /*!< Current sense fractional delay */ + TFA9894_BF_TDMPRES= 0x02b1, /*!< Control for HW manager */ + TFA9894_BF_AMPOCRT= 0x02d2, /*!< Amplifier on-off criteria for shutdown */ + TFA9894_BF_REV = 0x030f, /*!< Revision info */ + TFA9894_BF_REFCKEXT= 0x0401, /*!< PLL external reference clock */ + TFA9894_BF_REFCKSEL= 0x0420, /*!< PLL internal reference clock */ + TFA9894_BF_MCLKSEL= 0x0432, /*!< Master Clock Selection */ + TFA9894_BF_MANAOOSC= 0x0460, /*!< Internal OSC1M off at PWDN */ + TFA9894_BF_ACKCLDDIS= 0x0470, /*!< Automatic PLL reference clock selection for cold start */ + TFA9894_BF_SPKSSEN= 0x0510, /*!< Enable speaker sub-system */ + TFA9894_BF_MTPSSEN= 0x0520, /*!< Enable FAIM sub-system */ + TFA9894_BF_WDTCLKEN= 0x0530, /*!< Enable Coolflux watchdog clock */ + TFA9894_BF_VDDS = 0x1000, /*!< POR */ + TFA9894_BF_PLLS = 0x1010, /*!< PLL Lock */ + TFA9894_BF_OTDS = 0x1020, /*!< OTP alarm */ + TFA9894_BF_OVDS = 0x1030, /*!< OVP alarm */ + TFA9894_BF_UVDS = 0x1040, /*!< UVP alarm */ + TFA9894_BF_OCDS = 0x1050, /*!< OCP amplifier (sticky register, clear on read) */ + TFA9894_BF_CLKS = 0x1060, /*!< Clocks stable */ + TFA9894_BF_MTPB = 0x1070, /*!< MTP busy */ + TFA9894_BF_NOCLK = 0x1080, /*!< Lost clock */ + TFA9894_BF_ACS = 0x1090, /*!< Cold Start */ + TFA9894_BF_WDS = 0x10a0, /*!< Watchdog */ + TFA9894_BF_SWS = 0x10b0, /*!< Amplifier engage */ + TFA9894_BF_AMPS = 0x10c0, /*!< Amplifier enable */ + TFA9894_BF_AREFS = 0x10d0, /*!< References enable */ + TFA9894_BF_ADCCR = 0x10e0, /*!< Control ADC */ + TFA9894_BF_BODNOK= 0x10f0, /*!< BOD Flag - VDD NOT OK */ + TFA9894_BF_DCIL = 0x1100, /*!< DCDC current limiting */ + TFA9894_BF_DCDCA = 0x1110, /*!< DCDC active (sticky register, clear on read) */ + TFA9894_BF_DCOCPOK= 0x1120, /*!< DCDC OCP nmos (sticky register, clear on read) */ + TFA9894_BF_DCHVBAT= 0x1140, /*!< DCDC level 1x */ + TFA9894_BF_DCH114= 0x1150, /*!< DCDC level 1.14x */ + TFA9894_BF_DCH107= 0x1160, /*!< DCDC level 1.07x */ + TFA9894_BF_SPKS = 0x1170, /*!< Speaker status */ + TFA9894_BF_CLKOOR= 0x1180, /*!< External clock status */ + TFA9894_BF_MANALARM= 0x1190, /*!< Alarm state */ + TFA9894_BF_TDMERR= 0x11a0, /*!< TDM error */ + TFA9894_BF_TDMLUTER= 0x11b0, /*!< TDM lookup table error */ + TFA9894_BF_OCPOAP= 0x1200, /*!< OCPOK pmos A */ + TFA9894_BF_OCPOAN= 0x1210, /*!< OCPOK nmos A */ + TFA9894_BF_OCPOBP= 0x1220, /*!< OCPOK pmos B */ + TFA9894_BF_OCPOBN= 0x1230, /*!< OCPOK nmos B */ + TFA9894_BF_CLIPS = 0x1240, /*!< Amplifier clipping */ + TFA9894_BF_MANMUTE= 0x1250, /*!< Audio mute sequence */ + TFA9894_BF_MANOPER= 0x1260, /*!< Device in Operating state */ + TFA9894_BF_LP1 = 0x1270, /*!< Low power MODE1 detection */ + TFA9894_BF_LA = 0x1280, /*!< Low amplitude detection */ + TFA9894_BF_VDDPH = 0x1290, /*!< VDDP greater than VBAT flag */ + TFA9894_BF_TDMSTAT= 0x1402, /*!< TDM Status bits */ + TFA9894_BF_MANSTATE= 0x1433, /*!< Device Manager status */ + TFA9894_BF_DCMODE= 0x14b1, /*!< DCDC mode status bits */ + TFA9894_BF_BATS = 0x1509, /*!< Battery voltage (V) */ + TFA9894_BF_TEMPS = 0x1608, /*!< IC Temperature (C) */ + TFA9894_BF_VDDPS = 0x1709, /*!< IC VDDP voltage (1023*VDDP/13V) */ + TFA9894_BF_TDME = 0x2000, /*!< Enable interface */ + TFA9894_BF_TDMSPKE= 0x2010, /*!< Control audio tdm channel in sink0 */ + TFA9894_BF_TDMDCE= 0x2020, /*!< Control audio tdm channel in sink1 */ + TFA9894_BF_TDMCSE= 0x2030, /*!< Source 0 enable */ + TFA9894_BF_TDMVSE= 0x2040, /*!< Source 1 enable */ + TFA9894_BF_TDMCFE= 0x2050, /*!< Source 2 enable */ + TFA9894_BF_TDMCF2E= 0x2060, /*!< Source 3 enable */ + TFA9894_BF_TDMCLINV= 0x2070, /*!< Reception data to BCK clock */ + TFA9894_BF_TDMFSPOL= 0x2080, /*!< FS polarity */ + TFA9894_BF_TDMDEL= 0x2090, /*!< Data delay to FS */ + TFA9894_BF_TDMADJ= 0x20a0, /*!< Data adjustment */ + TFA9894_BF_TDMOOMP= 0x20b1, /*!< Received audio compression */ + TFA9894_BF_TDMNBCK= 0x2103, /*!< TDM NBCK - Bit clock to FS ratio */ + TFA9894_BF_TDMFSLN= 0x2143, /*!< FS length (master mode only) */ + TFA9894_BF_TDMSLOTS= 0x2183, /*!< N-slots in Frame */ + TFA9894_BF_TDMTXDFO= 0x21c1, /*!< Format unused bits */ + TFA9894_BF_TDMTXUS0= 0x21e1, /*!< Format unused slots DATAO */ + TFA9894_BF_TDMSLLN= 0x2204, /*!< N-bits in slot */ + TFA9894_BF_TDMBRMG= 0x2254, /*!< N-bits remaining */ + TFA9894_BF_TDMSSIZE= 0x22a4, /*!< Sample size per slot */ + TFA9894_BF_TDMSPKS= 0x2303, /*!< TDM slot for sink 0 */ + TFA9894_BF_TDMDCS= 0x2343, /*!< TDM slot for sink 1 */ + TFA9894_BF_TDMCFSEL= 0x2381, /*!< TDM Source 2 data selection */ + TFA9894_BF_TDMCF2SEL= 0x23a1, /*!< TDM Source 3 data selection */ + TFA9894_BF_TDMCSS= 0x2403, /*!< Slot Position of source 0 data */ + TFA9894_BF_TDMVSS= 0x2443, /*!< Slot Position of source 1 data */ + TFA9894_BF_TDMCFS= 0x2483, /*!< Slot Position of source 2 data */ + TFA9894_BF_TDMCF2S= 0x24c3, /*!< Slot Position of source 3 data */ + TFA9894_BF_ISTVDDS= 0x4000, /*!< Status POR */ + TFA9894_BF_ISTBSTOC= 0x4010, /*!< Status DCDC OCP */ + TFA9894_BF_ISTOTDS= 0x4020, /*!< Status OTP alarm */ + TFA9894_BF_ISTOCPR= 0x4030, /*!< Status OCP alarm */ + TFA9894_BF_ISTUVDS= 0x4040, /*!< Status UVP alarm */ + TFA9894_BF_ISTMANALARM= 0x4050, /*!< Status manager alarm state */ + TFA9894_BF_ISTTDMER= 0x4060, /*!< Status TDM error */ + TFA9894_BF_ISTNOCLK= 0x4070, /*!< Status lost clock */ + TFA9894_BF_ISTCFMER= 0x4080, /*!< Status cfma error */ + TFA9894_BF_ISTCFMAC= 0x4090, /*!< Status cfma ack */ + TFA9894_BF_ISTSPKS= 0x40a0, /*!< Status coolflux speaker error */ + TFA9894_BF_ISTACS= 0x40b0, /*!< Status cold started */ + TFA9894_BF_ISTWDS= 0x40c0, /*!< Status watchdog reset */ + TFA9894_BF_ISTBODNOK= 0x40d0, /*!< Status brown out detect */ + TFA9894_BF_ISTLP1= 0x40e0, /*!< Status low power mode1 detect */ + TFA9894_BF_ISTCLKOOR= 0x40f0, /*!< Status clock out of range */ + TFA9894_BF_ICLVDDS= 0x4400, /*!< Clear POR */ + TFA9894_BF_ICLBSTOC= 0x4410, /*!< Clear DCDC OCP */ + TFA9894_BF_ICLOTDS= 0x4420, /*!< Clear OTP alarm */ + TFA9894_BF_ICLOCPR= 0x4430, /*!< Clear OCP alarm */ + TFA9894_BF_ICLUVDS= 0x4440, /*!< Clear UVP alarm */ + TFA9894_BF_ICLMANALARM= 0x4450, /*!< Clear manager alarm state */ + TFA9894_BF_ICLTDMER= 0x4460, /*!< Clear TDM error */ + TFA9894_BF_ICLNOCLK= 0x4470, /*!< Clear lost clk */ + TFA9894_BF_ICLCFMER= 0x4480, /*!< Clear cfma err */ + TFA9894_BF_ICLCFMAC= 0x4490, /*!< Clear cfma ack */ + TFA9894_BF_ICLSPKS= 0x44a0, /*!< Clear coolflux speaker error */ + TFA9894_BF_ICLACS= 0x44b0, /*!< Clear cold started */ + TFA9894_BF_ICLWDS= 0x44c0, /*!< Clear watchdog reset */ + TFA9894_BF_ICLBODNOK= 0x44d0, /*!< Clear brown out detect */ + TFA9894_BF_ICLLP1= 0x44e0, /*!< Clear low power mode1 detect */ + TFA9894_BF_ICLCLKOOR= 0x44f0, /*!< Clear clock out of range */ + TFA9894_BF_IEVDDS= 0x4800, /*!< Enable POR */ + TFA9894_BF_IEBSTOC= 0x4810, /*!< Enable DCDC OCP */ + TFA9894_BF_IEOTDS= 0x4820, /*!< Enable OTP alarm */ + TFA9894_BF_IEOCPR= 0x4830, /*!< Enable OCP alarm */ + TFA9894_BF_IEUVDS= 0x4840, /*!< Enable UVP alarm */ + TFA9894_BF_IEMANALARM= 0x4850, /*!< Enable Manager Alarm state */ + TFA9894_BF_IETDMER= 0x4860, /*!< Enable TDM error */ + TFA9894_BF_IENOCLK= 0x4870, /*!< Enable lost clk */ + TFA9894_BF_IECFMER= 0x4880, /*!< Enable cfma err */ + TFA9894_BF_IECFMAC= 0x4890, /*!< Enable cfma ack */ + TFA9894_BF_IESPKS= 0x48a0, /*!< Enable coolflux speaker error */ + TFA9894_BF_IEACS = 0x48b0, /*!< Enable cold started */ + TFA9894_BF_IEWDS = 0x48c0, /*!< Enable watchdog reset */ + TFA9894_BF_IEBODNOK= 0x48d0, /*!< Enable brown out detect */ + TFA9894_BF_IELP1 = 0x48e0, /*!< Enable low power mode1 detect */ + TFA9894_BF_IECLKOOR= 0x48f0, /*!< Enable clock out of range */ + TFA9894_BF_IPOVDDS= 0x4c00, /*!< Polarity POR */ + TFA9894_BF_IPOBSTOC= 0x4c10, /*!< Polarity DCDC OCP */ + TFA9894_BF_IPOOTDS= 0x4c20, /*!< Polarity OTP alarm */ + TFA9894_BF_IPOOCPR= 0x4c30, /*!< Polarity ocp alarm */ + TFA9894_BF_IPOUVDS= 0x4c40, /*!< Polarity UVP alarm */ + TFA9894_BF_IPOMANALARM= 0x4c50, /*!< Polarity manager alarm state */ + TFA9894_BF_IPOTDMER= 0x4c60, /*!< Polarity TDM error */ + TFA9894_BF_IPONOCLK= 0x4c70, /*!< Polarity lost clk */ + TFA9894_BF_IPOCFMER= 0x4c80, /*!< Polarity cfma err */ + TFA9894_BF_IPOCFMAC= 0x4c90, /*!< Polarity cfma ack */ + TFA9894_BF_IPOSPKS= 0x4ca0, /*!< Polarity coolflux speaker error */ + TFA9894_BF_IPOACS= 0x4cb0, /*!< Polarity cold started */ + TFA9894_BF_IPOWDS= 0x4cc0, /*!< Polarity watchdog reset */ + TFA9894_BF_IPOBODNOK= 0x4cd0, /*!< Polarity brown out detect */ + TFA9894_BF_IPOLP1= 0x4ce0, /*!< Polarity low power mode1 detect */ + TFA9894_BF_IPOCLKOOR= 0x4cf0, /*!< Polarity clock out of range */ + TFA9894_BF_BSSCR = 0x5001, /*!< Battery safeguard attack time */ + TFA9894_BF_BSST = 0x5023, /*!< Battery safeguard threshold voltage level */ + TFA9894_BF_BSSRL = 0x5061, /*!< Battery safeguard maximum reduction */ + TFA9894_BF_BSSRR = 0x5082, /*!< Battery safeguard release time */ + TFA9894_BF_BSSHY = 0x50b1, /*!< Battery Safeguard hysteresis */ + TFA9894_BF_BSSR = 0x50e0, /*!< Battery voltage read out */ + TFA9894_BF_BSSBY = 0x50f0, /*!< Bypass HW clipper */ + TFA9894_BF_CFSM = 0x5130, /*!< Coolflux firmware soft mute control */ + TFA9894_BF_VOL = 0x5187, /*!< CF firmware volume control */ + TFA9894_BF_CLIPCTRL= 0x5202, /*!< Clip control setting */ + TFA9894_BF_SLOPEE= 0x5230, /*!< Enables slope control */ + TFA9894_BF_SLOPESET= 0x5240, /*!< Slope speed setting (binary coded) */ + TFA9894_BF_AMPGAIN= 0x5287, /*!< Amplifier gain */ + TFA9894_BF_TDMDCG= 0x5703, /*!< Second channel gain in case of stereo using a single coil. (Total gain depending on INPLEV). (In case of mono OR stereo using 2 separate DCDC channel 1 should be disabled using TDMDCE) */ + TFA9894_BF_TDMSPKG= 0x5743, /*!< Total gain depending on INPLEV setting (channel 0) */ + TFA9894_BF_DCINSEL= 0x5781, /*!< VAMP_OUT2 input selection */ + TFA9894_BF_LNMODE= 0x5881, /*!< Low noise gain mode control */ + TFA9894_BF_LPM1MODE= 0x5ac1, /*!< Low power mode control */ + TFA9894_BF_TDMSRCMAP= 0x5d02, /*!< TDM source mapping */ + TFA9894_BF_TDMSRCAS= 0x5d31, /*!< Sensed value A */ + TFA9894_BF_TDMSRCBS= 0x5d51, /*!< Sensed value B */ + TFA9894_BF_TDMSRCACLIP= 0x5d71, /*!< Clip information (analog /digital) for source0 */ + TFA9894_BF_TDMSRCBCLIP= 0x5d91, /*!< Clip information (analog /digital) for source1 */ + TFA9894_BF_DELCURCOMP= 0x6102, /*!< Delay to allign compensation signal with current sense signal */ + TFA9894_BF_SIGCURCOMP= 0x6130, /*!< Polarity of compensation for current sense */ + TFA9894_BF_ENCURCOMP= 0x6140, /*!< Enable current sense compensation */ + TFA9894_BF_LVLCLPPWM= 0x6152, /*!< Set the amount of pwm pulse that may be skipped before clip-flag is triggered */ + TFA9894_BF_DCVOF = 0x7005, /*!< First Boost Voltage Level */ + TFA9894_BF_DCVOS = 0x7065, /*!< Second Boost Voltage Level */ + TFA9894_BF_DCMCC = 0x70c3, /*!< Max Coil Current */ + TFA9894_BF_DCCV = 0x7101, /*!< Slope compensation current, represents LxF (inductance x frequency) value */ + TFA9894_BF_DCIE = 0x7120, /*!< Adaptive boost mode */ + TFA9894_BF_DCSR = 0x7130, /*!< Soft ramp up/down */ + TFA9894_BF_DCDIS = 0x7140, /*!< DCDC on/off */ + TFA9894_BF_DCPWM = 0x7150, /*!< DCDC PWM only mode */ + TFA9894_BF_DCTRACK= 0x7160, /*!< Boost algorithm selection, effective only when boost_intelligent is set to 1 */ + TFA9894_BF_DCTRIP= 0x7204, /*!< 1st adaptive boost trip levels, effective only when DCIE is set to 1 */ + TFA9894_BF_DCTRIP2= 0x7254, /*!< 2nd adaptive boost trip levels, effective only when DCIE is set to 1 */ + TFA9894_BF_DCTRIPT= 0x72a4, /*!< Track adaptive boost trip levels, effective only when boost_intelligent is set to 1 */ + TFA9894_BF_DCTRIPHYSTE= 0x72f0, /*!< Enable hysteresis on booster trip levels */ + TFA9894_BF_DCHOLD= 0x7304, /*!< Hold time for DCDC booster, effective only when boost_intelligent is set to 1 */ + TFA9894_BF_RST = 0x9000, /*!< Reset for Coolflux DSP */ + TFA9894_BF_DMEM = 0x9011, /*!< Target memory for CFMA using I2C interface */ + TFA9894_BF_AIF = 0x9030, /*!< Auto increment */ + TFA9894_BF_CFINT = 0x9040, /*!< Coolflux Interrupt - auto clear */ + TFA9894_BF_CFCGATE= 0x9050, /*!< Coolflux clock gating disabling control */ + TFA9894_BF_REQCMD= 0x9080, /*!< Firmware event request rpc command */ + TFA9894_BF_REQRST= 0x9090, /*!< Firmware event request reset restart */ + TFA9894_BF_REQMIPS= 0x90a0, /*!< Firmware event request short on mips */ + TFA9894_BF_REQMUTED= 0x90b0, /*!< Firmware event request mute sequence ready */ + TFA9894_BF_REQVOL= 0x90c0, /*!< Firmware event request volume ready */ + TFA9894_BF_REQDMG= 0x90d0, /*!< Firmware event request speaker damage detected */ + TFA9894_BF_REQCAL= 0x90e0, /*!< Firmware event request calibration completed */ + TFA9894_BF_REQRSV= 0x90f0, /*!< Firmware event request reserved */ + TFA9894_BF_MADD = 0x910f, /*!< CF memory address */ + TFA9894_BF_MEMA = 0x920f, /*!< Activate memory access */ + TFA9894_BF_ERR = 0x9307, /*!< CF error flags */ + TFA9894_BF_ACKCMD= 0x9380, /*!< Firmware event acknowledge rpc command */ + TFA9894_BF_ACKRST= 0x9390, /*!< Firmware event acknowledge reset restart */ + TFA9894_BF_ACKMIPS= 0x93a0, /*!< Firmware event acknowledge short on mips */ + TFA9894_BF_ACKMUTED= 0x93b0, /*!< Firmware event acknowledge mute sequence ready */ + TFA9894_BF_ACKVOL= 0x93c0, /*!< Firmware event acknowledge volume ready */ + TFA9894_BF_ACKDMG= 0x93d0, /*!< Firmware event acknowledge speaker damage detected */ + TFA9894_BF_ACKCAL= 0x93e0, /*!< Firmware event acknowledge calibration completed */ + TFA9894_BF_ACKRSV= 0x93f0, /*!< Firmware event acknowledge reserved */ + TFA9894_BF_MTPK = 0xa107, /*!< KEY2 to access KEY2 protected registers, customer key */ + TFA9894_BF_KEY1LOCKED= 0xa200, /*!< Indicates KEY1 is locked */ + TFA9894_BF_KEY2LOCKED= 0xa210, /*!< Indicates KEY2 is locked */ + TFA9894_BF_CMTPI = 0xa350, /*!< Start copying all the data from mtp to I2C mtp registers - auto clear */ + TFA9894_BF_CIMTP = 0xa360, /*!< Start copying data from I2C mtp registers to mtp - auto clear */ + TFA9894_BF_MTPRDMSB= 0xa50f, /*!< MSB word of MTP manual read data */ + TFA9894_BF_MTPRDLSB= 0xa60f, /*!< LSB word of MTP manual read data */ + TFA9894_BF_EXTTS = 0xb108, /*!< External temperature (C) */ + TFA9894_BF_TROS = 0xb190, /*!< Select temp Speaker calibration */ + TFA9894_BF_SWPROFIL= 0xe00f, /*!< Software profile data */ + TFA9894_BF_SWVSTEP= 0xe10f, /*!< Software vstep information */ + TFA9894_BF_MTPOTC= 0xf000, /*!< Calibration schedule */ + TFA9894_BF_MTPEX = 0xf010, /*!< Calibration Ron executed */ + TFA9894_BF_DCMCCAPI= 0xf020, /*!< Calibration current limit DCDC */ + TFA9894_BF_DCMCCSB= 0xf030, /*!< Sign bit for delta calibration current limit DCDC */ + TFA9894_BF_USERDEF= 0xf042, /*!< Calibration delta current limit DCDC */ + TFA9894_BF_CUSTINFO= 0xf078, /*!< Reserved space for allowing customer to store speaker information */ + TFA9894_BF_R25C = 0xf50f, /*!< Ron resistance of speaker coil */ +} nxpTfa9894BfEnumList_t; +#define TFA9894_NAMETABLE static tfaBfName_t Tfa9894DatasheetNames[]= {\ + { 0x0, "PWDN"}, /* Powerdown control , */\ + { 0x10, "I2CR"}, /* I2C Reset - Auto clear , */\ + { 0x20, "CFE"}, /* Enable CoolFlux DSP , */\ + { 0x30, "AMPE"}, /* Enable Amplifier , */\ + { 0x40, "DCA"}, /* Enable DCDC Boost converter , */\ + { 0x50, "SBSL"}, /* Coolflux configured , */\ + { 0x60, "AMPC"}, /* CoolFlux control over amplifier , */\ + { 0x71, "INTP"}, /* Interrupt config , */\ + { 0x90, "FSSSEL"}, /* Audio sample reference , */\ + { 0xa0, "BYPOCP"}, /* Bypass OCP , */\ + { 0xb0, "TSTOCP"}, /* OCP testing control , */\ + { 0xc0, "BSSS"}, /* Vbat protection steepness , */\ + { 0xd0, "HPFBYP"}, /* Bypass High Pass Filter , */\ + { 0xe0, "DPSA"}, /* Enable DPSA , */\ + { 0x101, "AMPINSEL"}, /* Amplifier input selection , */\ + { 0x120, "MANSCONF"}, /* Device I2C settings configured , */\ + { 0x130, "MANCOLD"}, /* Execute cold start , */\ + { 0x140, "MANROBOD"}, /* Reaction on BOD , */\ + { 0x150, "BODE"}, /* Enable BOD (only in direct control mode) , */\ + { 0x160, "BODHYS"}, /* Enable Hysteresis of BOD , */\ + { 0x171, "BODFILT"}, /* BOD filter , */\ + { 0x191, "BODTHLVL"}, /* BOD threshold , */\ + { 0x1b0, "MUTETO"}, /* Time out SB mute sequence , */\ + { 0x1c0, "MANWDE"}, /* Watchdog enable , */\ + { 0x1e0, "OPENMTP"}, /* Control for FAIM protection , */\ + { 0x1f0, "FAIMVBGOVRRL"}, /* Overrule the enabling of VBG for faim erase/write access, */\ + { 0x203, "AUDFS"}, /* Audio sample rate Fs , */\ + { 0x240, "INPLEV"}, /* TDM output attenuation , */\ + { 0x255, "FRACTDEL"}, /* Current sense fractional delay , */\ + { 0x2b1, "TDMPRES"}, /* Control for HW manager , */\ + { 0x2d2, "AMPOCRT"}, /* Amplifier on-off criteria for shutdown , */\ + { 0x30f, "REV"}, /* Revision info , */\ + { 0x401, "REFCKEXT"}, /* PLL external reference clock , */\ + { 0x420, "REFCKSEL"}, /* PLL internal reference clock , */\ + { 0x432, "MCLKSEL"}, /* Master Clock Selection , */\ + { 0x460, "MANAOOSC"}, /* Internal OSC1M off at PWDN , */\ + { 0x470, "ACKCLDDIS"}, /* Automatic PLL reference clock selection for cold start, */\ + { 0x510, "SPKSSEN"}, /* Enable speaker sub-system , */\ + { 0x520, "MTPSSEN"}, /* Enable FAIM sub-system , */\ + { 0x530, "WDTCLKEN"}, /* Enable Coolflux watchdog clock , */\ + { 0x1000, "VDDS"}, /* POR , */\ + { 0x1010, "PLLS"}, /* PLL Lock , */\ + { 0x1020, "OTDS"}, /* OTP alarm , */\ + { 0x1030, "OVDS"}, /* OVP alarm , */\ + { 0x1040, "UVDS"}, /* UVP alarm , */\ + { 0x1050, "OCDS"}, /* OCP amplifier (sticky register, clear on read) , */\ + { 0x1060, "CLKS"}, /* Clocks stable , */\ + { 0x1070, "MTPB"}, /* MTP busy , */\ + { 0x1080, "NOCLK"}, /* Lost clock , */\ + { 0x1090, "ACS"}, /* Cold Start , */\ + { 0x10a0, "WDS"}, /* Watchdog , */\ + { 0x10b0, "SWS"}, /* Amplifier engage , */\ + { 0x10c0, "AMPS"}, /* Amplifier enable , */\ + { 0x10d0, "AREFS"}, /* References enable , */\ + { 0x10e0, "ADCCR"}, /* Control ADC , */\ + { 0x10f0, "BODNOK"}, /* BOD Flag - VDD NOT OK , */\ + { 0x1100, "DCIL"}, /* DCDC current limiting , */\ + { 0x1110, "DCDCA"}, /* DCDC active (sticky register, clear on read) , */\ + { 0x1120, "DCOCPOK"}, /* DCDC OCP nmos (sticky register, clear on read) , */\ + { 0x1140, "DCHVBAT"}, /* DCDC level 1x , */\ + { 0x1150, "DCH114"}, /* DCDC level 1.14x , */\ + { 0x1160, "DCH107"}, /* DCDC level 1.07x , */\ + { 0x1170, "SPKS"}, /* Speaker status , */\ + { 0x1180, "CLKOOR"}, /* External clock status , */\ + { 0x1190, "MANALARM"}, /* Alarm state , */\ + { 0x11a0, "TDMERR"}, /* TDM error , */\ + { 0x11b0, "TDMLUTER"}, /* TDM lookup table error , */\ + { 0x1200, "OCPOAP"}, /* OCPOK pmos A , */\ + { 0x1210, "OCPOAN"}, /* OCPOK nmos A , */\ + { 0x1220, "OCPOBP"}, /* OCPOK pmos B , */\ + { 0x1230, "OCPOBN"}, /* OCPOK nmos B , */\ + { 0x1240, "CLIPS"}, /* Amplifier clipping , */\ + { 0x1250, "MANMUTE"}, /* Audio mute sequence , */\ + { 0x1260, "MANOPER"}, /* Device in Operating state , */\ + { 0x1270, "LP1"}, /* Low power MODE1 detection , */\ + { 0x1280, "LA"}, /* Low amplitude detection , */\ + { 0x1290, "VDDPH"}, /* VDDP greater than VBAT flag , */\ + { 0x1402, "TDMSTAT"}, /* TDM Status bits , */\ + { 0x1433, "MANSTATE"}, /* Device Manager status , */\ + { 0x14b1, "DCMODE"}, /* DCDC mode status bits , */\ + { 0x1509, "BATS"}, /* Battery voltage (V) , */\ + { 0x1608, "TEMPS"}, /* IC Temperature (C) , */\ + { 0x1709, "VDDPS"}, /* IC VDDP voltage (1023*VDDP/13V) , */\ + { 0x2000, "TDME"}, /* Enable interface , */\ + { 0x2010, "TDMSPKE"}, /* Control audio tdm channel in sink0 , */\ + { 0x2020, "TDMDCE"}, /* Control audio tdm channel in sink1 , */\ + { 0x2030, "TDMCSE"}, /* Source 0 enable , */\ + { 0x2040, "TDMVSE"}, /* Source 1 enable , */\ + { 0x2050, "TDMCFE"}, /* Source 2 enable , */\ + { 0x2060, "TDMCF2E"}, /* Source 3 enable , */\ + { 0x2070, "TDMCLINV"}, /* Reception data to BCK clock , */\ + { 0x2080, "TDMFSPOL"}, /* FS polarity , */\ + { 0x2090, "TDMDEL"}, /* Data delay to FS , */\ + { 0x20a0, "TDMADJ"}, /* Data adjustment , */\ + { 0x20b1, "TDMOOMP"}, /* Received audio compression , */\ + { 0x2103, "TDMNBCK"}, /* TDM NBCK - Bit clock to FS ratio , */\ + { 0x2143, "TDMFSLN"}, /* FS length (master mode only) , */\ + { 0x2183, "TDMSLOTS"}, /* N-slots in Frame , */\ + { 0x21c1, "TDMTXDFO"}, /* Format unused bits , */\ + { 0x21e1, "TDMTXUS0"}, /* Format unused slots DATAO , */\ + { 0x2204, "TDMSLLN"}, /* N-bits in slot , */\ + { 0x2254, "TDMBRMG"}, /* N-bits remaining , */\ + { 0x22a4, "TDMSSIZE"}, /* Sample size per slot , */\ + { 0x2303, "TDMSPKS"}, /* TDM slot for sink 0 , */\ + { 0x2343, "TDMDCS"}, /* TDM slot for sink 1 , */\ + { 0x2381, "TDMCFSEL"}, /* TDM Source 2 data selection , */\ + { 0x23a1, "TDMCF2SEL"}, /* TDM Source 3 data selection , */\ + { 0x2403, "TDMCSS"}, /* Slot Position of source 0 data , */\ + { 0x2443, "TDMVSS"}, /* Slot Position of source 1 data , */\ + { 0x2483, "TDMCFS"}, /* Slot Position of source 2 data , */\ + { 0x24c3, "TDMCF2S"}, /* Slot Position of source 3 data , */\ + { 0x4000, "ISTVDDS"}, /* Status POR , */\ + { 0x4010, "ISTBSTOC"}, /* Status DCDC OCP , */\ + { 0x4020, "ISTOTDS"}, /* Status OTP alarm , */\ + { 0x4030, "ISTOCPR"}, /* Status OCP alarm , */\ + { 0x4040, "ISTUVDS"}, /* Status UVP alarm , */\ + { 0x4050, "ISTMANALARM"}, /* Status manager alarm state , */\ + { 0x4060, "ISTTDMER"}, /* Status TDM error , */\ + { 0x4070, "ISTNOCLK"}, /* Status lost clock , */\ + { 0x4080, "ISTCFMER"}, /* Status cfma error , */\ + { 0x4090, "ISTCFMAC"}, /* Status cfma ack , */\ + { 0x40a0, "ISTSPKS"}, /* Status coolflux speaker error , */\ + { 0x40b0, "ISTACS"}, /* Status cold started , */\ + { 0x40c0, "ISTWDS"}, /* Status watchdog reset , */\ + { 0x40d0, "ISTBODNOK"}, /* Status brown out detect , */\ + { 0x40e0, "ISTLP1"}, /* Status low power mode1 detect , */\ + { 0x40f0, "ISTCLKOOR"}, /* Status clock out of range , */\ + { 0x4400, "ICLVDDS"}, /* Clear POR , */\ + { 0x4410, "ICLBSTOC"}, /* Clear DCDC OCP , */\ + { 0x4420, "ICLOTDS"}, /* Clear OTP alarm , */\ + { 0x4430, "ICLOCPR"}, /* Clear OCP alarm , */\ + { 0x4440, "ICLUVDS"}, /* Clear UVP alarm , */\ + { 0x4450, "ICLMANALARM"}, /* Clear manager alarm state , */\ + { 0x4460, "ICLTDMER"}, /* Clear TDM error , */\ + { 0x4470, "ICLNOCLK"}, /* Clear lost clk , */\ + { 0x4480, "ICLCFMER"}, /* Clear cfma err , */\ + { 0x4490, "ICLCFMAC"}, /* Clear cfma ack , */\ + { 0x44a0, "ICLSPKS"}, /* Clear coolflux speaker error , */\ + { 0x44b0, "ICLACS"}, /* Clear cold started , */\ + { 0x44c0, "ICLWDS"}, /* Clear watchdog reset , */\ + { 0x44d0, "ICLBODNOK"}, /* Clear brown out detect , */\ + { 0x44e0, "ICLLP1"}, /* Clear low power mode1 detect , */\ + { 0x44f0, "ICLCLKOOR"}, /* Clear clock out of range , */\ + { 0x4800, "IEVDDS"}, /* Enable POR , */\ + { 0x4810, "IEBSTOC"}, /* Enable DCDC OCP , */\ + { 0x4820, "IEOTDS"}, /* Enable OTP alarm , */\ + { 0x4830, "IEOCPR"}, /* Enable OCP alarm , */\ + { 0x4840, "IEUVDS"}, /* Enable UVP alarm , */\ + { 0x4850, "IEMANALARM"}, /* Enable Manager Alarm state , */\ + { 0x4860, "IETDMER"}, /* Enable TDM error , */\ + { 0x4870, "IENOCLK"}, /* Enable lost clk , */\ + { 0x4880, "IECFMER"}, /* Enable cfma err , */\ + { 0x4890, "IECFMAC"}, /* Enable cfma ack , */\ + { 0x48a0, "IESPKS"}, /* Enable coolflux speaker error , */\ + { 0x48b0, "IEACS"}, /* Enable cold started , */\ + { 0x48c0, "IEWDS"}, /* Enable watchdog reset , */\ + { 0x48d0, "IEBODNOK"}, /* Enable brown out detect , */\ + { 0x48e0, "IELP1"}, /* Enable low power mode1 detect , */\ + { 0x48f0, "IECLKOOR"}, /* Enable clock out of range , */\ + { 0x4c00, "IPOVDDS"}, /* Polarity POR , */\ + { 0x4c10, "IPOBSTOC"}, /* Polarity DCDC OCP , */\ + { 0x4c20, "IPOOTDS"}, /* Polarity OTP alarm , */\ + { 0x4c30, "IPOOCPR"}, /* Polarity ocp alarm , */\ + { 0x4c40, "IPOUVDS"}, /* Polarity UVP alarm , */\ + { 0x4c50, "IPOMANALARM"}, /* Polarity manager alarm state , */\ + { 0x4c60, "IPOTDMER"}, /* Polarity TDM error , */\ + { 0x4c70, "IPONOCLK"}, /* Polarity lost clk , */\ + { 0x4c80, "IPOCFMER"}, /* Polarity cfma err , */\ + { 0x4c90, "IPOCFMAC"}, /* Polarity cfma ack , */\ + { 0x4ca0, "IPOSPKS"}, /* Polarity coolflux speaker error , */\ + { 0x4cb0, "IPOACS"}, /* Polarity cold started , */\ + { 0x4cc0, "IPOWDS"}, /* Polarity watchdog reset , */\ + { 0x4cd0, "IPOBODNOK"}, /* Polarity brown out detect , */\ + { 0x4ce0, "IPOLP1"}, /* Polarity low power mode1 detect , */\ + { 0x4cf0, "IPOCLKOOR"}, /* Polarity clock out of range , */\ + { 0x5001, "BSSCR"}, /* Battery safeguard attack time , */\ + { 0x5023, "BSST"}, /* Battery safeguard threshold voltage level , */\ + { 0x5061, "BSSRL"}, /* Battery safeguard maximum reduction , */\ + { 0x5082, "BSSRR"}, /* Battery safeguard release time , */\ + { 0x50b1, "BSSHY"}, /* Battery Safeguard hysteresis , */\ + { 0x50e0, "BSSR"}, /* Battery voltage read out , */\ + { 0x50f0, "BSSBY"}, /* Bypass HW clipper , */\ + { 0x5130, "CFSM"}, /* Coolflux firmware soft mute control , */\ + { 0x5187, "VOL"}, /* CF firmware volume control , */\ + { 0x5202, "CLIPCTRL"}, /* Clip control setting , */\ + { 0x5230, "SLOPEE"}, /* Enables slope control , */\ + { 0x5240, "SLOPESET"}, /* Slope speed setting (binary coded) , */\ + { 0x5287, "AMPGAIN"}, /* Amplifier gain , */\ + { 0x5703, "TDMDCG"}, /* Second channel gain in case of stereo using a single coil. (Total gain depending on INPLEV). (In case of mono OR stereo using 2 separate DCDC channel 1 should be disabled using TDMDCE), */\ + { 0x5743, "TDMSPKG"}, /* Total gain depending on INPLEV setting (channel 0), */\ + { 0x5781, "DCINSEL"}, /* VAMP_OUT2 input selection , */\ + { 0x5881, "LNMODE"}, /* Low noise gain mode control , */\ + { 0x5ac1, "LPM1MODE"}, /* Low power mode control , */\ + { 0x5d02, "TDMSRCMAP"}, /* TDM source mapping , */\ + { 0x5d31, "TDMSRCAS"}, /* Sensed value A , */\ + { 0x5d51, "TDMSRCBS"}, /* Sensed value B , */\ + { 0x5d71, "TDMSRCACLIP"}, /* Clip information (analog /digital) for source0 , */\ + { 0x5d91, "TDMSRCBCLIP"}, /* Clip information (analog /digital) for source1 , */\ + { 0x6102, "DELCURCOMP"}, /* Delay to allign compensation signal with current sense signal, */\ + { 0x6130, "SIGCURCOMP"}, /* Polarity of compensation for current sense , */\ + { 0x6140, "ENCURCOMP"}, /* Enable current sense compensation , */\ + { 0x6152, "LVLCLPPWM"}, /* Set the amount of pwm pulse that may be skipped before clip-flag is triggered, */\ + { 0x7005, "DCVOF"}, /* First Boost Voltage Level , */\ + { 0x7065, "DCVOS"}, /* Second Boost Voltage Level , */\ + { 0x70c3, "DCMCC"}, /* Max Coil Current , */\ + { 0x7101, "DCCV"}, /* Slope compensation current, represents LxF (inductance x frequency) value , */\ + { 0x7120, "DCIE"}, /* Adaptive boost mode , */\ + { 0x7130, "DCSR"}, /* Soft ramp up/down , */\ + { 0x7140, "DCDIS"}, /* DCDC on/off , */\ + { 0x7150, "DCPWM"}, /* DCDC PWM only mode , */\ + { 0x7160, "DCTRACK"}, /* Boost algorithm selection, effective only when boost_intelligent is set to 1, */\ + { 0x7204, "DCTRIP"}, /* 1st adaptive boost trip levels, effective only when DCIE is set to 1, */\ + { 0x7254, "DCTRIP2"}, /* 2nd adaptive boost trip levels, effective only when DCIE is set to 1, */\ + { 0x72a4, "DCTRIPT"}, /* Track adaptive boost trip levels, effective only when boost_intelligent is set to 1, */\ + { 0x72f0, "DCTRIPHYSTE"}, /* Enable hysteresis on booster trip levels , */\ + { 0x7304, "DCHOLD"}, /* Hold time for DCDC booster, effective only when boost_intelligent is set to 1, */\ + { 0x9000, "RST"}, /* Reset for Coolflux DSP , */\ + { 0x9011, "DMEM"}, /* Target memory for CFMA using I2C interface , */\ + { 0x9030, "AIF"}, /* Auto increment , */\ + { 0x9040, "CFINT"}, /* Coolflux Interrupt - auto clear , */\ + { 0x9050, "CFCGATE"}, /* Coolflux clock gating disabling control , */\ + { 0x9080, "REQCMD"}, /* Firmware event request rpc command , */\ + { 0x9090, "REQRST"}, /* Firmware event request reset restart , */\ + { 0x90a0, "REQMIPS"}, /* Firmware event request short on mips , */\ + { 0x90b0, "REQMUTED"}, /* Firmware event request mute sequence ready , */\ + { 0x90c0, "REQVOL"}, /* Firmware event request volume ready , */\ + { 0x90d0, "REQDMG"}, /* Firmware event request speaker damage detected , */\ + { 0x90e0, "REQCAL"}, /* Firmware event request calibration completed , */\ + { 0x90f0, "REQRSV"}, /* Firmware event request reserved , */\ + { 0x910f, "MADD"}, /* CF memory address , */\ + { 0x920f, "MEMA"}, /* Activate memory access , */\ + { 0x9307, "ERR"}, /* CF error flags , */\ + { 0x9380, "ACKCMD"}, /* Firmware event acknowledge rpc command , */\ + { 0x9390, "ACKRST"}, /* Firmware event acknowledge reset restart , */\ + { 0x93a0, "ACKMIPS"}, /* Firmware event acknowledge short on mips , */\ + { 0x93b0, "ACKMUTED"}, /* Firmware event acknowledge mute sequence ready , */\ + { 0x93c0, "ACKVOL"}, /* Firmware event acknowledge volume ready , */\ + { 0x93d0, "ACKDMG"}, /* Firmware event acknowledge speaker damage detected, */\ + { 0x93e0, "ACKCAL"}, /* Firmware event acknowledge calibration completed , */\ + { 0x93f0, "ACKRSV"}, /* Firmware event acknowledge reserved , */\ + { 0xa107, "MTPK"}, /* KEY2 to access KEY2 protected registers, customer key, */\ + { 0xa200, "KEY1LOCKED"}, /* Indicates KEY1 is locked , */\ + { 0xa210, "KEY2LOCKED"}, /* Indicates KEY2 is locked , */\ + { 0xa350, "CMTPI"}, /* Start copying all the data from mtp to I2C mtp registers - auto clear, */\ + { 0xa360, "CIMTP"}, /* Start copying data from I2C mtp registers to mtp - auto clear, */\ + { 0xa50f, "MTPRDMSB"}, /* MSB word of MTP manual read data , */\ + { 0xa60f, "MTPRDLSB"}, /* LSB word of MTP manual read data , */\ + { 0xb108, "EXTTS"}, /* External temperature (C) , */\ + { 0xb190, "TROS"}, /* Select temp Speaker calibration , */\ + { 0xe00f, "SWPROFIL"}, /* Software profile data , */\ + { 0xe10f, "SWVSTEP"}, /* Software vstep information , */\ + { 0xf000, "MTPOTC"}, /* Calibration schedule , */\ + { 0xf010, "MTPEX"}, /* Calibration Ron executed , */\ + { 0xf020, "DCMCCAPI"}, /* Calibration current limit DCDC , */\ + { 0xf030, "DCMCCSB"}, /* Sign bit for delta calibration current limit DCDC , */\ + { 0xf042, "USERDEF"}, /* Calibration delta current limit DCDC , */\ + { 0xf078, "CUSTINFO"}, /* Reserved space for allowing customer to store speaker information, */\ + { 0xf50f, "R25C"}, /* Ron resistance of speaker coil , */\ + { 0xffff,"Unknown bitfield enum" } /* not found */\ +}; + +#define TFA9894_BITNAMETABLE static tfaBfName_t Tfa9894BitNames[]= {\ + { 0x0, "powerdown"}, /* Powerdown control , */\ + { 0x10, "reset"}, /* I2C Reset - Auto clear , */\ + { 0x20, "enbl_coolflux"}, /* Enable CoolFlux DSP , */\ + { 0x30, "enbl_amplifier"}, /* Enable Amplifier , */\ + { 0x40, "enbl_boost"}, /* Enable DCDC Boost converter , */\ + { 0x50, "coolflux_configured"}, /* Coolflux configured , */\ + { 0x60, "sel_enbl_amplifier"}, /* CoolFlux control over amplifier , */\ + { 0x71, "int_pad_io"}, /* Interrupt config , */\ + { 0x90, "fs_pulse_sel"}, /* Audio sample reference , */\ + { 0xa0, "bypass_ocp"}, /* Bypass OCP , */\ + { 0xb0, "test_ocp"}, /* OCP testing control , */\ + { 0xc0, "batsense_steepness"}, /* Vbat protection steepness , */\ + { 0xd0, "bypass_hp"}, /* Bypass High Pass Filter , */\ + { 0xe0, "enbl_dpsa"}, /* Enable DPSA , */\ + { 0xf0, "sel_hysteresis"}, /* Select hysteresis for clock range detector , */\ + { 0x101, "vamp_sel1"}, /* Amplifier input selection , */\ + { 0x120, "src_set_configured"}, /* Device I2C settings configured , */\ + { 0x130, "execute_cold_start"}, /* Execute cold start , */\ + { 0x140, "man_enbl_brown_out"}, /* Reaction on BOD , */\ + { 0x150, "bod_enbl"}, /* Enable BOD (only in direct control mode) , */\ + { 0x160, "bod_hyst_enbl"}, /* Enable Hysteresis of BOD , */\ + { 0x171, "bod_delay_set"}, /* BOD filter , */\ + { 0x191, "bod_lvl_set"}, /* BOD threshold , */\ + { 0x1b0, "disable_mute_time_out"}, /* Time out SB mute sequence , */\ + { 0x1c0, "man_enbl_watchdog"}, /* Watchdog enable , */\ + { 0x1d0, "disable_engage"}, /* Disable Engage , */\ + { 0x1e0, "unprotect_faim"}, /* Control for FAIM protection , */\ + { 0x1f0, "faim_enable_vbg"}, /* Overrule the enabling of VBG for faim erase/write access, */\ + { 0x203, "audio_fs"}, /* Audio sample rate Fs , */\ + { 0x240, "input_level"}, /* TDM output attenuation , */\ + { 0x255, "cs_frac_delay"}, /* Current sense fractional delay , */\ + { 0x2b1, "use_tdm_presence"}, /* Control for HW manager , */\ + { 0x2d2, "ctrl_on2off_criterion"}, /* Amplifier on-off criteria for shutdown , */\ + { 0x30f, "device_rev"}, /* Revision info , */\ + { 0x401, "pll_clkin_sel"}, /* PLL external reference clock , */\ + { 0x420, "pll_clkin_sel_osc"}, /* PLL internal reference clock , */\ + { 0x432, "mclk_sel"}, /* Master Clock Selection , */\ + { 0x460, "enbl_osc1m_auto_off"}, /* Internal OSC1M off at PWDN , */\ + { 0x470, "disable_auto_sel_refclk"}, /* Automatic PLL reference clock selection for cold start, */\ + { 0x510, "enbl_spkr_ss"}, /* Enable speaker sub-system , */\ + { 0x520, "enbl_faim_ss"}, /* Enable FAIM sub-system , */\ + { 0x530, "enbl_wdt_clk"}, /* Enable Coolflux watchdog clock , */\ + { 0xe07, "ctrl_digtoana"}, /* Spare control from digital to analog , */\ + { 0xf0f, "hidden_code"}, /* Hidden code to enable access to hidden register. (0x5A6B/23147 default for engineering), */\ + { 0x1000, "flag_por"}, /* POR , */\ + { 0x1010, "flag_pll_lock"}, /* PLL Lock , */\ + { 0x1020, "flag_otpok"}, /* OTP alarm , */\ + { 0x1030, "flag_ovpok"}, /* OVP alarm , */\ + { 0x1040, "flag_uvpok"}, /* UVP alarm , */\ + { 0x1050, "flag_ocp_alarm"}, /* OCP amplifier (sticky register, clear on read) , */\ + { 0x1060, "flag_clocks_stable"}, /* Clocks stable , */\ + { 0x1070, "flag_mtp_busy"}, /* MTP busy , */\ + { 0x1080, "flag_lost_clk"}, /* Lost clock , */\ + { 0x1090, "flag_cold_started"}, /* Cold Start , */\ + { 0x10a0, "flag_watchdog_reset"}, /* Watchdog , */\ + { 0x10b0, "flag_engage"}, /* Amplifier engage , */\ + { 0x10c0, "flag_enbl_amp"}, /* Amplifier enable , */\ + { 0x10d0, "flag_enbl_ref"}, /* References enable , */\ + { 0x10e0, "flag_adc10_ready"}, /* Control ADC , */\ + { 0x10f0, "flag_bod_vddd_nok"}, /* BOD Flag - VDD NOT OK , */\ + { 0x1100, "flag_bst_bstcur"}, /* DCDC current limiting , */\ + { 0x1110, "flag_bst_hiz"}, /* DCDC active (sticky register, clear on read) , */\ + { 0x1120, "flag_bst_ocpok"}, /* DCDC OCP nmos (sticky register, clear on read) , */\ + { 0x1130, "flag_bst_peakcur"}, /* Indicates current is max in DC-to-DC converter , */\ + { 0x1140, "flag_bst_voutcomp"}, /* DCDC level 1x , */\ + { 0x1150, "flag_bst_voutcomp86"}, /* DCDC level 1.14x , */\ + { 0x1160, "flag_bst_voutcomp93"}, /* DCDC level 1.07x , */\ + { 0x1170, "flag_cf_speakererror"}, /* Speaker status , */\ + { 0x1180, "flag_clk_out_of_range"}, /* External clock status , */\ + { 0x1190, "flag_man_alarm_state"}, /* Alarm state , */\ + { 0x11a0, "flag_tdm_error"}, /* TDM error , */\ + { 0x11b0, "flag_tdm_lut_error"}, /* TDM lookup table error , */\ + { 0x1200, "flag_ocpokap"}, /* OCPOK pmos A , */\ + { 0x1210, "flag_ocpokan"}, /* OCPOK nmos A , */\ + { 0x1220, "flag_ocpokbp"}, /* OCPOK pmos B , */\ + { 0x1230, "flag_ocpokbn"}, /* OCPOK nmos B , */\ + { 0x1240, "flag_clip"}, /* Amplifier clipping , */\ + { 0x1250, "flag_man_start_mute_audio"}, /* Audio mute sequence , */\ + { 0x1260, "flag_man_operating_state"}, /* Device in Operating state , */\ + { 0x1270, "flag_lp_detect_mode1"}, /* Low power MODE1 detection , */\ + { 0x1280, "flag_low_amplitude"}, /* Low amplitude detection , */\ + { 0x1290, "flag_vddp_gt_vbat"}, /* VDDP greater than VBAT flag , */\ + { 0x1402, "tdm_status"}, /* TDM Status bits , */\ + { 0x1433, "man_state"}, /* Device Manager status , */\ + { 0x1473, "amp_ctrl_state"}, /* Amplifier control status , */\ + { 0x14b1, "status_bst_mode"}, /* DCDC mode status bits , */\ + { 0x1509, "bat_adc"}, /* Battery voltage (V) , */\ + { 0x1608, "temp_adc"}, /* IC Temperature (C) , */\ + { 0x1709, "vddp_adc"}, /* IC VDDP voltage (1023*VDDP/13V) , */\ + { 0x2000, "tdm_enable"}, /* Enable interface , */\ + { 0x2010, "tdm_sink0_enable"}, /* Control audio tdm channel in sink0 , */\ + { 0x2020, "tdm_sink1_enable"}, /* Control audio tdm channel in sink1 , */\ + { 0x2030, "tdm_source0_enable"}, /* Source 0 enable , */\ + { 0x2040, "tdm_source1_enable"}, /* Source 1 enable , */\ + { 0x2050, "tdm_source2_enable"}, /* Source 2 enable , */\ + { 0x2060, "tdm_source3_enable"}, /* Source 3 enable , */\ + { 0x2070, "tdm_clk_inversion"}, /* Reception data to BCK clock , */\ + { 0x2080, "tdm_fs_ws_polarity"}, /* FS polarity , */\ + { 0x2090, "tdm_data_delay"}, /* Data delay to FS , */\ + { 0x20a0, "tdm_data_adjustment"}, /* Data adjustment , */\ + { 0x20b1, "tdm_audio_sample_compression"}, /* Received audio compression , */\ + { 0x2103, "tdm_nbck"}, /* TDM NBCK - Bit clock to FS ratio , */\ + { 0x2143, "tdm_fs_ws_length"}, /* FS length (master mode only) , */\ + { 0x2183, "tdm_nb_of_slots"}, /* N-slots in Frame , */\ + { 0x21c1, "tdm_txdata_format"}, /* Format unused bits , */\ + { 0x21e1, "tdm_txdata_format_unused_slot"}, /* Format unused slots DATAO , */\ + { 0x2204, "tdm_slot_length"}, /* N-bits in slot , */\ + { 0x2254, "tdm_bits_remaining"}, /* N-bits remaining , */\ + { 0x22a4, "tdm_sample_size"}, /* Sample size per slot , */\ + { 0x2303, "tdm_sink0_slot"}, /* TDM slot for sink 0 , */\ + { 0x2343, "tdm_sink1_slot"}, /* TDM slot for sink 1 , */\ + { 0x2381, "tdm_source2_sel"}, /* TDM Source 2 data selection , */\ + { 0x23a1, "tdm_source3_sel"}, /* TDM Source 3 data selection , */\ + { 0x2403, "tdm_source0_slot"}, /* Slot Position of source 0 data , */\ + { 0x2443, "tdm_source1_slot"}, /* Slot Position of source 1 data , */\ + { 0x2483, "tdm_source2_slot"}, /* Slot Position of source 2 data , */\ + { 0x24c3, "tdm_source3_slot"}, /* Slot Position of source 3 data , */\ + { 0x4000, "int_out_flag_por"}, /* Status POR , */\ + { 0x4010, "int_out_flag_bst_ocpok"}, /* Status DCDC OCP , */\ + { 0x4020, "int_out_flag_otpok"}, /* Status OTP alarm , */\ + { 0x4030, "int_out_flag_ocp_alarm"}, /* Status OCP alarm , */\ + { 0x4040, "int_out_flag_uvpok"}, /* Status UVP alarm , */\ + { 0x4050, "int_out_flag_man_alarm_state"}, /* Status manager alarm state , */\ + { 0x4060, "int_out_flag_tdm_error"}, /* Status TDM error , */\ + { 0x4070, "int_out_flag_lost_clk"}, /* Status lost clock , */\ + { 0x4080, "int_out_flag_cfma_err"}, /* Status cfma error , */\ + { 0x4090, "int_out_flag_cfma_ack"}, /* Status cfma ack , */\ + { 0x40a0, "int_out_flag_cf_speakererror"}, /* Status coolflux speaker error , */\ + { 0x40b0, "int_out_flag_cold_started"}, /* Status cold started , */\ + { 0x40c0, "int_out_flag_watchdog_reset"}, /* Status watchdog reset , */\ + { 0x40d0, "int_out_flag_bod_vddd_nok"}, /* Status brown out detect , */\ + { 0x40e0, "int_out_flag_lp_detect_mode1"}, /* Status low power mode1 detect , */\ + { 0x40f0, "int_out_flag_clk_out_of_range"}, /* Status clock out of range , */\ + { 0x4400, "int_in_flag_por"}, /* Clear POR , */\ + { 0x4410, "int_in_flag_bst_ocpok"}, /* Clear DCDC OCP , */\ + { 0x4420, "int_in_flag_otpok"}, /* Clear OTP alarm , */\ + { 0x4430, "int_in_flag_ocp_alarm"}, /* Clear OCP alarm , */\ + { 0x4440, "int_in_flag_uvpok"}, /* Clear UVP alarm , */\ + { 0x4450, "int_in_flag_man_alarm_state"}, /* Clear manager alarm state , */\ + { 0x4460, "int_in_flag_tdm_error"}, /* Clear TDM error , */\ + { 0x4470, "int_in_flag_lost_clk"}, /* Clear lost clk , */\ + { 0x4480, "int_in_flag_cfma_err"}, /* Clear cfma err , */\ + { 0x4490, "int_in_flag_cfma_ack"}, /* Clear cfma ack , */\ + { 0x44a0, "int_in_flag_cf_speakererror"}, /* Clear coolflux speaker error , */\ + { 0x44b0, "int_in_flag_cold_started"}, /* Clear cold started , */\ + { 0x44c0, "int_in_flag_watchdog_reset"}, /* Clear watchdog reset , */\ + { 0x44d0, "int_in_flag_bod_vddd_nok"}, /* Clear brown out detect , */\ + { 0x44e0, "int_in_flag_lp_detect_mode1"}, /* Clear low power mode1 detect , */\ + { 0x44f0, "int_in_flag_clk_out_of_range"}, /* Clear clock out of range , */\ + { 0x4800, "int_enable_flag_por"}, /* Enable POR , */\ + { 0x4810, "int_enable_flag_bst_ocpok"}, /* Enable DCDC OCP , */\ + { 0x4820, "int_enable_flag_otpok"}, /* Enable OTP alarm , */\ + { 0x4830, "int_enable_flag_ocp_alarm"}, /* Enable OCP alarm , */\ + { 0x4840, "int_enable_flag_uvpok"}, /* Enable UVP alarm , */\ + { 0x4850, "int_enable_flag_man_alarm_state"}, /* Enable Manager Alarm state , */\ + { 0x4860, "int_enable_flag_tdm_error"}, /* Enable TDM error , */\ + { 0x4870, "int_enable_flag_lost_clk"}, /* Enable lost clk , */\ + { 0x4880, "int_enable_flag_cfma_err"}, /* Enable cfma err , */\ + { 0x4890, "int_enable_flag_cfma_ack"}, /* Enable cfma ack , */\ + { 0x48a0, "int_enable_flag_cf_speakererror"}, /* Enable coolflux speaker error , */\ + { 0x48b0, "int_enable_flag_cold_started"}, /* Enable cold started , */\ + { 0x48c0, "int_enable_flag_watchdog_reset"}, /* Enable watchdog reset , */\ + { 0x48d0, "int_enable_flag_bod_vddd_nok"}, /* Enable brown out detect , */\ + { 0x48e0, "int_enable_flag_lp_detect_mode1"}, /* Enable low power mode1 detect , */\ + { 0x48f0, "int_enable_flag_clk_out_of_range"}, /* Enable clock out of range , */\ + { 0x4c00, "int_polarity_flag_por"}, /* Polarity POR , */\ + { 0x4c10, "int_polarity_flag_bst_ocpok"}, /* Polarity DCDC OCP , */\ + { 0x4c20, "int_polarity_flag_otpok"}, /* Polarity OTP alarm , */\ + { 0x4c30, "int_polarity_flag_ocp_alarm"}, /* Polarity ocp alarm , */\ + { 0x4c40, "int_polarity_flag_uvpok"}, /* Polarity UVP alarm , */\ + { 0x4c50, "int_polarity_flag_man_alarm_state"}, /* Polarity manager alarm state , */\ + { 0x4c60, "int_polarity_flag_tdm_error"}, /* Polarity TDM error , */\ + { 0x4c70, "int_polarity_flag_lost_clk"}, /* Polarity lost clk , */\ + { 0x4c80, "int_polarity_flag_cfma_err"}, /* Polarity cfma err , */\ + { 0x4c90, "int_polarity_flag_cfma_ack"}, /* Polarity cfma ack , */\ + { 0x4ca0, "int_polarity_flag_cf_speakererror"}, /* Polarity coolflux speaker error , */\ + { 0x4cb0, "int_polarity_flag_cold_started"}, /* Polarity cold started , */\ + { 0x4cc0, "int_polarity_flag_watchdog_reset"}, /* Polarity watchdog reset , */\ + { 0x4cd0, "int_polarity_flag_bod_vddd_nok"}, /* Polarity brown out detect , */\ + { 0x4ce0, "int_polarity_flag_lp_detect_mode1"}, /* Polarity low power mode1 detect , */\ + { 0x4cf0, "int_polarity_flag_clk_out_of_range"}, /* Polarity clock out of range , */\ + { 0x5001, "vbat_prot_attack_time"}, /* Battery safeguard attack time , */\ + { 0x5023, "vbat_prot_thlevel"}, /* Battery safeguard threshold voltage level , */\ + { 0x5061, "vbat_prot_max_reduct"}, /* Battery safeguard maximum reduction , */\ + { 0x5082, "vbat_prot_release_time"}, /* Battery safeguard release time , */\ + { 0x50b1, "vbat_prot_hysterese"}, /* Battery Safeguard hysteresis , */\ + { 0x50d0, "rst_min_vbat"}, /* Reset clipper - auto clear , */\ + { 0x50e0, "sel_vbat"}, /* Battery voltage read out , */\ + { 0x50f0, "bypass_clipper"}, /* Bypass HW clipper , */\ + { 0x5130, "cf_mute"}, /* Coolflux firmware soft mute control , */\ + { 0x5187, "cf_volume"}, /* CF firmware volume control , */\ + { 0x5202, "ctrl_cc"}, /* Clip control setting , */\ + { 0x5230, "ctrl_slopectrl"}, /* Enables slope control , */\ + { 0x5240, "ctrl_slope"}, /* Slope speed setting (binary coded) , */\ + { 0x5287, "gain"}, /* Amplifier gain , */\ + { 0x5301, "dpsa_level"}, /* DPSA threshold levels , */\ + { 0x5321, "dpsa_release"}, /* DPSA Release time , */\ + { 0x5340, "clipfast"}, /* Clock selection for HW clipper for battery safeguard, */\ + { 0x5350, "bypass_lp"}, /* Bypass the low power filter inside temperature sensor, */\ + { 0x5360, "first_order_mode"}, /* Overrule to 1st order mode of control stage when clipping, */\ + { 0x5370, "icomp_engage"}, /* Engage of icomp , */\ + { 0x5380, "ctrl_kickback"}, /* Prevent double pulses of output stage , */\ + { 0x5390, "icomp_engage_overrule"}, /* To overrule the functional icomp_engage signal during validation, */\ + { 0x53a3, "ctrl_dem"}, /* Enable DEM icomp and DEM one bit dac , */\ + { 0x5400, "bypass_ctrlloop"}, /* Switch amplifier into open loop configuration , */\ + { 0x5413, "ctrl_dem_mismatch"}, /* Enable DEM icomp mismatch for testing , */\ + { 0x5452, "dpsa_drive"}, /* Drive setting (binary coded) , */\ + { 0x550a, "enbl_amp"}, /* Switch on the class-D power sections, each part of the analog sections can be switched on/off individually, */\ + { 0x55b0, "enbl_engage"}, /* Enables/engage power stage and control loop , */\ + { 0x55c0, "enbl_engage_pst"}, /* Enables/engage power stage and control loop , */\ + { 0x5600, "pwm_shape"}, /* PWM shape , */\ + { 0x5614, "pwm_delay"}, /* PWM delay bits to set the delay, clockd is 1/(k*2048*fs), */\ + { 0x5660, "reclock_pwm"}, /* Reclock the PWM signal inside analog , */\ + { 0x5670, "reclock_voltsense"}, /* Reclock the voltage sense PWM signal , */\ + { 0x5680, "enbl_pwm_phase_shift"}, /* Control for PWM phase shift , */\ + { 0x5690, "sel_pwm_delay_src"}, /* Control for selection for PWM delay line source , */\ + { 0x56a1, "enbl_odd_up_even_down"}, /* Control for PWM reference sawtooth generartion , */\ + { 0x5703, "ctrl_att_dcdc"}, /* Second channel gain in case of stereo using a single coil. (Total gain depending on INPLEV). (In case of mono OR stereo using 2 separate DCDC channel 1 should be disabled using TDMDCE), */\ + { 0x5743, "ctrl_att_spkr"}, /* Total gain depending on INPLEV setting (channel 0), */\ + { 0x5781, "vamp_sel2"}, /* VAMP_OUT2 input selection , */\ + { 0x5805, "zero_lvl"}, /* Low noise gain switch zero trigger level , */\ + { 0x5861, "ctrl_fb_resistor"}, /* Select amplifier feedback resistor connection , */\ + { 0x5881, "lownoisegain_mode"}, /* Low noise gain mode control , */\ + { 0x5905, "threshold_lvl"}, /* Low noise gain switch trigger level , */\ + { 0x5965, "hold_time"}, /* Low noise mode hold time before entering into low noise mode, */\ + { 0x5a05, "lpm1_cal_offset"}, /* Low power mode1 detector ctrl cal_offset from gain module , */\ + { 0x5a65, "lpm1_zero_lvl"}, /* Low power mode1 zero crossing detection level , */\ + { 0x5ac1, "lpm1_mode"}, /* Low power mode control , */\ + { 0x5b05, "lpm1_threshold_lvl"}, /* Low power mode1 amplitude trigger level , */\ + { 0x5b65, "lpm1_hold_time"}, /* Low power mode hold time before entering into low power mode, */\ + { 0x5bc0, "disable_low_power_mode"}, /* Low power mode1 detector control , */\ + { 0x5c00, "enbl_minion"}, /* Enables minion (small) power stage , */\ + { 0x5c13, "vth_vddpvbat"}, /* Select vddp-vbat threshold signal , */\ + { 0x5c50, "lpen_vddpvbat"}, /* Select vddp-vbat filtred vs unfiltered compare , */\ + { 0x5c61, "ctrl_rfb"}, /* Feedback resistor selection - I2C direct mode , */\ + { 0x5d02, "tdm_source_mapping"}, /* TDM source mapping , */\ + { 0x5d31, "tdm_sourcea_frame_sel"}, /* Sensed value A , */\ + { 0x5d51, "tdm_sourceb_frame_sel"}, /* Sensed value B , */\ + { 0x5d71, "tdm_source0_clip_sel"}, /* Clip information (analog /digital) for source0 , */\ + { 0x5d91, "tdm_source1_clip_sel"}, /* Clip information (analog /digital) for source1 , */\ + { 0x5e02, "rst_min_vbat_delay"}, /* Delay for reseting the min_vbat value inside HW Clipper (number of Fs pulses), */\ + { 0x5e30, "rst_min_vbat_sel"}, /* Control for selecting reset signal for min_bat , */\ + { 0x5f00, "hard_mute"}, /* Hard mute - PWM , */\ + { 0x5f12, "ns_hp2ln_criterion"}, /* 0..7 zeroes at ns as threshold to swap from high_power to low_noise, */\ + { 0x5f42, "ns_ln2hp_criterion"}, /* 0..7 zeroes at ns as threshold to swap from low_noise to high_power, */\ + { 0x5f78, "spare_out"}, /* Spare out register , */\ + { 0x600f, "spare_in"}, /* Spare IN , */\ + { 0x6102, "cursense_comp_delay"}, /* Delay to allign compensation signal with current sense signal, */\ + { 0x6130, "cursense_comp_sign"}, /* Polarity of compensation for current sense , */\ + { 0x6140, "enbl_cursense_comp"}, /* Enable current sense compensation , */\ + { 0x6152, "pwms_clip_lvl"}, /* Set the amount of pwm pulse that may be skipped before clip-flag is triggered, */\ + { 0x7005, "frst_boost_voltage"}, /* First Boost Voltage Level , */\ + { 0x7065, "scnd_boost_voltage"}, /* Second Boost Voltage Level , */\ + { 0x70c3, "boost_cur"}, /* Max Coil Current , */\ + { 0x7101, "bst_slpcmplvl"}, /* Slope compensation current, represents LxF (inductance x frequency) value , */\ + { 0x7120, "boost_intel"}, /* Adaptive boost mode , */\ + { 0x7130, "boost_speed"}, /* Soft ramp up/down , */\ + { 0x7140, "dcdcoff_mode"}, /* DCDC on/off , */\ + { 0x7150, "dcdc_pwmonly"}, /* DCDC PWM only mode , */\ + { 0x7160, "boost_track"}, /* Boost algorithm selection, effective only when boost_intelligent is set to 1, */\ + { 0x7170, "sel_dcdc_envelope_8fs"}, /* Selection of data for adaptive boost algorithm, effective only when boost_intelligent is set to 1, */\ + { 0x7180, "ignore_flag_voutcomp86"}, /* Determines the maximum PWM frequency be the most efficient in relation to the Booster inductor value, */\ + { 0x7204, "boost_trip_lvl_1st"}, /* 1st adaptive boost trip levels, effective only when DCIE is set to 1, */\ + { 0x7254, "boost_trip_lvl_2nd"}, /* 2nd adaptive boost trip levels, effective only when DCIE is set to 1, */\ + { 0x72a4, "boost_trip_lvl_track"}, /* Track adaptive boost trip levels, effective only when boost_intelligent is set to 1, */\ + { 0x72f0, "enbl_trip_hyst"}, /* Enable hysteresis on booster trip levels , */\ + { 0x7304, "boost_hold_time"}, /* Hold time for DCDC booster, effective only when boost_intelligent is set to 1, */\ + { 0x7350, "dcdc_pfm20khz_limit"}, /* DCDC in PFM mode pwm mode is activated each 50us to force a pwm pulse, */\ + { 0x7361, "dcdc_ctrl_maxzercnt"}, /* Number of zero current flags to count before going to pfm mode, */\ + { 0x7386, "dcdc_vbat_delta_detect"}, /* Threshold before booster is reacting on a delta Vbat (in PFM mode) by temporarily switching to PWM mode, */\ + { 0x73f0, "dcdc_ignore_vbat"}, /* Ignore an increase on Vbat , */\ + { 0x7404, "bst_drive"}, /* Binary coded drive setting for boost converter power stage, */\ + { 0x7451, "bst_scalecur"}, /* For testing direct control scale current , */\ + { 0x7474, "bst_slopecur"}, /* For testing direct control slope current , */\ + { 0x74c1, "bst_slope"}, /* Boost slope speed , */\ + { 0x74e0, "bst_bypass_bstcur"}, /* Bypass control for boost current settings , */\ + { 0x74f0, "bst_bypass_bstfoldback"}, /* Bypass control for boost foldback , */\ + { 0x7500, "enbl_bst_engage"}, /* Enable power stage dcdc controller , */\ + { 0x7510, "enbl_bst_hizcom"}, /* Enable hiz comparator , */\ + { 0x7520, "enbl_bst_peakcur"}, /* Enable peak current , */\ + { 0x7530, "enbl_bst_power"}, /* Enable line of the powerstage , */\ + { 0x7540, "enbl_bst_slopecur"}, /* Enable bit of max-current dac , */\ + { 0x7550, "enbl_bst_voutcomp"}, /* Enable vout comparators , */\ + { 0x7560, "enbl_bst_voutcomp86"}, /* Enable vout-86 comparators , */\ + { 0x7570, "enbl_bst_voutcomp93"}, /* Enable vout-93 comparators , */\ + { 0x7580, "enbl_bst_windac"}, /* Enable window dac , */\ + { 0x7595, "bst_windac"}, /* For testing direct control windac , */\ + { 0x7600, "boost_alg"}, /* Control for boost adaptive loop gain , */\ + { 0x7611, "boost_loopgain"}, /* DCDC boost loopgain setting , */\ + { 0x7631, "bst_freq"}, /* DCDC boost frequency control , */\ + { 0x7650, "enbl_bst_peak2avg"}, /* Enable boost peak2avg functionality , */\ + { 0x7660, "bst_use_new_zercur_detect"}, /* Enable new zero current detection for boost control, */\ + { 0x8001, "sel_clk_cs"}, /* Current sense clock duty cycle control , */\ + { 0x8021, "micadc_speed"}, /* Current sense clock for MiCADC selection - 32/44.1/48 KHz Fs band only, */\ + { 0x8040, "cs_gain_control"}, /* Current sense gain control , */\ + { 0x8050, "cs_bypass_gc"}, /* Bypasses the CS gain correction , */\ + { 0x8060, "invertpwm"}, /* Current sense common mode feedback pwm invert control, */\ + { 0x8087, "cs_gain"}, /* Current sense gain , */\ + { 0x8105, "cs_ktemp"}, /* Current sense temperature compensation trimming (1 - VALUE*TEMP) * signal, */\ + { 0x8164, "cs_ktemp2"}, /* Second order temperature compensation coefficient , */\ + { 0x81b0, "enbl_cs_adc"}, /* Enable current sense ADC , */\ + { 0x81c0, "enbl_cs_inn1"}, /* Enable connection of current sense negative1 , */\ + { 0x81d0, "enbl_cs_inn2"}, /* Enable connection of current sense negative2 , */\ + { 0x81e0, "enbl_cs_inp1"}, /* Enable connection of current sense positive1 , */\ + { 0x81f0, "enbl_cs_inp2"}, /* Enable connection of current sense positive2 , */\ + { 0x8200, "enbl_cs_ldo"}, /* Enable current sense LDO , */\ + { 0x8210, "enbl_cs_vbatldo"}, /* Enable of current sense LDO , */\ + { 0x8220, "cs_adc_bsoinv"}, /* Bitstream inversion for current sense ADC , */\ + { 0x8231, "cs_adc_hifreq"}, /* Frequency mode current sense ADC , */\ + { 0x8250, "cs_adc_nortz"}, /* Return to zero for current sense ADC , */\ + { 0x8263, "cs_adc_offset"}, /* Micadc ADC offset setting , */\ + { 0x82a0, "cs_adc_slowdel"}, /* Select delay for current sense ADC (internal decision circuitry), */\ + { 0x82b4, "cs_adc_gain"}, /* Gain setting for current sense ADC (two's complement), */\ + { 0x8300, "cs_resonator_enable"}, /* Enable for resonator to improve SRN , */\ + { 0x8310, "cs_classd_tran_skip"}, /* Skip current sense connection during a classD amplifier transition, */\ + { 0x8320, "cs_inn_short"}, /* Short current sense negative to common mode , */\ + { 0x8330, "cs_inp_short"}, /* Short current sense positive to common mode , */\ + { 0x8340, "cs_ldo_bypass"}, /* Bypass current sense LDO , */\ + { 0x8350, "cs_ldo_pulldown"}, /* Pull down current sense LDO, only valid if enbl_cs_ldo is high, */\ + { 0x8364, "cs_ldo_voset"}, /* Current sense LDO voltage level setting (two's complement), */\ + { 0x8800, "ctrl_vs_igen_supply"}, /* Control for selecting supply for VS current generator, */\ + { 0x8810, "ctrl_vs_force_div2"}, /* Select input resistive divider gain , */\ + { 0x8820, "enbl_dc_filter"}, /* Control for enabling the DC blocking filter for voltage and current sense, */\ + { 0x8901, "volsense_pwm_sel"}, /* Voltage sense source selection control , */\ + { 0x8920, "vs_gain_control"}, /* Voltage sense gain control , */\ + { 0x8930, "vs_bypass_gc"}, /* Bypasses the VS gain correction , */\ + { 0x8940, "vs_adc_bsoinv"}, /* Bitstream inversion for voltage sense ADC , */\ + { 0x8950, "vs_adc_nortz"}, /* Return to zero for voltage sense ADC , */\ + { 0x8960, "vs_adc_slowdel"}, /* Select delay for voltage sense ADC (internal decision circuitry), */\ + { 0x8970, "vs_classd_tran_skip"}, /* Skip voltage sense connection during a classD amplifier transition, */\ + { 0x8987, "vs_gain"}, /* Voltage sense gain , */\ + { 0x8a00, "vs_inn_short"}, /* Short voltage sense negative to common mode , */\ + { 0x8a10, "vs_inp_short"}, /* Short voltage sense positive to common mode , */\ + { 0x8a20, "vs_ldo_bypass"}, /* Bypass voltage sense LDO , */\ + { 0x8a30, "vs_ldo_pulldown"}, /* Pull down voltage sense LDO, only valid if enbl_cs_ldo is high, */\ + { 0x8a44, "vs_ldo_voset"}, /* Voltage sense LDO voltage level setting (two's complement), */\ + { 0x8a90, "enbl_vs_adc"}, /* Enable voltage sense ADC , */\ + { 0x8aa0, "enbl_vs_inn1"}, /* Enable connection of voltage sense negative1 , */\ + { 0x8ab0, "enbl_vs_inn2"}, /* Enable connection of voltage sense negative2 , */\ + { 0x8ac0, "enbl_vs_inp1"}, /* Enable connection of voltage sense positive1 , */\ + { 0x8ad0, "enbl_vs_inp2"}, /* Enable connection of voltage sense positive2 , */\ + { 0x8ae0, "enbl_vs_ldo"}, /* Enable voltage sense LDO , */\ + { 0x8af0, "enbl_vs_vbatldo"}, /* Enable of voltage sense LDO , */\ + { 0x9000, "cf_rst_dsp"}, /* Reset for Coolflux DSP , */\ + { 0x9011, "cf_dmem"}, /* Target memory for CFMA using I2C interface , */\ + { 0x9030, "cf_aif"}, /* Auto increment , */\ + { 0x9040, "cf_int"}, /* Coolflux Interrupt - auto clear , */\ + { 0x9050, "cf_cgate_off"}, /* Coolflux clock gating disabling control , */\ + { 0x9080, "cf_req_cmd"}, /* Firmware event request rpc command , */\ + { 0x9090, "cf_req_reset"}, /* Firmware event request reset restart , */\ + { 0x90a0, "cf_req_mips"}, /* Firmware event request short on mips , */\ + { 0x90b0, "cf_req_mute_ready"}, /* Firmware event request mute sequence ready , */\ + { 0x90c0, "cf_req_volume_ready"}, /* Firmware event request volume ready , */\ + { 0x90d0, "cf_req_damage"}, /* Firmware event request speaker damage detected , */\ + { 0x90e0, "cf_req_calibrate_ready"}, /* Firmware event request calibration completed , */\ + { 0x90f0, "cf_req_reserved"}, /* Firmware event request reserved , */\ + { 0x910f, "cf_madd"}, /* CF memory address , */\ + { 0x920f, "cf_mema"}, /* Activate memory access , */\ + { 0x9307, "cf_err"}, /* CF error flags , */\ + { 0x9380, "cf_ack_cmd"}, /* Firmware event acknowledge rpc command , */\ + { 0x9390, "cf_ack_reset"}, /* Firmware event acknowledge reset restart , */\ + { 0x93a0, "cf_ack_mips"}, /* Firmware event acknowledge short on mips , */\ + { 0x93b0, "cf_ack_mute_ready"}, /* Firmware event acknowledge mute sequence ready , */\ + { 0x93c0, "cf_ack_volume_ready"}, /* Firmware event acknowledge volume ready , */\ + { 0x93d0, "cf_ack_damage"}, /* Firmware event acknowledge speaker damage detected, */\ + { 0x93e0, "cf_ack_calibrate_ready"}, /* Firmware event acknowledge calibration completed , */\ + { 0x93f0, "cf_ack_reserved"}, /* Firmware event acknowledge reserved , */\ + { 0xa007, "mtpkey1"}, /* KEY1 To access KEY1 protected registers 0x5A/90d (default for engineering), */\ + { 0xa107, "mtpkey2"}, /* KEY2 to access KEY2 protected registers, customer key, */\ + { 0xa200, "key01_locked"}, /* Indicates KEY1 is locked , */\ + { 0xa210, "key02_locked"}, /* Indicates KEY2 is locked , */\ + { 0xa302, "mtp_man_address_in"}, /* MTP address from I2C register for read/writing mtp in manual single word mode, */\ + { 0xa330, "man_copy_mtp_to_iic"}, /* Start copying single word from MTP to I2C mtp register - auto clear, */\ + { 0xa340, "man_copy_iic_to_mtp"}, /* Start copying single word from I2C mtp register to mtp - auto clear, */\ + { 0xa350, "auto_copy_mtp_to_iic"}, /* Start copying all the data from mtp to I2C mtp registers - auto clear, */\ + { 0xa360, "auto_copy_iic_to_mtp"}, /* Start copying data from I2C mtp registers to mtp - auto clear, */\ + { 0xa400, "faim_set_clkws"}, /* Sets the FaIM controller clock wait state register, */\ + { 0xa410, "faim_sel_evenrows"}, /* All even rows of the FaIM are selected, active high, */\ + { 0xa420, "faim_sel_oddrows"}, /* All odd rows of the FaIM are selected, all rows in combination with sel_evenrows, */\ + { 0xa430, "faim_program_only"}, /* Skip the erase access at wr_faim command (write-program-marginread), */\ + { 0xa440, "faim_erase_only"}, /* Skip the program access at wr_faim command (write-erase-marginread), */\ + { 0xa50f, "mtp_man_data_out_msb"}, /* MSB word of MTP manual read data , */\ + { 0xa60f, "mtp_man_data_out_lsb"}, /* LSB word of MTP manual read data , */\ + { 0xa70f, "mtp_man_data_in_msb"}, /* MSB word of write data for MTP manual write , */\ + { 0xa80f, "mtp_man_data_in_lsb"}, /* LSB word of write data for MTP manual write , */\ + { 0xb000, "bypass_ocpcounter"}, /* Bypass OCP Counter , */\ + { 0xb010, "bypass_glitchfilter"}, /* Bypass glitch filter , */\ + { 0xb020, "bypass_ovp"}, /* Bypass OVP , */\ + { 0xb030, "bypass_uvp"}, /* Bypass UVP , */\ + { 0xb040, "bypass_otp"}, /* Bypass OTP , */\ + { 0xb050, "bypass_lost_clk"}, /* Bypass lost clock detector , */\ + { 0xb060, "ctrl_vpalarm"}, /* vpalarm (uvp ovp handling) , */\ + { 0xb070, "disable_main_ctrl_change_prot"}, /* Disable main control change protection , */\ + { 0xb087, "ocp_threshold"}, /* OCP threshold level , */\ + { 0xb108, "ext_temp"}, /* External temperature (C) , */\ + { 0xb190, "ext_temp_sel"}, /* Select temp Speaker calibration , */\ + { 0xc000, "use_direct_ctrls"}, /* Direct control to overrule several functions for testing, */\ + { 0xc010, "rst_datapath"}, /* Direct control for datapath reset , */\ + { 0xc020, "rst_cgu"}, /* Direct control for cgu reset , */\ + { 0xc038, "enbl_ref"}, /* Switch on the analog references, each part of the references can be switched on/off individually, */\ + { 0xc0c0, "use_direct_vs_ctrls"}, /* Voltage sense direct control to overrule several functions for testing, */\ + { 0xc0d0, "enbl_ringo"}, /* Enable the ring oscillator for test purpose , */\ + { 0xc0e0, "use_direct_clk_ctrl"}, /* Direct clock control to overrule several functions for testing, */\ + { 0xc0f0, "use_direct_pll_ctrl"}, /* Direct PLL control to overrule several functions for testing, */\ + { 0xc100, "enbl_tsense"}, /* Temperature sensor enable control - I2C direct mode, */\ + { 0xc110, "tsense_hibias"}, /* Bit to set the biasing in temp sensor to high , */\ + { 0xc120, "enbl_flag_vbg"}, /* Enable flagging of bandgap out of control , */\ + { 0xc20f, "abist_offset"}, /* Offset control for ABIST testing (two's complement), */\ + { 0xc300, "bypasslatch"}, /* Bypass latch , */\ + { 0xc311, "sourcea"}, /* Set OUTA to , */\ + { 0xc331, "sourceb"}, /* Set OUTB to , */\ + { 0xc350, "inverta"}, /* Invert pwma test signal , */\ + { 0xc360, "invertb"}, /* Invert pwmb test signal , */\ + { 0xc374, "pulselength"}, /* Pulse length setting test input for amplifier (clock d - k*2048*fs), */\ + { 0xc3d0, "test_abistfft_enbl"}, /* Enable ABIST with FFT on Coolflux DSP , */\ + { 0xc400, "bst_bypasslatch"}, /* Bypass latch in boost converter , */\ + { 0xc411, "bst_source"}, /* Sets the source of the pwmbst output to boost converter input for testing, */\ + { 0xc430, "bst_invertb"}, /* Invert pwmbst test signal , */\ + { 0xc444, "bst_pulselength"}, /* Pulse length setting test input for boost converter , */\ + { 0xc490, "test_bst_ctrlsthv"}, /* Test mode for boost control stage , */\ + { 0xc4a0, "test_bst_iddq"}, /* IDDQ testing in power stage of boost converter , */\ + { 0xc4b0, "test_bst_rdson"}, /* RDSON testing - boost power stage , */\ + { 0xc4c0, "test_bst_cvi"}, /* CVI testing - boost power stage , */\ + { 0xc4d0, "test_bst_ocp"}, /* Boost OCP. For old ocp (ctrl_reversebst is 0), For new ocp (ctrl_reversebst is 1), */\ + { 0xc4e0, "test_bst_sense"}, /* Test option for the sense NMOS in booster for current mode control., */\ + { 0xc500, "test_cvi"}, /* Analog BIST, switch choose which transistor will be used as current source (also cross coupled sources possible), */\ + { 0xc510, "test_discrete"}, /* Test function noise measurement , */\ + { 0xc520, "test_iddq"}, /* Set the power stages in iddq mode for gate stress., */\ + { 0xc530, "test_rdson"}, /* Analog BIST, switch to enable Rdson measurement , */\ + { 0xc540, "test_sdelta"}, /* Analog BIST, noise test , */\ + { 0xc550, "test_enbl_cs"}, /* Enable for digimux mode of current sense , */\ + { 0xc560, "test_enbl_vs"}, /* Enable for digimux mode of voltage sense , */\ + { 0xc570, "enbl_pwm_dcc"}, /* Enables direct control of pwm duty cycle for DCDC power stage, */\ + { 0xc583, "pwm_dcc_cnt"}, /* Control pwm duty cycle when enbl_pwm_dcc is 1 , */\ + { 0xc5c0, "enbl_ldo_stress"}, /* Enable stress of internal supply voltages powerstages, */\ + { 0xc607, "digimuxa_sel"}, /* DigimuxA input selection control routed to DATAO , */\ + { 0xc687, "digimuxb_sel"}, /* DigimuxB input selection control routed to INT , */\ + { 0xc707, "digimuxc_sel"}, /* DigimuxC input selection control routed to ADS1 , */\ + { 0xc800, "enbl_anamux1"}, /* Enable anamux1 , */\ + { 0xc810, "enbl_anamux2"}, /* Enable anamux2 , */\ + { 0xc820, "enbl_anamux3"}, /* Enable anamux3 , */\ + { 0xc830, "enbl_anamux4"}, /* Enable anamux4 , */\ + { 0xc844, "anamux1"}, /* Anamux selection control - anamux on TEST1 , */\ + { 0xc894, "anamux2"}, /* Anamux selection control - anamux on TEST2 , */\ + { 0xc903, "anamux3"}, /* Anamux selection control - anamux on TEST3 , */\ + { 0xc943, "anamux4"}, /* Anamux selection control - anamux on TEST4 , */\ + { 0xca05, "pll_seli"}, /* PLL SELI - I2C direct PLL control mode only , */\ + { 0xca64, "pll_selp"}, /* PLL SELP - I2C direct PLL control mode only , */\ + { 0xcab3, "pll_selr"}, /* PLL SELR - I2C direct PLL control mode only , */\ + { 0xcaf0, "pll_frm"}, /* PLL free running mode control; 1 in TCB direct control mode, else this control bit, */\ + { 0xcb09, "pll_ndec"}, /* PLL NDEC - I2C direct PLL control mode only , */\ + { 0xcba0, "pll_mdec_msb"}, /* MSB of PLL_mdec - I2C direct PLL control mode only, */\ + { 0xcbb0, "enbl_pll"}, /* Enables PLL in I2C direct PLL control mode only , */\ + { 0xcbc0, "enbl_osc"}, /* Enables OSC1M in I2C direct control mode only , */\ + { 0xcbd0, "pll_bypass"}, /* PLL bypass control in I2C direct PLL control mode only, */\ + { 0xcbe0, "pll_directi"}, /* PLL directi control in I2C direct PLL control mode only, */\ + { 0xcbf0, "pll_directo"}, /* PLL directo control in I2C direct PLL control mode only, */\ + { 0xcc0f, "pll_mdec_lsb"}, /* Bits 15..0 of PLL MDEC are I2C direct PLL control mode only, */\ + { 0xcd06, "pll_pdec"}, /* PLL PDEC - I2C direct PLL control mode only , */\ + { 0xce0f, "tsig_freq_lsb"}, /* Internal sinus test generator frequency control , */\ + { 0xcf02, "tsig_freq_msb"}, /* Select internal sinus test generator, frequency control msb bits, */\ + { 0xcf33, "tsig_gain"}, /* Test signal gain , */\ + { 0xd000, "adc10_reset"}, /* Reset for ADC10 - I2C direct control mode , */\ + { 0xd011, "adc10_test"}, /* Test mode selection signal for ADC10 - I2C direct control mode, */\ + { 0xd032, "adc10_sel"}, /* Select the input to convert for ADC10 - I2C direct control mode, */\ + { 0xd064, "adc10_prog_sample"}, /* ADC10 program sample setting - I2C direct control mode, */\ + { 0xd0b0, "adc10_enbl"}, /* Enable ADC10 - I2C direct control mode , */\ + { 0xd0c0, "bypass_lp_vbat"}, /* Bypass control for Low pass filter in batt sensor , */\ + { 0xd109, "data_adc10_tempbat"}, /* ADC 10 data output data for testing , */\ + { 0xd201, "clkdiv_audio_sel"}, /* Audio clock divider selection in direct clock control mode, */\ + { 0xd221, "clkdiv_muxa_sel"}, /* DCDC MUXA clock divider selection in direct clock control mode, */\ + { 0xd241, "clkdiv_muxb_sel"}, /* DCDC MUXB clock divider selection in direct clock control mode, */\ + { 0xd301, "int_ehs"}, /* Speed/load setting for INT IO cell, clk or data mode range (see SLIMMF IO datasheet), */\ + { 0xd321, "datao_ehs"}, /* Speed/load setting for DATAO IO cell, clk or data mode range (see SLIMMF IO datasheet), */\ + { 0xd340, "hs_mode"}, /* I2C high speed mode control , */\ + { 0xd407, "ctrl_digtoana_hidden"}, /* Spare digital to analog control bits - Hidden , */\ + { 0xd480, "enbl_clk_out_of_range"}, /* Clock out of range , */\ + { 0xd491, "sel_wdt_clk"}, /* Watch dog clock divider settings , */\ + { 0xd4b0, "inject_tsig"}, /* Control bit to switch to internal sinus test generator, */\ + { 0xd500, "source_in_testmode"}, /* TDM source in test mode (return only current and voltage sense), */\ + { 0xd510, "gainatt_feedback"}, /* Gainatt feedback to tdm , */\ + { 0xd522, "test_parametric_io"}, /* Test IO parametric , */\ + { 0xd550, "ctrl_bst_clk_lp1"}, /* Boost clock control in low power mode1 , */\ + { 0xd561, "test_spare_out1"}, /* Test spare out 1 , */\ + { 0xd580, "bst_dcmbst"}, /* DCM boost , */\ + { 0xd593, "test_spare_out2"}, /* Test spare out 2 , */\ + { 0xe00f, "sw_profile"}, /* Software profile data , */\ + { 0xe10f, "sw_vstep"}, /* Software vstep information , */\ + { 0xf000, "calibration_onetime"}, /* Calibration schedule , */\ + { 0xf010, "calibr_ron_done"}, /* Calibration Ron executed , */\ + { 0xf020, "calibr_dcdc_api_calibrate"}, /* Calibration current limit DCDC , */\ + { 0xf030, "calibr_dcdc_delta_sign"}, /* Sign bit for delta calibration current limit DCDC , */\ + { 0xf042, "calibr_dcdc_delta"}, /* Calibration delta current limit DCDC , */\ + { 0xf078, "calibr_speaker_info"}, /* Reserved space for allowing customer to store speaker information, */\ + { 0xf105, "calibr_vout_offset"}, /* DCDC offset calibration 2's complement (key1 protected), */\ + { 0xf163, "calibr_vbg_trim"}, /* Bandgap trimming control , */\ + { 0xf203, "calibr_gain"}, /* HW gain module (2's complement) , */\ + { 0xf245, "calibr_offset"}, /* Offset for amplifier, HW gain module (2's complement), */\ + { 0xf307, "calibr_gain_vs"}, /* Voltage sense gain , */\ + { 0xf387, "calibr_gain_cs"}, /* Current sense gain (signed two's complement format), */\ + { 0xf40f, "mtpdata4"}, /* MTP4 data , */\ + { 0xf50f, "calibr_R25C"}, /* Ron resistance of speaker coil , */\ + { 0xf60f, "mtpdata6"}, /* MTP6 data , */\ + { 0xf706, "ctrl_offset_a"}, /* Offset of level shifter A , */\ + { 0xf786, "ctrl_offset_b"}, /* Offset of amplifier level shifter B , */\ + { 0xf806, "htol_iic_addr"}, /* 7-bit I2C address to be used during HTOL testing , */\ + { 0xf870, "htol_iic_addr_en"}, /* HTOL I2C address enable control , */\ + { 0xf884, "calibr_temp_offset"}, /* Temperature offset 2's compliment (key1 protected), */\ + { 0xf8d2, "calibr_temp_gain"}, /* Temperature gain 2's compliment (key1 protected) , */\ + { 0xf900, "mtp_lock_dcdcoff_mode"}, /* Disable functionality of dcdcoff_mode bit , */\ + { 0xf910, "mtp_lock_enbl_coolflux"}, /* Disable functionality of enbl_coolflux bit , */\ + { 0xf920, "mtp_lock_bypass_clipper"}, /* Disable function bypass_clipper , */\ + { 0xf930, "mtp_enbl_pwm_delay_clock_gating"}, /* PWM delay clock auto gating , */\ + { 0xf940, "mtp_enbl_ocp_clock_gating"}, /* OCP clock auto gating , */\ + { 0xf950, "mtp_gate_cgu_clock_for_test"}, /* CGU test clock control , */\ + { 0xf987, "type_bits_fw"}, /* MTP control for firmware features - See Firmware I2C API document for details, */\ + { 0xfa0f, "mtpdataA"}, /* MTPdataA , */\ + { 0xfb0f, "mtpdataB"}, /* MTPdataB , */\ + { 0xfc0f, "mtpdataC"}, /* MTPdataC , */\ + { 0xfd0f, "mtpdataD"}, /* MTPdataD , */\ + { 0xfe0f, "mtpdataE"}, /* MTPdataE , */\ + { 0xff07, "calibr_osc_delta_ndiv"}, /* Calibration data for OSC1M, signed number representation, */\ + { 0xffff,"Unknown bitfield enum" } /* not found */\ +}; + +enum tfa9894_irq { + tfa9894_irq_max = -1, + tfa9894_irq_all = -1 /* all irqs */}; + +#define TFA9894_IRQ_NAMETABLE static tfaIrqName_t Tfa9894IrqNames[]= {\ +}; +#endif /* _TFA9894_TFAFIELDNAMES_H */ diff --git a/techpack/audio/asoc/codecs/tfa9874/tfa9896_tfafieldnames.h b/techpack/audio/asoc/codecs/tfa9874/tfa9896_tfafieldnames.h new file mode 100644 index 000000000000..9c2b15f02d42 --- /dev/null +++ b/techpack/audio/asoc/codecs/tfa9874/tfa9896_tfafieldnames.h @@ -0,0 +1,919 @@ +/** Filename: tfa9896_tfafieldnames.h + * This file was generated automatically on 08/15/16 at 09:43:38. + * Source file: TFA9896_N1B1_I2C_regmap_V16.xlsx + */ + +#ifndef _TFA9896_TFAFIELDNAMES_H +#define _TFA9896_TFAFIELDNAMES_H + + +#define TFA9896_I2CVERSION 16 + +typedef enum nxpTFA9896BfEnumList { + TFA9896_BF_VDDS = 0x0000, /*!< Power-on-reset flag (auto clear by reading) */ + TFA9896_BF_PLLS = 0x0010, /*!< PLL lock to programmed frequency */ + TFA9896_BF_OTDS = 0x0020, /*!< Over Temperature Protection alarm */ + TFA9896_BF_OVDS = 0x0030, /*!< Over Voltage Protection alarm */ + TFA9896_BF_UVDS = 0x0040, /*!< Under Voltage Protection alarm */ + TFA9896_BF_OCDS = 0x0050, /*!< Over Current Protection alarm */ + TFA9896_BF_CLKS = 0x0060, /*!< Clocks stable flag */ + TFA9896_BF_CLIPS = 0x0070, /*!< Amplifier clipping */ + TFA9896_BF_MTPB = 0x0080, /*!< MTP busy copying data to/from I2C registers */ + TFA9896_BF_NOCLK = 0x0090, /*!< lost clock detection (reference input clock) */ + TFA9896_BF_SPKS = 0x00a0, /*!< Speaker error */ + TFA9896_BF_ACS = 0x00b0, /*!< Cold Start required */ + TFA9896_BF_SWS = 0x00c0, /*!< Amplifier engage (Amp Switching) */ + TFA9896_BF_WDS = 0x00d0, /*!< watchdog reset (activates reset) */ + TFA9896_BF_AMPS = 0x00e0, /*!< Amplifier is enabled by manager */ + TFA9896_BF_AREFS = 0x00f0, /*!< References are enabled by manager */ + TFA9896_BF_BATS = 0x0109, /*!< Battery voltage from ADC readout */ + TFA9896_BF_TEMPS = 0x0208, /*!< Temperature readout from the temperature sensor ( C) */ + TFA9896_BF_REV = 0x030f, /*!< Device revision information */ + TFA9896_BF_RCV = 0x0420, /*!< Enable receiver mode */ + TFA9896_BF_CHS12 = 0x0431, /*!< Channel Selection TDM input for Coolflux */ + TFA9896_BF_INPLVL= 0x0450, /*!< Input level selection attenuator ( */ + TFA9896_BF_CHSA = 0x0461, /*!< Input selection for amplifier */ + TFA9896_BF_AUDFS = 0x04c3, /*!< Audio sample rate setting */ + TFA9896_BF_BSSCR = 0x0501, /*!< Batteery protection attack time */ + TFA9896_BF_BSST = 0x0523, /*!< Battery protection threshold level */ + TFA9896_BF_BSSRL = 0x0561, /*!< Battery protection maximum reduction */ + TFA9896_BF_BSSRR = 0x0582, /*!< Battery protection release time */ + TFA9896_BF_BSSHY = 0x05b1, /*!< Battery Protection Hysteresis */ + TFA9896_BF_BSSR = 0x05e0, /*!< Battery voltage value for read out (only) */ + TFA9896_BF_BSSBY = 0x05f0, /*!< Bypass clipper battery protection */ + TFA9896_BF_DPSA = 0x0600, /*!< Enable dynamic powerstage activation (DPSA) */ + TFA9896_BF_ATTEN = 0x0613, /*!< Gain attenuation setting */ + TFA9896_BF_CFSM = 0x0650, /*!< Soft mute in CoolFlux */ + TFA9896_BF_BSSS = 0x0670, /*!< Battery sense steepness */ + TFA9896_BF_VOL = 0x0687, /*!< Coolflux volume control */ + TFA9896_BF_DCVO2 = 0x0702, /*!< Second Boost Voltage */ + TFA9896_BF_DCMCC = 0x0733, /*!< Max boost coil current - step of 175 mA */ + TFA9896_BF_DCVO1 = 0x0772, /*!< First Boost Voltage */ + TFA9896_BF_DCIE = 0x07a0, /*!< Adaptive boost mode */ + TFA9896_BF_DCSR = 0x07b0, /*!< Soft Rampup/down mode for DCDC controller */ + TFA9896_BF_DCPAVG= 0x07c0, /*!< ctrl_peak2avg for analog part of DCDC */ + TFA9896_BF_DCPWM = 0x07d0, /*!< DCDC PWM only mode */ + TFA9896_BF_TROS = 0x0800, /*!< Selection ambient temperature for speaker calibration */ + TFA9896_BF_EXTTS = 0x0818, /*!< External temperature for speaker calibration (C) */ + TFA9896_BF_PWDN = 0x0900, /*!< powerdown selection */ + TFA9896_BF_I2CR = 0x0910, /*!< All I2C registers reset to default */ + TFA9896_BF_CFE = 0x0920, /*!< Enable CoolFlux */ + TFA9896_BF_AMPE = 0x0930, /*!< Enable Amplifier */ + TFA9896_BF_DCA = 0x0940, /*!< Enable DCDC Boost converter */ + TFA9896_BF_SBSL = 0x0950, /*!< Coolflux configured */ + TFA9896_BF_AMPC = 0x0960, /*!< Selection if Coolflux enables amplifier */ + TFA9896_BF_DCDIS = 0x0970, /*!< DCDC boost converter not connected */ + TFA9896_BF_PSDR = 0x0980, /*!< IDDQ amplifier test selection */ + TFA9896_BF_INTPAD= 0x09c1, /*!< INT pad (interrupt bump output) configuration */ + TFA9896_BF_IPLL = 0x09e0, /*!< PLL input reference clock selection */ + TFA9896_BF_DCTRIP= 0x0a04, /*!< Adaptive boost trip levels (effective only when boost_intel is set to 1) */ + TFA9896_BF_DCHOLD= 0x0a54, /*!< Hold time for DCDC booster (effective only when boost_intel is set to 1) */ + TFA9896_BF_MTPK = 0x0b07, /*!< KEY2 to access key2 protected registers (default for engineering) */ + TFA9896_BF_CVFDLY= 0x0c25, /*!< Fractional delay adjustment between current and voltage sense */ + TFA9896_BF_OPENMTP= 0x0ec0, /*!< Enable programming of the MTP memory */ + TFA9896_BF_TDMPRF= 0x1011, /*!< TDM usecase selection control */ + TFA9896_BF_TDMEN = 0x1030, /*!< TDM interface enable */ + TFA9896_BF_TDMCKINV= 0x1040, /*!< TDM clock inversion, receive on */ + TFA9896_BF_TDMFSLN= 0x1053, /*!< TDM FS length */ + TFA9896_BF_TDMFSPOL= 0x1090, /*!< TDM FS polarity (start frame) */ + TFA9896_BF_TDMSAMSZ= 0x10a4, /*!< TDM sample size for all TDM sinks and sources */ + TFA9896_BF_TDMSLOTS= 0x1103, /*!< TDM number of slots */ + TFA9896_BF_TDMSLLN= 0x1144, /*!< TDM slot length */ + TFA9896_BF_TDMBRMG= 0x1194, /*!< TDM bits remaining after the last slot */ + TFA9896_BF_TDMDDEL= 0x11e0, /*!< TDM data delay */ + TFA9896_BF_TDMDADJ= 0x11f0, /*!< TDM data adjustment */ + TFA9896_BF_TDMTXFRM= 0x1201, /*!< TDM TXDATA format */ + TFA9896_BF_TDMUUS0= 0x1221, /*!< TDM TXDATA format unused slot SD0 */ + TFA9896_BF_TDMUUS1= 0x1241, /*!< TDM TXDATA format unused slot SD1 */ + TFA9896_BF_TDMSI0EN= 0x1270, /*!< TDM sink0 enable */ + TFA9896_BF_TDMSI1EN= 0x1280, /*!< TDM sink1 enable */ + TFA9896_BF_TDMSI2EN= 0x1290, /*!< TDM sink2 enable */ + TFA9896_BF_TDMSO0EN= 0x12a0, /*!< TDM source0 enable */ + TFA9896_BF_TDMSO1EN= 0x12b0, /*!< TDM source1 enable */ + TFA9896_BF_TDMSO2EN= 0x12c0, /*!< TDM source2 enable */ + TFA9896_BF_TDMSI0IO= 0x12d0, /*!< TDM sink0 IO selection */ + TFA9896_BF_TDMSI1IO= 0x12e0, /*!< TDM sink1 IO selection */ + TFA9896_BF_TDMSI2IO= 0x12f0, /*!< TDM sink2 IO selection */ + TFA9896_BF_TDMSO0IO= 0x1300, /*!< TDM source0 IO selection */ + TFA9896_BF_TDMSO1IO= 0x1310, /*!< TDM source1 IO selection */ + TFA9896_BF_TDMSO2IO= 0x1320, /*!< TDM source2 IO selection */ + TFA9896_BF_TDMSI0SL= 0x1333, /*!< TDM sink0 slot position [GAIN IN] */ + TFA9896_BF_TDMSI1SL= 0x1373, /*!< TDM sink1 slot position [CH1 IN] */ + TFA9896_BF_TDMSI2SL= 0x13b3, /*!< TDM sink2 slot position [CH2 IN] */ + TFA9896_BF_TDMSO0SL= 0x1403, /*!< TDM source0 slot position [GAIN OUT] */ + TFA9896_BF_TDMSO1SL= 0x1443, /*!< TDM source1 slot position [Voltage Sense] */ + TFA9896_BF_TDMSO2SL= 0x1483, /*!< TDM source2 slot position [Current Sense] */ + TFA9896_BF_NBCK = 0x14c3, /*!< TDM NBCK bit clock ratio */ + TFA9896_BF_INTOVDDS= 0x2000, /*!< flag_por_int_out */ + TFA9896_BF_INTOPLLS= 0x2010, /*!< flag_pll_lock_int_out */ + TFA9896_BF_INTOOTDS= 0x2020, /*!< flag_otpok_int_out */ + TFA9896_BF_INTOOVDS= 0x2030, /*!< flag_ovpok_int_out */ + TFA9896_BF_INTOUVDS= 0x2040, /*!< flag_uvpok_int_out */ + TFA9896_BF_INTOOCDS= 0x2050, /*!< flag_ocp_alarm_int_out */ + TFA9896_BF_INTOCLKS= 0x2060, /*!< flag_clocks_stable_int_out */ + TFA9896_BF_INTOCLIPS= 0x2070, /*!< flag_clip_int_out */ + TFA9896_BF_INTOMTPB= 0x2080, /*!< mtp_busy_int_out */ + TFA9896_BF_INTONOCLK= 0x2090, /*!< flag_lost_clk_int_out */ + TFA9896_BF_INTOSPKS= 0x20a0, /*!< flag_cf_speakererror_int_out */ + TFA9896_BF_INTOACS= 0x20b0, /*!< flag_cold_started_int_out */ + TFA9896_BF_INTOSWS= 0x20c0, /*!< flag_engage_int_out */ + TFA9896_BF_INTOWDS= 0x20d0, /*!< flag_watchdog_reset_int_out */ + TFA9896_BF_INTOAMPS= 0x20e0, /*!< flag_enbl_amp_int_out */ + TFA9896_BF_INTOAREFS= 0x20f0, /*!< flag_enbl_ref_int_out */ + TFA9896_BF_INTOERR= 0x2200, /*!< flag_cfma_err_int_out */ + TFA9896_BF_INTOACK= 0x2210, /*!< flag_cfma_ack_int_out */ + TFA9896_BF_INTIVDDS= 0x2300, /*!< flag_por_int_in */ + TFA9896_BF_INTIPLLS= 0x2310, /*!< flag_pll_lock_int_in */ + TFA9896_BF_INTIOTDS= 0x2320, /*!< flag_otpok_int_in */ + TFA9896_BF_INTIOVDS= 0x2330, /*!< flag_ovpok_int_in */ + TFA9896_BF_INTIUVDS= 0x2340, /*!< flag_uvpok_int_in */ + TFA9896_BF_INTIOCDS= 0x2350, /*!< flag_ocp_alarm_int_in */ + TFA9896_BF_INTICLKS= 0x2360, /*!< flag_clocks_stable_int_in */ + TFA9896_BF_INTICLIPS= 0x2370, /*!< flag_clip_int_in */ + TFA9896_BF_INTIMTPB= 0x2380, /*!< mtp_busy_int_in */ + TFA9896_BF_INTINOCLK= 0x2390, /*!< flag_lost_clk_int_in */ + TFA9896_BF_INTISPKS= 0x23a0, /*!< flag_cf_speakererror_int_in */ + TFA9896_BF_INTIACS= 0x23b0, /*!< flag_cold_started_int_in */ + TFA9896_BF_INTISWS= 0x23c0, /*!< flag_engage_int_in */ + TFA9896_BF_INTIWDS= 0x23d0, /*!< flag_watchdog_reset_int_in */ + TFA9896_BF_INTIAMPS= 0x23e0, /*!< flag_enbl_amp_int_in */ + TFA9896_BF_INTIAREFS= 0x23f0, /*!< flag_enbl_ref_int_in */ + TFA9896_BF_INTIERR= 0x2500, /*!< flag_cfma_err_int_in */ + TFA9896_BF_INTIACK= 0x2510, /*!< flag_cfma_ack_int_in */ + TFA9896_BF_INTENVDDS= 0x2600, /*!< flag_por_int_enable */ + TFA9896_BF_INTENPLLS= 0x2610, /*!< flag_pll_lock_int_enable */ + TFA9896_BF_INTENOTDS= 0x2620, /*!< flag_otpok_int_enable */ + TFA9896_BF_INTENOVDS= 0x2630, /*!< flag_ovpok_int_enable */ + TFA9896_BF_INTENUVDS= 0x2640, /*!< flag_uvpok_int_enable */ + TFA9896_BF_INTENOCDS= 0x2650, /*!< flag_ocp_alarm_int_enable */ + TFA9896_BF_INTENCLKS= 0x2660, /*!< flag_clocks_stable_int_enable */ + TFA9896_BF_INTENCLIPS= 0x2670, /*!< flag_clip_int_enable */ + TFA9896_BF_INTENMTPB= 0x2680, /*!< mtp_busy_int_enable */ + TFA9896_BF_INTENNOCLK= 0x2690, /*!< flag_lost_clk_int_enable */ + TFA9896_BF_INTENSPKS= 0x26a0, /*!< flag_cf_speakererror_int_enable */ + TFA9896_BF_INTENACS= 0x26b0, /*!< flag_cold_started_int_enable */ + TFA9896_BF_INTENSWS= 0x26c0, /*!< flag_engage_int_enable */ + TFA9896_BF_INTENWDS= 0x26d0, /*!< flag_watchdog_reset_int_enable */ + TFA9896_BF_INTENAMPS= 0x26e0, /*!< flag_enbl_amp_int_enable */ + TFA9896_BF_INTENAREFS= 0x26f0, /*!< flag_enbl_ref_int_enable */ + TFA9896_BF_INTENERR= 0x2800, /*!< flag_cfma_err_int_enable */ + TFA9896_BF_INTENACK= 0x2810, /*!< flag_cfma_ack_int_enable */ + TFA9896_BF_INTPOLVDDS= 0x2900, /*!< flag_por_int_pol */ + TFA9896_BF_INTPOLPLLS= 0x2910, /*!< flag_pll_lock_int_pol */ + TFA9896_BF_INTPOLOTDS= 0x2920, /*!< flag_otpok_int_pol */ + TFA9896_BF_INTPOLOVDS= 0x2930, /*!< flag_ovpok_int_pol */ + TFA9896_BF_INTPOLUVDS= 0x2940, /*!< flag_uvpok_int_pol */ + TFA9896_BF_INTPOLOCDS= 0x2950, /*!< flag_ocp_alarm_int_pol */ + TFA9896_BF_INTPOLCLKS= 0x2960, /*!< flag_clocks_stable_int_pol */ + TFA9896_BF_INTPOLCLIPS= 0x2970, /*!< flag_clip_int_pol */ + TFA9896_BF_INTPOLMTPB= 0x2980, /*!< mtp_busy_int_pol */ + TFA9896_BF_INTPOLNOCLK= 0x2990, /*!< flag_lost_clk_int_pol */ + TFA9896_BF_INTPOLSPKS= 0x29a0, /*!< flag_cf_speakererror_int_pol */ + TFA9896_BF_INTPOLACS= 0x29b0, /*!< flag_cold_started_int_pol */ + TFA9896_BF_INTPOLSWS= 0x29c0, /*!< flag_engage_int_pol */ + TFA9896_BF_INTPOLWDS= 0x29d0, /*!< flag_watchdog_reset_int_pol */ + TFA9896_BF_INTPOLAMPS= 0x29e0, /*!< flag_enbl_amp_int_pol */ + TFA9896_BF_INTPOLAREFS= 0x29f0, /*!< flag_enbl_ref_int_pol */ + TFA9896_BF_INTPOLERR= 0x2b00, /*!< flag_cfma_err_int_pol */ + TFA9896_BF_INTPOLACK= 0x2b10, /*!< flag_cfma_ack_int_pol */ + TFA9896_BF_CLIP = 0x4900, /*!< Bypass clip control */ + TFA9896_BF_CIMTP = 0x62b0, /*!< Start copying data from I2C mtp registers to mtp */ + TFA9896_BF_RST = 0x7000, /*!< Reset CoolFlux DSP */ + TFA9896_BF_DMEM = 0x7011, /*!< Target memory for access */ + TFA9896_BF_AIF = 0x7030, /*!< Auto increment flag for memory-address */ + TFA9896_BF_CFINT = 0x7040, /*!< CF Interrupt - auto clear */ + TFA9896_BF_REQ = 0x7087, /*!< CF request for accessing the 8 channels */ + TFA9896_BF_MADD = 0x710f, /*!< Memory address */ + TFA9896_BF_MEMA = 0x720f, /*!< Activate memory access */ + TFA9896_BF_ERR = 0x7307, /*!< CF error flags */ + TFA9896_BF_ACK = 0x7387, /*!< CF acknowledgement of the requests channels */ + TFA9896_BF_MTPOTC= 0x8000, /*!< Calibration schedule selection */ + TFA9896_BF_MTPEX = 0x8010, /*!< Calibration of RON status bit */ +} nxpTFA9896BfEnumList_t; +#define TFA9896_NAMETABLE static tfaBfName_t Tfa9896DatasheetNames[]= {\ + { 0x0, "VDDS"}, /* Power-on-reset flag (auto clear by reading) , */\ + { 0x10, "PLLS"}, /* PLL lock to programmed frequency , */\ + { 0x20, "OTDS"}, /* Over Temperature Protection alarm , */\ + { 0x30, "OVDS"}, /* Over Voltage Protection alarm , */\ + { 0x40, "UVDS"}, /* Under Voltage Protection alarm , */\ + { 0x50, "OCDS"}, /* Over Current Protection alarm , */\ + { 0x60, "CLKS"}, /* Clocks stable flag , */\ + { 0x70, "CLIPS"}, /* Amplifier clipping , */\ + { 0x80, "MTPB"}, /* MTP busy copying data to/from I2C registers , */\ + { 0x90, "NOCLK"}, /* lost clock detection (reference input clock) , */\ + { 0xa0, "SPKS"}, /* Speaker error , */\ + { 0xb0, "ACS"}, /* Cold Start required , */\ + { 0xc0, "SWS"}, /* Amplifier engage (Amp Switching) , */\ + { 0xd0, "WDS"}, /* watchdog reset (activates reset) , */\ + { 0xe0, "AMPS"}, /* Amplifier is enabled by manager , */\ + { 0xf0, "AREFS"}, /* References are enabled by manager , */\ + { 0x109, "BATS"}, /* Battery voltage from ADC readout , */\ + { 0x208, "TEMPS"}, /* Temperature readout from the temperature sensor ( C), */\ + { 0x30f, "REV"}, /* Device revision information , */\ + { 0x420, "RCV"}, /* Enable receiver mode , */\ + { 0x431, "CHS12"}, /* Channel Selection TDM input for Coolflux , */\ + { 0x450, "INPLVL"}, /* Input level selection attenuator ( , */\ + { 0x461, "CHSA"}, /* Input selection for amplifier , */\ + { 0x4c3, "AUDFS"}, /* Audio sample rate setting , */\ + { 0x501, "BSSCR"}, /* Batteery protection attack time , */\ + { 0x523, "BSST"}, /* Battery protection threshold level , */\ + { 0x561, "BSSRL"}, /* Battery protection maximum reduction , */\ + { 0x582, "BSSRR"}, /* Battery protection release time , */\ + { 0x5b1, "BSSHY"}, /* Battery Protection Hysteresis , */\ + { 0x5e0, "BSSR"}, /* Battery voltage value for read out (only) , */\ + { 0x5f0, "BSSBY"}, /* Bypass clipper battery protection , */\ + { 0x600, "DPSA"}, /* Enable dynamic powerstage activation (DPSA) , */\ + { 0x613, "ATTEN"}, /* Gain attenuation setting , */\ + { 0x650, "CFSM"}, /* Soft mute in CoolFlux , */\ + { 0x670, "BSSS"}, /* Battery sense steepness , */\ + { 0x687, "VOL"}, /* Coolflux volume control , */\ + { 0x702, "DCVO2"}, /* Second Boost Voltage , */\ + { 0x733, "DCMCC"}, /* Max boost coil current - step of 175 mA , */\ + { 0x772, "DCVO1"}, /* First Boost Voltage , */\ + { 0x7a0, "DCIE"}, /* Adaptive boost mode , */\ + { 0x7b0, "DCSR"}, /* Soft Rampup/down mode for DCDC controller , */\ + { 0x7c0, "DCPAVG"}, /* ctrl_peak2avg for analog part of DCDC , */\ + { 0x7d0, "DCPWM"}, /* DCDC PWM only mode , */\ + { 0x800, "TROS"}, /* Selection ambient temperature for speaker calibration , */\ + { 0x818, "EXTTS"}, /* External temperature for speaker calibration (C) , */\ + { 0x900, "PWDN"}, /* powerdown selection , */\ + { 0x910, "I2CR"}, /* All I2C registers reset to default , */\ + { 0x920, "CFE"}, /* Enable CoolFlux , */\ + { 0x930, "AMPE"}, /* Enable Amplifier , */\ + { 0x940, "DCA"}, /* Enable DCDC Boost converter , */\ + { 0x950, "SBSL"}, /* Coolflux configured , */\ + { 0x960, "AMPC"}, /* Selection if Coolflux enables amplifier , */\ + { 0x970, "DCDIS"}, /* DCDC boost converter not connected , */\ + { 0x980, "PSDR"}, /* IDDQ amplifier test selection , */\ + { 0x9c1, "INTPAD"}, /* INT pad (interrupt bump output) configuration , */\ + { 0x9e0, "IPLL"}, /* PLL input reference clock selection , */\ + { 0xa04, "DCTRIP"}, /* Adaptive boost trip levels (effective only when boost_intel is set to 1), */\ + { 0xa54, "DCHOLD"}, /* Hold time for DCDC booster (effective only when boost_intel is set to 1), */\ + { 0xb07, "MTPK"}, /* KEY2 to access key2 protected registers (default for engineering), */\ + { 0xc25, "CVFDLY"}, /* Fractional delay adjustment between current and voltage sense, */\ + { 0xec0, "OPENMTP"}, /* Enable programming of the MTP memory , */\ + { 0x1011, "TDMPRF"}, /* TDM usecase selection control , */\ + { 0x1030, "TDMEN"}, /* TDM interface enable , */\ + { 0x1040, "TDMCKINV"}, /* TDM clock inversion, receive on , */\ + { 0x1053, "TDMFSLN"}, /* TDM FS length , */\ + { 0x1090, "TDMFSPOL"}, /* TDM FS polarity (start frame) , */\ + { 0x10a4, "TDMSAMSZ"}, /* TDM sample size for all TDM sinks and sources , */\ + { 0x1103, "TDMSLOTS"}, /* TDM number of slots , */\ + { 0x1144, "TDMSLLN"}, /* TDM slot length , */\ + { 0x1194, "TDMBRMG"}, /* TDM bits remaining after the last slot , */\ + { 0x11e0, "TDMDDEL"}, /* TDM data delay , */\ + { 0x11f0, "TDMDADJ"}, /* TDM data adjustment , */\ + { 0x1201, "TDMTXFRM"}, /* TDM TXDATA format , */\ + { 0x1221, "TDMUUS0"}, /* TDM TXDATA format unused slot SD0 , */\ + { 0x1241, "TDMUUS1"}, /* TDM TXDATA format unused slot SD1 , */\ + { 0x1270, "TDMSI0EN"}, /* TDM sink0 enable , */\ + { 0x1280, "TDMSI1EN"}, /* TDM sink1 enable , */\ + { 0x1290, "TDMSI2EN"}, /* TDM sink2 enable , */\ + { 0x12a0, "TDMSO0EN"}, /* TDM source0 enable , */\ + { 0x12b0, "TDMSO1EN"}, /* TDM source1 enable , */\ + { 0x12c0, "TDMSO2EN"}, /* TDM source2 enable , */\ + { 0x12d0, "TDMSI0IO"}, /* TDM sink0 IO selection , */\ + { 0x12e0, "TDMSI1IO"}, /* TDM sink1 IO selection , */\ + { 0x12f0, "TDMSI2IO"}, /* TDM sink2 IO selection , */\ + { 0x1300, "TDMSO0IO"}, /* TDM source0 IO selection , */\ + { 0x1310, "TDMSO1IO"}, /* TDM source1 IO selection , */\ + { 0x1320, "TDMSO2IO"}, /* TDM source2 IO selection , */\ + { 0x1333, "TDMSI0SL"}, /* TDM sink0 slot position [GAIN IN] , */\ + { 0x1373, "TDMSI1SL"}, /* TDM sink1 slot position [CH1 IN] , */\ + { 0x13b3, "TDMSI2SL"}, /* TDM sink2 slot position [CH2 IN] , */\ + { 0x1403, "TDMSO0SL"}, /* TDM source0 slot position [GAIN OUT] , */\ + { 0x1443, "TDMSO1SL"}, /* TDM source1 slot position [Voltage Sense] , */\ + { 0x1483, "TDMSO2SL"}, /* TDM source2 slot position [Current Sense] , */\ + { 0x14c3, "NBCK"}, /* TDM NBCK bit clock ratio , */\ + { 0x2000, "INTOVDDS"}, /* flag_por_int_out , */\ + { 0x2010, "INTOPLLS"}, /* flag_pll_lock_int_out , */\ + { 0x2020, "INTOOTDS"}, /* flag_otpok_int_out , */\ + { 0x2030, "INTOOVDS"}, /* flag_ovpok_int_out , */\ + { 0x2040, "INTOUVDS"}, /* flag_uvpok_int_out , */\ + { 0x2050, "INTOOCDS"}, /* flag_ocp_alarm_int_out , */\ + { 0x2060, "INTOCLKS"}, /* flag_clocks_stable_int_out , */\ + { 0x2070, "INTOCLIPS"}, /* flag_clip_int_out , */\ + { 0x2080, "INTOMTPB"}, /* mtp_busy_int_out , */\ + { 0x2090, "INTONOCLK"}, /* flag_lost_clk_int_out , */\ + { 0x20a0, "INTOSPKS"}, /* flag_cf_speakererror_int_out , */\ + { 0x20b0, "INTOACS"}, /* flag_cold_started_int_out , */\ + { 0x20c0, "INTOSWS"}, /* flag_engage_int_out , */\ + { 0x20d0, "INTOWDS"}, /* flag_watchdog_reset_int_out , */\ + { 0x20e0, "INTOAMPS"}, /* flag_enbl_amp_int_out , */\ + { 0x20f0, "INTOAREFS"}, /* flag_enbl_ref_int_out , */\ + { 0x2200, "INTOERR"}, /* flag_cfma_err_int_out , */\ + { 0x2210, "INTOACK"}, /* flag_cfma_ack_int_out , */\ + { 0x2300, "INTIVDDS"}, /* flag_por_int_in , */\ + { 0x2310, "INTIPLLS"}, /* flag_pll_lock_int_in , */\ + { 0x2320, "INTIOTDS"}, /* flag_otpok_int_in , */\ + { 0x2330, "INTIOVDS"}, /* flag_ovpok_int_in , */\ + { 0x2340, "INTIUVDS"}, /* flag_uvpok_int_in , */\ + { 0x2350, "INTIOCDS"}, /* flag_ocp_alarm_int_in , */\ + { 0x2360, "INTICLKS"}, /* flag_clocks_stable_int_in , */\ + { 0x2370, "INTICLIPS"}, /* flag_clip_int_in , */\ + { 0x2380, "INTIMTPB"}, /* mtp_busy_int_in , */\ + { 0x2390, "INTINOCLK"}, /* flag_lost_clk_int_in , */\ + { 0x23a0, "INTISPKS"}, /* flag_cf_speakererror_int_in , */\ + { 0x23b0, "INTIACS"}, /* flag_cold_started_int_in , */\ + { 0x23c0, "INTISWS"}, /* flag_engage_int_in , */\ + { 0x23d0, "INTIWDS"}, /* flag_watchdog_reset_int_in , */\ + { 0x23e0, "INTIAMPS"}, /* flag_enbl_amp_int_in , */\ + { 0x23f0, "INTIAREFS"}, /* flag_enbl_ref_int_in , */\ + { 0x2500, "INTIERR"}, /* flag_cfma_err_int_in , */\ + { 0x2510, "INTIACK"}, /* flag_cfma_ack_int_in , */\ + { 0x2600, "INTENVDDS"}, /* flag_por_int_enable , */\ + { 0x2610, "INTENPLLS"}, /* flag_pll_lock_int_enable , */\ + { 0x2620, "INTENOTDS"}, /* flag_otpok_int_enable , */\ + { 0x2630, "INTENOVDS"}, /* flag_ovpok_int_enable , */\ + { 0x2640, "INTENUVDS"}, /* flag_uvpok_int_enable , */\ + { 0x2650, "INTENOCDS"}, /* flag_ocp_alarm_int_enable , */\ + { 0x2660, "INTENCLKS"}, /* flag_clocks_stable_int_enable , */\ + { 0x2670, "INTENCLIPS"}, /* flag_clip_int_enable , */\ + { 0x2680, "INTENMTPB"}, /* mtp_busy_int_enable , */\ + { 0x2690, "INTENNOCLK"}, /* flag_lost_clk_int_enable , */\ + { 0x26a0, "INTENSPKS"}, /* flag_cf_speakererror_int_enable , */\ + { 0x26b0, "INTENACS"}, /* flag_cold_started_int_enable , */\ + { 0x26c0, "INTENSWS"}, /* flag_engage_int_enable , */\ + { 0x26d0, "INTENWDS"}, /* flag_watchdog_reset_int_enable , */\ + { 0x26e0, "INTENAMPS"}, /* flag_enbl_amp_int_enable , */\ + { 0x26f0, "INTENAREFS"}, /* flag_enbl_ref_int_enable , */\ + { 0x2800, "INTENERR"}, /* flag_cfma_err_int_enable , */\ + { 0x2810, "INTENACK"}, /* flag_cfma_ack_int_enable , */\ + { 0x2900, "INTPOLVDDS"}, /* flag_por_int_pol , */\ + { 0x2910, "INTPOLPLLS"}, /* flag_pll_lock_int_pol , */\ + { 0x2920, "INTPOLOTDS"}, /* flag_otpok_int_pol , */\ + { 0x2930, "INTPOLOVDS"}, /* flag_ovpok_int_pol , */\ + { 0x2940, "INTPOLUVDS"}, /* flag_uvpok_int_pol , */\ + { 0x2950, "INTPOLOCDS"}, /* flag_ocp_alarm_int_pol , */\ + { 0x2960, "INTPOLCLKS"}, /* flag_clocks_stable_int_pol , */\ + { 0x2970, "INTPOLCLIPS"}, /* flag_clip_int_pol , */\ + { 0x2980, "INTPOLMTPB"}, /* mtp_busy_int_pol , */\ + { 0x2990, "INTPOLNOCLK"}, /* flag_lost_clk_int_pol , */\ + { 0x29a0, "INTPOLSPKS"}, /* flag_cf_speakererror_int_pol , */\ + { 0x29b0, "INTPOLACS"}, /* flag_cold_started_int_pol , */\ + { 0x29c0, "INTPOLSWS"}, /* flag_engage_int_pol , */\ + { 0x29d0, "INTPOLWDS"}, /* flag_watchdog_reset_int_pol , */\ + { 0x29e0, "INTPOLAMPS"}, /* flag_enbl_amp_int_pol , */\ + { 0x29f0, "INTPOLAREFS"}, /* flag_enbl_ref_int_pol , */\ + { 0x2b00, "INTPOLERR"}, /* flag_cfma_err_int_pol , */\ + { 0x2b10, "INTPOLACK"}, /* flag_cfma_ack_int_pol , */\ + { 0x4900, "CLIP"}, /* Bypass clip control , */\ + { 0x62b0, "CIMTP"}, /* Start copying data from I2C mtp registers to mtp , */\ + { 0x7000, "RST"}, /* Reset CoolFlux DSP , */\ + { 0x7011, "DMEM"}, /* Target memory for access , */\ + { 0x7030, "AIF"}, /* Auto increment flag for memory-address , */\ + { 0x7040, "CFINT"}, /* CF Interrupt - auto clear , */\ + { 0x7087, "REQ"}, /* CF request for accessing the 8 channels , */\ + { 0x710f, "MADD"}, /* Memory address , */\ + { 0x720f, "MEMA"}, /* Activate memory access , */\ + { 0x7307, "ERR"}, /* CF error flags , */\ + { 0x7387, "ACK"}, /* CF acknowledgement of the requests channels , */\ + { 0x8000, "MTPOTC"}, /* Calibration schedule selection , */\ + { 0x8010, "MTPEX"}, /* Calibration of RON status bit , */\ + { 0x8045, "SWPROFIL" },\ + { 0x80a5, "SWVSTEP" },\ + { 0xffff,"Unknown bitfield enum" } /* not found */\ +}; + +#define TFA9896_BITNAMETABLE static tfaBfName_t Tfa9896BitNames[]= {\ + { 0x0, "flag_por"}, /* Power-on-reset flag (auto clear by reading) , */\ + { 0x10, "flag_pll_lock"}, /* PLL lock to programmed frequency , */\ + { 0x20, "flag_otpok"}, /* Over Temperature Protection alarm , */\ + { 0x30, "flag_ovpok"}, /* Over Voltage Protection alarm , */\ + { 0x40, "flag_uvpok"}, /* Under Voltage Protection alarm , */\ + { 0x50, "flag_ocp_alarm"}, /* Over Current Protection alarm , */\ + { 0x60, "flag_clocks_stable"}, /* Clocks stable flag , */\ + { 0x70, "flag_clip"}, /* Amplifier clipping , */\ + { 0x80, "mtp_busy"}, /* MTP busy copying data to/from I2C registers , */\ + { 0x90, "flag_lost_clk"}, /* lost clock detection (reference input clock) , */\ + { 0xa0, "flag_cf_speakererror"}, /* Speaker error , */\ + { 0xb0, "flag_cold_started"}, /* Cold Start required , */\ + { 0xc0, "flag_engage"}, /* Amplifier engage (Amp Switching) , */\ + { 0xd0, "flag_watchdog_reset"}, /* watchdog reset (activates reset) , */\ + { 0xe0, "flag_enbl_amp"}, /* Amplifier is enabled by manager , */\ + { 0xf0, "flag_enbl_ref"}, /* References are enabled by manager , */\ + { 0x109, "bat_adc"}, /* Battery voltage from ADC readout , */\ + { 0x208, "temp_adc"}, /* Temperature readout from the temperature sensor ( C), */\ + { 0x30f, "device_rev"}, /* Device revision information , */\ + { 0x420, "ctrl_rcv"}, /* Enable receiver mode , */\ + { 0x431, "chan_sel"}, /* Channel Selection TDM input for Coolflux , */\ + { 0x450, "input_level"}, /* Input level selection attenuator ( , */\ + { 0x461, "vamp_sel"}, /* Input selection for amplifier , */\ + { 0x4c3, "audio_fs"}, /* Audio sample rate setting , */\ + { 0x501, "vbat_prot_attacktime"}, /* Batteery protection attack time , */\ + { 0x523, "vbat_prot_thlevel"}, /* Battery protection threshold level , */\ + { 0x561, "vbat_prot_max_reduct"}, /* Battery protection maximum reduction , */\ + { 0x582, "vbat_prot_release_t"}, /* Battery protection release time , */\ + { 0x5b1, "vbat_prot_hysterese"}, /* Battery Protection Hysteresis , */\ + { 0x5d0, "reset_min_vbat"}, /* Battery supply safeguard clipper reset ( if CF_DSP is bypassed), */\ + { 0x5e0, "sel_vbat"}, /* Battery voltage value for read out (only) , */\ + { 0x5f0, "bypass_clipper"}, /* Bypass clipper battery protection , */\ + { 0x600, "dpsa"}, /* Enable dynamic powerstage activation (DPSA) , */\ + { 0x613, "ctrl_att"}, /* Gain attenuation setting , */\ + { 0x650, "cf_mute"}, /* Soft mute in CoolFlux , */\ + { 0x670, "batsense_steepness"}, /* Battery sense steepness , */\ + { 0x687, "vol"}, /* Coolflux volume control , */\ + { 0x702, "scnd_boost_voltage"}, /* Second Boost Voltage , */\ + { 0x733, "boost_cur"}, /* Max boost coil current - step of 175 mA , */\ + { 0x772, "frst_boost_voltage"}, /* First Boost Voltage , */\ + { 0x7a0, "boost_intel"}, /* Adaptive boost mode , */\ + { 0x7b0, "boost_speed"}, /* Soft Rampup/down mode for DCDC controller , */\ + { 0x7c0, "boost_peak2avg"}, /* ctrl_peak2avg for analog part of DCDC , */\ + { 0x7d0, "dcdc_pwmonly"}, /* DCDC PWM only mode , */\ + { 0x7e0, "ignore_flag_voutcomp86"}, /* Ignore flag_voutcomp86 (flag from analog) , */\ + { 0x800, "ext_temp_sel"}, /* Selection ambient temperature for speaker calibration , */\ + { 0x818, "ext_temp"}, /* External temperature for speaker calibration (C) , */\ + { 0x900, "powerdown"}, /* powerdown selection , */\ + { 0x910, "reset"}, /* All I2C registers reset to default , */\ + { 0x920, "enbl_coolflux"}, /* Enable CoolFlux , */\ + { 0x930, "enbl_amplifier"}, /* Enable Amplifier , */\ + { 0x940, "enbl_boost"}, /* Enable DCDC Boost converter , */\ + { 0x950, "coolflux_configured"}, /* Coolflux configured , */\ + { 0x960, "sel_enbl_amplifier"}, /* Selection if Coolflux enables amplifier , */\ + { 0x970, "dcdcoff_mode"}, /* DCDC boost converter not connected , */\ + { 0x980, "iddqtest"}, /* IDDQ amplifier test selection , */\ + { 0x9c1, "int_pad_io"}, /* INT pad (interrupt bump output) configuration , */\ + { 0x9e0, "sel_fs_bck"}, /* PLL input reference clock selection , */\ + { 0x9f0, "sel_scl_cf_clock"}, /* Coolflux sub-system clock selection , */\ + { 0xa04, "boost_trip_lvl"}, /* Adaptive boost trip levels (effective only when boost_intel is set to 1), */\ + { 0xa54, "boost_hold_time"}, /* Hold time for DCDC booster (effective only when boost_intel is set to 1), */\ + { 0xaa1, "bst_slpcmplvl"}, /* Slope compensation current, represents LxF (inductance x frequency) value , */\ + { 0xb07, "mtpkey2"}, /* KEY2 to access key2 protected registers (default for engineering), */\ + { 0xc00, "enbl_volt_sense"}, /* Voltage sense enabling control bit , */\ + { 0xc10, "vsense_pwm_sel"}, /* Voltage sense source selection , */\ + { 0xc25, "vi_frac_delay"}, /* Fractional delay adjustment between current and voltage sense, */\ + { 0xc80, "sel_voltsense_out"}, /* TDM output data selection for AEC , */\ + { 0xc90, "vsense_bypass_avg"}, /* Voltage sense average block bypass , */\ + { 0xd05, "cf_frac_delay"}, /* Fractional delay adjustment between current and voltage sense by firmware, */\ + { 0xe00, "bypass_dcdc_curr_prot"}, /* Control to switch off dcdc current reduction with bat protection, */\ + { 0xe10, "bypass_ocp"}, /* Bypass OCP (digital IP block) , */\ + { 0xe20, "ocptest"}, /* ocptest (analog IP block) enable , */\ + { 0xe80, "disable_clock_sh_prot"}, /* Disable clock_sh protection , */\ + { 0xe92, "reserve_reg_15_09"}, /* Spare control bits for future usage , */\ + { 0xec0, "unprotect_mtp"}, /* Enable programming of the MTP memory , */\ + { 0xed2, "reserve_reg_15_13"}, /* Spare control bits for future usage , */\ + { 0xf00, "dcdc_pfm20khz_limit"}, /* DCDC in PFM mode forcing each 50us a pwm pulse , */\ + { 0xf11, "dcdc_ctrl_maxzercnt"}, /* DCDC number of zero current flags required to go to pfm mode, */\ + { 0xf36, "dcdc_vbat_delta_detect"}, /* DCDC threshold required on a delta Vbat (in PFM mode) switching to PWM mode, */\ + { 0xfa0, "dcdc_ignore_vbat"}, /* Ignore an increase on Vbat , */\ + { 0x1011, "tdm_usecase"}, /* TDM usecase selection control , */\ + { 0x1030, "tdm_enable"}, /* TDM interface enable , */\ + { 0x1040, "tdm_clk_inversion"}, /* TDM clock inversion, receive on , */\ + { 0x1053, "tdm_fs_ws_length"}, /* TDM FS length , */\ + { 0x1090, "tdm_fs_ws_polarity"}, /* TDM FS polarity (start frame) , */\ + { 0x10a4, "tdm_sample_size"}, /* TDM sample size for all TDM sinks and sources , */\ + { 0x1103, "tdm_nb_of_slots"}, /* TDM number of slots , */\ + { 0x1144, "tdm_slot_length"}, /* TDM slot length , */\ + { 0x1194, "tdm_bits_remaining"}, /* TDM bits remaining after the last slot , */\ + { 0x11e0, "tdm_data_delay"}, /* TDM data delay , */\ + { 0x11f0, "tdm_data_adjustment"}, /* TDM data adjustment , */\ + { 0x1201, "tdm_txdata_format"}, /* TDM TXDATA format , */\ + { 0x1221, "tdm_txdata_format_unused_slot_sd0"}, /* TDM TXDATA format unused slot SD0 , */\ + { 0x1241, "tdm_txdata_format_unused_slot_sd1"}, /* TDM TXDATA format unused slot SD1 , */\ + { 0x1270, "tdm_sink0_enable"}, /* TDM sink0 enable , */\ + { 0x1280, "tdm_sink1_enable"}, /* TDM sink1 enable , */\ + { 0x1290, "tdm_sink2_enable"}, /* TDM sink2 enable , */\ + { 0x12a0, "tdm_source0_enable"}, /* TDM source0 enable , */\ + { 0x12b0, "tdm_source1_enable"}, /* TDM source1 enable , */\ + { 0x12c0, "tdm_source2_enable"}, /* TDM source2 enable , */\ + { 0x12d0, "tdm_sink0_io"}, /* TDM sink0 IO selection , */\ + { 0x12e0, "tdm_sink1_io"}, /* TDM sink1 IO selection , */\ + { 0x12f0, "tdm_sink2_io"}, /* TDM sink2 IO selection , */\ + { 0x1300, "tdm_source0_io"}, /* TDM source0 IO selection , */\ + { 0x1310, "tdm_source1_io"}, /* TDM source1 IO selection , */\ + { 0x1320, "tdm_source2_io"}, /* TDM source2 IO selection , */\ + { 0x1333, "tdm_sink0_slot"}, /* TDM sink0 slot position [GAIN IN] , */\ + { 0x1373, "tdm_sink1_slot"}, /* TDM sink1 slot position [CH1 IN] , */\ + { 0x13b3, "tdm_sink2_slot"}, /* TDM sink2 slot position [CH2 IN] , */\ + { 0x1403, "tdm_source0_slot"}, /* TDM source0 slot position [GAIN OUT] , */\ + { 0x1443, "tdm_source1_slot"}, /* TDM source1 slot position [Voltage Sense] , */\ + { 0x1483, "tdm_source2_slot"}, /* TDM source2 slot position [Current Sense] , */\ + { 0x14c3, "tdm_nbck"}, /* TDM NBCK bit clock ratio , */\ + { 0x1500, "flag_tdm_lut_error"}, /* TDM LUT error flag , */\ + { 0x1512, "flag_tdm_status"}, /* TDM interface status bits , */\ + { 0x1540, "flag_tdm_error"}, /* TDM interface error indicator , */\ + { 0x1551, "status_bst_mode"}, /* DCDC mode status bits , */\ + { 0x2000, "flag_por_int_out"}, /* flag_por_int_out , */\ + { 0x2010, "flag_pll_lock_int_out"}, /* flag_pll_lock_int_out , */\ + { 0x2020, "flag_otpok_int_out"}, /* flag_otpok_int_out , */\ + { 0x2030, "flag_ovpok_int_out"}, /* flag_ovpok_int_out , */\ + { 0x2040, "flag_uvpok_int_out"}, /* flag_uvpok_int_out , */\ + { 0x2050, "flag_ocp_alarm_int_out"}, /* flag_ocp_alarm_int_out , */\ + { 0x2060, "flag_clocks_stable_int_out"}, /* flag_clocks_stable_int_out , */\ + { 0x2070, "flag_clip_int_out"}, /* flag_clip_int_out , */\ + { 0x2080, "mtp_busy_int_out"}, /* mtp_busy_int_out , */\ + { 0x2090, "flag_lost_clk_int_out"}, /* flag_lost_clk_int_out , */\ + { 0x20a0, "flag_cf_speakererror_int_out"}, /* flag_cf_speakererror_int_out , */\ + { 0x20b0, "flag_cold_started_int_out"}, /* flag_cold_started_int_out , */\ + { 0x20c0, "flag_engage_int_out"}, /* flag_engage_int_out , */\ + { 0x20d0, "flag_watchdog_reset_int_out"}, /* flag_watchdog_reset_int_out , */\ + { 0x20e0, "flag_enbl_amp_int_out"}, /* flag_enbl_amp_int_out , */\ + { 0x20f0, "flag_enbl_ref_int_out"}, /* flag_enbl_ref_int_out , */\ + { 0x2100, "flag_voutcomp_int_out"}, /* flag_voutcomp_int_out , */\ + { 0x2110, "flag_voutcomp93_int_out"}, /* flag_voutcomp93_int_out , */\ + { 0x2120, "flag_voutcomp86_int_out"}, /* flag_voutcomp86_int_out , */\ + { 0x2130, "flag_hiz_int_out"}, /* flag_hiz_int_out , */\ + { 0x2140, "flag_ocpokbst_int_out"}, /* flag_ocpokbst_int_out , */\ + { 0x2150, "flag_peakcur_int_out"}, /* flag_peakcur_int_out , */\ + { 0x2160, "flag_ocpokap_int_out"}, /* flag_ocpokap_int_out , */\ + { 0x2170, "flag_ocpokan_int_out"}, /* flag_ocpokan_int_out , */\ + { 0x2180, "flag_ocpokbp_int_out"}, /* flag_ocpokbp_int_out , */\ + { 0x2190, "flag_ocpokbn_int_out"}, /* flag_ocpokbn_int_out , */\ + { 0x21a0, "flag_adc10_ready_int_out"}, /* flag_adc10_ready_int_out , */\ + { 0x21b0, "flag_clipa_high_int_out"}, /* flag_clipa_high_int_out , */\ + { 0x21c0, "flag_clipa_low_int_out"}, /* flag_clipa_low_int_out , */\ + { 0x21d0, "flag_clipb_high_int_out"}, /* flag_clipb_high_int_out , */\ + { 0x21e0, "flag_clipb_low_int_out"}, /* flag_clipb_low_int_out , */\ + { 0x21f0, "flag_tdm_error_int_out"}, /* flag_tdm_error_int_out , */\ + { 0x2200, "flag_cfma_err_int_out"}, /* flag_cfma_err_int_out , */\ + { 0x2210, "flag_cfma_ack_int_out"}, /* flag_cfma_ack_int_out , */\ + { 0x2300, "flag_por_int_in"}, /* flag_por_int_in , */\ + { 0x2310, "flag_pll_lock_int_in"}, /* flag_pll_lock_int_in , */\ + { 0x2320, "flag_otpok_int_in"}, /* flag_otpok_int_in , */\ + { 0x2330, "flag_ovpok_int_in"}, /* flag_ovpok_int_in , */\ + { 0x2340, "flag_uvpok_int_in"}, /* flag_uvpok_int_in , */\ + { 0x2350, "flag_ocp_alarm_int_in"}, /* flag_ocp_alarm_int_in , */\ + { 0x2360, "flag_clocks_stable_int_in"}, /* flag_clocks_stable_int_in , */\ + { 0x2370, "flag_clip_int_in"}, /* flag_clip_int_in , */\ + { 0x2380, "mtp_busy_int_in"}, /* mtp_busy_int_in , */\ + { 0x2390, "flag_lost_clk_int_in"}, /* flag_lost_clk_int_in , */\ + { 0x23a0, "flag_cf_speakererror_int_in"}, /* flag_cf_speakererror_int_in , */\ + { 0x23b0, "flag_cold_started_int_in"}, /* flag_cold_started_int_in , */\ + { 0x23c0, "flag_engage_int_in"}, /* flag_engage_int_in , */\ + { 0x23d0, "flag_watchdog_reset_int_in"}, /* flag_watchdog_reset_int_in , */\ + { 0x23e0, "flag_enbl_amp_int_in"}, /* flag_enbl_amp_int_in , */\ + { 0x23f0, "flag_enbl_ref_int_in"}, /* flag_enbl_ref_int_in , */\ + { 0x2400, "flag_voutcomp_int_in"}, /* flag_voutcomp_int_in , */\ + { 0x2410, "flag_voutcomp93_int_in"}, /* flag_voutcomp93_int_in , */\ + { 0x2420, "flag_voutcomp86_int_in"}, /* flag_voutcomp86_int_in , */\ + { 0x2430, "flag_hiz_int_in"}, /* flag_hiz_int_in , */\ + { 0x2440, "flag_ocpokbst_int_in"}, /* flag_ocpokbst_int_in , */\ + { 0x2450, "flag_peakcur_int_in"}, /* flag_peakcur_int_in , */\ + { 0x2460, "flag_ocpokap_int_in"}, /* flag_ocpokap_int_in , */\ + { 0x2470, "flag_ocpokan_int_in"}, /* flag_ocpokan_int_in , */\ + { 0x2480, "flag_ocpokbp_int_in"}, /* flag_ocpokbp_int_in , */\ + { 0x2490, "flag_ocpokbn_int_in"}, /* flag_ocpokbn_int_in , */\ + { 0x24a0, "flag_adc10_ready_int_in"}, /* flag_adc10_ready_int_in , */\ + { 0x24b0, "flag_clipa_high_int_in"}, /* flag_clipa_high_int_in , */\ + { 0x24c0, "flag_clipa_low_int_in"}, /* flag_clipa_low_int_in , */\ + { 0x24d0, "flag_clipb_high_int_in"}, /* flag_clipb_high_int_in , */\ + { 0x24e0, "flag_clipb_low_int_in"}, /* flag_clipb_low_int_in , */\ + { 0x24f0, "flag_tdm_error_int_in"}, /* flag_tdm_error_int_in , */\ + { 0x2500, "flag_cfma_err_int_in"}, /* flag_cfma_err_int_in , */\ + { 0x2510, "flag_cfma_ack_int_in"}, /* flag_cfma_ack_int_in , */\ + { 0x2600, "flag_por_int_enable"}, /* flag_por_int_enable , */\ + { 0x2610, "flag_pll_lock_int_enable"}, /* flag_pll_lock_int_enable , */\ + { 0x2620, "flag_otpok_int_enable"}, /* flag_otpok_int_enable , */\ + { 0x2630, "flag_ovpok_int_enable"}, /* flag_ovpok_int_enable , */\ + { 0x2640, "flag_uvpok_int_enable"}, /* flag_uvpok_int_enable , */\ + { 0x2650, "flag_ocp_alarm_int_enable"}, /* flag_ocp_alarm_int_enable , */\ + { 0x2660, "flag_clocks_stable_int_enable"}, /* flag_clocks_stable_int_enable , */\ + { 0x2670, "flag_clip_int_enable"}, /* flag_clip_int_enable , */\ + { 0x2680, "mtp_busy_int_enable"}, /* mtp_busy_int_enable , */\ + { 0x2690, "flag_lost_clk_int_enable"}, /* flag_lost_clk_int_enable , */\ + { 0x26a0, "flag_cf_speakererror_int_enable"}, /* flag_cf_speakererror_int_enable , */\ + { 0x26b0, "flag_cold_started_int_enable"}, /* flag_cold_started_int_enable , */\ + { 0x26c0, "flag_engage_int_enable"}, /* flag_engage_int_enable , */\ + { 0x26d0, "flag_watchdog_reset_int_enable"}, /* flag_watchdog_reset_int_enable , */\ + { 0x26e0, "flag_enbl_amp_int_enable"}, /* flag_enbl_amp_int_enable , */\ + { 0x26f0, "flag_enbl_ref_int_enable"}, /* flag_enbl_ref_int_enable , */\ + { 0x2700, "flag_voutcomp_int_enable"}, /* flag_voutcomp_int_enable , */\ + { 0x2710, "flag_voutcomp93_int_enable"}, /* flag_voutcomp93_int_enable , */\ + { 0x2720, "flag_voutcomp86_int_enable"}, /* flag_voutcomp86_int_enable , */\ + { 0x2730, "flag_hiz_int_enable"}, /* flag_hiz_int_enable , */\ + { 0x2740, "flag_ocpokbst_int_enable"}, /* flag_ocpokbst_int_enable , */\ + { 0x2750, "flag_peakcur_int_enable"}, /* flag_peakcur_int_enable , */\ + { 0x2760, "flag_ocpokap_int_enable"}, /* flag_ocpokap_int_enable , */\ + { 0x2770, "flag_ocpokan_int_enable"}, /* flag_ocpokan_int_enable , */\ + { 0x2780, "flag_ocpokbp_int_enable"}, /* flag_ocpokbp_int_enable , */\ + { 0x2790, "flag_ocpokbn_int_enable"}, /* flag_ocpokbn_int_enable , */\ + { 0x27a0, "flag_adc10_ready_int_enable"}, /* flag_adc10_ready_int_enable , */\ + { 0x27b0, "flag_clipa_high_int_enable"}, /* flag_clipa_high_int_enable , */\ + { 0x27c0, "flag_clipa_low_int_enable"}, /* flag_clipa_low_int_enable , */\ + { 0x27d0, "flag_clipb_high_int_enable"}, /* flag_clipb_high_int_enable , */\ + { 0x27e0, "flag_clipb_low_int_enable"}, /* flag_clipb_low_int_enable , */\ + { 0x27f0, "flag_tdm_error_int_enable"}, /* flag_tdm_error_int_enable , */\ + { 0x2800, "flag_cfma_err_int_enable"}, /* flag_cfma_err_int_enable , */\ + { 0x2810, "flag_cfma_ack_int_enable"}, /* flag_cfma_ack_int_enable , */\ + { 0x2900, "flag_por_int_pol"}, /* flag_por_int_pol , */\ + { 0x2910, "flag_pll_lock_int_pol"}, /* flag_pll_lock_int_pol , */\ + { 0x2920, "flag_otpok_int_pol"}, /* flag_otpok_int_pol , */\ + { 0x2930, "flag_ovpok_int_pol"}, /* flag_ovpok_int_pol , */\ + { 0x2940, "flag_uvpok_int_pol"}, /* flag_uvpok_int_pol , */\ + { 0x2950, "flag_ocp_alarm_int_pol"}, /* flag_ocp_alarm_int_pol , */\ + { 0x2960, "flag_clocks_stable_int_pol"}, /* flag_clocks_stable_int_pol , */\ + { 0x2970, "flag_clip_int_pol"}, /* flag_clip_int_pol , */\ + { 0x2980, "mtp_busy_int_pol"}, /* mtp_busy_int_pol , */\ + { 0x2990, "flag_lost_clk_int_pol"}, /* flag_lost_clk_int_pol , */\ + { 0x29a0, "flag_cf_speakererror_int_pol"}, /* flag_cf_speakererror_int_pol , */\ + { 0x29b0, "flag_cold_started_int_pol"}, /* flag_cold_started_int_pol , */\ + { 0x29c0, "flag_engage_int_pol"}, /* flag_engage_int_pol , */\ + { 0x29d0, "flag_watchdog_reset_int_pol"}, /* flag_watchdog_reset_int_pol , */\ + { 0x29e0, "flag_enbl_amp_int_pol"}, /* flag_enbl_amp_int_pol , */\ + { 0x29f0, "flag_enbl_ref_int_pol"}, /* flag_enbl_ref_int_pol , */\ + { 0x2a00, "flag_voutcomp_int_pol"}, /* flag_voutcomp_int_pol , */\ + { 0x2a10, "flag_voutcomp93_int_pol"}, /* flag_voutcomp93_int_pol , */\ + { 0x2a20, "flag_voutcomp86_int_pol"}, /* flag_voutcomp86_int_pol , */\ + { 0x2a30, "flag_hiz_int_pol"}, /* flag_hiz_int_pol , */\ + { 0x2a40, "flag_ocpokbst_int_pol"}, /* flag_ocpokbst_int_pol , */\ + { 0x2a50, "flag_peakcur_int_pol"}, /* flag_peakcur_int_pol , */\ + { 0x2a60, "flag_ocpokap_int_pol"}, /* flag_ocpokap_int_pol , */\ + { 0x2a70, "flag_ocpokan_int_pol"}, /* flag_ocpokan_int_pol , */\ + { 0x2a80, "flag_ocpokbp_int_pol"}, /* flag_ocpokbp_int_pol , */\ + { 0x2a90, "flag_ocpokbn_int_pol"}, /* flag_ocpokbn_int_pol , */\ + { 0x2aa0, "flag_adc10_ready_int_pol"}, /* flag_adc10_ready_int_pol , */\ + { 0x2ab0, "flag_clipa_high_int_pol"}, /* flag_clipa_high_int_pol , */\ + { 0x2ac0, "flag_clipa_low_int_pol"}, /* flag_clipa_low_int_pol , */\ + { 0x2ad0, "flag_clipb_high_int_pol"}, /* flag_clipb_high_int_pol , */\ + { 0x2ae0, "flag_clipb_low_int_pol"}, /* flag_clipb_low_int_pol , */\ + { 0x2af0, "flag_tdm_error_int_pol"}, /* flag_tdm_error_int_pol , */\ + { 0x2b00, "flag_cfma_err_int_pol"}, /* flag_cfma_err_int_pol , */\ + { 0x2b10, "flag_cfma_ack_int_pol"}, /* flag_cfma_ack_int_pol , */\ + { 0x3000, "flag_voutcomp"}, /* Status flag_voutcomp, indication Vset is larger than Vbat, */\ + { 0x3010, "flag_voutcomp93"}, /* Status flag_voutcomp93, indication Vset is larger than 1.07 x Vbat, */\ + { 0x3020, "flag_voutcomp86"}, /* Status flag voutcomp86, indication Vset is larger than 1.14 x Vbat, */\ + { 0x3030, "flag_hiz"}, /* Status flag_hiz, indication Vbst is larger than Vbat, */\ + { 0x3040, "flag_ocpokbst"}, /* Status flag_ocpokbst, indication no over current in boost converter PMOS switch, */\ + { 0x3050, "flag_peakcur"}, /* Status flag_peakcur, indication current is max in dcdc converter, */\ + { 0x3060, "flag_ocpokap"}, /* Status flag_ocpokap, indication no over current in amplifier A PMOS output stage, */\ + { 0x3070, "flag_ocpokan"}, /* Status flag_ocpokan, indication no over current in amplifier A NMOS output stage, */\ + { 0x3080, "flag_ocpokbp"}, /* Status flag_ocpokbp, indication no over current in amplifier B PMOS output stage, */\ + { 0x3090, "flag_ocpokbn"}, /* Status flag_ocpokbn, indication no over current in amplifier B NMOS output stage, */\ + { 0x30a0, "flag_adc10_ready"}, /* Status flag_adc10_ready, indication adc10 is ready, */\ + { 0x30b0, "flag_clipa_high"}, /* Status flag_clipa_high, indication pmos amplifier A is clipping, */\ + { 0x30c0, "flag_clipa_low"}, /* Status flag_clipa_low, indication nmos amplifier A is clipping, */\ + { 0x30d0, "flag_clipb_high"}, /* Status flag_clipb_high, indication pmos amplifier B is clipping, */\ + { 0x30e0, "flag_clipb_low"}, /* Status flag_clipb_low, indication nmos amplifier B is clipping, */\ + { 0x310f, "mtp_man_data_out"}, /* MTP manual read out data , */\ + { 0x3200, "key01_locked"}, /* Indicates KEY1 is locked , */\ + { 0x3210, "key02_locked"}, /* Indicates KEY2 is locked , */\ + { 0x3225, "mtp_ecc_tcout"}, /* MTP error correction test data out , */\ + { 0x3280, "mtpctrl_valid_test_rd"}, /* MTP test readout for read , */\ + { 0x3290, "mtpctrl_valid_test_wr"}, /* MTP test readout for write , */\ + { 0x32a0, "flag_in_alarm_state"}, /* Flag alarm state , */\ + { 0x32b0, "mtp_ecc_err2"}, /* Two or more bit errors detected in MTP, can not reconstruct value, */\ + { 0x32c0, "mtp_ecc_err1"}, /* One bit error detected in MTP, reconstructed value, */\ + { 0x32d0, "mtp_mtp_hvf"}, /* High voltage ready flag for MTP , */\ + { 0x32f0, "mtp_zero_check_fail"}, /* Zero check failed for MTP , */\ + { 0x3309, "data_adc10_tempbat"}, /* ADC10 data output for testing battery voltage and temperature, */\ + { 0x400f, "hid_code"}, /* 5A6Bh, 23147d to access hidden registers (default for engineering), */\ + { 0x4100, "bypass_hp"}, /* Bypass High Pass Filter , */\ + { 0x4110, "hard_mute"}, /* Hard Mute , */\ + { 0x4120, "soft_mute"}, /* Soft Mute , */\ + { 0x4134, "pwm_delay"}, /* PWM delay setting , */\ + { 0x4180, "pwm_shape"}, /* PWM Shape , */\ + { 0x4190, "pwm_bitlength"}, /* PWM Bitlength in noise shaper , */\ + { 0x4203, "drive"}, /* Drive bits to select number of amplifier power stages, */\ + { 0x4240, "reclock_pwm"}, /* Control for enabling reclocking of PWM signal , */\ + { 0x4250, "reclock_voltsense"}, /* Control for enabling reclocking of voltage sense signal, */\ + { 0x4281, "dpsalevel"}, /* DPSA threshold level , */\ + { 0x42a1, "dpsa_release"}, /* DPSA release time , */\ + { 0x42c0, "coincidence"}, /* Prevent simultaneously switching of output stage , */\ + { 0x42d0, "kickback"}, /* Prevent double pulses of output stage , */\ + { 0x4306, "drivebst"}, /* Drive bits to select the power transistor sections boost converter, */\ + { 0x4370, "boost_alg"}, /* Control for boost adaptive loop gain , */\ + { 0x4381, "boost_loopgain"}, /* DCDC boost loopgain setting , */\ + { 0x43a0, "ocptestbst"}, /* Boost OCP. For old ocp (ctrl_reversebst is 0); For new ocp (ctrl_reversebst is 1), */\ + { 0x43d0, "test_abistfft_enbl"}, /* FFT Coolflux , */\ + { 0x43e0, "bst_dcmbst"}, /* DCM mode control for DCDC during I2C direct control mode, */\ + { 0x43f0, "test_bcontrol"}, /* test_bcontrol , */\ + { 0x4400, "reversebst"}, /* OverCurrent Protection selection of power stage boost converter, */\ + { 0x4410, "sensetest"}, /* Test option for the sense NMOS in booster for current mode control., */\ + { 0x4420, "enbl_engagebst"}, /* Enable power stage of dcdc controller , */\ + { 0x4470, "enbl_slopecur"}, /* Enable bit of max-current dac , */\ + { 0x4480, "enbl_voutcomp"}, /* Enable vout comparators , */\ + { 0x4490, "enbl_voutcomp93"}, /* Enable vout-93 comparators , */\ + { 0x44a0, "enbl_voutcomp86"}, /* Enable vout-86 comparators , */\ + { 0x44b0, "enbl_hizcom"}, /* Enable hiz comparator , */\ + { 0x44c0, "enbl_peakcur"}, /* Enable peak current , */\ + { 0x44d0, "bypass_ovpglitch"}, /* Bypass OVP Glitch Filter , */\ + { 0x44e0, "enbl_windac"}, /* Enable window dac , */\ + { 0x44f0, "enbl_powerbst"}, /* Enable line of the powerstage , */\ + { 0x4507, "ocp_thr"}, /* OCP threshold level , */\ + { 0x4580, "bypass_glitchfilter"}, /* Bypass glitch filter , */\ + { 0x4590, "bypass_ovp"}, /* Bypass OVP , */\ + { 0x45a0, "bypass_uvp"}, /* Bypass UVP , */\ + { 0x45b0, "bypass_otp"}, /* Bypass OTP , */\ + { 0x45d0, "bypass_ocpcounter"}, /* Bypass OCP counter , */\ + { 0x45e0, "bypass_lost_clk"}, /* Bypass lost clock detector , */\ + { 0x45f0, "vpalarm"}, /* vpalarm (UVP/OUP handling) , */\ + { 0x4600, "bypass_gc"}, /* Bypasses the CS gain correction , */\ + { 0x4610, "cs_gain_control"}, /* Current sense gain control , */\ + { 0x4627, "cs_gain"}, /* Current sense gain , */\ + { 0x46a0, "bypass_lp"}, /* Bypass the low power filter inside temperature sensor, */\ + { 0x46b0, "bypass_pwmcounter"}, /* Bypass PWM Counter , */\ + { 0x46c0, "cs_negfixed"}, /* Current sense does not switch to neg , */\ + { 0x46d2, "cs_neghyst"}, /* Current sense switches to neg depending on hyseteris level, */\ + { 0x4700, "switch_fb"}, /* Current sense control switch_fb , */\ + { 0x4713, "se_hyst"}, /* Current sense control se_hyst , */\ + { 0x4754, "se_level"}, /* Current sense control se_level , */\ + { 0x47a5, "ktemp"}, /* Current sense control temperature compensation trimming, */\ + { 0x4800, "cs_negin"}, /* Current sense control negin , */\ + { 0x4810, "cs_sein"}, /* Current sense control cs_sein , */\ + { 0x4820, "cs_coincidence"}, /* Coincidence current sense , */\ + { 0x4830, "iddqtestbst"}, /* IDDQ testing in powerstage of DCDC boost converter, */\ + { 0x4840, "coincidencebst"}, /* Switch protection on to prevent simultaneously switching power stages bst and amp, */\ + { 0x4876, "delay_se_neg"}, /* delay of se and neg , */\ + { 0x48e1, "cs_ttrack"}, /* Sample and hold track time , */\ + { 0x4900, "bypass_clip"}, /* Bypass clip control , */\ + { 0x4920, "cf_cgate_off"}, /* Disable clock gating in the coolflux , */\ + { 0x4940, "clipfast"}, /* Clock selection for HW clipper for battery safeguard, */\ + { 0x4950, "cs_8ohm"}, /* 8 ohm mode for current sense (gain mode) , */\ + { 0x4974, "delay_clock_sh"}, /* delay_sh, tunes S7H delay , */\ + { 0x49c0, "inv_clksh"}, /* Invert the sample/hold clock for current sense ADC, */\ + { 0x49d0, "inv_neg"}, /* Invert neg signal , */\ + { 0x49e0, "inv_se"}, /* Invert se signal , */\ + { 0x49f0, "setse"}, /* Switches between Single Ended and differential mode; 1 is single ended, */\ + { 0x4a12, "adc10_sel"}, /* Select the input to convert the 10b ADC , */\ + { 0x4a60, "adc10_reset"}, /* Reset for ADC10 - I2C direct control mode , */\ + { 0x4a81, "adc10_test"}, /* Test mode selection signal for ADC10 - I2C direct control mode, */\ + { 0x4aa0, "bypass_lp_vbat"}, /* LP filter in batt sensor , */\ + { 0x4ae0, "dc_offset"}, /* Current sense decimator offset control , */\ + { 0x4af0, "tsense_hibias"}, /* Bit to set the biasing in temp sensor to high , */\ + { 0x4b00, "adc13_iset"}, /* MICADC setting of current consumption (debug use only), */\ + { 0x4b14, "adc13_gain"}, /* MICADC gain setting (two's complement format) , */\ + { 0x4b61, "adc13_slowdel"}, /* MICADC delay setting for internal clock (debug use only), */\ + { 0x4b83, "adc13_offset"}, /* MICADC offset setting , */\ + { 0x4bc0, "adc13_bsoinv"}, /* MICADC bit stream output invert mode for test , */\ + { 0x4bd0, "adc13_resonator_enable"}, /* MICADC give extra SNR with less stability (debug use only), */\ + { 0x4be0, "testmicadc"}, /* Mux at input of MICADC for test purpose , */\ + { 0x4c0f, "abist_offset"}, /* Offset control for ABIST testing , */\ + { 0x4d05, "windac"}, /* For testing direct control windac , */\ + { 0x4dc3, "pwm_dcc_cnt"}, /* control pwm duty cycle when enbl_pwm_dcc is 1 , */\ + { 0x4e04, "slopecur"}, /* For testing direct control slopecur , */\ + { 0x4e50, "ctrl_dem"}, /* Dynamic element matching control, rest of codes are optional, */\ + { 0x4ed0, "enbl_pwm_dcc"}, /* Enable direct control of pwm duty cycle , */\ + { 0x4f00, "bst_bypass_bstcur"}, /* Bypass control for boost current settings , */\ + { 0x4f10, "bst_bypass_bstfoldback"}, /* Bypass control for boost foldback , */\ + { 0x4f20, "bst_ctrl_azbst"}, /* Control of auto-zeroing of zero current comparator, */\ + { 0x5007, "gain"}, /* Gain setting of the gain multiplier , */\ + { 0x5081, "sourceb"}, /* PWM OUTB selection control , */\ + { 0x50a1, "sourcea"}, /* PWM OUTA selection control , */\ + { 0x50c1, "sourcebst"}, /* Sets the source of the pwmbst output to boost converter input for testing, */\ + { 0x50e0, "tdm_enable_loopback"}, /* TDM loopback test , */\ + { 0x5104, "pulselengthbst"}, /* Pulse length setting test input for boost converter, */\ + { 0x5150, "bypasslatchbst"}, /* Bypass latch in boost converter , */\ + { 0x5160, "invertbst"}, /* Invert pwmbst test signal , */\ + { 0x5174, "pulselength"}, /* Pulse length setting test input for amplifier , */\ + { 0x51c0, "bypasslatch"}, /* Bypass latch in PWM source selection module , */\ + { 0x51d0, "invertb"}, /* invert pwmb test signal , */\ + { 0x51e0, "inverta"}, /* invert pwma test signal , */\ + { 0x51f0, "bypass_ctrlloop"}, /* bypass_ctrlloop bypasses the control loop of the amplifier, */\ + { 0x5210, "test_rdsona"}, /* tbd for rdson testing , */\ + { 0x5220, "test_rdsonb"}, /* tbd for rdson testing , */\ + { 0x5230, "test_rdsonbst"}, /* tbd for rdson testing , */\ + { 0x5240, "test_cvia"}, /* tbd for rdson testing , */\ + { 0x5250, "test_cvib"}, /* tbd for rdson testing , */\ + { 0x5260, "test_cvibst"}, /* tbd for rdson testing , */\ + { 0x5306, "digimuxa_sel"}, /* DigimuxA input selection control (see Digimux list for details), */\ + { 0x5376, "digimuxb_sel"}, /* DigimuxB input selection control (see Digimux list for details), */\ + { 0x5400, "hs_mode"}, /* I2C high speed mode selection control , */\ + { 0x5412, "test_parametric_io"}, /* Control for parametric tests of IO cells , */\ + { 0x5440, "enbl_ringo"}, /* Enable ring oscillator control, for test purpose to check with ringo, */\ + { 0x5456, "digimuxc_sel"}, /* DigimuxC input selection control (see Digimux list for details), */\ + { 0x54c0, "dio_ehs"}, /* Slew control for DIO in output mode , */\ + { 0x54d0, "gainio_ehs"}, /* Slew control for GAINIO in output mode , */\ + { 0x550d, "enbl_amp"}, /* enbl_amp for testing to enable all analoge blocks in amplifier, */\ + { 0x5600, "use_direct_ctrls"}, /* Use direct controls to overrule several functions for testing - I2C direct control mode, */\ + { 0x5610, "rst_datapath"}, /* Reset datapath during direct control mode , */\ + { 0x5620, "rst_cgu"}, /* Reset CGU during durect control mode , */\ + { 0x5637, "enbl_ref"}, /* For testing to enable all analoge blocks in references, */\ + { 0x56b0, "enbl_engage"}, /* Enable output stage amplifier , */\ + { 0x56c0, "use_direct_clk_ctrl"}, /* use_direct_clk_ctrl, to overrule several functions direct for testing, */\ + { 0x56d0, "use_direct_pll_ctrl"}, /* use_direct_pll_ctrl, to overrule several functions direct for testing, */\ + { 0x5707, "anamux"}, /* Anamux control , */\ + { 0x57e0, "otptest"}, /* otptest, test mode otp amplifier , */\ + { 0x57f0, "reverse"}, /* 1b = Normal mode, slope is controlled , */\ + { 0x5813, "pll_selr"}, /* PLL pll_selr , */\ + { 0x5854, "pll_selp"}, /* PLL pll_selp , */\ + { 0x58a5, "pll_seli"}, /* PLL pll_seli , */\ + { 0x5950, "pll_mdec_msb"}, /* Most significant bits of pll_mdec[16] , */\ + { 0x5960, "pll_ndec_msb"}, /* Most significant bits of pll_ndec[9] , */\ + { 0x5970, "pll_frm"}, /* PLL pll_frm , */\ + { 0x5980, "pll_directi"}, /* PLL pll_directi , */\ + { 0x5990, "pll_directo"}, /* PLL pll_directo , */\ + { 0x59a0, "enbl_pll"}, /* PLL enbl_pll , */\ + { 0x59f0, "pll_bypass"}, /* PLL bypass , */\ + { 0x5a0f, "tsig_freq"}, /* Internal sinus test generator frequency control LSB bits, */\ + { 0x5b02, "tsig_freq_msb"}, /* Select internal sine wave generator, frequency control MSB bits, */\ + { 0x5b30, "inject_tsig"}, /* Control bit to switch to internal sinus test generator, */\ + { 0x5b44, "adc10_prog_sample"}, /* ADC10 program sample setting - I2C direct control mode, */\ + { 0x5c0f, "pll_mdec"}, /* PLL MDEC - I2C direct PLL control mode only , */\ + { 0x5d06, "pll_pdec"}, /* PLL PDEC - I2C direct PLL control mode only , */\ + { 0x5d78, "pll_ndec"}, /* PLL NDEC - I2C direct PLL control mode only , */\ + { 0x6007, "mtpkey1"}, /* 5Ah, 90d To access KEY1_Protected registers (Default for engineering), */\ + { 0x6185, "mtp_ecc_tcin"}, /* MTP ECC TCIN data , */\ + { 0x6203, "mtp_man_address_in"}, /* MTP address from I2C register for read/writing mtp in manual single word mode, */\ + { 0x6260, "mtp_ecc_eeb"}, /* Enable code bit generation (active low!) , */\ + { 0x6270, "mtp_ecc_ecb"}, /* Enable correction signal (active low!) , */\ + { 0x6280, "man_copy_mtp_to_iic"}, /* Start copying single word from mtp to I2C mtp register, */\ + { 0x6290, "man_copy_iic_to_mtp"}, /* Start copying single word from I2C mtp register to mtp, */\ + { 0x62a0, "auto_copy_mtp_to_iic"}, /* Start copying all the data from mtp to I2C mtp registers, */\ + { 0x62b0, "auto_copy_iic_to_mtp"}, /* Start copying data from I2C mtp registers to mtp , */\ + { 0x62d2, "mtp_speed_mode"}, /* MTP speed mode , */\ + { 0x6340, "mtp_direct_enable"}, /* mtp_direct_enable , */\ + { 0x6350, "mtp_direct_wr"}, /* mtp_direct_wr , */\ + { 0x6360, "mtp_direct_rd"}, /* mtp_direct_rd , */\ + { 0x6370, "mtp_direct_rst"}, /* mtp_direct_rst , */\ + { 0x6380, "mtp_direct_ers"}, /* mtp_direct_ers , */\ + { 0x6390, "mtp_direct_prg"}, /* mtp_direct_prg , */\ + { 0x63a0, "mtp_direct_epp"}, /* mtp_direct_epp , */\ + { 0x63b4, "mtp_direct_test"}, /* mtp_direct_test , */\ + { 0x640f, "mtp_man_data_in"}, /* Write data for MTP manual write , */\ + { 0x7000, "cf_rst_dsp"}, /* Reset CoolFlux DSP , */\ + { 0x7011, "cf_dmem"}, /* Target memory for access , */\ + { 0x7030, "cf_aif"}, /* Auto increment flag for memory-address , */\ + { 0x7040, "cf_int"}, /* CF Interrupt - auto clear , */\ + { 0x7087, "cf_req"}, /* CF request for accessing the 8 channels , */\ + { 0x710f, "cf_madd"}, /* Memory address , */\ + { 0x720f, "cf_mema"}, /* Activate memory access , */\ + { 0x7307, "cf_err"}, /* CF error flags , */\ + { 0x7387, "cf_ack"}, /* CF acknowledgement of the requests channels , */\ + { 0x8000, "calibration_onetime"}, /* Calibration schedule selection , */\ + { 0x8010, "calibr_ron_done"}, /* Calibration of RON status bit , */\ + { 0x8105, "calibr_vout_offset"}, /* calibr_vout_offset (DCDCoffset) 2's compliment (key1 protected), */\ + { 0x8163, "calibr_delta_gain"}, /* delta gain for vamp (alpha) 2's compliment (key1 protected), */\ + { 0x81a5, "calibr_offs_amp"}, /* offset for vamp (Ampoffset) 2's compliment (key1 protected), */\ + { 0x8207, "calibr_gain_cs"}, /* gain current sense (Imeasalpha) 2's compliment (key1 protected), */\ + { 0x8284, "calibr_temp_offset"}, /* temperature offset 2's compliment (key1 protected), */\ + { 0x82d2, "calibr_temp_gain"}, /* temperature gain 2's compliment (key1 protected) , */\ + { 0x830f, "calibr_ron"}, /* calibration value of the RON resistance of the coil, */\ + { 0x8505, "type_bits_hw"}, /* bit0 = disable function dcdcoff_mode ($09[7]) , */\ + { 0x8601, "type_bits_1_0_sw"}, /* MTP control SW , */\ + { 0x8681, "type_bits_9_8_sw"}, /* MTP control SW , */\ + { 0x870f, "type_bits2_sw"}, /* MTP-control SW2 , */\ + { 0x8806, "htol_iic_addr"}, /* 7-bit I2C address to be used during HTOL testing , */\ + { 0x8870, "htol_iic_addr_en"}, /* HTOL I2C_Address_Enable , */\ + { 0x8881, "ctrl_ovp_response"}, /* OVP response control , */\ + { 0x88a0, "disable_ovp_alarm_state"}, /* OVP alarm state control , */\ + { 0x88b0, "enbl_stretch_ovp"}, /* OVP alram strech control , */\ + { 0x88c0, "cf_debug_mode"}, /* Coolflux debug mode , */\ + { 0x8a0f, "production_data1"}, /* production_data1 , */\ + { 0x8b0f, "production_data2"}, /* production_data2 , */\ + { 0x8c0f, "production_data3"}, /* production_data3 , */\ + { 0x8d0f, "production_data4"}, /* production_data4 , */\ + { 0x8e0f, "production_data5"}, /* production_data5 , */\ + { 0x8f0f, "production_data6"}, /* production_data6 , */\ + { 0xffff,"Unknown bitfield enum" } /* not found */\ +}; + +enum TFA9896_irq { + TFA9896_irq_vdds = 0, + TFA9896_irq_plls = 1, + TFA9896_irq_ds = 2, + TFA9896_irq_vds = 3, + TFA9896_irq_uvds = 4, + TFA9896_irq_cds = 5, + TFA9896_irq_clks = 6, + TFA9896_irq_clips = 7, + TFA9896_irq_mtpb = 8, + TFA9896_irq_clk = 9, + TFA9896_irq_spks = 10, + TFA9896_irq_acs = 11, + TFA9896_irq_sws = 12, + TFA9896_irq_wds = 13, + TFA9896_irq_amps = 14, + TFA9896_irq_arefs = 15, + TFA9896_irq_err = 32, + TFA9896_irq_ack = 33, + TFA9896_irq_max = 34, + TFA9896_irq_all = -1 /* all irqs */}; + +#define TFA9896_IRQ_NAMETABLE static tfaIrqName_t TFA9896IrqNames[]= {\ + { 0, "VDDS"},\ + { 1, "PLLS"},\ + { 2, "DS"},\ + { 3, "VDS"},\ + { 4, "UVDS"},\ + { 5, "CDS"},\ + { 6, "CLKS"},\ + { 7, "CLIPS"},\ + { 8, "MTPB"},\ + { 9, "CLK"},\ + { 10, "SPKS"},\ + { 11, "ACS"},\ + { 12, "SWS"},\ + { 13, "WDS"},\ + { 14, "AMPS"},\ + { 15, "AREFS"},\ + { 16, "16"},\ + { 17, "17"},\ + { 18, "18"},\ + { 19, "19"},\ + { 20, "20"},\ + { 21, "21"},\ + { 22, "22"},\ + { 23, "23"},\ + { 24, "24"},\ + { 25, "25"},\ + { 26, "26"},\ + { 27, "27"},\ + { 28, "28"},\ + { 29, "29"},\ + { 30, "30"},\ + { 31, "31"},\ + { 32, "ERR"},\ + { 33, "ACK"},\ + { 34, "34"},\ +}; +#endif /* _TFA9896_TFAFIELDNAMES_H */ diff --git a/techpack/audio/asoc/codecs/tfa9874/tfa98xx.c b/techpack/audio/asoc/codecs/tfa9874/tfa98xx.c new file mode 100644 index 000000000000..4be3f0acc67a --- /dev/null +++ b/techpack/audio/asoc/codecs/tfa9874/tfa98xx.c @@ -0,0 +1,3336 @@ +/* + * tfa98xx.c tfa98xx codec module + * + * Copyright 2014-2017 NXP Semiconductors + * + * 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. + */ + +#define pr_fmt(fmt) "%s(): " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "config.h" +#include "tfa98xx.h" +#include "tfa.h" + +/* required for enum tfa9912_irq */ +#include "tfa98xx_tfafieldnames.h" + +#define TFA98XX_VERSION TFA98XX_API_REV_STR + +#define I2C_RETRIES 50 +#define I2C_RETRY_DELAY 5 /* ms */ + +#undef pr_info +#undef pr_debug +#define pr_info pr_err +#define pr_debug pr_err +#undef dev_dbg +#define dev_dbg dev_info + +struct tfa98xx *g_tfa98xx = NULL; +EXPORT_SYMBOL_GPL(g_tfa98xx); + +/* Change volume selection behavior: + * Uncomment following line to generate a profile change when updating + * a volume control (also changes to the profile of the modified volume + * control) + */ +/*#define TFA98XX_ALSA_CTRL_PROF_CHG_ON_VOL 1 +*/ + +/* Supported rates and data formats */ +#define TFA98XX_RATES SNDRV_PCM_RATE_8000_48000 +#define TFA98XX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) + +#define TF98XX_MAX_DSP_START_TRY_COUNT 10 + +extern int smartpa_present; + +/* data accessible by all instances */ +static struct kmem_cache *tfa98xx_cache = NULL; /* Memory pool used for DSP messages */ +/* Mutex protected data */ +static DEFINE_MUTEX(tfa98xx_mutex); +static LIST_HEAD(tfa98xx_device_list); +static int tfa98xx_device_count = 0; +static int tfa98xx_sync_count = 0; +static LIST_HEAD(profile_list); /* list of user selectable profiles */ +static int tfa98xx_mixer_profiles = 0; /* number of user selectable profiles */ +static int tfa98xx_mixer_profile = 0; /* current mixer profile */ +static struct snd_kcontrol_new *tfa98xx_controls; +static nxpTfaContainer_t *tfa98xx_container = NULL; + +static int tfa98xx_kmsg_regs = 0; +static int tfa98xx_ftrace_regs = 0; + +static char *fw_name = "tfa98xx.cnt"; +module_param(fw_name, charp, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(fw_name, "TFA98xx DSP firmware (container file) name."); + +static int trace_level = 0; +module_param(trace_level, int, S_IRUGO); +MODULE_PARM_DESC(trace_level, "TFA98xx debug trace level (0=off, bits:1=verbose,2=regdmesg,3=regftrace,4=timing)."); + +static char *dflt_prof_name = ""; +module_param(dflt_prof_name, charp, S_IRUGO); + +static int no_start = 0; +module_param(no_start, int, S_IRUGO); +MODULE_PARM_DESC(no_start, "do not start the work queue; for debugging via user\n"); + +static int no_reset = 0; +module_param(no_reset, int, S_IRUGO); +MODULE_PARM_DESC(no_reset, "do not use the reset line; for debugging via user\n"); + +static int pcm_sample_format = 0; +module_param(pcm_sample_format, int, S_IRUGO); +MODULE_PARM_DESC(pcm_sample_format, "PCM sample format: 0=S16_LE, 1=S24_LE, 2=S32_LE\n"); + +static int pcm_no_constraint = 0; +module_param(pcm_no_constraint, int, S_IRUGO); +MODULE_PARM_DESC(pcm_no_constraint, "do not use constraints for PCM parameters\n"); + +static void tfa98xx_tapdet_check_update(struct tfa98xx *tfa98xx); +static int tfa98xx_get_fssel(unsigned int rate); +static void tfa98xx_interrupt_enable(struct tfa98xx *tfa98xx, bool enable); + +static int get_profile_from_list(char *buf, int id); +static int get_profile_id_for_sr(int id, unsigned int rate); + +struct tfa98xx_rate { + unsigned int rate; + unsigned int fssel; +}; + +static const struct tfa98xx_rate rate_to_fssel[] = { + { 8000, 0 }, + { 11025, 1 }, + { 12000, 2 }, + { 16000, 3 }, + { 22050, 4 }, + { 24000, 5 }, + { 32000, 6 }, + { 44100, 7 }, + { 48000, 8 }, +}; + +static inline char *tfa_cont_profile_name(struct tfa98xx *tfa98xx, int prof_idx) +{ + if (tfa98xx->tfa->cnt == NULL) + return NULL; + return tfaContProfileName(tfa98xx->tfa->cnt, tfa98xx->tfa->dev_idx, prof_idx); +} + +static enum tfa_error tfa98xx_write_re25(struct tfa_device *tfa, int value) +{ + enum tfa_error err; + + /* clear MTPEX */ + err = tfa_dev_mtp_set(tfa, TFA_MTP_EX, 0); + if (err == tfa_error_ok) { + /* set RE25 in shadow regiser */ + err = tfa_dev_mtp_set(tfa, TFA_MTP_RE25_PRIM, value); + } + if (err == tfa_error_ok) { + /* set MTPEX to copy RE25 into MTP */ + err = tfa_dev_mtp_set(tfa, TFA_MTP_EX, 2); + } + + return err; +} + +/* Wrapper for tfa start */ +static enum tfa_error tfa98xx_tfa_start(struct tfa98xx *tfa98xx, int next_profile, int vstep) +{ + enum tfa_error err; + ktime_t start_time, stop_time; + u64 delta_time; + + if (trace_level & 8) { + start_time = ktime_get_boottime(); + } + + dev_info(&tfa98xx->i2c->dev, "tfa98xx_tfa_start enter\n"); + + err = tfa_dev_start(tfa98xx->tfa, next_profile, vstep); + + if (trace_level & 8) { + stop_time = ktime_get_boottime(); + delta_time = ktime_to_ns(ktime_sub(stop_time, start_time)); + do_div(delta_time, 1000); + dev_dbg(&tfa98xx->i2c->dev, "tfa_dev_start(%d,%d) time = %lld us\n", + next_profile, vstep, delta_time); + } + + if ((err == tfa_error_ok) && (tfa98xx->set_mtp_cal)) { + enum tfa_error err_cal; + err_cal = tfa98xx_write_re25(tfa98xx->tfa, tfa98xx->cal_data); + if (err_cal != tfa_error_ok) { + pr_err("Error, setting calibration value in mtp, err=%d\n", err_cal); + } else { + tfa98xx->set_mtp_cal = false; + pr_info("Calibration value (%d) set in mtp\n", + tfa98xx->cal_data); + } + } + + /* Check and update tap-detection state (in case of profile change) */ + tfa98xx_tapdet_check_update(tfa98xx); + + /* Remove sticky bit by reading it once */ + tfa_get_noclk(tfa98xx->tfa); + + /* A cold start erases the configuration, including interrupts setting. + * Restore it if required + */ + tfa98xx_interrupt_enable(tfa98xx, true); + + return err; +} + +static int tfa98xx_input_open(struct input_dev *dev) +{ + struct tfa98xx *tfa98xx = input_get_drvdata(dev); + dev_info(tfa98xx->codec->dev, "opening device file\n"); + + /* note: open function is called only once by the framework. + * No need to count number of open file instances. + */ + if (tfa98xx->dsp_fw_state != TFA98XX_DSP_FW_OK) { + dev_info(&tfa98xx->i2c->dev, + "DSP not loaded, cannot start tap-detection\n"); + return -EIO; + } + + /* enable tap-detection service */ + tfa98xx->tapdet_open = true; + tfa98xx_tapdet_check_update(tfa98xx); + + return 0; +} + +static void tfa98xx_input_close(struct input_dev *dev) +{ + struct tfa98xx *tfa98xx = input_get_drvdata(dev); + + dev_info(tfa98xx->codec->dev, "closing device file\n"); + + /* Note: close function is called if the device is unregistered */ + + /* disable tap-detection service */ + tfa98xx->tapdet_open = false; + tfa98xx_tapdet_check_update(tfa98xx); +} + +static int tfa98xx_register_inputdev(struct tfa98xx *tfa98xx) +{ + int err; + struct input_dev *input; + input = input_allocate_device(); + + if (!input) { + dev_err(tfa98xx->codec->dev, "Unable to allocate input device\n"); + return -ENOMEM; + } + + input->evbit[0] = BIT_MASK(EV_KEY); + input->keybit[BIT_WORD(BTN_0)] |= BIT_MASK(BTN_0); + input->keybit[BIT_WORD(BTN_1)] |= BIT_MASK(BTN_1); + input->keybit[BIT_WORD(BTN_2)] |= BIT_MASK(BTN_2); + input->keybit[BIT_WORD(BTN_3)] |= BIT_MASK(BTN_3); + input->keybit[BIT_WORD(BTN_4)] |= BIT_MASK(BTN_4); + input->keybit[BIT_WORD(BTN_5)] |= BIT_MASK(BTN_5); + input->keybit[BIT_WORD(BTN_6)] |= BIT_MASK(BTN_6); + input->keybit[BIT_WORD(BTN_7)] |= BIT_MASK(BTN_7); + input->keybit[BIT_WORD(BTN_8)] |= BIT_MASK(BTN_8); + input->keybit[BIT_WORD(BTN_9)] |= BIT_MASK(BTN_9); + + input->open = tfa98xx_input_open; + input->close = tfa98xx_input_close; + + input->name = "tfa98xx-tapdetect"; + + input->id.bustype = BUS_I2C; + input_set_drvdata(input, tfa98xx); + + err = input_register_device(input); + if (err) { + dev_err(tfa98xx->codec->dev, "Unable to register input device\n"); + goto err_free_dev; + } + + dev_dbg(tfa98xx->codec->dev, "Input device for tap-detection registered: %s\n", + input->name); + tfa98xx->input = input; + return 0; + +err_free_dev: + input_free_device(input); + return err; +} + +/* + * Check if an input device for tap-detection can and shall be registered. + * Register it if appropriate. + * If already registered, check if still relevant and remove it if necessary. + * unregister: true to request inputdev unregistration. + */ +static void __tfa98xx_inputdev_check_register(struct tfa98xx *tfa98xx, bool unregister) +{ + bool tap_profile = false; + unsigned int i; + for (i = 0; i < tfa_cnt_get_dev_nprof(tfa98xx->tfa); i++) { + if (strstr(tfa_cont_profile_name(tfa98xx, i), ".tap")) { + tap_profile = true; + tfa98xx->tapdet_profiles |= 1 << i; + dev_info(tfa98xx->codec->dev, + "found a tap-detection profile (%d - %s)\n", + i, tfa_cont_profile_name(tfa98xx, i)); + } + } + + /* Check for device support: + * - at device level + * - at container (profile) level + */ + if (!(tfa98xx->flags & TFA98XX_FLAG_TAPDET_AVAILABLE) || + !tap_profile || + unregister) { + /* No input device supported or required */ + if (tfa98xx->input) { + input_unregister_device(tfa98xx->input); + tfa98xx->input = NULL; + } + return; + } + + /* input device required */ + if (tfa98xx->input) + dev_info(tfa98xx->codec->dev, "Input device already registered, skipping\n"); + else + tfa98xx_register_inputdev(tfa98xx); +} + +static void tfa98xx_inputdev_check_register(struct tfa98xx *tfa98xx) +{ + __tfa98xx_inputdev_check_register(tfa98xx, false); +} + +static void tfa98xx_inputdev_unregister(struct tfa98xx *tfa98xx) +{ + __tfa98xx_inputdev_check_register(tfa98xx, true); +} + +#ifdef CONFIG_DEBUG_FS +/* OTC reporting + * Returns the MTP0 OTC bit value + */ +static int tfa98xx_dbgfs_otc_get(void *data, u64 *val) +{ + struct i2c_client *i2c = (struct i2c_client *)data; + struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); + int value; + + mutex_lock(&tfa98xx->dsp_lock); + value = tfa_dev_mtp_get(tfa98xx->tfa, TFA_MTP_OTC); + mutex_unlock(&tfa98xx->dsp_lock); + + if (value < 0) { + pr_err("[0x%x] Unable to check DSP access: %d\n", tfa98xx->i2c->addr, value); + return -EIO; + } + + *val = value; + pr_debug("[0x%x] OTC : %d\n", tfa98xx->i2c->addr, value); + + return 0; +} + +static int tfa98xx_dbgfs_otc_set(void *data, u64 val) +{ + struct i2c_client *i2c = (struct i2c_client *)data; + struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); + enum tfa_error err; + + if (val != 0 && val != 1) { + pr_err("[0x%x] Unexpected value %llu\n", tfa98xx->i2c->addr, val); + return -EINVAL; + } + + mutex_lock(&tfa98xx->dsp_lock); + err = tfa_dev_mtp_set(tfa98xx->tfa, TFA_MTP_OTC, val); + mutex_unlock(&tfa98xx->dsp_lock); + + if (err != tfa_error_ok) { + pr_err("[0x%x] Unable to check DSP access: %d\n", tfa98xx->i2c->addr, err); + return -EIO; + } + + pr_debug("[0x%x] OTC < %llu\n", tfa98xx->i2c->addr, val); + + return 0; +} + +static int tfa98xx_dbgfs_mtpex_get(void *data, u64 *val) +{ + struct i2c_client *i2c = (struct i2c_client *)data; + struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); + int value; + + mutex_lock(&tfa98xx->dsp_lock); + value = tfa_dev_mtp_get(tfa98xx->tfa, TFA_MTP_EX); + mutex_unlock(&tfa98xx->dsp_lock); + + if (value < 0) { + pr_err("[0x%x] Unable to check DSP access: %d\n", tfa98xx->i2c->addr, value); + return -EIO; + } + + + *val = value; + pr_debug("[0x%x] MTPEX : %d\n", tfa98xx->i2c->addr, value); + + return 0; +} + +static int tfa98xx_dbgfs_mtpex_set(void *data, u64 val) +{ + struct i2c_client *i2c = (struct i2c_client *)data; + struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); + enum tfa_error err; + + if (val != 0) { + pr_err("[0x%x] Can only clear MTPEX (0 value expected)\n", tfa98xx->i2c->addr); + return -EINVAL; + } + + mutex_lock(&tfa98xx->dsp_lock); + err = tfa_dev_mtp_set(tfa98xx->tfa, TFA_MTP_EX, val); + mutex_unlock(&tfa98xx->dsp_lock); + + if (err != tfa_error_ok) { + pr_err("[0x%x] Unable to check DSP access: %d\n", tfa98xx->i2c->addr, err); + return -EIO; + } + + pr_debug("[0x%x] MTPEX < 0\n", tfa98xx->i2c->addr); + + return 0; +} + +static int tfa98xx_dbgfs_temp_get(void *data, u64 *val) +{ + struct i2c_client *i2c = (struct i2c_client *)data; + struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); + + mutex_lock(&tfa98xx->dsp_lock); + *val = tfa98xx_get_exttemp(tfa98xx->tfa); + mutex_unlock(&tfa98xx->dsp_lock); + + pr_debug("[0x%x] TEMP : %llu\n", tfa98xx->i2c->addr, *val); + + return 0; +} + +static int tfa98xx_dbgfs_temp_set(void *data, u64 val) +{ + struct i2c_client *i2c = (struct i2c_client *)data; + struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); + + mutex_lock(&tfa98xx->dsp_lock); + tfa98xx_set_exttemp(tfa98xx->tfa, (short)val); + mutex_unlock(&tfa98xx->dsp_lock); + + pr_debug("[0x%x] TEMP < %llu\n", tfa98xx->i2c->addr, val); + + return 0; +} + +static ssize_t tfa98xx_dbgfs_start_set(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct i2c_client *i2c = file->private_data; + struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); + enum tfa_error ret; + char buf[32]; + const char ref[] = "please calibrate now"; + int buf_size; + + /* check string length, and account for eol */ + if (count > sizeof(ref) + 1 || count < (sizeof(ref) - 1)) + return -EINVAL; + + buf_size = min(count, (size_t)(sizeof(buf)-1)); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + buf[buf_size] = 0; + + /* Compare string, excluding the trailing \0 and the potentials eol */ + if (strncmp(buf, ref, sizeof(ref) - 1)) + return -EINVAL; + + mutex_lock(&tfa98xx->dsp_lock); + ret = tfa_calibrate(tfa98xx->tfa); + if (ret == tfa_error_ok) + ret = tfa98xx_tfa_start(tfa98xx, tfa98xx->profile, tfa98xx->vstep); + if (ret == tfa_error_ok) + tfa_dev_set_state(tfa98xx->tfa, TFA_STATE_UNMUTE); + mutex_unlock(&tfa98xx->dsp_lock); + + if (ret) { + pr_info("[0x%x] Calibration start failed (%d)\n", tfa98xx->i2c->addr, ret); + return -EIO; + } else { + pr_info("[0x%x] Calibration started\n", tfa98xx->i2c->addr); + } + + return count; +} + +static ssize_t tfa98xx_dbgfs_r_read(struct file *file, + char __user *user_buf, size_t count, + loff_t *ppos) +{ + struct i2c_client *i2c = file->private_data; + struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); + char *str; + uint16_t status; + int ret; + + mutex_lock(&tfa98xx->dsp_lock); + + /* Need to ensure DSP is access-able, use mtp read access for this + * purpose + */ + ret = tfa98xx_get_mtp(tfa98xx->tfa, &status); + if (ret) { + ret = -EIO; + pr_err("[0x%x] MTP read failed\n", tfa98xx->i2c->addr); + goto r_c_err; + } + + ret = tfaRunSpeakerCalibration(tfa98xx->tfa); + if (ret) { + ret = -EIO; + pr_err("[0x%x] calibration failed\n", tfa98xx->i2c->addr); + goto r_c_err; + } + + str = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!str) { + ret = -ENOMEM; + pr_err("[0x%x] memory allocation failed\n", tfa98xx->i2c->addr); + goto r_c_err; + } + + if (tfa98xx->tfa->spkr_count > 1) { + ret = snprintf(str, PAGE_SIZE, + "Prim:%d mOhms, Sec:%d mOhms\n", + tfa98xx->tfa->mohm[0], + tfa98xx->tfa->mohm[1]); + } else { + ret = snprintf(str, PAGE_SIZE, + "Prim:%d mOhms\n", + tfa98xx->tfa->mohm[0]); + } + + pr_info("[0x%x] calib_done: %s", tfa98xx->i2c->addr, str); + + if (ret < 0) + goto r_err; + + ret = simple_read_from_buffer(user_buf, count, ppos, str, ret); + +r_err: + kfree(str); +r_c_err: + mutex_unlock(&tfa98xx->dsp_lock); + return ret; +} + +static ssize_t tfa98xx_dbgfs_version_read(struct file *file, + char __user *user_buf, size_t count, + loff_t *ppos) +{ + char str[] = TFA98XX_VERSION "\n"; + int ret; + + ret = simple_read_from_buffer(user_buf, count, ppos, str, sizeof(str)); + + return ret; +} + +static ssize_t tfa98xx_dbgfs_dsp_state_get(struct file *file, + char __user *user_buf, size_t count, + loff_t *ppos) +{ + struct i2c_client *i2c = file->private_data; + struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); + int ret = 0; + char *str; + + switch (tfa98xx->dsp_init) { + case TFA98XX_DSP_INIT_STOPPED: + str = "Stopped\n"; + break; + case TFA98XX_DSP_INIT_RECOVER: + str = "Recover requested\n"; + break; + case TFA98XX_DSP_INIT_FAIL: + str = "Failed init\n"; + break; + case TFA98XX_DSP_INIT_PENDING: + str = "Pending init\n"; + break; + case TFA98XX_DSP_INIT_DONE: + str = "Init complete\n"; + break; + default: + str = "Invalid\n"; + } + + pr_info("[0x%x] dsp_state : %s\n", tfa98xx->i2c->addr, str); + + ret = simple_read_from_buffer(user_buf, count, ppos, str, strlen(str)); + return ret; +} + +static ssize_t tfa98xx_dbgfs_dsp_state_set(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct i2c_client *i2c = file->private_data; + struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); + enum tfa_error ret; + char buf[32]; + const char start_cmd[] = "start"; + const char stop_cmd[] = "stop"; + const char mon_start_cmd[] = "monitor start"; + const char mon_stop_cmd[] = "monitor stop"; + int buf_size; + + buf_size = min(count, (size_t)(sizeof(buf)-1)); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + buf[buf_size] = 0; + + /* Compare strings, excluding the trailing \0 */ + if (!strncmp(buf, start_cmd, sizeof(start_cmd) - 1)) { + pr_info("[0x%x] Manual triggering of dsp start...\n", tfa98xx->i2c->addr); + mutex_lock(&tfa98xx->dsp_lock); + ret = tfa98xx_tfa_start(tfa98xx, tfa98xx->profile, tfa98xx->vstep); + mutex_unlock(&tfa98xx->dsp_lock); + pr_debug("[0x%x] tfa_dev_start complete: %d\n", tfa98xx->i2c->addr, ret); + } else if (!strncmp(buf, stop_cmd, sizeof(stop_cmd) - 1)) { + pr_info("[0x%x] Manual triggering of dsp stop...\n", tfa98xx->i2c->addr); + mutex_lock(&tfa98xx->dsp_lock); + ret = tfa_dev_stop(tfa98xx->tfa); + mutex_unlock(&tfa98xx->dsp_lock); + pr_debug("[0x%x] tfa_dev_stop complete: %d\n", tfa98xx->i2c->addr, ret); + } else if (!strncmp(buf, mon_start_cmd, sizeof(mon_start_cmd) - 1)) { + pr_info("[0x%x] Manual start of monitor thread...\n", tfa98xx->i2c->addr); + queue_delayed_work(tfa98xx->tfa98xx_wq, + &tfa98xx->monitor_work, HZ); + } else if (!strncmp(buf, mon_stop_cmd, sizeof(mon_stop_cmd) - 1)) { + pr_info("[0x%x] Manual stop of monitor thread...\n", tfa98xx->i2c->addr); + cancel_delayed_work_sync(&tfa98xx->monitor_work); + } else { + return -EINVAL; + } + + return count; +} + +static ssize_t tfa98xx_dbgfs_fw_state_get(struct file *file, + char __user *user_buf, size_t count, + loff_t *ppos) +{ + struct i2c_client *i2c = file->private_data; + struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); + char *str; + + switch (tfa98xx->dsp_fw_state) { + case TFA98XX_DSP_FW_NONE: + str = "None\n"; + break; + case TFA98XX_DSP_FW_PENDING: + str = "Pending\n"; + break; + case TFA98XX_DSP_FW_FAIL: + str = "Fail\n"; + break; + case TFA98XX_DSP_FW_OK: + str = "Ok\n"; + break; + default: + str = "Invalid\n"; + } + + pr_info("[0x%x] fw_state : %s", tfa98xx->i2c->addr, str); + + return simple_read_from_buffer(user_buf, count, ppos, str, strlen(str)); +} + +static ssize_t tfa98xx_dbgfs_rpc_read(struct file *file, + char __user *user_buf, size_t count, + loff_t *ppos) +{ + struct i2c_client *i2c = file->private_data; + struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); + int ret = 0; + uint8_t *buffer; + enum Tfa98xx_Error error; + + if (tfa98xx->tfa == NULL) { + pr_debug("[0x%x] dsp is not available\n", tfa98xx->i2c->addr); + return -ENODEV; + } + + if (count == 0) + return 0; + + buffer = kmalloc(count, GFP_KERNEL); + if (buffer == NULL) { + pr_debug("[0x%x] can not allocate memory\n", tfa98xx->i2c->addr); + return -ENOMEM; + } + + mutex_lock(&tfa98xx->dsp_lock); + error = dsp_msg_read(tfa98xx->tfa, count, buffer); + mutex_unlock(&tfa98xx->dsp_lock); + if (error != Tfa98xx_Error_Ok) { + pr_debug("[0x%x] dsp_msg_read error: %d\n", tfa98xx->i2c->addr, error); + kfree(buffer); + return -EFAULT; + } + + ret = copy_to_user(user_buf, buffer, count); + kfree(buffer); + if (ret) + return -EFAULT; + + *ppos += count; + return count; +} + +static ssize_t tfa98xx_dbgfs_rpc_send(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct i2c_client *i2c = file->private_data; + struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); + nxpTfaFileDsc_t *msg_file; + enum Tfa98xx_Error error; + int err = 0; + + if (tfa98xx->tfa == NULL) { + pr_debug("[0x%x] dsp is not available\n", tfa98xx->i2c->addr); + return -ENODEV; + } + + if (count == 0) + return 0; + + /* msg_file.name is not used */ + msg_file = kmalloc(count + sizeof(nxpTfaFileDsc_t), GFP_KERNEL); + if ( msg_file == NULL ) { + pr_debug("[0x%x] can not allocate memory\n", tfa98xx->i2c->addr); + return -ENOMEM; + } + msg_file->size = count; + + if (copy_from_user(msg_file->data, user_buf, count)) + return -EFAULT; + + mutex_lock(&tfa98xx->dsp_lock); + if ((msg_file->data[0] == 'M') && (msg_file->data[1] == 'G')) { + error = tfaContWriteFile(tfa98xx->tfa, msg_file, 0, 0); /* int vstep_idx, int vstep_msg_idx both 0 */ + if (error != Tfa98xx_Error_Ok) { + pr_debug("[0x%x] tfaContWriteFile error: %d\n", tfa98xx->i2c->addr, error); + err = -EIO; + } + } else { + error = dsp_msg(tfa98xx->tfa, msg_file->size, msg_file->data); + if (error != Tfa98xx_Error_Ok) { + pr_debug("[0x%x] dsp_msg error: %d\n", tfa98xx->i2c->addr, error); + err = -EIO; + } + } + mutex_unlock(&tfa98xx->dsp_lock); + + kfree(msg_file); + + if (err) + return err; + return count; +} +/* -- RPC */ + +static int tfa98xx_dbgfs_pga_gain_get(void *data, u64 *val) +{ + struct i2c_client *i2c = (struct i2c_client *)data; + struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); + unsigned int value; + + value = tfa_get_pga_gain(tfa98xx->tfa); + if (value < 0) + return -EINVAL; + + *val = value; + return 0; +} + +static int tfa98xx_dbgfs_pga_gain_set(void *data, u64 val) +{ + struct i2c_client *i2c = (struct i2c_client *)data; + struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); + uint16_t value; + int err; + + value = val & 0xffff; + if (value > 7) + return -EINVAL; + + err = tfa_set_pga_gain(tfa98xx->tfa, value); + if (err < 0) + return -EINVAL; + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(tfa98xx_dbgfs_calib_otc_fops, tfa98xx_dbgfs_otc_get, + tfa98xx_dbgfs_otc_set, "%llu\n"); +DEFINE_SIMPLE_ATTRIBUTE(tfa98xx_dbgfs_calib_mtpex_fops, tfa98xx_dbgfs_mtpex_get, + tfa98xx_dbgfs_mtpex_set, "%llu\n"); +DEFINE_SIMPLE_ATTRIBUTE(tfa98xx_dbgfs_calib_temp_fops, tfa98xx_dbgfs_temp_get, + tfa98xx_dbgfs_temp_set, "%llu\n"); + +DEFINE_SIMPLE_ATTRIBUTE(tfa98xx_dbgfs_pga_gain_fops, tfa98xx_dbgfs_pga_gain_get, + tfa98xx_dbgfs_pga_gain_set, "%llu\n"); + +static const struct file_operations tfa98xx_dbgfs_calib_start_fops = { + .open = simple_open, + .write = tfa98xx_dbgfs_start_set, + .llseek = default_llseek, +}; + +static const struct file_operations tfa98xx_dbgfs_r_fops = { + .open = simple_open, + .read = tfa98xx_dbgfs_r_read, + .llseek = default_llseek, +}; + +static const struct file_operations tfa98xx_dbgfs_version_fops = { + .open = simple_open, + .read = tfa98xx_dbgfs_version_read, + .llseek = default_llseek, +}; + +static const struct file_operations tfa98xx_dbgfs_dsp_state_fops = { + .open = simple_open, + .read = tfa98xx_dbgfs_dsp_state_get, + .write = tfa98xx_dbgfs_dsp_state_set, + .llseek = default_llseek, +}; + +static const struct file_operations tfa98xx_dbgfs_fw_state_fops = { + .open = simple_open, + .read = tfa98xx_dbgfs_fw_state_get, + .llseek = default_llseek, +}; + +static const struct file_operations tfa98xx_dbgfs_rpc_fops = { + .open = simple_open, + .read = tfa98xx_dbgfs_rpc_read, + .write = tfa98xx_dbgfs_rpc_send, + .llseek = default_llseek, +}; + +static void tfa98xx_debug_init(struct tfa98xx *tfa98xx, struct i2c_client *i2c) +{ + char name[50]; + + scnprintf(name, MAX_CONTROL_NAME, "%s-%x", i2c->name, i2c->addr); + tfa98xx->dbg_dir = debugfs_create_dir(name, NULL); + debugfs_create_file("OTC", S_IRUGO|S_IWUGO, tfa98xx->dbg_dir, + i2c, &tfa98xx_dbgfs_calib_otc_fops); + debugfs_create_file("MTPEX", S_IRUGO|S_IWUGO, tfa98xx->dbg_dir, + i2c, &tfa98xx_dbgfs_calib_mtpex_fops); + debugfs_create_file("TEMP", S_IRUGO|S_IWUGO, tfa98xx->dbg_dir, + i2c, &tfa98xx_dbgfs_calib_temp_fops); + debugfs_create_file("calibrate", S_IRUGO|S_IWUGO, tfa98xx->dbg_dir, + i2c, &tfa98xx_dbgfs_calib_start_fops); + debugfs_create_file("R", S_IRUGO, tfa98xx->dbg_dir, + i2c, &tfa98xx_dbgfs_r_fops); + debugfs_create_file("version", S_IRUGO, tfa98xx->dbg_dir, + i2c, &tfa98xx_dbgfs_version_fops); + debugfs_create_file("dsp-state", S_IRUGO|S_IWUGO, tfa98xx->dbg_dir, + i2c, &tfa98xx_dbgfs_dsp_state_fops); + debugfs_create_file("fw-state", S_IRUGO|S_IWUGO, tfa98xx->dbg_dir, + i2c, &tfa98xx_dbgfs_fw_state_fops); + debugfs_create_file("rpc", S_IRUGO|S_IWUGO, tfa98xx->dbg_dir, + i2c, &tfa98xx_dbgfs_rpc_fops); + + if (tfa98xx->flags & TFA98XX_FLAG_SAAM_AVAILABLE) { + dev_dbg(tfa98xx->dev, "Adding pga_gain debug interface\n"); + debugfs_create_file("pga_gain", S_IRUGO, tfa98xx->dbg_dir, + tfa98xx->i2c, + &tfa98xx_dbgfs_pga_gain_fops); + } +} + +static void tfa98xx_debug_remove(struct tfa98xx *tfa98xx) +{ + if (tfa98xx->dbg_dir) + debugfs_remove_recursive(tfa98xx->dbg_dir); +} +#endif + + +/* copies the profile basename (i.e. part until .) into buf */ +static void get_profile_basename(char* buf, char* profile) +{ + int cp_len = 0, idx = 0; + char *pch; + + pch = strchr(profile, '.'); + idx = pch - profile; + cp_len = (pch != NULL) ? idx : (int) strlen(profile); + memcpy(buf, profile, cp_len); + buf[cp_len] = 0; +} + +/* return the profile name accociated with id from the profile list */ +static int get_profile_from_list(char *buf, int id) +{ + struct tfa98xx_baseprofile *bprof; + + list_for_each_entry(bprof, &profile_list, list) { + if (bprof->item_id == id) { + strcpy(buf, bprof->basename); + return 0; + } + } + + return -1; +} + +/* search for the profile in the profile list */ +static int is_profile_in_list(char *profile, int len) +{ + struct tfa98xx_baseprofile *bprof; + + list_for_each_entry(bprof, &profile_list, list) { + + if ((len == bprof->len) && (0 == strncmp(bprof->basename, profile, len))) + return 1; + } + + return 0; +} + +/* + * for the profile with id, look if the requested samplerate is + * supported, if found return the (container)profile for this + * samplerate, on error or if not found return -1 + */ +static int get_profile_id_for_sr(int id, unsigned int rate) +{ + int idx = 0; + struct tfa98xx_baseprofile *bprof; + + list_for_each_entry(bprof, &profile_list, list) { + if (id == bprof->item_id) { + idx = tfa98xx_get_fssel(rate); + if (idx < 0) { + /* samplerate not supported */ + return -1; + } + + return bprof->sr_rate_sup[idx]; + } + } + + /* profile not found */ + return -1; +} + +/* check if this profile is a calibration profile */ +static int is_calibration_profile(char *profile) +{ + if (strstr(profile, ".cal") != NULL) + return 1; + return 0; +} + +/* + * adds the (container)profile index of the samplerate found in + * the (container)profile to a fixed samplerate table in the (mixer)profile + */ +static int add_sr_to_profile(struct tfa98xx *tfa98xx, char *basename, int len, int profile) +{ + struct tfa98xx_baseprofile *bprof; + int idx = 0; + unsigned int sr = 0; + + list_for_each_entry(bprof, &profile_list, list) { + if ((len == bprof->len) && (0 == strncmp(bprof->basename, basename, len))) { + /* add supported samplerate for this profile */ + sr = tfa98xx_get_profile_sr(tfa98xx->tfa, profile); + if (!sr) { + pr_err("unable to identify supported sample rate for %s\n", bprof->basename); + return -1; + } + + /* get the index for this samplerate */ + idx = tfa98xx_get_fssel(sr); + if (idx < 0 || idx >= TFA98XX_NUM_RATES) { + pr_err("invalid index for samplerate %d\n", idx); + return -1; + } + + /* enter the (container)profile for this samplerate at the corresponding index */ + bprof->sr_rate_sup[idx] = profile; + + pr_info("added profile:samplerate = [%d:%d] for mixer profile: %s\n", profile, sr, bprof->basename); + } + } + + return 0; +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,16,0) +static struct snd_soc_codec *snd_soc_kcontrol_codec(struct snd_kcontrol *kcontrol) +{ + return snd_kcontrol_chip(kcontrol); +} +#endif + +static int tfa98xx_get_vstep(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(codec); + int mixer_profile = kcontrol->private_value; + int ret = 0; + int profile; + + profile = get_profile_id_for_sr(mixer_profile, tfa98xx->rate); + if (profile < 0) { + pr_err("tfa98xx: tfa98xx_get_vstep: invalid profile %d (mixer_profile=%d, rate=%d)\n", profile, mixer_profile, tfa98xx->rate); + return -EINVAL; + } + + mutex_lock(&tfa98xx_mutex); + list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { + int vstep = tfa98xx->prof_vsteps[profile]; + + ucontrol->value.integer.value[tfa98xx->tfa->dev_idx] = + tfacont_get_max_vstep(tfa98xx->tfa, profile) + - vstep - 1; + } + mutex_unlock(&tfa98xx_mutex); + + return ret; +} + +static int tfa98xx_set_vstep(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(codec); + int mixer_profile = kcontrol->private_value; + int profile; + int err = 0; + int change = 0; + + if (no_start != 0) + return 0; + + profile = get_profile_id_for_sr(mixer_profile, tfa98xx->rate); + if (profile < 0) { + pr_err("tfa98xx: tfa98xx_set_vstep: invalid profile %d (mixer_profile=%d, rate=%d)\n", profile, mixer_profile, tfa98xx->rate); + return -EINVAL; + } + + mutex_lock(&tfa98xx_mutex); + list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { + int vstep, vsteps; + int ready = 0; + int new_vstep; + int value = ucontrol->value.integer.value[tfa98xx->tfa->dev_idx]; + + vstep = tfa98xx->prof_vsteps[profile]; + vsteps = tfacont_get_max_vstep(tfa98xx->tfa, profile); + + if (vstep == vsteps - value - 1) + continue; + + new_vstep = vsteps - value - 1; + + if (new_vstep < 0) + new_vstep = 0; + + tfa98xx->prof_vsteps[profile] = new_vstep; + +#ifndef TFA98XX_ALSA_CTRL_PROF_CHG_ON_VOL + if (profile == tfa98xx->profile) { +#endif + /* this is the active profile, program the new vstep */ + tfa98xx->vstep = new_vstep; + mutex_lock(&tfa98xx->dsp_lock); + tfa98xx_dsp_system_stable(tfa98xx->tfa, &ready); + + if (ready) { + err = tfa98xx_tfa_start(tfa98xx, tfa98xx->profile, tfa98xx->vstep); + if (err) { + pr_err("Write vstep error: %d\n", err); + } else { + pr_info("Succesfully changed vstep index!\n"); + change = 1; + } + } + + mutex_unlock(&tfa98xx->dsp_lock); +#ifndef TFA98XX_ALSA_CTRL_PROF_CHG_ON_VOL + } +#endif + pr_info("%d: vstep:%d, (control value: %d) - profile %d\n", + tfa98xx->tfa->dev_idx, new_vstep, value, profile); + } + + if (change) { + list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { + mutex_lock(&tfa98xx->dsp_lock); + tfa_dev_set_state(tfa98xx->tfa, TFA_STATE_UNMUTE); + mutex_unlock(&tfa98xx->dsp_lock); + } + } + + mutex_unlock(&tfa98xx_mutex); + + return change; +} + +static int tfa98xx_info_vstep(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(codec); + + int mixer_profile = tfa98xx_mixer_profile; + int profile = get_profile_id_for_sr(mixer_profile, tfa98xx->rate); + if (profile < 0) { + pr_err("tfa98xx: tfa98xx_info_vstep: invalid profile %d (mixer_profile=%d, rate=%d)\n", profile, mixer_profile, tfa98xx->rate); + return -EINVAL; + } + + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + mutex_lock(&tfa98xx_mutex); + uinfo->count = tfa98xx_device_count; + mutex_unlock(&tfa98xx_mutex); + uinfo->value.integer.min = 0; + uinfo->value.integer.max = max(0, tfacont_get_max_vstep(tfa98xx->tfa, profile) - 1); + pr_info("vsteps count: %d [prof=%d]\n", tfacont_get_max_vstep(tfa98xx->tfa, profile), + profile); + return 0; +} + +static int tfa98xx_get_profile(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + mutex_lock(&tfa98xx_mutex); + ucontrol->value.integer.value[0] = tfa98xx_mixer_profile; + mutex_unlock(&tfa98xx_mutex); + + return 0; +} + +static int tfa98xx_set_profile(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(codec); + int change = 0; + int new_profile; + int prof_idx; + int profile_count = tfa98xx_mixer_profiles; + int profile = tfa98xx_mixer_profile; + + if (no_start != 0) + return 0; + + new_profile = ucontrol->value.integer.value[0]; + if (new_profile == profile) + return 0; + + if ((new_profile < 0) || (new_profile >= profile_count)) { + pr_err("not existing profile (%d)\n", new_profile); + return -EINVAL; + } + + /* get the container profile for the requested sample rate */ + prof_idx = get_profile_id_for_sr(new_profile, tfa98xx->rate); + if (prof_idx < 0) { + pr_err("tfa98xx: sample rate [%d] not supported for this mixer profile [%d].\n", tfa98xx->rate, new_profile); + return 0; + } + pr_debug("selected container profile [%d]\n", prof_idx); + + /* update mixer profile */ + tfa98xx_mixer_profile = new_profile; + + mutex_lock(&tfa98xx_mutex); + list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { + + /* update 'real' profile (container profile) */ + tfa98xx->profile = prof_idx; + tfa98xx->vstep = tfa98xx->prof_vsteps[prof_idx]; + + /* Flag DSP as invalidated as the profile change may invalidate the + * current DSP configuration. That way, further stream start can + * trigger a tfa_dev_start. + */ + tfa98xx->dsp_init = TFA98XX_DSP_INIT_INVALIDATED; + } + + + mutex_unlock(&tfa98xx_mutex); + + return change; +} + +static int tfa98xx_info_profile(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + char profile_name[MAX_CONTROL_NAME] = {0}; + int count = tfa98xx_mixer_profiles, err = -1; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = count; + + if (uinfo->value.enumerated.item >= count) + uinfo->value.enumerated.item = count - 1; + + err = get_profile_from_list(profile_name, uinfo->value.enumerated.item); + if (err != 0) + return -EINVAL; + + strcpy(uinfo->value.enumerated.name, profile_name); + + return 0; +} + +static int tfa98xx_info_stop_ctl(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + mutex_lock(&tfa98xx_mutex); + uinfo->count = tfa98xx_device_count; + mutex_unlock(&tfa98xx_mutex); + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + + return 0; +} + +static int tfa98xx_get_stop_ctl(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tfa98xx *tfa98xx; + + mutex_lock(&tfa98xx_mutex); + list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { + ucontrol->value.integer.value[tfa98xx->tfa->dev_idx] = 0; + } + mutex_unlock(&tfa98xx_mutex); + + return 0; +} + +static int tfa98xx_set_stop_ctl(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tfa98xx *tfa98xx; + + mutex_lock(&tfa98xx_mutex); + list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { + int ready = 0; + int i = tfa98xx->tfa->dev_idx; + + pr_info("%d: %ld\n", i, ucontrol->value.integer.value[i]); + + tfa98xx_dsp_system_stable(tfa98xx->tfa, &ready); + + if ((ucontrol->value.integer.value[i] != 0) && ready) { + cancel_delayed_work_sync(&tfa98xx->monitor_work); + + cancel_delayed_work_sync(&tfa98xx->init_work); + if (tfa98xx->dsp_fw_state != TFA98XX_DSP_FW_OK) + continue; + + mutex_lock(&tfa98xx->dsp_lock); + tfa_dev_stop(tfa98xx->tfa); + tfa98xx->dsp_init = TFA98XX_DSP_INIT_STOPPED; + mutex_unlock(&tfa98xx->dsp_lock); + } + + ucontrol->value.integer.value[i] = 0; + } + mutex_unlock(&tfa98xx_mutex); + + return 1; +} + +static int tfa98xx_info_cal_ctl(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + mutex_lock(&tfa98xx_mutex); + uinfo->count = tfa98xx_device_count; + mutex_unlock(&tfa98xx_mutex); + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 0xffff; /* 16 bit value */ + + return 0; +} + +static int tfa98xx_set_cal_ctl(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tfa98xx *tfa98xx; + + mutex_lock(&tfa98xx_mutex); + list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { + enum tfa_error err; + int i = tfa98xx->tfa->dev_idx; + + tfa98xx->cal_data = (uint16_t)ucontrol->value.integer.value[i]; + + mutex_lock(&tfa98xx->dsp_lock); + err = tfa98xx_write_re25(tfa98xx->tfa, tfa98xx->cal_data); + tfa98xx->set_mtp_cal = (err != tfa_error_ok); + if (tfa98xx->set_mtp_cal == false) { + pr_info("Calibration value (%d) set in mtp\n", + tfa98xx->cal_data); + } + mutex_unlock(&tfa98xx->dsp_lock); + } + mutex_unlock(&tfa98xx_mutex); + + return 1; +} + +static int tfa98xx_get_cal_ctl(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct tfa98xx *tfa98xx; + + mutex_lock(&tfa98xx_mutex); + list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { + mutex_lock(&tfa98xx->dsp_lock); + ucontrol->value.integer.value[tfa98xx->tfa->dev_idx] = tfa_dev_mtp_get(tfa98xx->tfa, TFA_MTP_RE25_PRIM); + mutex_unlock(&tfa98xx->dsp_lock); + } + mutex_unlock(&tfa98xx_mutex); + + return 0; +} + +static int tfa98xx_create_controls(struct tfa98xx *tfa98xx) +{ + int prof, nprof, mix_index = 0; + int nr_controls = 0, id = 0; + char *name; + struct tfa98xx_baseprofile *bprofile; + + /* Create the following controls: + * - enum control to select the active profile + * - one volume control for each profile hosting a vstep + * - Stop control on TFA1 devices + */ + + nr_controls = 2; /* Profile and stop control */ + + if (tfa98xx->flags & TFA98XX_FLAG_CALIBRATION_CTL) + nr_controls += 1; /* calibration */ + + /* allocate the tfa98xx_controls base on the nr of profiles */ + nprof = tfa_cnt_get_dev_nprof(tfa98xx->tfa); + for (prof = 0; prof < nprof; prof++) { + if (tfacont_get_max_vstep(tfa98xx->tfa, prof)) + nr_controls++; /* Playback Volume control */ + } + + tfa98xx_controls = devm_kzalloc(tfa98xx->codec->dev, + nr_controls * sizeof(tfa98xx_controls[0]), GFP_KERNEL); + if (!tfa98xx_controls) + return -ENOMEM; + + /* Create a mixer item for selecting the active profile */ + name = devm_kzalloc(tfa98xx->codec->dev, MAX_CONTROL_NAME, GFP_KERNEL); + if (!name) + return -ENOMEM; + scnprintf(name, MAX_CONTROL_NAME, "%s Profile", tfa98xx->fw.name); + tfa98xx_controls[mix_index].name = name; + tfa98xx_controls[mix_index].iface = SNDRV_CTL_ELEM_IFACE_MIXER; + tfa98xx_controls[mix_index].info = tfa98xx_info_profile; + tfa98xx_controls[mix_index].get = tfa98xx_get_profile; + tfa98xx_controls[mix_index].put = tfa98xx_set_profile; + + // tfa98xx_controls[mix_index].private_value = profs; /* save number of profiles */ + mix_index++; + + /* create mixer items for each profile that has volume */ + for (prof = 0; prof < nprof; prof++) { + /* create an new empty profile */ + bprofile = devm_kzalloc(tfa98xx->codec->dev, sizeof(*bprofile), GFP_KERNEL); + if (!bprofile) + return -ENOMEM; + + bprofile->len = 0; + bprofile->item_id = -1; + INIT_LIST_HEAD(&bprofile->list); + + /* copy profile name into basename until the . */ + get_profile_basename(bprofile->basename, tfa_cont_profile_name(tfa98xx, prof)); + bprofile->len = strlen(bprofile->basename); + + /* + * search the profile list for a profile with basename, if it is not found then + * add it to the list and add a new mixer control (if it has vsteps) + * also, if it is a calibration profile, do not add it to the list + */ + if ((is_profile_in_list(bprofile->basename, bprofile->len) == 0) && + is_calibration_profile(tfa_cont_profile_name(tfa98xx, prof)) == 0) { + /* the profile is not present, add it to the list */ + list_add(&bprofile->list, &profile_list); + bprofile->item_id = id++; + + pr_info("profile added [%d]: %s\n", bprofile->item_id, bprofile->basename); + + if (tfacont_get_max_vstep(tfa98xx->tfa, prof)) { + name = devm_kzalloc(tfa98xx->codec->dev, MAX_CONTROL_NAME, GFP_KERNEL); + if (!name) + return -ENOMEM; + + scnprintf(name, MAX_CONTROL_NAME, "%s %s Playback Volume", + tfa98xx->fw.name, bprofile->basename); + + tfa98xx_controls[mix_index].name = name; + tfa98xx_controls[mix_index].iface = SNDRV_CTL_ELEM_IFACE_MIXER; + tfa98xx_controls[mix_index].info = tfa98xx_info_vstep; + tfa98xx_controls[mix_index].get = tfa98xx_get_vstep; + tfa98xx_controls[mix_index].put = tfa98xx_set_vstep; + tfa98xx_controls[mix_index].private_value = bprofile->item_id; /* save profile index */ + mix_index++; + } + } + + /* look for the basename profile in the list of mixer profiles and add the + container profile index to the supported samplerates of this mixer profile */ + add_sr_to_profile(tfa98xx, bprofile->basename, bprofile->len, prof); + } + + /* set the number of user selectable profiles in the mixer */ + tfa98xx_mixer_profiles = id; + + /* Create a mixer item for stop control on TFA1 */ + name = devm_kzalloc(tfa98xx->codec->dev, MAX_CONTROL_NAME, GFP_KERNEL); + if (!name) + return -ENOMEM; + + scnprintf(name, MAX_CONTROL_NAME, "%s Stop", tfa98xx->fw.name); + tfa98xx_controls[mix_index].name = name; + tfa98xx_controls[mix_index].iface = SNDRV_CTL_ELEM_IFACE_MIXER; + tfa98xx_controls[mix_index].info = tfa98xx_info_stop_ctl; + tfa98xx_controls[mix_index].get = tfa98xx_get_stop_ctl; + tfa98xx_controls[mix_index].put = tfa98xx_set_stop_ctl; + mix_index++; + + if (tfa98xx->flags & TFA98XX_FLAG_CALIBRATION_CTL) { + name = devm_kzalloc(tfa98xx->codec->dev, MAX_CONTROL_NAME, GFP_KERNEL); + if (!name) + return -ENOMEM; + + scnprintf(name, MAX_CONTROL_NAME, "%s Calibration", tfa98xx->fw.name); + tfa98xx_controls[mix_index].name = name; + tfa98xx_controls[mix_index].iface = SNDRV_CTL_ELEM_IFACE_MIXER; + tfa98xx_controls[mix_index].info = tfa98xx_info_cal_ctl; + tfa98xx_controls[mix_index].get = tfa98xx_get_cal_ctl; + tfa98xx_controls[mix_index].put = tfa98xx_set_cal_ctl; + mix_index++; + } + + return snd_soc_add_codec_controls(tfa98xx->codec, + tfa98xx_controls, mix_index); +} + +static void *tfa98xx_devm_kstrdup(struct device *dev, char *buf) +{ + char *str = devm_kzalloc(dev, strlen(buf) + 1, GFP_KERNEL); + if (!str) + return str; + memcpy(str, buf, strlen(buf)); + return str; +} + +static int tfa98xx_append_i2c_address(struct device *dev, + struct i2c_client *i2c, + struct snd_soc_dapm_widget *widgets, + int num_widgets, + struct snd_soc_dai_driver *dai_drv, + int num_dai) +{ + char buf[50]; + int i; + int i2cbus = i2c->adapter->nr; + int addr = i2c->addr; + if (dai_drv && num_dai > 0) + for(i = 0; i < num_dai; i++) { + snprintf(buf, 50, "%s-%x-%x",dai_drv[i].name, i2cbus, + addr); + dai_drv[i].name = tfa98xx_devm_kstrdup(dev, buf); + + snprintf(buf, 50, "%s-%x-%x", + dai_drv[i].playback.stream_name, + i2cbus, addr); + dai_drv[i].playback.stream_name = tfa98xx_devm_kstrdup(dev, buf); + + snprintf(buf, 50, "%s-%x-%x", + dai_drv[i].capture.stream_name, + i2cbus, addr); + dai_drv[i].capture.stream_name = tfa98xx_devm_kstrdup(dev, buf); + } + + /* the idea behind this is convert: + * SND_SOC_DAPM_AIF_IN("AIF IN", "AIF Playback", 0, SND_SOC_NOPM, 0, 0), + * into: + * SND_SOC_DAPM_AIF_IN("AIF IN", "AIF Playback-2-36", 0, SND_SOC_NOPM, 0, 0), + */ + if (widgets && num_widgets > 0) + for(i = 0; i < num_widgets; i++) { + if(!widgets[i].sname) + continue; + if((widgets[i].id == snd_soc_dapm_aif_in) + || (widgets[i].id == snd_soc_dapm_aif_out)) { + snprintf(buf, 50, "%s-%x-%x", widgets[i].sname, + i2cbus, addr); + widgets[i].sname = tfa98xx_devm_kstrdup(dev, buf); + } + } + + return 0; +} + +static struct snd_soc_dapm_widget tfa98xx_dapm_widgets_common[] = { + /* Stream widgets */ + SND_SOC_DAPM_AIF_IN("AIF IN", "AIF Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF OUT", "AIF Capture", 0, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_OUTPUT("OUTL"), + SND_SOC_DAPM_INPUT("AEC Loopback"), +}; + +static struct snd_soc_dapm_widget tfa98xx_dapm_widgets_stereo[] = { + SND_SOC_DAPM_OUTPUT("OUTR"), +}; + +static struct snd_soc_dapm_widget tfa98xx_dapm_widgets_saam[] = { + SND_SOC_DAPM_INPUT("SAAM MIC"), +}; + +static struct snd_soc_dapm_widget tfa9888_dapm_inputs[] = { + SND_SOC_DAPM_INPUT("DMIC1"), + SND_SOC_DAPM_INPUT("DMIC2"), + SND_SOC_DAPM_INPUT("DMIC3"), + SND_SOC_DAPM_INPUT("DMIC4"), +}; + +static const struct snd_soc_dapm_route tfa98xx_dapm_routes_common[] = { + { "OUTL", NULL, "AIF IN" }, + { "AIF OUT", NULL, "AEC Loopback" }, +}; + +static const struct snd_soc_dapm_route tfa98xx_dapm_routes_saam[] = { + { "AIF OUT", NULL, "SAAM MIC" }, +}; + +static const struct snd_soc_dapm_route tfa98xx_dapm_routes_stereo[] = { + { "OUTR", NULL, "AIF IN" }, +}; + +static const struct snd_soc_dapm_route tfa9888_input_dapm_routes[] = { + { "AIF OUT", NULL, "DMIC1" }, + { "AIF OUT", NULL, "DMIC2" }, + { "AIF OUT", NULL, "DMIC3" }, + { "AIF OUT", NULL, "DMIC4" }, +}; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,2,0) +static struct snd_soc_dapm_context *snd_soc_codec_get_dapm(struct snd_soc_codec *codec) +{ + return &codec->dapm; +} +#endif + +static void tfa98xx_add_widgets(struct tfa98xx *tfa98xx) +{ + struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(tfa98xx->codec); + struct snd_soc_dapm_widget *widgets; + unsigned int num_dapm_widgets = ARRAY_SIZE(tfa98xx_dapm_widgets_common); + + widgets = devm_kzalloc(&tfa98xx->i2c->dev, + sizeof(struct snd_soc_dapm_widget) * + ARRAY_SIZE(tfa98xx_dapm_widgets_common), + GFP_KERNEL); + if (!widgets) + return; + memcpy(widgets, tfa98xx_dapm_widgets_common, + sizeof(struct snd_soc_dapm_widget) * + ARRAY_SIZE(tfa98xx_dapm_widgets_common)); + + tfa98xx_append_i2c_address(&tfa98xx->i2c->dev, + tfa98xx->i2c, + widgets, + num_dapm_widgets, + NULL, + 0); + + snd_soc_dapm_new_controls(dapm, widgets, + ARRAY_SIZE(tfa98xx_dapm_widgets_common)); + snd_soc_dapm_add_routes(dapm, tfa98xx_dapm_routes_common, + ARRAY_SIZE(tfa98xx_dapm_routes_common)); + + if (tfa98xx->flags & TFA98XX_FLAG_STEREO_DEVICE) { + snd_soc_dapm_new_controls(dapm, tfa98xx_dapm_widgets_stereo, + ARRAY_SIZE(tfa98xx_dapm_widgets_stereo)); + snd_soc_dapm_add_routes(dapm, tfa98xx_dapm_routes_stereo, + ARRAY_SIZE(tfa98xx_dapm_routes_stereo)); + } + + if (tfa98xx->flags & TFA98XX_FLAG_MULTI_MIC_INPUTS) { + snd_soc_dapm_new_controls(dapm, tfa9888_dapm_inputs, + ARRAY_SIZE(tfa9888_dapm_inputs)); + snd_soc_dapm_add_routes(dapm, tfa9888_input_dapm_routes, + ARRAY_SIZE(tfa9888_input_dapm_routes)); + } + + if (tfa98xx->flags & TFA98XX_FLAG_SAAM_AVAILABLE) { + snd_soc_dapm_new_controls(dapm, tfa98xx_dapm_widgets_saam, + ARRAY_SIZE(tfa98xx_dapm_widgets_saam)); + snd_soc_dapm_add_routes(dapm, tfa98xx_dapm_routes_saam, + ARRAY_SIZE(tfa98xx_dapm_routes_saam)); + } +} + +/* I2C wrapper functions */ +enum Tfa98xx_Error tfa98xx_write_register16(struct tfa_device *tfa, + unsigned char subaddress, + unsigned short value) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + struct tfa98xx *tfa98xx; + int ret; + int retries = I2C_RETRIES; + + if (tfa == NULL) { + pr_err("No device available\n"); + return Tfa98xx_Error_Fail; + } + + tfa98xx = (struct tfa98xx *)tfa->data; + if (!tfa98xx || !tfa98xx->regmap) { + pr_err("No tfa98xx regmap available\n"); + return Tfa98xx_Error_Bad_Parameter; + } +retry: + ret = regmap_write(tfa98xx->regmap, subaddress, value); + if (ret < 0) { + pr_warn("i2c error, retries left: %d\n", retries); + if (retries) { + retries--; + msleep(I2C_RETRY_DELAY); + goto retry; + } + return Tfa98xx_Error_Fail; + } + if (tfa98xx_kmsg_regs) + dev_dbg(&tfa98xx->i2c->dev, " WR reg=0x%02x, val=0x%04x %s\n", + subaddress, value, + ret<0? "Error!!" : ""); + + if (tfa98xx_ftrace_regs) + tfa98xx_trace_printk("\tWR reg=0x%02x, val=0x%04x %s\n", + subaddress, value, + ret<0? "Error!!" : ""); + return error; +} + +enum Tfa98xx_Error tfa98xx_read_register16(struct tfa_device *tfa, + unsigned char subaddress, + unsigned short *val) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + struct tfa98xx *tfa98xx; + unsigned int value; + int retries = I2C_RETRIES; + int ret; + + if (tfa == NULL) { + pr_err("No device available\n"); + return Tfa98xx_Error_Fail; + } + + tfa98xx = (struct tfa98xx *)tfa->data; + if (!tfa98xx || !tfa98xx->regmap) { + pr_err("No tfa98xx regmap available\n"); + return Tfa98xx_Error_Bad_Parameter; + } +retry: + ret = regmap_read(tfa98xx->regmap, subaddress, &value); + if (ret < 0) { + pr_warn("i2c error at subaddress 0x%x, retries left: %d\n", subaddress, retries); + if (retries) { + retries--; + msleep(I2C_RETRY_DELAY); + goto retry; + } + return Tfa98xx_Error_Fail; + } + *val = value & 0xffff; + + if (tfa98xx_kmsg_regs) + dev_dbg(&tfa98xx->i2c->dev, "RD reg=0x%02x, val=0x%04x %s\n", + subaddress, *val, + ret<0? "Error!!" : ""); + if (tfa98xx_ftrace_regs) + tfa98xx_trace_printk("\tRD reg=0x%02x, val=0x%04x %s\n", + subaddress, *val, + ret<0? "Error!!" : ""); + + return error; +} + + +/* + * init external dsp + */ +enum Tfa98xx_Error +tfa98xx_init_dsp(struct tfa_device *tfa) +{ + return Tfa98xx_Error_Not_Supported; +} + +int tfa98xx_get_dsp_status(struct tfa_device *tfa) +{ + return 0; +} + +/* + * write external dsp message + */ +enum Tfa98xx_Error +tfa98xx_write_dsp(struct tfa_device *tfa, int num_bytes, const char *command_buffer) +{ + return Tfa98xx_Error_Not_Supported; +} + +/* + * read external dsp message + */ +enum Tfa98xx_Error +tfa98xx_read_dsp(struct tfa_device *tfa, int num_bytes, unsigned char *result_buffer) +{ + return Tfa98xx_Error_Not_Supported; +} +/* + * write/read external dsp message + */ +enum Tfa98xx_Error +tfa98xx_writeread_dsp(struct tfa_device *tfa, int command_length, void *command_buffer, + int result_length, void *result_buffer) +{ + return Tfa98xx_Error_Not_Supported; +} + +enum Tfa98xx_Error tfa98xx_read_data(struct tfa_device *tfa, + unsigned char reg, + int len, unsigned char value[]) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + struct tfa98xx *tfa98xx; + struct i2c_client *tfa98xx_client; + int err; + int tries = 0; + struct i2c_msg msgs[] = { + { + .flags = 0, + .len = 1, + .buf = ®, + }, { + .flags = I2C_M_RD, + .len = len, + .buf = value, + }, + }; + + if (tfa == NULL) { + pr_err("No device available\n"); + return Tfa98xx_Error_Fail; + } + + tfa98xx = (struct tfa98xx *)tfa->data; + if (tfa98xx->i2c) { + tfa98xx_client = tfa98xx->i2c; + msgs[0].addr = tfa98xx_client->addr; + msgs[1].addr = tfa98xx_client->addr; + + do { + err = i2c_transfer(tfa98xx_client->adapter, msgs, + ARRAY_SIZE(msgs)); + if (err != ARRAY_SIZE(msgs)) + msleep_interruptible(I2C_RETRY_DELAY); + } while ((err != ARRAY_SIZE(msgs)) && (++tries < I2C_RETRIES)); + + if (err != ARRAY_SIZE(msgs)) { + dev_err(&tfa98xx_client->dev, "read transfer error %d\n", + err); + error = Tfa98xx_Error_Fail; + } + + if (tfa98xx_kmsg_regs) + dev_dbg(&tfa98xx_client->dev, "RD-DAT reg=0x%02x, len=%d\n", + reg, len); + if (tfa98xx_ftrace_regs) + tfa98xx_trace_printk("\t\tRD-DAT reg=0x%02x, len=%d\n", + reg, len); + } else { + pr_err("No device available\n"); + error = Tfa98xx_Error_Fail; + } + return error; +} + +enum Tfa98xx_Error tfa98xx_write_raw(struct tfa_device *tfa, + int len, + const unsigned char data[]) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + struct tfa98xx *tfa98xx; + int ret; + int retries = I2C_RETRIES; + + + if (tfa == NULL) { + pr_err("No device available\n"); + return Tfa98xx_Error_Fail; + } + + tfa98xx = (struct tfa98xx *)tfa->data; + +retry: + ret = i2c_master_send(tfa98xx->i2c, data, len); + if (ret < 0) { + pr_warn("i2c error, retries left: %d\n", retries); + if (retries) { + retries--; + msleep(I2C_RETRY_DELAY); + goto retry; + } + } + + if (ret == len) { + if (tfa98xx_kmsg_regs) + dev_dbg(&tfa98xx->i2c->dev, " WR-RAW len=%d\n", len); + if (tfa98xx_ftrace_regs) + tfa98xx_trace_printk("\t\tWR-RAW len=%d\n", len); + return Tfa98xx_Error_Ok; + } + pr_err(" WR-RAW (len=%d) Error I2C send size mismatch %d\n", len, ret); + error = Tfa98xx_Error_Fail; + + return error; +} + +/* Interrupts management */ + +static void tfa98xx_interrupt_enable_tfa2(struct tfa98xx *tfa98xx, bool enable) +{ + /* Only for 0x72 we need to enable NOCLK interrupts */ + if (tfa98xx->flags & TFA98XX_FLAG_REMOVE_PLOP_NOISE) + tfa_irq_ena(tfa98xx->tfa, tfa9912_irq_stnoclk, enable); + + if (tfa98xx->flags & TFA98XX_FLAG_LP_MODES) { + tfa_irq_ena(tfa98xx->tfa, 36, enable); /* FIXME: IELP0 does not excist for 9912 */ + tfa_irq_ena(tfa98xx->tfa, tfa9912_irq_stclpr, enable); + } +} + +/* Check if tap-detection can and shall be enabled. + * Configure SPK interrupt accordingly or setup polling mode + * Tap-detection shall be active if: + * - the service is enabled (tapdet_open), AND + * - the current profile is a tap-detection profile + * On TFA1 familiy of devices, activating tap-detection means enabling the SPK + * interrupt if available. + * We also update the tapdet_enabled and tapdet_poll variables. + */ +static void tfa98xx_tapdet_check_update(struct tfa98xx *tfa98xx) +{ + unsigned int enable = false; + + /* Support tap-detection on TFA1 family of devices */ + if ((tfa98xx->flags & TFA98XX_FLAG_TAPDET_AVAILABLE) == 0) + return; + + if (tfa98xx->tapdet_open && + (tfa98xx->tapdet_profiles & (1 << tfa98xx->profile))) + enable = true; + + if (!gpio_is_valid(tfa98xx->irq_gpio)) { + /* interrupt not available, setup polling mode */ + tfa98xx->tapdet_poll = true; + if (enable) + queue_delayed_work(tfa98xx->tfa98xx_wq, + &tfa98xx->tapdet_work, HZ/10); + else + cancel_delayed_work_sync(&tfa98xx->tapdet_work); + dev_dbg(tfa98xx->codec->dev, + "Polling for tap-detection: %s (%d; 0x%x, %d)\n", + enable? "enabled":"disabled", + tfa98xx->tapdet_open, tfa98xx->tapdet_profiles, + tfa98xx->profile); + + } else { + dev_dbg(tfa98xx->codec->dev, + "Interrupt for tap-detection: %s (%d; 0x%x, %d)\n", + enable? "enabled":"disabled", + tfa98xx->tapdet_open, tfa98xx->tapdet_profiles, + tfa98xx->profile); + /* enabled interrupt */ + tfa_irq_ena(tfa98xx->tfa, tfa9912_irq_sttapdet , enable); + } + + /* check disabled => enabled transition to clear pending events */ + if (!tfa98xx->tapdet_enabled && enable) { + /* clear pending event if any */ + tfa_irq_clear(tfa98xx->tfa, tfa9912_irq_sttapdet); + } + + if (!tfa98xx->tapdet_poll) + tfa_irq_ena(tfa98xx->tfa, tfa9912_irq_sttapdet, 1); /* enable again */ +} + +/* global enable / disable interrupts */ +static void tfa98xx_interrupt_enable(struct tfa98xx *tfa98xx, bool enable) +{ + if (tfa98xx->flags & TFA98XX_FLAG_SKIP_INTERRUPTS) + return; + + if (tfa98xx->tfa->tfa_family == 2) + tfa98xx_interrupt_enable_tfa2(tfa98xx, enable); +} + +/* Firmware management */ +static void tfa98xx_container_loaded(const struct firmware *cont, void *context) +{ + nxpTfaContainer_t *container; + struct tfa98xx *tfa98xx = context; + enum tfa_error tfa_err; + int container_size; + int ret; + + tfa98xx->dsp_fw_state = TFA98XX_DSP_FW_FAIL; + + if (!cont) { + pr_err("Failed to read %s\n", fw_name); + return; + } + + pr_info("loaded %s - size: %zu\n", fw_name, cont->size); + + mutex_lock(&tfa98xx_mutex); + if (tfa98xx_container == NULL) { + container = kzalloc(cont->size, GFP_KERNEL); + if (container == NULL) { + mutex_unlock(&tfa98xx_mutex); + release_firmware(cont); + pr_err("Error allocating memory\n"); + return; + } + + container_size = cont->size; + memcpy(container, cont->data, container_size); + release_firmware(cont); + + pr_info("%.2s%.2s\n", container->version, container->subversion); + pr_info("%.8s\n", container->customer); + pr_info("%.8s\n", container->application); + pr_info("%.8s\n", container->type); + pr_info("%d ndev\n", container->ndev); + pr_info("%d nprof\n", container->nprof); + + tfa_err = tfa_load_cnt(container, container_size); + if (tfa_err != tfa_error_ok) { + mutex_unlock(&tfa98xx_mutex); + kfree(container); + dev_err(tfa98xx->dev, "Cannot load container file, aborting\n"); + return; + } + + tfa98xx_container = container; + } else { + pr_info("container file already loaded...\n"); + container = tfa98xx_container; + release_firmware(cont); + } + mutex_unlock(&tfa98xx_mutex); + + tfa98xx->tfa->cnt = container; + + /* + i2c transaction limited to 64k + (Documentation/i2c/writing-clients) + */ + tfa98xx->tfa->buffer_size = 65536; + + /* DSP messages via i2c */ + tfa98xx->tfa->has_msg = 0; + + if (tfa_dev_probe(tfa98xx->i2c->addr, tfa98xx->tfa) != 0) { + dev_err(tfa98xx->dev, "Failed to probe TFA98xx @ 0x%.2x\n", tfa98xx->i2c->addr); + return; + } + + tfa98xx->tfa->dev_idx = tfa_cont_get_idx(tfa98xx->tfa); + if (tfa98xx->tfa->dev_idx < 0) { + dev_err(tfa98xx->dev, "Failed to find TFA98xx @ 0x%.2x in container file\n", tfa98xx->i2c->addr); + return; + } + + /* Enable debug traces */ + tfa98xx->tfa->verbose = trace_level & 1; + + /* prefix is the application name from the cnt */ + tfa_cnt_get_app_name(tfa98xx->tfa, tfa98xx->fw.name); + + /* set default profile/vstep */ + tfa98xx->profile = 0; + tfa98xx->vstep = 0; + + /* Override default profile if requested */ + if (strcmp(dflt_prof_name, "")) { + unsigned int i; + int nprof = tfa_cnt_get_dev_nprof(tfa98xx->tfa); + for (i = 0; i < nprof; i++) { + if (strcmp(tfa_cont_profile_name(tfa98xx, i), + dflt_prof_name) == 0) { + tfa98xx->profile = i; + dev_info(tfa98xx->dev, + "changing default profile to %s (%d)\n", + dflt_prof_name, tfa98xx->profile); + break; + } + } + if (i >= nprof) + dev_info(tfa98xx->dev, + "Default profile override failed (%s profile not found)\n", + dflt_prof_name); + } + + tfa98xx->dsp_fw_state = TFA98XX_DSP_FW_OK; + pr_info("Firmware init complete\n"); + + if (no_start != 0) + return; + + /* Only controls for master device */ + if (tfa98xx->tfa->dev_idx == 0) + tfa98xx_create_controls(tfa98xx); + + tfa98xx_inputdev_check_register(tfa98xx); + + if (tfa_is_cold(tfa98xx->tfa) == 0) { + pr_debug("Warning: device 0x%.2x is still warm\n", tfa98xx->i2c->addr); + tfa_reset(tfa98xx->tfa); + } + + /* Preload settings using internal clock on TFA2 */ + if (tfa98xx->tfa->tfa_family == 2) { + mutex_lock(&tfa98xx->dsp_lock); + ret = tfa98xx_tfa_start(tfa98xx, tfa98xx->profile, tfa98xx->vstep); + if (ret == Tfa98xx_Error_Not_Supported) + tfa98xx->dsp_fw_state = TFA98XX_DSP_FW_FAIL; + mutex_unlock(&tfa98xx->dsp_lock); + } + + tfa98xx_interrupt_enable(tfa98xx, true); +} + +static int tfa98xx_load_container(struct tfa98xx *tfa98xx) +{ + tfa98xx->dsp_fw_state = TFA98XX_DSP_FW_PENDING; + + return request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, + fw_name, tfa98xx->dev, GFP_KERNEL, + tfa98xx, tfa98xx_container_loaded); +} + + +static void tfa98xx_tapdet(struct tfa98xx *tfa98xx) +{ + unsigned int tap_pattern; + int btn; + + /* check tap pattern (BTN_0 is "error" wrong tap indication */ + tap_pattern = tfa_get_tap_pattern(tfa98xx->tfa); + switch (tap_pattern) { + case 0xffffffff: + pr_info("More than 4 taps detected! (flagTapPattern = -1)\n"); + btn = BTN_0; + break; + case 0xfffffffe: + case 0xfe: + pr_info("Illegal tap detected!\n"); + btn = BTN_0; + break; + case 0: + pr_info("Unrecognized pattern! (flagTapPattern = 0)\n"); + btn = BTN_0; + break; + default: + pr_info("Detected pattern: %d\n", tap_pattern); + btn = BTN_0 + tap_pattern; + break; + } + + input_report_key(tfa98xx->input, btn, 1); + input_report_key(tfa98xx->input, btn, 0); + input_sync(tfa98xx->input); + + /* acknowledge event done by clearing interrupt */ + +} + +static void tfa98xx_tapdet_work(struct work_struct *work) +{ + struct tfa98xx *tfa98xx; + + //TODO check is this is still needed for tap polling + tfa98xx = container_of(work, struct tfa98xx, tapdet_work.work); + + if ( tfa_irq_get(tfa98xx->tfa, tfa9912_irq_sttapdet)) + tfa98xx_tapdet(tfa98xx); + + queue_delayed_work(tfa98xx->tfa98xx_wq, &tfa98xx->tapdet_work, HZ/10); +} + +static void tfa98xx_monitor(struct work_struct *work) +{ + struct tfa98xx *tfa98xx; + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + + tfa98xx = container_of(work, struct tfa98xx, monitor_work.work); + + /* Check for tap-detection - bypass monitor if it is active */ + if (!tfa98xx->input) { + mutex_lock(&tfa98xx->dsp_lock); + error = tfa_status(tfa98xx->tfa); + mutex_unlock(&tfa98xx->dsp_lock); + if (error == Tfa98xx_Error_DSP_not_running) { + if (tfa98xx->dsp_init == TFA98XX_DSP_INIT_DONE) { + tfa98xx->dsp_init = TFA98XX_DSP_INIT_RECOVER; + queue_delayed_work(tfa98xx->tfa98xx_wq, &tfa98xx->init_work, 0); + } + } + } + + /* reschedule */ + queue_delayed_work(tfa98xx->tfa98xx_wq, &tfa98xx->monitor_work, 5*HZ); +} + +static void tfa98xx_dsp_init(struct tfa98xx *tfa98xx) +{ + int ret; + bool failed = false; + bool reschedule = false; + bool sync= false; + + if (tfa98xx->dsp_fw_state != TFA98XX_DSP_FW_OK) { + pr_debug("Skipping tfa_dev_start (no FW: %d)\n", tfa98xx->dsp_fw_state); + return; + } + + if(tfa98xx->dsp_init == TFA98XX_DSP_INIT_DONE) { + pr_debug("Stream already started, skipping DSP power-on\n"); + return; + } + + mutex_lock(&tfa98xx->dsp_lock); + + tfa98xx->dsp_init = TFA98XX_DSP_INIT_PENDING; + + if (tfa98xx->init_count < TF98XX_MAX_DSP_START_TRY_COUNT) { + /* directly try to start DSP */ + ret = tfa98xx_tfa_start(tfa98xx, tfa98xx->profile, tfa98xx->vstep); + if (ret == Tfa98xx_Error_Not_Supported) { + tfa98xx->dsp_fw_state = TFA98XX_DSP_FW_FAIL; + dev_err(&tfa98xx->i2c->dev, "Failed starting device\n"); + failed = true; + } else if (ret != Tfa98xx_Error_Ok) { + /* It may fail as we may not have a valid clock at that + * time, so re-schedule and re-try later. + */ + dev_err(&tfa98xx->i2c->dev, + "tfa_dev_start failed! (err %d) - %d\n", + ret, tfa98xx->init_count); + reschedule = true; + } else { + sync = true; + + /* Subsystem ready, tfa init complete */ + tfa98xx->dsp_init = TFA98XX_DSP_INIT_DONE; + dev_info(&tfa98xx->i2c->dev, + "tfa_dev_start success (%d)\n", + tfa98xx->init_count); + /* cancel other pending init works */ + cancel_delayed_work(&tfa98xx->init_work); + tfa98xx->init_count = 0; + } + } else { + /* exceeded max number ot start tentatives, cancel start */ + dev_err(&tfa98xx->i2c->dev, + "Failed starting device (%d)\n", + tfa98xx->init_count); + failed = true; + } + if (reschedule) { + /* reschedule this init work for later */ + queue_delayed_work(tfa98xx->tfa98xx_wq, + &tfa98xx->init_work, + msecs_to_jiffies(5)); + tfa98xx->init_count++; + } + if (failed) { + tfa98xx->dsp_init = TFA98XX_DSP_INIT_FAIL; + /* cancel other pending init works */ + cancel_delayed_work(&tfa98xx->init_work); + tfa98xx->init_count = 0; + } + mutex_unlock(&tfa98xx->dsp_lock); + + if (sync) { + /* check if all devices have started */ + bool do_sync; + mutex_lock(&tfa98xx_mutex); + + if (tfa98xx_sync_count < tfa98xx_device_count) + tfa98xx_sync_count++; + + do_sync = (tfa98xx_sync_count >= tfa98xx_device_count); + mutex_unlock(&tfa98xx_mutex); + + /* when all devices have started then unmute */ + if (do_sync) { + tfa98xx_sync_count = 0; + list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { + mutex_lock(&tfa98xx->dsp_lock); + tfa_dev_set_state(tfa98xx->tfa, TFA_STATE_UNMUTE); + + /* + * start monitor thread to check IC status bit + * periodically, and re-init IC to recover if + * needed. + */ + if (tfa98xx->tfa->tfa_family == 1) + queue_delayed_work(tfa98xx->tfa98xx_wq, + &tfa98xx->monitor_work, + 1*HZ); + mutex_unlock(&tfa98xx->dsp_lock); + } + + } + } + + + return; +} + + +static void tfa98xx_dsp_init_work(struct work_struct *work) +{ + struct tfa98xx *tfa98xx = container_of(work, struct tfa98xx, init_work.work); + + tfa98xx_dsp_init(tfa98xx); +} + +static void tfa98xx_interrupt(struct work_struct *work) +{ + struct tfa98xx *tfa98xx = container_of(work, struct tfa98xx, interrupt_work.work); + + pr_info("\n"); + + if (tfa98xx->flags & TFA98XX_FLAG_TAPDET_AVAILABLE) { + /* check for tap interrupt */ + if (tfa_irq_get(tfa98xx->tfa, tfa9912_irq_sttapdet)) { + tfa98xx_tapdet(tfa98xx); + + /* clear interrupt */ + tfa_irq_clear(tfa98xx->tfa, tfa9912_irq_sttapdet); + } + } /* TFA98XX_FLAG_TAPDET_AVAILABLE */ + + if (tfa98xx->flags & TFA98XX_FLAG_REMOVE_PLOP_NOISE) { + int start_triggered; + + mutex_lock(&tfa98xx->dsp_lock); + start_triggered = tfa_plop_noise_interrupt(tfa98xx->tfa, tfa98xx->profile, tfa98xx->vstep); + /* Only enable when the return value is 1, otherwise the interrupt is triggered twice */ + if(start_triggered) + tfa98xx_interrupt_enable(tfa98xx, true); + mutex_unlock(&tfa98xx->dsp_lock); + } /* TFA98XX_FLAG_REMOVE_PLOP_NOISE */ + + if (tfa98xx->flags & TFA98XX_FLAG_LP_MODES) { + tfa_lp_mode_interrupt(tfa98xx->tfa); + } /* TFA98XX_FLAG_LP_MODES */ + + /* unmask interrupts masked in IRQ handler */ + tfa_irq_unmask(tfa98xx->tfa); +} + +static int tfa98xx_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(codec); + unsigned int sr; + int len, prof, nprof, idx = 0; + char *basename; + u64 formats; + int err; + + /* + * Support CODEC to CODEC links, + * these are called with a NULL runtime pointer. + */ + if (!substream->runtime) + return 0; + + if (pcm_no_constraint != 0) + return 0; + + switch (pcm_sample_format) { + case 1: + formats = SNDRV_PCM_FMTBIT_S24_LE; + break; + case 2: + formats = SNDRV_PCM_FMTBIT_S32_LE; + break; + default: + formats = SNDRV_PCM_FMTBIT_S16_LE; + break; + } + + err = snd_pcm_hw_constraint_mask64(substream->runtime, + SNDRV_PCM_HW_PARAM_FORMAT, formats); + if (err < 0) + return err; + + if (no_start != 0) + return 0; + + if (tfa98xx->dsp_fw_state != TFA98XX_DSP_FW_OK) { + dev_info(codec->dev, "Container file not loaded\n"); + return -EINVAL; + } + + basename = kzalloc(MAX_CONTROL_NAME, GFP_KERNEL); + if (!basename) + return -ENOMEM; + + /* copy profile name into basename until the . */ + get_profile_basename(basename, tfa_cont_profile_name(tfa98xx, tfa98xx->profile)); + len = strlen(basename); + + /* loop over all profiles and get the supported samples rate(s) from + * the profiles with the same basename + */ + nprof = tfa_cnt_get_dev_nprof(tfa98xx->tfa); + tfa98xx->rate_constraint.list = &tfa98xx->rate_constraint_list[0]; + tfa98xx->rate_constraint.count = 0; + for (prof = 0; prof < nprof; prof++) { + if (0 == strncmp(basename, tfa_cont_profile_name(tfa98xx, prof), len)) { + /* Check which sample rate is supported with current profile, + * and enforce this. + */ + sr = tfa98xx_get_profile_sr(tfa98xx->tfa, prof); + if (!sr) + dev_info(codec->dev, "Unable to identify supported sample rate\n"); + + if (tfa98xx->rate_constraint.count >= TFA98XX_NUM_RATES) { + dev_err(codec->dev, "too many sample rates\n"); + } else { + tfa98xx->rate_constraint_list[idx++] = sr; + tfa98xx->rate_constraint.count += 1; + } + } + } + + kfree(basename); + +return 0; + +// return snd_pcm_hw_constraint_list(substream->runtime, 0, +// SNDRV_PCM_HW_PARAM_RATE, +// &tfa98xx->rate_constraint); +} + +static int tfa98xx_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(codec_dai->codec); + + tfa98xx->sysclk = freq; + return 0; +} + +static int tfa98xx_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, + unsigned int rx_mask, int slots, int slot_width) +{ + pr_debug("\n"); + return 0; +} + +static int tfa98xx_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(dai->codec); + struct snd_soc_codec *codec = dai->codec; + + pr_info("fmt=0x%x\n", fmt); + + /* Supported mode: regular I2S, slave, or PDM */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) { + dev_err(codec->dev, "Invalid Codec master mode\n"); + return -EINVAL; + } + break; + case SND_SOC_DAIFMT_PDM: + break; + default: + dev_err(codec->dev, "Unsupported DAI format %d\n", + fmt & SND_SOC_DAIFMT_FORMAT_MASK); + return -EINVAL; + } + + tfa98xx->audio_mode = fmt & SND_SOC_DAIFMT_FORMAT_MASK; + + return 0; +} + +static int tfa98xx_get_fssel(unsigned int rate) +{ + int i; + for (i = 0; i < ARRAY_SIZE(rate_to_fssel); i++) { + if (rate_to_fssel[i].rate == rate) { + return rate_to_fssel[i].fssel; + } + } + return -EINVAL; +} + +static int tfa98xx_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(codec); + unsigned int rate; + int prof_idx; + + /* Supported */ + rate = params_rate(params); + pr_info("Requested rate: %d, sample size: %d, physical size: %d\n", + rate, snd_pcm_format_width(params_format(params)), + snd_pcm_format_physical_width(params_format(params))); + + if (no_start != 0) + return 0; + + /* check if samplerate is supported for this mixer profile */ + prof_idx = get_profile_id_for_sr(tfa98xx_mixer_profile, rate); + if (prof_idx < 0) { + pr_err("tfa98xx: invalid sample rate %d.\n", rate); + return -EINVAL; + } + pr_info("mixer profile:container profile = [%d:%d]\n", tfa98xx_mixer_profile, prof_idx); + + + /* update 'real' profile (container profile) */ + tfa98xx->profile = prof_idx; + + /* update to new rate */ + tfa98xx->rate = rate; + + return 0; +} + +static int tfa98xx_mute(struct snd_soc_dai *dai, int mute, int stream) +{ + struct snd_soc_codec *codec = dai->codec; + struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(codec); + + dev_info(&tfa98xx->i2c->dev, "%s: state: %d\n", __func__, mute); + + if (no_start) { + pr_info("no_start parameter set no tfa_dev_start or tfa_dev_stop, returning\n"); + return 0; + } + + if (mute) { + /* stop DSP only when both playback and capture streams + * are deactivated + */ + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + tfa98xx->pstream = 0; + else + tfa98xx->cstream = 0; + if (tfa98xx->pstream != 0 || tfa98xx->cstream != 0) + return 0; + + mutex_lock(&tfa98xx_mutex); + tfa98xx_sync_count = 0; + mutex_unlock(&tfa98xx_mutex); + + cancel_delayed_work_sync(&tfa98xx->monitor_work); + + cancel_delayed_work_sync(&tfa98xx->init_work); + if (tfa98xx->dsp_fw_state != TFA98XX_DSP_FW_OK) + return 0; + mutex_lock(&tfa98xx->dsp_lock); + tfa_dev_stop(tfa98xx->tfa); + tfa98xx->dsp_init = TFA98XX_DSP_INIT_STOPPED; + mutex_unlock(&tfa98xx->dsp_lock); + } else { + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + tfa98xx->pstream = 1; + else + tfa98xx->cstream = 1; + +#if 1 + if (tfa98xx->dsp_init != TFA98XX_DSP_INIT_PENDING) + tfa98xx_dsp_init(tfa98xx); +#else + /* Start DSP */ + if (tfa98xx->dsp_init != TFA98XX_DSP_INIT_PENDING) + queue_delayed_work(tfa98xx->tfa98xx_wq, + &tfa98xx->init_work, 0); +#endif + } + + return 0; +} + +static const struct snd_soc_dai_ops tfa98xx_dai_ops = { + .startup = tfa98xx_startup, + .set_fmt = tfa98xx_set_fmt, + .set_sysclk = tfa98xx_set_dai_sysclk, + .set_tdm_slot = tfa98xx_set_tdm_slot, + .hw_params = tfa98xx_hw_params, + .mute_stream = tfa98xx_mute, +}; + +static struct snd_soc_dai_driver tfa98xx_dai[] = { + { + .name = "tfa98xx-aif", + .id = 1, + .playback = { + .stream_name = "AIF Playback", + .channels_min = 1, + .channels_max = 4, + .rates = TFA98XX_RATES, + .formats = TFA98XX_FORMATS, + }, + .capture = { + .stream_name = "AIF Capture", + .channels_min = 1, + .channels_max = 4, + .rates = TFA98XX_RATES, + .formats = TFA98XX_FORMATS, + }, + .ops = &tfa98xx_dai_ops, + .symmetric_rates = 1, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0) + .symmetric_channels = 1, + .symmetric_samplebits = 1, +#endif + }, +}; + +static int tfa98xx_probe(struct snd_soc_codec *codec) +{ + struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(codec); + int ret; + + pr_debug("\n"); + + /* setup work queue, will be used to initial DSP on first boot up */ + tfa98xx->tfa98xx_wq = create_singlethread_workqueue("tfa98xx"); + if (!tfa98xx->tfa98xx_wq) + return -ENOMEM; + + INIT_DELAYED_WORK(&tfa98xx->init_work, tfa98xx_dsp_init_work); + INIT_DELAYED_WORK(&tfa98xx->monitor_work, tfa98xx_monitor); + INIT_DELAYED_WORK(&tfa98xx->interrupt_work, tfa98xx_interrupt); + INIT_DELAYED_WORK(&tfa98xx->tapdet_work, tfa98xx_tapdet_work); + + tfa98xx->codec = codec; + + ret = tfa98xx_load_container(tfa98xx); + pr_info("Container loading requested: %d\n", ret); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,16,0) + codec->control_data = tfa98xx->regmap; + ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP); + if (ret != 0) { + dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); + return ret; + } +#endif + tfa98xx_add_widgets(tfa98xx); + + dev_info(codec->dev, "tfa98xx codec registered (%s)", + tfa98xx->fw.name); + +//suzhiguang,store for calibration + g_tfa98xx = tfa98xx; + return ret; +} + +static int tfa98xx_remove(struct snd_soc_codec *codec) +{ + struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(codec); + pr_debug("\n"); + + tfa98xx_interrupt_enable(tfa98xx, false); + + tfa98xx_inputdev_unregister(tfa98xx); + + cancel_delayed_work_sync(&tfa98xx->interrupt_work); + cancel_delayed_work_sync(&tfa98xx->monitor_work); + cancel_delayed_work_sync(&tfa98xx->init_work); + cancel_delayed_work_sync(&tfa98xx->tapdet_work); + + if (tfa98xx->tfa98xx_wq) + destroy_workqueue(tfa98xx->tfa98xx_wq); + + return 0; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,16,0) +static struct regmap *tfa98xx_get_regmap(struct device *dev) +{ + struct tfa98xx *tfa98xx = dev_get_drvdata(dev); + + return tfa98xx->regmap; +} +#endif +static struct snd_soc_codec_driver soc_codec_dev_tfa98xx = { + .probe = tfa98xx_probe, + .remove = tfa98xx_remove, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,16,0) + .get_regmap = tfa98xx_get_regmap, +#endif +}; + + +static bool tfa98xx_writeable_register(struct device *dev, unsigned int reg) +{ + /* enable read access for all registers */ + return 1; +} + +static bool tfa98xx_readable_register(struct device *dev, unsigned int reg) +{ + /* enable read access for all registers */ + return 1; +} + +static bool tfa98xx_volatile_register(struct device *dev, unsigned int reg) +{ + /* enable read access for all registers */ + return 1; +} + +static const struct regmap_config tfa98xx_regmap = { + .reg_bits = 8, + .val_bits = 16, + + .max_register = TFA98XX_MAX_REGISTER, + .writeable_reg = tfa98xx_writeable_register, + .readable_reg = tfa98xx_readable_register, + .volatile_reg = tfa98xx_volatile_register, + .cache_type = REGCACHE_NONE, +}; + +static void tfa98xx_irq_tfa2(struct tfa98xx *tfa98xx) +{ + pr_info("\n"); + + /* + * mask interrupts + * will be unmasked after handling interrupts in workqueue + */ + tfa_irq_mask(tfa98xx->tfa); + queue_delayed_work(tfa98xx->tfa98xx_wq, &tfa98xx->interrupt_work, 0); +} + + +static irqreturn_t tfa98xx_irq(int irq, void *data) +{ + struct tfa98xx *tfa98xx = data; + + if (tfa98xx->tfa->tfa_family == 2) + tfa98xx_irq_tfa2(tfa98xx); + + return IRQ_HANDLED; +} + +static int tfa98xx_ext_reset(struct tfa98xx *tfa98xx) +{ + if (tfa98xx && gpio_is_valid(tfa98xx->reset_gpio)) { + gpio_set_value_cansleep(tfa98xx->reset_gpio, 1); + mdelay(1); + gpio_set_value_cansleep(tfa98xx->reset_gpio, 0); + mdelay(1); + } + return 0; +} + +static int tfa98xx_parse_dt(struct device *dev, struct tfa98xx *tfa98xx, + struct device_node *np) { + tfa98xx->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0); + if (tfa98xx->reset_gpio < 0) + dev_dbg(dev, "No reset GPIO provided, will not HW reset device\n"); + + tfa98xx->irq_gpio = of_get_named_gpio(np, "irq-gpio", 0); + if (tfa98xx->irq_gpio < 0) + dev_dbg(dev, "No IRQ GPIO provided.\n"); + + return 0; +} + +static ssize_t tfa98xx_reg_write(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t off, size_t count) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct tfa98xx *tfa98xx = dev_get_drvdata(dev); + + if (count != 1) { + pr_debug("invalid register address"); + return -EINVAL; + } + + tfa98xx->reg = buf[0]; + + return 1; +} + +static ssize_t tfa98xx_rw_write(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t off, size_t count) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct tfa98xx *tfa98xx = dev_get_drvdata(dev); + u8 *data; + int ret; + int retries = I2C_RETRIES; + + data = kmalloc(count+1, GFP_KERNEL); + if (data == NULL) { + pr_debug("can not allocate memory\n"); + return -ENOMEM; + } + + data[0] = tfa98xx->reg; + memcpy(&data[1], buf, count); + +retry: + ret = i2c_master_send(tfa98xx->i2c, data, count+1); + if (ret < 0) { + pr_warn("i2c error, retries left: %d\n", retries); + if (retries) { + retries--; + msleep(I2C_RETRY_DELAY); + goto retry; + } + } + + kfree(data); + + /* the number of data bytes written without the register address */ + return ((ret > 1) ? count : -EIO); +} + +static ssize_t tfa98xx_rw_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t off, size_t count) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct tfa98xx *tfa98xx = dev_get_drvdata(dev); + struct i2c_msg msgs[] = { + { + .addr = tfa98xx->i2c->addr, + .flags = 0, + .len = 1, + .buf = &tfa98xx->reg, + }, + { + .addr = tfa98xx->i2c->addr, + .flags = I2C_M_RD, + .len = count, + .buf = buf, + }, + }; + int ret; + int retries = I2C_RETRIES; +retry: + ret = i2c_transfer(tfa98xx->i2c->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret < 0) { + pr_warn("i2c error, retries left: %d\n", retries); + if (retries) { + retries--; + msleep(I2C_RETRY_DELAY); + goto retry; + } + return ret; + } + /* ret contains the number of i2c transaction */ + /* return the number of bytes read */ + return ((ret > 1) ? count : -EIO); +} + +static struct bin_attribute dev_attr_rw = { + .attr = { + .name = "rw", + .mode = S_IRUSR | S_IWUSR, + }, + .size = 0, + .read = tfa98xx_rw_read, + .write = tfa98xx_rw_write, +}; + +static struct bin_attribute dev_attr_reg = { + .attr = { + .name = "reg", + .mode = S_IWUSR, + }, + .size = 0, + .read = NULL, + .write = tfa98xx_reg_write, +}; + +static ssize_t tfa98xx_state_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + pr_err("%s",__func__); + + return 0; +} + +static ssize_t tfa98xx_state_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct tfa98xx *tfa98xx; + int ret; + int cal_profile = -1, mtpex_state = -1, spkr_count = 0; + int state ,err; + + if(g_tfa98xx == NULL) + { + pr_err("%s g_tfa98xx = NULL\n",__func__); + return 0; + } + + tfa98xx = g_tfa98xx; + + pr_err("tfa98xx_state_show\n"); + + cal_profile = tfaContGetCalProfile(tfa98xx->tfa); + + if (cal_profile >= 0) { + tfa98xx->profile = cal_profile; + } else { + cal_profile = 0; + pr_err("tfa get cal profile error\n"); + } + + mutex_lock(&tfa98xx->dsp_lock); + + state = tfa_dev_get_state(tfa98xx->tfa); + if (state != TFA_STATE_OPERATING) { + pr_err("tfa Calibration must be started in operating state!\n"); + goto err_exit_mutex; + } + + err = tfa_supported_speakers(tfa98xx->tfa, &spkr_count); + if (err) { + pr_err("tfa Getting the number of supported speakers failed\n"); + goto err_exit_mutex; + } + + err = tfaRunColdStartup(tfa98xx->tfa, cal_profile); + if (err) { + pr_err("tfa It is not possible to set device into cold-boot state!\n"); + goto err_exit_mutex; + } + + /* Startup the device, ending in initCF state */ + err = tfaRunSpeakerBoost(tfa98xx->tfa, 0, cal_profile); + if (err) { + pr_err("tfa It is not possible to start device up!\n"); + goto err_exit_mutex; + } + + /* Check if CF is not in bypass */ + if (!tfa_cf_enabled(tfa98xx->tfa)) { + pr_err("tfa It is not possible to calibrate with CF in bypass! \n"); + goto err_exit_mutex; + } + mtpex_state = tfa_dev_mtp_get(tfa98xx->tfa, TFA_MTP_EX); + tfa_dev_set_state(tfa98xx->tfa, TFA_STATE_OPERATING); + if (tfa_dev_mtp_get(tfa98xx->tfa, TFA_MTP_EX) ) { + if (mtpex_state == 1) { + pr_err("tfa DSP already calibrated.\n Calibration skipped, previous results loaded.\n"); + //mtpex_state= tfa_dev_mtp_get(devs[dev_idx], TFA_MTP_EX); + } + /* Go to the Operating state */ + err = tfa_dsp_get_calibration_impedance(tfa98xx->tfa); + } + else + { + /* Go to the Operating state */ + //tfa_dev_set_state(devs[dev_idx], TFA_STATE_OPERATING); + /* calibrate */ + err = tfaRunSpeakerCalibration(tfa98xx->tfa); + if (err) + goto err_exit_mutex; + } + +// if (tfa98xx->tfa->tfa_family == 2 && !tfa98xx->tfa->is_probus_device) { +// scaling_factor = 1024; +// } + +#if 0 + imp[0] = (float)tfa98xx->tfa->mohm[0] / scaling_factor; + + if (spkr_count == 1) { + pr_err("tfa Calibration value is: %2.2f ohm\n", imp[0]); + } + else { + imp[1] = (float)tfa98xx->tfa->mohm[1] / scaling_factor; + pr_err("tfa Calibration value is: %2.2f %2.2f ohm\n", imp[0], imp[1]); + } +#else + pr_err("tfa Calibration value is: %d ohm\n", tfa98xx->tfa->mohm[0]); +#endif + + mutex_unlock(&tfa98xx->dsp_lock); + ret = sprintf(buf,"%d:%d",2,tfa98xx->tfa->mohm[0]); + return ret; + +err_exit_mutex: + mutex_unlock(&tfa98xx->dsp_lock); + ret = sprintf(buf,"%d:%d",2,0); + return ret; + +} + +static struct device_attribute tfa98xx_state_attr = + __ATTR(calibra, 0444, tfa98xx_state_show, tfa98xx_state_store); + + +static int tfa98xx_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct snd_soc_dai_driver *dai; + struct tfa98xx *tfa98xx; + struct device_node *np = i2c->dev.of_node; + int irq_flags; + unsigned int reg; + int ret; + + pr_info("addr=0x%x\n", i2c->addr); + + if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C)) { + dev_err(&i2c->dev, "check_functionality failed\n"); + return -EIO; + } + + tfa98xx = devm_kzalloc(&i2c->dev, sizeof(struct tfa98xx), GFP_KERNEL); + if (tfa98xx == NULL) + return -ENOMEM; + + tfa98xx->dev = &i2c->dev; + tfa98xx->i2c = i2c; + tfa98xx->dsp_init = TFA98XX_DSP_INIT_STOPPED; + tfa98xx->rate = 48000; /* init to the default sample rate (48kHz) */ + tfa98xx->tfa = NULL; + + tfa98xx->regmap = devm_regmap_init_i2c(i2c, &tfa98xx_regmap); + if (IS_ERR(tfa98xx->regmap)) { + ret = PTR_ERR(tfa98xx->regmap); + dev_err(&i2c->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + i2c_set_clientdata(i2c, tfa98xx); + mutex_init(&tfa98xx->dsp_lock); + init_waitqueue_head(&tfa98xx->wq); + + if (np) { + ret = tfa98xx_parse_dt(&i2c->dev, tfa98xx, np); + if (ret) { + dev_err(&i2c->dev, "Failed to parse DT node\n"); + return ret; + } + if (no_start) + tfa98xx->irq_gpio = -1; + if (no_reset) + tfa98xx->reset_gpio = -1; + } else { + tfa98xx->reset_gpio = -1; + tfa98xx->irq_gpio = -1; + } + + if (gpio_is_valid(tfa98xx->reset_gpio)) { + ret = devm_gpio_request_one(&i2c->dev, tfa98xx->reset_gpio, + GPIOF_OUT_INIT_LOW, "TFA98XX_RST"); + if (ret) { + pr_err("%s devm_gpio_request_one tfa98xx->reset_gpio failed\n",__func__); + return ret; + } + } + + if (gpio_is_valid(tfa98xx->irq_gpio)) { + ret = devm_gpio_request_one(&i2c->dev, tfa98xx->irq_gpio, + GPIOF_DIR_IN, "TFA98XX_INT"); + if (ret) { + pr_err("%s devm_gpio_request_one tfa98xx->irq_gpio failed\n",__func__); + return ret; + } + } + + /* Power up! */ + tfa98xx_ext_reset(tfa98xx); + + if ((no_start == 0) && (no_reset == 0)) { + ret = regmap_read(tfa98xx->regmap, 0x03, ®); + if (ret < 0) { + pr_err("tfa failed to read Revision register: %d\n", + ret); + //suzhiguang + if (gpio_is_valid(tfa98xx->reset_gpio)) { + gpio_free(tfa98xx->reset_gpio); + } + if (gpio_is_valid(tfa98xx->irq_gpio)) { + gpio_free(tfa98xx->irq_gpio); + } + return -EIO; + } + switch (reg & 0xff) { + case 0x72: /* tfa9872 */ + pr_info("TFA9872 detected\n"); + tfa98xx->flags |= TFA98XX_FLAG_MULTI_MIC_INPUTS; + tfa98xx->flags |= TFA98XX_FLAG_CALIBRATION_CTL; + tfa98xx->flags |= TFA98XX_FLAG_REMOVE_PLOP_NOISE; + /* tfa98xx->flags |= TFA98XX_FLAG_LP_MODES; */ + tfa98xx->flags |= TFA98XX_FLAG_TDM_DEVICE; + smartpa_present = 1; + break; + case 0x74: /* tfa9874 */ + pr_info("TFA9874 detected\n"); + tfa98xx->flags |= TFA98XX_FLAG_MULTI_MIC_INPUTS; + tfa98xx->flags |= TFA98XX_FLAG_CALIBRATION_CTL; + tfa98xx->flags |= TFA98XX_FLAG_TDM_DEVICE; + smartpa_present = 1; + break; + case 0x88: /* tfa9888 */ + pr_info("TFA9888 detected\n"); + tfa98xx->flags |= TFA98XX_FLAG_STEREO_DEVICE; + tfa98xx->flags |= TFA98XX_FLAG_MULTI_MIC_INPUTS; + tfa98xx->flags |= TFA98XX_FLAG_TDM_DEVICE; + smartpa_present = 1; + break; + case 0x13: /* tfa9912 */ + pr_info("TFA9912 detected\n"); + tfa98xx->flags |= TFA98XX_FLAG_MULTI_MIC_INPUTS; + tfa98xx->flags |= TFA98XX_FLAG_TDM_DEVICE; + /* tfa98xx->flags |= TFA98XX_FLAG_TAPDET_AVAILABLE; */ + smartpa_present = 1; + break; + case 0x94: /* tfa9894 */ + pr_info("TFA9894 detected\n"); + tfa98xx->flags |= TFA98XX_FLAG_MULTI_MIC_INPUTS; + tfa98xx->flags |= TFA98XX_FLAG_TDM_DEVICE; + smartpa_present = 1; + break; + case 0x80: /* tfa9890 */ + case 0x81: /* tfa9890 */ + pr_info("TFA9890 detected\n"); + tfa98xx->flags |= TFA98XX_FLAG_SKIP_INTERRUPTS; + smartpa_present = 1; + break; + case 0x92: /* tfa9891 */ + pr_info("TFA9891 detected\n"); + tfa98xx->flags |= TFA98XX_FLAG_SAAM_AVAILABLE; + tfa98xx->flags |= TFA98XX_FLAG_SKIP_INTERRUPTS; + smartpa_present = 1; + break; + case 0x12: /* tfa9895 */ + pr_info("TFA9895 detected\n"); + tfa98xx->flags |= TFA98XX_FLAG_SKIP_INTERRUPTS; + break; + case 0x97: + pr_info("TFA9897 detected\n"); + tfa98xx->flags |= TFA98XX_FLAG_SKIP_INTERRUPTS; + tfa98xx->flags |= TFA98XX_FLAG_TDM_DEVICE; + smartpa_present = 1; + break; + case 0x96: + pr_info("TFA9896 detected\n"); + tfa98xx->flags |= TFA98XX_FLAG_SKIP_INTERRUPTS; + tfa98xx->flags |= TFA98XX_FLAG_TDM_DEVICE; + smartpa_present = 1; + break; + default: + pr_info("Unsupported device revision (0x%x)\n", reg & 0xff); + return -EINVAL; + } + } + + tfa98xx->tfa = devm_kzalloc(&i2c->dev, sizeof(struct tfa_device), GFP_KERNEL); + if (tfa98xx->tfa == NULL) + return -ENOMEM; + + tfa98xx->tfa->data = (void *)tfa98xx; + tfa98xx->tfa->cachep = tfa98xx_cache; + + /* Modify the stream names, by appending the i2c device address. + * This is used with multicodec, in order to discriminate the devices. + * Stream names appear in the dai definition and in the stream . + * We create copies of original structures because each device will + * have its own instance of this structure, with its own address. + */ + dai = devm_kzalloc(&i2c->dev, sizeof(tfa98xx_dai), GFP_KERNEL); + if (!dai) + return -ENOMEM; + memcpy(dai, tfa98xx_dai, sizeof(tfa98xx_dai)); + + tfa98xx_append_i2c_address(&i2c->dev, + i2c, + NULL, + 0, + dai, + ARRAY_SIZE(tfa98xx_dai)); + + ret = snd_soc_register_codec(&i2c->dev, + &soc_codec_dev_tfa98xx, dai, + ARRAY_SIZE(tfa98xx_dai)); + + if (ret < 0) { + dev_err(&i2c->dev, "Failed to register TFA98xx: %d\n", ret); + return ret; + } + + if (gpio_is_valid(tfa98xx->irq_gpio) && + !(tfa98xx->flags & TFA98XX_FLAG_SKIP_INTERRUPTS)) { + /* register irq handler */ + irq_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; + ret = devm_request_threaded_irq(&i2c->dev, + gpio_to_irq(tfa98xx->irq_gpio), + NULL, tfa98xx_irq, irq_flags, + "tfa98xx", tfa98xx); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to request IRQ %d: %d\n", + gpio_to_irq(tfa98xx->irq_gpio), ret); + return ret; + } + } else { + dev_info(&i2c->dev, "Skipping IRQ registration\n"); + /* disable feature support if gpio was invalid */ + tfa98xx->flags |= TFA98XX_FLAG_SKIP_INTERRUPTS; + } + +#ifdef CONFIG_DEBUG_FS + if (no_start == 0) + tfa98xx_debug_init(tfa98xx, i2c); +#endif + + + ret = sysfs_create_file(&i2c->dev.kobj, &tfa98xx_state_attr.attr); + if(ret < 0) + { + pr_err("%s sysfs_create_file tfa98xx_state_attr err.",__func__); + } + + + /* Register the sysfs files for climax backdoor access */ + ret = device_create_bin_file(&i2c->dev, &dev_attr_rw); + if (ret) + dev_info(&i2c->dev, "error creating sysfs files\n"); + ret = device_create_bin_file(&i2c->dev, &dev_attr_reg); + if (ret) + dev_info(&i2c->dev, "error creating sysfs files\n"); + + pr_info("%s Probe completed successfully!\n", __func__); + + INIT_LIST_HEAD(&tfa98xx->list); + + mutex_lock(&tfa98xx_mutex); + tfa98xx_device_count++; + list_add(&tfa98xx->list, &tfa98xx_device_list); + mutex_unlock(&tfa98xx_mutex); + + return 0; +} + +static int tfa98xx_i2c_remove(struct i2c_client *i2c) +{ + struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); + + pr_debug("addr=0x%x\n", i2c->addr); + + tfa98xx_interrupt_enable(tfa98xx, false); + + cancel_delayed_work_sync(&tfa98xx->interrupt_work); + cancel_delayed_work_sync(&tfa98xx->monitor_work); + cancel_delayed_work_sync(&tfa98xx->init_work); + cancel_delayed_work_sync(&tfa98xx->tapdet_work); + + device_remove_bin_file(&i2c->dev, &dev_attr_reg); + device_remove_bin_file(&i2c->dev, &dev_attr_rw); +#ifdef CONFIG_DEBUG_FS + tfa98xx_debug_remove(tfa98xx); +#endif + + snd_soc_unregister_codec(&i2c->dev); + + if (gpio_is_valid(tfa98xx->irq_gpio)) + devm_gpio_free(&i2c->dev, tfa98xx->irq_gpio); + if (gpio_is_valid(tfa98xx->reset_gpio)) + devm_gpio_free(&i2c->dev, tfa98xx->reset_gpio); + + mutex_lock(&tfa98xx_mutex); + list_del(&tfa98xx->list); + tfa98xx_device_count--; + if (tfa98xx_device_count == 0) { + kfree(tfa98xx_container); + tfa98xx_container = NULL; + } + mutex_unlock(&tfa98xx_mutex); + + return 0; +} + +static const struct i2c_device_id tfa98xx_i2c_id[] = { + { "tfa98xx", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tfa98xx_i2c_id); + +#ifdef CONFIG_OF +static struct of_device_id tfa98xx_dt_match[] = { + { .compatible = "nxp,tfa98xx" }, + { .compatible = "nxp,tfa9872" }, + { .compatible = "nxp,tfa9874" }, + { .compatible = "nxp,tfa9888" }, + { .compatible = "nxp,tfa9890" }, + { .compatible = "nxp,tfa9891" }, + { .compatible = "nxp,tfa9894" }, + { .compatible = "nxp,tfa9895" }, + { .compatible = "nxp,tfa9896" }, + { .compatible = "nxp,tfa9897" }, + { .compatible = "nxp,tfa9912" }, + { }, +}; +#endif + +static struct i2c_driver tfa98xx_i2c_driver = { + .driver = { + .name = "tfa98xx", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(tfa98xx_dt_match), + }, + .probe = tfa98xx_i2c_probe, + .remove = tfa98xx_i2c_remove, + .id_table = tfa98xx_i2c_id, +}; + +static int __init tfa98xx_i2c_init(void) +{ + int ret = 0; + + pr_info("TFA98XX driver version %s\n", TFA98XX_VERSION); + + /* Enable debug traces */ + tfa98xx_kmsg_regs = trace_level & 2; + tfa98xx_ftrace_regs = trace_level & 4; + + /* Initialize kmem_cache */ + tfa98xx_cache = kmem_cache_create("tfa98xx_cache", /* Cache name /proc/slabinfo */ + PAGE_SIZE, /* Structure size, we should fit in single page */ + 0, /* Structure alignment */ + (SLAB_HWCACHE_ALIGN | SLAB_RECLAIM_ACCOUNT | + SLAB_MEM_SPREAD), /* Cache property */ + NULL); /* Object constructor */ + if (!tfa98xx_cache) { + pr_err("tfa98xx can't create memory pool\n"); + ret = -ENOMEM; + } + + ret = i2c_add_driver(&tfa98xx_i2c_driver); + + return ret; +} +module_init(tfa98xx_i2c_init); + +static void __exit tfa98xx_i2c_exit(void) +{ + i2c_del_driver(&tfa98xx_i2c_driver); + kmem_cache_destroy(tfa98xx_cache); +} +module_exit(tfa98xx_i2c_exit); + +MODULE_DESCRIPTION("ASoC TFA98XX driver"); +MODULE_LICENSE("GPL"); + diff --git a/techpack/audio/asoc/codecs/tfa9874/tfa98xx.h b/techpack/audio/asoc/codecs/tfa9874/tfa98xx.h new file mode 100644 index 000000000000..07940b3610cb --- /dev/null +++ b/techpack/audio/asoc/codecs/tfa9874/tfa98xx.h @@ -0,0 +1,131 @@ +/* + * Copyright 2014-2017 NXP Semiconductors + * + * 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 __TFA98XX_INC__ +#define __TFA98XX_INC__ + +#include +#include +#include + +#include "tfa_device.h" +#include "tfa_container.h" +#include "config.h" + +/* max. length of a alsa mixer control name */ +#define MAX_CONTROL_NAME 48 + +#define TFA98XX_MAX_REGISTER 0xff + +#define TFA98XX_FLAG_SKIP_INTERRUPTS (1 << 0) +#define TFA98XX_FLAG_SAAM_AVAILABLE (1 << 1) +#define TFA98XX_FLAG_STEREO_DEVICE (1 << 2) +#define TFA98XX_FLAG_MULTI_MIC_INPUTS (1 << 3) +#define TFA98XX_FLAG_TAPDET_AVAILABLE (1 << 4) +#define TFA98XX_FLAG_CALIBRATION_CTL (1 << 5) +#define TFA98XX_FLAG_REMOVE_PLOP_NOISE (1 << 6) +#define TFA98XX_FLAG_LP_MODES (1 << 7) +#define TFA98XX_FLAG_TDM_DEVICE (1 << 8) + +#define TFA98XX_NUM_RATES 9 + +/* DSP init status */ +enum tfa98xx_dsp_init_state { + TFA98XX_DSP_INIT_STOPPED, /* DSP not running */ + TFA98XX_DSP_INIT_RECOVER, /* DSP error detected at runtime */ + TFA98XX_DSP_INIT_FAIL, /* DSP init failed */ + TFA98XX_DSP_INIT_PENDING, /* DSP start requested */ + TFA98XX_DSP_INIT_DONE, /* DSP running */ + TFA98XX_DSP_INIT_INVALIDATED, /* DSP was running, requires re-init */ +}; + +enum tfa98xx_dsp_fw_state { + TFA98XX_DSP_FW_NONE = 0, + TFA98XX_DSP_FW_PENDING, + TFA98XX_DSP_FW_FAIL, + TFA98XX_DSP_FW_OK, +}; + +struct tfa98xx_firmware { + void *base; + struct tfa98xx_device *dev; + char name[9]; //TODO get length from tfa parameter defs +}; + +struct tfa98xx_baseprofile { + char basename[MAX_CONTROL_NAME]; /* profile basename */ + int len; /* profile length */ + int item_id; /* profile id */ + int sr_rate_sup[TFA98XX_NUM_RATES]; /* sample rates supported by this profile */ + struct list_head list; /* list of all profiles */ +}; + +struct tfa98xx { + struct regmap *regmap; + struct i2c_client *i2c; + struct regulator *vdd; + struct snd_soc_codec *codec; + struct workqueue_struct *tfa98xx_wq; + struct delayed_work init_work; + struct delayed_work monitor_work; + struct delayed_work interrupt_work; + struct delayed_work tapdet_work; + struct mutex dsp_lock; + int dsp_init; + int dsp_fw_state; + int sysclk; + int rst_gpio; + u16 rev; + int audio_mode; + struct tfa98xx_firmware fw; + char *fw_name; + int rate; + wait_queue_head_t wq; + struct device *dev; + unsigned int init_count; + int pstream; + int cstream; + struct input_dev *input; + bool tapdet_enabled; /* service enabled */ + bool tapdet_open; /* device file opened */ + unsigned int tapdet_profiles; /* tapdet profile bitfield */ + bool tapdet_poll; /* tapdet running on polling mode */ + + unsigned int rate_constraint_list[TFA98XX_NUM_RATES]; + struct snd_pcm_hw_constraint_list rate_constraint; + + int reset_gpio; + int power_gpio; + int irq_gpio; + + struct list_head list; + struct tfa_device *tfa; + int vstep; + int profile; + int prof_vsteps[TFACONT_MAXPROFS]; /* store vstep per profile (single device) */ + +#ifdef CONFIG_DEBUG_FS + struct dentry *dbg_dir; +#endif + u8 reg; + unsigned int flags; + bool set_mtp_cal; + uint16_t cal_data; +}; + + +#endif /* __TFA98XX_INC__ */ + diff --git a/techpack/audio/asoc/codecs/tfa9874/tfa98xx_genregs_N1C.h b/techpack/audio/asoc/codecs/tfa9874/tfa98xx_genregs_N1C.h new file mode 100644 index 000000000000..7a124b82b332 --- /dev/null +++ b/techpack/audio/asoc/codecs/tfa9874/tfa98xx_genregs_N1C.h @@ -0,0 +1,3853 @@ +/** Filename: Tfa98xx_genregs.h + * This file was generated automatically on 09/01/15 at 09:40:23. + * Source file: TFA9888_N1C_I2C_regmap_V1.xlsx + */ + +#ifndef TFA2_GENREGS_H +#define TFA2_GENREGS_H + + +#define TFA98XX_SYS_CONTROL0 0x00 +#define TFA98XX_SYS_CONTROL1 0x01 +#define TFA98XX_SYS_CONTROL2 0x02 +#define TFA98XX_DEVICE_REVISION 0x03 +#define TFA98XX_CLOCK_CONTROL 0x04 +#define TFA98XX_CLOCK_GATING_CONTROL 0x05 +#define TFA98XX_SIDE_TONE_CONFIG 0x0d +#define TFA98XX_CTRL_DIGTOANA_REG 0x0e +#define TFA98XX_STATUS_FLAGS0 0x10 +#define TFA98XX_STATUS_FLAGS1 0x11 +#define TFA98XX_STATUS_FLAGS2 0x12 +#define TFA98XX_STATUS_FLAGS3 0x13 +#define TFA98XX_STATUS_FLAGS4 0x14 +#define TFA98XX_BATTERY_VOLTAGE 0x15 +#define TFA98XX_TEMPERATURE 0x16 +#define TFA98XX_TDM_CONFIG0 0x20 +#define TFA98XX_TDM_CONFIG1 0x21 +#define TFA98XX_TDM_CONFIG2 0x22 +#define TFA98XX_TDM_CONFIG3 0x23 +#define TFA98XX_TDM_CONFIG4 0x24 +#define TFA98XX_TDM_CONFIG5 0x25 +#define TFA98XX_TDM_CONFIG6 0x26 +#define TFA98XX_TDM_CONFIG7 0x27 +#define TFA98XX_TDM_CONFIG8 0x28 +#define TFA98XX_TDM_CONFIG9 0x29 +#define TFA98XX_PDM_CONFIG0 0x31 +#define TFA98XX_PDM_CONFIG1 0x32 +#define TFA98XX_HAPTIC_DRIVER_CONFIG 0x33 +#define TFA98XX_GPIO_DATAIN_REG 0x34 +#define TFA98XX_GPIO_CONFIG 0x35 +#define TFA98XX_INTERRUPT_OUT_REG1 0x40 +#define TFA98XX_INTERRUPT_OUT_REG2 0x41 +#define TFA98XX_INTERRUPT_OUT_REG3 0x42 +#define TFA98XX_INTERRUPT_IN_REG1 0x44 +#define TFA98XX_INTERRUPT_IN_REG2 0x45 +#define TFA98XX_INTERRUPT_IN_REG3 0x46 +#define TFA98XX_INTERRUPT_ENABLE_REG1 0x48 +#define TFA98XX_INTERRUPT_ENABLE_REG2 0x49 +#define TFA98XX_INTERRUPT_ENABLE_REG3 0x4a +#define TFA98XX_STATUS_POLARITY_REG1 0x4c +#define TFA98XX_STATUS_POLARITY_REG2 0x4d +#define TFA98XX_STATUS_POLARITY_REG3 0x4e +#define TFA98XX_BAT_PROT_CONFIG 0x50 +#define TFA98XX_AUDIO_CONTROL 0x51 +#define TFA98XX_AMPLIFIER_CONFIG 0x52 +#define TFA98XX_AUDIO_CONTROL2 0x5a +#define TFA98XX_DCDC_CONTROL0 0x70 +#define TFA98XX_CF_CONTROLS 0x90 +#define TFA98XX_CF_MAD 0x91 +#define TFA98XX_CF_MEM 0x92 +#define TFA98XX_CF_STATUS 0x93 +#define TFA98XX_MTPKEY2_REG 0xa1 +#define TFA98XX_MTP_STATUS 0xa2 +#define TFA98XX_KEY_PROTECTED_MTP_CONTROL 0xa3 +#define TFA98XX_MTP_DATA_OUT_MSB 0xa5 +#define TFA98XX_MTP_DATA_OUT_LSB 0xa6 +#define TFA98XX_TEMP_SENSOR_CONFIG 0xb1 +#define TFA98XX_KEY2_PROTECTED_MTP0 0xf0 +#define TFA98XX_KEY1_PROTECTED_MTP4 0xf4 +#define TFA98XX_KEY1_PROTECTED_MTP5 0xf5 + +/* + * (0x00)-sys_control0 + */ + +/* + * powerdown + */ +#define TFA98XX_SYS_CONTROL0_PWDN (0x1<<0) +#define TFA98XX_SYS_CONTROL0_PWDN_POS 0 +#define TFA98XX_SYS_CONTROL0_PWDN_LEN 1 +#define TFA98XX_SYS_CONTROL0_PWDN_MAX 1 +#define TFA98XX_SYS_CONTROL0_PWDN_MSK 0x1 + +/* + * reset + */ +#define TFA98XX_SYS_CONTROL0_I2CR (0x1<<1) +#define TFA98XX_SYS_CONTROL0_I2CR_POS 1 +#define TFA98XX_SYS_CONTROL0_I2CR_LEN 1 +#define TFA98XX_SYS_CONTROL0_I2CR_MAX 1 +#define TFA98XX_SYS_CONTROL0_I2CR_MSK 0x2 + +/* + * enbl_coolflux + */ +#define TFA98XX_SYS_CONTROL0_CFE (0x1<<2) +#define TFA98XX_SYS_CONTROL0_CFE_POS 2 +#define TFA98XX_SYS_CONTROL0_CFE_LEN 1 +#define TFA98XX_SYS_CONTROL0_CFE_MAX 1 +#define TFA98XX_SYS_CONTROL0_CFE_MSK 0x4 + +/* + * enbl_amplifier + */ +#define TFA98XX_SYS_CONTROL0_AMPE (0x1<<3) +#define TFA98XX_SYS_CONTROL0_AMPE_POS 3 +#define TFA98XX_SYS_CONTROL0_AMPE_LEN 1 +#define TFA98XX_SYS_CONTROL0_AMPE_MAX 1 +#define TFA98XX_SYS_CONTROL0_AMPE_MSK 0x8 + +/* + * enbl_boost + */ +#define TFA98XX_SYS_CONTROL0_DCA (0x1<<4) +#define TFA98XX_SYS_CONTROL0_DCA_POS 4 +#define TFA98XX_SYS_CONTROL0_DCA_LEN 1 +#define TFA98XX_SYS_CONTROL0_DCA_MAX 1 +#define TFA98XX_SYS_CONTROL0_DCA_MSK 0x10 + +/* + * coolflux_configured + */ +#define TFA98XX_SYS_CONTROL0_SBSL (0x1<<5) +#define TFA98XX_SYS_CONTROL0_SBSL_POS 5 +#define TFA98XX_SYS_CONTROL0_SBSL_LEN 1 +#define TFA98XX_SYS_CONTROL0_SBSL_MAX 1 +#define TFA98XX_SYS_CONTROL0_SBSL_MSK 0x20 + +/* + * sel_enbl_amplifier + */ +#define TFA98XX_SYS_CONTROL0_AMPC (0x1<<6) +#define TFA98XX_SYS_CONTROL0_AMPC_POS 6 +#define TFA98XX_SYS_CONTROL0_AMPC_LEN 1 +#define TFA98XX_SYS_CONTROL0_AMPC_MAX 1 +#define TFA98XX_SYS_CONTROL0_AMPC_MSK 0x40 + +/* + * int_pad_io + */ +#define TFA98XX_SYS_CONTROL0_INTP (0x3<<7) +#define TFA98XX_SYS_CONTROL0_INTP_POS 7 +#define TFA98XX_SYS_CONTROL0_INTP_LEN 2 +#define TFA98XX_SYS_CONTROL0_INTP_MAX 3 +#define TFA98XX_SYS_CONTROL0_INTP_MSK 0x180 + +/* + * fs_pulse_sel + */ +#define TFA98XX_SYS_CONTROL0_FSSSEL (0x3<<9) +#define TFA98XX_SYS_CONTROL0_FSSSEL_POS 9 +#define TFA98XX_SYS_CONTROL0_FSSSEL_LEN 2 +#define TFA98XX_SYS_CONTROL0_FSSSEL_MAX 3 +#define TFA98XX_SYS_CONTROL0_FSSSEL_MSK 0x600 + +/* + * bypass_ocp + */ +#define TFA98XX_SYS_CONTROL0_BYPOCP (0x1<<11) +#define TFA98XX_SYS_CONTROL0_BYPOCP_POS 11 +#define TFA98XX_SYS_CONTROL0_BYPOCP_LEN 1 +#define TFA98XX_SYS_CONTROL0_BYPOCP_MAX 1 +#define TFA98XX_SYS_CONTROL0_BYPOCP_MSK 0x800 + +/* + * test_ocp + */ +#define TFA98XX_SYS_CONTROL0_TSTOCP (0x1<<12) +#define TFA98XX_SYS_CONTROL0_TSTOCP_POS 12 +#define TFA98XX_SYS_CONTROL0_TSTOCP_LEN 1 +#define TFA98XX_SYS_CONTROL0_TSTOCP_MAX 1 +#define TFA98XX_SYS_CONTROL0_TSTOCP_MSK 0x1000 + + +/* + * (0x01)-sys_control1 + */ + +/* + * vamp_sel + */ +#define TFA98XX_SYS_CONTROL1_AMPINSEL (0x3<<0) +#define TFA98XX_SYS_CONTROL1_AMPINSEL_POS 0 +#define TFA98XX_SYS_CONTROL1_AMPINSEL_LEN 2 +#define TFA98XX_SYS_CONTROL1_AMPINSEL_MAX 3 +#define TFA98XX_SYS_CONTROL1_AMPINSEL_MSK 0x3 + +/* + * src_set_configured + */ +#define TFA98XX_SYS_CONTROL1_MANSCONF (0x1<<2) +#define TFA98XX_SYS_CONTROL1_MANSCONF_POS 2 +#define TFA98XX_SYS_CONTROL1_MANSCONF_LEN 1 +#define TFA98XX_SYS_CONTROL1_MANSCONF_MAX 1 +#define TFA98XX_SYS_CONTROL1_MANSCONF_MSK 0x4 + +/* + * execute_cold_start + */ +#define TFA98XX_SYS_CONTROL1_MANCOLD (0x1<<3) +#define TFA98XX_SYS_CONTROL1_MANCOLD_POS 3 +#define TFA98XX_SYS_CONTROL1_MANCOLD_LEN 1 +#define TFA98XX_SYS_CONTROL1_MANCOLD_MAX 1 +#define TFA98XX_SYS_CONTROL1_MANCOLD_MSK 0x8 + +/* + * enbl_osc1m_auto_off + */ +#define TFA98XX_SYS_CONTROL1_MANAOOSC (0x1<<4) +#define TFA98XX_SYS_CONTROL1_MANAOOSC_POS 4 +#define TFA98XX_SYS_CONTROL1_MANAOOSC_LEN 1 +#define TFA98XX_SYS_CONTROL1_MANAOOSC_MAX 1 +#define TFA98XX_SYS_CONTROL1_MANAOOSC_MSK 0x10 + +/* + * man_enbl_brown_out + */ +#define TFA98XX_SYS_CONTROL1_MANROBOD (0x1<<5) +#define TFA98XX_SYS_CONTROL1_MANROBOD_POS 5 +#define TFA98XX_SYS_CONTROL1_MANROBOD_LEN 1 +#define TFA98XX_SYS_CONTROL1_MANROBOD_MAX 1 +#define TFA98XX_SYS_CONTROL1_MANROBOD_MSK 0x20 + +/* + * enbl_bod + */ +#define TFA98XX_SYS_CONTROL1_BODE (0x1<<6) +#define TFA98XX_SYS_CONTROL1_BODE_POS 6 +#define TFA98XX_SYS_CONTROL1_BODE_LEN 1 +#define TFA98XX_SYS_CONTROL1_BODE_MAX 1 +#define TFA98XX_SYS_CONTROL1_BODE_MSK 0x40 + +/* + * enbl_bod_hyst + */ +#define TFA98XX_SYS_CONTROL1_BODHYS (0x1<<7) +#define TFA98XX_SYS_CONTROL1_BODHYS_POS 7 +#define TFA98XX_SYS_CONTROL1_BODHYS_LEN 1 +#define TFA98XX_SYS_CONTROL1_BODHYS_MAX 1 +#define TFA98XX_SYS_CONTROL1_BODHYS_MSK 0x80 + +/* + * bod_delay + */ +#define TFA98XX_SYS_CONTROL1_BODFILT (0x3<<8) +#define TFA98XX_SYS_CONTROL1_BODFILT_POS 8 +#define TFA98XX_SYS_CONTROL1_BODFILT_LEN 2 +#define TFA98XX_SYS_CONTROL1_BODFILT_MAX 3 +#define TFA98XX_SYS_CONTROL1_BODFILT_MSK 0x300 + +/* + * bod_lvlsel + */ +#define TFA98XX_SYS_CONTROL1_BODTHLVL (0x3<<10) +#define TFA98XX_SYS_CONTROL1_BODTHLVL_POS 10 +#define TFA98XX_SYS_CONTROL1_BODTHLVL_LEN 2 +#define TFA98XX_SYS_CONTROL1_BODTHLVL_MAX 3 +#define TFA98XX_SYS_CONTROL1_BODTHLVL_MSK 0xc00 + +/* + * disable_mute_time_out + */ +#define TFA98XX_SYS_CONTROL1_MUTETO (0x1<<13) +#define TFA98XX_SYS_CONTROL1_MUTETO_POS 13 +#define TFA98XX_SYS_CONTROL1_MUTETO_LEN 1 +#define TFA98XX_SYS_CONTROL1_MUTETO_MAX 1 +#define TFA98XX_SYS_CONTROL1_MUTETO_MSK 0x2000 + +/* + * pwm_sel_rcv_ns + */ +#define TFA98XX_SYS_CONTROL1_RCVNS (0x1<<14) +#define TFA98XX_SYS_CONTROL1_RCVNS_POS 14 +#define TFA98XX_SYS_CONTROL1_RCVNS_LEN 1 +#define TFA98XX_SYS_CONTROL1_RCVNS_MAX 1 +#define TFA98XX_SYS_CONTROL1_RCVNS_MSK 0x4000 + +/* + * man_enbl_watchdog + */ +#define TFA98XX_SYS_CONTROL1_MANWDE (0x1<<15) +#define TFA98XX_SYS_CONTROL1_MANWDE_POS 15 +#define TFA98XX_SYS_CONTROL1_MANWDE_LEN 1 +#define TFA98XX_SYS_CONTROL1_MANWDE_MAX 1 +#define TFA98XX_SYS_CONTROL1_MANWDE_MSK 0x8000 + + +/* + * (0x02)-sys_control2 + */ + +/* + * audio_fs + */ +#define TFA98XX_SYS_CONTROL2_AUDFS (0xf<<0) +#define TFA98XX_SYS_CONTROL2_AUDFS_POS 0 +#define TFA98XX_SYS_CONTROL2_AUDFS_LEN 4 +#define TFA98XX_SYS_CONTROL2_AUDFS_MAX 15 +#define TFA98XX_SYS_CONTROL2_AUDFS_MSK 0xf + +/* + * input_level + */ +#define TFA98XX_SYS_CONTROL2_INPLEV (0x1<<4) +#define TFA98XX_SYS_CONTROL2_INPLEV_POS 4 +#define TFA98XX_SYS_CONTROL2_INPLEV_LEN 1 +#define TFA98XX_SYS_CONTROL2_INPLEV_MAX 1 +#define TFA98XX_SYS_CONTROL2_INPLEV_MSK 0x10 + +/* + * cs_frac_delay + */ +#define TFA98XX_SYS_CONTROL2_FRACTDEL (0x3f<<5) +#define TFA98XX_SYS_CONTROL2_FRACTDEL_POS 5 +#define TFA98XX_SYS_CONTROL2_FRACTDEL_LEN 6 +#define TFA98XX_SYS_CONTROL2_FRACTDEL_MAX 63 +#define TFA98XX_SYS_CONTROL2_FRACTDEL_MSK 0x7e0 + +/* + * bypass_hvbat_filter + */ +#define TFA98XX_SYS_CONTROL2_BYPHVBF (0x1<<11) +#define TFA98XX_SYS_CONTROL2_BYPHVBF_POS 11 +#define TFA98XX_SYS_CONTROL2_BYPHVBF_LEN 1 +#define TFA98XX_SYS_CONTROL2_BYPHVBF_MAX 1 +#define TFA98XX_SYS_CONTROL2_BYPHVBF_MSK 0x800 + +/* + * ctrl_rcvldop_bypass + */ +#define TFA98XX_SYS_CONTROL2_LDOBYP (0x1<<12) +#define TFA98XX_SYS_CONTROL2_LDOBYP_POS 12 +#define TFA98XX_SYS_CONTROL2_LDOBYP_LEN 1 +#define TFA98XX_SYS_CONTROL2_LDOBYP_MAX 1 +#define TFA98XX_SYS_CONTROL2_LDOBYP_MSK 0x1000 + + +/* + * (0x03)-device_revision + */ + +/* + * device_rev + */ +#define TFA98XX_DEVICE_REVISION_REV (0xffff<<0) +#define TFA98XX_DEVICE_REVISION_REV_POS 0 +#define TFA98XX_DEVICE_REVISION_REV_LEN 16 +#define TFA98XX_DEVICE_REVISION_REV_MAX 65535 +#define TFA98XX_DEVICE_REVISION_REV_MSK 0xffff + + +/* + * (0x04)-clock_control + */ + +/* + * pll_clkin_sel + */ +#define TFA98XX_CLOCK_CONTROL_REFCKEXT (0x3<<0) +#define TFA98XX_CLOCK_CONTROL_REFCKEXT_POS 0 +#define TFA98XX_CLOCK_CONTROL_REFCKEXT_LEN 2 +#define TFA98XX_CLOCK_CONTROL_REFCKEXT_MAX 3 +#define TFA98XX_CLOCK_CONTROL_REFCKEXT_MSK 0x3 + +/* + * pll_clkin_sel_osc + */ +#define TFA98XX_CLOCK_CONTROL_REFCKSEL (0x1<<2) +#define TFA98XX_CLOCK_CONTROL_REFCKSEL_POS 2 +#define TFA98XX_CLOCK_CONTROL_REFCKSEL_LEN 1 +#define TFA98XX_CLOCK_CONTROL_REFCKSEL_MAX 1 +#define TFA98XX_CLOCK_CONTROL_REFCKSEL_MSK 0x4 + + +/* + * (0x05)-clock_gating_control + */ + +/* + * enbl_spkr_ss_left + */ +#define TFA98XX_CLOCK_GATING_CONTROL_SSLEFTE (0x1<<0) +#define TFA98XX_CLOCK_GATING_CONTROL_SSLEFTE_POS 0 +#define TFA98XX_CLOCK_GATING_CONTROL_SSLEFTE_LEN 1 +#define TFA98XX_CLOCK_GATING_CONTROL_SSLEFTE_MAX 1 +#define TFA98XX_CLOCK_GATING_CONTROL_SSLEFTE_MSK 0x1 + +/* + * enbl_spkr_ss_right + */ +#define TFA98XX_CLOCK_GATING_CONTROL_SSRIGHTE (0x1<<1) +#define TFA98XX_CLOCK_GATING_CONTROL_SSRIGHTE_POS 1 +#define TFA98XX_CLOCK_GATING_CONTROL_SSRIGHTE_LEN 1 +#define TFA98XX_CLOCK_GATING_CONTROL_SSRIGHTE_MAX 1 +#define TFA98XX_CLOCK_GATING_CONTROL_SSRIGHTE_MSK 0x2 + +/* + * enbl_volsense_left + */ +#define TFA98XX_CLOCK_GATING_CONTROL_VSLEFTE (0x1<<2) +#define TFA98XX_CLOCK_GATING_CONTROL_VSLEFTE_POS 2 +#define TFA98XX_CLOCK_GATING_CONTROL_VSLEFTE_LEN 1 +#define TFA98XX_CLOCK_GATING_CONTROL_VSLEFTE_MAX 1 +#define TFA98XX_CLOCK_GATING_CONTROL_VSLEFTE_MSK 0x4 + +/* + * enbl_volsense_right + */ +#define TFA98XX_CLOCK_GATING_CONTROL_VSRIGHTE (0x1<<3) +#define TFA98XX_CLOCK_GATING_CONTROL_VSRIGHTE_POS 3 +#define TFA98XX_CLOCK_GATING_CONTROL_VSRIGHTE_LEN 1 +#define TFA98XX_CLOCK_GATING_CONTROL_VSRIGHTE_MAX 1 +#define TFA98XX_CLOCK_GATING_CONTROL_VSRIGHTE_MSK 0x8 + +/* + * enbl_cursense_left + */ +#define TFA98XX_CLOCK_GATING_CONTROL_CSLEFTE (0x1<<4) +#define TFA98XX_CLOCK_GATING_CONTROL_CSLEFTE_POS 4 +#define TFA98XX_CLOCK_GATING_CONTROL_CSLEFTE_LEN 1 +#define TFA98XX_CLOCK_GATING_CONTROL_CSLEFTE_MAX 1 +#define TFA98XX_CLOCK_GATING_CONTROL_CSLEFTE_MSK 0x10 + +/* + * enbl_cursense_right + */ +#define TFA98XX_CLOCK_GATING_CONTROL_CSRIGHTE (0x1<<5) +#define TFA98XX_CLOCK_GATING_CONTROL_CSRIGHTE_POS 5 +#define TFA98XX_CLOCK_GATING_CONTROL_CSRIGHTE_LEN 1 +#define TFA98XX_CLOCK_GATING_CONTROL_CSRIGHTE_MAX 1 +#define TFA98XX_CLOCK_GATING_CONTROL_CSRIGHTE_MSK 0x20 + +/* + * enbl_pdm_ss + */ +#define TFA98XX_CLOCK_GATING_CONTROL_SSPDME (0x1<<6) +#define TFA98XX_CLOCK_GATING_CONTROL_SSPDME_POS 6 +#define TFA98XX_CLOCK_GATING_CONTROL_SSPDME_LEN 1 +#define TFA98XX_CLOCK_GATING_CONTROL_SSPDME_MAX 1 +#define TFA98XX_CLOCK_GATING_CONTROL_SSPDME_MSK 0x40 + + +/* + * (0x0d)-side_tone_config + */ + +/* + * side_tone_gain + */ +#define TFA98XX_SIDE_TONE_CONFIG_STGAIN (0x1ff<<1) +#define TFA98XX_SIDE_TONE_CONFIG_STGAIN_POS 1 +#define TFA98XX_SIDE_TONE_CONFIG_STGAIN_LEN 9 +#define TFA98XX_SIDE_TONE_CONFIG_STGAIN_MAX 511 +#define TFA98XX_SIDE_TONE_CONFIG_STGAIN_MSK 0x3fe + +/* + * mute_side_tone + */ +#define TFA98XX_SIDE_TONE_CONFIG_PDMSMUTE (0x1<<10) +#define TFA98XX_SIDE_TONE_CONFIG_PDMSMUTE_POS 10 +#define TFA98XX_SIDE_TONE_CONFIG_PDMSMUTE_LEN 1 +#define TFA98XX_SIDE_TONE_CONFIG_PDMSMUTE_MAX 1 +#define TFA98XX_SIDE_TONE_CONFIG_PDMSMUTE_MSK 0x400 + + +/* + * (0x0e)-ctrl_digtoana_reg + */ + +/* + * ctrl_digtoana + */ +#define TFA98XX_CTRL_DIGTOANA_REG_SWVSTEP (0x7f<<0) +#define TFA98XX_CTRL_DIGTOANA_REG_SWVSTEP_POS 0 +#define TFA98XX_CTRL_DIGTOANA_REG_SWVSTEP_LEN 7 +#define TFA98XX_CTRL_DIGTOANA_REG_SWVSTEP_MAX 127 +#define TFA98XX_CTRL_DIGTOANA_REG_SWVSTEP_MSK 0x7f + + +/* + * (0x10)-status_flags0 + */ + +/* + * flag_por + */ +#define TFA98XX_STATUS_FLAGS0_VDDS (0x1<<0) +#define TFA98XX_STATUS_FLAGS0_VDDS_POS 0 +#define TFA98XX_STATUS_FLAGS0_VDDS_LEN 1 +#define TFA98XX_STATUS_FLAGS0_VDDS_MAX 1 +#define TFA98XX_STATUS_FLAGS0_VDDS_MSK 0x1 + +/* + * flag_pll_lock + */ +#define TFA98XX_STATUS_FLAGS0_PLLS (0x1<<1) +#define TFA98XX_STATUS_FLAGS0_PLLS_POS 1 +#define TFA98XX_STATUS_FLAGS0_PLLS_LEN 1 +#define TFA98XX_STATUS_FLAGS0_PLLS_MAX 1 +#define TFA98XX_STATUS_FLAGS0_PLLS_MSK 0x2 + +/* + * flag_otpok + */ +#define TFA98XX_STATUS_FLAGS0_OTDS (0x1<<2) +#define TFA98XX_STATUS_FLAGS0_OTDS_POS 2 +#define TFA98XX_STATUS_FLAGS0_OTDS_LEN 1 +#define TFA98XX_STATUS_FLAGS0_OTDS_MAX 1 +#define TFA98XX_STATUS_FLAGS0_OTDS_MSK 0x4 + +/* + * flag_ovpok + */ +#define TFA98XX_STATUS_FLAGS0_OVDS (0x1<<3) +#define TFA98XX_STATUS_FLAGS0_OVDS_POS 3 +#define TFA98XX_STATUS_FLAGS0_OVDS_LEN 1 +#define TFA98XX_STATUS_FLAGS0_OVDS_MAX 1 +#define TFA98XX_STATUS_FLAGS0_OVDS_MSK 0x8 + +/* + * flag_uvpok + */ +#define TFA98XX_STATUS_FLAGS0_UVDS (0x1<<4) +#define TFA98XX_STATUS_FLAGS0_UVDS_POS 4 +#define TFA98XX_STATUS_FLAGS0_UVDS_LEN 1 +#define TFA98XX_STATUS_FLAGS0_UVDS_MAX 1 +#define TFA98XX_STATUS_FLAGS0_UVDS_MSK 0x10 + +/* + * flag_clocks_stable + */ +#define TFA98XX_STATUS_FLAGS0_CLKS (0x1<<6) +#define TFA98XX_STATUS_FLAGS0_CLKS_POS 5 +#define TFA98XX_STATUS_FLAGS0_CLKS_LEN 1 +#define TFA98XX_STATUS_FLAGS0_CLKS_MAX 1 +#define TFA98XX_STATUS_FLAGS0_CLKS_MSK 0x20 + +/* + * flag_mtp_busy + */ +#define TFA98XX_STATUS_FLAGS0_MTPB (0x1<<6) +#define TFA98XX_STATUS_FLAGS0_MTPB_POS 6 +#define TFA98XX_STATUS_FLAGS0_MTPB_LEN 1 +#define TFA98XX_STATUS_FLAGS0_MTPB_MAX 1 +#define TFA98XX_STATUS_FLAGS0_MTPB_MSK 0x40 + +/* + * flag_lost_clk + */ +#define TFA98XX_STATUS_FLAGS0_NOCLK (0x1<<7) +#define TFA98XX_STATUS_FLAGS0_NOCLK_POS 7 +#define TFA98XX_STATUS_FLAGS0_NOCLK_LEN 1 +#define TFA98XX_STATUS_FLAGS0_NOCLK_MAX 1 +#define TFA98XX_STATUS_FLAGS0_NOCLK_MSK 0x80 + +/* + * flag_cf_speakererror + */ +#define TFA98XX_STATUS_FLAGS0_SPKS (0x1<<8) +#define TFA98XX_STATUS_FLAGS0_SPKS_POS 8 +#define TFA98XX_STATUS_FLAGS0_SPKS_LEN 1 +#define TFA98XX_STATUS_FLAGS0_SPKS_MAX 1 +#define TFA98XX_STATUS_FLAGS0_SPKS_MSK 0x100 + +/* + * flag_cold_started + */ +#define TFA98XX_STATUS_FLAGS0_ACS (0x1<<9) +#define TFA98XX_STATUS_FLAGS0_ACS_POS 9 +#define TFA98XX_STATUS_FLAGS0_ACS_LEN 1 +#define TFA98XX_STATUS_FLAGS0_ACS_MAX 1 +#define TFA98XX_STATUS_FLAGS0_ACS_MSK 0x200 + +/* + * flag_engage + */ +#define TFA98XX_STATUS_FLAGS0_SWS (0x1<<10) +#define TFA98XX_STATUS_FLAGS0_SWS_POS 10 +#define TFA98XX_STATUS_FLAGS0_SWS_LEN 1 +#define TFA98XX_STATUS_FLAGS0_SWS_MAX 1 +#define TFA98XX_STATUS_FLAGS0_SWS_MSK 0x400 + +/* + * flag_watchdog_reset + */ +#define TFA98XX_STATUS_FLAGS0_WDS (0x1<<11) +#define TFA98XX_STATUS_FLAGS0_WDS_POS 11 +#define TFA98XX_STATUS_FLAGS0_WDS_LEN 1 +#define TFA98XX_STATUS_FLAGS0_WDS_MAX 1 +#define TFA98XX_STATUS_FLAGS0_WDS_MSK 0x800 + +/* + * flag_enbl_amp + */ +#define TFA98XX_STATUS_FLAGS0_AMPS (0x1<<12) +#define TFA98XX_STATUS_FLAGS0_AMPS_POS 12 +#define TFA98XX_STATUS_FLAGS0_AMPS_LEN 1 +#define TFA98XX_STATUS_FLAGS0_AMPS_MAX 1 +#define TFA98XX_STATUS_FLAGS0_AMPS_MSK 0x1000 + +/* + * flag_enbl_ref + */ +#define TFA98XX_STATUS_FLAGS0_AREFS (0x1<<13) +#define TFA98XX_STATUS_FLAGS0_AREFS_POS 13 +#define TFA98XX_STATUS_FLAGS0_AREFS_LEN 1 +#define TFA98XX_STATUS_FLAGS0_AREFS_MAX 1 +#define TFA98XX_STATUS_FLAGS0_AREFS_MSK 0x2000 + +/* + * flag_adc10_ready + */ +#define TFA98XX_STATUS_FLAGS0_ADCCR (0x1<<14) +#define TFA98XX_STATUS_FLAGS0_ADCCR_POS 14 +#define TFA98XX_STATUS_FLAGS0_ADCCR_LEN 1 +#define TFA98XX_STATUS_FLAGS0_ADCCR_MAX 1 +#define TFA98XX_STATUS_FLAGS0_ADCCR_MSK 0x4000 + +/* + * flag_bod_vddd_nok + */ +#define TFA98XX_STATUS_FLAGS0_BODNOK (0x1<<15) +#define TFA98XX_STATUS_FLAGS0_BODNOK_POS 15 +#define TFA98XX_STATUS_FLAGS0_BODNOK_LEN 1 +#define TFA98XX_STATUS_FLAGS0_BODNOK_MAX 1 +#define TFA98XX_STATUS_FLAGS0_BODNOK_MSK 0x8000 + + +/* + * (0x11)-status_flags1 + */ + +/* + * flag_bst_bstcur + */ +#define TFA98XX_STATUS_FLAGS1_DCIL (0x1<<0) +#define TFA98XX_STATUS_FLAGS1_DCIL_POS 0 +#define TFA98XX_STATUS_FLAGS1_DCIL_LEN 1 +#define TFA98XX_STATUS_FLAGS1_DCIL_MAX 1 +#define TFA98XX_STATUS_FLAGS1_DCIL_MSK 0x1 + +/* + * flag_bst_hiz + */ +#define TFA98XX_STATUS_FLAGS1_DCDCA (0x1<<1) +#define TFA98XX_STATUS_FLAGS1_DCDCA_POS 1 +#define TFA98XX_STATUS_FLAGS1_DCDCA_LEN 1 +#define TFA98XX_STATUS_FLAGS1_DCDCA_MAX 1 +#define TFA98XX_STATUS_FLAGS1_DCDCA_MSK 0x2 + +/* + * flag_bst_ocpok + */ +#define TFA98XX_STATUS_FLAGS1_DCOCPOK (0x1<<2) +#define TFA98XX_STATUS_FLAGS1_DCOCPOK_POS 2 +#define TFA98XX_STATUS_FLAGS1_DCOCPOK_LEN 1 +#define TFA98XX_STATUS_FLAGS1_DCOCPOK_MAX 1 +#define TFA98XX_STATUS_FLAGS1_DCOCPOK_MSK 0x4 + +/* + * flag_bst_voutcomp + */ +#define TFA98XX_STATUS_FLAGS1_DCHVBAT (0x1<<4) +#define TFA98XX_STATUS_FLAGS1_DCHVBAT_POS 4 +#define TFA98XX_STATUS_FLAGS1_DCHVBAT_LEN 1 +#define TFA98XX_STATUS_FLAGS1_DCHVBAT_MAX 1 +#define TFA98XX_STATUS_FLAGS1_DCHVBAT_MSK 0x10 + +/* + * flag_bst_voutcomp86 + */ +#define TFA98XX_STATUS_FLAGS1_DCH114 (0x1<<5) +#define TFA98XX_STATUS_FLAGS1_DCH114_POS 5 +#define TFA98XX_STATUS_FLAGS1_DCH114_LEN 1 +#define TFA98XX_STATUS_FLAGS1_DCH114_MAX 1 +#define TFA98XX_STATUS_FLAGS1_DCH114_MSK 0x20 + +/* + * flag_bst_voutcomp93 + */ +#define TFA98XX_STATUS_FLAGS1_DCH107 (0x1<<6) +#define TFA98XX_STATUS_FLAGS1_DCH107_POS 6 +#define TFA98XX_STATUS_FLAGS1_DCH107_LEN 1 +#define TFA98XX_STATUS_FLAGS1_DCH107_MAX 1 +#define TFA98XX_STATUS_FLAGS1_DCH107_MSK 0x40 + +/* + * flag_soft_mute_busy + */ +#define TFA98XX_STATUS_FLAGS1_STMUTEB (0x1<<7) +#define TFA98XX_STATUS_FLAGS1_STMUTEB_POS 7 +#define TFA98XX_STATUS_FLAGS1_STMUTEB_LEN 1 +#define TFA98XX_STATUS_FLAGS1_STMUTEB_MAX 1 +#define TFA98XX_STATUS_FLAGS1_STMUTEB_MSK 0x80 + +/* + * flag_soft_mute_state + */ +#define TFA98XX_STATUS_FLAGS1_STMUTE (0x1<<8) +#define TFA98XX_STATUS_FLAGS1_STMUTE_POS 8 +#define TFA98XX_STATUS_FLAGS1_STMUTE_LEN 1 +#define TFA98XX_STATUS_FLAGS1_STMUTE_MAX 1 +#define TFA98XX_STATUS_FLAGS1_STMUTE_MSK 0x100 + +/* + * flag_tdm_lut_error + */ +#define TFA98XX_STATUS_FLAGS1_TDMLUTER (0x1<<9) +#define TFA98XX_STATUS_FLAGS1_TDMLUTER_POS 9 +#define TFA98XX_STATUS_FLAGS1_TDMLUTER_LEN 1 +#define TFA98XX_STATUS_FLAGS1_TDMLUTER_MAX 1 +#define TFA98XX_STATUS_FLAGS1_TDMLUTER_MSK 0x200 + +/* + * flag_tdm_status + */ +#define TFA98XX_STATUS_FLAGS1_TDMSTAT (0x7<<10) +#define TFA98XX_STATUS_FLAGS1_TDMSTAT_POS 10 +#define TFA98XX_STATUS_FLAGS1_TDMSTAT_LEN 3 +#define TFA98XX_STATUS_FLAGS1_TDMSTAT_MAX 7 +#define TFA98XX_STATUS_FLAGS1_TDMSTAT_MSK 0x1c00 + +/* + * flag_tdm_error + */ +#define TFA98XX_STATUS_FLAGS1_TDMERR (0x1<<13) +#define TFA98XX_STATUS_FLAGS1_TDMERR_POS 13 +#define TFA98XX_STATUS_FLAGS1_TDMERR_LEN 1 +#define TFA98XX_STATUS_FLAGS1_TDMERR_MAX 1 +#define TFA98XX_STATUS_FLAGS1_TDMERR_MSK 0x2000 + +/* + * flag_haptic_busy + */ +#define TFA98XX_STATUS_FLAGS1_HAPTIC (0x1<<14) +#define TFA98XX_STATUS_FLAGS1_HAPTIC_POS 14 +#define TFA98XX_STATUS_FLAGS1_HAPTIC_LEN 1 +#define TFA98XX_STATUS_FLAGS1_HAPTIC_MAX 1 +#define TFA98XX_STATUS_FLAGS1_HAPTIC_MSK 0x4000 + + +/* + * (0x12)-status_flags2 + */ + +/* + * flag_ocpokap_left + */ +#define TFA98XX_STATUS_FLAGS2_OCPOAPL (0x1<<0) +#define TFA98XX_STATUS_FLAGS2_OCPOAPL_POS 0 +#define TFA98XX_STATUS_FLAGS2_OCPOAPL_LEN 1 +#define TFA98XX_STATUS_FLAGS2_OCPOAPL_MAX 1 +#define TFA98XX_STATUS_FLAGS2_OCPOAPL_MSK 0x1 + +/* + * flag_ocpokan_left + */ +#define TFA98XX_STATUS_FLAGS2_OCPOANL (0x1<<1) +#define TFA98XX_STATUS_FLAGS2_OCPOANL_POS 1 +#define TFA98XX_STATUS_FLAGS2_OCPOANL_LEN 1 +#define TFA98XX_STATUS_FLAGS2_OCPOANL_MAX 1 +#define TFA98XX_STATUS_FLAGS2_OCPOANL_MSK 0x2 + +/* + * flag_ocpokbp_left + */ +#define TFA98XX_STATUS_FLAGS2_OCPOBPL (0x1<<2) +#define TFA98XX_STATUS_FLAGS2_OCPOBPL_POS 2 +#define TFA98XX_STATUS_FLAGS2_OCPOBPL_LEN 1 +#define TFA98XX_STATUS_FLAGS2_OCPOBPL_MAX 1 +#define TFA98XX_STATUS_FLAGS2_OCPOBPL_MSK 0x4 + +/* + * flag_ocpokbn_left + */ +#define TFA98XX_STATUS_FLAGS2_OCPOBNL (0x1<<3) +#define TFA98XX_STATUS_FLAGS2_OCPOBNL_POS 3 +#define TFA98XX_STATUS_FLAGS2_OCPOBNL_LEN 1 +#define TFA98XX_STATUS_FLAGS2_OCPOBNL_MAX 1 +#define TFA98XX_STATUS_FLAGS2_OCPOBNL_MSK 0x8 + +/* + * flag_clipa_high_left + */ +#define TFA98XX_STATUS_FLAGS2_CLIPAHL (0x1<<4) +#define TFA98XX_STATUS_FLAGS2_CLIPAHL_POS 4 +#define TFA98XX_STATUS_FLAGS2_CLIPAHL_LEN 1 +#define TFA98XX_STATUS_FLAGS2_CLIPAHL_MAX 1 +#define TFA98XX_STATUS_FLAGS2_CLIPAHL_MSK 0x10 + +/* + * flag_clipa_low_left + */ +#define TFA98XX_STATUS_FLAGS2_CLIPALL (0x1<<5) +#define TFA98XX_STATUS_FLAGS2_CLIPALL_POS 5 +#define TFA98XX_STATUS_FLAGS2_CLIPALL_LEN 1 +#define TFA98XX_STATUS_FLAGS2_CLIPALL_MAX 1 +#define TFA98XX_STATUS_FLAGS2_CLIPALL_MSK 0x20 + +/* + * flag_clipb_high_left + */ +#define TFA98XX_STATUS_FLAGS2_CLIPBHL (0x1<<6) +#define TFA98XX_STATUS_FLAGS2_CLIPBHL_POS 6 +#define TFA98XX_STATUS_FLAGS2_CLIPBHL_LEN 1 +#define TFA98XX_STATUS_FLAGS2_CLIPBHL_MAX 1 +#define TFA98XX_STATUS_FLAGS2_CLIPBHL_MSK 0x40 + +/* + * flag_clipb_low_left + */ +#define TFA98XX_STATUS_FLAGS2_CLIPBLL (0x1<<7) +#define TFA98XX_STATUS_FLAGS2_CLIPBLL_POS 7 +#define TFA98XX_STATUS_FLAGS2_CLIPBLL_LEN 1 +#define TFA98XX_STATUS_FLAGS2_CLIPBLL_MAX 1 +#define TFA98XX_STATUS_FLAGS2_CLIPBLL_MSK 0x80 + +/* + * flag_ocpokap_rcv + */ +#define TFA98XX_STATUS_FLAGS2_OCPOAPRC (0x1<<8) +#define TFA98XX_STATUS_FLAGS2_OCPOAPRC_POS 8 +#define TFA98XX_STATUS_FLAGS2_OCPOAPRC_LEN 1 +#define TFA98XX_STATUS_FLAGS2_OCPOAPRC_MAX 1 +#define TFA98XX_STATUS_FLAGS2_OCPOAPRC_MSK 0x100 + +/* + * flag_ocpokan_rcv + */ +#define TFA98XX_STATUS_FLAGS2_OCPOANRC (0x1<<9) +#define TFA98XX_STATUS_FLAGS2_OCPOANRC_POS 9 +#define TFA98XX_STATUS_FLAGS2_OCPOANRC_LEN 1 +#define TFA98XX_STATUS_FLAGS2_OCPOANRC_MAX 1 +#define TFA98XX_STATUS_FLAGS2_OCPOANRC_MSK 0x200 + +/* + * flag_ocpokbp_rcv + */ +#define TFA98XX_STATUS_FLAGS2_OCPOBPRC (0x1<<10) +#define TFA98XX_STATUS_FLAGS2_OCPOBPRC_POS 10 +#define TFA98XX_STATUS_FLAGS2_OCPOBPRC_LEN 1 +#define TFA98XX_STATUS_FLAGS2_OCPOBPRC_MAX 1 +#define TFA98XX_STATUS_FLAGS2_OCPOBPRC_MSK 0x400 + +/* + * flag_ocpokbn_rcv + */ +#define TFA98XX_STATUS_FLAGS2_OCPOBNRC (0x1<<11) +#define TFA98XX_STATUS_FLAGS2_OCPOBNRC_POS 11 +#define TFA98XX_STATUS_FLAGS2_OCPOBNRC_LEN 1 +#define TFA98XX_STATUS_FLAGS2_OCPOBNRC_MAX 1 +#define TFA98XX_STATUS_FLAGS2_OCPOBNRC_MSK 0x800 + +/* + * flag_rcvldop_ready + */ +#define TFA98XX_STATUS_FLAGS2_RCVLDOR (0x1<<12) +#define TFA98XX_STATUS_FLAGS2_RCVLDOR_POS 12 +#define TFA98XX_STATUS_FLAGS2_RCVLDOR_LEN 1 +#define TFA98XX_STATUS_FLAGS2_RCVLDOR_MAX 1 +#define TFA98XX_STATUS_FLAGS2_RCVLDOR_MSK 0x1000 + +/* + * flag_rcvldop_bypassready + */ +#define TFA98XX_STATUS_FLAGS2_RCVLDOBR (0x1<<13) +#define TFA98XX_STATUS_FLAGS2_RCVLDOBR_POS 13 +#define TFA98XX_STATUS_FLAGS2_RCVLDOBR_LEN 1 +#define TFA98XX_STATUS_FLAGS2_RCVLDOBR_MAX 1 +#define TFA98XX_STATUS_FLAGS2_RCVLDOBR_MSK 0x2000 + +/* + * flag_ocp_alarm_left + */ +#define TFA98XX_STATUS_FLAGS2_OCDSL (0x1<<14) +#define TFA98XX_STATUS_FLAGS2_OCDSL_POS 14 +#define TFA98XX_STATUS_FLAGS2_OCDSL_LEN 1 +#define TFA98XX_STATUS_FLAGS2_OCDSL_MAX 1 +#define TFA98XX_STATUS_FLAGS2_OCDSL_MSK 0x4000 + +/* + * flag_clip_left + */ +#define TFA98XX_STATUS_FLAGS2_CLIPSL (0x1<<15) +#define TFA98XX_STATUS_FLAGS2_CLIPSL_POS 15 +#define TFA98XX_STATUS_FLAGS2_CLIPSL_LEN 1 +#define TFA98XX_STATUS_FLAGS2_CLIPSL_MAX 1 +#define TFA98XX_STATUS_FLAGS2_CLIPSL_MSK 0x8000 + + +/* + * (0x13)-status_flags3 + */ + +/* + * flag_ocpokap_right + */ +#define TFA98XX_STATUS_FLAGS3_OCPOAPR (0x1<<0) +#define TFA98XX_STATUS_FLAGS3_OCPOAPR_POS 0 +#define TFA98XX_STATUS_FLAGS3_OCPOAPR_LEN 1 +#define TFA98XX_STATUS_FLAGS3_OCPOAPR_MAX 1 +#define TFA98XX_STATUS_FLAGS3_OCPOAPR_MSK 0x1 + +/* + * flag_ocpokan_right + */ +#define TFA98XX_STATUS_FLAGS3_OCPOANR (0x1<<1) +#define TFA98XX_STATUS_FLAGS3_OCPOANR_POS 1 +#define TFA98XX_STATUS_FLAGS3_OCPOANR_LEN 1 +#define TFA98XX_STATUS_FLAGS3_OCPOANR_MAX 1 +#define TFA98XX_STATUS_FLAGS3_OCPOANR_MSK 0x2 + +/* + * flag_ocpokbp_right + */ +#define TFA98XX_STATUS_FLAGS3_OCPOBPR (0x1<<2) +#define TFA98XX_STATUS_FLAGS3_OCPOBPR_POS 2 +#define TFA98XX_STATUS_FLAGS3_OCPOBPR_LEN 1 +#define TFA98XX_STATUS_FLAGS3_OCPOBPR_MAX 1 +#define TFA98XX_STATUS_FLAGS3_OCPOBPR_MSK 0x4 + +/* + * flag_ocpokbn_right + */ +#define TFA98XX_STATUS_FLAGS3_OCPOBNR (0x1<<3) +#define TFA98XX_STATUS_FLAGS3_OCPOBNR_POS 3 +#define TFA98XX_STATUS_FLAGS3_OCPOBNR_LEN 1 +#define TFA98XX_STATUS_FLAGS3_OCPOBNR_MAX 1 +#define TFA98XX_STATUS_FLAGS3_OCPOBNR_MSK 0x8 + +/* + * flag_clipa_high_right + */ +#define TFA98XX_STATUS_FLAGS3_CLIPAHR (0x1<<4) +#define TFA98XX_STATUS_FLAGS3_CLIPAHR_POS 4 +#define TFA98XX_STATUS_FLAGS3_CLIPAHR_LEN 1 +#define TFA98XX_STATUS_FLAGS3_CLIPAHR_MAX 1 +#define TFA98XX_STATUS_FLAGS3_CLIPAHR_MSK 0x10 + +/* + * flag_clipa_low_right + */ +#define TFA98XX_STATUS_FLAGS3_CLIPALR (0x1<<5) +#define TFA98XX_STATUS_FLAGS3_CLIPALR_POS 5 +#define TFA98XX_STATUS_FLAGS3_CLIPALR_LEN 1 +#define TFA98XX_STATUS_FLAGS3_CLIPALR_MAX 1 +#define TFA98XX_STATUS_FLAGS3_CLIPALR_MSK 0x20 + +/* + * flag_clipb_high_right + */ +#define TFA98XX_STATUS_FLAGS3_CLIPBHR (0x1<<6) +#define TFA98XX_STATUS_FLAGS3_CLIPBHR_POS 6 +#define TFA98XX_STATUS_FLAGS3_CLIPBHR_LEN 1 +#define TFA98XX_STATUS_FLAGS3_CLIPBHR_MAX 1 +#define TFA98XX_STATUS_FLAGS3_CLIPBHR_MSK 0x40 + +/* + * flag_clipb_low_right + */ +#define TFA98XX_STATUS_FLAGS3_CLIPBLR (0x1<<7) +#define TFA98XX_STATUS_FLAGS3_CLIPBLR_POS 7 +#define TFA98XX_STATUS_FLAGS3_CLIPBLR_LEN 1 +#define TFA98XX_STATUS_FLAGS3_CLIPBLR_MAX 1 +#define TFA98XX_STATUS_FLAGS3_CLIPBLR_MSK 0x80 + +/* + * flag_ocp_alarm_right + */ +#define TFA98XX_STATUS_FLAGS3_OCDSR (0x1<<8) +#define TFA98XX_STATUS_FLAGS3_OCDSR_POS 8 +#define TFA98XX_STATUS_FLAGS3_OCDSR_LEN 1 +#define TFA98XX_STATUS_FLAGS3_OCDSR_MAX 1 +#define TFA98XX_STATUS_FLAGS3_OCDSR_MSK 0x100 + +/* + * flag_clip_right + */ +#define TFA98XX_STATUS_FLAGS3_CLIPSR (0x1<<9) +#define TFA98XX_STATUS_FLAGS3_CLIPSR_POS 9 +#define TFA98XX_STATUS_FLAGS3_CLIPSR_LEN 1 +#define TFA98XX_STATUS_FLAGS3_CLIPSR_MAX 1 +#define TFA98XX_STATUS_FLAGS3_CLIPSR_MSK 0x200 + +/* + * flag_mic_ocpok + */ +#define TFA98XX_STATUS_FLAGS3_OCPOKMC (0x1<<10) +#define TFA98XX_STATUS_FLAGS3_OCPOKMC_POS 10 +#define TFA98XX_STATUS_FLAGS3_OCPOKMC_LEN 1 +#define TFA98XX_STATUS_FLAGS3_OCPOKMC_MAX 1 +#define TFA98XX_STATUS_FLAGS3_OCPOKMC_MSK 0x400 + +/* + * flag_man_alarm_state + */ +#define TFA98XX_STATUS_FLAGS3_MANALARM (0x1<<11) +#define TFA98XX_STATUS_FLAGS3_MANALARM_POS 11 +#define TFA98XX_STATUS_FLAGS3_MANALARM_LEN 1 +#define TFA98XX_STATUS_FLAGS3_MANALARM_MAX 1 +#define TFA98XX_STATUS_FLAGS3_MANALARM_MSK 0x800 + +/* + * flag_man_wait_src_settings + */ +#define TFA98XX_STATUS_FLAGS3_MANWAIT1 (0x1<<12) +#define TFA98XX_STATUS_FLAGS3_MANWAIT1_POS 12 +#define TFA98XX_STATUS_FLAGS3_MANWAIT1_LEN 1 +#define TFA98XX_STATUS_FLAGS3_MANWAIT1_MAX 1 +#define TFA98XX_STATUS_FLAGS3_MANWAIT1_MSK 0x1000 + +/* + * flag_man_wait_cf_config + */ +#define TFA98XX_STATUS_FLAGS3_MANWAIT2 (0x1<<13) +#define TFA98XX_STATUS_FLAGS3_MANWAIT2_POS 13 +#define TFA98XX_STATUS_FLAGS3_MANWAIT2_LEN 1 +#define TFA98XX_STATUS_FLAGS3_MANWAIT2_MAX 1 +#define TFA98XX_STATUS_FLAGS3_MANWAIT2_MSK 0x2000 + +/* + * flag_man_start_mute_audio + */ +#define TFA98XX_STATUS_FLAGS3_MANMUTE (0x1<<14) +#define TFA98XX_STATUS_FLAGS3_MANMUTE_POS 14 +#define TFA98XX_STATUS_FLAGS3_MANMUTE_LEN 1 +#define TFA98XX_STATUS_FLAGS3_MANMUTE_MAX 1 +#define TFA98XX_STATUS_FLAGS3_MANMUTE_MSK 0x4000 + +/* + * flag_man_operating_state + */ +#define TFA98XX_STATUS_FLAGS3_MANOPER (0x1<<15) +#define TFA98XX_STATUS_FLAGS3_MANOPER_POS 15 +#define TFA98XX_STATUS_FLAGS3_MANOPER_LEN 1 +#define TFA98XX_STATUS_FLAGS3_MANOPER_MAX 1 +#define TFA98XX_STATUS_FLAGS3_MANOPER_MSK 0x8000 + + +/* + * (0x14)-status_flags4 + */ + +/* + * flag_cf_speakererror_left + */ +#define TFA98XX_STATUS_FLAGS4_SPKSL (0x1<<0) +#define TFA98XX_STATUS_FLAGS4_SPKSL_POS 0 +#define TFA98XX_STATUS_FLAGS4_SPKSL_LEN 1 +#define TFA98XX_STATUS_FLAGS4_SPKSL_MAX 1 +#define TFA98XX_STATUS_FLAGS4_SPKSL_MSK 0x1 + +/* + * flag_cf_speakererror_right + */ +#define TFA98XX_STATUS_FLAGS4_SPKSR (0x1<<1) +#define TFA98XX_STATUS_FLAGS4_SPKSR_POS 1 +#define TFA98XX_STATUS_FLAGS4_SPKSR_LEN 1 +#define TFA98XX_STATUS_FLAGS4_SPKSR_MAX 1 +#define TFA98XX_STATUS_FLAGS4_SPKSR_MSK 0x2 + +/* + * flag_clk_out_of_range + */ +#define TFA98XX_STATUS_FLAGS4_CLKOOR (0x1<<2) +#define TFA98XX_STATUS_FLAGS4_CLKOOR_POS 2 +#define TFA98XX_STATUS_FLAGS4_CLKOOR_LEN 1 +#define TFA98XX_STATUS_FLAGS4_CLKOOR_MAX 1 +#define TFA98XX_STATUS_FLAGS4_CLKOOR_MSK 0x4 + +/* + * man_state + */ +#define TFA98XX_STATUS_FLAGS4_MANSTATE (0xf<<3) +#define TFA98XX_STATUS_FLAGS4_MANSTATE_POS 3 +#define TFA98XX_STATUS_FLAGS4_MANSTATE_LEN 4 +#define TFA98XX_STATUS_FLAGS4_MANSTATE_MAX 15 +#define TFA98XX_STATUS_FLAGS4_MANSTATE_MSK 0x78 + + +/* + * (0x15)-battery_voltage + */ + +/* + * bat_adc + */ +#define TFA98XX_BATTERY_VOLTAGE_BATS (0x3ff<<0) +#define TFA98XX_BATTERY_VOLTAGE_BATS_POS 0 +#define TFA98XX_BATTERY_VOLTAGE_BATS_LEN 10 +#define TFA98XX_BATTERY_VOLTAGE_BATS_MAX 1023 +#define TFA98XX_BATTERY_VOLTAGE_BATS_MSK 0x3ff + + +/* + * (0x16)-temperature + */ + +/* + * temp_adc + */ +#define TFA98XX_TEMPERATURE_TEMPS (0x1ff<<0) +#define TFA98XX_TEMPERATURE_TEMPS_POS 0 +#define TFA98XX_TEMPERATURE_TEMPS_LEN 9 +#define TFA98XX_TEMPERATURE_TEMPS_MAX 511 +#define TFA98XX_TEMPERATURE_TEMPS_MSK 0x1ff + + +/* + * (0x20)-tdm_config0 + */ + +/* + * tdm_usecase + */ +#define TFA98XX_TDM_CONFIG0_TDMUC (0xf<<0) +#define TFA98XX_TDM_CONFIG0_TDMUC_POS 0 +#define TFA98XX_TDM_CONFIG0_TDMUC_LEN 4 +#define TFA98XX_TDM_CONFIG0_TDMUC_MAX 15 +#define TFA98XX_TDM_CONFIG0_TDMUC_MSK 0xf + +/* + * tdm_enable + */ +#define TFA98XX_TDM_CONFIG0_TDME (0x1<<4) +#define TFA98XX_TDM_CONFIG0_TDME_POS 4 +#define TFA98XX_TDM_CONFIG0_TDME_LEN 1 +#define TFA98XX_TDM_CONFIG0_TDME_MAX 1 +#define TFA98XX_TDM_CONFIG0_TDME_MSK 0x10 + +/* + * tdm_mode + */ +#define TFA98XX_TDM_CONFIG0_TDMMODE (0x1<<5) +#define TFA98XX_TDM_CONFIG0_TDMMODE_POS 5 +#define TFA98XX_TDM_CONFIG0_TDMMODE_LEN 1 +#define TFA98XX_TDM_CONFIG0_TDMMODE_MAX 1 +#define TFA98XX_TDM_CONFIG0_TDMMODE_MSK 0x20 + +/* + * tdm_clk_inversion + */ +#define TFA98XX_TDM_CONFIG0_TDMCLINV (0x1<<6) +#define TFA98XX_TDM_CONFIG0_TDMCLINV_POS 6 +#define TFA98XX_TDM_CONFIG0_TDMCLINV_LEN 1 +#define TFA98XX_TDM_CONFIG0_TDMCLINV_MAX 1 +#define TFA98XX_TDM_CONFIG0_TDMCLINV_MSK 0x40 + +/* + * tdm_fs_ws_length + */ +#define TFA98XX_TDM_CONFIG0_TDMFSLN (0xf<<7) +#define TFA98XX_TDM_CONFIG0_TDMFSLN_POS 7 +#define TFA98XX_TDM_CONFIG0_TDMFSLN_LEN 4 +#define TFA98XX_TDM_CONFIG0_TDMFSLN_MAX 15 +#define TFA98XX_TDM_CONFIG0_TDMFSLN_MSK 0x780 + +/* + * tdm_fs_ws_polarity + */ +#define TFA98XX_TDM_CONFIG0_TDMFSPOL (0x1<<11) +#define TFA98XX_TDM_CONFIG0_TDMFSPOL_POS 11 +#define TFA98XX_TDM_CONFIG0_TDMFSPOL_LEN 1 +#define TFA98XX_TDM_CONFIG0_TDMFSPOL_MAX 1 +#define TFA98XX_TDM_CONFIG0_TDMFSPOL_MSK 0x800 + +/* + * tdm_nbck + */ +#define TFA98XX_TDM_CONFIG0_TDMNBCK (0xf<<12) +#define TFA98XX_TDM_CONFIG0_TDMNBCK_POS 12 +#define TFA98XX_TDM_CONFIG0_TDMNBCK_LEN 4 +#define TFA98XX_TDM_CONFIG0_TDMNBCK_MAX 15 +#define TFA98XX_TDM_CONFIG0_TDMNBCK_MSK 0xf000 + + +/* + * (0x21)-tdm_config1 + */ + +/* + * tdm_nb_of_slots + */ +#define TFA98XX_TDM_CONFIG1_TDMSLOTS (0xf<<0) +#define TFA98XX_TDM_CONFIG1_TDMSLOTS_POS 0 +#define TFA98XX_TDM_CONFIG1_TDMSLOTS_LEN 4 +#define TFA98XX_TDM_CONFIG1_TDMSLOTS_MAX 15 +#define TFA98XX_TDM_CONFIG1_TDMSLOTS_MSK 0xf + +/* + * tdm_slot_length + */ +#define TFA98XX_TDM_CONFIG1_TDMSLLN (0x1f<<4) +#define TFA98XX_TDM_CONFIG1_TDMSLLN_POS 4 +#define TFA98XX_TDM_CONFIG1_TDMSLLN_LEN 5 +#define TFA98XX_TDM_CONFIG1_TDMSLLN_MAX 31 +#define TFA98XX_TDM_CONFIG1_TDMSLLN_MSK 0x1f0 + +/* + * tdm_bits_remaining + */ +#define TFA98XX_TDM_CONFIG1_TDMBRMG (0x1f<<9) +#define TFA98XX_TDM_CONFIG1_TDMBRMG_POS 9 +#define TFA98XX_TDM_CONFIG1_TDMBRMG_LEN 5 +#define TFA98XX_TDM_CONFIG1_TDMBRMG_MAX 31 +#define TFA98XX_TDM_CONFIG1_TDMBRMG_MSK 0x3e00 + +/* + * tdm_data_delay + */ +#define TFA98XX_TDM_CONFIG1_TDMDEL (0x1<<14) +#define TFA98XX_TDM_CONFIG1_TDMDEL_POS 14 +#define TFA98XX_TDM_CONFIG1_TDMDEL_LEN 1 +#define TFA98XX_TDM_CONFIG1_TDMDEL_MAX 1 +#define TFA98XX_TDM_CONFIG1_TDMDEL_MSK 0x4000 + +/* + * tdm_data_adjustment + */ +#define TFA98XX_TDM_CONFIG1_TDMADJ (0x1<<15) +#define TFA98XX_TDM_CONFIG1_TDMADJ_POS 15 +#define TFA98XX_TDM_CONFIG1_TDMADJ_LEN 1 +#define TFA98XX_TDM_CONFIG1_TDMADJ_MAX 1 +#define TFA98XX_TDM_CONFIG1_TDMADJ_MSK 0x8000 + + +/* + * (0x22)-tdm_config2 + */ + +/* + * tdm_audio_sample_compression + */ +#define TFA98XX_TDM_CONFIG2_TDMOOMP (0x3<<0) +#define TFA98XX_TDM_CONFIG2_TDMOOMP_POS 0 +#define TFA98XX_TDM_CONFIG2_TDMOOMP_LEN 2 +#define TFA98XX_TDM_CONFIG2_TDMOOMP_MAX 3 +#define TFA98XX_TDM_CONFIG2_TDMOOMP_MSK 0x3 + +/* + * tdm_sample_size + */ +#define TFA98XX_TDM_CONFIG2_TDMSSIZE (0x1f<<2) +#define TFA98XX_TDM_CONFIG2_TDMSSIZE_POS 2 +#define TFA98XX_TDM_CONFIG2_TDMSSIZE_LEN 5 +#define TFA98XX_TDM_CONFIG2_TDMSSIZE_MAX 31 +#define TFA98XX_TDM_CONFIG2_TDMSSIZE_MSK 0x7c + +/* + * tdm_txdata_format + */ +#define TFA98XX_TDM_CONFIG2_TDMTXDFO (0x3<<7) +#define TFA98XX_TDM_CONFIG2_TDMTXDFO_POS 7 +#define TFA98XX_TDM_CONFIG2_TDMTXDFO_LEN 2 +#define TFA98XX_TDM_CONFIG2_TDMTXDFO_MAX 3 +#define TFA98XX_TDM_CONFIG2_TDMTXDFO_MSK 0x180 + +/* + * tdm_txdata_format_unused_slot_sd0 + */ +#define TFA98XX_TDM_CONFIG2_TDMTXUS0 (0x3<<9) +#define TFA98XX_TDM_CONFIG2_TDMTXUS0_POS 9 +#define TFA98XX_TDM_CONFIG2_TDMTXUS0_LEN 2 +#define TFA98XX_TDM_CONFIG2_TDMTXUS0_MAX 3 +#define TFA98XX_TDM_CONFIG2_TDMTXUS0_MSK 0x600 + +/* + * tdm_txdata_format_unused_slot_sd1 + */ +#define TFA98XX_TDM_CONFIG2_TDMTXUS1 (0x3<<11) +#define TFA98XX_TDM_CONFIG2_TDMTXUS1_POS 11 +#define TFA98XX_TDM_CONFIG2_TDMTXUS1_LEN 2 +#define TFA98XX_TDM_CONFIG2_TDMTXUS1_MAX 3 +#define TFA98XX_TDM_CONFIG2_TDMTXUS1_MSK 0x1800 + +/* + * tdm_txdata_format_unused_slot_sd2 + */ +#define TFA98XX_TDM_CONFIG2_TDMTXUS2 (0x3<<13) +#define TFA98XX_TDM_CONFIG2_TDMTXUS2_POS 13 +#define TFA98XX_TDM_CONFIG2_TDMTXUS2_LEN 2 +#define TFA98XX_TDM_CONFIG2_TDMTXUS2_MAX 3 +#define TFA98XX_TDM_CONFIG2_TDMTXUS2_MSK 0x6000 + + +/* + * (0x23)-tdm_config3 + */ + +/* + * tdm_sink1_enable + */ +#define TFA98XX_TDM_CONFIG3_TDMLE (0x1<<1) +#define TFA98XX_TDM_CONFIG3_TDMLE_POS 1 +#define TFA98XX_TDM_CONFIG3_TDMLE_LEN 1 +#define TFA98XX_TDM_CONFIG3_TDMLE_MAX 1 +#define TFA98XX_TDM_CONFIG3_TDMLE_MSK 0x2 + +/* + * tdm_sink2_enable + */ +#define TFA98XX_TDM_CONFIG3_TDMRE (0x1<<2) +#define TFA98XX_TDM_CONFIG3_TDMRE_POS 2 +#define TFA98XX_TDM_CONFIG3_TDMRE_LEN 1 +#define TFA98XX_TDM_CONFIG3_TDMRE_MAX 1 +#define TFA98XX_TDM_CONFIG3_TDMRE_MSK 0x4 + +/* + * tdm_source1_enable + */ +#define TFA98XX_TDM_CONFIG3_TDMVSRE (0x1<<4) +#define TFA98XX_TDM_CONFIG3_TDMVSRE_POS 4 +#define TFA98XX_TDM_CONFIG3_TDMVSRE_LEN 1 +#define TFA98XX_TDM_CONFIG3_TDMVSRE_MAX 1 +#define TFA98XX_TDM_CONFIG3_TDMVSRE_MSK 0x10 + +/* + * tdm_source2_enable + */ +#define TFA98XX_TDM_CONFIG3_TDMCSRE (0x1<<5) +#define TFA98XX_TDM_CONFIG3_TDMCSRE_POS 5 +#define TFA98XX_TDM_CONFIG3_TDMCSRE_LEN 1 +#define TFA98XX_TDM_CONFIG3_TDMCSRE_MAX 1 +#define TFA98XX_TDM_CONFIG3_TDMCSRE_MSK 0x20 + +/* + * tdm_source3_enable + */ +#define TFA98XX_TDM_CONFIG3_TDMVSLE (0x1<<6) +#define TFA98XX_TDM_CONFIG3_TDMVSLE_POS 6 +#define TFA98XX_TDM_CONFIG3_TDMVSLE_LEN 1 +#define TFA98XX_TDM_CONFIG3_TDMVSLE_MAX 1 +#define TFA98XX_TDM_CONFIG3_TDMVSLE_MSK 0x40 + +/* + * tdm_source4_enable + */ +#define TFA98XX_TDM_CONFIG3_TDMCSLE (0x1<<7) +#define TFA98XX_TDM_CONFIG3_TDMCSLE_POS 7 +#define TFA98XX_TDM_CONFIG3_TDMCSLE_LEN 1 +#define TFA98XX_TDM_CONFIG3_TDMCSLE_MAX 1 +#define TFA98XX_TDM_CONFIG3_TDMCSLE_MSK 0x80 + +/* + * tdm_source5_enable + */ +#define TFA98XX_TDM_CONFIG3_TDMCFRE (0x1<<8) +#define TFA98XX_TDM_CONFIG3_TDMCFRE_POS 8 +#define TFA98XX_TDM_CONFIG3_TDMCFRE_LEN 1 +#define TFA98XX_TDM_CONFIG3_TDMCFRE_MAX 1 +#define TFA98XX_TDM_CONFIG3_TDMCFRE_MSK 0x100 + +/* + * tdm_source6_enable + */ +#define TFA98XX_TDM_CONFIG3_TDMCFLE (0x1<<9) +#define TFA98XX_TDM_CONFIG3_TDMCFLE_POS 9 +#define TFA98XX_TDM_CONFIG3_TDMCFLE_LEN 1 +#define TFA98XX_TDM_CONFIG3_TDMCFLE_MAX 1 +#define TFA98XX_TDM_CONFIG3_TDMCFLE_MSK 0x200 + +/* + * tdm_source7_enable + */ +#define TFA98XX_TDM_CONFIG3_TDMCF3E (0x1<<10) +#define TFA98XX_TDM_CONFIG3_TDMCF3E_POS 10 +#define TFA98XX_TDM_CONFIG3_TDMCF3E_LEN 1 +#define TFA98XX_TDM_CONFIG3_TDMCF3E_MAX 1 +#define TFA98XX_TDM_CONFIG3_TDMCF3E_MSK 0x400 + +/* + * tdm_source8_enable + */ +#define TFA98XX_TDM_CONFIG3_TDMCF4E (0x1<<11) +#define TFA98XX_TDM_CONFIG3_TDMCF4E_POS 11 +#define TFA98XX_TDM_CONFIG3_TDMCF4E_LEN 1 +#define TFA98XX_TDM_CONFIG3_TDMCF4E_MAX 1 +#define TFA98XX_TDM_CONFIG3_TDMCF4E_MSK 0x800 + +/* + * tdm_source9_enable + */ +#define TFA98XX_TDM_CONFIG3_TDMPD1E (0x1<<12) +#define TFA98XX_TDM_CONFIG3_TDMPD1E_POS 12 +#define TFA98XX_TDM_CONFIG3_TDMPD1E_LEN 1 +#define TFA98XX_TDM_CONFIG3_TDMPD1E_MAX 1 +#define TFA98XX_TDM_CONFIG3_TDMPD1E_MSK 0x1000 + +/* + * tdm_source10_enable + */ +#define TFA98XX_TDM_CONFIG3_TDMPD2E (0x1<<13) +#define TFA98XX_TDM_CONFIG3_TDMPD2E_POS 13 +#define TFA98XX_TDM_CONFIG3_TDMPD2E_LEN 1 +#define TFA98XX_TDM_CONFIG3_TDMPD2E_MAX 1 +#define TFA98XX_TDM_CONFIG3_TDMPD2E_MSK 0x2000 + + +/* + * (0x24)-tdm_config4 + */ + +/* + * tdm_sink1_io + */ +#define TFA98XX_TDM_CONFIG4_TDMLIO (0x3<<2) +#define TFA98XX_TDM_CONFIG4_TDMLIO_POS 2 +#define TFA98XX_TDM_CONFIG4_TDMLIO_LEN 2 +#define TFA98XX_TDM_CONFIG4_TDMLIO_MAX 3 +#define TFA98XX_TDM_CONFIG4_TDMLIO_MSK 0xc + +/* + * tdm_sink2_io + */ +#define TFA98XX_TDM_CONFIG4_TDMRIO (0x3<<4) +#define TFA98XX_TDM_CONFIG4_TDMRIO_POS 4 +#define TFA98XX_TDM_CONFIG4_TDMRIO_LEN 2 +#define TFA98XX_TDM_CONFIG4_TDMRIO_MAX 3 +#define TFA98XX_TDM_CONFIG4_TDMRIO_MSK 0x30 + +/* + * tdm_source1_io + */ +#define TFA98XX_TDM_CONFIG4_TDMVSRIO (0x3<<8) +#define TFA98XX_TDM_CONFIG4_TDMVSRIO_POS 8 +#define TFA98XX_TDM_CONFIG4_TDMVSRIO_LEN 2 +#define TFA98XX_TDM_CONFIG4_TDMVSRIO_MAX 3 +#define TFA98XX_TDM_CONFIG4_TDMVSRIO_MSK 0x300 + +/* + * tdm_source2_io + */ +#define TFA98XX_TDM_CONFIG4_TDMCSRIO (0x3<<10) +#define TFA98XX_TDM_CONFIG4_TDMCSRIO_POS 10 +#define TFA98XX_TDM_CONFIG4_TDMCSRIO_LEN 2 +#define TFA98XX_TDM_CONFIG4_TDMCSRIO_MAX 3 +#define TFA98XX_TDM_CONFIG4_TDMCSRIO_MSK 0xc00 + +/* + * tdm_source3_io + */ +#define TFA98XX_TDM_CONFIG4_TDMVSLIO (0x3<<12) +#define TFA98XX_TDM_CONFIG4_TDMVSLIO_POS 12 +#define TFA98XX_TDM_CONFIG4_TDMVSLIO_LEN 2 +#define TFA98XX_TDM_CONFIG4_TDMVSLIO_MAX 3 +#define TFA98XX_TDM_CONFIG4_TDMVSLIO_MSK 0x3000 + +/* + * tdm_source4_io + */ +#define TFA98XX_TDM_CONFIG4_TDMCSLIO (0x3<<14) +#define TFA98XX_TDM_CONFIG4_TDMCSLIO_POS 14 +#define TFA98XX_TDM_CONFIG4_TDMCSLIO_LEN 2 +#define TFA98XX_TDM_CONFIG4_TDMCSLIO_MAX 3 +#define TFA98XX_TDM_CONFIG4_TDMCSLIO_MSK 0xc000 + + +/* + * (0x25)-tdm_config5 + */ + +/* + * tdm_source5_io + */ +#define TFA98XX_TDM_CONFIG5_TDMCFRIO (0x3<<0) +#define TFA98XX_TDM_CONFIG5_TDMCFRIO_POS 0 +#define TFA98XX_TDM_CONFIG5_TDMCFRIO_LEN 2 +#define TFA98XX_TDM_CONFIG5_TDMCFRIO_MAX 3 +#define TFA98XX_TDM_CONFIG5_TDMCFRIO_MSK 0x3 + +/* + * tdm_source6_io + */ +#define TFA98XX_TDM_CONFIG5_TDMCFLIO (0x3<<2) +#define TFA98XX_TDM_CONFIG5_TDMCFLIO_POS 2 +#define TFA98XX_TDM_CONFIG5_TDMCFLIO_LEN 2 +#define TFA98XX_TDM_CONFIG5_TDMCFLIO_MAX 3 +#define TFA98XX_TDM_CONFIG5_TDMCFLIO_MSK 0xc + +/* + * tdm_source7_io + */ +#define TFA98XX_TDM_CONFIG5_TDMCF3IO (0x3<<4) +#define TFA98XX_TDM_CONFIG5_TDMCF3IO_POS 4 +#define TFA98XX_TDM_CONFIG5_TDMCF3IO_LEN 2 +#define TFA98XX_TDM_CONFIG5_TDMCF3IO_MAX 3 +#define TFA98XX_TDM_CONFIG5_TDMCF3IO_MSK 0x30 + +/* + * tdm_source8_io + */ +#define TFA98XX_TDM_CONFIG5_TDMCF4IO (0x3<<6) +#define TFA98XX_TDM_CONFIG5_TDMCF4IO_POS 6 +#define TFA98XX_TDM_CONFIG5_TDMCF4IO_LEN 2 +#define TFA98XX_TDM_CONFIG5_TDMCF4IO_MAX 3 +#define TFA98XX_TDM_CONFIG5_TDMCF4IO_MSK 0xc0 + +/* + * tdm_source9_io + */ +#define TFA98XX_TDM_CONFIG5_TDMPD1IO (0x3<<8) +#define TFA98XX_TDM_CONFIG5_TDMPD1IO_POS 8 +#define TFA98XX_TDM_CONFIG5_TDMPD1IO_LEN 2 +#define TFA98XX_TDM_CONFIG5_TDMPD1IO_MAX 3 +#define TFA98XX_TDM_CONFIG5_TDMPD1IO_MSK 0x300 + +/* + * tdm_source10_io + */ +#define TFA98XX_TDM_CONFIG5_TDMPD2IO (0x3<<10) +#define TFA98XX_TDM_CONFIG5_TDMPD2IO_POS 10 +#define TFA98XX_TDM_CONFIG5_TDMPD2IO_LEN 2 +#define TFA98XX_TDM_CONFIG5_TDMPD2IO_MAX 3 +#define TFA98XX_TDM_CONFIG5_TDMPD2IO_MSK 0xc00 + + +/* + * (0x26)-tdm_config6 + */ + +/* + * tdm_sink1_slot + */ +#define TFA98XX_TDM_CONFIG6_TDMLS (0xf<<4) +#define TFA98XX_TDM_CONFIG6_TDMLS_POS 4 +#define TFA98XX_TDM_CONFIG6_TDMLS_LEN 4 +#define TFA98XX_TDM_CONFIG6_TDMLS_MAX 15 +#define TFA98XX_TDM_CONFIG6_TDMLS_MSK 0xf0 + +/* + * tdm_sink2_slot + */ +#define TFA98XX_TDM_CONFIG6_TDMRS (0xf<<8) +#define TFA98XX_TDM_CONFIG6_TDMRS_POS 8 +#define TFA98XX_TDM_CONFIG6_TDMRS_LEN 4 +#define TFA98XX_TDM_CONFIG6_TDMRS_MAX 15 +#define TFA98XX_TDM_CONFIG6_TDMRS_MSK 0xf00 + + +/* + * (0x27)-tdm_config7 + */ + +/* + * tdm_source1_slot + */ +#define TFA98XX_TDM_CONFIG7_TDMVSRS (0xf<<0) +#define TFA98XX_TDM_CONFIG7_TDMVSRS_POS 0 +#define TFA98XX_TDM_CONFIG7_TDMVSRS_LEN 4 +#define TFA98XX_TDM_CONFIG7_TDMVSRS_MAX 15 +#define TFA98XX_TDM_CONFIG7_TDMVSRS_MSK 0xf + +/* + * tdm_source2_slot + */ +#define TFA98XX_TDM_CONFIG7_TDMCSRS (0xf<<4) +#define TFA98XX_TDM_CONFIG7_TDMCSRS_POS 4 +#define TFA98XX_TDM_CONFIG7_TDMCSRS_LEN 4 +#define TFA98XX_TDM_CONFIG7_TDMCSRS_MAX 15 +#define TFA98XX_TDM_CONFIG7_TDMCSRS_MSK 0xf0 + +/* + * tdm_source3_slot + */ +#define TFA98XX_TDM_CONFIG7_TDMVSLS (0xf<<8) +#define TFA98XX_TDM_CONFIG7_TDMVSLS_POS 8 +#define TFA98XX_TDM_CONFIG7_TDMVSLS_LEN 4 +#define TFA98XX_TDM_CONFIG7_TDMVSLS_MAX 15 +#define TFA98XX_TDM_CONFIG7_TDMVSLS_MSK 0xf00 + +/* + * tdm_source4_slot + */ +#define TFA98XX_TDM_CONFIG7_TDMCSLS (0xf<<12) +#define TFA98XX_TDM_CONFIG7_TDMCSLS_POS 12 +#define TFA98XX_TDM_CONFIG7_TDMCSLS_LEN 4 +#define TFA98XX_TDM_CONFIG7_TDMCSLS_MAX 15 +#define TFA98XX_TDM_CONFIG7_TDMCSLS_MSK 0xf000 + + +/* + * (0x28)-tdm_config8 + */ + +/* + * tdm_source5_slot + */ +#define TFA98XX_TDM_CONFIG8_TDMCFRS (0xf<<0) +#define TFA98XX_TDM_CONFIG8_TDMCFRS_POS 0 +#define TFA98XX_TDM_CONFIG8_TDMCFRS_LEN 4 +#define TFA98XX_TDM_CONFIG8_TDMCFRS_MAX 15 +#define TFA98XX_TDM_CONFIG8_TDMCFRS_MSK 0xf + +/* + * tdm_source6_slot + */ +#define TFA98XX_TDM_CONFIG8_TDMCFLS (0xf<<4) +#define TFA98XX_TDM_CONFIG8_TDMCFLS_POS 4 +#define TFA98XX_TDM_CONFIG8_TDMCFLS_LEN 4 +#define TFA98XX_TDM_CONFIG8_TDMCFLS_MAX 15 +#define TFA98XX_TDM_CONFIG8_TDMCFLS_MSK 0xf0 + +/* + * tdm_source7_slot + */ +#define TFA98XX_TDM_CONFIG8_TDMCF3S (0xf<<8) +#define TFA98XX_TDM_CONFIG8_TDMCF3S_POS 8 +#define TFA98XX_TDM_CONFIG8_TDMCF3S_LEN 4 +#define TFA98XX_TDM_CONFIG8_TDMCF3S_MAX 15 +#define TFA98XX_TDM_CONFIG8_TDMCF3S_MSK 0xf00 + +/* + * tdm_source8_slot + */ +#define TFA98XX_TDM_CONFIG8_TDMCF4S (0xf<<12) +#define TFA98XX_TDM_CONFIG8_TDMCF4S_POS 12 +#define TFA98XX_TDM_CONFIG8_TDMCF4S_LEN 4 +#define TFA98XX_TDM_CONFIG8_TDMCF4S_MAX 15 +#define TFA98XX_TDM_CONFIG8_TDMCF4S_MSK 0xf000 + + +/* + * (0x29)-tdm_config9 + */ + +/* + * tdm_source9_slot + */ +#define TFA98XX_TDM_CONFIG9_TDMPD1S (0xf<<0) +#define TFA98XX_TDM_CONFIG9_TDMPD1S_POS 0 +#define TFA98XX_TDM_CONFIG9_TDMPD1S_LEN 4 +#define TFA98XX_TDM_CONFIG9_TDMPD1S_MAX 15 +#define TFA98XX_TDM_CONFIG9_TDMPD1S_MSK 0xf + +/* + * tdm_source10_slot + */ +#define TFA98XX_TDM_CONFIG9_TDMPD2S (0xf<<4) +#define TFA98XX_TDM_CONFIG9_TDMPD2S_POS 4 +#define TFA98XX_TDM_CONFIG9_TDMPD2S_LEN 4 +#define TFA98XX_TDM_CONFIG9_TDMPD2S_MAX 15 +#define TFA98XX_TDM_CONFIG9_TDMPD2S_MSK 0xf0 + + +/* + * (0x31)-pdm_config0 + */ + +/* + * pdm_mode + */ +#define TFA98XX_PDM_CONFIG0_PDMSM (0x1<<0) +#define TFA98XX_PDM_CONFIG0_PDMSM_POS 0 +#define TFA98XX_PDM_CONFIG0_PDMSM_LEN 1 +#define TFA98XX_PDM_CONFIG0_PDMSM_MAX 1 +#define TFA98XX_PDM_CONFIG0_PDMSM_MSK 0x1 + +/* + * pdm_side_tone_sel + */ +#define TFA98XX_PDM_CONFIG0_PDMSTSEL (0x3<<1) +#define TFA98XX_PDM_CONFIG0_PDMSTSEL_POS 1 +#define TFA98XX_PDM_CONFIG0_PDMSTSEL_LEN 2 +#define TFA98XX_PDM_CONFIG0_PDMSTSEL_MAX 3 +#define TFA98XX_PDM_CONFIG0_PDMSTSEL_MSK 0x6 + +/* + * pdm_left_sel + */ +#define TFA98XX_PDM_CONFIG0_PDMLSEL (0x1<<3) +#define TFA98XX_PDM_CONFIG0_PDMLSEL_POS 3 +#define TFA98XX_PDM_CONFIG0_PDMLSEL_LEN 1 +#define TFA98XX_PDM_CONFIG0_PDMLSEL_MAX 1 +#define TFA98XX_PDM_CONFIG0_PDMLSEL_MSK 0x8 + +/* + * pdm_right_sel + */ +#define TFA98XX_PDM_CONFIG0_PDMRSEL (0x1<<4) +#define TFA98XX_PDM_CONFIG0_PDMRSEL_POS 4 +#define TFA98XX_PDM_CONFIG0_PDMRSEL_LEN 1 +#define TFA98XX_PDM_CONFIG0_PDMRSEL_MAX 1 +#define TFA98XX_PDM_CONFIG0_PDMRSEL_MSK 0x10 + +/* + * enbl_micvdd + */ +#define TFA98XX_PDM_CONFIG0_MICVDDE (0x1<<5) +#define TFA98XX_PDM_CONFIG0_MICVDDE_POS 5 +#define TFA98XX_PDM_CONFIG0_MICVDDE_LEN 1 +#define TFA98XX_PDM_CONFIG0_MICVDDE_MAX 1 +#define TFA98XX_PDM_CONFIG0_MICVDDE_MSK 0x20 + + +/* + * (0x32)-pdm_config1 + */ + +/* + * pdm_nbck + */ +#define TFA98XX_PDM_CONFIG1_PDMCLRAT (0x3<<0) +#define TFA98XX_PDM_CONFIG1_PDMCLRAT_POS 0 +#define TFA98XX_PDM_CONFIG1_PDMCLRAT_LEN 2 +#define TFA98XX_PDM_CONFIG1_PDMCLRAT_MAX 3 +#define TFA98XX_PDM_CONFIG1_PDMCLRAT_MSK 0x3 + +/* + * pdm_gain + */ +#define TFA98XX_PDM_CONFIG1_PDMGAIN (0xf<<2) +#define TFA98XX_PDM_CONFIG1_PDMGAIN_POS 2 +#define TFA98XX_PDM_CONFIG1_PDMGAIN_LEN 4 +#define TFA98XX_PDM_CONFIG1_PDMGAIN_MAX 15 +#define TFA98XX_PDM_CONFIG1_PDMGAIN_MSK 0x3c + +/* + * sel_pdm_out_data + */ +#define TFA98XX_PDM_CONFIG1_PDMOSEL (0xf<<6) +#define TFA98XX_PDM_CONFIG1_PDMOSEL_POS 6 +#define TFA98XX_PDM_CONFIG1_PDMOSEL_LEN 4 +#define TFA98XX_PDM_CONFIG1_PDMOSEL_MAX 15 +#define TFA98XX_PDM_CONFIG1_PDMOSEL_MSK 0x3c0 + +/* + * sel_cf_haptic_data + */ +#define TFA98XX_PDM_CONFIG1_SELCFHAPD (0x1<<10) +#define TFA98XX_PDM_CONFIG1_SELCFHAPD_POS 10 +#define TFA98XX_PDM_CONFIG1_SELCFHAPD_LEN 1 +#define TFA98XX_PDM_CONFIG1_SELCFHAPD_MAX 1 +#define TFA98XX_PDM_CONFIG1_SELCFHAPD_MSK 0x400 + + +/* + * (0x33)-haptic_driver_config + */ + +/* + * haptic_duration + */ +#define TFA98XX_HAPTIC_DRIVER_CONFIG_HAPTIME (0xff<<0) +#define TFA98XX_HAPTIC_DRIVER_CONFIG_HAPTIME_POS 0 +#define TFA98XX_HAPTIC_DRIVER_CONFIG_HAPTIME_LEN 8 +#define TFA98XX_HAPTIC_DRIVER_CONFIG_HAPTIME_MAX 255 +#define TFA98XX_HAPTIC_DRIVER_CONFIG_HAPTIME_MSK 0xff + +/* + * haptic_data + */ +#define TFA98XX_HAPTIC_DRIVER_CONFIG_HAPLEVEL (0xff<<8) +#define TFA98XX_HAPTIC_DRIVER_CONFIG_HAPLEVEL_POS 8 +#define TFA98XX_HAPTIC_DRIVER_CONFIG_HAPLEVEL_LEN 8 +#define TFA98XX_HAPTIC_DRIVER_CONFIG_HAPLEVEL_MAX 255 +#define TFA98XX_HAPTIC_DRIVER_CONFIG_HAPLEVEL_MSK 0xff00 + + +/* + * (0x34)-gpio_datain_reg + */ + +/* + * gpio_datain + */ +#define TFA98XX_GPIO_DATAIN_REG_GPIODIN (0xf<<0) +#define TFA98XX_GPIO_DATAIN_REG_GPIODIN_POS 0 +#define TFA98XX_GPIO_DATAIN_REG_GPIODIN_LEN 4 +#define TFA98XX_GPIO_DATAIN_REG_GPIODIN_MAX 15 +#define TFA98XX_GPIO_DATAIN_REG_GPIODIN_MSK 0xf + + +/* + * (0x35)-gpio_config + */ + +/* + * gpio_ctrl + */ +#define TFA98XX_GPIO_CONFIG_GPIOCTRL (0x1<<0) +#define TFA98XX_GPIO_CONFIG_GPIOCTRL_POS 0 +#define TFA98XX_GPIO_CONFIG_GPIOCTRL_LEN 1 +#define TFA98XX_GPIO_CONFIG_GPIOCTRL_MAX 1 +#define TFA98XX_GPIO_CONFIG_GPIOCTRL_MSK 0x1 + +/* + * gpio_dir + */ +#define TFA98XX_GPIO_CONFIG_GPIOCONF (0xf<<1) +#define TFA98XX_GPIO_CONFIG_GPIOCONF_POS 1 +#define TFA98XX_GPIO_CONFIG_GPIOCONF_LEN 4 +#define TFA98XX_GPIO_CONFIG_GPIOCONF_MAX 15 +#define TFA98XX_GPIO_CONFIG_GPIOCONF_MSK 0x1e + +/* + * gpio_dataout + */ +#define TFA98XX_GPIO_CONFIG_GPIODOUT (0xf<<5) +#define TFA98XX_GPIO_CONFIG_GPIODOUT_POS 5 +#define TFA98XX_GPIO_CONFIG_GPIODOUT_LEN 4 +#define TFA98XX_GPIO_CONFIG_GPIODOUT_MAX 15 +#define TFA98XX_GPIO_CONFIG_GPIODOUT_MSK 0x1e0 + + +/* + * (0x40)-interrupt_out_reg1 + */ + +/* + * int_out_flag_por + */ +#define TFA98XX_INTERRUPT_OUT_REG1_ISTVDDS (0x1<<0) +#define TFA98XX_INTERRUPT_OUT_REG1_ISTVDDS_POS 0 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTVDDS_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTVDDS_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTVDDS_MSK 0x1 + +/* + * int_out_flag_pll_lock + */ +#define TFA98XX_INTERRUPT_OUT_REG1_ISTPLLS (0x1<<1) +#define TFA98XX_INTERRUPT_OUT_REG1_ISTPLLS_POS 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTPLLS_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTPLLS_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTPLLS_MSK 0x2 + +/* + * int_out_flag_otpok + */ +#define TFA98XX_INTERRUPT_OUT_REG1_ISTOTDS (0x1<<2) +#define TFA98XX_INTERRUPT_OUT_REG1_ISTOTDS_POS 2 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTOTDS_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTOTDS_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTOTDS_MSK 0x4 + +/* + * int_out_flag_ovpok + */ +#define TFA98XX_INTERRUPT_OUT_REG1_ISTOVDS (0x1<<3) +#define TFA98XX_INTERRUPT_OUT_REG1_ISTOVDS_POS 3 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTOVDS_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTOVDS_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTOVDS_MSK 0x8 + +/* + * int_out_flag_uvpok + */ +#define TFA98XX_INTERRUPT_OUT_REG1_ISTUVDS (0x1<<4) +#define TFA98XX_INTERRUPT_OUT_REG1_ISTUVDS_POS 4 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTUVDS_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTUVDS_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTUVDS_MSK 0x10 + +/* + * int_out_flag_clocks_stable + */ +#define TFA98XX_INTERRUPT_OUT_REG1_ISTCLKS (0x1<<5) +#define TFA98XX_INTERRUPT_OUT_REG1_ISTCLKS_POS 5 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTCLKS_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTCLKS_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTCLKS_MSK 0x20 + +/* + * int_out_flag_mtp_busy + */ +#define TFA98XX_INTERRUPT_OUT_REG1_ISTMTPB (0x1<<6) +#define TFA98XX_INTERRUPT_OUT_REG1_ISTMTPB_POS 6 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTMTPB_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTMTPB_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTMTPB_MSK 0x40 + +/* + * int_out_flag_lost_clk + */ +#define TFA98XX_INTERRUPT_OUT_REG1_ISTNOCLK (0x1<<7) +#define TFA98XX_INTERRUPT_OUT_REG1_ISTNOCLK_POS 7 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTNOCLK_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTNOCLK_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTNOCLK_MSK 0x80 + +/* + * int_out_flag_cf_speakererror + */ +#define TFA98XX_INTERRUPT_OUT_REG1_ISTSPKS (0x1<<8) +#define TFA98XX_INTERRUPT_OUT_REG1_ISTSPKS_POS 8 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTSPKS_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTSPKS_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTSPKS_MSK 0x100 + +/* + * int_out_flag_cold_started + */ +#define TFA98XX_INTERRUPT_OUT_REG1_ISTACS (0x1<<9) +#define TFA98XX_INTERRUPT_OUT_REG1_ISTACS_POS 9 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTACS_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTACS_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTACS_MSK 0x200 + +/* + * int_out_flag_engage + */ +#define TFA98XX_INTERRUPT_OUT_REG1_ISTSWS (0x1<<10) +#define TFA98XX_INTERRUPT_OUT_REG1_ISTSWS_POS 10 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTSWS_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTSWS_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTSWS_MSK 0x400 + +/* + * int_out_flag_watchdog_reset + */ +#define TFA98XX_INTERRUPT_OUT_REG1_ISTWDS (0x1<<11) +#define TFA98XX_INTERRUPT_OUT_REG1_ISTWDS_POS 11 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTWDS_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTWDS_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTWDS_MSK 0x800 + +/* + * int_out_flag_enbl_amp + */ +#define TFA98XX_INTERRUPT_OUT_REG1_ISTAMPS (0x1<<12) +#define TFA98XX_INTERRUPT_OUT_REG1_ISTAMPS_POS 12 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTAMPS_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTAMPS_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTAMPS_MSK 0x1000 + +/* + * int_out_flag_enbl_ref + */ +#define TFA98XX_INTERRUPT_OUT_REG1_ISTAREFS (0x1<<13) +#define TFA98XX_INTERRUPT_OUT_REG1_ISTAREFS_POS 13 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTAREFS_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTAREFS_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTAREFS_MSK 0x2000 + +/* + * int_out_flag_adc10_ready + */ +#define TFA98XX_INTERRUPT_OUT_REG1_ISTADCCR (0x1<<14) +#define TFA98XX_INTERRUPT_OUT_REG1_ISTADCCR_POS 14 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTADCCR_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTADCCR_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTADCCR_MSK 0x4000 + +/* + * int_out_flag_bod_vddd_nok + */ +#define TFA98XX_INTERRUPT_OUT_REG1_ISTBODNOK (0x1<<15) +#define TFA98XX_INTERRUPT_OUT_REG1_ISTBODNOK_POS 15 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTBODNOK_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTBODNOK_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG1_ISTBODNOK_MSK 0x8000 + + +/* + * (0x41)-interrupt_out_reg2 + */ + +/* + * int_out_flag_bst_bstcur + */ +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTCU (0x1<<0) +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTCU_POS 0 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTCU_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTCU_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTCU_MSK 0x1 + +/* + * int_out_flag_bst_hiz + */ +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTHI (0x1<<1) +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTHI_POS 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTHI_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTHI_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTHI_MSK 0x2 + +/* + * int_out_flag_bst_ocpok + */ +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTOC (0x1<<2) +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTOC_POS 2 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTOC_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTOC_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTOC_MSK 0x4 + +/* + * int_out_flag_bst_peakcur + */ +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTPKCUR (0x1<<3) +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTPKCUR_POS 3 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTPKCUR_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTPKCUR_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTPKCUR_MSK 0x8 + +/* + * int_out_flag_bst_voutcomp + */ +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTVC (0x1<<4) +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTVC_POS 4 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTVC_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTVC_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBSTVC_MSK 0x10 + +/* + * int_out_flag_bst_voutcomp86 + */ +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBST86 (0x1<<5) +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBST86_POS 5 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBST86_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBST86_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBST86_MSK 0x20 + +/* + * int_out_flag_bst_voutcomp93 + */ +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBST93 (0x1<<6) +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBST93_POS 6 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBST93_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBST93_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTBST93_MSK 0x40 + +/* + * int_out_flag_rcvldop_ready + */ +#define TFA98XX_INTERRUPT_OUT_REG2_ISTRCVLD (0x1<<7) +#define TFA98XX_INTERRUPT_OUT_REG2_ISTRCVLD_POS 7 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTRCVLD_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTRCVLD_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTRCVLD_MSK 0x80 + +/* + * int_out_flag_ocp_alarm_left + */ +#define TFA98XX_INTERRUPT_OUT_REG2_ISTOCPL (0x1<<8) +#define TFA98XX_INTERRUPT_OUT_REG2_ISTOCPL_POS 8 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTOCPL_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTOCPL_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTOCPL_MSK 0x100 + +/* + * int_out_flag_ocp_alarm_right + */ +#define TFA98XX_INTERRUPT_OUT_REG2_ISTOCPR (0x1<<9) +#define TFA98XX_INTERRUPT_OUT_REG2_ISTOCPR_POS 9 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTOCPR_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTOCPR_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTOCPR_MSK 0x200 + +/* + * int_out_flag_man_wait_src_settings + */ +#define TFA98XX_INTERRUPT_OUT_REG2_ISTMWSRC (0x1<<10) +#define TFA98XX_INTERRUPT_OUT_REG2_ISTMWSRC_POS 10 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTMWSRC_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTMWSRC_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTMWSRC_MSK 0x400 + +/* + * int_out_flag_man_wait_cf_config + */ +#define TFA98XX_INTERRUPT_OUT_REG2_ISTMWCFC (0x1<<11) +#define TFA98XX_INTERRUPT_OUT_REG2_ISTMWCFC_POS 11 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTMWCFC_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTMWCFC_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTMWCFC_MSK 0x800 + +/* + * int_out_flag_man_start_mute_audio + */ +#define TFA98XX_INTERRUPT_OUT_REG2_ISTMWSMU (0x1<<12) +#define TFA98XX_INTERRUPT_OUT_REG2_ISTMWSMU_POS 12 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTMWSMU_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTMWSMU_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTMWSMU_MSK 0x1000 + +/* + * int_out_flag_cfma_err + */ +#define TFA98XX_INTERRUPT_OUT_REG2_ISTCFMER (0x1<<13) +#define TFA98XX_INTERRUPT_OUT_REG2_ISTCFMER_POS 13 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTCFMER_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTCFMER_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTCFMER_MSK 0x2000 + +/* + * int_out_flag_cfma_ack + */ +#define TFA98XX_INTERRUPT_OUT_REG2_ISTCFMAC (0x1<<14) +#define TFA98XX_INTERRUPT_OUT_REG2_ISTCFMAC_POS 14 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTCFMAC_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTCFMAC_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTCFMAC_MSK 0x4000 + +/* + * int_out_flag_clk_out_of_range + */ +#define TFA98XX_INTERRUPT_OUT_REG2_ISTCLKOOR (0x1<<15) +#define TFA98XX_INTERRUPT_OUT_REG2_ISTCLKOOR_POS 15 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTCLKOOR_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTCLKOOR_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG2_ISTCLKOOR_MSK 0x8000 + + +/* + * (0x42)-interrupt_out_reg3 + */ + +/* + * int_out_flag_tdm_error + */ +#define TFA98XX_INTERRUPT_OUT_REG3_ISTTDMER (0x1<<0) +#define TFA98XX_INTERRUPT_OUT_REG3_ISTTDMER_POS 0 +#define TFA98XX_INTERRUPT_OUT_REG3_ISTTDMER_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG3_ISTTDMER_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG3_ISTTDMER_MSK 0x1 + +/* + * int_out_flag_clip_left + */ +#define TFA98XX_INTERRUPT_OUT_REG3_ISTCLPL (0x1<<1) +#define TFA98XX_INTERRUPT_OUT_REG3_ISTCLPL_POS 1 +#define TFA98XX_INTERRUPT_OUT_REG3_ISTCLPL_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG3_ISTCLPL_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG3_ISTCLPL_MSK 0x2 + +/* + * int_out_flag_clip_right + */ +#define TFA98XX_INTERRUPT_OUT_REG3_ISTCLPR (0x1<<2) +#define TFA98XX_INTERRUPT_OUT_REG3_ISTCLPR_POS 2 +#define TFA98XX_INTERRUPT_OUT_REG3_ISTCLPR_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG3_ISTCLPR_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG3_ISTCLPR_MSK 0x4 + +/* + * int_out_flag_mic_ocpok + */ +#define TFA98XX_INTERRUPT_OUT_REG3_ISTOCPM (0x1<<3) +#define TFA98XX_INTERRUPT_OUT_REG3_ISTOCPM_POS 3 +#define TFA98XX_INTERRUPT_OUT_REG3_ISTOCPM_LEN 1 +#define TFA98XX_INTERRUPT_OUT_REG3_ISTOCPM_MAX 1 +#define TFA98XX_INTERRUPT_OUT_REG3_ISTOCPM_MSK 0x8 + + +/* + * (0x44)-interrupt_in_reg1 + */ + +/* + * int_in_flag_por + */ +#define TFA98XX_INTERRUPT_IN_REG1_ICLVDDS (0x1<<0) +#define TFA98XX_INTERRUPT_IN_REG1_ICLVDDS_POS 0 +#define TFA98XX_INTERRUPT_IN_REG1_ICLVDDS_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLVDDS_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLVDDS_MSK 0x1 + +/* + * int_in_flag_pll_lock + */ +#define TFA98XX_INTERRUPT_IN_REG1_ICLPLLS (0x1<<1) +#define TFA98XX_INTERRUPT_IN_REG1_ICLPLLS_POS 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLPLLS_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLPLLS_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLPLLS_MSK 0x2 + +/* + * int_in_flag_otpok + */ +#define TFA98XX_INTERRUPT_IN_REG1_ICLOTDS (0x1<<2) +#define TFA98XX_INTERRUPT_IN_REG1_ICLOTDS_POS 2 +#define TFA98XX_INTERRUPT_IN_REG1_ICLOTDS_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLOTDS_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLOTDS_MSK 0x4 + +/* + * int_in_flag_ovpok + */ +#define TFA98XX_INTERRUPT_IN_REG1_ICLOVDS (0x1<<3) +#define TFA98XX_INTERRUPT_IN_REG1_ICLOVDS_POS 3 +#define TFA98XX_INTERRUPT_IN_REG1_ICLOVDS_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLOVDS_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLOVDS_MSK 0x8 + +/* + * int_in_flag_uvpok + */ +#define TFA98XX_INTERRUPT_IN_REG1_ICLUVDS (0x1<<4) +#define TFA98XX_INTERRUPT_IN_REG1_ICLUVDS_POS 4 +#define TFA98XX_INTERRUPT_IN_REG1_ICLUVDS_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLUVDS_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLUVDS_MSK 0x10 + +/* + * int_in_flag_clocks_stable + */ +#define TFA98XX_INTERRUPT_IN_REG1_ICLCLKS (0x1<<5) +#define TFA98XX_INTERRUPT_IN_REG1_ICLCLKS_POS 5 +#define TFA98XX_INTERRUPT_IN_REG1_ICLCLKS_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLCLKS_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLCLKS_MSK 0x20 + +/* + * int_in_flag_mtp_busy + */ +#define TFA98XX_INTERRUPT_IN_REG1_ICLMTPB (0x1<<6) +#define TFA98XX_INTERRUPT_IN_REG1_ICLMTPB_POS 6 +#define TFA98XX_INTERRUPT_IN_REG1_ICLMTPB_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLMTPB_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLMTPB_MSK 0x40 + +/* + * int_in_flag_lost_clk + */ +#define TFA98XX_INTERRUPT_IN_REG1_ICLNOCLK (0x1<<7) +#define TFA98XX_INTERRUPT_IN_REG1_ICLNOCLK_POS 7 +#define TFA98XX_INTERRUPT_IN_REG1_ICLNOCLK_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLNOCLK_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLNOCLK_MSK 0x80 + +/* + * int_in_flag_cf_speakererror + */ +#define TFA98XX_INTERRUPT_IN_REG1_ICLSPKS (0x1<<8) +#define TFA98XX_INTERRUPT_IN_REG1_ICLSPKS_POS 8 +#define TFA98XX_INTERRUPT_IN_REG1_ICLSPKS_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLSPKS_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLSPKS_MSK 0x100 + +/* + * int_in_flag_cold_started + */ +#define TFA98XX_INTERRUPT_IN_REG1_ICLACS (0x1<<9) +#define TFA98XX_INTERRUPT_IN_REG1_ICLACS_POS 9 +#define TFA98XX_INTERRUPT_IN_REG1_ICLACS_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLACS_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLACS_MSK 0x200 + +/* + * int_in_flag_engage + */ +#define TFA98XX_INTERRUPT_IN_REG1_ICLSWS (0x1<<10) +#define TFA98XX_INTERRUPT_IN_REG1_ICLSWS_POS 10 +#define TFA98XX_INTERRUPT_IN_REG1_ICLSWS_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLSWS_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLSWS_MSK 0x400 + +/* + * int_in_flag_watchdog_reset + */ +#define TFA98XX_INTERRUPT_IN_REG1_ICLWDS (0x1<<11) +#define TFA98XX_INTERRUPT_IN_REG1_ICLWDS_POS 11 +#define TFA98XX_INTERRUPT_IN_REG1_ICLWDS_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLWDS_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLWDS_MSK 0x800 + +/* + * int_in_flag_enbl_amp + */ +#define TFA98XX_INTERRUPT_IN_REG1_ICLAMPS (0x1<<12) +#define TFA98XX_INTERRUPT_IN_REG1_ICLAMPS_POS 12 +#define TFA98XX_INTERRUPT_IN_REG1_ICLAMPS_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLAMPS_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLAMPS_MSK 0x1000 + +/* + * int_in_flag_enbl_ref + */ +#define TFA98XX_INTERRUPT_IN_REG1_ICLAREFS (0x1<<13) +#define TFA98XX_INTERRUPT_IN_REG1_ICLAREFS_POS 13 +#define TFA98XX_INTERRUPT_IN_REG1_ICLAREFS_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLAREFS_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLAREFS_MSK 0x2000 + +/* + * int_in_flag_adc10_ready + */ +#define TFA98XX_INTERRUPT_IN_REG1_ICLADCCR (0x1<<14) +#define TFA98XX_INTERRUPT_IN_REG1_ICLADCCR_POS 14 +#define TFA98XX_INTERRUPT_IN_REG1_ICLADCCR_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLADCCR_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLADCCR_MSK 0x4000 + +/* + * int_in_flag_bod_vddd_nok + */ +#define TFA98XX_INTERRUPT_IN_REG1_ICLBODNOK (0x1<<15) +#define TFA98XX_INTERRUPT_IN_REG1_ICLBODNOK_POS 15 +#define TFA98XX_INTERRUPT_IN_REG1_ICLBODNOK_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLBODNOK_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG1_ICLBODNOK_MSK 0x8000 + + +/* + * (0x45)-interrupt_in_reg2 + */ + +/* + * int_in_flag_bst_bstcur + */ +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTCU (0x1<<0) +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTCU_POS 0 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTCU_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTCU_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTCU_MSK 0x1 + +/* + * int_in_flag_bst_hiz + */ +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTHI (0x1<<1) +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTHI_POS 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTHI_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTHI_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTHI_MSK 0x2 + +/* + * int_in_flag_bst_ocpok + */ +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTOC (0x1<<2) +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTOC_POS 2 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTOC_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTOC_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTOC_MSK 0x4 + +/* + * int_in_flag_bst_peakcur + */ +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTPC (0x1<<3) +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTPC_POS 3 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTPC_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTPC_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTPC_MSK 0x8 + +/* + * int_in_flag_bst_voutcomp + */ +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTVC (0x1<<4) +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTVC_POS 4 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTVC_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTVC_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBSTVC_MSK 0x10 + +/* + * int_in_flag_bst_voutcomp86 + */ +#define TFA98XX_INTERRUPT_IN_REG2_ICLBST86 (0x1<<5) +#define TFA98XX_INTERRUPT_IN_REG2_ICLBST86_POS 5 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBST86_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBST86_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBST86_MSK 0x20 + +/* + * int_in_flag_bst_voutcomp93 + */ +#define TFA98XX_INTERRUPT_IN_REG2_ICLBST93 (0x1<<6) +#define TFA98XX_INTERRUPT_IN_REG2_ICLBST93_POS 6 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBST93_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBST93_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLBST93_MSK 0x40 + +/* + * int_in_flag_rcvldop_ready + */ +#define TFA98XX_INTERRUPT_IN_REG2_ICLRCVLD (0x1<<7) +#define TFA98XX_INTERRUPT_IN_REG2_ICLRCVLD_POS 7 +#define TFA98XX_INTERRUPT_IN_REG2_ICLRCVLD_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLRCVLD_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLRCVLD_MSK 0x80 + +/* + * int_in_flag_ocp_alarm_left + */ +#define TFA98XX_INTERRUPT_IN_REG2_ICLOCPL (0x1<<8) +#define TFA98XX_INTERRUPT_IN_REG2_ICLOCPL_POS 8 +#define TFA98XX_INTERRUPT_IN_REG2_ICLOCPL_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLOCPL_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLOCPL_MSK 0x100 + +/* + * int_in_flag_ocp_alarm_right + */ +#define TFA98XX_INTERRUPT_IN_REG2_ICLOCPR (0x1<<9) +#define TFA98XX_INTERRUPT_IN_REG2_ICLOCPR_POS 9 +#define TFA98XX_INTERRUPT_IN_REG2_ICLOCPR_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLOCPR_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLOCPR_MSK 0x200 + +/* + * int_in_flag_man_wait_src_settings + */ +#define TFA98XX_INTERRUPT_IN_REG2_ICLMWSRC (0x1<<10) +#define TFA98XX_INTERRUPT_IN_REG2_ICLMWSRC_POS 10 +#define TFA98XX_INTERRUPT_IN_REG2_ICLMWSRC_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLMWSRC_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLMWSRC_MSK 0x400 + +/* + * int_in_flag_man_wait_cf_config + */ +#define TFA98XX_INTERRUPT_IN_REG2_ICLMWCFC (0x1<<11) +#define TFA98XX_INTERRUPT_IN_REG2_ICLMWCFC_POS 11 +#define TFA98XX_INTERRUPT_IN_REG2_ICLMWCFC_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLMWCFC_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLMWCFC_MSK 0x800 + +/* + * int_in_flag_man_start_mute_audio + */ +#define TFA98XX_INTERRUPT_IN_REG2_ICLMWSMU (0x1<<12) +#define TFA98XX_INTERRUPT_IN_REG2_ICLMWSMU_POS 12 +#define TFA98XX_INTERRUPT_IN_REG2_ICLMWSMU_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLMWSMU_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLMWSMU_MSK 0x1000 + +/* + * int_in_flag_cfma_err + */ +#define TFA98XX_INTERRUPT_IN_REG2_ICLCFMER (0x1<<13) +#define TFA98XX_INTERRUPT_IN_REG2_ICLCFMER_POS 13 +#define TFA98XX_INTERRUPT_IN_REG2_ICLCFMER_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLCFMER_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLCFMER_MSK 0x2000 + +/* + * int_in_flag_cfma_ack + */ +#define TFA98XX_INTERRUPT_IN_REG2_ICLCFMAC (0x1<<14) +#define TFA98XX_INTERRUPT_IN_REG2_ICLCFMAC_POS 14 +#define TFA98XX_INTERRUPT_IN_REG2_ICLCFMAC_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLCFMAC_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLCFMAC_MSK 0x4000 + +/* + * int_in_flag_clk_out_of_range + */ +#define TFA98XX_INTERRUPT_IN_REG2_ICLCLKOOR (0x1<<15) +#define TFA98XX_INTERRUPT_IN_REG2_ICLCLKOOR_POS 15 +#define TFA98XX_INTERRUPT_IN_REG2_ICLCLKOOR_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLCLKOOR_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG2_ICLCLKOOR_MSK 0x8000 + + +/* + * (0x46)-interrupt_in_reg3 + */ + +/* + * int_in_flag_tdm_error + */ +#define TFA98XX_INTERRUPT_IN_REG3_ICLTDMER (0x1<<0) +#define TFA98XX_INTERRUPT_IN_REG3_ICLTDMER_POS 0 +#define TFA98XX_INTERRUPT_IN_REG3_ICLTDMER_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG3_ICLTDMER_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG3_ICLTDMER_MSK 0x1 + +/* + * int_in_flag_clip_left + */ +#define TFA98XX_INTERRUPT_IN_REG3_ICLCLPL (0x1<<1) +#define TFA98XX_INTERRUPT_IN_REG3_ICLCLPL_POS 1 +#define TFA98XX_INTERRUPT_IN_REG3_ICLCLPL_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG3_ICLCLPL_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG3_ICLCLPL_MSK 0x2 + +/* + * int_in_flag_clip_right + */ +#define TFA98XX_INTERRUPT_IN_REG3_ICLCLPR (0x1<<2) +#define TFA98XX_INTERRUPT_IN_REG3_ICLCLPR_POS 2 +#define TFA98XX_INTERRUPT_IN_REG3_ICLCLPR_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG3_ICLCLPR_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG3_ICLCLPR_MSK 0x4 + +/* + * int_in_flag_mic_ocpok + */ +#define TFA98XX_INTERRUPT_IN_REG3_ICLOCPM (0x1<<3) +#define TFA98XX_INTERRUPT_IN_REG3_ICLOCPM_POS 3 +#define TFA98XX_INTERRUPT_IN_REG3_ICLOCPM_LEN 1 +#define TFA98XX_INTERRUPT_IN_REG3_ICLOCPM_MAX 1 +#define TFA98XX_INTERRUPT_IN_REG3_ICLOCPM_MSK 0x8 + + +/* + * (0x48)-interrupt_enable_reg1 + */ + +/* + * int_enable_flag_por + */ +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEVDDS (0x1<<0) +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEVDDS_POS 0 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEVDDS_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEVDDS_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEVDDS_MSK 0x1 + +/* + * int_enable_flag_pll_lock + */ +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEPLLS (0x1<<1) +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEPLLS_POS 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEPLLS_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEPLLS_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEPLLS_MSK 0x2 + +/* + * int_enable_flag_otpok + */ +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEOTDS (0x1<<2) +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEOTDS_POS 2 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEOTDS_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEOTDS_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEOTDS_MSK 0x4 + +/* + * int_enable_flag_ovpok + */ +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEOVDS (0x1<<3) +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEOVDS_POS 3 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEOVDS_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEOVDS_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEOVDS_MSK 0x8 + +/* + * int_enable_flag_uvpok + */ +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEUVDS (0x1<<4) +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEUVDS_POS 4 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEUVDS_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEUVDS_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEUVDS_MSK 0x10 + +/* + * int_enable_flag_clocks_stable + */ +#define TFA98XX_INTERRUPT_ENABLE_REG1_IECLKS (0x1<<5) +#define TFA98XX_INTERRUPT_ENABLE_REG1_IECLKS_POS 5 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IECLKS_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IECLKS_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IECLKS_MSK 0x20 + +/* + * int_enable_flag_mtp_busy + */ +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEMTPB (0x1<<6) +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEMTPB_POS 6 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEMTPB_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEMTPB_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEMTPB_MSK 0x40 + +/* + * int_enable_flag_lost_clk + */ +#define TFA98XX_INTERRUPT_ENABLE_REG1_IENOCLK (0x1<<7) +#define TFA98XX_INTERRUPT_ENABLE_REG1_IENOCLK_POS 7 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IENOCLK_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IENOCLK_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IENOCLK_MSK 0x80 + +/* + * int_enable_flag_cf_speakererror + */ +#define TFA98XX_INTERRUPT_ENABLE_REG1_IESPKS (0x1<<8) +#define TFA98XX_INTERRUPT_ENABLE_REG1_IESPKS_POS 8 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IESPKS_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IESPKS_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IESPKS_MSK 0x100 + +/* + * int_enable_flag_cold_started + */ +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEACS (0x1<<9) +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEACS_POS 9 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEACS_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEACS_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEACS_MSK 0x200 + +/* + * int_enable_flag_engage + */ +#define TFA98XX_INTERRUPT_ENABLE_REG1_IESWS (0x1<<10) +#define TFA98XX_INTERRUPT_ENABLE_REG1_IESWS_POS 10 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IESWS_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IESWS_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IESWS_MSK 0x400 + +/* + * int_enable_flag_watchdog_reset + */ +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEWDS (0x1<<11) +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEWDS_POS 11 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEWDS_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEWDS_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEWDS_MSK 0x800 + +/* + * int_enable_flag_enbl_amp + */ +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEAMPS (0x1<<12) +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEAMPS_POS 12 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEAMPS_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEAMPS_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEAMPS_MSK 0x1000 + +/* + * int_enable_flag_enbl_ref + */ +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEAREFS (0x1<<13) +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEAREFS_POS 13 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEAREFS_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEAREFS_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEAREFS_MSK 0x2000 + +/* + * int_enable_flag_adc10_ready + */ +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEADCCR (0x1<<14) +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEADCCR_POS 14 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEADCCR_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEADCCR_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEADCCR_MSK 0x4000 + +/* + * int_enable_flag_bod_vddd_nok + */ +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEBODNOK (0x1<<15) +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEBODNOK_POS 15 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEBODNOK_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEBODNOK_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG1_IEBODNOK_MSK 0x8000 + + +/* + * (0x49)-interrupt_enable_reg2 + */ + +/* + * int_enable_flag_bst_bstcur + */ +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTCU (0x1<<0) +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTCU_POS 0 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTCU_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTCU_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTCU_MSK 0x1 + +/* + * int_enable_flag_bst_hiz + */ +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTHI (0x1<<1) +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTHI_POS 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTHI_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTHI_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTHI_MSK 0x2 + +/* + * int_enable_flag_bst_ocpok + */ +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTOC (0x1<<2) +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTOC_POS 2 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTOC_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTOC_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTOC_MSK 0x4 + +/* + * int_enable_flag_bst_peakcur + */ +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTPC (0x1<<3) +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTPC_POS 3 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTPC_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTPC_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTPC_MSK 0x8 + +/* + * int_enable_flag_bst_voutcomp + */ +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTVC (0x1<<4) +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTVC_POS 4 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTVC_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTVC_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBSTVC_MSK 0x10 + +/* + * int_enable_flag_bst_voutcomp86 + */ +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBST86 (0x1<<5) +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBST86_POS 5 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBST86_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBST86_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBST86_MSK 0x20 + +/* + * int_enable_flag_bst_voutcomp93 + */ +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBST93 (0x1<<6) +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBST93_POS 6 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBST93_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBST93_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEBST93_MSK 0x40 + +/* + * int_enable_flag_rcvldop_ready + */ +#define TFA98XX_INTERRUPT_ENABLE_REG2_IERCVLD (0x1<<7) +#define TFA98XX_INTERRUPT_ENABLE_REG2_IERCVLD_POS 7 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IERCVLD_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IERCVLD_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IERCVLD_MSK 0x80 + +/* + * int_enable_flag_ocp_alarm_left + */ +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEOCPL (0x1<<8) +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEOCPL_POS 8 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEOCPL_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEOCPL_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEOCPL_MSK 0x100 + +/* + * int_enable_flag_ocp_alarm_right + */ +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEOCPR (0x1<<9) +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEOCPR_POS 9 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEOCPR_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEOCPR_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEOCPR_MSK 0x200 + +/* + * int_enable_flag_man_wait_src_settings + */ +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEMWSRC (0x1<<10) +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEMWSRC_POS 10 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEMWSRC_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEMWSRC_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEMWSRC_MSK 0x400 + +/* + * int_enable_flag_man_wait_cf_config + */ +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEMWCFC (0x1<<11) +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEMWCFC_POS 11 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEMWCFC_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEMWCFC_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEMWCFC_MSK 0x800 + +/* + * int_enable_flag_man_start_mute_audio + */ +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEMWSMU (0x1<<12) +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEMWSMU_POS 12 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEMWSMU_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEMWSMU_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IEMWSMU_MSK 0x1000 + +/* + * int_enable_flag_cfma_err + */ +#define TFA98XX_INTERRUPT_ENABLE_REG2_IECFMER (0x1<<13) +#define TFA98XX_INTERRUPT_ENABLE_REG2_IECFMER_POS 13 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IECFMER_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IECFMER_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IECFMER_MSK 0x2000 + +/* + * int_enable_flag_cfma_ack + */ +#define TFA98XX_INTERRUPT_ENABLE_REG2_IECFMAC (0x1<<14) +#define TFA98XX_INTERRUPT_ENABLE_REG2_IECFMAC_POS 14 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IECFMAC_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IECFMAC_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IECFMAC_MSK 0x4000 + +/* + * int_enable_flag_clk_out_of_range + */ +#define TFA98XX_INTERRUPT_ENABLE_REG2_IECLKOOR (0x1<<15) +#define TFA98XX_INTERRUPT_ENABLE_REG2_IECLKOOR_POS 15 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IECLKOOR_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IECLKOOR_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG2_IECLKOOR_MSK 0x8000 + + +/* + * (0x4a)-interrupt_enable_reg3 + */ + +/* + * int_enable_flag_tdm_error + */ +#define TFA98XX_INTERRUPT_ENABLE_REG3_IETDMER (0x1<<0) +#define TFA98XX_INTERRUPT_ENABLE_REG3_IETDMER_POS 0 +#define TFA98XX_INTERRUPT_ENABLE_REG3_IETDMER_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG3_IETDMER_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG3_IETDMER_MSK 0x1 + +/* + * int_enable_flag_clip_left + */ +#define TFA98XX_INTERRUPT_ENABLE_REG3_IECLPL (0x1<<1) +#define TFA98XX_INTERRUPT_ENABLE_REG3_IECLPL_POS 1 +#define TFA98XX_INTERRUPT_ENABLE_REG3_IECLPL_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG3_IECLPL_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG3_IECLPL_MSK 0x2 + +/* + * int_enable_flag_clip_right + */ +#define TFA98XX_INTERRUPT_ENABLE_REG3_IECLPR (0x1<<2) +#define TFA98XX_INTERRUPT_ENABLE_REG3_IECLPR_POS 2 +#define TFA98XX_INTERRUPT_ENABLE_REG3_IECLPR_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG3_IECLPR_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG3_IECLPR_MSK 0x4 + +/* + * int_enable_flag_mic_ocpok + */ +#define TFA98XX_INTERRUPT_ENABLE_REG3_IEOCPM1 (0x1<<3) +#define TFA98XX_INTERRUPT_ENABLE_REG3_IEOCPM1_POS 3 +#define TFA98XX_INTERRUPT_ENABLE_REG3_IEOCPM1_LEN 1 +#define TFA98XX_INTERRUPT_ENABLE_REG3_IEOCPM1_MAX 1 +#define TFA98XX_INTERRUPT_ENABLE_REG3_IEOCPM1_MSK 0x8 + + +/* + * (0x4c)-status_polarity_reg1 + */ + +/* + * int_polarity_flag_por + */ +#define TFA98XX_STATUS_POLARITY_REG1_IPOVDDS (0x1<<0) +#define TFA98XX_STATUS_POLARITY_REG1_IPOVDDS_POS 0 +#define TFA98XX_STATUS_POLARITY_REG1_IPOVDDS_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOVDDS_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOVDDS_MSK 0x1 + +/* + * int_polarity_flag_pll_lock + */ +#define TFA98XX_STATUS_POLARITY_REG1_IPOPLLS (0x1<<1) +#define TFA98XX_STATUS_POLARITY_REG1_IPOPLLS_POS 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOPLLS_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOPLLS_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOPLLS_MSK 0x2 + +/* + * int_polarity_flag_otpok + */ +#define TFA98XX_STATUS_POLARITY_REG1_IPOOTDS (0x1<<2) +#define TFA98XX_STATUS_POLARITY_REG1_IPOOTDS_POS 2 +#define TFA98XX_STATUS_POLARITY_REG1_IPOOTDS_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOOTDS_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOOTDS_MSK 0x4 + +/* + * int_polarity_flag_ovpok + */ +#define TFA98XX_STATUS_POLARITY_REG1_IPOOVDS (0x1<<3) +#define TFA98XX_STATUS_POLARITY_REG1_IPOOVDS_POS 3 +#define TFA98XX_STATUS_POLARITY_REG1_IPOOVDS_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOOVDS_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOOVDS_MSK 0x8 + +/* + * int_polarity_flag_uvpok + */ +#define TFA98XX_STATUS_POLARITY_REG1_IPOUVDS (0x1<<4) +#define TFA98XX_STATUS_POLARITY_REG1_IPOUVDS_POS 4 +#define TFA98XX_STATUS_POLARITY_REG1_IPOUVDS_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOUVDS_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOUVDS_MSK 0x10 + +/* + * int_polarity_flag_clocks_stable + */ +#define TFA98XX_STATUS_POLARITY_REG1_IPOCLKS (0x1<<5) +#define TFA98XX_STATUS_POLARITY_REG1_IPOCLKS_POS 5 +#define TFA98XX_STATUS_POLARITY_REG1_IPOCLKS_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOCLKS_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOCLKS_MSK 0x20 + +/* + * int_polarity_flag_mtp_busy + */ +#define TFA98XX_STATUS_POLARITY_REG1_IPOMTPB (0x1<<6) +#define TFA98XX_STATUS_POLARITY_REG1_IPOMTPB_POS 6 +#define TFA98XX_STATUS_POLARITY_REG1_IPOMTPB_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOMTPB_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOMTPB_MSK 0x40 + +/* + * int_polarity_flag_lost_clk + */ +#define TFA98XX_STATUS_POLARITY_REG1_IPONOCLK (0x1<<7) +#define TFA98XX_STATUS_POLARITY_REG1_IPONOCLK_POS 7 +#define TFA98XX_STATUS_POLARITY_REG1_IPONOCLK_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPONOCLK_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPONOCLK_MSK 0x80 + +/* + * int_polarity_flag_cf_speakererror + */ +#define TFA98XX_STATUS_POLARITY_REG1_IPOSPKS (0x1<<8) +#define TFA98XX_STATUS_POLARITY_REG1_IPOSPKS_POS 8 +#define TFA98XX_STATUS_POLARITY_REG1_IPOSPKS_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOSPKS_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOSPKS_MSK 0x100 + +/* + * int_polarity_flag_cold_started + */ +#define TFA98XX_STATUS_POLARITY_REG1_IPOACS (0x1<<9) +#define TFA98XX_STATUS_POLARITY_REG1_IPOACS_POS 9 +#define TFA98XX_STATUS_POLARITY_REG1_IPOACS_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOACS_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOACS_MSK 0x200 + +/* + * int_polarity_flag_engage + */ +#define TFA98XX_STATUS_POLARITY_REG1_IPOSWS (0x1<<10) +#define TFA98XX_STATUS_POLARITY_REG1_IPOSWS_POS 10 +#define TFA98XX_STATUS_POLARITY_REG1_IPOSWS_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOSWS_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOSWS_MSK 0x400 + +/* + * int_polarity_flag_watchdog_reset + */ +#define TFA98XX_STATUS_POLARITY_REG1_IPOWDS (0x1<<11) +#define TFA98XX_STATUS_POLARITY_REG1_IPOWDS_POS 11 +#define TFA98XX_STATUS_POLARITY_REG1_IPOWDS_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOWDS_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOWDS_MSK 0x800 + +/* + * int_polarity_flag_enbl_amp + */ +#define TFA98XX_STATUS_POLARITY_REG1_IPOAMPS (0x1<<12) +#define TFA98XX_STATUS_POLARITY_REG1_IPOAMPS_POS 12 +#define TFA98XX_STATUS_POLARITY_REG1_IPOAMPS_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOAMPS_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOAMPS_MSK 0x1000 + +/* + * int_polarity_flag_enbl_ref + */ +#define TFA98XX_STATUS_POLARITY_REG1_IPOAREFS (0x1<<13) +#define TFA98XX_STATUS_POLARITY_REG1_IPOAREFS_POS 13 +#define TFA98XX_STATUS_POLARITY_REG1_IPOAREFS_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOAREFS_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOAREFS_MSK 0x2000 + +/* + * int_polarity_flag_adc10_ready + */ +#define TFA98XX_STATUS_POLARITY_REG1_IPOADCCR (0x1<<14) +#define TFA98XX_STATUS_POLARITY_REG1_IPOADCCR_POS 14 +#define TFA98XX_STATUS_POLARITY_REG1_IPOADCCR_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOADCCR_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOADCCR_MSK 0x4000 + +/* + * int_polarity_flag_bod_vddd_nok + */ +#define TFA98XX_STATUS_POLARITY_REG1_IPOBODNOK (0x1<<15) +#define TFA98XX_STATUS_POLARITY_REG1_IPOBODNOK_POS 15 +#define TFA98XX_STATUS_POLARITY_REG1_IPOBODNOK_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOBODNOK_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG1_IPOBODNOK_MSK 0x8000 + + +/* + * (0x4d)-status_polarity_reg2 + */ + +/* + * int_polarity_flag_bst_bstcur + */ +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTCU (0x1<<0) +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTCU_POS 0 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTCU_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTCU_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTCU_MSK 0x1 + +/* + * int_polarity_flag_bst_hiz + */ +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTHI (0x1<<1) +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTHI_POS 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTHI_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTHI_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTHI_MSK 0x2 + +/* + * int_polarity_flag_bst_ocpok + */ +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTOC (0x1<<2) +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTOC_POS 2 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTOC_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTOC_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTOC_MSK 0x4 + +/* + * int_polarity_flag_bst_peakcur + */ +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTPC (0x1<<3) +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTPC_POS 3 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTPC_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTPC_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTPC_MSK 0x8 + +/* + * int_polarity_flag_bst_voutcomp + */ +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTVC (0x1<<4) +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTVC_POS 4 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTVC_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTVC_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBSTVC_MSK 0x10 + +/* + * int_polarity_flag_bst_voutcomp86 + */ +#define TFA98XX_STATUS_POLARITY_REG2_IPOBST86 (0x1<<5) +#define TFA98XX_STATUS_POLARITY_REG2_IPOBST86_POS 5 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBST86_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBST86_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBST86_MSK 0x20 + +/* + * int_polarity_flag_bst_voutcomp93 + */ +#define TFA98XX_STATUS_POLARITY_REG2_IPOBST93 (0x1<<6) +#define TFA98XX_STATUS_POLARITY_REG2_IPOBST93_POS 6 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBST93_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBST93_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOBST93_MSK 0x40 + +/* + * int_polarity_flag_rcvldop_ready + */ +#define TFA98XX_STATUS_POLARITY_REG2_IPORCVLD (0x1<<7) +#define TFA98XX_STATUS_POLARITY_REG2_IPORCVLD_POS 7 +#define TFA98XX_STATUS_POLARITY_REG2_IPORCVLD_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPORCVLD_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPORCVLD_MSK 0x80 + +/* + * int_polarity_flag_ocp_alarm_left + */ +#define TFA98XX_STATUS_POLARITY_REG2_IPOOCPL (0x1<<8) +#define TFA98XX_STATUS_POLARITY_REG2_IPOOCPL_POS 8 +#define TFA98XX_STATUS_POLARITY_REG2_IPOOCPL_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOOCPL_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOOCPL_MSK 0x100 + +/* + * int_polarity_flag_ocp_alarm_right + */ +#define TFA98XX_STATUS_POLARITY_REG2_IPOOCPR (0x1<<9) +#define TFA98XX_STATUS_POLARITY_REG2_IPOOCPR_POS 9 +#define TFA98XX_STATUS_POLARITY_REG2_IPOOCPR_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOOCPR_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOOCPR_MSK 0x200 + +/* + * int_polarity_flag_man_wait_src_settings + */ +#define TFA98XX_STATUS_POLARITY_REG2_IPOMWSRC (0x1<<10) +#define TFA98XX_STATUS_POLARITY_REG2_IPOMWSRC_POS 10 +#define TFA98XX_STATUS_POLARITY_REG2_IPOMWSRC_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOMWSRC_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOMWSRC_MSK 0x400 + +/* + * int_polarity_flag_man_wait_cf_config + */ +#define TFA98XX_STATUS_POLARITY_REG2_IPOMWCFC (0x1<<11) +#define TFA98XX_STATUS_POLARITY_REG2_IPOMWCFC_POS 11 +#define TFA98XX_STATUS_POLARITY_REG2_IPOMWCFC_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOMWCFC_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOMWCFC_MSK 0x800 + +/* + * int_polarity_flag_man_start_mute_audio + */ +#define TFA98XX_STATUS_POLARITY_REG2_IPOMWSMU (0x1<<12) +#define TFA98XX_STATUS_POLARITY_REG2_IPOMWSMU_POS 12 +#define TFA98XX_STATUS_POLARITY_REG2_IPOMWSMU_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOMWSMU_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOMWSMU_MSK 0x1000 + +/* + * int_polarity_flag_cfma_err + */ +#define TFA98XX_STATUS_POLARITY_REG2_IPOCFMER (0x1<<13) +#define TFA98XX_STATUS_POLARITY_REG2_IPOCFMER_POS 13 +#define TFA98XX_STATUS_POLARITY_REG2_IPOCFMER_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOCFMER_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOCFMER_MSK 0x2000 + +/* + * int_polarity_flag_cfma_ack + */ +#define TFA98XX_STATUS_POLARITY_REG2_IPOCFMAC (0x1<<14) +#define TFA98XX_STATUS_POLARITY_REG2_IPOCFMAC_POS 14 +#define TFA98XX_STATUS_POLARITY_REG2_IPOCFMAC_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOCFMAC_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPOCFMAC_MSK 0x4000 + +/* + * int_polarity_flag_clk_out_of_range + */ +#define TFA98XX_STATUS_POLARITY_REG2_IPCLKOOR (0x1<<15) +#define TFA98XX_STATUS_POLARITY_REG2_IPCLKOOR_POS 15 +#define TFA98XX_STATUS_POLARITY_REG2_IPCLKOOR_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPCLKOOR_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG2_IPCLKOOR_MSK 0x8000 + + +/* + * (0x4e)-status_polarity_reg3 + */ + +/* + * int_polarity_flag_tdm_error + */ +#define TFA98XX_STATUS_POLARITY_REG3_IPOTDMER (0x1<<0) +#define TFA98XX_STATUS_POLARITY_REG3_IPOTDMER_POS 0 +#define TFA98XX_STATUS_POLARITY_REG3_IPOTDMER_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG3_IPOTDMER_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG3_IPOTDMER_MSK 0x1 + +/* + * int_polarity_flag_clip_left + */ +#define TFA98XX_STATUS_POLARITY_REG3_IPOCLPL (0x1<<1) +#define TFA98XX_STATUS_POLARITY_REG3_IPOCLPL_POS 1 +#define TFA98XX_STATUS_POLARITY_REG3_IPOCLPL_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG3_IPOCLPL_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG3_IPOCLPL_MSK 0x2 + +/* + * int_polarity_flag_clip_right + */ +#define TFA98XX_STATUS_POLARITY_REG3_IPOCLPR (0x1<<2) +#define TFA98XX_STATUS_POLARITY_REG3_IPOCLPR_POS 2 +#define TFA98XX_STATUS_POLARITY_REG3_IPOCLPR_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG3_IPOCLPR_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG3_IPOCLPR_MSK 0x4 + +/* + * int_polarity_flag_mic_ocpok + */ +#define TFA98XX_STATUS_POLARITY_REG3_IPOOCPM (0x1<<3) +#define TFA98XX_STATUS_POLARITY_REG3_IPOOCPM_POS 3 +#define TFA98XX_STATUS_POLARITY_REG3_IPOOCPM_LEN 1 +#define TFA98XX_STATUS_POLARITY_REG3_IPOOCPM_MAX 1 +#define TFA98XX_STATUS_POLARITY_REG3_IPOOCPM_MSK 0x8 + + +/* + * (0x50)-bat_prot_config + */ + +/* + * vbat_prot_attack_time + */ +#define TFA98XX_BAT_PROT_CONFIG_BSSCR (0x3<<0) +#define TFA98XX_BAT_PROT_CONFIG_BSSCR_POS 0 +#define TFA98XX_BAT_PROT_CONFIG_BSSCR_LEN 2 +#define TFA98XX_BAT_PROT_CONFIG_BSSCR_MAX 3 +#define TFA98XX_BAT_PROT_CONFIG_BSSCR_MSK 0x3 + +/* + * vbat_prot_thlevel + */ +#define TFA98XX_BAT_PROT_CONFIG_BSST (0xf<<2) +#define TFA98XX_BAT_PROT_CONFIG_BSST_POS 2 +#define TFA98XX_BAT_PROT_CONFIG_BSST_LEN 4 +#define TFA98XX_BAT_PROT_CONFIG_BSST_MAX 15 +#define TFA98XX_BAT_PROT_CONFIG_BSST_MSK 0x3c + +/* + * vbat_prot_max_reduct + */ +#define TFA98XX_BAT_PROT_CONFIG_BSSRL (0x3<<6) +#define TFA98XX_BAT_PROT_CONFIG_BSSRL_POS 6 +#define TFA98XX_BAT_PROT_CONFIG_BSSRL_LEN 2 +#define TFA98XX_BAT_PROT_CONFIG_BSSRL_MAX 3 +#define TFA98XX_BAT_PROT_CONFIG_BSSRL_MSK 0xc0 + +/* + * vbat_prot_release_time + */ +#define TFA98XX_BAT_PROT_CONFIG_BSSRR (0x7<<8) +#define TFA98XX_BAT_PROT_CONFIG_BSSRR_POS 8 +#define TFA98XX_BAT_PROT_CONFIG_BSSRR_LEN 3 +#define TFA98XX_BAT_PROT_CONFIG_BSSRR_MAX 7 +#define TFA98XX_BAT_PROT_CONFIG_BSSRR_MSK 0x700 + +/* + * vbat_prot_hysterese + */ +#define TFA98XX_BAT_PROT_CONFIG_BSSHY (0x3<<11) +#define TFA98XX_BAT_PROT_CONFIG_BSSHY_POS 11 +#define TFA98XX_BAT_PROT_CONFIG_BSSHY_LEN 2 +#define TFA98XX_BAT_PROT_CONFIG_BSSHY_MAX 3 +#define TFA98XX_BAT_PROT_CONFIG_BSSHY_MSK 0x1800 + +/* + * sel_vbat + */ +#define TFA98XX_BAT_PROT_CONFIG_BSSR (0x1<<14) +#define TFA98XX_BAT_PROT_CONFIG_BSSR_POS 14 +#define TFA98XX_BAT_PROT_CONFIG_BSSR_LEN 1 +#define TFA98XX_BAT_PROT_CONFIG_BSSR_MAX 1 +#define TFA98XX_BAT_PROT_CONFIG_BSSR_MSK 0x4000 + +/* + * bypass_clipper + */ +#define TFA98XX_BAT_PROT_CONFIG_BSSBY (0x1<<15) +#define TFA98XX_BAT_PROT_CONFIG_BSSBY_POS 15 +#define TFA98XX_BAT_PROT_CONFIG_BSSBY_LEN 1 +#define TFA98XX_BAT_PROT_CONFIG_BSSBY_MAX 1 +#define TFA98XX_BAT_PROT_CONFIG_BSSBY_MSK 0x8000 + + +/* + * (0x51)-audio_control + */ + +/* + * batsense_steepness + */ +#define TFA98XX_AUDIO_CONTROL_BSSS (0x1<<0) +#define TFA98XX_AUDIO_CONTROL_BSSS_POS 0 +#define TFA98XX_AUDIO_CONTROL_BSSS_LEN 1 +#define TFA98XX_AUDIO_CONTROL_BSSS_MAX 1 +#define TFA98XX_AUDIO_CONTROL_BSSS_MSK 0x1 + +/* + * soft_mute + */ +#define TFA98XX_AUDIO_CONTROL_INTSMUTE (0x1<<1) +#define TFA98XX_AUDIO_CONTROL_INTSMUTE_POS 1 +#define TFA98XX_AUDIO_CONTROL_INTSMUTE_LEN 1 +#define TFA98XX_AUDIO_CONTROL_INTSMUTE_MAX 1 +#define TFA98XX_AUDIO_CONTROL_INTSMUTE_MSK 0x2 + +/* + * cf_mute_left + */ +#define TFA98XX_AUDIO_CONTROL_CFSML (0x1<<2) +#define TFA98XX_AUDIO_CONTROL_CFSML_POS 2 +#define TFA98XX_AUDIO_CONTROL_CFSML_LEN 1 +#define TFA98XX_AUDIO_CONTROL_CFSML_MAX 1 +#define TFA98XX_AUDIO_CONTROL_CFSML_MSK 0x4 + +/* + * cf_mute_right + */ +#define TFA98XX_AUDIO_CONTROL_CFSMR (0x1<<3) +#define TFA98XX_AUDIO_CONTROL_CFSMR_POS 3 +#define TFA98XX_AUDIO_CONTROL_CFSMR_LEN 1 +#define TFA98XX_AUDIO_CONTROL_CFSMR_MAX 1 +#define TFA98XX_AUDIO_CONTROL_CFSMR_MSK 0x8 + +/* + * bypass_hp_left + */ +#define TFA98XX_AUDIO_CONTROL_HPFBYPL (0x1<<4) +#define TFA98XX_AUDIO_CONTROL_HPFBYPL_POS 4 +#define TFA98XX_AUDIO_CONTROL_HPFBYPL_LEN 1 +#define TFA98XX_AUDIO_CONTROL_HPFBYPL_MAX 1 +#define TFA98XX_AUDIO_CONTROL_HPFBYPL_MSK 0x10 + +/* + * bypass_hp_right + */ +#define TFA98XX_AUDIO_CONTROL_HPFBYPR (0x1<<5) +#define TFA98XX_AUDIO_CONTROL_HPFBYPR_POS 5 +#define TFA98XX_AUDIO_CONTROL_HPFBYPR_LEN 1 +#define TFA98XX_AUDIO_CONTROL_HPFBYPR_MAX 1 +#define TFA98XX_AUDIO_CONTROL_HPFBYPR_MSK 0x20 + +/* + * enbl_dpsa_left + */ +#define TFA98XX_AUDIO_CONTROL_DPSAL (0x1<<6) +#define TFA98XX_AUDIO_CONTROL_DPSAL_POS 6 +#define TFA98XX_AUDIO_CONTROL_DPSAL_LEN 1 +#define TFA98XX_AUDIO_CONTROL_DPSAL_MAX 1 +#define TFA98XX_AUDIO_CONTROL_DPSAL_MSK 0x40 + +/* + * enbl_dpsa_right + */ +#define TFA98XX_AUDIO_CONTROL_DPSAR (0x1<<7) +#define TFA98XX_AUDIO_CONTROL_DPSAR_POS 7 +#define TFA98XX_AUDIO_CONTROL_DPSAR_LEN 1 +#define TFA98XX_AUDIO_CONTROL_DPSAR_MAX 1 +#define TFA98XX_AUDIO_CONTROL_DPSAR_MSK 0x80 + +/* + * cf_volume + */ +#define TFA98XX_AUDIO_CONTROL_VOL (0xff<<8) +#define TFA98XX_AUDIO_CONTROL_VOL_POS 8 +#define TFA98XX_AUDIO_CONTROL_VOL_LEN 8 +#define TFA98XX_AUDIO_CONTROL_VOL_MAX 255 +#define TFA98XX_AUDIO_CONTROL_VOL_MSK 0xff00 + + +/* + * (0x52)-amplifier_config + */ + +/* + * ctrl_rcv + */ +#define TFA98XX_AMPLIFIER_CONFIG_HNDSFRCV (0x1<<0) +#define TFA98XX_AMPLIFIER_CONFIG_HNDSFRCV_POS 0 +#define TFA98XX_AMPLIFIER_CONFIG_HNDSFRCV_LEN 1 +#define TFA98XX_AMPLIFIER_CONFIG_HNDSFRCV_MAX 1 +#define TFA98XX_AMPLIFIER_CONFIG_HNDSFRCV_MSK 0x1 + +/* + * ctrl_cc + */ +#define TFA98XX_AMPLIFIER_CONFIG_CLIPCTRL (0x7<<2) +#define TFA98XX_AMPLIFIER_CONFIG_CLIPCTRL_POS 2 +#define TFA98XX_AMPLIFIER_CONFIG_CLIPCTRL_LEN 3 +#define TFA98XX_AMPLIFIER_CONFIG_CLIPCTRL_MAX 7 +#define TFA98XX_AMPLIFIER_CONFIG_CLIPCTRL_MSK 0x1c + +/* + * gain + */ +#define TFA98XX_AMPLIFIER_CONFIG_AMPGAIN (0xff<<5) +#define TFA98XX_AMPLIFIER_CONFIG_AMPGAIN_POS 5 +#define TFA98XX_AMPLIFIER_CONFIG_AMPGAIN_LEN 8 +#define TFA98XX_AMPLIFIER_CONFIG_AMPGAIN_MAX 255 +#define TFA98XX_AMPLIFIER_CONFIG_AMPGAIN_MSK 0x1fe0 + +/* + * ctrl_slopectrl + */ +#define TFA98XX_AMPLIFIER_CONFIG_SLOPEE (0x1<<13) +#define TFA98XX_AMPLIFIER_CONFIG_SLOPEE_POS 13 +#define TFA98XX_AMPLIFIER_CONFIG_SLOPEE_LEN 1 +#define TFA98XX_AMPLIFIER_CONFIG_SLOPEE_MAX 1 +#define TFA98XX_AMPLIFIER_CONFIG_SLOPEE_MSK 0x2000 + +/* + * ctrl_slope + */ +#define TFA98XX_AMPLIFIER_CONFIG_SLOPESET (0x3<<14) +#define TFA98XX_AMPLIFIER_CONFIG_SLOPESET_POS 14 +#define TFA98XX_AMPLIFIER_CONFIG_SLOPESET_LEN 2 +#define TFA98XX_AMPLIFIER_CONFIG_SLOPESET_MAX 3 +#define TFA98XX_AMPLIFIER_CONFIG_SLOPESET_MSK 0xc000 + + +/* + * (0x5a)-audio_control2 + */ + +/* + * cf_volume_sec + */ +#define TFA98XX_AUDIO_CONTROL2_VOLSEC (0xff<<0) +#define TFA98XX_AUDIO_CONTROL2_VOLSEC_POS 0 +#define TFA98XX_AUDIO_CONTROL2_VOLSEC_LEN 8 +#define TFA98XX_AUDIO_CONTROL2_VOLSEC_MAX 255 +#define TFA98XX_AUDIO_CONTROL2_VOLSEC_MSK 0xff + +/* + * sw_profile + */ +#define TFA98XX_AUDIO_CONTROL2_SWPROFIL (0xff<<8) +#define TFA98XX_AUDIO_CONTROL2_SWPROFIL_POS 8 +#define TFA98XX_AUDIO_CONTROL2_SWPROFIL_LEN 8 +#define TFA98XX_AUDIO_CONTROL2_SWPROFIL_MAX 255 +#define TFA98XX_AUDIO_CONTROL2_SWPROFIL_MSK 0xff00 + + +/* + * (0x70)-dcdc_control0 + */ + +/* + * boost_volt + */ +#define TFA98XX_DCDC_CONTROL0_DCVO (0x7<<0) +#define TFA98XX_DCDC_CONTROL0_DCVO_POS 0 +#define TFA98XX_DCDC_CONTROL0_DCVO_LEN 3 +#define TFA98XX_DCDC_CONTROL0_DCVO_MAX 7 +#define TFA98XX_DCDC_CONTROL0_DCVO_MSK 0x7 + +/* + * boost_cur + */ +#define TFA98XX_DCDC_CONTROL0_DCMCC (0xf<<3) +#define TFA98XX_DCDC_CONTROL0_DCMCC_POS 3 +#define TFA98XX_DCDC_CONTROL0_DCMCC_LEN 4 +#define TFA98XX_DCDC_CONTROL0_DCMCC_MAX 15 +#define TFA98XX_DCDC_CONTROL0_DCMCC_MSK 0x78 + +/* + * bst_coil_value + */ +#define TFA98XX_DCDC_CONTROL0_DCCV (0x3<<7) +#define TFA98XX_DCDC_CONTROL0_DCCV_POS 7 +#define TFA98XX_DCDC_CONTROL0_DCCV_LEN 2 +#define TFA98XX_DCDC_CONTROL0_DCCV_MAX 3 +#define TFA98XX_DCDC_CONTROL0_DCCV_MSK 0x180 + +/* + * boost_intel + */ +#define TFA98XX_DCDC_CONTROL0_DCIE (0x1<<9) +#define TFA98XX_DCDC_CONTROL0_DCIE_POS 9 +#define TFA98XX_DCDC_CONTROL0_DCIE_LEN 1 +#define TFA98XX_DCDC_CONTROL0_DCIE_MAX 1 +#define TFA98XX_DCDC_CONTROL0_DCIE_MSK 0x200 + +/* + * boost_speed + */ +#define TFA98XX_DCDC_CONTROL0_DCSR (0x1<<10) +#define TFA98XX_DCDC_CONTROL0_DCSR_POS 10 +#define TFA98XX_DCDC_CONTROL0_DCSR_LEN 1 +#define TFA98XX_DCDC_CONTROL0_DCSR_MAX 1 +#define TFA98XX_DCDC_CONTROL0_DCSR_MSK 0x400 + +/* + * dcdc_synchronisation + */ +#define TFA98XX_DCDC_CONTROL0_DCSYNCP (0x7<<11) +#define TFA98XX_DCDC_CONTROL0_DCSYNCP_POS 11 +#define TFA98XX_DCDC_CONTROL0_DCSYNCP_LEN 3 +#define TFA98XX_DCDC_CONTROL0_DCSYNCP_MAX 7 +#define TFA98XX_DCDC_CONTROL0_DCSYNCP_MSK 0x3800 + +/* + * dcdcoff_mode + */ +#define TFA98XX_DCDC_CONTROL0_DCDIS (0x1<<14) +#define TFA98XX_DCDC_CONTROL0_DCDIS_POS 14 +#define TFA98XX_DCDC_CONTROL0_DCDIS_LEN 1 +#define TFA98XX_DCDC_CONTROL0_DCDIS_MAX 1 +#define TFA98XX_DCDC_CONTROL0_DCDIS_MSK 0x4000 + + +/* + * (0x90)-cf_controls + */ + +/* + * cf_rst_dsp + */ +#define TFA98XX_CF_CONTROLS_RST (0x1<<0) +#define TFA98XX_CF_CONTROLS_RST_POS 0 +#define TFA98XX_CF_CONTROLS_RST_LEN 1 +#define TFA98XX_CF_CONTROLS_RST_MAX 1 +#define TFA98XX_CF_CONTROLS_RST_MSK 0x1 + +/* + * cf_dmem + */ +#define TFA98XX_CF_CONTROLS_DMEM (0x3<<1) +#define TFA98XX_CF_CONTROLS_DMEM_POS 1 +#define TFA98XX_CF_CONTROLS_DMEM_LEN 2 +#define TFA98XX_CF_CONTROLS_DMEM_MAX 3 +#define TFA98XX_CF_CONTROLS_DMEM_MSK 0x6 + +/* + * cf_aif + */ +#define TFA98XX_CF_CONTROLS_AIF (0x1<<3) +#define TFA98XX_CF_CONTROLS_AIF_POS 3 +#define TFA98XX_CF_CONTROLS_AIF_LEN 1 +#define TFA98XX_CF_CONTROLS_AIF_MAX 1 +#define TFA98XX_CF_CONTROLS_AIF_MSK 0x8 + +/* + * cf_int + */ +#define TFA98XX_CF_CONTROLS_CFINT (0x1<<4) +#define TFA98XX_CF_CONTROLS_CFINT_POS 4 +#define TFA98XX_CF_CONTROLS_CFINT_LEN 1 +#define TFA98XX_CF_CONTROLS_CFINT_MAX 1 +#define TFA98XX_CF_CONTROLS_CFINT_MSK 0x10 + +/* + * cf_cgate_off + */ +#define TFA98XX_CF_CONTROLS_CFCGATE (0x1<<5) +#define TFA98XX_CF_CONTROLS_CFCGATE_POS 5 +#define TFA98XX_CF_CONTROLS_CFCGATE_LEN 1 +#define TFA98XX_CF_CONTROLS_CFCGATE_MAX 1 +#define TFA98XX_CF_CONTROLS_CFCGATE_MSK 0x20 + +/* + * cf_req_cmd + */ +#define TFA98XX_CF_CONTROLS_REQCMD (0x1<<8) +#define TFA98XX_CF_CONTROLS_REQCMD_POS 8 +#define TFA98XX_CF_CONTROLS_REQCMD_LEN 1 +#define TFA98XX_CF_CONTROLS_REQCMD_MAX 1 +#define TFA98XX_CF_CONTROLS_REQCMD_MSK 0x100 + +/* + * cf_req_reset + */ +#define TFA98XX_CF_CONTROLS_REQRST (0x1<<9) +#define TFA98XX_CF_CONTROLS_REQRST_POS 9 +#define TFA98XX_CF_CONTROLS_REQRST_LEN 1 +#define TFA98XX_CF_CONTROLS_REQRST_MAX 1 +#define TFA98XX_CF_CONTROLS_REQRST_MSK 0x200 + +/* + * cf_req_mips + */ +#define TFA98XX_CF_CONTROLS_REQMIPS (0x1<<10) +#define TFA98XX_CF_CONTROLS_REQMIPS_POS 10 +#define TFA98XX_CF_CONTROLS_REQMIPS_LEN 1 +#define TFA98XX_CF_CONTROLS_REQMIPS_MAX 1 +#define TFA98XX_CF_CONTROLS_REQMIPS_MSK 0x400 + +/* + * cf_req_mute_ready + */ +#define TFA98XX_CF_CONTROLS_REQMUTED (0x1<<11) +#define TFA98XX_CF_CONTROLS_REQMUTED_POS 11 +#define TFA98XX_CF_CONTROLS_REQMUTED_LEN 1 +#define TFA98XX_CF_CONTROLS_REQMUTED_MAX 1 +#define TFA98XX_CF_CONTROLS_REQMUTED_MSK 0x800 + +/* + * cf_req_volume_ready + */ +#define TFA98XX_CF_CONTROLS_REQVOL (0x1<<12) +#define TFA98XX_CF_CONTROLS_REQVOL_POS 12 +#define TFA98XX_CF_CONTROLS_REQVOL_LEN 1 +#define TFA98XX_CF_CONTROLS_REQVOL_MAX 1 +#define TFA98XX_CF_CONTROLS_REQVOL_MSK 0x1000 + +/* + * cf_req_damage + */ +#define TFA98XX_CF_CONTROLS_REQDMG (0x1<<13) +#define TFA98XX_CF_CONTROLS_REQDMG_POS 13 +#define TFA98XX_CF_CONTROLS_REQDMG_LEN 1 +#define TFA98XX_CF_CONTROLS_REQDMG_MAX 1 +#define TFA98XX_CF_CONTROLS_REQDMG_MSK 0x2000 + +/* + * cf_req_calibrate_ready + */ +#define TFA98XX_CF_CONTROLS_REQCAL (0x1<<14) +#define TFA98XX_CF_CONTROLS_REQCAL_POS 14 +#define TFA98XX_CF_CONTROLS_REQCAL_LEN 1 +#define TFA98XX_CF_CONTROLS_REQCAL_MAX 1 +#define TFA98XX_CF_CONTROLS_REQCAL_MSK 0x4000 + +/* + * cf_req_reserved + */ +#define TFA98XX_CF_CONTROLS_REQRSV (0x1<<15) +#define TFA98XX_CF_CONTROLS_REQRSV_POS 15 +#define TFA98XX_CF_CONTROLS_REQRSV_LEN 1 +#define TFA98XX_CF_CONTROLS_REQRSV_MAX 1 +#define TFA98XX_CF_CONTROLS_REQRSV_MSK 0x8000 + + +/* + * (0x91)-cf_mad + */ + +/* + * cf_madd + */ +#define TFA98XX_CF_MAD_MADD (0xffff<<0) +#define TFA98XX_CF_MAD_MADD_POS 0 +#define TFA98XX_CF_MAD_MADD_LEN 16 +#define TFA98XX_CF_MAD_MADD_MAX 65535 +#define TFA98XX_CF_MAD_MADD_MSK 0xffff + + +/* + * (0x92)-cf_mem + */ + +/* + * cf_mema + */ +#define TFA98XX_CF_MEM_MEMA (0xffff<<0) +#define TFA98XX_CF_MEM_MEMA_POS 0 +#define TFA98XX_CF_MEM_MEMA_LEN 16 +#define TFA98XX_CF_MEM_MEMA_MAX 65535 +#define TFA98XX_CF_MEM_MEMA_MSK 0xffff + + +/* + * (0x93)-cf_status + */ + +/* + * cf_err + */ +#define TFA98XX_CF_STATUS_ERR (0xff<<0) +#define TFA98XX_CF_STATUS_ERR_POS 0 +#define TFA98XX_CF_STATUS_ERR_LEN 8 +#define TFA98XX_CF_STATUS_ERR_MAX 255 +#define TFA98XX_CF_STATUS_ERR_MSK 0xff + +/* + * cf_ack_cmd + */ +#define TFA98XX_CF_STATUS_ACKCMD (0x1<<8) +#define TFA98XX_CF_STATUS_ACKCMD_POS 8 +#define TFA98XX_CF_STATUS_ACKCMD_LEN 1 +#define TFA98XX_CF_STATUS_ACKCMD_MAX 1 +#define TFA98XX_CF_STATUS_ACKCMD_MSK 0x100 + +/* + * cf_ack_reset + */ +#define TFA98XX_CF_STATUS_ACKRST (0x1<<9) +#define TFA98XX_CF_STATUS_ACKRST_POS 9 +#define TFA98XX_CF_STATUS_ACKRST_LEN 1 +#define TFA98XX_CF_STATUS_ACKRST_MAX 1 +#define TFA98XX_CF_STATUS_ACKRST_MSK 0x200 + +/* + * cf_ack_mips + */ +#define TFA98XX_CF_STATUS_ACKMIPS (0x1<<10) +#define TFA98XX_CF_STATUS_ACKMIPS_POS 10 +#define TFA98XX_CF_STATUS_ACKMIPS_LEN 1 +#define TFA98XX_CF_STATUS_ACKMIPS_MAX 1 +#define TFA98XX_CF_STATUS_ACKMIPS_MSK 0x400 + +/* + * cf_ack_mute_ready + */ +#define TFA98XX_CF_STATUS_ACKMUTED (0x1<<11) +#define TFA98XX_CF_STATUS_ACKMUTED_POS 11 +#define TFA98XX_CF_STATUS_ACKMUTED_LEN 1 +#define TFA98XX_CF_STATUS_ACKMUTED_MAX 1 +#define TFA98XX_CF_STATUS_ACKMUTED_MSK 0x800 + +/* + * cf_ack_volume_ready + */ +#define TFA98XX_CF_STATUS_ACKVOL (0x1<<12) +#define TFA98XX_CF_STATUS_ACKVOL_POS 12 +#define TFA98XX_CF_STATUS_ACKVOL_LEN 1 +#define TFA98XX_CF_STATUS_ACKVOL_MAX 1 +#define TFA98XX_CF_STATUS_ACKVOL_MSK 0x1000 + +/* + * cf_ack_damage + */ +#define TFA98XX_CF_STATUS_ACKDMG (0x1<<13) +#define TFA98XX_CF_STATUS_ACKDMG_POS 13 +#define TFA98XX_CF_STATUS_ACKDMG_LEN 1 +#define TFA98XX_CF_STATUS_ACKDMG_MAX 1 +#define TFA98XX_CF_STATUS_ACKDMG_MSK 0x2000 + +/* + * cf_ack_calibrate_ready + */ +#define TFA98XX_CF_STATUS_ACKCAL (0x1<<14) +#define TFA98XX_CF_STATUS_ACKCAL_POS 14 +#define TFA98XX_CF_STATUS_ACKCAL_LEN 1 +#define TFA98XX_CF_STATUS_ACKCAL_MAX 1 +#define TFA98XX_CF_STATUS_ACKCAL_MSK 0x4000 + +/* + * cf_ack_reserved + */ +#define TFA98XX_CF_STATUS_ACKRSV (0x1<<15) +#define TFA98XX_CF_STATUS_ACKRSV_POS 15 +#define TFA98XX_CF_STATUS_ACKRSV_LEN 1 +#define TFA98XX_CF_STATUS_ACKRSV_MAX 1 +#define TFA98XX_CF_STATUS_ACKRSV_MSK 0x8000 + + +/* + * (0xa1)-mtpkey2_reg + */ + +/* + * mtpkey2 + */ +#define TFA98XX_MTPKEY2_REG_MTPK (0xff<<0) +#define TFA98XX_MTPKEY2_REG_MTPK_POS 0 +#define TFA98XX_MTPKEY2_REG_MTPK_LEN 8 +#define TFA98XX_MTPKEY2_REG_MTPK_MAX 255 +#define TFA98XX_MTPKEY2_REG_MTPK_MSK 0xff + + +/* + * (0xa2)-mtp_status + */ + +/* + * key01_locked + */ +#define TFA98XX_MTP_STATUS_KEY1LOCKED (0x1<<0) +#define TFA98XX_MTP_STATUS_KEY1LOCKED_POS 0 +#define TFA98XX_MTP_STATUS_KEY1LOCKED_LEN 1 +#define TFA98XX_MTP_STATUS_KEY1LOCKED_MAX 1 +#define TFA98XX_MTP_STATUS_KEY1LOCKED_MSK 0x1 + +/* + * key02_locked + */ +#define TFA98XX_MTP_STATUS_KEY2LOCKED (0x1<<1) +#define TFA98XX_MTP_STATUS_KEY2LOCKED_POS 1 +#define TFA98XX_MTP_STATUS_KEY2LOCKED_LEN 1 +#define TFA98XX_MTP_STATUS_KEY2LOCKED_MAX 1 +#define TFA98XX_MTP_STATUS_KEY2LOCKED_MSK 0x2 + + +/* + * (0xa3)-KEY_protected_mtp_control + */ + +/* + * auto_copy_iic_to_mtp + */ +#define TFA98XX_KEY_PROTECTED_MTP_CONTROL_CIMTP (0x1<<6) +#define TFA98XX_KEY_PROTECTED_MTP_CONTROL_CIMTP_POS 6 +#define TFA98XX_KEY_PROTECTED_MTP_CONTROL_CIMTP_LEN 1 +#define TFA98XX_KEY_PROTECTED_MTP_CONTROL_CIMTP_MAX 1 +#define TFA98XX_KEY_PROTECTED_MTP_CONTROL_CIMTP_MSK 0x40 + + +/* + * (0xa5)-mtp_data_out_msb + */ + +/* + * mtp_man_data_out_msb + */ +#define TFA98XX_MTP_DATA_OUT_MSB_MTPRDMSB (0xffff<<0) +#define TFA98XX_MTP_DATA_OUT_MSB_MTPRDMSB_POS 0 +#define TFA98XX_MTP_DATA_OUT_MSB_MTPRDMSB_LEN 16 +#define TFA98XX_MTP_DATA_OUT_MSB_MTPRDMSB_MAX 65535 +#define TFA98XX_MTP_DATA_OUT_MSB_MTPRDMSB_MSK 0xffff + + +/* + * (0xa6)-mtp_data_out_lsb + */ + +/* + * mtp_man_data_out_lsb + */ +#define TFA98XX_MTP_DATA_OUT_LSB_MTPRDLSB (0xffff<<0) +#define TFA98XX_MTP_DATA_OUT_LSB_MTPRDLSB_POS 0 +#define TFA98XX_MTP_DATA_OUT_LSB_MTPRDLSB_LEN 16 +#define TFA98XX_MTP_DATA_OUT_LSB_MTPRDLSB_MAX 65535 +#define TFA98XX_MTP_DATA_OUT_LSB_MTPRDLSB_MSK 0xffff + + +/* + * (0xb1)-temp_sensor_config + */ + +/* + * ext_temp + */ +#define TFA98XX_TEMP_SENSOR_CONFIG_EXTTS (0x1ff<<0) +#define TFA98XX_TEMP_SENSOR_CONFIG_EXTTS_POS 0 +#define TFA98XX_TEMP_SENSOR_CONFIG_EXTTS_LEN 9 +#define TFA98XX_TEMP_SENSOR_CONFIG_EXTTS_MAX 511 +#define TFA98XX_TEMP_SENSOR_CONFIG_EXTTS_MSK 0x1ff + +/* + * ext_temp_sel + */ +#define TFA98XX_TEMP_SENSOR_CONFIG_TROS (0x1<<9) +#define TFA98XX_TEMP_SENSOR_CONFIG_TROS_POS 9 +#define TFA98XX_TEMP_SENSOR_CONFIG_TROS_LEN 1 +#define TFA98XX_TEMP_SENSOR_CONFIG_TROS_MAX 1 +#define TFA98XX_TEMP_SENSOR_CONFIG_TROS_MSK 0x200 + + +/* + * (0xf0)-KEY2_protected_MTP0 + */ + +/* + * calibration_onetime + */ +#define TFA98XX_KEY2_PROTECTED_MTP0_MTPOTC (0x1<<0) +#define TFA98XX_KEY2_PROTECTED_MTP0_MTPOTC_POS 0 +#define TFA98XX_KEY2_PROTECTED_MTP0_MTPOTC_LEN 1 +#define TFA98XX_KEY2_PROTECTED_MTP0_MTPOTC_MAX 1 +#define TFA98XX_KEY2_PROTECTED_MTP0_MTPOTC_MSK 0x1 + +/* + * calibr_ron_done + */ +#define TFA98XX_KEY2_PROTECTED_MTP0_MTPEX (0x1<<1) +#define TFA98XX_KEY2_PROTECTED_MTP0_MTPEX_POS 1 +#define TFA98XX_KEY2_PROTECTED_MTP0_MTPEX_LEN 1 +#define TFA98XX_KEY2_PROTECTED_MTP0_MTPEX_MAX 1 +#define TFA98XX_KEY2_PROTECTED_MTP0_MTPEX_MSK 0x2 + +/* + * calibr_dcdc_api_calibrate + */ +#define TFA98XX_KEY2_PROTECTED_MTP0_DCMCCAPI (0x1<<2) +#define TFA98XX_KEY2_PROTECTED_MTP0_DCMCCAPI_POS 2 +#define TFA98XX_KEY2_PROTECTED_MTP0_DCMCCAPI_LEN 1 +#define TFA98XX_KEY2_PROTECTED_MTP0_DCMCCAPI_MAX 1 +#define TFA98XX_KEY2_PROTECTED_MTP0_DCMCCAPI_MSK 0x4 + +/* + * calibr_dcdc_delta_sign + */ +#define TFA98XX_KEY2_PROTECTED_MTP0_DCMCCSB (0x1<<3) +#define TFA98XX_KEY2_PROTECTED_MTP0_DCMCCSB_POS 3 +#define TFA98XX_KEY2_PROTECTED_MTP0_DCMCCSB_LEN 1 +#define TFA98XX_KEY2_PROTECTED_MTP0_DCMCCSB_MAX 1 +#define TFA98XX_KEY2_PROTECTED_MTP0_DCMCCSB_MSK 0x8 + +/* + * calibr_dcdc_delta + */ +#define TFA98XX_KEY2_PROTECTED_MTP0_USERDEF (0x7<<4) +#define TFA98XX_KEY2_PROTECTED_MTP0_USERDEF_POS 4 +#define TFA98XX_KEY2_PROTECTED_MTP0_USERDEF_LEN 3 +#define TFA98XX_KEY2_PROTECTED_MTP0_USERDEF_MAX 7 +#define TFA98XX_KEY2_PROTECTED_MTP0_USERDEF_MSK 0x70 + + +/* + * (0xf4)-KEY1_protected_MTP4 + */ + + +/* + * (0xf5)-KEY1_protected_MTP5 + */ + +#endif /* TFA98XX_GENREGS_H */ diff --git a/techpack/audio/asoc/codecs/tfa9874/tfa98xx_parameters.h b/techpack/audio/asoc/codecs/tfa9874/tfa98xx_parameters.h new file mode 100644 index 000000000000..50f9a8c82914 --- /dev/null +++ b/techpack/audio/asoc/codecs/tfa9874/tfa98xx_parameters.h @@ -0,0 +1,741 @@ +/* + * Copyright 2013-2017 NXP Semiconductors + * + * 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. + */ + +/* + * tfa98xx_parameters.h + * + * Created on: Jul 22, 2013 + * Author: NLV02095 + */ + +#ifndef TFA98XXPARAMETERS_H_ +#define TFA98XXPARAMETERS_H_ + +//#include "config.h" +// workaround for Visual Studio: +// fatal error C1083: Cannot open include file: 'config.h': No such file or directory +#ifdef __KERNEL__ +#include +#else +#include +#endif + +#include "tfa_service.h" + +#if (defined(WIN32) || defined(_X64)) +/* These warnings are disabled because it is only given by Windows and there is no easy fix */ +#pragma warning(disable:4200) +#pragma warning(disable:4214) +#endif + +/* + * profiles & volumesteps + * + */ +#define TFA_MAX_PROFILES (64) +#define TFA_MAX_VSTEPS (64) +#define TFA_MAX_VSTEP_MSG_MARKER (100) /* This marker is used to indicate if all msgs need to be written to the device */ +#define TFA_MAX_MSGS (10) + +// the pack pragma is required to make that the size in memory +// matches the actual variable lenghts +// This is to assure that the binary files can be transported between +// different platforms. +#pragma pack (push, 1) + +/* + * typedef for 24 bit value using 3 bytes + */ +typedef struct uint24 { + uint8_t b[3]; +} uint24_t; +/* + * the generic header + * all char types are in ASCII + */ +typedef struct nxpTfaHeader { + uint16_t id; + char version[2]; // "V_" : V=version, vv=subversion + char subversion[2]; // "vv" : vv=subversion + uint16_t size; // data size in bytes following CRC + uint32_t CRC; // 32-bits CRC for following data + char customer[8]; // “name of customer” + char application[8]; // “application name” + char type[8]; // “application type name” +} nxpTfaHeader_t; + +typedef enum nxpTfaSamplerate { + fs_8k, // 8kHz + fs_11k025, // 11.025kHz + fs_12k, // 12kHz + fs_16k, // 16kHz + fs_22k05, // 22.05kHz + fs_24k, // 24kHz + fs_32k, // 32kHz + fs_44k1, // 44.1kHz + fs_48k, // 48kHz + fs_96k, // 96kHz + fs_count // Should always be last item. +} nxpTfaSamplerate_t; + +// Keep in sync with nxpTfaSamplerate_t ! +static const int nxpTfaSamplerateHz[fs_count] = { 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 96000 }; + + +/* + * coolflux direct memory access + */ +typedef struct nxpTfaDspMem { + uint8_t type; /* 0--3: p, x, y, iomem */ + uint16_t address; /* target address */ + uint8_t size; /* data size in words */ + int words[]; /* payload in signed 32bit integer (two's complement) */ +} nxpTfaDspMem_t; + +/* + * the biquad coefficients for the API together with index in filter + * the biquad_index is the actual index in the equalizer +1 + */ +#define BIQUAD_COEFF_SIZE 6 + +/* +* Output fixed point coeffs structure +*/ +typedef struct { + int a2; + int a1; + int b2; + int b1; + int b0; +}nxpTfaBiquad_t; + +typedef struct nxpTfaBiquadOld { + uint8_t bytes[BIQUAD_COEFF_SIZE*sizeof(uint24_t)]; +}nxpTfaBiquadOld_t; + +typedef struct nxpTfaBiquadFloat { + float headroom; + float b0; + float b1; + float b2; + float a1; + float a2; +} nxpTfaBiquadFloat_t; + +/* +* EQ filter definitions +* Note: This is not in line with smartstudio (JV: 12/12/2016) +*/ +typedef enum nxpTfaFilterType { + fCustom, //User defined biquad coefficients + fFlat, //Vary only gain + fLowpass, //2nd order Butterworth low pass + fHighpass, //2nd order Butterworth high pass + fLowshelf, + fHighshelf, + fNotch, + fPeak, + fBandpass, + f1stLP, + f1stHP, + fElliptic +} nxpTfaFilterType_t; + +/* + * filter parameters for biquad (re-)calculation + */ +typedef struct nxpTfaFilter { + nxpTfaBiquadOld_t biquad; + uint8_t enabled; + uint8_t type; // (== enum FilterTypes, assure 8bits length) + float frequency; + float Q; + float gain; +} nxpTfaFilter_t ; //8 * float + int32 + byte == 37 + +/* + * biquad params for calculation +*/ + +#define TFA_BQ_EQ_INDEX 0 +#define TFA_BQ_ANTI_ALIAS_INDEX 10 +#define TFA_BQ_INTEGRATOR_INDEX 13 + +/* +* Loudspeaker Compensation filter definitions +*/ +typedef struct nxpTfaLsCompensationFilter { + nxpTfaBiquad_t biquad; + uint8_t lsCompOn; // Loudspeaker compensation on/off; when 'off', the DSP code doesn't apply the bwExt => bwExtOn GUI flag should be gray to avoid confusion + uint8_t bwExtOn; // Bandwidth extension on/off + float fRes; // [Hz] speaker resonance frequency + float Qt; // Speaker resonance Q-factor + float fBwExt; // [Hz] Band width extension frequency + float samplingFreq;// [Hz] Sampling frequency +} nxpTfaLsCompensationFilter_t; + +/* +* Anti Aliasing Elliptic filter definitions +*/ +typedef struct nxpTfaAntiAliasFilter { + nxpTfaBiquad_t biquad; /**< Output results fixed point coeffs */ + uint8_t enabled; + float cutOffFreq; // cut off frequency + float samplingFreq; // sampling frequency + float rippleDb; // range: [0.1 3.0] + float rolloff; // range: [-1.0 1.0] +} nxpTfaAntiAliasFilter_t; + +/** +* Integrator filter input definitions +*/ +typedef struct nxpTfaIntegratorFilter { + nxpTfaBiquad_t biquad; /**< Output results fixed point coeffs */ + uint8_t type; /**< Butterworth filter type: high or low pass */ + float cutOffFreq; /**< cut off frequency in Hertz; range: [100.0 4000.0] */ + float samplingFreq; /**< sampling frequency in Hertz */ + float leakage; /**< leakage factor; range [0.0 1.0] */ +} nxpTfaIntegratorFilter_t; + + +typedef struct nxpTfaEqFilter { + nxpTfaBiquad_t biquad; + uint8_t enabled; + uint8_t type; // (== enum FilterTypes, assure 8bits length) + float cutOffFreq; // cut off frequency, // range: [100.0 4000.0] + float samplingFreq; // sampling frequency + float Q; // range: [0.5 5.0] + float gainDb; // range: [-10.0 10.0] +} nxpTfaEqFilter_t ; //8 * float + int32 + byte == 37 + +typedef struct nxpTfaContAntiAlias { + int8_t index; /**< index determines destination type; anti-alias, integrator,eq */ + uint8_t type; + float cutOffFreq; // cut off frequency + float samplingFreq; + float rippleDb; // integrator leakage + float rolloff; + uint8_t bytes[5*3]; // payload 5*24buts coeffs +}nxpTfaContAntiAlias_t; + +typedef struct nxpTfaContIntegrator { + int8_t index; /**< index determines destination type; anti-alias, integrator,eq */ + uint8_t type; + float cutOffFreq; // cut off frequency + float samplingFreq; + float leakage; // integrator leakage + float reserved; + uint8_t bytes[5*3]; // payload 5*24buts coeffs +}nxpTfaContIntegrator_t; + +typedef struct nxpTfaContEq { + int8_t index; + uint8_t type; // (== enum FilterTypes, assure 8bits length) + float cutOffFreq; // cut off frequency, // range: [100.0 4000.0] + float samplingFreq; // sampling frequency + float Q; // range: [0.5 5.0] + float gainDb; // range: [-10.0 10.0] + uint8_t bytes[5*3]; // payload 5*24buts coeffs +} nxpTfaContEq_t ; //8 * float + int32 + byte == 37 + +typedef union nxpTfaContBiquad { + nxpTfaContEq_t eq; + nxpTfaContAntiAlias_t aa; + nxpTfaContIntegrator_t in; +}nxpTfaContBiquad_t; + +#define TFA_BQ_EQ_INDEX 0 +#define TFA_BQ_ANTI_ALIAS_INDEX 10 +#define TFA_BQ_INTEGRATOR_INDEX 13 +#define TFA98XX_MAX_EQ 10 + +typedef struct nxpTfaEqualizer { + nxpTfaFilter_t filter[TFA98XX_MAX_EQ]; +} nxpTfaEqualizer_t; + +/* + * files + */ +#define HDR(c1,c2) (c2<<8|c1) // little endian +typedef enum nxpTfaHeaderType { + paramsHdr = HDR('P','M'), /* containter file */ + volstepHdr = HDR('V','P'), + patchHdr = HDR('P','A'), + speakerHdr = HDR('S','P'), + presetHdr = HDR('P','R'), + configHdr = HDR('C','O'), + equalizerHdr = HDR('E','Q'), + drcHdr = HDR('D','R'), + msgHdr = HDR('M','G'), /* generic message */ + infoHdr = HDR('I','N') +} nxpTfaHeaderType_t; + +/* + * equalizer file + */ +#define NXPTFA_EQ_VERSION '1' +#define NXPTFA_EQ_SUBVERSION "00" +typedef struct nxpTfaEqualizerFile { + nxpTfaHeader_t hdr; + uint8_t samplerate; // ==enum samplerates, assure 8 bits + nxpTfaFilter_t filter[TFA98XX_MAX_EQ];// note: API index counts from 1..10 +} nxpTfaEqualizerFile_t; + +/* + * patch file + */ +#define NXPTFA_PA_VERSION '1' +#define NXPTFA_PA_SUBVERSION "00" +typedef struct nxpTfaPatchFile { + nxpTfaHeader_t hdr; + uint8_t data[]; +} nxpTfaPatch_t; + +/* + * generic message file + * - the payload of this file includes the opcode and is send straight to the DSP + */ +#define NXPTFA_MG_VERSION '3' +#define NXPTFA_MG_SUBVERSION "00" +typedef struct nxpTfaMsgFile { + nxpTfaHeader_t hdr; + uint8_t data[]; +} nxpTfaMsgFile_t; + +/* + * NOTE the tfa98xx API defines the enum Tfa98xx_config_type that defines + * the subtypes as decribes below. + * tfa98xx_dsp_config_parameter_type() can be used to get the + * supported type for the active device.. + */ +/* + * config file V1 sub 1 + */ +#define NXPTFA_CO_VERSION '1' +#define NXPTFA_CO3_VERSION '3' +#define NXPTFA_CO_SUBVERSION1 "01" +typedef struct nxpTfaConfigS1File { + nxpTfaHeader_t hdr; + uint8_t data[55*3]; +} nxpTfaConfigS1_t; + +/* + * config file V1 sub 2 + */ +#define NXPTFA_CO_SUBVERSION2 "02" +typedef struct nxpTfaConfigS2File { + nxpTfaHeader_t hdr; + uint8_t data[67*3]; +} nxpTfaConfigS2_t; + +/* + * config file V1 sub 3 + */ +#define NXPTFA_CO_SUBVERSION3 "03" +typedef struct nxpTfaConfigS3File { + nxpTfaHeader_t hdr; + uint8_t data[67*3]; +} nxpTfaConfigS3_t; + +/* + * config file V1.0 + */ +#define NXPTFA_CO_SUBVERSION "00" +typedef struct nxpTfaConfigFile { + nxpTfaHeader_t hdr; + uint8_t data[]; +} nxpTfaConfig_t; + +/* + * preset file + */ +#define NXPTFA_PR_VERSION '1' +#define NXPTFA_PR_SUBVERSION "00" +typedef struct nxpTfaPresetFile { + nxpTfaHeader_t hdr; + uint8_t data[]; +} nxpTfaPreset_t; + +/* + * drc file + */ +#define NXPTFA_DR_VERSION '1' +#define NXPTFA_DR_SUBVERSION "00" +typedef struct nxpTfaDrcFile { + nxpTfaHeader_t hdr; + uint8_t data[]; +} nxpTfaDrc_t; + +/* + * drc file + * for tfa 2 there is also a xml-version + */ +#define NXPTFA_DR3_VERSION '3' +#define NXPTFA_DR3_SUBVERSION "00" +typedef struct nxpTfaDrcFile2 { + nxpTfaHeader_t hdr; + uint8_t version[3]; + uint8_t data[]; +} nxpTfaDrc2_t; + +/* + * volume step structures + */ +// VP01 +#define NXPTFA_VP1_VERSION '1' +#define NXPTFA_VP1_SUBVERSION "01" +typedef struct nxpTfaVolumeStep1 { + float attenuation; // IEEE single float + uint8_t preset[TFA98XX_PRESET_LENGTH]; +} nxpTfaVolumeStep1_t; + +// VP02 +#define NXPTFA_VP2_VERSION '2' +#define NXPTFA_VP2_SUBVERSION "01" +typedef struct nxpTfaVolumeStep2 { + float attenuation; // IEEE single float + uint8_t preset[TFA98XX_PRESET_LENGTH]; + nxpTfaFilter_t filter[TFA98XX_MAX_EQ];// note: API index counts from 1..10 +} nxpTfaVolumeStep2_t; + +/* + * volumestep file + */ +#define NXPTFA_VP_VERSION '1' +#define NXPTFA_VP_SUBVERSION "00" +typedef struct nxpTfaVolumeStepFile { + nxpTfaHeader_t hdr; + uint8_t vsteps; // can also be calulated from size+type + uint8_t samplerate; // ==enum samplerates, assure 8 bits + uint8_t payload; //start of variable length contents:N times volsteps +}nxpTfaVolumeStepFile_t; +/* + * volumestep2 file + */ +typedef struct nxpTfaVolumeStep2File { + nxpTfaHeader_t hdr; + uint8_t vsteps; // can also be calulated from size+type + uint8_t samplerate; // ==enum samplerates, assure 8 bits + nxpTfaVolumeStep2_t vstep[]; //start of variable length contents:N times volsteps +}nxpTfaVolumeStep2File_t; + +/* + * volumestepMax2 file + */ +typedef struct nxpTfaVolumeStepMax2File { + nxpTfaHeader_t hdr; + uint8_t version[3]; + uint8_t NrOfVsteps; + uint8_t vstepsBin[]; +}nxpTfaVolumeStepMax2File_t; + +/* + * volumestepMax2 file + * This volumestep should ONLY be used for the use of bin2hdr! + * This can only be used to find the messagetype of the vstep (without header) + */ +typedef struct nxpTfaVolumeStepMax2_1File { + uint8_t version[3]; + uint8_t NrOfVsteps; + uint8_t vstepsBin[]; +}nxpTfaVolumeStepMax2_1File_t; + +struct nxpTfaVolumeStepRegisterInfo { + uint8_t NrOfRegisters; + uint16_t registerInfo[]; +}; + +struct nxpTfaVolumeStepMessageInfo { + uint8_t NrOfMessages; + uint8_t MessageType; + uint24_t MessageLength; + uint8_t CmdId[3]; + uint8_t ParameterData[]; +}; +/**************************old v2 *************************************************/ + +/* + * subv 00 volumestep file + */ +typedef struct nxpTfaOldHeader { + uint16_t id; + char version[2]; // "V_" : V=version, vv=subversion + char subversion[2]; // "vv" : vv=subversion + uint16_t size; // data size in bytes following CRC + uint32_t CRC; // 32-bits CRC for following data +} nxpTfaOldHeader_t; + +typedef struct nxpOldTfaFilter { + double bq[5]; + int32_t type; + double frequency; + double Q; + double gain; + uint8_t enabled; +} nxpTfaOldFilter_t ; + +typedef struct nxpTfaOldVolumeStep2 { + float attenuation; // IEEE single float + uint8_t preset[TFA98XX_PRESET_LENGTH]; + nxpTfaOldFilter_t eq[10]; +} nxpTfaOldVolumeStep2_t; + +typedef struct nxpTfaOldVolumeStepFile { + nxpTfaOldHeader_t hdr; + nxpTfaOldVolumeStep2_t step[]; +}nxpTfaOldVolumeStep2File_t; +/**************************end old v2 *************************************************/ + +/* + * speaker file header + */ +struct nxpTfaSpkHeader { + struct nxpTfaHeader hdr; + char name[8]; // speaker nick name (e.g. “dumbo”) + char vendor[16]; + char type[8]; + // dimensions (mm) + uint8_t height; + uint8_t width; + uint8_t depth; + uint16_t ohm; +}; + +/* + * speaker file + */ +#define NXPTFA_SP_VERSION '1' +#define NXPTFA_SP_SUBVERSION "00" +typedef struct nxpTfaSpeakerFile { + nxpTfaHeader_t hdr; + char name[8]; // speaker nick name (e.g. “dumbo”) + char vendor[16]; + char type[8]; + // dimensions (mm) + uint8_t height; + uint8_t width; + uint8_t depth; + uint8_t ohm_primary; + uint8_t ohm_secondary; + uint8_t data[]; //payload TFA98XX_SPEAKERPARAMETER_LENGTH +} nxpTfaSpeakerFile_t; + +#define NXPTFA_VP3_VERSION '3' +#define NXPTFA_VP3_SUBVERSION "00" + +struct nxpTfaFWVer { + uint8_t Major; + uint8_t minor; + uint8_t minor_update:6; + uint8_t Update:2; +}; + +struct nxpTfaFWMsg { + struct nxpTfaFWVer fwVersion; + struct nxpTfaMsg payload; +}; + +typedef struct nxpTfaLiveData { + char name[25]; + char addrs[25]; + int tracker; + int scalefactor; +} nxpTfaLiveData_t; + +#define NXPTFA_SP3_VERSION '3' +#define NXPTFA_SP3_SUBVERSION "00" +struct nxpTfaSpeakerFileMax2 { + nxpTfaHeader_t hdr; + char name[8]; // speaker nick name (e.g. “dumbo”) + char vendor[16]; + char type[8]; + // dimensions (mm) + uint8_t height; + uint8_t width; + uint8_t depth; + uint8_t ohm_primary; + uint8_t ohm_secondary; + struct nxpTfaFWMsg FWmsg; //payload including FW ver and Cmd ID +}; + +/* + * parameter container file + */ +/* + * descriptors + * Note 1: append new DescriptorType at the end + * Note 2: add new descriptors to dsc_name[] in tfaContUtil.c + */ +typedef enum nxpTfaDescriptorType { + dscDevice, // device list + dscProfile, // profile list + dscRegister, // register patch + dscString, // ascii, zero terminated string + dscFile, // filename + file contents + dscPatch, // patch file + dscMarker, // marker to indicate end of a list + dscMode, + dscSetInputSelect, + dscSetOutputSelect, + dscSetProgramConfig, + dscSetLagW, + dscSetGains, + dscSetvBatFactors, + dscSetSensesCal, + dscSetSensesDelay, + dscBitfield, + dscDefault, // used to reset bitfields to there default values + dscLiveData, + dscLiveDataString, + dscGroup, + dscCmd, + dscSetMBDrc, + dscFilter, + dscNoInit, + dscFeatures, + dscCfMem, // coolflux memory x,y,io + dscSetFwkUseCase, + dscSetVddpConfig, + dsc_last // trailer +} nxpTfaDescriptorType_t; + +#define TFA_BITFIELDDSCMSK 0x7fffffff +typedef struct nxpTfaDescPtr { + uint32_t offset:24; + uint32_t type:8; // (== enum nxpTfaDescriptorType, assure 8bits length) +}nxpTfaDescPtr_t; + +/* + * generic file descriptor + */ +typedef struct nxpTfaFileDsc { + nxpTfaDescPtr_t name; + uint32_t size; // file data length in bytes + uint8_t data[]; //payload +} nxpTfaFileDsc_t; + + +/* + * device descriptor list + */ +typedef struct nxpTfaDeviceList { + uint8_t length; // nr of items in the list + uint8_t bus; // bus + uint8_t dev; // device + uint8_t func; // subfunction or subdevice + uint32_t devid; // device hw fw id + nxpTfaDescPtr_t name; // device name + nxpTfaDescPtr_t list[]; // items list +} nxpTfaDeviceList_t; + +/* + * profile descriptor list + */ +typedef struct nxpTfaProfileList { + uint32_t length:8; // nr of items in the list + name + uint32_t group:8; // profile group number + uint32_t ID:16; // profile ID + nxpTfaDescPtr_t name; // profile name + nxpTfaDescPtr_t list[]; // items list (lenght-1 items) +} nxpTfaProfileList_t; +#define TFA_PROFID 0x1234 + +/* + * livedata descriptor list + */ +typedef struct nxpTfaLiveDataList { + uint32_t length:8; // nr of items in the list + uint32_t ID:24; // profile ID + nxpTfaDescPtr_t name; // livedata name + nxpTfaDescPtr_t list[]; // items list +} nxpTfaLiveDataList_t; +#define TFA_LIVEDATAID 0x5678 + +/* + * Bitfield descriptor + */ +typedef struct nxpTfaBitfield { + uint16_t value; + uint16_t field; // ==datasheet defined, 16 bits +} nxpTfaBitfield_t; + +/* + * Bitfield enumuration bits descriptor + */ +typedef struct nxpTfaBfEnum { + unsigned int len:4; // this is the actual length-1 + unsigned int pos:4; + unsigned int address:8; +} nxpTfaBfEnum_t; + +/* + * Register patch descriptor + */ +typedef struct nxpTfaRegpatch { + uint8_t address; // register address + uint16_t value; // value to write + uint16_t mask; // mask of bits to write +} nxpTfaRegpatch_t; + +/* + * Mode descriptor + */ +typedef struct nxpTfaUseCase { + int value; // mode value, maps to enum Tfa98xx_Mode +} nxpTfaMode_t; + +/* + * NoInit descriptor + */ +typedef struct nxpTfaNoInit { + uint8_t value; // noInit value +} nxpTfaNoInit_t; + +/* + * Features descriptor + */ +typedef struct nxpTfaFeatures { + uint16_t value[3]; // features value +} nxpTfaFeatures_t; + + +/* + * the container file + * - the size field is 32bits long (generic=16) + * - all char types are in ASCII + */ +#define NXPTFA_PM_VERSION '1' +#define NXPTFA_PM3_VERSION '3' +#define NXPTFA_PM_SUBVERSION '1' +typedef struct nxpTfaContainer { + char id[2]; // "XX" : XX=type + char version[2]; // "V_" : V=version, vv=subversion + char subversion[2]; // "vv" : vv=subversion + uint32_t size; // data size in bytes following CRC + uint32_t CRC; // 32-bits CRC for following data + uint16_t rev; // "extra chars for rev nr" + char customer[8]; // “name of customer” + char application[8]; // “application name” + char type[8]; // “application type name” + uint16_t ndev; // "nr of device lists" + uint16_t nprof; // "nr of profile lists" + uint16_t nliveData; // "nr of livedata lists" + nxpTfaDescPtr_t index[]; // start of item index table +} nxpTfaContainer_t; + +#pragma pack (pop) + +#endif /* TFA98XXPARAMETERS_H_ */ diff --git a/techpack/audio/asoc/codecs/tfa9874/tfa98xx_tfafieldnames.h b/techpack/audio/asoc/codecs/tfa9874/tfa98xx_tfafieldnames.h new file mode 100644 index 000000000000..3f9a437df8b9 --- /dev/null +++ b/techpack/audio/asoc/codecs/tfa9874/tfa98xx_tfafieldnames.h @@ -0,0 +1,147 @@ +/* + * Copyright 2014-2017 NXP Semiconductors + * + * 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. + */ + +typedef struct TfaBfName { + unsigned short bfEnum; + char *bfName; +} tfaBfName_t; + +typedef struct TfaIrqName { + unsigned short irqEnum; + char *irqName; +} tfaIrqName_t; + +#include "tfa1_tfafieldnames.h" +#include "tfa2_tfafieldnames_N1C.h" +/* diffs for specific devices */ +#include "tfa9887_tfafieldnames.h" +#include "tfa9890_tfafieldnames.h" +#include "tfa9891_tfafieldnames.h" +#include "tfa9872_tfafieldnames.h" +#include "tfa9912_tfafieldnames.h" +#include "tfa9896_tfafieldnames.h" +#include "tfa9874_tfafieldnames.h" +#include "tfa9894_tfafieldnames.h" + +/* missing 'common' defs break the build but unused in TFA1 context */ +#define TFA1_BF_AMPINSEL -1 +#define TFA1_BF_MANSCONF -1 +#define TFA1_BF_MANCOLD -1 +#define TFA1_BF_INTSMUTE -1 +#define TFA1_BF_CFSMR -1 +#define TFA1_BF_CFSML -1 +#define TFA1_BF_DCMCCAPI -1 +#define TFA1_BF_DCMCCSB -1 +#define TFA1_BF_USERDEF -1 +#define TFA1_BF_MANSTATE -1 +#define TFA1_BF_MANOPER -1 +#define TFA1_BF_REFCKSEL -1 +#define TFA1_BF_VOLSEC -1 +#define TFA1_BF_FRACTDEL -1 +#define TFA1_BF_ACKDMG -1 +#define TFA1_BF_SSRIGHTE -1 +#define TFA1_BF_SSLEFTE -1 +#define TFA1_BF_R25CL -1 +#define TFA1_BF_R25CR -1 +#define TFA1_BF_SWPROFIL 0x8045 /*!< profile save */ +#define TFA1_BF_SWVSTEP 0x80a5 /*!< vstep save */ + +/* missing 'common' defs break the build */ +#define TFA2_BF_CFSM -1 + + +/* MTP access uses registers + * defs are derived from corresponding bitfield names as used in the BF macros + */ +#define MTPKEY2 MTPK /* unlock key2 MTPK */ +#define MTP0 MTPOTC /* MTP data */ +#define MTP_CONTROL CIMTP /* copy i2c to mtp */ + +/* interrupt enable register uses HW name in TFA2 */ +#define TFA2_BF_INTENVDDS TFA2_BF_IEVDDS + + +/* TFA9891 specific bit field names */ +#define TFA1_BF_SAAMGAIN 0x2202 +#define TFA2_BF_SAAMGAIN -1 + +/* TFA9872 specific bit field names */ +#define TFA2_BF_IELP0 TFA9872_BF_IELP0 +#define TFA2_BF_ISTLP0 TFA9872_BF_ISTLP0 +#define TFA2_BF_IPOLP0 TFA9872_BF_IPOLP0 +#define TFA2_BF_IELP1 TFA9872_BF_IELP1 +#define TFA2_BF_ISTLP1 TFA9872_BF_ISTLP1 +#define TFA2_BF_IPOLP1 TFA9872_BF_IPOLP1 +#define TFA2_BF_LP0 TFA9872_BF_LP0 +#define TFA2_BF_LP1 TFA9872_BF_LP1 +#define TFA2_BF_R25C TFA9872_BF_R25C +#define TFA2_BF_SAMMODE TFA9872_BF_SAMMODE + +/* interrupt bit field names of TFA2 and TFA1 do not match */ +#define TFA1_BF_IEACS TFA1_BF_INTENACS +#define TFA1_BF_IPOACS TFA1_BF_INTPOLACS +#define TFA1_BF_ISTACS TFA1_BF_INTOACS +#define TFA1_BF_ISTVDDS TFA1_BF_INTOVDDS +#define TFA1_BF_ICLVDDS TFA1_BF_INTIVDDS +#define TFA1_BF_IPOVDDS TFA1_BF_INTPOLVDDS +#define TFA1_BF_IENOCLK TFA1_BF_INTENNOCLK +#define TFA1_BF_ISTNOCLK TFA1_BF_INTONOCLK +#define TFA1_BF_IPONOCLK TFA1_BF_INTPOLNOCLK + +/* interrupt bit fields not available on TFA1 */ +#define TFA1_BF_IECLKOOR -1 +#define TFA1_BF_ISTCLKOOR -1 +#define TFA1_BF_IEMWSRC -1 +#define TFA1_BF_ISTMWSRC -1 +#define TFA1_BF_IPOMWSRC -1 +#define TFA1_BF_IEMWSMU -1 +#define TFA1_BF_ISTMWSMU -1 +#define TFA1_BF_IPOMWSMU -1 +#define TFA1_BF_IEMWCFC -1 +#define TFA1_BF_ISTMWCFC -1 +#define TFA1_BF_IPOMWCFC -1 +#define TFA1_BF_CLKOOR -1 +#define TFA1_BF_MANWAIT1 -1 +#define TFA1_BF_MANWAIT2 -1 +#define TFA1_BF_MANMUTE -1 +#define TFA1_BF_IPCLKOOR -1 +#define TFA1_BF_ICLCLKOOR -1 +#define TFA1_BF_IPOSWS -1 +#define TFA1_BF_IESWS -1 +#define TFA1_BF_ISTSWS -1 +#define TFA1_BF_IESPKS -1 +#define TFA1_BF_ISTSPKS -1 +#define TFA1_BF_IPOSPKS -1 +#define TFA1_BF_IECLKS -1 +#define TFA1_BF_ISTCLKS -1 +#define TFA1_BF_IPOCLKS -1 +#define TFA1_BF_IEAMPS -1 +#define TFA1_BF_ISTAMPS -1 +#define TFA1_BF_IPOAMPS -1 +#define TFA1_BF_IELP0 -1 +#define TFA1_BF_ISTLP0 -1 +#define TFA1_BF_IPOLP0 -1 +#define TFA1_BF_IELP1 -1 +#define TFA1_BF_ISTLP1 -1 +#define TFA1_BF_IPOLP1 -1 +#define TFA1_BF_LP0 -1 +#define TFA1_BF_LP1 -1 +#define TFA1_BF_R25C -1 +#define TFA1_BF_SAMMODE -1 + +/* TDM STATUS fields not available on TFA1 */ +#define TFA1_BF_TDMLUTER -1 +#define TFA1_BF_TDMERR -1 diff --git a/techpack/audio/asoc/codecs/tfa9874/tfa9912_device_genregs.h b/techpack/audio/asoc/codecs/tfa9874/tfa9912_device_genregs.h new file mode 100644 index 000000000000..6a4b7303e64e --- /dev/null +++ b/techpack/audio/asoc/codecs/tfa9874/tfa9912_device_genregs.h @@ -0,0 +1,255 @@ +/** Filename: tfa9912_device_genregs.h + * This file was generated automatically on 04/19/17 at 12:26:46. + * Source file: TFA9912_N1A_I2C_regmap_V1.39.xlsx + */ + +#ifndef _TFA9912_DEVICE_GENREGS_H +#define _TFA9912_DEVICE_GENREGS_H + + +#define TFA99XX_SYS_CONTROL0 0x00 +#define TFA99XX_SYS_CONTROL1 0x01 +#define TFA99XX_SYS_CONTROL2 0x02 +#define TFA99XX_DEVICE_REVISION 0x03 +#define TFA99XX_CLOCK_CONTROL 0x04 +#define TFA99XX_CLOCK_GATING_CONTROL 0x05 +#define TFA99XX_HW_PATH_CFG 0x06 +#define TFA99XX_CLKCHK_TH 0x07 +#define TFA99XX_AMP_CTRL 0x08 +#define TFA99XX_SIDE_TONE_CONFIG 0x0d +#define TFA99XX_CTRL_DIGTOANA_REG 0x0e +#define TFA99XX_STATUS_FLAGS0 0x10 +#define TFA99XX_STATUS_FLAGS1 0x11 +#define TFA99XX_STATUS_FLAGS3 0x13 +#define TFA99XX_STATUS_FLAGS4 0x14 +#define TFA99XX_BATTERY_VOLTAGE 0x15 +#define TFA99XX_TEMPERATURE 0x16 +#define TFA99XX_VDDP_VOLTAGE 0x17 +#define TFA99XX_TDM_CONFIG0 0x20 +#define TFA99XX_TDM_CONFIG1 0x21 +#define TFA99XX_TDM_CONFIG2 0x22 +#define TFA99XX_TDM_CONFIG3 0x23 +#define TFA99XX_TDM_CONFIG4 0x24 +#define TFA99XX_TDM_CONFIG5 0x25 +#define TFA99XX_TDM_CONFIG6 0x26 +#define TFA99XX_TDM_CONFIG7 0x27 +#define TFA99XX_TDM_CONFIG8 0x28 +#define TFA99XX_TDM_CONFIG9 0x29 +#define TFA99XX_PDM_CONFIG0 0x31 +#define TFA99XX_PDM_CONFIG1 0x32 +#define TFA99XX_INTERRUPT_OUT_REG1 0x40 +#define TFA99XX_INTERRUPT_OUT_REG2 0x41 +#define TFA99XX_INTERRUPT_OUT_REG3 0x42 +#define TFA99XX_INTERRUPT_IN_REG1 0x44 +#define TFA99XX_INTERRUPT_IN_REG2 0x45 +#define TFA99XX_INTERRUPT_IN_REG3 0x46 +#define TFA99XX_INTERRUPT_ENABLE_REG1 0x48 +#define TFA99XX_INTERRUPT_ENABLE_REG2 0x49 +#define TFA99XX_INTERRUPT_ENABLE_REG3 0x4a +#define TFA99XX_STATUS_POLARITY_REG1 0x4c +#define TFA99XX_STATUS_POLARITY_REG2 0x4d +#define TFA99XX_STATUS_POLARITY_REG3 0x4e +#define TFA99XX_BAT_PROT_CONFIG 0x50 +#define TFA99XX_AUDIO_CONTROL 0x51 +#define TFA99XX_AMPLIFIER_CONFIG 0x52 +#define TFA99XX_KEY1_PROTECTED_AMPLIFIER_CONTROL0 0x53 +#define TFA99XX_KEY1_PROTECTED_AMPLIFIER_CONTROL1 0x54 +#define TFA99XX_KEY1_PROTECTED_AMPLIFIER_CONTROL2 0x55 +#define TFA99XX_KEY1_PROTECTED_AMPLIFIER_CONTROL4 0x57 +#define TFA99XX_KEY1_PROTECTED_PWM_CONFIG 0x58 +#define TFA99XX_CF_TAP_STATUS_0 0x5c +#define TFA99XX_CF_TAP_STATUS_1 0x5d +#define TFA99XX_TAP_CONTROL 0x5f +#define TFA99XX_PGA_CONTROL0 0x60 +#define TFA99XX_GAIN_ATT 0x61 +#define TFA99XX_LOW_NOISE_GAIN1 0x62 +#define TFA99XX_LOW_NOISE_GAIN2 0x63 +#define TFA99XX_MODE1_DETECTOR1 0x64 +#define TFA99XX_MODE1_DETECTOR2 0x65 +#define TFA99XX_BST_PFM_CTRL 0x66 +#define TFA99XX_LOW_POWER_CTRL 0x67 +#define TFA99XX_TDM_SOURCE_CTRL 0x68 +#define TFA99XX_SAM_CTRL 0x69 +#define TFA99XX_RST_MIN_VBAT_CTRL 0x6a +#define TFA99XX_SYS_CONTROL3 0x6b +#define TFA99XX_STATUS_FLAGS5 0x6e +#define TFA99XX_DCDC_CONTROL0 0x70 +#define TFA99XX_KEY1_PROTECTED_DCDC_CONTROL3 0x73 +#define TFA99XX_DCDC_CONTROL4 0x74 +#define TFA99XX_DCDC_CONTROL5 0x75 +#define TFA99XX_DCDC_CONTROL6 0x76 +#define TFA99XX_KEY2_PROTECTED_DCDC_CONTROL7 0x77 +#define TFA99XX_KEY2_PROTECTED_CURSENSE_CONFIG0 0x80 +#define TFA99XX_KEY2_PROTECTED_CURSENSE_CONFIG2 0x82 +#define TFA99XX_KEY2_PROTECTED_CURSENSE_CONFIG3 0x83 +#define TFA99XX_KEY2_PROTECTED_CURSENSE_CONFIG4 0x84 +#define TFA99XX_KEY2_PROTECTED_CURSENSE_CONFIG5 0x85 +#define TFA99XX_KEY2_PROTECTED_CURSENSE_CONFIG7 0x87 +#define TFA99XX_KEY2_PROTECTED_VOLSENSE_CONFIG 0x88 +#define TFA99XX_CURSENSE_CONFIG 0x89 +#define TFA99XX_CF_CONTROLS 0x90 +#define TFA99XX_CF_MAD 0x91 +#define TFA99XX_CF_MEM 0x92 +#define TFA99XX_CF_STATUS 0x93 +#define TFA99XX_MTPKEY1_REG 0xa0 +#define TFA99XX_MTPKEY2_REG 0xa1 +#define TFA99XX_MTP_STATUS 0xa2 +#define TFA99XX_KEY_PROTECTED_MTP_CONTROL 0xa3 +#define TFA99XX_KEY1_PROTECTED_FAIM_CONTROL 0xa4 +#define TFA99XX_MTP_DATA_OUT_MSB 0xa5 +#define TFA99XX_MTP_DATA_OUT_LSB 0xa6 +#define TFA99XX_KEY1_PROTECTED_PROTECTION_CONFIG 0xb0 +#define TFA99XX_TEMP_SENSOR_CONFIG 0xb1 +#define TFA99XX_KEY1_PROTECTED_DIRECT_CONTROL0 0xc0 +#define TFA99XX_KEY1_PROTECTED_DIRECT_CONTROL1 0xc1 +#define TFA99XX_KEY1_PROTECTED_TEST_CONFIG0 0xc3 +#define TFA99XX_KEY1_PROTECTED_TEST_CONFIG1 0xc4 +#define TFA99XX_KEY1_PROTECTED_TEST_CONFIG2 0xc5 +#define TFA99XX_KEY1_PROTECTED_TEST_CONFIG3 0xc6 +#define TFA99XX_KEY1_PROTECTED_DIGIMUX_CONTROL1 0xc8 +#define TFA99XX_KEY1_PROTECTED_ANAMUX_CONTROL0 0xca +#define TFA99XX_KEY1_PROTECTED_ANAMUX_CONTROL1 0xcb +#define TFA99XX_KEY1_PROTECTED_PLL_TEST0 0xcd +#define TFA99XX_KEY1_PROTECTED_PLL_TEST3 0xd0 +#define TFA99XX_KEY1_PROTECTED_TSIG_CONTROL1 0xd2 +#define TFA99XX_KEY1_PROTECTED_ADC10_CONTROL 0xd3 +#define TFA99XX_KEY1_PROTECTED_ADC10_DATA 0xd4 +#define TFA99XX_KEY2_PROTECTED_CTRL_DIGTOANA 0xd5 +#define TFA99XX_KEY1_PROTECTED_CLKDIV_CONTROL 0xd6 +#define TFA99XX_KEY1_PROTECTED_IO_CONFIG2 0xd7 +#define TFA99XX_KEY1_PROTECTED_TEST_CTRL1 0xd8 +#define TFA99XX_KEY1_PROTECTED_MODE_OVERRULE 0xd9 +#define TFA99XX_KEY1_PROTECTED_FRO8_CALIB_CTRL 0xed +#define TFA99XX_SOFTWARE_PROFILE 0xee +#define TFA99XX_SOFTWARE_VSTEP 0xef +#define TFA99XX_KEY2_PROTECTED_MTP0 0xf0 +#define TFA99XX_KEY1_PROTECTED_MTP2 0xf2 +#define TFA99XX_KEY2_PROTECTED_MTP4 0xf4 +#define TFA99XX_KEY1_PROTECTED_MTP6 0xf6 +#define TFA99XX_KEY1_PROTECTED_MTP7 0xf7 +#define TFA99XX_KEY1_PROTECTED_MTP9 0xf9 +#define TFA99XX_KEY1_PROTECTED_MTPF 0xff +#define TFA99XX_SYS_CONTROL0_POR +#define TFA99XX_SYS_CONTROL1_POR +#define TFA99XX_SYS_CONTROL2_POR +#define TFA99XX_DEVICE_REVISION_POR +#define TFA99XX_CLOCK_CONTROL_POR +#define TFA99XX_CLOCK_GATING_CONTROL_POR +#define TFA99XX_HW_PATH_CFG_POR +#define TFA99XX_CLKCHK_TH_POR +#define TFA99XX_AMP_CTRL_POR +#define TFA99XX_SIDE_TONE_CONFIG_POR +#define TFA99XX_CTRL_DIGTOANA_REG_POR +#define TFA99XX_STATUS_FLAGS0_POR +#define TFA99XX_STATUS_FLAGS1_POR +#define TFA99XX_STATUS_FLAGS3_POR +#define TFA99XX_STATUS_FLAGS4_POR +#define TFA99XX_BATTERY_VOLTAGE_POR +#define TFA99XX_TEMPERATURE_POR +#define TFA99XX_VDDP_VOLTAGE_POR +#define TFA99XX_TDM_CONFIG0_POR +#define TFA99XX_TDM_CONFIG1_POR +#define TFA99XX_TDM_CONFIG2_POR +#define TFA99XX_TDM_CONFIG3_POR +#define TFA99XX_TDM_CONFIG4_POR +#define TFA99XX_TDM_CONFIG5_POR +#define TFA99XX_TDM_CONFIG6_POR +#define TFA99XX_TDM_CONFIG7_POR +#define TFA99XX_TDM_CONFIG8_POR +#define TFA99XX_TDM_CONFIG9_POR +#define TFA99XX_PDM_CONFIG0_POR +#define TFA99XX_PDM_CONFIG1_POR +#define TFA99XX_INTERRUPT_OUT_REG1_POR +#define TFA99XX_INTERRUPT_OUT_REG2_POR +#define TFA99XX_INTERRUPT_OUT_REG3_POR +#define TFA99XX_INTERRUPT_IN_REG1_POR +#define TFA99XX_INTERRUPT_IN_REG2_POR +#define TFA99XX_INTERRUPT_IN_REG3_POR +#define TFA99XX_INTERRUPT_ENABLE_REG1_POR +#define TFA99XX_INTERRUPT_ENABLE_REG2_POR +#define TFA99XX_INTERRUPT_ENABLE_REG3_POR +#define TFA99XX_STATUS_POLARITY_REG1_POR +#define TFA99XX_STATUS_POLARITY_REG2_POR +#define TFA99XX_STATUS_POLARITY_REG3_POR +#define TFA99XX_BAT_PROT_CONFIG_POR +#define TFA99XX_AUDIO_CONTROL_POR +#define TFA99XX_AMPLIFIER_CONFIG_POR +#define TFA99XX_KEY1_PROTECTED_AMPLIFIER_CONTROL0_POR +#define TFA99XX_KEY1_PROTECTED_AMPLIFIER_CONTROL1_POR +#define TFA99XX_KEY1_PROTECTED_AMPLIFIER_CONTROL2_POR +#define TFA99XX_KEY1_PROTECTED_AMPLIFIER_CONTROL4_POR +#define TFA99XX_KEY1_PROTECTED_PWM_CONFIG_POR +#define TFA99XX_CF_TAP_STATUS_0_POR +#define TFA99XX_CF_TAP_STATUS_1_POR +#define TFA99XX_TAP_CONTROL_POR +#define TFA99XX_PGA_CONTROL0_POR +#define TFA99XX_GAIN_ATT_POR +#define TFA99XX_LOW_NOISE_GAIN1_POR +#define TFA99XX_LOW_NOISE_GAIN2_POR +#define TFA99XX_MODE1_DETECTOR1_POR +#define TFA99XX_MODE1_DETECTOR2_POR +#define TFA99XX_BST_PFM_CTRL_POR +#define TFA99XX_LOW_POWER_CTRL_POR +#define TFA99XX_TDM_SOURCE_CTRL_POR +#define TFA99XX_SAM_CTRL_POR +#define TFA99XX_RST_MIN_VBAT_CTRL_POR +#define TFA99XX_SYS_CONTROL3_POR +#define TFA99XX_STATUS_FLAGS5_POR +#define TFA99XX_DCDC_CONTROL0_POR +#define TFA99XX_KEY1_PROTECTED_DCDC_CONTROL3_POR +#define TFA99XX_DCDC_CONTROL4_POR +#define TFA99XX_DCDC_CONTROL5_POR +#define TFA99XX_DCDC_CONTROL6_POR +#define TFA99XX_KEY2_PROTECTED_DCDC_CONTROL7_POR +#define TFA99XX_KEY2_PROTECTED_CURSENSE_CONFIG0_POR +#define TFA99XX_KEY2_PROTECTED_CURSENSE_CONFIG2_POR +#define TFA99XX_KEY2_PROTECTED_CURSENSE_CONFIG3_POR +#define TFA99XX_KEY2_PROTECTED_CURSENSE_CONFIG4_POR +#define TFA99XX_KEY2_PROTECTED_CURSENSE_CONFIG5_POR +#define TFA99XX_KEY2_PROTECTED_CURSENSE_CONFIG7_POR +#define TFA99XX_KEY2_PROTECTED_VOLSENSE_CONFIG_POR +#define TFA99XX_CURSENSE_CONFIG_POR +#define TFA99XX_CF_CONTROLS_POR +#define TFA99XX_CF_MAD_POR +#define TFA99XX_CF_MEM_POR +#define TFA99XX_CF_STATUS_POR +#define TFA99XX_MTPKEY1_REG_POR +#define TFA99XX_MTPKEY2_REG_POR +#define TFA99XX_MTP_STATUS_POR +#define TFA99XX_KEY_PROTECTED_MTP_CONTROL_POR +#define TFA99XX_KEY1_PROTECTED_FAIM_CONTROL_POR +#define TFA99XX_MTP_DATA_OUT_MSB_POR +#define TFA99XX_MTP_DATA_OUT_LSB_POR +#define TFA99XX_KEY1_PROTECTED_PROTECTION_CONFIG_POR +#define TFA99XX_TEMP_SENSOR_CONFIG_POR +#define TFA99XX_KEY1_PROTECTED_DIRECT_CONTROL0_POR +#define TFA99XX_KEY1_PROTECTED_DIRECT_CONTROL1_POR +#define TFA99XX_KEY1_PROTECTED_TEST_CONFIG0_POR +#define TFA99XX_KEY1_PROTECTED_TEST_CONFIG1_POR +#define TFA99XX_KEY1_PROTECTED_TEST_CONFIG2_POR +#define TFA99XX_KEY1_PROTECTED_TEST_CONFIG3_POR +#define TFA99XX_KEY1_PROTECTED_DIGIMUX_CONTROL1_POR +#define TFA99XX_KEY1_PROTECTED_ANAMUX_CONTROL0_POR +#define TFA99XX_KEY1_PROTECTED_ANAMUX_CONTROL1_POR +#define TFA99XX_KEY1_PROTECTED_PLL_TEST0_POR +#define TFA99XX_KEY1_PROTECTED_PLL_TEST3_POR +#define TFA99XX_KEY1_PROTECTED_TSIG_CONTROL1_POR +#define TFA99XX_KEY1_PROTECTED_ADC10_CONTROL_POR +#define TFA99XX_KEY1_PROTECTED_ADC10_DATA_POR +#define TFA99XX_KEY2_PROTECTED_CTRL_DIGTOANA_POR +#define TFA99XX_KEY1_PROTECTED_CLKDIV_CONTROL_POR +#define TFA99XX_KEY1_PROTECTED_IO_CONFIG2_POR +#define TFA99XX_KEY1_PROTECTED_TEST_CTRL1_POR +#define TFA99XX_KEY1_PROTECTED_MODE_OVERRULE_POR +#define TFA99XX_KEY1_PROTECTED_FRO8_CALIB_CTRL_POR +#define TFA99XX_SOFTWARE_PROFILE_POR +#define TFA99XX_SOFTWARE_VSTEP_POR +#define TFA99XX_KEY2_PROTECTED_MTP0_POR +#define TFA99XX_KEY1_PROTECTED_MTP2_POR +#define TFA99XX_KEY2_PROTECTED_MTP4_POR +#define TFA99XX_KEY1_PROTECTED_MTP6_POR +#define TFA99XX_KEY1_PROTECTED_MTP7_POR +#define TFA99XX_KEY1_PROTECTED_MTP9_POR +#define TFA99XX_KEY1_PROTECTED_MTPF_POR + +#endif /* _TFA9912_DEVICE_GENREGS_H */ diff --git a/techpack/audio/asoc/codecs/tfa9874/tfa9912_tfafieldnames.h b/techpack/audio/asoc/codecs/tfa9874/tfa9912_tfafieldnames.h new file mode 100644 index 000000000000..bc4da8ab048b --- /dev/null +++ b/techpack/audio/asoc/codecs/tfa9874/tfa9912_tfafieldnames.h @@ -0,0 +1,1764 @@ +/** Filename: tfa9912_tfafieldnames.h + * This file was generated automatically on 06/14/17 at 18:04:05. + * Source file: TFA9912_N1A_I2C_regmap_V1.41.xlsx + */ + +#ifndef _TFA9912_TFAFIELDNAMES_H +#define _TFA9912_TFAFIELDNAMES_H + + +#define TFA9912_I2CVERSION 1.41 + +typedef enum nxpTfa9912BfEnumList { + TFA9912_BF_PWDN = 0x0000, /*!< Powerdown selection */ + TFA9912_BF_I2CR = 0x0010, /*!< I2C Reset - Auto clear */ + TFA9912_BF_CFE = 0x0020, /*!< Enable CoolFlux */ + TFA9912_BF_AMPE = 0x0030, /*!< Enables the Amplifier */ + TFA9912_BF_DCA = 0x0040, /*!< Activate DC-to-DC converter */ + TFA9912_BF_SBSL = 0x0050, /*!< Coolflux configured */ + TFA9912_BF_AMPC = 0x0060, /*!< CoolFlux controls amplifier */ + TFA9912_BF_INTP = 0x0071, /*!< Interrupt config */ + TFA9912_BF_FSSSEL= 0x0090, /*!< Audio sample reference */ + TFA9912_BF_BYPOCP= 0x00b0, /*!< Bypass OCP */ + TFA9912_BF_TSTOCP= 0x00c0, /*!< OCP testing control */ + TFA9912_BF_AMPINSEL= 0x0101, /*!< Amplifier input selection */ + TFA9912_BF_MANSCONF= 0x0120, /*!< I2C configured */ + TFA9912_BF_MANCOLD= 0x0130, /*!< Execute cold start */ + TFA9912_BF_MANAOOSC= 0x0140, /*!< Internal osc off at PWDN */ + TFA9912_BF_MANROBOD= 0x0150, /*!< Reaction on BOD */ + TFA9912_BF_BODE = 0x0160, /*!< BOD Enable */ + TFA9912_BF_BODHYS= 0x0170, /*!< BOD Hysteresis */ + TFA9912_BF_BODFILT= 0x0181, /*!< BOD filter */ + TFA9912_BF_BODTHLVL= 0x01a1, /*!< BOD threshold */ + TFA9912_BF_MUTETO= 0x01d0, /*!< Time out SB mute sequence */ + TFA9912_BF_RCVNS = 0x01e0, /*!< Noise shaper selection */ + TFA9912_BF_MANWDE= 0x01f0, /*!< Watchdog enable */ + TFA9912_BF_AUDFS = 0x0203, /*!< Sample rate (fs) */ + TFA9912_BF_INPLEV= 0x0240, /*!< TDM output attenuation */ + TFA9912_BF_FRACTDEL= 0x0255, /*!< V/I Fractional delay */ + TFA9912_BF_BYPHVBF= 0x02b0, /*!< Bypass HVBAT filter */ + TFA9912_BF_TDMC = 0x02c0, /*!< TDM Compatibility with TFA9872 */ + TFA9912_BF_ENBLADC10= 0x02e0, /*!< ADC10 Enable - I2C direct mode */ + TFA9912_BF_REV = 0x030f, /*!< Revision info */ + TFA9912_BF_REFCKEXT= 0x0401, /*!< PLL external ref clock */ + TFA9912_BF_REFCKSEL= 0x0420, /*!< PLL internal ref clock */ + TFA9912_BF_ENCFCKSEL= 0x0430, /*!< Coolflux DSP clock scaling, low power mode */ + TFA9912_BF_CFCKSEL= 0x0441, /*!< Coolflux DSP clock scaler selection for low power mode */ + TFA9912_BF_TDMINFSEL= 0x0460, /*!< TDM clock selection */ + TFA9912_BF_DISBLAUTOCLKSEL= 0x0470, /*!< Disable Automatic dsp clock source selection */ + TFA9912_BF_SELCLKSRC= 0x0480, /*!< I2C selection of DSP clock when auto select is disabled */ + TFA9912_BF_SELTIMSRC= 0x0490, /*!< I2C selection of Watchdog and Timer clock */ + TFA9912_BF_SSLEFTE= 0x0500, /*!< */ + TFA9912_BF_SPKSSEN= 0x0510, /*!< Enable speaker path */ + TFA9912_BF_VSLEFTE= 0x0520, /*!< */ + TFA9912_BF_VSRIGHTE= 0x0530, /*!< Voltage sense */ + TFA9912_BF_CSLEFTE= 0x0540, /*!< */ + TFA9912_BF_CSRIGHTE= 0x0550, /*!< Current sense */ + TFA9912_BF_SSPDME= 0x0560, /*!< Sub-system PDM */ + TFA9912_BF_PGALE = 0x0570, /*!< Enable PGA chop clock for left channel */ + TFA9912_BF_PGARE = 0x0580, /*!< Enable PGA chop clock */ + TFA9912_BF_SSTDME= 0x0590, /*!< Sub-system TDM */ + TFA9912_BF_SSPBSTE= 0x05a0, /*!< Sub-system boost */ + TFA9912_BF_SSADCE= 0x05b0, /*!< Sub-system ADC */ + TFA9912_BF_SSFAIME= 0x05c0, /*!< Sub-system FAIM */ + TFA9912_BF_SSCFTIME= 0x05d0, /*!< CF Sub-system timer */ + TFA9912_BF_SSCFWDTE= 0x05e0, /*!< CF Sub-system WDT */ + TFA9912_BF_FAIMVBGOVRRL= 0x05f0, /*!< Over rule of vbg for FaIM access */ + TFA9912_BF_SAMSPKSEL= 0x0600, /*!< Input selection for TAP/SAM */ + TFA9912_BF_PDM2IISEN= 0x0610, /*!< PDM2IIS Bridge enable */ + TFA9912_BF_TAPRSTBYPASS= 0x0620, /*!< Tap decimator reset bypass - Bypass the decimator reset from tapdec */ + TFA9912_BF_CARDECISEL0= 0x0631, /*!< Cardec input 0 sel */ + TFA9912_BF_CARDECISEL1= 0x0651, /*!< Cardec input sel */ + TFA9912_BF_TAPDECSEL= 0x0670, /*!< Select TAP/Cardec for TAP */ + TFA9912_BF_COMPCOUNT= 0x0680, /*!< Comparator o/p filter selection */ + TFA9912_BF_STARTUPMODE= 0x0691, /*!< Startup Mode Selection */ + TFA9912_BF_AUTOTAP= 0x06b0, /*!< Enable auto tap switching */ + TFA9912_BF_COMPINITIME= 0x06c1, /*!< Comparator initialization time to be used in Tap Machine */ + TFA9912_BF_ANAPINITIME= 0x06e1, /*!< Analog initialization time to be used in Tap Machine */ + TFA9912_BF_CCHKTH= 0x0707, /*!< Clock check Higher Threshold */ + TFA9912_BF_CCHKTL= 0x0787, /*!< Clock check Higher Threshold */ + TFA9912_BF_AMPOCRT= 0x0802, /*!< Amplifier on-off criteria for shutdown */ + TFA9912_BF_AMPTCRR= 0x0832, /*!< Amplifier on-off criteria for tap mode entry */ + TFA9912_BF_STGS = 0x0d00, /*!< PDM side tone gain selector */ + TFA9912_BF_STGAIN= 0x0d18, /*!< Side tone gain */ + TFA9912_BF_STSMUTE= 0x0da0, /*!< Side tone soft mute */ + TFA9912_BF_ST1C = 0x0db0, /*!< side tone one s complement */ + TFA9912_BF_CMFBEL= 0x0e80, /*!< CMFB enable left */ + TFA9912_BF_VDDS = 0x1000, /*!< POR */ + TFA9912_BF_PLLS = 0x1010, /*!< PLL lock */ + TFA9912_BF_OTDS = 0x1020, /*!< OTP alarm */ + TFA9912_BF_OVDS = 0x1030, /*!< OVP alarm */ + TFA9912_BF_UVDS = 0x1040, /*!< UVP alarm */ + TFA9912_BF_CLKS = 0x1050, /*!< Clocks stable */ + TFA9912_BF_MTPB = 0x1060, /*!< MTP busy */ + TFA9912_BF_NOCLK = 0x1070, /*!< Lost clock */ + TFA9912_BF_ACS = 0x1090, /*!< Cold Start */ + TFA9912_BF_SWS = 0x10a0, /*!< Amplifier engage */ + TFA9912_BF_WDS = 0x10b0, /*!< Watchdog */ + TFA9912_BF_AMPS = 0x10c0, /*!< Amplifier enable */ + TFA9912_BF_AREFS = 0x10d0, /*!< References enable */ + TFA9912_BF_ADCCR = 0x10e0, /*!< Control ADC */ + TFA9912_BF_BODNOK= 0x10f0, /*!< BOD */ + TFA9912_BF_DCIL = 0x1100, /*!< DCDC current limiting */ + TFA9912_BF_DCDCA = 0x1110, /*!< DCDC active */ + TFA9912_BF_DCOCPOK= 0x1120, /*!< DCDC OCP nmos */ + TFA9912_BF_DCPEAKCUR= 0x1130, /*!< Indicates current is max in DC-to-DC converter */ + TFA9912_BF_DCHVBAT= 0x1140, /*!< DCDC level 1x */ + TFA9912_BF_DCH114= 0x1150, /*!< DCDC level 1.14x */ + TFA9912_BF_DCH107= 0x1160, /*!< DCDC level 1.07x */ + TFA9912_BF_STMUTEB= 0x1170, /*!< side tone (un)mute busy */ + TFA9912_BF_STMUTE= 0x1180, /*!< side tone mute state */ + TFA9912_BF_TDMLUTER= 0x1190, /*!< TDM LUT error */ + TFA9912_BF_TDMSTAT= 0x11a2, /*!< TDM status bits */ + TFA9912_BF_TDMERR= 0x11d0, /*!< TDM error */ + TFA9912_BF_HAPTIC= 0x11e0, /*!< Status haptic driver */ + TFA9912_BF_OCPOAP= 0x1300, /*!< OCPOK pmos A */ + TFA9912_BF_OCPOAN= 0x1310, /*!< OCPOK nmos A */ + TFA9912_BF_OCPOBP= 0x1320, /*!< OCPOK pmos B */ + TFA9912_BF_OCPOBN= 0x1330, /*!< OCPOK nmos B */ + TFA9912_BF_CLIPAH= 0x1340, /*!< Clipping A to Vddp */ + TFA9912_BF_CLIPAL= 0x1350, /*!< Clipping A to gnd */ + TFA9912_BF_CLIPBH= 0x1360, /*!< Clipping B to Vddp */ + TFA9912_BF_CLIPBL= 0x1370, /*!< Clipping B to gnd */ + TFA9912_BF_OCDS = 0x1380, /*!< OCP amplifier */ + TFA9912_BF_CLIPS = 0x1390, /*!< Amplifier clipping */ + TFA9912_BF_TCMPTRG= 0x13a0, /*!< Status Tap comparator triggered */ + TFA9912_BF_TAPDET= 0x13b0, /*!< Status Tap detected */ + TFA9912_BF_MANWAIT1= 0x13c0, /*!< Wait HW I2C settings */ + TFA9912_BF_MANWAIT2= 0x13d0, /*!< Wait CF config */ + TFA9912_BF_MANMUTE= 0x13e0, /*!< Audio mute sequence */ + TFA9912_BF_MANOPER= 0x13f0, /*!< Operating state */ + TFA9912_BF_SPKSL = 0x1400, /*!< Left speaker status */ + TFA9912_BF_SPKS = 0x1410, /*!< Speaker status */ + TFA9912_BF_CLKOOR= 0x1420, /*!< External clock status */ + TFA9912_BF_MANSTATE= 0x1433, /*!< Device manager status */ + TFA9912_BF_DCMODE= 0x1471, /*!< DCDC mode status bits */ + TFA9912_BF_DSPCLKSRC= 0x1490, /*!< DSP clock source selected by manager */ + TFA9912_BF_STARTUPMODSTAT= 0x14a1, /*!< Startup Mode Selected by Manager(Read Only) */ + TFA9912_BF_TSPMSTATE= 0x14c3, /*!< Tap Machine State */ + TFA9912_BF_BATS = 0x1509, /*!< Battery voltage (V) */ + TFA9912_BF_TEMPS = 0x1608, /*!< IC Temperature (C) */ + TFA9912_BF_VDDPS = 0x1709, /*!< IC VDDP voltage ( 1023*VDDP/13 V) */ + TFA9912_BF_DCILCF= 0x17a0, /*!< DCDC current limiting for DSP */ + TFA9912_BF_TDMUC = 0x2000, /*!< Mode setting */ + TFA9912_BF_DIO4SEL= 0x2011, /*!< DIO4 Input selection */ + TFA9912_BF_TDME = 0x2040, /*!< Enable TDM interface */ + TFA9912_BF_TDMMODE= 0x2050, /*!< Slave/master */ + TFA9912_BF_TDMCLINV= 0x2060, /*!< Reception data to BCK clock */ + TFA9912_BF_TDMFSLN= 0x2073, /*!< FS length */ + TFA9912_BF_TDMFSPOL= 0x20b0, /*!< FS polarity */ + TFA9912_BF_TDMNBCK= 0x20c3, /*!< N-BCK's in FS */ + TFA9912_BF_TDMSLOTS= 0x2103, /*!< N-slots in Frame */ + TFA9912_BF_TDMSLLN= 0x2144, /*!< N-bits in slot */ + TFA9912_BF_TDMBRMG= 0x2194, /*!< N-bits remaining */ + TFA9912_BF_TDMDEL= 0x21e0, /*!< data delay to FS */ + TFA9912_BF_TDMADJ= 0x21f0, /*!< data adjustment */ + TFA9912_BF_TDMOOMP= 0x2201, /*!< Received audio compression */ + TFA9912_BF_TDMSSIZE= 0x2224, /*!< Sample size per slot */ + TFA9912_BF_TDMTXDFO= 0x2271, /*!< Format unused bits in a slot */ + TFA9912_BF_TDMTXUS0= 0x2291, /*!< Format unused slots GAINIO */ + TFA9912_BF_TDMTXUS1= 0x22b1, /*!< Format unused slots DIO1 */ + TFA9912_BF_TDMTXUS2= 0x22d1, /*!< Format unused slots DIO2 */ + TFA9912_BF_TDMGIE= 0x2300, /*!< Control gain (channel in 0) */ + TFA9912_BF_TDMDCE= 0x2310, /*!< Control audio left (channel in 1 ) */ + TFA9912_BF_TDMSPKE= 0x2320, /*!< Control audio right (channel in 2 ) */ + TFA9912_BF_TDMCSE= 0x2330, /*!< Current sense */ + TFA9912_BF_TDMVSE= 0x2340, /*!< Voltage sense */ + TFA9912_BF_TDMGOE= 0x2350, /*!< DSP Gainout */ + TFA9912_BF_TDMCF2E= 0x2360, /*!< DSP 2 */ + TFA9912_BF_TDMCF3E= 0x2370, /*!< DSP 3 */ + TFA9912_BF_TDMCFE= 0x2380, /*!< DSP */ + TFA9912_BF_TDMES6= 0x2390, /*!< Loopback of Audio left (channel 1) */ + TFA9912_BF_TDMES7= 0x23a0, /*!< Loopback of Audio right (channel 2) */ + TFA9912_BF_TDMCF4E= 0x23b0, /*!< AEC ref right control */ + TFA9912_BF_TDMPD1E= 0x23c0, /*!< PDM 1 control */ + TFA9912_BF_TDMPD2E= 0x23d0, /*!< PDM 2 control */ + TFA9912_BF_TDMGIN= 0x2401, /*!< IO gainin */ + TFA9912_BF_TDMLIO= 0x2421, /*!< IO audio left */ + TFA9912_BF_TDMRIO= 0x2441, /*!< IO audio right */ + TFA9912_BF_TDMCSIO= 0x2461, /*!< IO Current Sense */ + TFA9912_BF_TDMVSIO= 0x2481, /*!< IO voltage sense */ + TFA9912_BF_TDMGOIO= 0x24a1, /*!< IO gain out */ + TFA9912_BF_TDMCFIO2= 0x24c1, /*!< IO DSP 2 */ + TFA9912_BF_TDMCFIO3= 0x24e1, /*!< IO DSP 3 */ + TFA9912_BF_TDMCFIO= 0x2501, /*!< IO DSP */ + TFA9912_BF_TDMLPB6= 0x2521, /*!< IO Source 6 */ + TFA9912_BF_TDMLPB7= 0x2541, /*!< IO Source 7 */ + TFA9912_BF_TDMGS = 0x2603, /*!< Control gainin */ + TFA9912_BF_TDMDCS= 0x2643, /*!< tdm slot for audio left (channel 1) */ + TFA9912_BF_TDMSPKS= 0x2683, /*!< tdm slot for audio right (channel 2) */ + TFA9912_BF_TDMCSS= 0x26c3, /*!< Slot Position of Current Sense Out */ + TFA9912_BF_TDMVSS= 0x2703, /*!< Slot Position of Voltage sense */ + TFA9912_BF_TDMCGOS= 0x2743, /*!< Slot Position of GAIN out */ + TFA9912_BF_TDMCF2S= 0x2783, /*!< Slot Position DSPout2 */ + TFA9912_BF_TDMCF3S= 0x27c3, /*!< Slot Position DSPout3 */ + TFA9912_BF_TDMCFS= 0x2803, /*!< Slot Position of DSPout */ + TFA9912_BF_TDMEDAT6S= 0x2843, /*!< Slot Position of loopback channel left */ + TFA9912_BF_TDMEDAT7S= 0x2883, /*!< Slot Position of loopback channel right */ + TFA9912_BF_TDMTXUS3= 0x2901, /*!< Format unused slots D3 */ + TFA9912_BF_PDMSM = 0x3100, /*!< PDM control */ + TFA9912_BF_PDMSTSEL= 0x3110, /*!< PDM Decimator input selection */ + TFA9912_BF_PDMSTENBL= 0x3120, /*!< Side tone input enable */ + TFA9912_BF_PDMLSEL= 0x3130, /*!< PDM data selection for left channel during PDM direct mode */ + TFA9912_BF_PDMRSEL= 0x3140, /*!< PDM data selection for right channel during PDM direct mode */ + TFA9912_BF_MICVDDE= 0x3150, /*!< Enable MICVDD */ + TFA9912_BF_PDMCLRAT= 0x3201, /*!< PDM BCK/Fs ratio */ + TFA9912_BF_PDMGAIN= 0x3223, /*!< PDM gain */ + TFA9912_BF_PDMOSEL= 0x3263, /*!< PDM output selection - RE/FE data combination */ + TFA9912_BF_SELCFHAPD= 0x32a0, /*!< Select the source for haptic data output (not for customer) */ + TFA9912_BF_ISTVDDS= 0x4000, /*!< Status POR */ + TFA9912_BF_ISTPLLS= 0x4010, /*!< Status PLL lock */ + TFA9912_BF_ISTOTDS= 0x4020, /*!< Status OTP alarm */ + TFA9912_BF_ISTOVDS= 0x4030, /*!< Status OVP alarm */ + TFA9912_BF_ISTUVDS= 0x4040, /*!< Status UVP alarm */ + TFA9912_BF_ISTCLKS= 0x4050, /*!< Status clocks stable */ + TFA9912_BF_ISTMTPB= 0x4060, /*!< Status MTP busy */ + TFA9912_BF_ISTNOCLK= 0x4070, /*!< Status lost clock */ + TFA9912_BF_ISTSPKS= 0x4080, /*!< Status speaker error */ + TFA9912_BF_ISTACS= 0x4090, /*!< Status cold start */ + TFA9912_BF_ISTSWS= 0x40a0, /*!< Status amplifier engage */ + TFA9912_BF_ISTWDS= 0x40b0, /*!< Status watchdog */ + TFA9912_BF_ISTAMPS= 0x40c0, /*!< Status amplifier enable */ + TFA9912_BF_ISTAREFS= 0x40d0, /*!< Status Ref enable */ + TFA9912_BF_ISTADCCR= 0x40e0, /*!< Status Control ADC */ + TFA9912_BF_ISTBODNOK= 0x40f0, /*!< Status BOD */ + TFA9912_BF_ISTBSTCU= 0x4100, /*!< Status DCDC current limiting */ + TFA9912_BF_ISTBSTHI= 0x4110, /*!< Status DCDC active */ + TFA9912_BF_ISTBSTOC= 0x4120, /*!< Status DCDC OCP */ + TFA9912_BF_ISTBSTPKCUR= 0x4130, /*!< Status bst peakcur */ + TFA9912_BF_ISTBSTVC= 0x4140, /*!< Status DCDC level 1x */ + TFA9912_BF_ISTBST86= 0x4150, /*!< Status DCDC level 1.14x */ + TFA9912_BF_ISTBST93= 0x4160, /*!< Status DCDC level 1.07x */ + TFA9912_BF_ISTRCVLD= 0x4170, /*!< Status rcvldop ready */ + TFA9912_BF_ISTOCPL= 0x4180, /*!< Status ocp alarm left */ + TFA9912_BF_ISTOCPR= 0x4190, /*!< Status ocp alarm */ + TFA9912_BF_ISTMWSRC= 0x41a0, /*!< Status Waits HW I2C settings */ + TFA9912_BF_ISTMWCFC= 0x41b0, /*!< Status waits CF config */ + TFA9912_BF_ISTMWSMU= 0x41c0, /*!< Status Audio mute sequence */ + TFA9912_BF_ISTCFMER= 0x41d0, /*!< Status cfma error */ + TFA9912_BF_ISTCFMAC= 0x41e0, /*!< Status cfma ack */ + TFA9912_BF_ISTCLKOOR= 0x41f0, /*!< Status flag_clk_out_of_range */ + TFA9912_BF_ISTTDMER= 0x4200, /*!< Status tdm error */ + TFA9912_BF_ISTCLPL= 0x4210, /*!< Status clip left */ + TFA9912_BF_ISTCLPR= 0x4220, /*!< Status clip */ + TFA9912_BF_ISTOCPM= 0x4230, /*!< Status mic ocpok */ + TFA9912_BF_ISTLP1= 0x4250, /*!< Status low power mode1 */ + TFA9912_BF_ISTLA = 0x4260, /*!< Status low amplitude detection */ + TFA9912_BF_ISTVDDP= 0x4270, /*!< Status VDDP greater than VBAT */ + TFA9912_BF_ISTTAPDET= 0x4280, /*!< Status Tap detected */ + TFA9912_BF_ISTAUDMOD= 0x4290, /*!< Status Audio Mode activated */ + TFA9912_BF_ISTSAMMOD= 0x42a0, /*!< Status SAM Mode activated */ + TFA9912_BF_ISTTAPMOD= 0x42b0, /*!< Status Tap Mode Activated */ + TFA9912_BF_ISTTAPTRG= 0x42c0, /*!< Status Tap comparator triggered */ + TFA9912_BF_ICLVDDS= 0x4400, /*!< Clear POR */ + TFA9912_BF_ICLPLLS= 0x4410, /*!< Clear PLL lock */ + TFA9912_BF_ICLOTDS= 0x4420, /*!< Clear OTP alarm */ + TFA9912_BF_ICLOVDS= 0x4430, /*!< Clear OVP alarm */ + TFA9912_BF_ICLUVDS= 0x4440, /*!< Clear UVP alarm */ + TFA9912_BF_ICLCLKS= 0x4450, /*!< Clear clocks stable */ + TFA9912_BF_ICLMTPB= 0x4460, /*!< Clear mtp busy */ + TFA9912_BF_ICLNOCLK= 0x4470, /*!< Clear lost clk */ + TFA9912_BF_ICLSPKS= 0x4480, /*!< Clear speaker error */ + TFA9912_BF_ICLACS= 0x4490, /*!< Clear cold started */ + TFA9912_BF_ICLSWS= 0x44a0, /*!< Clear amplifier engage */ + TFA9912_BF_ICLWDS= 0x44b0, /*!< Clear watchdog */ + TFA9912_BF_ICLAMPS= 0x44c0, /*!< Clear enbl amp */ + TFA9912_BF_ICLAREFS= 0x44d0, /*!< Clear ref enable */ + TFA9912_BF_ICLADCCR= 0x44e0, /*!< Clear control ADC */ + TFA9912_BF_ICLBODNOK= 0x44f0, /*!< Clear BOD */ + TFA9912_BF_ICLBSTCU= 0x4500, /*!< Clear DCDC current limiting */ + TFA9912_BF_ICLBSTHI= 0x4510, /*!< Clear DCDC active */ + TFA9912_BF_ICLBSTOC= 0x4520, /*!< Clear DCDC OCP */ + TFA9912_BF_ICLBSTPC= 0x4530, /*!< Clear bst peakcur */ + TFA9912_BF_ICLBSTVC= 0x4540, /*!< Clear DCDC level 1x */ + TFA9912_BF_ICLBST86= 0x4550, /*!< Clear DCDC level 1.14x */ + TFA9912_BF_ICLBST93= 0x4560, /*!< Clear DCDC level 1.07x */ + TFA9912_BF_ICLRCVLD= 0x4570, /*!< Clear rcvldop ready */ + TFA9912_BF_ICLOCPL= 0x4580, /*!< Clear ocp alarm left */ + TFA9912_BF_ICLOCPR= 0x4590, /*!< Clear ocp alarm */ + TFA9912_BF_ICLMWSRC= 0x45a0, /*!< Clear wait HW I2C settings */ + TFA9912_BF_ICLMWCFC= 0x45b0, /*!< Clear wait cf config */ + TFA9912_BF_ICLMWSMU= 0x45c0, /*!< Clear audio mute sequence */ + TFA9912_BF_ICLCFMER= 0x45d0, /*!< Clear cfma err */ + TFA9912_BF_ICLCFMAC= 0x45e0, /*!< Clear cfma ack */ + TFA9912_BF_ICLCLKOOR= 0x45f0, /*!< Clear flag_clk_out_of_range */ + TFA9912_BF_ICLTDMER= 0x4600, /*!< Clear tdm error */ + TFA9912_BF_ICLCLPL= 0x4610, /*!< Clear clip left */ + TFA9912_BF_ICLCLP= 0x4620, /*!< Clear clip */ + TFA9912_BF_ICLOCPM= 0x4630, /*!< Clear mic ocpok */ + TFA9912_BF_ICLLP1= 0x4650, /*!< Clear low power mode1 */ + TFA9912_BF_ICLLA = 0x4660, /*!< Clear low amplitude detection */ + TFA9912_BF_ICLVDDP= 0x4670, /*!< Clear VDDP greater then VBAT */ + TFA9912_BF_ICLTAPDET= 0x4680, /*!< Clear Tap detected */ + TFA9912_BF_ICLAUDMOD= 0x4690, /*!< Clear Audio Mode activated */ + TFA9912_BF_ICLSAMMOD= 0x46a0, /*!< Clear SAM Mode activated */ + TFA9912_BF_ICLTAPMOD= 0x46b0, /*!< Clear Tap Mode Activated */ + TFA9912_BF_ICLTAPTRG= 0x46c0, /*!< Clear Comparator Interrupt */ + TFA9912_BF_IEVDDS= 0x4800, /*!< Enable por */ + TFA9912_BF_IEPLLS= 0x4810, /*!< Enable pll lock */ + TFA9912_BF_IEOTDS= 0x4820, /*!< Enable OTP alarm */ + TFA9912_BF_IEOVDS= 0x4830, /*!< Enable OVP alarm */ + TFA9912_BF_IEUVDS= 0x4840, /*!< Enable UVP alarm */ + TFA9912_BF_IECLKS= 0x4850, /*!< Enable clocks stable */ + TFA9912_BF_IEMTPB= 0x4860, /*!< Enable mtp busy */ + TFA9912_BF_IENOCLK= 0x4870, /*!< Enable lost clk */ + TFA9912_BF_IESPKS= 0x4880, /*!< Enable speaker error */ + TFA9912_BF_IEACS = 0x4890, /*!< Enable cold started */ + TFA9912_BF_IESWS = 0x48a0, /*!< Enable amplifier engage */ + TFA9912_BF_IEWDS = 0x48b0, /*!< Enable watchdog */ + TFA9912_BF_IEAMPS= 0x48c0, /*!< Enable enbl amp */ + TFA9912_BF_IEAREFS= 0x48d0, /*!< Enable ref enable */ + TFA9912_BF_IEADCCR= 0x48e0, /*!< Enable Control ADC */ + TFA9912_BF_IEBODNOK= 0x48f0, /*!< Enable BOD */ + TFA9912_BF_IEBSTCU= 0x4900, /*!< Enable DCDC current limiting */ + TFA9912_BF_IEBSTHI= 0x4910, /*!< Enable DCDC active */ + TFA9912_BF_IEBSTOC= 0x4920, /*!< Enable DCDC OCP */ + TFA9912_BF_IEBSTPC= 0x4930, /*!< Enable bst peakcur */ + TFA9912_BF_IEBSTVC= 0x4940, /*!< Enable DCDC level 1x */ + TFA9912_BF_IEBST86= 0x4950, /*!< Enable DCDC level 1.14x */ + TFA9912_BF_IEBST93= 0x4960, /*!< Enable DCDC level 1.07x */ + TFA9912_BF_IERCVLD= 0x4970, /*!< Enable rcvldop ready */ + TFA9912_BF_IEOCPL= 0x4980, /*!< Enable ocp alarm left */ + TFA9912_BF_IEOCPR= 0x4990, /*!< Enable ocp alarm */ + TFA9912_BF_IEMWSRC= 0x49a0, /*!< Enable waits HW I2C settings */ + TFA9912_BF_IEMWCFC= 0x49b0, /*!< Enable man wait cf config */ + TFA9912_BF_IEMWSMU= 0x49c0, /*!< Enable man Audio mute sequence */ + TFA9912_BF_IECFMER= 0x49d0, /*!< Enable cfma err */ + TFA9912_BF_IECFMAC= 0x49e0, /*!< Enable cfma ack */ + TFA9912_BF_IECLKOOR= 0x49f0, /*!< Enable flag_clk_out_of_range */ + TFA9912_BF_IETDMER= 0x4a00, /*!< Enable tdm error */ + TFA9912_BF_IECLPL= 0x4a10, /*!< Enable clip left */ + TFA9912_BF_IECLPR= 0x4a20, /*!< Enable clip */ + TFA9912_BF_IEOCPM1= 0x4a30, /*!< Enable mic ocpok */ + TFA9912_BF_IELP1 = 0x4a50, /*!< Enable low power mode1 */ + TFA9912_BF_IELA = 0x4a60, /*!< Enable low amplitude detection */ + TFA9912_BF_IEVDDP= 0x4a70, /*!< Enable VDDP greater than VBAT */ + TFA9912_BF_IETAPDET= 0x4a80, /*!< Enable Tap detected */ + TFA9912_BF_IEAUDMOD= 0x4a90, /*!< Enable Audio Mode activated */ + TFA9912_BF_IESAMMOD= 0x4aa0, /*!< Enable SAM Mode activated */ + TFA9912_BF_IETAPMOD= 0x4ab0, /*!< Enable Tap Mode Activated */ + TFA9912_BF_IETAPTRG= 0x4ac0, /*!< Enable comparator interrupt */ + TFA9912_BF_IPOVDDS= 0x4c00, /*!< Polarity por */ + TFA9912_BF_IPOPLLS= 0x4c10, /*!< Polarity pll lock */ + TFA9912_BF_IPOOTDS= 0x4c20, /*!< Polarity OTP alarm */ + TFA9912_BF_IPOOVDS= 0x4c30, /*!< Polarity OVP alarm */ + TFA9912_BF_IPOUVDS= 0x4c40, /*!< Polarity UVP alarm */ + TFA9912_BF_IPOCLKS= 0x4c50, /*!< Polarity clocks stable */ + TFA9912_BF_IPOMTPB= 0x4c60, /*!< Polarity mtp busy */ + TFA9912_BF_IPONOCLK= 0x4c70, /*!< Polarity lost clk */ + TFA9912_BF_IPOSPKS= 0x4c80, /*!< Polarity speaker error */ + TFA9912_BF_IPOACS= 0x4c90, /*!< Polarity cold started */ + TFA9912_BF_IPOSWS= 0x4ca0, /*!< Polarity amplifier engage */ + TFA9912_BF_IPOWDS= 0x4cb0, /*!< Polarity watchdog */ + TFA9912_BF_IPOAMPS= 0x4cc0, /*!< Polarity enbl amp */ + TFA9912_BF_IPOAREFS= 0x4cd0, /*!< Polarity ref enable */ + TFA9912_BF_IPOADCCR= 0x4ce0, /*!< Polarity Control ADC */ + TFA9912_BF_IPOBODNOK= 0x4cf0, /*!< Polarity BOD */ + TFA9912_BF_IPOBSTCU= 0x4d00, /*!< Polarity DCDC current limiting */ + TFA9912_BF_IPOBSTHI= 0x4d10, /*!< Polarity DCDC active */ + TFA9912_BF_IPOBSTOC= 0x4d20, /*!< Polarity DCDC OCP */ + TFA9912_BF_IPOBSTPC= 0x4d30, /*!< Polarity bst peakcur */ + TFA9912_BF_IPOBSTVC= 0x4d40, /*!< Polarity DCDC level 1x */ + TFA9912_BF_IPOBST86= 0x4d50, /*!< Polarity DCDC level 1.14x */ + TFA9912_BF_IPOBST93= 0x4d60, /*!< Polarity DCDC level 1.07x */ + TFA9912_BF_IPORCVLD= 0x4d70, /*!< Polarity rcvldop ready */ + TFA9912_BF_IPOOCPL= 0x4d80, /*!< Polarity ocp alarm left */ + TFA9912_BF_IPOOCPR= 0x4d90, /*!< Polarity ocp alarm */ + TFA9912_BF_IPOMWSRC= 0x4da0, /*!< Polarity waits HW I2C settings */ + TFA9912_BF_IPOMWCFC= 0x4db0, /*!< Polarity man wait cf config */ + TFA9912_BF_IPOMWSMU= 0x4dc0, /*!< Polarity man audio mute sequence */ + TFA9912_BF_IPOCFMER= 0x4dd0, /*!< Polarity cfma err */ + TFA9912_BF_IPOCFMAC= 0x4de0, /*!< Polarity cfma ack */ + TFA9912_BF_IPOCLKOOR= 0x4df0, /*!< Polarity flag_clk_out_of_range */ + TFA9912_BF_IPOTDMER= 0x4e00, /*!< Polarity tdm error */ + TFA9912_BF_IPOCLPL= 0x4e10, /*!< Polarity clip left */ + TFA9912_BF_IPOCLPR= 0x4e20, /*!< Polarity clip */ + TFA9912_BF_IPOOCPM= 0x4e30, /*!< Polarity mic ocpok */ + TFA9912_BF_IPOLP1= 0x4e50, /*!< Polarity low power mode1 */ + TFA9912_BF_IPOLA = 0x4e60, /*!< Polarity low amplitude detection */ + TFA9912_BF_IPOVDDP= 0x4e70, /*!< Polarity VDDP greater than VBAT */ + TFA9912_BF_IPOLTAPDET= 0x4e80, /*!< PolarityTap detected */ + TFA9912_BF_IPOLAUDMOD= 0x4e90, /*!< PolarityAudio Mode activated */ + TFA9912_BF_IPOLSAMMOD= 0x4ea0, /*!< PolaritySAM Mode activated */ + TFA9912_BF_IPOLTAPMOD= 0x4eb0, /*!< Polarity Tap Mode Activated */ + TFA9912_BF_IPOLTAPTRG= 0x4ec0, /*!< PolarityTap Comparator Trigger */ + TFA9912_BF_BSSCR = 0x5001, /*!< Battery Safeguard attack time */ + TFA9912_BF_BSST = 0x5023, /*!< Battery Safeguard threshold voltage level */ + TFA9912_BF_BSSRL = 0x5061, /*!< Battery Safeguard maximum reduction */ + TFA9912_BF_BSSRR = 0x5082, /*!< Battery Safeguard release time */ + TFA9912_BF_BSSHY = 0x50b1, /*!< Battery Safeguard hysteresis */ + TFA9912_BF_BSSAC = 0x50d0, /*!< Reset clipper - Auto clear */ + TFA9912_BF_BSSR = 0x50e0, /*!< Battery voltage read out */ + TFA9912_BF_BSSBY = 0x50f0, /*!< Bypass HW clipper */ + TFA9912_BF_BSSS = 0x5100, /*!< Vbat prot steepness */ + TFA9912_BF_INTSMUTE= 0x5110, /*!< Soft mute HW */ + TFA9912_BF_CFSML = 0x5120, /*!< Soft mute FW left */ + TFA9912_BF_CFSM = 0x5130, /*!< Soft mute FW */ + TFA9912_BF_HPFBYPL= 0x5140, /*!< Bypass HPF left */ + TFA9912_BF_HPFBYP= 0x5150, /*!< Bypass HPF */ + TFA9912_BF_DPSAL = 0x5160, /*!< Enable DPSA left */ + TFA9912_BF_DPSA = 0x5170, /*!< Enable DPSA */ + TFA9912_BF_VOL = 0x5187, /*!< FW volume control for primary audio channel */ + TFA9912_BF_HNDSFRCV= 0x5200, /*!< Selection receiver */ + TFA9912_BF_CLIPCTRL= 0x5222, /*!< Clip control setting */ + TFA9912_BF_AMPGAIN= 0x5257, /*!< Amplifier gain */ + TFA9912_BF_SLOPEE= 0x52d0, /*!< Enables slope control */ + TFA9912_BF_SLOPESET= 0x52e0, /*!< Slope speed setting (bin. coded) */ + TFA9912_BF_CFTAPPAT= 0x5c07, /*!< Coolflux tap pattern */ + TFA9912_BF_TAPDBGINFO= 0x5c83, /*!< Reserved */ + TFA9912_BF_TATPSTAT1= 0x5d0f, /*!< Tap Status 1 from CF FW */ + TFA9912_BF_TCOMPTHR= 0x5f03, /*!< Comparator threshold (in uV) */ + TFA9912_BF_PGAGAIN= 0x6081, /*!< PGA gain selection */ + TFA9912_BF_TDMSPKG= 0x6123, /*!< System gain (INPLEV 0) */ + TFA9912_BF_LPM1LVL= 0x6505, /*!< low power mode1 detector ctrl threshold for low_audio_lvl */ + TFA9912_BF_LPM1HLD= 0x6565, /*!< Low power mode1 detector, ctrl hold time before low audio is reckoned to be low audio */ + TFA9912_BF_LPM1DIS= 0x65c0, /*!< low power mode1 detector control */ + TFA9912_BF_DCDIS = 0x6630, /*!< DCDC */ + TFA9912_BF_TDMSRCMAP= 0x6801, /*!< tdm source mapping */ + TFA9912_BF_TDMSRCAS= 0x6821, /*!< frame a selection */ + TFA9912_BF_TDMSRCBS= 0x6841, /*!< frame b selection */ + TFA9912_BF_ANC1C = 0x68a0, /*!< ANC one s complement */ + TFA9912_BF_SAMMODE= 0x6901, /*!< Sam mode */ + TFA9912_BF_DCMCC = 0x7033, /*!< Max coil current */ + TFA9912_BF_DCCV = 0x7071, /*!< Slope compensation current, represents LxF (inductance x frequency) value */ + TFA9912_BF_DCIE = 0x7090, /*!< Adaptive boost mode */ + TFA9912_BF_DCSR = 0x70a0, /*!< Soft ramp up/down */ + TFA9912_BF_DCINSEL= 0x70c1, /*!< DCDC IIR input Selection */ + TFA9912_BF_DCPWM = 0x70f0, /*!< DCDC PWM only mode */ + TFA9912_BF_DCTRIP= 0x7504, /*!< Adaptive boost trip levels 1, effective only when boost_intelligent is set to 1 */ + TFA9912_BF_DCTRIP2= 0x7554, /*!< Adaptive boost trip level 2, effective only when boost_intelligent is set to 1 */ + TFA9912_BF_DCTRIPT= 0x75a4, /*!< Adaptive boost trip levels, effective only when boost_intelligent is set to 1 */ + TFA9912_BF_DCVOF = 0x7635, /*!< First boost voltage level */ + TFA9912_BF_DCVOS = 0x7695, /*!< Second boost voltage level */ + TFA9912_BF_RST = 0x9000, /*!< Reset */ + TFA9912_BF_DMEM = 0x9011, /*!< Target memory */ + TFA9912_BF_AIF = 0x9030, /*!< Auto increment */ + TFA9912_BF_CFINT = 0x9040, /*!< Interrupt - auto clear */ + TFA9912_BF_CFCGATE= 0x9050, /*!< Coolflux clock gating disabling control */ + TFA9912_BF_REQCMD= 0x9080, /*!< Firmware event request rpc command */ + TFA9912_BF_REQRST= 0x9090, /*!< Firmware event request reset restart */ + TFA9912_BF_REQMIPS= 0x90a0, /*!< Firmware event request short on mips */ + TFA9912_BF_REQMUTED= 0x90b0, /*!< Firmware event request mute sequence ready */ + TFA9912_BF_REQVOL= 0x90c0, /*!< Firmware event request volume ready */ + TFA9912_BF_REQDMG= 0x90d0, /*!< Firmware event request speaker damage detected */ + TFA9912_BF_REQCAL= 0x90e0, /*!< Firmware event request calibration completed */ + TFA9912_BF_REQRSV= 0x90f0, /*!< Firmware event request reserved */ + TFA9912_BF_MADD = 0x910f, /*!< Memory address */ + TFA9912_BF_MEMA = 0x920f, /*!< Activate memory access */ + TFA9912_BF_ERR = 0x9307, /*!< Error flags */ + TFA9912_BF_ACKCMD= 0x9380, /*!< Firmware event acknowledge rpc command */ + TFA9912_BF_ACKRST= 0x9390, /*!< Firmware event acknowledge reset restart */ + TFA9912_BF_ACKMIPS= 0x93a0, /*!< Firmware event acknowledge short on mips */ + TFA9912_BF_ACKMUTED= 0x93b0, /*!< Firmware event acknowledge mute sequence ready */ + TFA9912_BF_ACKVOL= 0x93c0, /*!< Firmware event acknowledge volume ready */ + TFA9912_BF_ACKDMG= 0x93d0, /*!< Firmware event acknowledge speaker damage detected */ + TFA9912_BF_ACKCAL= 0x93e0, /*!< Firmware event acknowledge calibration completed */ + TFA9912_BF_ACKRSV= 0x93f0, /*!< Firmware event acknowledge reserved */ + TFA9912_BF_MTPK = 0xa107, /*!< MTP KEY2 register */ + TFA9912_BF_KEY1LOCKED= 0xa200, /*!< Indicates KEY1 is locked */ + TFA9912_BF_KEY2LOCKED= 0xa210, /*!< Indicates KEY2 is locked */ + TFA9912_BF_CIMTP = 0xa360, /*!< Start copying data from I2C mtp registers to mtp */ + TFA9912_BF_MTPRDMSB= 0xa50f, /*!< MSB word of MTP manual read data */ + TFA9912_BF_MTPRDLSB= 0xa60f, /*!< LSB word of MTP manual read data */ + TFA9912_BF_EXTTS = 0xb108, /*!< External temperature (C) */ + TFA9912_BF_TROS = 0xb190, /*!< Select temp Speaker calibration */ + TFA9912_BF_SWPROFIL= 0xee0f, /*!< Software profile data */ + TFA9912_BF_SWVSTEP= 0xef0f, /*!< Software vstep information */ + TFA9912_BF_MTPOTC= 0xf000, /*!< Calibration schedule */ + TFA9912_BF_MTPEX = 0xf010, /*!< Calibration Ron executed */ + TFA9912_BF_DCMCCAPI= 0xf020, /*!< Calibration current limit DCDC */ + TFA9912_BF_DCMCCSB= 0xf030, /*!< Sign bit for delta calibration current limit DCDC */ + TFA9912_BF_DCMCCCL= 0xf042, /*!< Calibration delta current limit DCDC */ + TFA9912_BF_USERDEF= 0xf078, /*!< Reserved space for allowing customer to store speaker information */ + TFA9912_BF_R25C = 0xf40f, /*!< Ron resistance of speaker coil */ +} nxpTfa9912BfEnumList_t; +#define TFA9912_NAMETABLE static tfaBfName_t Tfa9912DatasheetNames[]= {\ + { 0x0, "PWDN"}, /* Powerdown selection , */\ + { 0x10, "I2CR"}, /* I2C Reset - Auto clear , */\ + { 0x20, "CFE"}, /* Enable CoolFlux , */\ + { 0x30, "AMPE"}, /* Enables the Amplifier , */\ + { 0x40, "DCA"}, /* Activate DC-to-DC converter , */\ + { 0x50, "SBSL"}, /* Coolflux configured , */\ + { 0x60, "AMPC"}, /* CoolFlux controls amplifier , */\ + { 0x71, "INTP"}, /* Interrupt config , */\ + { 0x90, "FSSSEL"}, /* Audio sample reference , */\ + { 0xb0, "BYPOCP"}, /* Bypass OCP , */\ + { 0xc0, "TSTOCP"}, /* OCP testing control , */\ + { 0x101, "AMPINSEL"}, /* Amplifier input selection , */\ + { 0x120, "MANSCONF"}, /* I2C configured , */\ + { 0x130, "MANCOLD"}, /* Execute cold start , */\ + { 0x140, "MANAOOSC"}, /* Internal osc off at PWDN , */\ + { 0x150, "MANROBOD"}, /* Reaction on BOD , */\ + { 0x160, "BODE"}, /* BOD Enable , */\ + { 0x170, "BODHYS"}, /* BOD Hysteresis , */\ + { 0x181, "BODFILT"}, /* BOD filter , */\ + { 0x1a1, "BODTHLVL"}, /* BOD threshold , */\ + { 0x1d0, "MUTETO"}, /* Time out SB mute sequence , */\ + { 0x1e0, "RCVNS"}, /* Noise shaper selection , */\ + { 0x1f0, "MANWDE"}, /* Watchdog enable , */\ + { 0x203, "AUDFS"}, /* Sample rate (fs) , */\ + { 0x240, "INPLEV"}, /* TDM output attenuation , */\ + { 0x255, "FRACTDEL"}, /* V/I Fractional delay , */\ + { 0x2b0, "BYPHVBF"}, /* Bypass HVBAT filter , */\ + { 0x2c0, "TDMC"}, /* TDM Compatibility with TFA9872 , */\ + { 0x2e0, "ENBLADC10"}, /* ADC10 Enable - I2C direct mode , */\ + { 0x30f, "REV"}, /* Revision info , */\ + { 0x401, "REFCKEXT"}, /* PLL external ref clock , */\ + { 0x420, "REFCKSEL"}, /* PLL internal ref clock , */\ + { 0x430, "ENCFCKSEL"}, /* Coolflux DSP clock scaling, low power mode , */\ + { 0x441, "CFCKSEL"}, /* Coolflux DSP clock scaler selection for low power mode, */\ + { 0x460, "TDMINFSEL"}, /* TDM clock selection , */\ + { 0x470, "DISBLAUTOCLKSEL"}, /* Disable Automatic dsp clock source selection , */\ + { 0x480, "SELCLKSRC"}, /* I2C selection of DSP clock when auto select is disabled, */\ + { 0x490, "SELTIMSRC"}, /* I2C selection of Watchdog and Timer clock , */\ + { 0x500, "SSLEFTE"}, /* , */\ + { 0x510, "SPKSSEN"}, /* Enable speaker path , */\ + { 0x520, "VSLEFTE"}, /* , */\ + { 0x530, "VSRIGHTE"}, /* Voltage sense , */\ + { 0x540, "CSLEFTE"}, /* , */\ + { 0x550, "CSRIGHTE"}, /* Current sense , */\ + { 0x560, "SSPDME"}, /* Sub-system PDM , */\ + { 0x570, "PGALE"}, /* Enable PGA chop clock for left channel , */\ + { 0x580, "PGARE"}, /* Enable PGA chop clock , */\ + { 0x590, "SSTDME"}, /* Sub-system TDM , */\ + { 0x5a0, "SSPBSTE"}, /* Sub-system boost , */\ + { 0x5b0, "SSADCE"}, /* Sub-system ADC , */\ + { 0x5c0, "SSFAIME"}, /* Sub-system FAIM , */\ + { 0x5d0, "SSCFTIME"}, /* CF Sub-system timer , */\ + { 0x5e0, "SSCFWDTE"}, /* CF Sub-system WDT , */\ + { 0x5f0, "FAIMVBGOVRRL"}, /* Over rule of vbg for FaIM access , */\ + { 0x600, "SAMSPKSEL"}, /* Input selection for TAP/SAM , */\ + { 0x610, "PDM2IISEN"}, /* PDM2IIS Bridge enable , */\ + { 0x620, "TAPRSTBYPASS"}, /* Tap decimator reset bypass - Bypass the decimator reset from tapdec, */\ + { 0x631, "CARDECISEL0"}, /* Cardec input 0 sel , */\ + { 0x651, "CARDECISEL1"}, /* Cardec input sel , */\ + { 0x670, "TAPDECSEL"}, /* Select TAP/Cardec for TAP , */\ + { 0x680, "COMPCOUNT"}, /* Comparator o/p filter selection , */\ + { 0x691, "STARTUPMODE"}, /* Startup Mode Selection , */\ + { 0x6b0, "AUTOTAP"}, /* Enable auto tap switching , */\ + { 0x6c1, "COMPINITIME"}, /* Comparator initialization time to be used in Tap Machine, */\ + { 0x6e1, "ANAPINITIME"}, /* Analog initialization time to be used in Tap Machine, */\ + { 0x707, "CCHKTH"}, /* Clock check Higher Threshold , */\ + { 0x787, "CCHKTL"}, /* Clock check Higher Threshold , */\ + { 0x802, "AMPOCRT"}, /* Amplifier on-off criteria for shutdown , */\ + { 0x832, "AMPTCRR"}, /* Amplifier on-off criteria for tap mode entry , */\ + { 0xd00, "STGS"}, /* PDM side tone gain selector , */\ + { 0xd18, "STGAIN"}, /* Side tone gain , */\ + { 0xda0, "STSMUTE"}, /* Side tone soft mute , */\ + { 0xdb0, "ST1C"}, /* side tone one s complement , */\ + { 0xe80, "CMFBEL"}, /* CMFB enable left , */\ + { 0x1000, "VDDS"}, /* POR , */\ + { 0x1010, "PLLS"}, /* PLL lock , */\ + { 0x1020, "OTDS"}, /* OTP alarm , */\ + { 0x1030, "OVDS"}, /* OVP alarm , */\ + { 0x1040, "UVDS"}, /* UVP alarm , */\ + { 0x1050, "CLKS"}, /* Clocks stable , */\ + { 0x1060, "MTPB"}, /* MTP busy , */\ + { 0x1070, "NOCLK"}, /* Lost clock , */\ + { 0x1090, "ACS"}, /* Cold Start , */\ + { 0x10a0, "SWS"}, /* Amplifier engage , */\ + { 0x10b0, "WDS"}, /* Watchdog , */\ + { 0x10c0, "AMPS"}, /* Amplifier enable , */\ + { 0x10d0, "AREFS"}, /* References enable , */\ + { 0x10e0, "ADCCR"}, /* Control ADC , */\ + { 0x10f0, "BODNOK"}, /* BOD , */\ + { 0x1100, "DCIL"}, /* DCDC current limiting , */\ + { 0x1110, "DCDCA"}, /* DCDC active , */\ + { 0x1120, "DCOCPOK"}, /* DCDC OCP nmos , */\ + { 0x1130, "DCPEAKCUR"}, /* Indicates current is max in DC-to-DC converter , */\ + { 0x1140, "DCHVBAT"}, /* DCDC level 1x , */\ + { 0x1150, "DCH114"}, /* DCDC level 1.14x , */\ + { 0x1160, "DCH107"}, /* DCDC level 1.07x , */\ + { 0x1170, "STMUTEB"}, /* side tone (un)mute busy , */\ + { 0x1180, "STMUTE"}, /* side tone mute state , */\ + { 0x1190, "TDMLUTER"}, /* TDM LUT error , */\ + { 0x11a2, "TDMSTAT"}, /* TDM status bits , */\ + { 0x11d0, "TDMERR"}, /* TDM error , */\ + { 0x11e0, "HAPTIC"}, /* Status haptic driver , */\ + { 0x1300, "OCPOAP"}, /* OCPOK pmos A , */\ + { 0x1310, "OCPOAN"}, /* OCPOK nmos A , */\ + { 0x1320, "OCPOBP"}, /* OCPOK pmos B , */\ + { 0x1330, "OCPOBN"}, /* OCPOK nmos B , */\ + { 0x1340, "CLIPAH"}, /* Clipping A to Vddp , */\ + { 0x1350, "CLIPAL"}, /* Clipping A to gnd , */\ + { 0x1360, "CLIPBH"}, /* Clipping B to Vddp , */\ + { 0x1370, "CLIPBL"}, /* Clipping B to gnd , */\ + { 0x1380, "OCDS"}, /* OCP amplifier , */\ + { 0x1390, "CLIPS"}, /* Amplifier clipping , */\ + { 0x13a0, "TCMPTRG"}, /* Status Tap comparator triggered , */\ + { 0x13b0, "TAPDET"}, /* Status Tap detected , */\ + { 0x13c0, "MANWAIT1"}, /* Wait HW I2C settings , */\ + { 0x13d0, "MANWAIT2"}, /* Wait CF config , */\ + { 0x13e0, "MANMUTE"}, /* Audio mute sequence , */\ + { 0x13f0, "MANOPER"}, /* Operating state , */\ + { 0x1400, "SPKSL"}, /* Left speaker status , */\ + { 0x1410, "SPKS"}, /* Speaker status , */\ + { 0x1420, "CLKOOR"}, /* External clock status , */\ + { 0x1433, "MANSTATE"}, /* Device manager status , */\ + { 0x1471, "DCMODE"}, /* DCDC mode status bits , */\ + { 0x1490, "DSPCLKSRC"}, /* DSP clock source selected by manager , */\ + { 0x14a1, "STARTUPMODSTAT"}, /* Startup Mode Selected by Manager(Read Only) , */\ + { 0x14c3, "TSPMSTATE"}, /* Tap Machine State , */\ + { 0x1509, "BATS"}, /* Battery voltage (V) , */\ + { 0x1608, "TEMPS"}, /* IC Temperature (C) , */\ + { 0x1709, "VDDPS"}, /* IC VDDP voltage ( 1023*VDDP/13 V) , */\ + { 0x17a0, "DCILCF"}, /* DCDC current limiting for DSP , */\ + { 0x2000, "TDMUC"}, /* Mode setting , */\ + { 0x2011, "DIO4SEL"}, /* DIO4 Input selection , */\ + { 0x2040, "TDME"}, /* Enable TDM interface , */\ + { 0x2050, "TDMMODE"}, /* Slave/master , */\ + { 0x2060, "TDMCLINV"}, /* Reception data to BCK clock , */\ + { 0x2073, "TDMFSLN"}, /* FS length , */\ + { 0x20b0, "TDMFSPOL"}, /* FS polarity , */\ + { 0x20c3, "TDMNBCK"}, /* N-BCK's in FS , */\ + { 0x2103, "TDMSLOTS"}, /* N-slots in Frame , */\ + { 0x2144, "TDMSLLN"}, /* N-bits in slot , */\ + { 0x2194, "TDMBRMG"}, /* N-bits remaining , */\ + { 0x21e0, "TDMDEL"}, /* data delay to FS , */\ + { 0x21f0, "TDMADJ"}, /* data adjustment , */\ + { 0x2201, "TDMOOMP"}, /* Received audio compression , */\ + { 0x2224, "TDMSSIZE"}, /* Sample size per slot , */\ + { 0x2271, "TDMTXDFO"}, /* Format unused bits in a slot , */\ + { 0x2291, "TDMTXUS0"}, /* Format unused slots GAINIO , */\ + { 0x22b1, "TDMTXUS1"}, /* Format unused slots DIO1 , */\ + { 0x22d1, "TDMTXUS2"}, /* Format unused slots DIO2 , */\ + { 0x2300, "TDMGIE"}, /* Control gain (channel in 0) , */\ + { 0x2310, "TDMDCE"}, /* Control audio left (channel in 1 ) , */\ + { 0x2320, "TDMSPKE"}, /* Control audio right (channel in 2 ) , */\ + { 0x2330, "TDMCSE"}, /* Current sense , */\ + { 0x2340, "TDMVSE"}, /* Voltage sense , */\ + { 0x2350, "TDMGOE"}, /* DSP Gainout , */\ + { 0x2360, "TDMCF2E"}, /* DSP 2 , */\ + { 0x2370, "TDMCF3E"}, /* DSP 3 , */\ + { 0x2380, "TDMCFE"}, /* DSP , */\ + { 0x2390, "TDMES6"}, /* Loopback of Audio left (channel 1) , */\ + { 0x23a0, "TDMES7"}, /* Loopback of Audio right (channel 2) , */\ + { 0x23b0, "TDMCF4E"}, /* AEC ref right control , */\ + { 0x23c0, "TDMPD1E"}, /* PDM 1 control , */\ + { 0x23d0, "TDMPD2E"}, /* PDM 2 control , */\ + { 0x2401, "TDMGIN"}, /* IO gainin , */\ + { 0x2421, "TDMLIO"}, /* IO audio left , */\ + { 0x2441, "TDMRIO"}, /* IO audio right , */\ + { 0x2461, "TDMCSIO"}, /* IO Current Sense , */\ + { 0x2481, "TDMVSIO"}, /* IO voltage sense , */\ + { 0x24a1, "TDMGOIO"}, /* IO gain out , */\ + { 0x24c1, "TDMCFIO2"}, /* IO DSP 2 , */\ + { 0x24e1, "TDMCFIO3"}, /* IO DSP 3 , */\ + { 0x2501, "TDMCFIO"}, /* IO DSP , */\ + { 0x2521, "TDMLPB6"}, /* IO Source 6 , */\ + { 0x2541, "TDMLPB7"}, /* IO Source 7 , */\ + { 0x2603, "TDMGS"}, /* Control gainin , */\ + { 0x2643, "TDMDCS"}, /* tdm slot for audio left (channel 1) , */\ + { 0x2683, "TDMSPKS"}, /* tdm slot for audio right (channel 2) , */\ + { 0x26c3, "TDMCSS"}, /* Slot Position of Current Sense Out , */\ + { 0x2703, "TDMVSS"}, /* Slot Position of Voltage sense , */\ + { 0x2743, "TDMCGOS"}, /* Slot Position of GAIN out , */\ + { 0x2783, "TDMCF2S"}, /* Slot Position DSPout2 , */\ + { 0x27c3, "TDMCF3S"}, /* Slot Position DSPout3 , */\ + { 0x2803, "TDMCFS"}, /* Slot Position of DSPout , */\ + { 0x2843, "TDMEDAT6S"}, /* Slot Position of loopback channel left , */\ + { 0x2883, "TDMEDAT7S"}, /* Slot Position of loopback channel right , */\ + { 0x2901, "TDMTXUS3"}, /* Format unused slots D3 , */\ + { 0x3100, "PDMSM"}, /* PDM control , */\ + { 0x3110, "PDMSTSEL"}, /* PDM Decimator input selection , */\ + { 0x3120, "PDMSTENBL"}, /* Side tone input enable , */\ + { 0x3130, "PDMLSEL"}, /* PDM data selection for left channel during PDM direct mode, */\ + { 0x3140, "PDMRSEL"}, /* PDM data selection for right channel during PDM direct mode, */\ + { 0x3150, "MICVDDE"}, /* Enable MICVDD , */\ + { 0x3201, "PDMCLRAT"}, /* PDM BCK/Fs ratio , */\ + { 0x3223, "PDMGAIN"}, /* PDM gain , */\ + { 0x3263, "PDMOSEL"}, /* PDM output selection - RE/FE data combination , */\ + { 0x32a0, "SELCFHAPD"}, /* Select the source for haptic data output (not for customer), */\ + { 0x4000, "ISTVDDS"}, /* Status POR , */\ + { 0x4010, "ISTPLLS"}, /* Status PLL lock , */\ + { 0x4020, "ISTOTDS"}, /* Status OTP alarm , */\ + { 0x4030, "ISTOVDS"}, /* Status OVP alarm , */\ + { 0x4040, "ISTUVDS"}, /* Status UVP alarm , */\ + { 0x4050, "ISTCLKS"}, /* Status clocks stable , */\ + { 0x4060, "ISTMTPB"}, /* Status MTP busy , */\ + { 0x4070, "ISTNOCLK"}, /* Status lost clock , */\ + { 0x4080, "ISTSPKS"}, /* Status speaker error , */\ + { 0x4090, "ISTACS"}, /* Status cold start , */\ + { 0x40a0, "ISTSWS"}, /* Status amplifier engage , */\ + { 0x40b0, "ISTWDS"}, /* Status watchdog , */\ + { 0x40c0, "ISTAMPS"}, /* Status amplifier enable , */\ + { 0x40d0, "ISTAREFS"}, /* Status Ref enable , */\ + { 0x40e0, "ISTADCCR"}, /* Status Control ADC , */\ + { 0x40f0, "ISTBODNOK"}, /* Status BOD , */\ + { 0x4100, "ISTBSTCU"}, /* Status DCDC current limiting , */\ + { 0x4110, "ISTBSTHI"}, /* Status DCDC active , */\ + { 0x4120, "ISTBSTOC"}, /* Status DCDC OCP , */\ + { 0x4130, "ISTBSTPKCUR"}, /* Status bst peakcur , */\ + { 0x4140, "ISTBSTVC"}, /* Status DCDC level 1x , */\ + { 0x4150, "ISTBST86"}, /* Status DCDC level 1.14x , */\ + { 0x4160, "ISTBST93"}, /* Status DCDC level 1.07x , */\ + { 0x4170, "ISTRCVLD"}, /* Status rcvldop ready , */\ + { 0x4180, "ISTOCPL"}, /* Status ocp alarm left , */\ + { 0x4190, "ISTOCPR"}, /* Status ocp alarm , */\ + { 0x41a0, "ISTMWSRC"}, /* Status Waits HW I2C settings , */\ + { 0x41b0, "ISTMWCFC"}, /* Status waits CF config , */\ + { 0x41c0, "ISTMWSMU"}, /* Status Audio mute sequence , */\ + { 0x41d0, "ISTCFMER"}, /* Status cfma error , */\ + { 0x41e0, "ISTCFMAC"}, /* Status cfma ack , */\ + { 0x41f0, "ISTCLKOOR"}, /* Status flag_clk_out_of_range , */\ + { 0x4200, "ISTTDMER"}, /* Status tdm error , */\ + { 0x4210, "ISTCLPL"}, /* Status clip left , */\ + { 0x4220, "ISTCLPR"}, /* Status clip , */\ + { 0x4230, "ISTOCPM"}, /* Status mic ocpok , */\ + { 0x4250, "ISTLP1"}, /* Status low power mode1 , */\ + { 0x4260, "ISTLA"}, /* Status low amplitude detection , */\ + { 0x4270, "ISTVDDP"}, /* Status VDDP greater than VBAT , */\ + { 0x4280, "ISTTAPDET"}, /* Status Tap detected , */\ + { 0x4290, "ISTAUDMOD"}, /* Status Audio Mode activated , */\ + { 0x42a0, "ISTSAMMOD"}, /* Status SAM Mode activated , */\ + { 0x42b0, "ISTTAPMOD"}, /* Status Tap Mode Activated , */\ + { 0x42c0, "ISTTAPTRG"}, /* Status Tap comparator triggered , */\ + { 0x4400, "ICLVDDS"}, /* Clear POR , */\ + { 0x4410, "ICLPLLS"}, /* Clear PLL lock , */\ + { 0x4420, "ICLOTDS"}, /* Clear OTP alarm , */\ + { 0x4430, "ICLOVDS"}, /* Clear OVP alarm , */\ + { 0x4440, "ICLUVDS"}, /* Clear UVP alarm , */\ + { 0x4450, "ICLCLKS"}, /* Clear clocks stable , */\ + { 0x4460, "ICLMTPB"}, /* Clear mtp busy , */\ + { 0x4470, "ICLNOCLK"}, /* Clear lost clk , */\ + { 0x4480, "ICLSPKS"}, /* Clear speaker error , */\ + { 0x4490, "ICLACS"}, /* Clear cold started , */\ + { 0x44a0, "ICLSWS"}, /* Clear amplifier engage , */\ + { 0x44b0, "ICLWDS"}, /* Clear watchdog , */\ + { 0x44c0, "ICLAMPS"}, /* Clear enbl amp , */\ + { 0x44d0, "ICLAREFS"}, /* Clear ref enable , */\ + { 0x44e0, "ICLADCCR"}, /* Clear control ADC , */\ + { 0x44f0, "ICLBODNOK"}, /* Clear BOD , */\ + { 0x4500, "ICLBSTCU"}, /* Clear DCDC current limiting , */\ + { 0x4510, "ICLBSTHI"}, /* Clear DCDC active , */\ + { 0x4520, "ICLBSTOC"}, /* Clear DCDC OCP , */\ + { 0x4530, "ICLBSTPC"}, /* Clear bst peakcur , */\ + { 0x4540, "ICLBSTVC"}, /* Clear DCDC level 1x , */\ + { 0x4550, "ICLBST86"}, /* Clear DCDC level 1.14x , */\ + { 0x4560, "ICLBST93"}, /* Clear DCDC level 1.07x , */\ + { 0x4570, "ICLRCVLD"}, /* Clear rcvldop ready , */\ + { 0x4580, "ICLOCPL"}, /* Clear ocp alarm left , */\ + { 0x4590, "ICLOCPR"}, /* Clear ocp alarm , */\ + { 0x45a0, "ICLMWSRC"}, /* Clear wait HW I2C settings , */\ + { 0x45b0, "ICLMWCFC"}, /* Clear wait cf config , */\ + { 0x45c0, "ICLMWSMU"}, /* Clear audio mute sequence , */\ + { 0x45d0, "ICLCFMER"}, /* Clear cfma err , */\ + { 0x45e0, "ICLCFMAC"}, /* Clear cfma ack , */\ + { 0x45f0, "ICLCLKOOR"}, /* Clear flag_clk_out_of_range , */\ + { 0x4600, "ICLTDMER"}, /* Clear tdm error , */\ + { 0x4610, "ICLCLPL"}, /* Clear clip left , */\ + { 0x4620, "ICLCLP"}, /* Clear clip , */\ + { 0x4630, "ICLOCPM"}, /* Clear mic ocpok , */\ + { 0x4650, "ICLLP1"}, /* Clear low power mode1 , */\ + { 0x4660, "ICLLA"}, /* Clear low amplitude detection , */\ + { 0x4670, "ICLVDDP"}, /* Clear VDDP greater then VBAT , */\ + { 0x4680, "ICLTAPDET"}, /* Clear Tap detected , */\ + { 0x4690, "ICLAUDMOD"}, /* Clear Audio Mode activated , */\ + { 0x46a0, "ICLSAMMOD"}, /* Clear SAM Mode activated , */\ + { 0x46b0, "ICLTAPMOD"}, /* Clear Tap Mode Activated , */\ + { 0x46c0, "ICLTAPTRG"}, /* Clear Comparator Interrupt , */\ + { 0x4800, "IEVDDS"}, /* Enable por , */\ + { 0x4810, "IEPLLS"}, /* Enable pll lock , */\ + { 0x4820, "IEOTDS"}, /* Enable OTP alarm , */\ + { 0x4830, "IEOVDS"}, /* Enable OVP alarm , */\ + { 0x4840, "IEUVDS"}, /* Enable UVP alarm , */\ + { 0x4850, "IECLKS"}, /* Enable clocks stable , */\ + { 0x4860, "IEMTPB"}, /* Enable mtp busy , */\ + { 0x4870, "IENOCLK"}, /* Enable lost clk , */\ + { 0x4880, "IESPKS"}, /* Enable speaker error , */\ + { 0x4890, "IEACS"}, /* Enable cold started , */\ + { 0x48a0, "IESWS"}, /* Enable amplifier engage , */\ + { 0x48b0, "IEWDS"}, /* Enable watchdog , */\ + { 0x48c0, "IEAMPS"}, /* Enable enbl amp , */\ + { 0x48d0, "IEAREFS"}, /* Enable ref enable , */\ + { 0x48e0, "IEADCCR"}, /* Enable Control ADC , */\ + { 0x48f0, "IEBODNOK"}, /* Enable BOD , */\ + { 0x4900, "IEBSTCU"}, /* Enable DCDC current limiting , */\ + { 0x4910, "IEBSTHI"}, /* Enable DCDC active , */\ + { 0x4920, "IEBSTOC"}, /* Enable DCDC OCP , */\ + { 0x4930, "IEBSTPC"}, /* Enable bst peakcur , */\ + { 0x4940, "IEBSTVC"}, /* Enable DCDC level 1x , */\ + { 0x4950, "IEBST86"}, /* Enable DCDC level 1.14x , */\ + { 0x4960, "IEBST93"}, /* Enable DCDC level 1.07x , */\ + { 0x4970, "IERCVLD"}, /* Enable rcvldop ready , */\ + { 0x4980, "IEOCPL"}, /* Enable ocp alarm left , */\ + { 0x4990, "IEOCPR"}, /* Enable ocp alarm , */\ + { 0x49a0, "IEMWSRC"}, /* Enable waits HW I2C settings , */\ + { 0x49b0, "IEMWCFC"}, /* Enable man wait cf config , */\ + { 0x49c0, "IEMWSMU"}, /* Enable man Audio mute sequence , */\ + { 0x49d0, "IECFMER"}, /* Enable cfma err , */\ + { 0x49e0, "IECFMAC"}, /* Enable cfma ack , */\ + { 0x49f0, "IECLKOOR"}, /* Enable flag_clk_out_of_range , */\ + { 0x4a00, "IETDMER"}, /* Enable tdm error , */\ + { 0x4a10, "IECLPL"}, /* Enable clip left , */\ + { 0x4a20, "IECLPR"}, /* Enable clip , */\ + { 0x4a30, "IEOCPM1"}, /* Enable mic ocpok , */\ + { 0x4a50, "IELP1"}, /* Enable low power mode1 , */\ + { 0x4a60, "IELA"}, /* Enable low amplitude detection , */\ + { 0x4a70, "IEVDDP"}, /* Enable VDDP greater than VBAT , */\ + { 0x4a80, "IETAPDET"}, /* Enable Tap detected , */\ + { 0x4a90, "IEAUDMOD"}, /* Enable Audio Mode activated , */\ + { 0x4aa0, "IESAMMOD"}, /* Enable SAM Mode activated , */\ + { 0x4ab0, "IETAPMOD"}, /* Enable Tap Mode Activated , */\ + { 0x4ac0, "IETAPTRG"}, /* Enable comparator interrupt , */\ + { 0x4c00, "IPOVDDS"}, /* Polarity por , */\ + { 0x4c10, "IPOPLLS"}, /* Polarity pll lock , */\ + { 0x4c20, "IPOOTDS"}, /* Polarity OTP alarm , */\ + { 0x4c30, "IPOOVDS"}, /* Polarity OVP alarm , */\ + { 0x4c40, "IPOUVDS"}, /* Polarity UVP alarm , */\ + { 0x4c50, "IPOCLKS"}, /* Polarity clocks stable , */\ + { 0x4c60, "IPOMTPB"}, /* Polarity mtp busy , */\ + { 0x4c70, "IPONOCLK"}, /* Polarity lost clk , */\ + { 0x4c80, "IPOSPKS"}, /* Polarity speaker error , */\ + { 0x4c90, "IPOACS"}, /* Polarity cold started , */\ + { 0x4ca0, "IPOSWS"}, /* Polarity amplifier engage , */\ + { 0x4cb0, "IPOWDS"}, /* Polarity watchdog , */\ + { 0x4cc0, "IPOAMPS"}, /* Polarity enbl amp , */\ + { 0x4cd0, "IPOAREFS"}, /* Polarity ref enable , */\ + { 0x4ce0, "IPOADCCR"}, /* Polarity Control ADC , */\ + { 0x4cf0, "IPOBODNOK"}, /* Polarity BOD , */\ + { 0x4d00, "IPOBSTCU"}, /* Polarity DCDC current limiting , */\ + { 0x4d10, "IPOBSTHI"}, /* Polarity DCDC active , */\ + { 0x4d20, "IPOBSTOC"}, /* Polarity DCDC OCP , */\ + { 0x4d30, "IPOBSTPC"}, /* Polarity bst peakcur , */\ + { 0x4d40, "IPOBSTVC"}, /* Polarity DCDC level 1x , */\ + { 0x4d50, "IPOBST86"}, /* Polarity DCDC level 1.14x , */\ + { 0x4d60, "IPOBST93"}, /* Polarity DCDC level 1.07x , */\ + { 0x4d70, "IPORCVLD"}, /* Polarity rcvldop ready , */\ + { 0x4d80, "IPOOCPL"}, /* Polarity ocp alarm left , */\ + { 0x4d90, "IPOOCPR"}, /* Polarity ocp alarm , */\ + { 0x4da0, "IPOMWSRC"}, /* Polarity waits HW I2C settings , */\ + { 0x4db0, "IPOMWCFC"}, /* Polarity man wait cf config , */\ + { 0x4dc0, "IPOMWSMU"}, /* Polarity man audio mute sequence , */\ + { 0x4dd0, "IPOCFMER"}, /* Polarity cfma err , */\ + { 0x4de0, "IPOCFMAC"}, /* Polarity cfma ack , */\ + { 0x4df0, "IPOCLKOOR"}, /* Polarity flag_clk_out_of_range , */\ + { 0x4e00, "IPOTDMER"}, /* Polarity tdm error , */\ + { 0x4e10, "IPOCLPL"}, /* Polarity clip left , */\ + { 0x4e20, "IPOCLPR"}, /* Polarity clip , */\ + { 0x4e30, "IPOOCPM"}, /* Polarity mic ocpok , */\ + { 0x4e50, "IPOLP1"}, /* Polarity low power mode1 , */\ + { 0x4e60, "IPOLA"}, /* Polarity low amplitude detection , */\ + { 0x4e70, "IPOVDDP"}, /* Polarity VDDP greater than VBAT , */\ + { 0x4e80, "IPOLTAPDET"}, /* PolarityTap detected , */\ + { 0x4e90, "IPOLAUDMOD"}, /* PolarityAudio Mode activated , */\ + { 0x4ea0, "IPOLSAMMOD"}, /* PolaritySAM Mode activated , */\ + { 0x4eb0, "IPOLTAPMOD"}, /* Polarity Tap Mode Activated , */\ + { 0x4ec0, "IPOLTAPTRG"}, /* PolarityTap Comparator Trigger , */\ + { 0x5001, "BSSCR"}, /* Battery Safeguard attack time , */\ + { 0x5023, "BSST"}, /* Battery Safeguard threshold voltage level , */\ + { 0x5061, "BSSRL"}, /* Battery Safeguard maximum reduction , */\ + { 0x5082, "BSSRR"}, /* Battery Safeguard release time , */\ + { 0x50b1, "BSSHY"}, /* Battery Safeguard hysteresis , */\ + { 0x50d0, "BSSAC"}, /* Reset clipper - Auto clear , */\ + { 0x50e0, "BSSR"}, /* Battery voltage read out , */\ + { 0x50f0, "BSSBY"}, /* Bypass HW clipper , */\ + { 0x5100, "BSSS"}, /* Vbat prot steepness , */\ + { 0x5110, "INTSMUTE"}, /* Soft mute HW , */\ + { 0x5120, "CFSML"}, /* Soft mute FW left , */\ + { 0x5130, "CFSM"}, /* Soft mute FW , */\ + { 0x5140, "HPFBYPL"}, /* Bypass HPF left , */\ + { 0x5150, "HPFBYP"}, /* Bypass HPF , */\ + { 0x5160, "DPSAL"}, /* Enable DPSA left , */\ + { 0x5170, "DPSA"}, /* Enable DPSA , */\ + { 0x5187, "VOL"}, /* FW volume control for primary audio channel , */\ + { 0x5200, "HNDSFRCV"}, /* Selection receiver , */\ + { 0x5222, "CLIPCTRL"}, /* Clip control setting , */\ + { 0x5257, "AMPGAIN"}, /* Amplifier gain , */\ + { 0x52d0, "SLOPEE"}, /* Enables slope control , */\ + { 0x52e0, "SLOPESET"}, /* Slope speed setting (bin. coded) , */\ + { 0x5c07, "CFTAPPAT"}, /* Coolflux tap pattern , */\ + { 0x5c83, "TAPDBGINFO"}, /* Reserved , */\ + { 0x5d0f, "TATPSTAT1"}, /* Tap Status 1 from CF FW , */\ + { 0x5f03, "TCOMPTHR"}, /* Comparator threshold (in uV) , */\ + { 0x6081, "PGAGAIN"}, /* PGA gain selection , */\ + { 0x6123, "TDMSPKG"}, /* System gain (INPLEV 0) , */\ + { 0x6505, "LPM1LVL"}, /* low power mode1 detector ctrl threshold for low_audio_lvl , */\ + { 0x6565, "LPM1HLD"}, /* Low power mode1 detector, ctrl hold time before low audio is reckoned to be low audio, */\ + { 0x65c0, "LPM1DIS"}, /* low power mode1 detector control , */\ + { 0x6630, "DCDIS"}, /* DCDC , */\ + { 0x6801, "TDMSRCMAP"}, /* tdm source mapping , */\ + { 0x6821, "TDMSRCAS"}, /* frame a selection , */\ + { 0x6841, "TDMSRCBS"}, /* frame b selection , */\ + { 0x68a0, "ANC1C"}, /* ANC one s complement , */\ + { 0x6901, "SAMMODE"}, /* Sam mode , */\ + { 0x7033, "DCMCC"}, /* Max coil current , */\ + { 0x7071, "DCCV"}, /* Slope compensation current, represents LxF (inductance x frequency) value , */\ + { 0x7090, "DCIE"}, /* Adaptive boost mode , */\ + { 0x70a0, "DCSR"}, /* Soft ramp up/down , */\ + { 0x70c1, "DCINSEL"}, /* DCDC IIR input Selection , */\ + { 0x70f0, "DCPWM"}, /* DCDC PWM only mode , */\ + { 0x7504, "DCTRIP"}, /* Adaptive boost trip levels 1, effective only when boost_intelligent is set to 1, */\ + { 0x7554, "DCTRIP2"}, /* Adaptive boost trip level 2, effective only when boost_intelligent is set to 1, */\ + { 0x75a4, "DCTRIPT"}, /* Adaptive boost trip levels, effective only when boost_intelligent is set to 1, */\ + { 0x7635, "DCVOF"}, /* First boost voltage level , */\ + { 0x7695, "DCVOS"}, /* Second boost voltage level , */\ + { 0x9000, "RST"}, /* Reset , */\ + { 0x9011, "DMEM"}, /* Target memory , */\ + { 0x9030, "AIF"}, /* Auto increment , */\ + { 0x9040, "CFINT"}, /* Interrupt - auto clear , */\ + { 0x9050, "CFCGATE"}, /* Coolflux clock gating disabling control , */\ + { 0x9080, "REQCMD"}, /* Firmware event request rpc command , */\ + { 0x9090, "REQRST"}, /* Firmware event request reset restart , */\ + { 0x90a0, "REQMIPS"}, /* Firmware event request short on mips , */\ + { 0x90b0, "REQMUTED"}, /* Firmware event request mute sequence ready , */\ + { 0x90c0, "REQVOL"}, /* Firmware event request volume ready , */\ + { 0x90d0, "REQDMG"}, /* Firmware event request speaker damage detected , */\ + { 0x90e0, "REQCAL"}, /* Firmware event request calibration completed , */\ + { 0x90f0, "REQRSV"}, /* Firmware event request reserved , */\ + { 0x910f, "MADD"}, /* Memory address , */\ + { 0x920f, "MEMA"}, /* Activate memory access , */\ + { 0x9307, "ERR"}, /* Error flags , */\ + { 0x9380, "ACKCMD"}, /* Firmware event acknowledge rpc command , */\ + { 0x9390, "ACKRST"}, /* Firmware event acknowledge reset restart , */\ + { 0x93a0, "ACKMIPS"}, /* Firmware event acknowledge short on mips , */\ + { 0x93b0, "ACKMUTED"}, /* Firmware event acknowledge mute sequence ready , */\ + { 0x93c0, "ACKVOL"}, /* Firmware event acknowledge volume ready , */\ + { 0x93d0, "ACKDMG"}, /* Firmware event acknowledge speaker damage detected, */\ + { 0x93e0, "ACKCAL"}, /* Firmware event acknowledge calibration completed , */\ + { 0x93f0, "ACKRSV"}, /* Firmware event acknowledge reserved , */\ + { 0xa107, "MTPK"}, /* MTP KEY2 register , */\ + { 0xa200, "KEY1LOCKED"}, /* Indicates KEY1 is locked , */\ + { 0xa210, "KEY2LOCKED"}, /* Indicates KEY2 is locked , */\ + { 0xa360, "CIMTP"}, /* Start copying data from I2C mtp registers to mtp , */\ + { 0xa50f, "MTPRDMSB"}, /* MSB word of MTP manual read data , */\ + { 0xa60f, "MTPRDLSB"}, /* LSB word of MTP manual read data , */\ + { 0xb108, "EXTTS"}, /* External temperature (C) , */\ + { 0xb190, "TROS"}, /* Select temp Speaker calibration , */\ + { 0xee0f, "SWPROFIL"}, /* Software profile data , */\ + { 0xef0f, "SWVSTEP"}, /* Software vstep information , */\ + { 0xf000, "MTPOTC"}, /* Calibration schedule , */\ + { 0xf010, "MTPEX"}, /* Calibration Ron executed , */\ + { 0xf020, "DCMCCAPI"}, /* Calibration current limit DCDC , */\ + { 0xf030, "DCMCCSB"}, /* Sign bit for delta calibration current limit DCDC , */\ + { 0xf042, "DCMCCCL"}, /* Calibration delta current limit DCDC , */\ + { 0xf078, "USERDEF"}, /* Reserved space for allowing customer to store speaker information, */\ + { 0xf40f, "R25C"}, /* Ron resistance of speaker coil , */\ + { 0xffff,"Unknown bitfield enum" } /* not found */\ +}; + +#define TFA9912_BITNAMETABLE static tfaBfName_t Tfa9912BitNames[]= {\ + { 0x0, "powerdown"}, /* Powerdown selection , */\ + { 0x10, "reset"}, /* I2C Reset - Auto clear , */\ + { 0x20, "enbl_coolflux"}, /* Enable CoolFlux , */\ + { 0x30, "enbl_amplifier"}, /* Enables the Amplifier , */\ + { 0x40, "enbl_boost"}, /* Activate DC-to-DC converter , */\ + { 0x50, "coolflux_configured"}, /* Coolflux configured , */\ + { 0x60, "sel_enbl_amplifier"}, /* CoolFlux controls amplifier , */\ + { 0x71, "int_pad_io"}, /* Interrupt config , */\ + { 0x90, "fs_pulse_sel"}, /* Audio sample reference , */\ + { 0xb0, "bypass_ocp"}, /* Bypass OCP , */\ + { 0xc0, "test_ocp"}, /* OCP testing control , */\ + { 0x101, "vamp_sel"}, /* Amplifier input selection , */\ + { 0x120, "src_set_configured"}, /* I2C configured , */\ + { 0x130, "execute_cold_start"}, /* Execute cold start , */\ + { 0x140, "enbl_fro8m_auto_off"}, /* Internal osc off at PWDN , */\ + { 0x150, "man_enbl_brown_out"}, /* Reaction on BOD , */\ + { 0x160, "enbl_bod"}, /* BOD Enable , */\ + { 0x170, "enbl_bod_hyst"}, /* BOD Hysteresis , */\ + { 0x181, "bod_delay"}, /* BOD filter , */\ + { 0x1a1, "bod_lvlsel"}, /* BOD threshold , */\ + { 0x1d0, "disable_mute_time_out"}, /* Time out SB mute sequence , */\ + { 0x1e0, "pwm_sel_rcv_ns"}, /* Noise shaper selection , */\ + { 0x1f0, "man_enbl_watchdog"}, /* Watchdog enable , */\ + { 0x203, "audio_fs"}, /* Sample rate (fs) , */\ + { 0x240, "input_level"}, /* TDM output attenuation , */\ + { 0x255, "cs_frac_delay"}, /* V/I Fractional delay , */\ + { 0x2b0, "bypass_hvbat_filter"}, /* Bypass HVBAT filter , */\ + { 0x2c0, "tdm_tfa9872_compatible"}, /* TDM Compatibility with TFA9872 , */\ + { 0x2d0, "sel_hysteresis"}, /* Select hysteresis for clock range detector , */\ + { 0x2e0, "enbl_adc10"}, /* ADC10 Enable - I2C direct mode , */\ + { 0x30f, "device_rev"}, /* Revision info , */\ + { 0x401, "pll_clkin_sel"}, /* PLL external ref clock , */\ + { 0x420, "pll_clkin_sel_osc"}, /* PLL internal ref clock , */\ + { 0x430, "cf_clock_scaling"}, /* Coolflux DSP clock scaling, low power mode , */\ + { 0x441, "sel_cf_clock"}, /* Coolflux DSP clock scaler selection for low power mode, */\ + { 0x460, "tdm_intf_sel"}, /* TDM clock selection , */\ + { 0x470, "disable_auto_sel_refclk"}, /* Disable Automatic dsp clock source selection , */\ + { 0x480, "sel_clk_src"}, /* I2C selection of DSP clock when auto select is disabled, */\ + { 0x490, "wdt_tim_clk_src"}, /* I2C selection of Watchdog and Timer clock , */\ + { 0x510, "enbl_spkr_ss"}, /* Enable speaker path , */\ + { 0x530, "enbl_volsense"}, /* Voltage sense , */\ + { 0x550, "enbl_cursense"}, /* Current sense , */\ + { 0x560, "enbl_pdm_ss"}, /* Sub-system PDM , */\ + { 0x580, "enbl_pga_chop"}, /* Enable PGA chop clock , */\ + { 0x590, "enbl_tdm_ss"}, /* Sub-system TDM , */\ + { 0x5a0, "enbl_bst_ss"}, /* Sub-system boost , */\ + { 0x5b0, "enbl_adc10_ss"}, /* Sub-system ADC , */\ + { 0x5c0, "enbl_faim_ss"}, /* Sub-system FAIM , */\ + { 0x5d0, "enbl_tim_clk"}, /* CF Sub-system timer , */\ + { 0x5e0, "enbl_wdt_clk"}, /* CF Sub-system WDT , */\ + { 0x5f0, "faim_enable_vbg"}, /* Over rule of vbg for FaIM access , */\ + { 0x600, "aux_spkr_sel"}, /* Input selection for TAP/SAM , */\ + { 0x620, "bypass_tapdec_reset"}, /* Tap decimator reset bypass - Bypass the decimator reset from tapdec, */\ + { 0x631, "car_dec_in_sel0"}, /* Cardec input 0 sel , */\ + { 0x651, "car_dec_in_sel1"}, /* Cardec input sel , */\ + { 0x670, "tapdec_sel"}, /* Select TAP/Cardec for TAP , */\ + { 0x680, "comp_count"}, /* Comparator o/p filter selection , */\ + { 0x691, "startup_mode"}, /* Startup Mode Selection , */\ + { 0x6b0, "enable_auto_tap_switching"}, /* Enable auto tap switching , */\ + { 0x6c1, "comp_init_time"}, /* Comparator initialization time to be used in Tap Machine, */\ + { 0x6e1, "ana_init_time"}, /* Analog initialization time to be used in Tap Machine, */\ + { 0x707, "clkchk_th_hi"}, /* Clock check Higher Threshold , */\ + { 0x787, "clkchk_th_lo"}, /* Clock check Higher Threshold , */\ + { 0x802, "ctrl_on2off_criterion"}, /* Amplifier on-off criteria for shutdown , */\ + { 0x832, "ctrl_on2tap_criterion"}, /* Amplifier on-off criteria for tap mode entry , */\ + { 0xd00, "side_tone_gain_sel"}, /* PDM side tone gain selector , */\ + { 0xd18, "side_tone_gain"}, /* Side tone gain , */\ + { 0xda0, "mute_side_tone"}, /* Side tone soft mute , */\ + { 0xdb0, "side_tone_1scomplement"}, /* side tone one s complement , */\ + { 0xe07, "ctrl_digtoana"}, /* Spare control from digital to analog , */\ + { 0xf0f, "hidden_code"}, /* 5A6Bh, 23147d to access registers (default for engineering), */\ + { 0x1000, "flag_por"}, /* POR , */\ + { 0x1010, "flag_pll_lock"}, /* PLL lock , */\ + { 0x1020, "flag_otpok"}, /* OTP alarm , */\ + { 0x1030, "flag_ovpok"}, /* OVP alarm , */\ + { 0x1040, "flag_uvpok"}, /* UVP alarm , */\ + { 0x1050, "flag_clocks_stable"}, /* Clocks stable , */\ + { 0x1060, "flag_mtp_busy"}, /* MTP busy , */\ + { 0x1070, "flag_lost_clk"}, /* Lost clock , */\ + { 0x1090, "flag_cold_started"}, /* Cold Start , */\ + { 0x10a0, "flag_engage"}, /* Amplifier engage , */\ + { 0x10b0, "flag_watchdog_reset"}, /* Watchdog , */\ + { 0x10c0, "flag_enbl_amp"}, /* Amplifier enable , */\ + { 0x10d0, "flag_enbl_ref"}, /* References enable , */\ + { 0x10e0, "flag_adc10_ready"}, /* Control ADC , */\ + { 0x10f0, "flag_bod_vddd_nok"}, /* BOD , */\ + { 0x1100, "flag_bst_bstcur"}, /* DCDC current limiting , */\ + { 0x1110, "flag_bst_hiz"}, /* DCDC active , */\ + { 0x1120, "flag_bst_ocpok"}, /* DCDC OCP nmos , */\ + { 0x1130, "flag_bst_peakcur"}, /* Indicates current is max in DC-to-DC converter , */\ + { 0x1140, "flag_bst_voutcomp"}, /* DCDC level 1x , */\ + { 0x1150, "flag_bst_voutcomp86"}, /* DCDC level 1.14x , */\ + { 0x1160, "flag_bst_voutcomp93"}, /* DCDC level 1.07x , */\ + { 0x1170, "flag_soft_mute_busy"}, /* side tone (un)mute busy , */\ + { 0x1180, "flag_soft_mute_state"}, /* side tone mute state , */\ + { 0x1190, "flag_tdm_lut_error"}, /* TDM LUT error , */\ + { 0x11a2, "flag_tdm_status"}, /* TDM status bits , */\ + { 0x11d0, "flag_tdm_error"}, /* TDM error , */\ + { 0x1300, "flag_ocpokap"}, /* OCPOK pmos A , */\ + { 0x1310, "flag_ocpokan"}, /* OCPOK nmos A , */\ + { 0x1320, "flag_ocpokbp"}, /* OCPOK pmos B , */\ + { 0x1330, "flag_ocpokbn"}, /* OCPOK nmos B , */\ + { 0x1340, "flag_clipa_high"}, /* Clipping A to Vddp , */\ + { 0x1350, "flag_clipa_low"}, /* Clipping A to gnd , */\ + { 0x1360, "flag_clipb_high"}, /* Clipping B to Vddp , */\ + { 0x1370, "flag_clipb_low"}, /* Clipping B to gnd , */\ + { 0x1380, "flag_ocp_alarm"}, /* OCP amplifier , */\ + { 0x1390, "flag_clip"}, /* Amplifier clipping , */\ + { 0x13a0, "flag_tap_comp_trig"}, /* Status Tap comparator triggered , */\ + { 0x13b0, "flag_cf_tapdetected"}, /* Status Tap detected , */\ + { 0x13c0, "flag_man_wait_src_settings"}, /* Wait HW I2C settings , */\ + { 0x13d0, "flag_man_wait_cf_config"}, /* Wait CF config , */\ + { 0x13e0, "flag_man_start_mute_audio"}, /* Audio mute sequence , */\ + { 0x1410, "flag_cf_speakererror"}, /* Speaker status , */\ + { 0x1420, "flag_clk_out_of_range"}, /* External clock status , */\ + { 0x1433, "man_state"}, /* Device manager status , */\ + { 0x1471, "status_bst_mode"}, /* DCDC mode status bits , */\ + { 0x1490, "man_dsp_clk_src"}, /* DSP clock source selected by manager , */\ + { 0x14a1, "man_startup_mode"}, /* Startup Mode Selected by Manager(Read Only) , */\ + { 0x14c3, "tap_machine_state"}, /* Tap Machine State , */\ + { 0x1509, "bat_adc"}, /* Battery voltage (V) , */\ + { 0x1608, "temp_adc"}, /* IC Temperature (C) , */\ + { 0x1709, "vddp_adc"}, /* IC VDDP voltage ( 1023*VDDP/13 V) , */\ + { 0x17a0, "flag_bst_bstcur_cf"}, /* DCDC current limiting for DSP , */\ + { 0x2000, "tdm_usecase"}, /* Mode setting , */\ + { 0x2011, "dio4_input_sel"}, /* DIO4 Input selection , */\ + { 0x2040, "tdm_enable"}, /* Enable TDM interface , */\ + { 0x2060, "tdm_clk_inversion"}, /* Reception data to BCK clock , */\ + { 0x2073, "tdm_fs_ws_length"}, /* FS length , */\ + { 0x20b0, "tdm_fs_ws_polarity"}, /* FS polarity , */\ + { 0x20c3, "tdm_nbck"}, /* N-BCK's in FS , */\ + { 0x2103, "tdm_nb_of_slots"}, /* N-slots in Frame , */\ + { 0x2144, "tdm_slot_length"}, /* N-bits in slot , */\ + { 0x2194, "tdm_bits_remaining"}, /* N-bits remaining , */\ + { 0x21e0, "tdm_data_delay"}, /* data delay to FS , */\ + { 0x21f0, "tdm_data_adjustment"}, /* data adjustment , */\ + { 0x2201, "tdm_audio_sample_compression"}, /* Received audio compression , */\ + { 0x2224, "tdm_sample_size"}, /* Sample size per slot , */\ + { 0x2271, "tdm_txdata_format"}, /* Format unused bits in a slot , */\ + { 0x2291, "tdm_txdata_format_unused_slot_sd0"}, /* Format unused slots GAINIO , */\ + { 0x22b1, "tdm_txdata_format_unused_slot_sd1"}, /* Format unused slots DIO1 , */\ + { 0x22d1, "tdm_txdata_format_unused_slot_sd2"}, /* Format unused slots DIO2 , */\ + { 0x2300, "tdm_sink0_enable"}, /* Control gain (channel in 0) , */\ + { 0x2310, "tdm_sink1_enable"}, /* Control audio left (channel in 1 ) , */\ + { 0x2320, "tdm_sink2_enable"}, /* Control audio right (channel in 2 ) , */\ + { 0x2330, "tdm_source0_enable"}, /* Current sense , */\ + { 0x2340, "tdm_source1_enable"}, /* Voltage sense , */\ + { 0x2350, "tdm_source2_enable"}, /* DSP Gainout , */\ + { 0x2360, "tdm_source3_enable"}, /* DSP 2 , */\ + { 0x2370, "tdm_source4_enable"}, /* DSP 3 , */\ + { 0x2380, "tdm_source5_enable"}, /* DSP , */\ + { 0x2390, "tdm_source6_enable"}, /* Loopback of Audio left (channel 1) , */\ + { 0x23a0, "tdm_source7_enable"}, /* Loopback of Audio right (channel 2) , */\ + { 0x2401, "tdm_sink0_io"}, /* IO gainin , */\ + { 0x2421, "tdm_sink1_io"}, /* IO audio left , */\ + { 0x2441, "tdm_sink2_io"}, /* IO audio right , */\ + { 0x2461, "tdm_source0_io"}, /* IO Current Sense , */\ + { 0x2481, "tdm_source1_io"}, /* IO voltage sense , */\ + { 0x24a1, "tdm_source2_io"}, /* IO gain out , */\ + { 0x24c1, "tdm_source3_io"}, /* IO DSP 2 , */\ + { 0x24e1, "tdm_source4_io"}, /* IO DSP 3 , */\ + { 0x2501, "tdm_source5_io"}, /* IO DSP , */\ + { 0x2521, "tdm_source6_io"}, /* IO Source 6 , */\ + { 0x2541, "tdm_source7_io"}, /* IO Source 7 , */\ + { 0x2603, "tdm_sink0_slot"}, /* Control gainin , */\ + { 0x2643, "tdm_sink1_slot"}, /* tdm slot for audio left (channel 1) , */\ + { 0x2683, "tdm_sink2_slot"}, /* tdm slot for audio right (channel 2) , */\ + { 0x26c3, "tdm_source0_slot"}, /* Slot Position of Current Sense Out , */\ + { 0x2703, "tdm_source1_slot"}, /* Slot Position of Voltage sense , */\ + { 0x2743, "tdm_source2_slot"}, /* Slot Position of GAIN out , */\ + { 0x2783, "tdm_source3_slot"}, /* Slot Position DSPout2 , */\ + { 0x27c3, "tdm_source4_slot"}, /* Slot Position DSPout3 , */\ + { 0x2803, "tdm_source5_slot"}, /* Slot Position of DSPout , */\ + { 0x2843, "tdm_source6_slot"}, /* Slot Position of loopback channel left , */\ + { 0x2883, "tdm_source7_slot"}, /* Slot Position of loopback channel right , */\ + { 0x2901, "tdm_txdata_format_unused_slot_sd3"}, /* Format unused slots D3 , */\ + { 0x3100, "pdm_mode"}, /* PDM control , */\ + { 0x3110, "pdm_input_sel"}, /* PDM Decimator input selection , */\ + { 0x3120, "enbl_pdm_side_tone"}, /* Side tone input enable , */\ + { 0x3201, "pdm_nbck"}, /* PDM BCK/Fs ratio , */\ + { 0x4000, "int_out_flag_por"}, /* Status POR , */\ + { 0x4010, "int_out_flag_pll_lock"}, /* Status PLL lock , */\ + { 0x4020, "int_out_flag_otpok"}, /* Status OTP alarm , */\ + { 0x4030, "int_out_flag_ovpok"}, /* Status OVP alarm , */\ + { 0x4040, "int_out_flag_uvpok"}, /* Status UVP alarm , */\ + { 0x4050, "int_out_flag_clocks_stable"}, /* Status clocks stable , */\ + { 0x4060, "int_out_flag_mtp_busy"}, /* Status MTP busy , */\ + { 0x4070, "int_out_flag_lost_clk"}, /* Status lost clock , */\ + { 0x4080, "int_out_flag_cf_speakererror"}, /* Status speaker error , */\ + { 0x4090, "int_out_flag_cold_started"}, /* Status cold start , */\ + { 0x40a0, "int_out_flag_engage"}, /* Status amplifier engage , */\ + { 0x40b0, "int_out_flag_watchdog_reset"}, /* Status watchdog , */\ + { 0x40c0, "int_out_flag_enbl_amp"}, /* Status amplifier enable , */\ + { 0x40d0, "int_out_flag_enbl_ref"}, /* Status Ref enable , */\ + { 0x40e0, "int_out_flag_adc10_ready"}, /* Status Control ADC , */\ + { 0x40f0, "int_out_flag_bod_vddd_nok"}, /* Status BOD , */\ + { 0x4100, "int_out_flag_bst_bstcur"}, /* Status DCDC current limiting , */\ + { 0x4110, "int_out_flag_bst_hiz"}, /* Status DCDC active , */\ + { 0x4120, "int_out_flag_bst_ocpok"}, /* Status DCDC OCP , */\ + { 0x4130, "int_out_flag_bst_peakcur"}, /* Status bst peakcur , */\ + { 0x4140, "int_out_flag_bst_voutcomp"}, /* Status DCDC level 1x , */\ + { 0x4150, "int_out_flag_bst_voutcomp86"}, /* Status DCDC level 1.14x , */\ + { 0x4160, "int_out_flag_bst_voutcomp93"}, /* Status DCDC level 1.07x , */\ + { 0x4190, "int_out_flag_ocp_alarm"}, /* Status ocp alarm , */\ + { 0x41a0, "int_out_flag_man_wait_src_settings"}, /* Status Waits HW I2C settings , */\ + { 0x41b0, "int_out_flag_man_wait_cf_config"}, /* Status waits CF config , */\ + { 0x41c0, "int_out_flag_man_start_mute_audio"}, /* Status Audio mute sequence , */\ + { 0x41d0, "int_out_flag_cfma_err"}, /* Status cfma error , */\ + { 0x41e0, "int_out_flag_cfma_ack"}, /* Status cfma ack , */\ + { 0x41f0, "int_out_flag_clk_out_of_range"}, /* Status flag_clk_out_of_range , */\ + { 0x4200, "int_out_flag_tdm_error"}, /* Status tdm error , */\ + { 0x4220, "int_out_flag_clip"}, /* Status clip , */\ + { 0x4250, "int_out_flag_lp_detect_mode1"}, /* Status low power mode1 , */\ + { 0x4260, "int_out_flag_low_amplitude"}, /* Status low amplitude detection , */\ + { 0x4270, "int_out_flag_vddp_gt_vbat"}, /* Status VDDP greater than VBAT , */\ + { 0x4280, "int_out_newtap"}, /* Status Tap detected , */\ + { 0x4290, "int_out_audiomodeactive"}, /* Status Audio Mode activated , */\ + { 0x42a0, "int_out_sammodeactive"}, /* Status SAM Mode activated , */\ + { 0x42b0, "int_out_tapmodeactive"}, /* Status Tap Mode Activated , */\ + { 0x42c0, "int_out_flag_tap_comp_trig"}, /* Status Tap comparator triggered , */\ + { 0x4400, "int_in_flag_por"}, /* Clear POR , */\ + { 0x4410, "int_in_flag_pll_lock"}, /* Clear PLL lock , */\ + { 0x4420, "int_in_flag_otpok"}, /* Clear OTP alarm , */\ + { 0x4430, "int_in_flag_ovpok"}, /* Clear OVP alarm , */\ + { 0x4440, "int_in_flag_uvpok"}, /* Clear UVP alarm , */\ + { 0x4450, "int_in_flag_clocks_stable"}, /* Clear clocks stable , */\ + { 0x4460, "int_in_flag_mtp_busy"}, /* Clear mtp busy , */\ + { 0x4470, "int_in_flag_lost_clk"}, /* Clear lost clk , */\ + { 0x4480, "int_in_flag_cf_speakererror"}, /* Clear speaker error , */\ + { 0x4490, "int_in_flag_cold_started"}, /* Clear cold started , */\ + { 0x44a0, "int_in_flag_engage"}, /* Clear amplifier engage , */\ + { 0x44b0, "int_in_flag_watchdog_reset"}, /* Clear watchdog , */\ + { 0x44c0, "int_in_flag_enbl_amp"}, /* Clear enbl amp , */\ + { 0x44d0, "int_in_flag_enbl_ref"}, /* Clear ref enable , */\ + { 0x44e0, "int_in_flag_adc10_ready"}, /* Clear control ADC , */\ + { 0x44f0, "int_in_flag_bod_vddd_nok"}, /* Clear BOD , */\ + { 0x4500, "int_in_flag_bst_bstcur"}, /* Clear DCDC current limiting , */\ + { 0x4510, "int_in_flag_bst_hiz"}, /* Clear DCDC active , */\ + { 0x4520, "int_in_flag_bst_ocpok"}, /* Clear DCDC OCP , */\ + { 0x4530, "int_in_flag_bst_peakcur"}, /* Clear bst peakcur , */\ + { 0x4540, "int_in_flag_bst_voutcomp"}, /* Clear DCDC level 1x , */\ + { 0x4550, "int_in_flag_bst_voutcomp86"}, /* Clear DCDC level 1.14x , */\ + { 0x4560, "int_in_flag_bst_voutcomp93"}, /* Clear DCDC level 1.07x , */\ + { 0x4590, "int_in_flag_ocp_alarm"}, /* Clear ocp alarm , */\ + { 0x45a0, "int_in_flag_man_wait_src_settings"}, /* Clear wait HW I2C settings , */\ + { 0x45b0, "int_in_flag_man_wait_cf_config"}, /* Clear wait cf config , */\ + { 0x45c0, "int_in_flag_man_start_mute_audio"}, /* Clear audio mute sequence , */\ + { 0x45d0, "int_in_flag_cfma_err"}, /* Clear cfma err , */\ + { 0x45e0, "int_in_flag_cfma_ack"}, /* Clear cfma ack , */\ + { 0x45f0, "int_in_flag_clk_out_of_range"}, /* Clear flag_clk_out_of_range , */\ + { 0x4600, "int_in_flag_tdm_error"}, /* Clear tdm error , */\ + { 0x4620, "int_in_flag_clip"}, /* Clear clip , */\ + { 0x4650, "int_in_flag_lp_detect_mode1"}, /* Clear low power mode1 , */\ + { 0x4660, "int_in_flag_low_amplitude"}, /* Clear low amplitude detection , */\ + { 0x4670, "int_in_flag_vddp_gt_vbat"}, /* Clear VDDP greater then VBAT , */\ + { 0x4680, "int_in_newtap"}, /* Clear Tap detected , */\ + { 0x4690, "int_in_audiomodeactive"}, /* Clear Audio Mode activated , */\ + { 0x46a0, "int_in_sammodeactive"}, /* Clear SAM Mode activated , */\ + { 0x46b0, "int_in_tapmodeactive"}, /* Clear Tap Mode Activated , */\ + { 0x46c0, "int_in_flag_tap_comp_trig"}, /* Clear Comparator Interrupt , */\ + { 0x4800, "int_enable_flag_por"}, /* Enable por , */\ + { 0x4810, "int_enable_flag_pll_lock"}, /* Enable pll lock , */\ + { 0x4820, "int_enable_flag_otpok"}, /* Enable OTP alarm , */\ + { 0x4830, "int_enable_flag_ovpok"}, /* Enable OVP alarm , */\ + { 0x4840, "int_enable_flag_uvpok"}, /* Enable UVP alarm , */\ + { 0x4850, "int_enable_flag_clocks_stable"}, /* Enable clocks stable , */\ + { 0x4860, "int_enable_flag_mtp_busy"}, /* Enable mtp busy , */\ + { 0x4870, "int_enable_flag_lost_clk"}, /* Enable lost clk , */\ + { 0x4880, "int_enable_flag_cf_speakererror"}, /* Enable speaker error , */\ + { 0x4890, "int_enable_flag_cold_started"}, /* Enable cold started , */\ + { 0x48a0, "int_enable_flag_engage"}, /* Enable amplifier engage , */\ + { 0x48b0, "int_enable_flag_watchdog_reset"}, /* Enable watchdog , */\ + { 0x48c0, "int_enable_flag_enbl_amp"}, /* Enable enbl amp , */\ + { 0x48d0, "int_enable_flag_enbl_ref"}, /* Enable ref enable , */\ + { 0x48e0, "int_enable_flag_adc10_ready"}, /* Enable Control ADC , */\ + { 0x48f0, "int_enable_flag_bod_vddd_nok"}, /* Enable BOD , */\ + { 0x4900, "int_enable_flag_bst_bstcur"}, /* Enable DCDC current limiting , */\ + { 0x4910, "int_enable_flag_bst_hiz"}, /* Enable DCDC active , */\ + { 0x4920, "int_enable_flag_bst_ocpok"}, /* Enable DCDC OCP , */\ + { 0x4930, "int_enable_flag_bst_peakcur"}, /* Enable bst peakcur , */\ + { 0x4940, "int_enable_flag_bst_voutcomp"}, /* Enable DCDC level 1x , */\ + { 0x4950, "int_enable_flag_bst_voutcomp86"}, /* Enable DCDC level 1.14x , */\ + { 0x4960, "int_enable_flag_bst_voutcomp93"}, /* Enable DCDC level 1.07x , */\ + { 0x4990, "int_enable_flag_ocp_alarm"}, /* Enable ocp alarm , */\ + { 0x49a0, "int_enable_flag_man_wait_src_settings"}, /* Enable waits HW I2C settings , */\ + { 0x49b0, "int_enable_flag_man_wait_cf_config"}, /* Enable man wait cf config , */\ + { 0x49c0, "int_enable_flag_man_start_mute_audio"}, /* Enable man Audio mute sequence , */\ + { 0x49d0, "int_enable_flag_cfma_err"}, /* Enable cfma err , */\ + { 0x49e0, "int_enable_flag_cfma_ack"}, /* Enable cfma ack , */\ + { 0x49f0, "int_enable_flag_clk_out_of_range"}, /* Enable flag_clk_out_of_range , */\ + { 0x4a00, "int_enable_flag_tdm_error"}, /* Enable tdm error , */\ + { 0x4a20, "int_enable_flag_clip"}, /* Enable clip , */\ + { 0x4a50, "int_enable_flag_lp_detect_mode1"}, /* Enable low power mode1 , */\ + { 0x4a60, "int_enable_flag_low_amplitude"}, /* Enable low amplitude detection , */\ + { 0x4a70, "int_enable_flag_vddp_gt_vbat"}, /* Enable VDDP greater than VBAT , */\ + { 0x4a80, "int_enable_newtap"}, /* Enable Tap detected , */\ + { 0x4a90, "int_enable_audiomodeactive"}, /* Enable Audio Mode activated , */\ + { 0x4aa0, "int_enable_sammodeactive"}, /* Enable SAM Mode activated , */\ + { 0x4ab0, "int_enable_tapmodeactive"}, /* Enable Tap Mode Activated , */\ + { 0x4ac0, "int_enable_flag_tap_comp_trig"}, /* Enable comparator interrupt , */\ + { 0x4c00, "int_polarity_flag_por"}, /* Polarity por , */\ + { 0x4c10, "int_polarity_flag_pll_lock"}, /* Polarity pll lock , */\ + { 0x4c20, "int_polarity_flag_otpok"}, /* Polarity OTP alarm , */\ + { 0x4c30, "int_polarity_flag_ovpok"}, /* Polarity OVP alarm , */\ + { 0x4c40, "int_polarity_flag_uvpok"}, /* Polarity UVP alarm , */\ + { 0x4c50, "int_polarity_flag_clocks_stable"}, /* Polarity clocks stable , */\ + { 0x4c60, "int_polarity_flag_mtp_busy"}, /* Polarity mtp busy , */\ + { 0x4c70, "int_polarity_flag_lost_clk"}, /* Polarity lost clk , */\ + { 0x4c80, "int_polarity_flag_cf_speakererror"}, /* Polarity speaker error , */\ + { 0x4c90, "int_polarity_flag_cold_started"}, /* Polarity cold started , */\ + { 0x4ca0, "int_polarity_flag_engage"}, /* Polarity amplifier engage , */\ + { 0x4cb0, "int_polarity_flag_watchdog_reset"}, /* Polarity watchdog , */\ + { 0x4cc0, "int_polarity_flag_enbl_amp"}, /* Polarity enbl amp , */\ + { 0x4cd0, "int_polarity_flag_enbl_ref"}, /* Polarity ref enable , */\ + { 0x4ce0, "int_polarity_flag_adc10_ready"}, /* Polarity Control ADC , */\ + { 0x4cf0, "int_polarity_flag_bod_vddd_nok"}, /* Polarity BOD , */\ + { 0x4d00, "int_polarity_flag_bst_bstcur"}, /* Polarity DCDC current limiting , */\ + { 0x4d10, "int_polarity_flag_bst_hiz"}, /* Polarity DCDC active , */\ + { 0x4d20, "int_polarity_flag_bst_ocpok"}, /* Polarity DCDC OCP , */\ + { 0x4d30, "int_polarity_flag_bst_peakcur"}, /* Polarity bst peakcur , */\ + { 0x4d40, "int_polarity_flag_bst_voutcomp"}, /* Polarity DCDC level 1x , */\ + { 0x4d50, "int_polarity_flag_bst_voutcomp86"}, /* Polarity DCDC level 1.14x , */\ + { 0x4d60, "int_polarity_flag_bst_voutcomp93"}, /* Polarity DCDC level 1.07x , */\ + { 0x4d90, "int_polarity_flag_ocp_alarm"}, /* Polarity ocp alarm , */\ + { 0x4da0, "int_polarity_flag_man_wait_src_settings"}, /* Polarity waits HW I2C settings , */\ + { 0x4db0, "int_polarity_flag_man_wait_cf_config"}, /* Polarity man wait cf config , */\ + { 0x4dc0, "int_polarity_flag_man_start_mute_audio"}, /* Polarity man audio mute sequence , */\ + { 0x4dd0, "int_polarity_flag_cfma_err"}, /* Polarity cfma err , */\ + { 0x4de0, "int_polarity_flag_cfma_ack"}, /* Polarity cfma ack , */\ + { 0x4df0, "int_polarity_flag_clk_out_of_range"}, /* Polarity flag_clk_out_of_range , */\ + { 0x4e00, "int_polarity_flag_tdm_error"}, /* Polarity tdm error , */\ + { 0x4e20, "int_polarity_flag_clip"}, /* Polarity clip , */\ + { 0x4e50, "int_polarity_flag_lp_detect_mode1"}, /* Polarity low power mode1 , */\ + { 0x4e60, "int_polarity_flag_low_amplitude"}, /* Polarity low amplitude detection , */\ + { 0x4e70, "int_polarity_flag_vddp_gt_vbat"}, /* Polarity VDDP greater than VBAT , */\ + { 0x4e80, "int_polarity_newtap"}, /* PolarityTap detected , */\ + { 0x4e90, "int_polarity_audiomodeactive"}, /* PolarityAudio Mode activated , */\ + { 0x4ea0, "int_polarity_sammodeactive"}, /* PolaritySAM Mode activated , */\ + { 0x4eb0, "int_polarity_tapmodeactive"}, /* Polarity Tap Mode Activated , */\ + { 0x4ec0, "int_polarity_flag_tap_comp_trig"}, /* PolarityTap Comparator Trigger , */\ + { 0x5001, "vbat_prot_attack_time"}, /* Battery Safeguard attack time , */\ + { 0x5023, "vbat_prot_thlevel"}, /* Battery Safeguard threshold voltage level , */\ + { 0x5061, "vbat_prot_max_reduct"}, /* Battery Safeguard maximum reduction , */\ + { 0x5082, "vbat_prot_release_time"}, /* Battery Safeguard release time , */\ + { 0x50b1, "vbat_prot_hysterese"}, /* Battery Safeguard hysteresis , */\ + { 0x50d0, "rst_min_vbat"}, /* Reset clipper - Auto clear , */\ + { 0x50e0, "sel_vbat"}, /* Battery voltage read out , */\ + { 0x50f0, "bypass_clipper"}, /* Bypass HW clipper , */\ + { 0x5100, "batsense_steepness"}, /* Vbat prot steepness , */\ + { 0x5110, "soft_mute"}, /* Soft mute HW , */\ + { 0x5130, "cf_mute"}, /* Soft mute FW , */\ + { 0x5150, "bypass_hp"}, /* Bypass HPF , */\ + { 0x5170, "enbl_dpsa"}, /* Enable DPSA , */\ + { 0x5187, "cf_volume"}, /* FW volume control for primary audio channel , */\ + { 0x5222, "ctrl_cc"}, /* Clip control setting , */\ + { 0x5257, "gain"}, /* Amplifier gain , */\ + { 0x52d0, "ctrl_slopectrl"}, /* Enables slope control , */\ + { 0x52e0, "ctrl_slope"}, /* Slope speed setting (bin. coded) , */\ + { 0x5301, "dpsa_level"}, /* DPSA threshold levels , */\ + { 0x5321, "dpsa_release"}, /* DPSA Release time , */\ + { 0x5340, "clipfast"}, /* Clock selection for HW clipper for Battery Safeguard, */\ + { 0x5350, "bypass_lp"}, /* Bypass the low power filter inside temperature sensor, */\ + { 0x5360, "enbl_low_latency"}, /* CF low latency outputs for add module , */\ + { 0x5400, "first_order_mode"}, /* Overrule to 1st order mode of control stage when clipping, */\ + { 0x5410, "bypass_ctrlloop"}, /* Switch amplifier into open loop configuration , */\ + { 0x5430, "icomp_engage"}, /* Engage of icomp , */\ + { 0x5440, "ctrl_kickback"}, /* Prevent double pulses of output stage , */\ + { 0x5450, "icomp_engage_overrule"}, /* To overrule the functional icomp_engage signal during validation, */\ + { 0x5503, "ctrl_dem"}, /* Enable DEM icomp and DEM one bit dac , */\ + { 0x5543, "ctrl_dem_mismatch"}, /* Enable DEM icomp mismatch for testing , */\ + { 0x5582, "dpsa_drive"}, /* Drive setting (bin. coded) - I2C direct mode , */\ + { 0x570a, "enbl_amp"}, /* Switch on the class-D power sections, each part of the analog sections can be switched on/off individually , */\ + { 0x57b0, "enbl_engage"}, /* Enables/engage power stage and control loop - I2C direct mode, */\ + { 0x57c0, "enbl_engage_pst"}, /* Enables/engage power stage and control loop , */\ + { 0x5810, "hard_mute"}, /* Hard mute - PWM , */\ + { 0x5820, "pwm_shape"}, /* PWM shape , */\ + { 0x5844, "pwm_delay"}, /* PWM delay bits to set the delay, clock is 1/(k*2048*fs), */\ + { 0x5890, "reclock_pwm"}, /* Reclock the pwm signal inside analog , */\ + { 0x58a0, "reclock_voltsense"}, /* Reclock the voltage sense pwm signal , */\ + { 0x58c0, "enbl_pwm_phase_shift"}, /* Control for pwm phase shift , */\ + { 0x5c07, "flag_cf_tap_pattern"}, /* Coolflux tap pattern , */\ + { 0x5c83, "tap_debug_info"}, /* Reserved , */\ + { 0x5d0f, "tap_status_1"}, /* Tap Status 1 from CF FW , */\ + { 0x5f03, "tap_comp_threshold"}, /* Comparator threshold (in uV) , */\ + { 0x6081, "pga_gain_set"}, /* PGA gain selection , */\ + { 0x60b0, "pga_lowpass_enable"}, /* Lowpass enable , */\ + { 0x60c0, "pga_pwr_enable"}, /* PGA power enable , */\ + { 0x60d0, "pga_switch_enable"}, /* PGA switch enable , */\ + { 0x60e0, "pga_switch_aux_enable"}, /* Switch enable aux , */\ + { 0x6123, "ctrl_att"}, /* System gain (INPLEV 0) , */\ + { 0x6265, "zero_lvl"}, /* ctrl threshold for zero X-ing , */\ + { 0x62c1, "ctrl_fb_resistor"}, /* Select amplifier feedback resistor connection , */\ + { 0x62e1, "lownoisegain_mode"}, /* ctrl select mode , */\ + { 0x6305, "threshold_lvl"}, /* ctrl threshold for low_audio_lvl , */\ + { 0x6365, "hold_time"}, /* ctrl hold time before low audio is reckoned to be low audio, */\ + { 0x6405, "lpm1_cal_offset"}, /* low power mode1 detector ctrl cal_offset from gain module , */\ + { 0x6465, "lpm1_zero_lvl"}, /* low power mode1 detector ctrl threshold for zero X-ing , */\ + { 0x64e1, "lpm1_mode"}, /* low power mode1 detector ctrl select mode , */\ + { 0x6505, "lpm1_threshold_lvl"}, /* low power mode1 detector ctrl threshold for low_audio_lvl , */\ + { 0x6565, "lpm1_hold_time"}, /* Low power mode1 detector, ctrl hold time before low audio is reckoned to be low audio, */\ + { 0x65c0, "disable_low_power_mode"}, /* low power mode1 detector control , */\ + { 0x6600, "dcdc_pfm20khz_limit"}, /* DCDC in PFM mode pwm mode is activated each 50us to force a pwm pulse, */\ + { 0x6611, "dcdc_ctrl_maxzercnt"}, /* DCDC. Number of zero current flags to count before going to pfm mode, */\ + { 0x6630, "dcdcoff_mode"}, /* DCDC , */\ + { 0x6656, "dcdc_vbat_delta_detect"}, /* Threshold before booster is reacting on a delta Vbat (in PFM mode) by temporarily switching to PWM mode, */\ + { 0x66c0, "dcdc_ignore_vbat"}, /* Ignore an increase on Vbat , */\ + { 0x6700, "enbl_minion"}, /* Enables minion (small) power stage - direct ctrl , */\ + { 0x6713, "vth_vddpvbat"}, /* select vddp-vbat thres signal , */\ + { 0x6750, "lpen_vddpvbat"}, /* select vddp-vbat filtered vs unfiltered compare , */\ + { 0x6761, "ctrl_rfb"}, /* Feedback resistor selection - I2C direct mode , */\ + { 0x6801, "tdm_source_mapping"}, /* tdm source mapping , */\ + { 0x6821, "tdm_sourcea_frame_sel"}, /* frame a selection , */\ + { 0x6841, "tdm_sourceb_frame_sel"}, /* frame b selection , */\ + { 0x6901, "sam_mode"}, /* Sam mode , */\ + { 0x6931, "pdmdat_h_sel"}, /* pdm out value when pdm_clk is higth , */\ + { 0x6951, "pdmdat_l_sel"}, /* pdm out value when pdm_clk is low , */\ + { 0x6970, "cs_sam_set"}, /* Enable SAM input for current sense - I2C Direct Mode, */\ + { 0x6980, "cs_adc_nortz"}, /* Return to zero for current sense ADC , */\ + { 0x6990, "sam_spkr_sel"}, /* SAM o/p sel during SAM and audio , */\ + { 0x6b00, "disable_engage"}, /* Disable auto engage , */\ + { 0x6c02, "ns_hp2ln_criterion"}, /* 0..7 zeroes at ns as threshold to swap from high_power to low_noise, */\ + { 0x6c32, "ns_ln2hp_criterion"}, /* 0..7 zeroes at ns as threshold to swap from low_noise to high_power, */\ + { 0x6c60, "sel_clip_pwms"}, /* To select clip-flags , */\ + { 0x6c72, "pwms_clip_lvl"}, /* To set the amount of pwm pulse that may be skipped before clip-flag is triggered. , */\ + { 0x6ca5, "spare_out"}, /* spare_out , */\ + { 0x6d0f, "spare_in"}, /* spare_in , */\ + { 0x6e10, "flag_lp_detect_mode1"}, /* low power mode 1 detection , */\ + { 0x6e20, "flag_low_amplitude"}, /* low amplitude detection , */\ + { 0x6e30, "flag_vddp_gt_vbat"}, /* vddp greater than vbat , */\ + { 0x7033, "boost_cur"}, /* Max coil current , */\ + { 0x7071, "bst_slpcmplvl"}, /* Slope compensation current, represents LxF (inductance x frequency) value , */\ + { 0x7090, "boost_intel"}, /* Adaptive boost mode , */\ + { 0x70a0, "boost_speed"}, /* Soft ramp up/down , */\ + { 0x70c1, "dcdc_sel"}, /* DCDC IIR input Selection , */\ + { 0x70f0, "dcdc_pwmonly"}, /* DCDC PWM only mode , */\ + { 0x7104, "bst_drive"}, /* Binary coded drive setting for boost converter power stage, */\ + { 0x7151, "bst_scalecur"}, /* For testing direct control scale current , */\ + { 0x7174, "bst_slopecur"}, /* For testing direct control slope current - I2C direct mode, */\ + { 0x71c1, "bst_slope"}, /* Boost slope speed , */\ + { 0x71e0, "bst_bypass_bstcur"}, /* Bypass control for boost current settings , */\ + { 0x71f0, "bst_bypass_bstfoldback"}, /* Bypass control for boost foldback , */\ + { 0x7200, "enbl_bst_engage"}, /* Enable power stage dcdc controller - I2C direct mode, */\ + { 0x7210, "enbl_bst_hizcom"}, /* Enable hiz comparator - I2C direct mode , */\ + { 0x7220, "enbl_bst_peak2avg"}, /* Enable boost peak2avg functionality , */\ + { 0x7230, "enbl_bst_peakcur"}, /* Enable peak current - I2C direct mode , */\ + { 0x7240, "enbl_bst_power"}, /* Enable line of the powerstage - I2C direct mode , */\ + { 0x7250, "enbl_bst_slopecur"}, /* Enable bit of max-current dac - I2C direct mode , */\ + { 0x7260, "enbl_bst_voutcomp"}, /* Enable vout comparators - I2C direct mode , */\ + { 0x7270, "enbl_bst_voutcomp86"}, /* Enable vout-86 comparators - I2C direct mode , */\ + { 0x7280, "enbl_bst_voutcomp93"}, /* Enable vout-93 comparators - I2C direct mode , */\ + { 0x7290, "enbl_bst_windac"}, /* Enable window dac - I2C direct mode , */\ + { 0x72a5, "bst_windac"}, /* for testing direct control windac - I2C direct mode, */\ + { 0x7300, "boost_alg"}, /* Control for boost adaptive loop gain , */\ + { 0x7311, "boost_loopgain"}, /* DCDC boost loopgain setting , */\ + { 0x7331, "bst_freq"}, /* DCDC boost frequency control , */\ + { 0x7430, "boost_track"}, /* Boost algorithm selection, effective only when boost_intelligent is set to 1, */\ + { 0x7494, "boost_hold_time"}, /* Hold time for DCDC booster, effective only when boost_intelligent is set to 1, */\ + { 0x74e0, "sel_dcdc_envelope_8fs"}, /* Selection of data for adaptive boost algorithm, effective only when boost_intelligent is set to 1, */\ + { 0x74f0, "ignore_flag_voutcomp86"}, /* Ignore flag_voutcomp86 , */\ + { 0x7504, "boost_trip_lvl_1st"}, /* Adaptive boost trip levels 1, effective only when boost_intelligent is set to 1, */\ + { 0x7554, "boost_trip_lvl_2nd"}, /* Adaptive boost trip level 2, effective only when boost_intelligent is set to 1, */\ + { 0x75a4, "boost_trip_lvl_track"}, /* Adaptive boost trip levels, effective only when boost_intelligent is set to 1, */\ + { 0x7602, "track_decay"}, /* DCDC Boost decay speed after a peak value, effective only when boost_track is set to 1, */\ + { 0x7635, "frst_boost_voltage"}, /* First boost voltage level , */\ + { 0x7695, "scnd_boost_voltage"}, /* Second boost voltage level , */\ + { 0x7720, "pga_test_ldo_bypass"}, /* bypass internal PGA LDO , */\ + { 0x8001, "sel_clk_cs"}, /* Current sense clock duty cycle control , */\ + { 0x8021, "micadc_speed"}, /* Current sense clock for MiCADC selection - 32/44.1/48 KHz Fs band only, */\ + { 0x8050, "cs_gain_control"}, /* Current sense gain control , */\ + { 0x8060, "cs_bypass_gc"}, /* Bypasses the CS gain correction , */\ + { 0x8087, "cs_gain"}, /* Current sense gain , */\ + { 0x8200, "enbl_cmfb"}, /* Current sense common mode feedback control , */\ + { 0x8210, "invertpwm"}, /* Current sense common mode feedback pwm invert control, */\ + { 0x8222, "cmfb_gain"}, /* Current sense common mode feedback control gain , */\ + { 0x8256, "cmfb_offset"}, /* Current sense common mode feedback control offset , */\ + { 0x8305, "cs_ktemp"}, /* First order temperature compensation coefficient , */\ + { 0x8364, "cs_ktemp2"}, /* Second order temperature compensation coefficient , */\ + { 0x8400, "cs_adc_bsoinv"}, /* Bitstream inversion for current sense ADC , */\ + { 0x8421, "cs_adc_hifreq"}, /* Frequency mode current sense ADC , */\ + { 0x8453, "cs_adc_offset"}, /* Micadc ADC offset setting , */\ + { 0x8490, "cs_adc_slowdel"}, /* Select delay for current sense ADC (internal decision circuitry), */\ + { 0x84a4, "cs_adc_gain"}, /* Gain setting for current sense ADC (two's complement), */\ + { 0x8500, "cs_resonator_enable"}, /* Enable for resonator to improve SRN , */\ + { 0x8510, "cs_classd_tran_skip"}, /* Skip current sense connection during a classD amplifier transition, */\ + { 0x8530, "cs_inn_short"}, /* Short current sense negative to common mode , */\ + { 0x8540, "cs_inp_short"}, /* Short current sense positive to common mode , */\ + { 0x8550, "cs_ldo_bypass"}, /* Bypass current sense LDO , */\ + { 0x8560, "cs_ldo_pulldown"}, /* Pull down current sense LDO, only valid if left_enbl_cs_ldo is high, */\ + { 0x8574, "cs_ldo_voset"}, /* Current sense LDO voltage level setting (two's complement), */\ + { 0x8700, "enbl_cs_adc"}, /* Enable current sense ADC - I2C direct mode , */\ + { 0x8710, "enbl_cs_inn1"}, /* Enable connection of current sense negative1 - I2C direct mode, */\ + { 0x8720, "enbl_cs_inn2"}, /* Enable connection of current sense negative2 - I2C direct mode, */\ + { 0x8730, "enbl_cs_inp1"}, /* Enable connection of current sense positive1 , */\ + { 0x8740, "enbl_cs_inp2"}, /* Enable connection of current sense positive2 - I2C direct mode, */\ + { 0x8750, "enbl_cs_ldo"}, /* Enable current sense LDO - I2C direct mode , */\ + { 0x8760, "enbl_cs_nofloating_n"}, /* Connect current sense negative to gnda at transitions of booster or classd amplifiers. Otherwise floating (0), */\ + { 0x8770, "enbl_cs_nofloating_p"}, /* Connect current sense positive to gnda at transitions of booster or classd amplifiers. Otherwise floating (0), */\ + { 0x8780, "enbl_cs_vbatldo"}, /* Enable of current sense LDO -- I2C direct mode , */\ + { 0x8800, "volsense_pwm_sel"}, /* Voltage sense PWM source selection control , */\ + { 0x8810, "vol_cur_sense_dc_offset"}, /* voltage and current sense decimator offset control, */\ + { 0x8902, "cursense_comp_delay"}, /* To align compensation signal with current sense signal, */\ + { 0x8930, "cursense_comp_sign"}, /* To change polarity of compensation for current sense compensation, */\ + { 0x8940, "enbl_cursense_comp"}, /* To enable current sense compensation , */\ + { 0x9000, "cf_rst_dsp"}, /* Reset , */\ + { 0x9011, "cf_dmem"}, /* Target memory , */\ + { 0x9030, "cf_aif"}, /* Auto increment , */\ + { 0x9040, "cf_int"}, /* Interrupt - auto clear , */\ + { 0x9050, "cf_cgate_off"}, /* Coolflux clock gating disabling control , */\ + { 0x9080, "cf_req_cmd"}, /* Firmware event request rpc command , */\ + { 0x9090, "cf_req_reset"}, /* Firmware event request reset restart , */\ + { 0x90a0, "cf_req_mips"}, /* Firmware event request short on mips , */\ + { 0x90b0, "cf_req_mute_ready"}, /* Firmware event request mute sequence ready , */\ + { 0x90c0, "cf_req_volume_ready"}, /* Firmware event request volume ready , */\ + { 0x90d0, "cf_req_damage"}, /* Firmware event request speaker damage detected , */\ + { 0x90e0, "cf_req_calibrate_ready"}, /* Firmware event request calibration completed , */\ + { 0x90f0, "cf_req_reserved"}, /* Firmware event request reserved , */\ + { 0x910f, "cf_madd"}, /* Memory address , */\ + { 0x920f, "cf_mema"}, /* Activate memory access , */\ + { 0x9307, "cf_err"}, /* Error flags , */\ + { 0x9380, "cf_ack_cmd"}, /* Firmware event acknowledge rpc command , */\ + { 0x9390, "cf_ack_reset"}, /* Firmware event acknowledge reset restart , */\ + { 0x93a0, "cf_ack_mips"}, /* Firmware event acknowledge short on mips , */\ + { 0x93b0, "cf_ack_mute_ready"}, /* Firmware event acknowledge mute sequence ready , */\ + { 0x93c0, "cf_ack_volume_ready"}, /* Firmware event acknowledge volume ready , */\ + { 0x93d0, "cf_ack_damage"}, /* Firmware event acknowledge speaker damage detected, */\ + { 0x93e0, "cf_ack_calibrate_ready"}, /* Firmware event acknowledge calibration completed , */\ + { 0x93f0, "cf_ack_reserved"}, /* Firmware event acknowledge reserved , */\ + { 0xa007, "mtpkey1"}, /* 5Ah, 90d To access KEY1_Protected registers (Default for engineering), */\ + { 0xa107, "mtpkey2"}, /* MTP KEY2 register , */\ + { 0xa200, "key01_locked"}, /* Indicates KEY1 is locked , */\ + { 0xa210, "key02_locked"}, /* Indicates KEY2 is locked , */\ + { 0xa302, "mtp_man_address_in"}, /* MTP address from I2C register for read/writing mtp in manual single word mode, */\ + { 0xa330, "man_copy_mtp_to_iic"}, /* Start copying single word from mtp to I2C mtp register, */\ + { 0xa340, "man_copy_iic_to_mtp"}, /* Start copying single word from I2C mtp register to mtp, */\ + { 0xa350, "auto_copy_mtp_to_iic"}, /* Start copying all the data from mtp to I2C mtp registers, */\ + { 0xa360, "auto_copy_iic_to_mtp"}, /* Start copying data from I2C mtp registers to mtp , */\ + { 0xa400, "faim_set_clkws"}, /* Sets the FaIM controller clock wait state register, */\ + { 0xa410, "faim_sel_evenrows"}, /* All even rows of the FaIM are selected, active high, */\ + { 0xa420, "faim_sel_oddrows"}, /* All odd rows of the FaIM are selected, all rows in combination with sel_evenrows, */\ + { 0xa430, "faim_program_only"}, /* Skip the erase access at wr_faim command (write-program-marginread), */\ + { 0xa440, "faim_erase_only"}, /* Skip the program access at wr_faim command (write-erase-marginread), */\ + { 0xa50f, "mtp_man_data_out_msb"}, /* MSB word of MTP manual read data , */\ + { 0xa60f, "mtp_man_data_out_lsb"}, /* LSB word of MTP manual read data , */\ + { 0xa70f, "mtp_man_data_in_msb"}, /* MSB word of write data for MTP manual write , */\ + { 0xa80f, "mtp_man_data_in_lsb"}, /* LSB word of write data for MTP manual write , */\ + { 0xb010, "bypass_ocpcounter"}, /* Bypass OCP Counter , */\ + { 0xb020, "bypass_glitchfilter"}, /* Bypass glitch filter , */\ + { 0xb030, "bypass_ovp"}, /* Bypass OVP , */\ + { 0xb040, "bypass_uvp"}, /* Bypass UVP , */\ + { 0xb050, "bypass_otp"}, /* Bypass OTP , */\ + { 0xb060, "bypass_lost_clk"}, /* Bypass lost clock detector , */\ + { 0xb070, "ctrl_vpalarm"}, /* vpalarm (uvp ovp handling) , */\ + { 0xb087, "ocp_threshold"}, /* OCP threshold level , */\ + { 0xb108, "ext_temp"}, /* External temperature (C) , */\ + { 0xb190, "ext_temp_sel"}, /* Select temp Speaker calibration , */\ + { 0xc000, "use_direct_ctrls"}, /* Direct control to overrule several functions for testing, */\ + { 0xc010, "rst_datapath"}, /* Direct control for datapath reset , */\ + { 0xc020, "rst_cgu"}, /* Direct control for cgu reset , */\ + { 0xc038, "enbl_ref"}, /* Switch on the analog references, each part of the references can be switched on/off individually - - I2C direct mode, */\ + { 0xc0d0, "enbl_ringo"}, /* Enable the ring oscillator for test purpose , */\ + { 0xc0e0, "use_direct_clk_ctrl"}, /* Direct clock control to overrule several functions for testing, */\ + { 0xc0f0, "use_direct_pll_ctrl"}, /* Direct PLL control to overrule several functions for testing, */\ + { 0xc100, "enbl_tsense"}, /* Temperature sensor enable control - I2C direct mode, */\ + { 0xc110, "tsense_hibias"}, /* Bit to set the biasing in temp sensor to high - I2C direct mode, */\ + { 0xc120, "enbl_flag_vbg"}, /* Enable flagging of bandgap out of control , */\ + { 0xc130, "tap_comp_enable"}, /* Tap Comparator enable control - I2C direct mode , */\ + { 0xc140, "tap_comp_switch_enable"}, /* Tap Comparator Switch enable control - I2C direct mode, */\ + { 0xc150, "tap_comp_switch_aux_enable"}, /* Tap Comparator Switch enable control - I2C direct mode, */\ + { 0xc161, "tap_comp_test_enable"}, /* Comparator threshold - fine value , */\ + { 0xc180, "curdist_enable"}, /* Enable control - I2C direct mode , */\ + { 0xc190, "vbg2i_enbl"}, /* Enable control - I2C direct mode , */\ + { 0xc1a0, "bg_filt_bypass_enbl"}, /* Enable control , */\ + { 0xc20f, "abist_offset"}, /* Offset control for ABIST testing (two's complement), */\ + { 0xc300, "bypasslatch"}, /* Bypass latch , */\ + { 0xc311, "sourcea"}, /* Set OUTA to , */\ + { 0xc331, "sourceb"}, /* Set OUTB to , */\ + { 0xc350, "inverta"}, /* Invert pwma test signal , */\ + { 0xc360, "invertb"}, /* Invert pwmb test signal , */\ + { 0xc374, "pulselength"}, /* Pulse length setting test input for amplifier (clock d - k*2048*fs), */\ + { 0xc3c0, "tdm_enable_loopback"}, /* TDM loopback test , */\ + { 0xc3d0, "test_abistfft_enbl"}, /* FFT Coolflux , */\ + { 0xc3e0, "test_pwr_switch"}, /* Test mode for digital power switches core sw/mem sw/micvdd sw, */\ + { 0xc400, "bst_bypasslatch"}, /* Bypass latch in boost converter , */\ + { 0xc411, "bst_source"}, /* Sets the source of the pwmbst output to boost converter input for testing, */\ + { 0xc430, "bst_invertb"}, /* Invert pwmbst test signal , */\ + { 0xc444, "bst_pulselength"}, /* Pulse length setting test input for boost converter , */\ + { 0xc490, "test_bst_ctrlsthv"}, /* Test mode for boost control stage , */\ + { 0xc4a0, "test_bst_iddq"}, /* IDDQ testing in power stage of boost converter , */\ + { 0xc4b0, "test_bst_rdson"}, /* RDSON testing - boost power stage , */\ + { 0xc4c0, "test_bst_cvi"}, /* CVI testing - boost power stage , */\ + { 0xc4d0, "test_bst_ocp"}, /* Boost OCP. For old ocp (ctrl_reversebst is 0), For new ocp (ctrl_reversebst is 1), */\ + { 0xc4e0, "test_bst_sense"}, /* Test option for the sense NMOS in booster for current mode control., */\ + { 0xc500, "test_cvi"}, /* Analog BIST, switch choose which transistor will be used as current source (also cross coupled sources possible), */\ + { 0xc510, "test_discrete"}, /* Test function noise measurement , */\ + { 0xc520, "test_iddq"}, /* Set the power stages in iddq mode for gate stress., */\ + { 0xc540, "test_rdson"}, /* Analog BIST, switch to enable Rdson measurement , */\ + { 0xc550, "test_sdelta"}, /* Analog BIST, noise test , */\ + { 0xc560, "bypass_fro8"}, /* Bypass fro8 with pdm_clk , */\ + { 0xc570, "test_enbl_cs"}, /* Enable for digimux mode of current sense , */\ + { 0xc5b0, "pga_test_enable"}, /* Enable PGA test mode , */\ + { 0xc5c0, "pga_test_offset_enable"}, /* Enable PGA test offset , */\ + { 0xc5d0, "pga_test_shortinput_enable"}, /* Enable PGA test short input , */\ + { 0xc600, "enbl_pwm_dcc"}, /* Enables direct control of pwm duty cycle for DCDC power stage, */\ + { 0xc613, "pwm_dcc_cnt"}, /* Control pwm duty cycle when enbl_pwm_dcc is 1 , */\ + { 0xc650, "enbl_ldo_stress"}, /* Enable stress of internal supply voltages powerstages, */\ + { 0xc660, "enbl_powerswitch"}, /* Vddd core power switch control - overrules the manager control, */\ + { 0xc707, "digimuxa_sel"}, /* DigimuxA input selection control routed to DIO4 (see Digimux list for details), */\ + { 0xc787, "digimuxb_sel"}, /* DigimuxB input selection control routed to DIO3 (see Digimux list for details), */\ + { 0xc807, "digimuxc_sel"}, /* DigimuxC input selection control routed to TDO (see Digimux list for details), */\ + { 0xc901, "dio1_ehs"}, /* Speed/load setting for DIO1 IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ + { 0xc921, "dio2_ehs"}, /* Speed/load setting for DIO2 IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ + { 0xc941, "dio3_ehs"}, /* Speed/load setting for DIO3 cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ + { 0xc961, "dio4_ehs"}, /* Speed/load setting for DIO4 IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ + { 0xc981, "spdmo_ehs"}, /* Speed/load setting for PDMO IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ + { 0xc9a1, "tdo_ehs"}, /* Speed/load setting for TDM IO cell, clk or data mode range (see SLIMMF IO cell datasheet), */\ + { 0xc9c0, "int_ehs"}, /* Slew Rate INT IO cell, clk or data mode range (see IIC3V3 IO cell datasheet), */\ + { 0xc9d0, "pdmclk_ehs"}, /* Slew RateBCK2/PDMCLK IO cell, clk or data mode range (see IIC3V3 IO cell datasheet), */\ + { 0xc9e0, "fs2_ehs"}, /* Slew Rate DS2 IO cell, clk or data mode range (see IIC3V3 IO cell datasheet), */\ + { 0xc9f0, "hs_mode"}, /* I2C high speed mode control , */\ + { 0xca00, "enbl_anamux1"}, /* Enable anamux1 , */\ + { 0xca10, "enbl_anamux2"}, /* Enable anamux2 , */\ + { 0xca20, "enbl_anamux3"}, /* Enable anamux3 , */\ + { 0xca30, "enbl_anamux4"}, /* Enable anamux4 , */\ + { 0xca74, "anamux1"}, /* Anamux selection control - anamux on TEST1 , */\ + { 0xcb04, "anamux2"}, /* Anamux selection control - anamux on TEST2 , */\ + { 0xcb54, "anamux3"}, /* Anamux selection control - anamux on TEST3 , */\ + { 0xcba4, "anamux4"}, /* Anamux selection control - anamux on TEST4 , */\ + { 0xcc05, "pll_seli_lbw"}, /* PLL SELI - Low B/W PLL control mode or I2C direct PLL control mode only, */\ + { 0xcc64, "pll_selp_lbw"}, /* PLL SELP - Low B/W PLL control mode or I2C direct PLL control mode only, */\ + { 0xccb3, "pll_selr_lbw"}, /* PLL SELR - Low B/W PLL control mode or I2C direct PLL control mode only, */\ + { 0xccf0, "sel_user_pll_bw"}, /* PLL Low Bandwidth Mode control , */\ + { 0xcdf0, "pll_frm"}, /* PLL free running mode control; 1 in TCB direct control mode, else this control bit, */\ + { 0xce09, "pll_ndec"}, /* PLL NDEC - I2C direct PLL control mode only , */\ + { 0xcea0, "pll_mdec_msb"}, /* MSB of pll_mdec - I2C direct PLL control mode only, */\ + { 0xceb0, "enbl_pll"}, /* Enables PLL in I2C direct PLL control mode only , */\ + { 0xcec0, "enbl_fro8"}, /* Enables FRO8M in I2C direct control mode only , */\ + { 0xced0, "pll_bypass"}, /* PLL bypass control in I2C direct PLL control mode only, */\ + { 0xcee0, "pll_directi"}, /* PLL directi control in I2C direct PLL control mode only, */\ + { 0xcef0, "pll_directo"}, /* PLL directo control in I2C direct PLL control mode only, */\ + { 0xcf0f, "pll_mdec_lsb"}, /* Bits 15..0 of PLL MDEC are I2C direct PLL control mode only, */\ + { 0xd006, "pll_pdec"}, /* PLL PDEC - I2C direct PLL control mode only , */\ + { 0xd10f, "tsig_freq_lsb"}, /* Internal sinus test generator frequency control , */\ + { 0xd202, "tsig_freq_msb"}, /* Select internal sinus test generator, frequency control msb bits, */\ + { 0xd230, "inject_tsig"}, /* Control bit to switch to internal sinus test generator, */\ + { 0xd283, "tsig_gain"}, /* Test signal gain , */\ + { 0xd300, "adc10_reset"}, /* Reset for ADC10 - I2C direct control mode , */\ + { 0xd311, "adc10_test"}, /* Test mode selection signal for ADC10 - I2C direct control mode, */\ + { 0xd332, "adc10_sel"}, /* Select the input to convert for ADC10 - I2C direct control mode, */\ + { 0xd364, "adc10_prog_sample"}, /* ADC10 program sample setting - I2C direct control mode, */\ + { 0xd3b0, "adc10_enbl"}, /* Enable ADC10 - I2C direct control mode , */\ + { 0xd3c0, "bypass_lp_vbat"}, /* Bypass control for Low pass filter in batt sensor , */\ + { 0xd409, "data_adc10_tempbat"}, /* ADC 10 data output data for testing , */\ + { 0xd507, "ctrl_digtoana_hidden"}, /* Spare digital to analog control bits - Hidden , */\ + { 0xd580, "enbl_clk_range_chk"}, /* Clock out of range , */\ + { 0xd601, "clkdiv_dsp_sel"}, /* DSP clock divider selection in direct clock control mode, */\ + { 0xd621, "clkdiv_audio_sel"}, /* Audio clock divider selection in direct clock control mode, */\ + { 0xd641, "clkdiv_muxa_sel"}, /* DCDC MUXA clock divider selection in direct clock control mode, */\ + { 0xd661, "clkdiv_muxb_sel"}, /* DCDC MUXB clock divider selection in direct clock control mode, */\ + { 0xd681, "dsp_tap_clk"}, /* Dsp clock frequency selection in TAP mode; , */\ + { 0xd6a1, "sel_wdt_clk"}, /* Watch dog clock post divider value , */\ + { 0xd6c1, "sel_tim_clk"}, /* Timer clock post divider value , */\ + { 0xd700, "ads1_ehs"}, /* Slew Rate ADS1 IO cell, clk or data mode range (see IIC3V3 IO cell datasheet), */\ + { 0xd710, "ads2_ehs"}, /* Slew Rate ADS2 IO cell, clk or data mode range (see IIC3V3 IO cell datasheet), */\ + { 0xd822, "test_parametric_io"}, /* test io parametric , */\ + { 0xd850, "ctrl_bst_clk_lp1"}, /* boost clock control in low power mode1 , */\ + { 0xd861, "test_spare_out1"}, /* test spare out 1 , */\ + { 0xd880, "bst_dcmbst"}, /* dcm boost - I2C direct mode , */\ + { 0xd8a1, "force_pga_clock"}, /* force pga clock , */\ + { 0xd8c3, "test_spare_out2"}, /* test spare out 1 , */\ + { 0xd900, "overrules_usercase"}, /* Overrule Mode control use , */\ + { 0xd910, "ovr_switch_ref"}, /* Overrule Value , */\ + { 0xd920, "ovr_enbl_pll"}, /* Overrule Value , */\ + { 0xd930, "ovr_switch_amp"}, /* Overrule Value , */\ + { 0xd940, "ovr_enbl_clk_cs"}, /* Overrule Value , */\ + { 0xd951, "ovr_sel_clk_cs"}, /* CS clock selection overrule , */\ + { 0xd970, "ovr_switch_cs"}, /* Overrule Value , */\ + { 0xd980, "ovr_enbl_csvs_ss"}, /* Overrule Value , */\ + { 0xd990, "ovr_enbl_comp"}, /* Overrule Value , */\ + { 0xed00, "enbl_fro8cal"}, /* Enable FRO calibration , */\ + { 0xed10, "start_fro8_calibration"}, /* Start FRO8 Calibration , */\ + { 0xed20, "fro8_calibration_done"}, /* FRO8 Calibration done - Read Only , */\ + { 0xed45, "fro8_auto_trim_val"}, /* Calibration value from Auto Calibration block, to be written into MTP - Read Only, */\ + { 0xee0f, "sw_profile"}, /* Software profile data , */\ + { 0xef0f, "sw_vstep"}, /* Software vstep information , */\ + { 0xf000, "calibration_onetime"}, /* Calibration schedule , */\ + { 0xf010, "calibr_ron_done"}, /* Calibration Ron executed , */\ + { 0xf020, "calibr_dcdc_api_calibrate"}, /* Calibration current limit DCDC , */\ + { 0xf030, "calibr_dcdc_delta_sign"}, /* Sign bit for delta calibration current limit DCDC , */\ + { 0xf042, "calibr_dcdc_delta"}, /* Calibration delta current limit DCDC , */\ + { 0xf078, "calibr_speaker_info"}, /* Reserved space for allowing customer to store speaker information, */\ + { 0xf105, "calibr_vout_offset"}, /* DCDC offset calibration 2's complement (key1 protected), */\ + { 0xf163, "spare_mtp1_9_6"}, /* HW gain module - left channel (2's complement) , */\ + { 0xf1a5, "spare_mtp1_15_10"}, /* Offset for amplifier, HW gain module - left channel (2's complement), */\ + { 0xf203, "calibr_gain"}, /* HW gain module (2's complement) , */\ + { 0xf245, "calibr_offset"}, /* Offset for amplifier, HW gain module (2's complement), */\ + { 0xf2a3, "spare_mtp2_13_10"}, /* Trimming of LDO (2.7V) , */\ + { 0xf307, "spare_mtp3_7_0"}, /* SPARE , */\ + { 0xf387, "calibr_gain_cs"}, /* Current sense gain (signed two's complement format), */\ + { 0xf40f, "calibr_R25C"}, /* Ron resistance of speaker coil , */\ + { 0xf50f, "spare_mtp5_15_0"}, /* SPARE , */\ + { 0xf600, "mtp_lock_enbl_coolflux"}, /* Disable function dcdcoff_mode , */\ + { 0xf610, "mtp_pwm_delay_enbl_clk_auto_gating"}, /* Auto clock gating on pwm_delay , */\ + { 0xf620, "mtp_ocp_enbl_clk_auto_gating"}, /* Auto clock gating on module ocp , */\ + { 0xf630, "mtp_disable_clk_a_gating"}, /* Disable clock_a gating , */\ + { 0xf642, "spare_mtp6_6_3"}, /* SPARE , */\ + { 0xf686, "spare_mtp6_14_8"}, /* Offset of left amplifier level shifter B , */\ + { 0xf706, "ctrl_offset_a"}, /* Offset of level shifter A , */\ + { 0xf786, "ctrl_offset_b"}, /* Offset of amplifier level shifter B , */\ + { 0xf806, "htol_iic_addr"}, /* 7-bit I2C address to be used during HTOL testing , */\ + { 0xf870, "htol_iic_addr_en"}, /* HTOL I2C address enable control , */\ + { 0xf884, "calibr_temp_offset"}, /* Temperature offset 2's compliment (key1 protected), */\ + { 0xf8d2, "calibr_temp_gain"}, /* Temperature gain 2's compliment (key1 protected) , */\ + { 0xf910, "disable_sam_mode"}, /* Disable sam mode , */\ + { 0xf920, "mtp_lock_bypass_clipper"}, /* Disable function bypass_clipper , */\ + { 0xf930, "mtp_lock_max_dcdc_voltage"}, /* Disable programming of max dcdc boost voltage , */\ + { 0xf943, "calibr_vbg_trim"}, /* Bandgap trimming control , */\ + { 0xf987, "type_bits_fw"}, /* MTP-control FW - See Firmware I2C API document for details, */\ + { 0xfa0f, "mtpdataA"}, /* MTPdataA (key1 protected) , */\ + { 0xfb0f, "mtpdataB"}, /* MTPdataB (key1 protected) , */\ + { 0xfc0f, "mtpdataC"}, /* MTPdataC (key1 protected) , */\ + { 0xfd0f, "mtpdataD"}, /* MTPdataD (key1 protected) , */\ + { 0xfe0f, "mtpdataE"}, /* MTPdataE (key1 protected) , */\ + { 0xff05, "fro8_trim"}, /* 8 MHz oscillator trim code , */\ + { 0xff61, "fro8_short_nwell_r"}, /* Short 4 or 6 n-well resistors , */\ + { 0xff81, "fro8_boost_i"}, /* Self bias current selection , */\ + { 0xffff,"Unknown bitfield enum" } /* not found */\ +}; + +enum tfa9912_irq { + tfa9912_irq_stvdds = 0, + tfa9912_irq_stplls = 1, + tfa9912_irq_stotds = 2, + tfa9912_irq_stovds = 3, + tfa9912_irq_stuvds = 4, + tfa9912_irq_stclks = 5, + tfa9912_irq_stmtpb = 6, + tfa9912_irq_stnoclk = 7, + tfa9912_irq_stspks = 8, + tfa9912_irq_stacs = 9, + tfa9912_irq_stsws = 10, + tfa9912_irq_stwds = 11, + tfa9912_irq_stamps = 12, + tfa9912_irq_starefs = 13, + tfa9912_irq_stadccr = 14, + tfa9912_irq_stbodnok = 15, + tfa9912_irq_stbstcu = 16, + tfa9912_irq_stbsthi = 17, + tfa9912_irq_stbstoc = 18, + tfa9912_irq_stbstpkcur = 19, + tfa9912_irq_stbstvc = 20, + tfa9912_irq_stbst86 = 21, + tfa9912_irq_stbst93 = 22, + tfa9912_irq_strcvld = 23, + tfa9912_irq_stocpl = 24, + tfa9912_irq_stocpr = 25, + tfa9912_irq_stmwsrc = 26, + tfa9912_irq_stmwcfc = 27, + tfa9912_irq_stmwsmu = 28, + tfa9912_irq_stcfmer = 29, + tfa9912_irq_stcfmac = 30, + tfa9912_irq_stclkoor = 31, + tfa9912_irq_sttdmer = 32, + tfa9912_irq_stclpl = 33, + tfa9912_irq_stclpr = 34, + tfa9912_irq_stocpm = 35, + tfa9912_irq_stlp1 = 37, + tfa9912_irq_stla = 38, + tfa9912_irq_stvddp = 39, + tfa9912_irq_sttapdet = 40, + tfa9912_irq_staudmod = 41, + tfa9912_irq_stsammod = 42, + tfa9912_irq_sttapmod = 43, + tfa9912_irq_sttaptrg = 44, + tfa9912_irq_max = 45, + tfa9912_irq_all = -1 /* all irqs */}; + +#define TFA9912_IRQ_NAMETABLE static tfaIrqName_t Tfa9912IrqNames[]= {\ + { 0, "STVDDS"},\ + { 1, "STPLLS"},\ + { 2, "STOTDS"},\ + { 3, "STOVDS"},\ + { 4, "STUVDS"},\ + { 5, "STCLKS"},\ + { 6, "STMTPB"},\ + { 7, "STNOCLK"},\ + { 8, "STSPKS"},\ + { 9, "STACS"},\ + { 10, "STSWS"},\ + { 11, "STWDS"},\ + { 12, "STAMPS"},\ + { 13, "STAREFS"},\ + { 14, "STADCCR"},\ + { 15, "STBODNOK"},\ + { 16, "STBSTCU"},\ + { 17, "STBSTHI"},\ + { 18, "STBSTOC"},\ + { 19, "STBSTPKCUR"},\ + { 20, "STBSTVC"},\ + { 21, "STBST86"},\ + { 22, "STBST93"},\ + { 23, "STRCVLD"},\ + { 24, "STOCPL"},\ + { 25, "STOCPR"},\ + { 26, "STMWSRC"},\ + { 27, "STMWCFC"},\ + { 28, "STMWSMU"},\ + { 29, "STCFMER"},\ + { 30, "STCFMAC"},\ + { 31, "STCLKOOR"},\ + { 32, "STTDMER"},\ + { 33, "STCLPL"},\ + { 34, "STCLPR"},\ + { 35, "STOCPM"},\ + { 36, "36"},\ + { 37, "STLP1"},\ + { 38, "STLA"},\ + { 39, "STVDDP"},\ + { 40, "STTAPDET"},\ + { 41, "STAUDMOD"},\ + { 42, "STSAMMOD"},\ + { 43, "STTAPMOD"},\ + { 44, "STTAPTRG"},\ +}; +#endif /* _TFA9912_TFAFIELDNAMES_H */ diff --git a/techpack/audio/asoc/codecs/tfa9874/tfaContUtil.h b/techpack/audio/asoc/codecs/tfa9874/tfaContUtil.h new file mode 100644 index 000000000000..434f50a192ab --- /dev/null +++ b/techpack/audio/asoc/codecs/tfa9874/tfaContUtil.h @@ -0,0 +1,110 @@ +/* + * Copyright 2012-2017 NXP Semiconductors + * + * 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. + */ + +/* + * tfaContUtil.h + * + * interface to the Tfa98xx API + * + * Created on: Apr 6, 2012 + * Author: wim + */ + +#ifndef TFACONTUTIL_H_ +#define TFACONTUTIL_H_ + +#ifdef __ANDROID__ +#include +#else +#define LOGV if (0/*tfa98xx_verbose*/) printf //TODO improve logging +#endif + +#include "tfa_dsp_fw.h" +#include "tfa98xx_parameters.h" + +#if defined(WIN32) || defined(_X64) +#include +#else +#include +#include +#endif + +#ifndef timer_INCLUDED +#define timer_INCLUDED +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +#define NXPTFA_MAXLINE (256) /* maximum string length */ +#define NXPTFA_MAXBUFFER (50*1024) /* maximum buffer size to hold the container */ + +/* + * buffer types for setting parameters + */ +typedef enum nxpTfa98xxParamsType { + tfa_patch_params, + tfa_speaker_params, + tfa_preset_params, + tfa_config_params, + tfa_equalizer_params, + tfa_drc_params, + tfa_vstep_params, + tfa_cnt_params, + tfa_msg_params, + tfa_no_params, + tfa_info_params, + tfa_algo_params +} nxpTfa98xxParamsType_t; + +enum Tfa98xx_Error tfaVersions(int dev_idx, char *strings, int maxlength); +int tfa98xxSaveFile(int dev_idx, char *filename, nxpTfa98xxParamsType_t params); +enum Tfa98xx_Error tfaGetDspFWAPIVersion(int dev_idx); +int tfaGetRegMapVersion(int dev_idx, char *buffer); +int compare_strings(char *buffer, char *name, int buffersize); +enum Tfa98xx_Error tfaVersion(char *buffer); + +/* + * save dedicated device files. Depends on the file extension + */ +int tfa98xxSaveFileWrapper(int dev_idx, char *filename); + +enum Tfa98xx_Error tfa98xx_verify_speaker_range(int idx, float imp[2], int spkr_count); + +/* hex dump of cnt */ +void tfa_cnt_hexdump(void); +void tfa_cnt_dump(void); + +/* Timer functions (currently only used by livedata) */ +int start_timer(int, void (*)(void)); +void stop_timer(void); + +void extern_msleep_interruptible(int msec); + +enum Tfa98xx_Error tfa_open(int maxdev); +void tfa_close(int maxdev); + +int is_ext_dsp(int dev_idx); +enum Tfa98xx_Error tfa_send_calibration_values(); +enum Tfa98xx_Error tfa_start(int next_profile, int vstep); +enum Tfa98xx_Error tfa_stop(); + +enum Tfa98xx_Error tfa_system_open(unsigned char *slave_address, int count); +#if defined(__cplusplus) +} /* extern "C" */ +#endif +#endif /* TFACONTUTIL_H_ */ diff --git a/techpack/audio/asoc/codecs/tfa9874/tfaOsal.h b/techpack/audio/asoc/codecs/tfa9874/tfaOsal.h new file mode 100644 index 000000000000..18bf3a6576bd --- /dev/null +++ b/techpack/audio/asoc/codecs/tfa9874/tfaOsal.h @@ -0,0 +1,52 @@ +/* + * Copyright 2014-2017 NXP Semiconductors + * + * 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. + */ + +/* + * tfaOsal.c + * + * Operating specifics + */ + + +#ifndef TFAOSAL_H_ +#define TFAOSAL_H_ + +/* load hal plugin from dynamic lib */ +void * tfaosal_plugload(char *libarg); +/*generic function to load library and symbol from the library*/ +extern void * load_library(char *libname); +extern void * load_symbol(void *dlib_handle, char *dl_sym); + +int tfaosal_filewrite(const char *fullname, unsigned char *buffer, int filelenght ); + +#define isSpaceCharacter(C) (C==' '||C=='\t') + +#if defined (WIN32) || defined(_X64) +//suppress warnings for unsafe string routines. +#pragma warning(disable : 4996) +#pragma warning(disable : 4054) +char *basename(const char *fullpath); +#define bzero(ADDR,SZ) memset(ADDR,0,SZ) +#endif + +void tfaRun_Sleepus(int us); + +/* + * Read file + */ +int tfaReadFile(char *fname, void **buffer); + +#endif diff --git a/techpack/audio/asoc/codecs/tfa9874/tfa_container.c b/techpack/audio/asoc/codecs/tfa9874/tfa_container.c new file mode 100644 index 000000000000..cf01b1db8489 --- /dev/null +++ b/techpack/audio/asoc/codecs/tfa9874/tfa_container.c @@ -0,0 +1,2312 @@ +/* + * Copyright 2014-2017 NXP Semiconductors + * + * 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 "dbgprint.h" +#include "tfa_container.h" +#include "tfa.h" +#include "tfa98xx_tfafieldnames.h" +#include "tfa_internal.h" + +/* defines */ +#define MODULE_BIQUADFILTERBANK 2 +#define BIQUAD_COEFF_SIZE 6 + +/* module globals */ +static uint8_t gslave_address = 0; /* This is used to SET the slave with the --slave option */ + +static int float_to_int(uint32_t x) +{ + unsigned e = (0x7F + 31) - ((*(unsigned *) &x & 0x7F800000) >> 23); + unsigned m = 0x80000000 | (*(unsigned *) &x << 8); + return -(int)((m >> e) & -(e < 32)); +} + +/* + * check the container file +*/ +enum tfa_error tfa_load_cnt(void *cnt, int length) +{ + nxpTfaContainer_t *cntbuf = (nxpTfaContainer_t *)cnt; + + if (length > TFA_MAX_CNT_LENGTH) { + pr_err("incorrect length\n"); + return tfa_error_container; + } + + if (HDR(cntbuf->id[0],cntbuf->id[1]) == 0) { + pr_err("header is 0\n"); + return tfa_error_container; + } + + if ( (HDR(cntbuf->id[0],cntbuf->id[1])) != paramsHdr ) { + pr_err("wrong header type: 0x%02x 0x%02x\n", cntbuf->id[0],cntbuf->id[1]); + return tfa_error_container; + } + + if (cntbuf->size == 0) { + pr_err("data size is 0\n"); + return tfa_error_container; + } + + /* check CRC */ + if ( tfaContCrcCheckContainer(cntbuf)) { + pr_err("CRC error\n"); + return tfa_error_container; + } + + /* check sub version level */ + if ((cntbuf->subversion[1] != NXPTFA_PM_SUBVERSION) && + (cntbuf->subversion[0] != '0')) { + pr_err("container sub-version not supported: %c%c\n", + cntbuf->subversion[0], cntbuf->subversion[1]); + return tfa_error_container; + } + + return tfa_error_ok; +} + +/* + * Dump the contents of the file header + */ +void tfaContShowHeader(nxpTfaHeader_t *hdr) { + char _id[2]; + + pr_debug("File header\n"); + + _id[1] = hdr->id >> 8; + _id[0] = hdr->id & 0xff; + pr_debug("\tid:%.2s version:%.2s subversion:%.2s\n", _id, + hdr->version, hdr->subversion); + pr_debug("\tsize:%d CRC:0x%08x \n", hdr->size, hdr->CRC); + pr_debug( "\tcustomer:%.8s application:%.8s type:%.8s\n", hdr->customer, + hdr->application, hdr->type); +} + +/* + * return device list dsc from index + */ +nxpTfaDeviceList_t *tfaContGetDevList(nxpTfaContainer_t *cont, int dev_idx) +{ + uint8_t *base = (uint8_t *) cont; + + if (cont == NULL) + return NULL; + + if ( (dev_idx < 0) || (dev_idx >= cont->ndev)) + return NULL; + + if (cont->index[dev_idx].type != dscDevice) + return NULL; + + base += cont->index[dev_idx].offset; + return (nxpTfaDeviceList_t *) base; +} + +/* + * get the Nth profile for the Nth device + */ +nxpTfaProfileList_t *tfaContGetDevProfList(nxpTfaContainer_t * cont, int devIdx, int profIdx) +{ + nxpTfaDeviceList_t *dev; + int idx, hit; + uint8_t *base = (uint8_t *) cont; + + dev = tfaContGetDevList(cont, devIdx); + if (dev) { + for (idx = 0, hit = 0; idx < dev->length; idx++) { + if (dev->list[idx].type == dscProfile) { + if (profIdx == hit++) + return (nxpTfaProfileList_t *) (dev->list[idx].offset+base); + } + } + } + + return NULL; +} + +/* + * get the number of profiles for the Nth device + */ +int tfa_cnt_get_dev_nprof(struct tfa_device *tfa) +{ + nxpTfaDeviceList_t *dev; + int idx, nprof = 0; + + if (tfa->cnt == NULL) + return 0; + + if ((tfa->dev_idx < 0) || (tfa->dev_idx >= tfa->cnt->ndev)) + return 0; + + dev = tfaContGetDevList(tfa->cnt, tfa->dev_idx); + if (dev) { + for (idx = 0; idx < dev->length; idx++) { + if (dev->list[idx].type == dscProfile) { + nprof++; + } + } + } + + return nprof; +} + +/* + * get the Nth lifedata for the Nth device + */ +nxpTfaLiveDataList_t *tfaContGetDevLiveDataList(nxpTfaContainer_t * cont, int devIdx, + int lifeDataIdx) +{ + nxpTfaDeviceList_t *dev; + int idx, hit; + uint8_t *base = (uint8_t *) cont; + + dev = tfaContGetDevList(cont, devIdx); + if (dev) { + for (idx = 0, hit = 0; idx < dev->length; idx++) { + if (dev->list[idx].type == dscLiveData) { + if (lifeDataIdx == hit++) + return (nxpTfaLiveDataList_t *) + (dev->list[idx].offset + base); + } + } + } + + return NULL; +} + +/* + * Get the max volume step associated with Nth profile for the Nth device + */ +int tfacont_get_max_vstep(struct tfa_device *tfa, int prof_idx) { + nxpTfaVolumeStep2File_t *vp; + struct nxpTfaVolumeStepMax2File *vp3; + int vstep_count = 0; + vp = (nxpTfaVolumeStep2File_t *) tfacont_getfiledata(tfa, prof_idx, volstepHdr); + if (vp == NULL) + return 0; + /* check the header type to load different NrOfVStep appropriately */ + if (tfa->tfa_family == 2) { + /* this is actually tfa2, so re-read the buffer*/ + vp3 = (struct nxpTfaVolumeStepMax2File *) + tfacont_getfiledata(tfa, prof_idx, volstepHdr); + if ( vp3 ) { + vstep_count = vp3->NrOfVsteps; + } + } else { + /* this is max1*/ + if ( vp ) { + vstep_count = vp->vsteps; + } + } + return vstep_count; +} + +/** + * Get the file contents associated with the device or profile + * Search within the device tree, if not found, search within the profile + * tree. There can only be one type of file within profile or device. + */ +nxpTfaFileDsc_t *tfacont_getfiledata(struct tfa_device *tfa, int prof_idx, enum nxpTfaHeaderType type) +{ + nxpTfaDeviceList_t *dev; + nxpTfaProfileList_t *prof; + nxpTfaFileDsc_t *file; + nxpTfaHeader_t *hdr; + unsigned int i; + + if (tfa->cnt == NULL) { + pr_err("invalid pointer to container file\n"); + return NULL; + } + + dev = tfaContGetDevList(tfa->cnt, tfa->dev_idx); + if (dev == NULL) { + pr_err("invalid pointer to container file device list\n"); + return NULL; + } + + /* process the device list until a file type is encountered */ + for (i=0;ilength;i++) { + if ( dev->list[i].type == dscFile ) { + file = (nxpTfaFileDsc_t *)(dev->list[i].offset+(uint8_t *)tfa->cnt); + if (file != NULL) { + hdr = (nxpTfaHeader_t *)file->data; + /* check for file type */ + if ( hdr->id == type) { + return (nxpTfaFileDsc_t *)&file->data; + } + } + } + } + + /* File not found in device tree. + * So, look in the profile list until the file type is encountered + */ + prof = tfaContGetDevProfList(tfa->cnt, tfa->dev_idx, prof_idx); + if (prof == NULL) { + pr_err("invalid pointer to container file profile list\n"); + return NULL; + } + + for (i=0;ilength;i++) { + if (prof->list[i].type == dscFile) { + file = (nxpTfaFileDsc_t *)(prof->list[i].offset+(uint8_t *)tfa->cnt); + if (file != NULL) { + hdr= (nxpTfaHeader_t *)file->data; + if (hdr != NULL) { + /* check for file type */ + if ( hdr->id == type) { + return (nxpTfaFileDsc_t *)&file->data; + } + } + } + } + } + + if (tfa->verbose) + pr_debug("%s: no file found of type %d\n", __FUNCTION__, type); + + return NULL; +} + +/* + * write a parameter file to the device + */ +static enum Tfa98xx_Error tfaContWriteVstep(struct tfa_device *tfa, nxpTfaVolumeStep2File_t *vp, int vstep) +{ + enum Tfa98xx_Error err; + unsigned short vol; + + if (vstep < vp->vsteps) { + /* vol = (unsigned short)(voldB / (-0.5f)); */ + vol = (unsigned short)(-2 * float_to_int(*((uint32_t *)&vp->vstep[vstep].attenuation))); + if (vol > 255) /* restricted to 8 bits */ + vol = 255; + + err = tfa98xx_set_volume_level(tfa, vol); + if (err != Tfa98xx_Error_Ok) + return err; + + err = tfa98xx_dsp_write_preset(tfa, sizeof(vp->vstep[0].preset), vp->vstep[vstep].preset); + if (err != Tfa98xx_Error_Ok) + return err; + err = tfa_cont_write_filterbank(tfa, vp->vstep[vstep].filter); + + } else { + pr_err("Incorrect volume given. The value vstep[%d] >= %d\n", vstep , vp->vsteps); + err = Tfa98xx_Error_Bad_Parameter; + } + + if (tfa->verbose) pr_debug("vstep[%d][%d]\n", tfa->dev_idx, vstep); + + return err; +} + +static struct nxpTfaVolumeStepMessageInfo * +tfaContGetmsgInfoFromReg(struct nxpTfaVolumeStepRegisterInfo *regInfo) +{ + char *p = (char*) regInfo; + p += sizeof(regInfo->NrOfRegisters) + (regInfo->NrOfRegisters * sizeof(uint32_t)); + return (struct nxpTfaVolumeStepMessageInfo*) p; +} + +static int +tfaContGetmsgLen(struct nxpTfaVolumeStepMessageInfo *msgInfo) +{ + return (msgInfo->MessageLength.b[0] << 16) + (msgInfo->MessageLength.b[1] << 8) + msgInfo->MessageLength.b[2]; +} + +static struct nxpTfaVolumeStepMessageInfo * +tfaContGetNextmsgInfo(struct nxpTfaVolumeStepMessageInfo *msgInfo) +{ + char *p = (char*) msgInfo; + int msgLen = tfaContGetmsgLen(msgInfo); + int type = msgInfo->MessageType; + + p += sizeof(msgInfo->MessageType) + sizeof(msgInfo->MessageLength); + if (type == 3) + p += msgLen; + else + p += msgLen * 3; + + return (struct nxpTfaVolumeStepMessageInfo*) p; +} + +static struct nxpTfaVolumeStepRegisterInfo* +tfaContGetNextRegFromEndInfo(struct nxpTfaVolumeStepMessageInfo *msgInfo) +{ + char *p = (char*) msgInfo; + p += sizeof(msgInfo->NrOfMessages); + return (struct nxpTfaVolumeStepRegisterInfo*) p; + +} + +static struct nxpTfaVolumeStepRegisterInfo* +tfaContGetRegForVstep(nxpTfaVolumeStepMax2File_t *vp, int idx) +{ + int i, j, nrMessage; + + struct nxpTfaVolumeStepRegisterInfo *regInfo + = (struct nxpTfaVolumeStepRegisterInfo*) vp->vstepsBin; + struct nxpTfaVolumeStepMessageInfo *msgInfo = NULL; + + for (i = 0; i < idx; i++) { + msgInfo = tfaContGetmsgInfoFromReg(regInfo); + nrMessage = msgInfo->NrOfMessages; + + for (j = 0; j < nrMessage; j++) { + msgInfo = tfaContGetNextmsgInfo(msgInfo); + } + regInfo = tfaContGetNextRegFromEndInfo(msgInfo); + } + + return regInfo; +} + +#pragma pack (push, 1) +struct tfa_partial_msg_block { + uint8_t offset; + uint16_t change; + uint8_t update[16][3]; +}; +#pragma pack (pop) + +static enum Tfa98xx_Error tfaContWriteVstepMax2_One(struct tfa_device *tfa, struct nxpTfaVolumeStepMessageInfo *new_msg, + struct nxpTfaVolumeStepMessageInfo *old_msg, int enable_partial_update) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + int len = (tfaContGetmsgLen(new_msg) - 1) * 3; + char *buf = (char*)new_msg->ParameterData; + uint8_t *partial = NULL; + uint8_t cmdid[3]; + int use_partial_coeff = 0; + + if (enable_partial_update) { + if (new_msg->MessageType != old_msg->MessageType) { + pr_debug("Message type differ - Disable Partial Update\n"); + enable_partial_update = 0; + } else if (tfaContGetmsgLen(new_msg) != tfaContGetmsgLen(old_msg)) { + pr_debug("Message Length differ - Disable Partial Update\n"); + enable_partial_update = 0; + } + } + + if ((enable_partial_update) && (new_msg->MessageType == 1)) { + /* No patial updates for message type 1 (Coefficients) */ + enable_partial_update = 0; + if ((tfa->rev & 0xff) == 0x88) { + use_partial_coeff = 1; + } else if ((tfa->rev & 0xff) == 0x13) { + use_partial_coeff = 1; + } + } + + /* Change Message Len to the actual buffer len */ + memcpy(cmdid, new_msg->CmdId, sizeof(cmdid)); + + /* The algoparams and mbdrc msg id will be changed to the reset type when SBSL=0 + * if SBSL=1 the msg will remain unchanged. It's up to the tuning engineer to choose the 'without_reset' + * types inside the vstep. In other words: the reset msg is applied during SBSL==0 else it remains unchanged. + */ + if (tfa_needs_reset(tfa) == 1) { + if (new_msg->MessageType == 0) { + cmdid[2] = SB_PARAM_SET_ALGO_PARAMS; + if (tfa->verbose) + pr_debug("P-ID for SetAlgoParams modified!\n"); + } else if (new_msg->MessageType == 2) { + cmdid[2] = SB_PARAM_SET_MBDRC; + if (tfa->verbose) + pr_debug("P-ID for SetMBDrc modified!\n"); + } + } + + /* + * +sizeof(struct tfa_partial_msg_block) will allow to fit one + * additonnal partial block If the partial update goes over the len of + * a regular message ,we can safely write our block and check afterward + * that we are over the size of a usual update + */ + if (enable_partial_update) { + partial = kmem_cache_alloc(tfa->cachep, GFP_KERNEL); + if (!partial) + pr_debug("Partial update memory error - Disabling\n"); + } + + if (partial) { + uint8_t offset = 0, i = 0; + uint16_t *change; + uint8_t *n = new_msg->ParameterData; + uint8_t *o = old_msg->ParameterData; + uint8_t *p = partial; + uint8_t* trim = partial; + + /* set dspFiltersReset */ + *p++ = 0x02; + *p++ = 0x00; + *p++ = 0x00; + + while ((o < (old_msg->ParameterData + len)) && + (p < (partial + len - 3))) { + if ((offset == 0xff) || + (memcmp(n, o, 3 * sizeof(uint8_t)))) { + *p++ = offset; + change = (uint16_t*) p; + *change = 0; + p += 2; + + for (i = 0; + (i < 16) && (o < (old_msg->ParameterData + len)); + i++, n += 3, o += 3) { + if (memcmp(n, o, 3 * sizeof(uint8_t))) { + *change |= BIT(i); + memcpy(p, n, 3); + p += 3; + trim = p; + } + } + + offset = 0; + *change = cpu_to_be16(*change); + } else { + n += 3; + o += 3; + offset++; + } + } + + if (trim == partial) { + pr_debug("No Change in message - discarding %d bytes\n", len); + len = 0; + + } else if (trim < (partial + len - 3)) { + pr_debug("Using partial update: %d -> %d bytes\n", len , (int)(trim-partial+3)); + + /* Add the termination marker */ + memset(trim, 0x00, 3); + trim += 3; + + /* Signal This will be a partial update */ + cmdid[2] |= BIT(6); + buf = (char*) partial; + len = (int)(trim - partial); + } else { + pr_debug("Partial too big - use regular update\n"); + } + } + + if (use_partial_coeff) { + err = dsp_partial_coefficients(tfa, old_msg->ParameterData, new_msg->ParameterData); + } else if (len) { + uint8_t *buffer; + + if (tfa->verbose) + pr_debug("Command-ID used: 0x%02x%02x%02x \n", cmdid[0], cmdid[1], cmdid[2]); + + buffer = kmem_cache_alloc(tfa->cachep, GFP_KERNEL); + if (buffer == NULL) { + err = Tfa98xx_Error_Fail; + } else { + memcpy(&buffer[0], cmdid, 3); + memcpy(&buffer[3], buf, len); + err = dsp_msg(tfa, 3 + len, (char *)buffer); + kmem_cache_free(tfa->cachep, buffer); + } + } + + if (partial) + kmem_cache_free(tfa->cachep, partial); + + return err; +} + +static enum Tfa98xx_Error tfaContWriteVstepMax2(struct tfa_device *tfa, nxpTfaVolumeStepMax2File_t *vp, int vstep_idx, int vstep_msg_idx) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + struct nxpTfaVolumeStepRegisterInfo *regInfo = NULL; + struct nxpTfaVolumeStepMessageInfo *msgInfo = NULL, *p_msgInfo = NULL; + nxpTfaBitfield_t bitF; + int i, nrMessages, enp = tfa->partial_enable; + + if (vstep_idx >= vp->NrOfVsteps) { + pr_debug("Volumestep %d is not available \n", vstep_idx); + return Tfa98xx_Error_Bad_Parameter; + } + + if (tfa->p_regInfo == NULL) { + if (tfa->verbose) + pr_debug("Inital vstep write\n"); + enp = 0; + } + + regInfo = tfaContGetRegForVstep(vp, vstep_idx); + + msgInfo = tfaContGetmsgInfoFromReg(regInfo); + nrMessages = msgInfo->NrOfMessages; + + if (enp) { + p_msgInfo = tfaContGetmsgInfoFromReg(tfa->p_regInfo); + if (nrMessages != p_msgInfo->NrOfMessages) { + pr_debug("Message different - Disable partial update\n"); + enp = 0; + } + } + + for (i = 0; i < nrMessages; i++) { + /* Messagetype(3) is Smartstudio Info! Dont send this! */ + if(msgInfo->MessageType == 3) { + /* MessageLength is in bytes */ + msgInfo = tfaContGetNextmsgInfo(msgInfo); + if(enp) + p_msgInfo = tfaContGetNextmsgInfo(p_msgInfo); + continue; + } + + /* If no vstepMsgIndex is passed on, all message needs to be send */ + if ((vstep_msg_idx >= TFA_MAX_VSTEP_MSG_MARKER) || (vstep_msg_idx == i)) { + err = tfaContWriteVstepMax2_One(tfa, msgInfo, p_msgInfo, enp); + if (err != Tfa98xx_Error_Ok) { + /* + * Force a full update for the next write + * As the current status of the DSP is unknown + */ + tfa->p_regInfo = NULL; + return err; + } + } + + msgInfo = tfaContGetNextmsgInfo(msgInfo); + if(enp) + p_msgInfo = tfaContGetNextmsgInfo(p_msgInfo); + } + + tfa->p_regInfo = regInfo; + + for(i=0; iNrOfRegisters*2; i++) { + /* Byte swap the datasheetname */ + bitF.field = (uint16_t)(regInfo->registerInfo[i]>>8) | (regInfo->registerInfo[i]<<8); + i++; + bitF.value = (uint16_t)regInfo->registerInfo[i]>>8; + err = tfaRunWriteBitfield(tfa , bitF); + if (err != Tfa98xx_Error_Ok) + return err; + } + + /* Save the current vstep */ + tfa_dev_set_swvstep(tfa, (unsigned short)vstep_idx); + + return err; +} + +/* + * Write DRC message to the dsp + * If needed modify the cmd-id + */ + +enum Tfa98xx_Error tfaContWriteDrcFile(struct tfa_device *tfa, int size, uint8_t data[]) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + uint8_t *msg = NULL; + + msg = kmem_cache_alloc(tfa->cachep, GFP_KERNEL); + if (msg == NULL) + return Tfa98xx_Error_Fail; + memcpy(msg, data, size); + + if (TFA_GET_BF(tfa, SBSL) == 0) { + /* Only do this when not set already */ + if (msg[2] != SB_PARAM_SET_MBDRC) { + msg[2] = SB_PARAM_SET_MBDRC; + + if (tfa->verbose) { + pr_debug("P-ID for SetMBDrc modified!: "); + pr_debug("Command-ID used: 0x%02x%02x%02x \n", + msg[0], msg[1], msg[2]); + } + } + } + + /* Send cmdId + payload to dsp */ + err = dsp_msg(tfa, size, (const char *)msg); + + kmem_cache_free(tfa->cachep, msg); + + return err; +} + + +/* + * write a parameter file to the device + * The VstepIndex and VstepMsgIndex are only used to write a specific msg from the vstep file. + */ +enum Tfa98xx_Error tfaContWriteFile(struct tfa_device *tfa, nxpTfaFileDsc_t *file, int vstep_idx, int vstep_msg_idx) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + nxpTfaHeader_t *hdr = (nxpTfaHeader_t *)file->data; + nxpTfaHeaderType_t type; + int size; + + if (tfa->verbose) { + tfaContShowHeader(hdr); + } + + type = (nxpTfaHeaderType_t) hdr->id; + + switch (type) { + case msgHdr: /* generic DSP message */ + size = hdr->size - sizeof(nxpTfaMsgFile_t); + err = dsp_msg(tfa, size, (const char *)((nxpTfaMsgFile_t *)hdr)->data); + break; + case volstepHdr: + if (tfa->tfa_family == 2) { + err = tfaContWriteVstepMax2(tfa, (nxpTfaVolumeStepMax2File_t *)hdr, vstep_idx, vstep_msg_idx); + } else { + err = tfaContWriteVstep(tfa, (nxpTfaVolumeStep2File_t *)hdr, vstep_idx); + } + break; + case speakerHdr: + if (tfa->tfa_family == 2) { + /* Remove header and xml_id */ + size = hdr->size - sizeof(struct nxpTfaSpkHeader) - sizeof(struct nxpTfaFWVer); + + err = dsp_msg(tfa, size, + (const char *)(((nxpTfaSpeakerFile_t *)hdr)->data + (sizeof(struct nxpTfaFWVer)))); + } else { + size = hdr->size - sizeof(nxpTfaSpeakerFile_t); + err = tfa98xx_dsp_write_speaker_parameters(tfa, size, + (const unsigned char *)((nxpTfaSpeakerFile_t *)hdr)->data); + } + break; + case presetHdr: + size = hdr->size - sizeof(nxpTfaPreset_t); + err = tfa98xx_dsp_write_preset(tfa, size, (const unsigned char *)((nxpTfaPreset_t *)hdr)->data); + break; + case equalizerHdr: + err = tfa_cont_write_filterbank(tfa, ((nxpTfaEqualizerFile_t *)hdr)->filter); + break; + case patchHdr: + size = hdr->size - sizeof(nxpTfaPatch_t ); // size is total length + err = tfa_dsp_patch(tfa, size, (const unsigned char *) ((nxpTfaPatch_t *)hdr)->data); + break; + case configHdr: + size = hdr->size - sizeof(nxpTfaConfig_t); + err = tfa98xx_dsp_write_config(tfa, size, (const unsigned char *)((nxpTfaConfig_t *)hdr)->data); + break; + case drcHdr: + if(hdr->version[0] == NXPTFA_DR3_VERSION) { + /* Size is total size - hdrsize(36) - xmlversion(3) */ + size = hdr->size - sizeof(nxpTfaDrc2_t); + err = tfaContWriteDrcFile(tfa, size, ((nxpTfaDrc2_t *)hdr)->data); + } else { + /* + * The DRC file is split as: + * 36 bytes for generic header (customer, application, and type) + * 127x3 (381) bytes first block contains the device and sample rate + * independent settings + * 127x3 (381) bytes block the device and sample rate specific values. + * The second block can always be recalculated from the first block, + * if vlsCal and the sample rate are known. + */ + //size = hdr->size - sizeof(nxpTfaDrc_t); + size = 381; /* fixed size for first block */ + + //+381 is done to only send the second part of the drc block + err = tfa98xx_dsp_write_drc(tfa, size, ((const unsigned char *)((nxpTfaDrc_t *)hdr)->data+381)); + } + break; + case infoHdr: + /* Ignore */ + break; + default: + pr_err("Header is of unknown type: 0x%x\n", type); + return Tfa98xx_Error_Bad_Parameter; + } + + return err; +} + +/** + * get the 1st of this dsc type this devicelist + */ +static nxpTfaDescPtr_t *tfa_cnt_get_dsc(nxpTfaContainer_t *cnt, nxpTfaDescriptorType_t type, int dev_idx) +{ + nxpTfaDeviceList_t *dev = tfaContDevice(cnt, dev_idx); + nxpTfaDescPtr_t *_this; + int i; + + if ( !dev ) { + return NULL; + } + /* process the list until a the type is encountered */ + for(i=0;ilength;i++) { + if ( dev->list[i].type == (uint32_t)type ) { + _this = (nxpTfaDescPtr_t *)(dev->list[i].offset+(uint8_t *)cnt); + return _this; + } + + } + + return NULL; +} + +/** + * get the device type from the patch in this devicelist + * - find the patch file for this devidx + * - return the devid from the patch or 0 if not found + */ +int tfa_cnt_get_devid(nxpTfaContainer_t *cnt, int dev_idx) +{ + nxpTfaPatch_t *patchfile; + nxpTfaDescPtr_t *patchdsc; + uint8_t *patchheader; + unsigned short devid, checkaddress; + int checkvalue; + + patchdsc = tfa_cnt_get_dsc(cnt, dscPatch, dev_idx); + if ( !patchdsc ) /* no patch for this device, assume non-i2c */ + return 0; + patchdsc += 2; /* first the filename dsc and filesize, so skip them */ + patchfile = (nxpTfaPatch_t *)patchdsc; + + patchheader = patchfile->data; + + checkaddress = (patchheader[1] << 8) + patchheader[2]; + checkvalue = + (patchheader[3] << 16) + (patchheader[4] << 8) + patchheader[5]; + + devid = patchheader[0]; + + if(checkaddress == 0xFFFF && checkvalue != 0xFFFFFF && checkvalue != 0) { + devid = patchheader[5]<<8 | patchheader[0]; /* full revid */ + } + + return devid; +} + +/** + * get the firmware version from the patch in this devicelist + */ +int tfa_cnt_get_patch_version(struct tfa_device *tfa) +{ + nxpTfaPatch_t *patchfile; + nxpTfaDescPtr_t *patchdsc; + uint8_t *data; + int size, version; + + if (tfa->cnt == NULL) + return -1; + + patchdsc = tfa_cnt_get_dsc(tfa->cnt, dscPatch, tfa->dev_idx); + patchdsc += 2; /* first the filename dsc and filesize, so skip them */ + patchfile = (nxpTfaPatch_t *)patchdsc; + + size = patchfile->hdr.size - sizeof(nxpTfaPatch_t); + data = patchfile->data; + + version = (data[size-3] << 16) + (data[size-2] << 8) + data[size-1]; + + return version; +} + + +/* + * get the slave for the device if it exists + */ +enum Tfa98xx_Error tfaContGetSlave(struct tfa_device *tfa, uint8_t *slave_addr) +{ + nxpTfaDeviceList_t *dev = NULL; + + /* Make sure the cnt file is loaded */ + if (tfa->cnt != NULL) { + dev = tfaContDevice(tfa->cnt, tfa->dev_idx); + } + + if (dev == NULL) { + /* Check if slave argument is used! */ + if(gslave_address == 0) { + return Tfa98xx_Error_Bad_Parameter; + } else { + *slave_addr = gslave_address; + return Tfa98xx_Error_Ok; + } + } + + *slave_addr = dev->dev; + return Tfa98xx_Error_Ok; +} + +/* If no container file is given, we can always have used the slave argument */ +void tfaContSetSlave(uint8_t slave_addr) +{ + gslave_address = slave_addr; +} + +/* + * lookup slave and return device index + */ +int tfa_cont_get_idx(struct tfa_device *tfa) +{ + nxpTfaDeviceList_t *dev = NULL; + int i; + + for (i=0; icnt->ndev; i++) { + dev = tfaContDevice(tfa->cnt, i); + if (dev->dev == tfa->slave_address) + break; + + } + if (i == tfa->cnt->ndev) + return -1; + + return i; +} + +/* + * write a bit field + */ +enum Tfa98xx_Error tfaRunWriteBitfield(struct tfa_device *tfa, nxpTfaBitfield_t bf) +{ + enum Tfa98xx_Error error; + uint16_t value; + union { + uint16_t field; + nxpTfaBfEnum_t Enum; + } bfUni; + + value=bf.value; + bfUni.field = bf.field; +#if 1//def TFA_DEBUG + if (tfa->verbose) + // pr_err ("tfa bitfield: %s=0x%x (0x%x[%d..%d]=0x%x)\n", tfaContBfName(bfUni.field, tfa->rev), value, + // bfUni.Enum.address, bfUni.Enum.pos, bfUni.Enum.pos+bfUni.Enum.len, value); + pr_err ("tfa bitfield: 0x%x value : 0x%x)\n", value, + bfUni.field); + +#endif + error = tfa_set_bf(tfa, bfUni.field, value); + + return error; +} + +/* + * read a bit field + */ +enum Tfa98xx_Error tfaRunReadBitfield(struct tfa_device *tfa, nxpTfaBitfield_t *bf) +{ + enum Tfa98xx_Error error; + union { + uint16_t field; + nxpTfaBfEnum_t Enum; + } bfUni; + uint16_t regvalue, msk; + + bfUni.field = bf->field; + + error = reg_read(tfa, (unsigned char)(bfUni.Enum.address), ®value); + if (error) return error; + + msk = ((1<<(bfUni.Enum.len+1))-1)<value = regvalue>>bfUni.Enum.pos; + + return error; +} + +/* + dsp mem direct write + */ +static enum Tfa98xx_Error tfaRunWriteDspMem(struct tfa_device *tfa, nxpTfaDspMem_t *cfmem) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + int i; + + for(i=0;isize;i++) { + if (tfa->verbose) + pr_debug("dsp mem (%d): 0x%02x=0x%04x\n", cfmem->type, cfmem->address, cfmem->words[i]); + + error = mem_write(tfa, cfmem->address++, cfmem->words[i], cfmem->type); + if (error) return error; + } + + return error; +} + +/* + * write filter payload to DSP + * note that the data is in an aligned union for all filter variants + * the aa data is used but it's the same for all of them + */ +static enum Tfa98xx_Error tfaRunWriteFilter(struct tfa_device *tfa, nxpTfaContBiquad_t *bq) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + enum Tfa98xx_DMEM dmem; + uint16_t address; + uint8_t data[3*3+sizeof(bq->aa.bytes)]; + int i, channel=0, runs=1; + int8_t saved_index=bq->aa.index; /* This is used to set back the index */ + + /* Channel=1 is primary, Channel=2 is secondary*/ + if (bq->aa.index > 100) { + bq->aa.index -= 100; + channel = 2; + } else if (bq->aa.index > 50) { + bq->aa.index -= 50; + channel = 1; + } else if((tfa->rev & 0xff) == 0x88) { + runs=2; + } + + if (tfa->verbose) { + if(channel == 2) + pr_debug("filter[%d,S]", bq->aa.index); + else if(channel == 1) + pr_debug("filter[%d,P]", bq->aa.index); + else + pr_debug("filter[%d]", bq->aa.index); + } + + for(i=0; iaa.index, &address, channel); + if(dmem == Tfa98xx_DMEM_ERR) { + if (tfa->verbose) { + pr_debug("Warning: XFilter settings are applied via msg file (ini filter[x] format is skipped).\n"); + } + /* Dont exit with an error here, We could continue without problems */ + return Tfa98xx_Error_Ok; + } + + /* send a DSP memory message that targets the devices specific memory for the filter + * msg params: which_mem, start_offset, num_words + */ + memset(data, 0, 3*3); + data[2] = dmem; /* output[0] = which_mem */ + data[4] = address >> 8; /* output[1] = start_offset */ + data[5] = address & 0xff; + data[8] = sizeof(bq->aa.bytes)/3; /*output[2] = num_words */ + memcpy( &data[9], bq->aa.bytes, sizeof(bq->aa.bytes)); /* payload */ + + if(tfa->tfa_family == 2) { + error = tfa_dsp_cmd_id_write(tfa, MODULE_FRAMEWORK, FW_PAR_ID_SET_MEMORY, sizeof(data), data); + } else { + error = tfa_dsp_cmd_id_write(tfa, MODULE_FRAMEWORK, 4 /* param */ , sizeof(data), data); + } + } + +#ifdef TFA_DEBUG + if (tfa->verbose) { + if (bq->aa.index==13) { + pr_debug("=%d,%.0f,%.2f \n", + bq->in.type, bq->in.cutOffFreq, bq->in.leakage); + } else if(bq->aa.index >= 10 && bq->aa.index <= 12) { + pr_debug("=%d,%.0f,%.1f,%.1f \n", bq->aa.type, + bq->aa.cutOffFreq, bq->aa.rippleDb, bq->aa.rolloff); + } else { + pr_debug("= unsupported filter index \n"); + } + } +#endif + + /* Because we can load the same filters multiple times + * For example: When we switch profile we re-write in operating mode. + * We then need to remember the index (primary, secondary or both) + */ + bq->aa.index = saved_index; + + return error; +} + +/* + * write the register based on the input address, value and mask + * only the part that is masked will be updated + */ +static enum Tfa98xx_Error tfaRunWriteRegister(struct tfa_device *tfa, nxpTfaRegpatch_t *reg) +{ + enum Tfa98xx_Error error; + uint16_t value,newvalue; + + if (tfa->verbose) + pr_debug("register: 0x%02x=0x%04x (msk=0x%04x)\n", reg->address, reg->value, reg->mask); + + error = reg_read(tfa, reg->address, &value); + if (error) return error; + + value &= ~reg->mask; + newvalue = reg->value & reg->mask; + + value |= newvalue; + error = reg_write(tfa, reg->address, value); + + return error; + +} + +// write reg and bitfield items in the devicelist to the target +enum Tfa98xx_Error tfaContWriteRegsDev(struct tfa_device *tfa) +{ + nxpTfaDeviceList_t *dev = tfaContDevice(tfa->cnt, tfa->dev_idx); + nxpTfaBitfield_t *bitF; + int i; + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + + if ( !dev ) { + return Tfa98xx_Error_Bad_Parameter; + } + + /* process the list until a patch, file of profile is encountered */ + for(i=0;ilength;i++) { + if ( dev->list[i].type == dscPatch || + dev->list[i].type ==dscFile || + dev->list[i].type ==dscProfile ) break; + + if ( dev->list[i].type == dscBitfield) { + bitF = (nxpTfaBitfield_t *)( dev->list[i].offset+(uint8_t *)tfa->cnt); + err = tfaRunWriteBitfield(tfa , *bitF); + } + if ( dev->list[i].type == dscRegister ) { + err = tfaRunWriteRegister(tfa, (nxpTfaRegpatch_t *)( dev->list[i].offset+(char*)tfa->cnt)); + } + + if ( err ) break; + } + + return err; +} + +// write reg and bitfield items in the profilelist the target +enum Tfa98xx_Error tfaContWriteRegsProf(struct tfa_device *tfa, int prof_idx) +{ + nxpTfaProfileList_t *prof = tfaContGetDevProfList(tfa->cnt, tfa->dev_idx, prof_idx); + nxpTfaBitfield_t *bitf; + unsigned int i; + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + + if ( !prof ) { + return Tfa98xx_Error_Bad_Parameter; + } + + if (tfa->verbose) + pr_debug("----- profile: %s (%d) -----\n", tfaContGetString(tfa->cnt, &prof->name), prof_idx); + + /* process the list until the end of the profile or the default section */ + for(i=0;ilength;i++) { + /* We only want to write the values before the default section when we switch profile */ + if(prof->list[i].type == dscDefault) + break; + + if ( prof->list[i].type == dscBitfield) { + bitf = (nxpTfaBitfield_t *)( prof->list[i].offset+(uint8_t *)tfa->cnt); + err = tfaRunWriteBitfield(tfa , *bitf); + } + if ( prof->list[i].type == dscRegister ) { + err = tfaRunWriteRegister(tfa, (nxpTfaRegpatch_t *)( prof->list[i].offset+(char*)tfa->cnt)); + } + if ( err ) break; + } + return err; +} + +// write patchfile in the devicelist to the target +enum Tfa98xx_Error tfaContWritePatch(struct tfa_device *tfa) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + nxpTfaDeviceList_t *dev = tfaContDevice(tfa->cnt, tfa->dev_idx); + nxpTfaFileDsc_t *file; + nxpTfaPatch_t *patchfile; + int size, i; + + if ( !dev ) { + return Tfa98xx_Error_Bad_Parameter; + } + /* process the list until a patch is encountered */ + for(i=0;ilength;i++) { + if ( dev->list[i].type == dscPatch ) { + file = (nxpTfaFileDsc_t *)(dev->list[i].offset+(uint8_t *)tfa->cnt); + patchfile =(nxpTfaPatch_t *)&file->data; + if (tfa->verbose) tfaContShowHeader(&patchfile->hdr); + size = patchfile->hdr.size - sizeof(nxpTfaPatch_t ); // size is total length + err = tfa_dsp_patch(tfa, size, (const unsigned char *) patchfile->data); + if ( err ) return err; + } + } + + return Tfa98xx_Error_Ok; +} + +/** + * Create a buffer which can be used to send to the dsp. + */ +static void create_dsp_buffer_msg(struct tfa_device *tfa, nxpTfaMsg_t *msg, char *buffer, int *size) +{ + int i, nr = 0; + + (void)tfa; + + /* Copy cmdId. Remember that the cmdId is reversed */ + buffer[nr++] = msg->cmdId[2]; + buffer[nr++] = msg->cmdId[1]; + buffer[nr++] = msg->cmdId[0]; + + /* Copy the data to the buffer */ + for(i=0; imsg_size; i++) { + buffer[nr++] = (uint8_t) ((msg->data[i] >> 16) & 0xffff); + buffer[nr++] = (uint8_t) ((msg->data[i] >> 8) & 0xff); + buffer[nr++] = (uint8_t) (msg->data[i] & 0xff); + } + + *size = nr; +} + +// write all param files in the devicelist to the target +enum Tfa98xx_Error tfaContWriteFiles(struct tfa_device *tfa) +{ + nxpTfaDeviceList_t *dev = tfaContDevice(tfa->cnt, tfa->dev_idx); + nxpTfaFileDsc_t *file; + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + char buffer[(MEMTRACK_MAX_WORDS * 3) + 3] = {0}; //every word requires 3 and 3 is the msg + int i, size = 0; + + if ( !dev ) { + return Tfa98xx_Error_Bad_Parameter; + } + /* process the list and write all files */ + for(i=0;ilength;i++) { + if ( dev->list[i].type == dscFile ) { + file = (nxpTfaFileDsc_t *)(dev->list[i].offset+(uint8_t *)tfa->cnt); + if ( tfaContWriteFile(tfa, file, 0 , TFA_MAX_VSTEP_MSG_MARKER) ){ + return Tfa98xx_Error_Bad_Parameter; + } + } + + if ( dev->list[i].type == dscSetInputSelect || + dev->list[i].type == dscSetOutputSelect || + dev->list[i].type == dscSetProgramConfig || + dev->list[i].type == dscSetLagW || + dev->list[i].type == dscSetGains || + dev->list[i].type == dscSetvBatFactors || + dev->list[i].type == dscSetSensesCal || + dev->list[i].type == dscSetSensesDelay || + dev->list[i].type == dscSetMBDrc || + dev->list[i].type == dscSetFwkUseCase || + dev->list[i].type == dscSetVddpConfig ) { + create_dsp_buffer_msg(tfa, (nxpTfaMsg_t *) + ( dev->list[i].offset+(char*)tfa->cnt), buffer, &size); + if (tfa->verbose) { + pr_debug("command: %s=0x%02x%02x%02x \n", + tfaContGetCommandString(dev->list[i].type), + (unsigned char)buffer[0], (unsigned char)buffer[1], (unsigned char)buffer[2]); + } + + err = dsp_msg(tfa, size, buffer); + } + + if ( dev->list[i].type == dscCmd ) { + size = *(uint16_t *)(dev->list[i].offset+(char*)tfa->cnt); + + err = dsp_msg(tfa, size, dev->list[i].offset+2+(char*)tfa->cnt); + if (tfa->verbose) { + const char *cmd_id = dev->list[i].offset+2+(char*)tfa->cnt; + pr_debug("Writing cmd=0x%02x%02x%02x \n", (uint8_t)cmd_id[0], (uint8_t)cmd_id[1], (uint8_t)cmd_id[2]); + } + } + if (err != Tfa98xx_Error_Ok) + break; + + if ( dev->list[i].type == dscCfMem ) { + err = tfaRunWriteDspMem(tfa, (nxpTfaDspMem_t *)(dev->list[i].offset+(uint8_t *)tfa->cnt)); + } + + if (err != Tfa98xx_Error_Ok) + break; + } + + return err; +} + +/* + * write all param files in the profilelist to the target + * this is used during startup when maybe ACS is set + */ +enum Tfa98xx_Error tfaContWriteFilesProf(struct tfa_device *tfa, int prof_idx, int vstep_idx) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + nxpTfaProfileList_t *prof = tfaContGetDevProfList(tfa->cnt, tfa->dev_idx, prof_idx); + char buffer[(MEMTRACK_MAX_WORDS * 3) + 3] = {0}; //every word requires 3 and 3 is the msg + unsigned int i; + nxpTfaFileDsc_t *file; + nxpTfaPatch_t *patchfile; + int size; + + if ( !prof ) { + return Tfa98xx_Error_Bad_Parameter; + } + + /* process the list and write all files */ + for(i=0;ilength;i++) { + switch (prof->list[i].type) { + case dscFile: + file = (nxpTfaFileDsc_t *)(prof->list[i].offset+(uint8_t *)tfa->cnt); + err = tfaContWriteFile(tfa, file, vstep_idx, TFA_MAX_VSTEP_MSG_MARKER); + break; + case dscPatch: + file = (nxpTfaFileDsc_t *)(prof->list[i].offset+(uint8_t *)tfa->cnt); + patchfile =(nxpTfaPatch_t *)&file->data; + if (tfa->verbose) tfaContShowHeader(&patchfile->hdr); + size = patchfile->hdr.size - sizeof(nxpTfaPatch_t ); // size is total length + err = tfa_dsp_patch(tfa, size, (const unsigned char *) patchfile->data); + break; + case dscCfMem: + err = tfaRunWriteDspMem(tfa, (nxpTfaDspMem_t *)(prof->list[i].offset+(uint8_t *)tfa->cnt)); + break; + case dscSetInputSelect: + case dscSetOutputSelect: + case dscSetProgramConfig: + case dscSetLagW: + case dscSetGains: + case dscSetvBatFactors: + case dscSetSensesCal: + case dscSetSensesDelay: + case dscSetMBDrc: + case dscSetFwkUseCase: + case dscSetVddpConfig: + create_dsp_buffer_msg(tfa, (nxpTfaMsg_t *) + (prof->list[i].offset+(uint8_t *)tfa->cnt), buffer, &size); + if (tfa->verbose) { + pr_debug("command: %s=0x%02x%02x%02x \n", + tfaContGetCommandString(prof->list[i].type), + (unsigned char)buffer[0], (unsigned char)buffer[1], (unsigned char)buffer[2]); + } + + err = dsp_msg(tfa, size, buffer); + break; + default: + /* ignore any other type */ + break; + } + } + + return err; +} + +static enum Tfa98xx_Error tfaContWriteItem(struct tfa_device *tfa, nxpTfaDescPtr_t * dsc) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + nxpTfaRegpatch_t *reg; + nxpTfaMode_t *cas; + nxpTfaBitfield_t *bitf; + + // When no DSP should only write to HW registers. + if(tfa->ext_dsp == 0 && !(dsc->type == dscBitfield || dsc->type == dscRegister)) { + return Tfa98xx_Error_Ok; + } + + switch (dsc->type) { + case dscDefault: + case dscDevice: // ignore + case dscProfile: // profile list + break; + case dscRegister: // register patch + reg = (nxpTfaRegpatch_t *)(dsc->offset+(uint8_t *)tfa->cnt); + return tfaRunWriteRegister(tfa, reg); + //pr_debug("$0x%2x=0x%02x,0x%02x\n", reg->address, reg->mask, reg->value); + break; + case dscString: // ascii: zero terminated string + pr_debug(";string: %s\n", tfaContGetString(tfa->cnt, dsc)); + break; + case dscFile: // filename + file contents + case dscPatch: + break; + case dscMode: + cas = (nxpTfaMode_t *)(dsc->offset+(uint8_t *)tfa->cnt); + if(cas->value == Tfa98xx_Mode_RCV) + tfa98xx_select_mode(tfa, Tfa98xx_Mode_RCV); + else + tfa98xx_select_mode(tfa, Tfa98xx_Mode_Normal); + break; + case dscCfMem: + err = tfaRunWriteDspMem(tfa, (nxpTfaDspMem_t *)(dsc->offset+(uint8_t *)tfa->cnt)); + break; + case dscBitfield: + bitf = (nxpTfaBitfield_t *)(dsc->offset+(uint8_t *)tfa->cnt); + return tfaRunWriteBitfield(tfa , *bitf); + break; + case dscFilter: + return tfaRunWriteFilter(tfa, (nxpTfaContBiquad_t *)(dsc->offset+(uint8_t *)tfa->cnt)); + break; + } + + return err; +} + +static unsigned int tfa98xx_sr_from_field(unsigned int field) +{ + switch (field) { + case 0: + return 8000; + case 1: + return 11025; + case 2: + return 12000; + case 3: + return 16000; + case 4: + return 22050; + case 5: + return 24000; + case 6: + return 32000; + case 7: + return 44100; + case 8: + return 48000; + default: + return 0; + } +} + +enum Tfa98xx_Error tfa_write_filters(struct tfa_device *tfa, int prof_idx) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + nxpTfaProfileList_t *prof = tfaContGetDevProfList(tfa->cnt, tfa->dev_idx, prof_idx); + unsigned int i; + int status; + + if ( !prof ) { + return Tfa98xx_Error_Bad_Parameter; + } + + if (tfa->verbose) { + pr_debug("----- profile: %s (%d) -----\n", tfaContGetString(tfa->cnt, &prof->name), prof_idx); + pr_debug("Waiting for CLKS... \n"); + } + + for(i=10; i>0; i--) { + err = tfa98xx_dsp_system_stable(tfa, &status); + if(status) + break; + else + msleep_interruptible(10); + } + + if(i==0) { + if (tfa->verbose) + pr_err("Unable to write filters, CLKS=0 \n"); + + return Tfa98xx_Error_StateTimedOut; + } + + /* process the list until the end of the profile or the default section */ + for(i=0;ilength;i++) { + if ( prof->list[i].type == dscFilter ) { + if (tfaContWriteItem(tfa, &prof->list[i]) != Tfa98xx_Error_Ok) + return Tfa98xx_Error_Bad_Parameter; + } + } + + return err; +} + +unsigned int tfa98xx_get_profile_sr(struct tfa_device *tfa, unsigned int prof_idx) +{ + nxpTfaBitfield_t *bitf; + unsigned int i; + nxpTfaDeviceList_t *dev; + nxpTfaProfileList_t *prof; + int fs_profile = -1; + + dev = tfaContDevice(tfa->cnt, tfa->dev_idx); + if (!dev) + return 0; + + prof = tfaContGetDevProfList(tfa->cnt, tfa->dev_idx, prof_idx); + if (!prof) + return 0; + + /* Check profile fields first */ + for(i = 0; i < prof->length; i++) { + if(prof->list[i].type == dscDefault) + break; + + /* check for profile settingd (AUDFS) */ + if (prof->list[i].type == dscBitfield) { + bitf = (nxpTfaBitfield_t *)(prof->list[i].offset+(uint8_t *)tfa->cnt); + if (bitf->field == TFA_FAM(tfa, AUDFS)) { + fs_profile = bitf->value; + break; + } + } + } + + if (tfa->verbose) + pr_debug("%s - profile fs: 0x%x = %dHz (%d - %d)\n", + __FUNCTION__, fs_profile, + tfa98xx_sr_from_field(fs_profile), + tfa->dev_idx, prof_idx); + + if (fs_profile != -1) + return tfa98xx_sr_from_field(fs_profile); + + /* Check for container default setting */ + /* process the list until a patch, file of profile is encountered */ + for(i = 0; i < dev->length; i++) { + if (dev->list[i].type == dscPatch || + dev->list[i].type ==dscFile || + dev->list[i].type ==dscProfile) + break; + + if (dev->list[i].type == dscBitfield) { + bitf = (nxpTfaBitfield_t *)( dev->list[i].offset+(uint8_t *)tfa->cnt); + if (bitf->field == TFA_FAM(tfa, AUDFS)) { + fs_profile = bitf->value; + break; + } + } + /* Ignore register case */ + } + + if (tfa->verbose) + pr_debug("%s - default fs: 0x%x = %dHz (%d - %d)\n", + __FUNCTION__, fs_profile, + tfa98xx_sr_from_field(fs_profile), + tfa->dev_idx, prof_idx); + + if (fs_profile != -1) + return tfa98xx_sr_from_field(fs_profile); + + return 48000; /* default of HW */ +} + +static enum Tfa98xx_Error get_sample_rate_info(struct tfa_device *tfa, nxpTfaProfileList_t *prof, nxpTfaProfileList_t *previous_prof, int fs_previous_profile) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + nxpTfaBitfield_t *bitf; + unsigned int i; + int fs_default_profile=8; /* default is 48kHz */ + int fs_next_profile=8; /* default is 48kHz */ + + + /* ---------- default settings previous profile ---------- */ + for(i=0;ilength;i++) { + /* Search for the default section */ + if(i == 0) { + while(previous_prof->list[i].type != dscDefault && i < previous_prof->length) { + i++; + } + i++; + } + + /* Only if we found the default section search for AUDFS */ + if(i < previous_prof->length) { + if ( previous_prof->list[i].type == dscBitfield ) { + bitf = (nxpTfaBitfield_t *)(previous_prof->list[i].offset+(uint8_t *)tfa->cnt); + if(bitf->field == TFA_FAM(tfa, AUDFS)) { + fs_default_profile = bitf->value; + break; + } + } + } + } + + /* ---------- settings next profile ---------- */ + for(i=0;ilength;i++) { + /* We only want to write the values before the default section */ + if(prof->list[i].type == dscDefault) + break; + /* search for AUDFS */ + if ( prof->list[i].type == dscBitfield ) { + bitf = (nxpTfaBitfield_t *)(prof->list[i].offset+(uint8_t *)tfa->cnt); + if(bitf->field == TFA_FAM(tfa, AUDFS)) { + fs_next_profile = bitf->value; + break; + } + } + } + + /* Enable if needed for debugging! + if (tfa->verbose) { + pr_debug("sample rate from the previous profile: %d \n", fs_previous_profile); + pr_debug("sample rate in the default section: %d \n", fs_default_profile); + pr_debug("sample rate for the next profile: %d \n", fs_next_profile); + } + */ + + if(fs_next_profile != fs_default_profile) { + if (tfa->verbose) + pr_debug("Writing delay tables for AUDFS=%d \n", fs_next_profile); + + /* If the AUDFS from the next profile is not the same as + * the AUDFS from the default we need to write new delay tables + */ + err = tfa98xx_dsp_write_tables(tfa, fs_next_profile); + } else if(fs_default_profile != fs_previous_profile) { + if (tfa->verbose) + pr_debug("Writing delay tables for AUDFS=%d \n", fs_default_profile); + + /* But if we do not have a new AUDFS in the next profile and + * the AUDFS from the default profile is not the same as the AUDFS + * from the previous profile we also need to write new delay tables + */ + err = tfa98xx_dsp_write_tables(tfa, fs_default_profile); + } + + return err; +} + +/* + * process all items in the profilelist + * NOTE an error return during processing will leave the device muted + * + */ +enum Tfa98xx_Error tfaContWriteProfile(struct tfa_device *tfa, int prof_idx, int vstep_idx) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + nxpTfaProfileList_t *prof = tfaContGetDevProfList(tfa->cnt, tfa->dev_idx, prof_idx); + nxpTfaProfileList_t *previous_prof = tfaContGetDevProfList(tfa->cnt, tfa->dev_idx, tfa_dev_get_swprof(tfa)); + char buffer[(MEMTRACK_MAX_WORDS * 4) + 4] = {0}; //every word requires 3 or 4 bytes, and 3 or 4 is the msg + unsigned int i, k=0, j=0, tries=0; + nxpTfaFileDsc_t *file; + int size = 0, ready, fs_previous_profile = 8; /* default fs is 48kHz*/ + + if ( !prof || !previous_prof ) { + pr_err("Error trying to get the (previous) swprofile \n"); + return Tfa98xx_Error_Bad_Parameter; + } + + if (tfa->verbose) { + tfa98xx_trace_printk("device:%s profile:%s vstep:%d\n", tfaContDeviceName(tfa->cnt, tfa->dev_idx), + tfaContProfileName(tfa->cnt, tfa->dev_idx,prof_idx),vstep_idx); + } + + /* We only make a power cycle when the profiles are not in the same group */ + if (prof->group == previous_prof->group && prof->group != 0) { + if (tfa->verbose) { + pr_debug("The new profile (%s) is in the same group as the current profile (%s) \n", + tfaContGetString(tfa->cnt, &prof->name), tfaContGetString(tfa->cnt, &previous_prof->name)); + } + } else { + /* mute */ + err = tfaRunMute(tfa); + if (err) return err; + + /* Get current sample rate before we start switching */ + fs_previous_profile = TFA_GET_BF(tfa, AUDFS); + + /* clear SBSL to make sure we stay in initCF state */ + if (tfa->tfa_family == 2) { + TFA_SET_BF_VOLATILE(tfa, SBSL, 0); + } + + /* When we switch profile we first power down the subsystem + * This should only be done when we are in operating mode + */ + if (((tfa->tfa_family == 2) && (TFA_GET_BF(tfa, MANSTATE) >= 6)) || (tfa->tfa_family != 2)) { + err = tfa98xx_powerdown(tfa, 1); + if (err) return err; + + /* Wait until we are in PLL powerdown */ + do { + err = tfa98xx_dsp_system_stable(tfa, &ready); + if (!ready) + break; + else + msleep_interruptible(10); /* wait 10ms to avoid busload */ + tries++; + } while (tries <= 100); + + if (tries > 100) { + pr_debug("Wait for PLL powerdown timed out!\n"); + return Tfa98xx_Error_StateTimedOut; + } + } else { + pr_debug("No need to go to powerdown now \n"); + } + } + + /* set all bitfield settings */ + /* First set all default settings */ + if (tfa->verbose) { + pr_debug("---------- default settings profile: %s (%d) ---------- \n", + tfaContGetString(tfa->cnt, &previous_prof->name), tfa_dev_get_swprof(tfa)); + } + + err = show_current_state(tfa); + + /* Loop profile length */ + for(i=0;ilength;i++) { + /* Search for the default section */ + if(i == 0) { + while(previous_prof->list[i].type != dscDefault && i < previous_prof->length) { + i++; + } + i++; + } + + /* Only if we found the default section try writing the items */ + if(i < previous_prof->length) { + if ( tfaContWriteItem(tfa, &previous_prof->list[i]) != Tfa98xx_Error_Ok ) + return Tfa98xx_Error_Bad_Parameter; + } + } + + if (tfa->verbose) + pr_debug("---------- new settings profile: %s (%d) ---------- \n", + tfaContGetString(tfa->cnt, &prof->name), prof_idx); + + /* set new settings */ + for(i=0;ilength;i++) { + /* Remember where we currently are with writing items*/ + j = i; + + /* We only want to write the values before the default section when we switch profile */ + /* process and write all non-file items */ + switch (prof->list[i].type) { + case dscFile: + case dscPatch: + case dscSetInputSelect: + case dscSetOutputSelect: + case dscSetProgramConfig: + case dscSetLagW: + case dscSetGains: + case dscSetvBatFactors: + case dscSetSensesCal: + case dscSetSensesDelay: + case dscSetMBDrc: + case dscSetFwkUseCase: + case dscSetVddpConfig: + case dscCmd: + case dscFilter: + case dscDefault: + /* When one of these files are found, we exit */ + i = prof->length; + break; + default: + err = tfaContWriteItem(tfa, &prof->list[i]); + if ( err != Tfa98xx_Error_Ok ) + return Tfa98xx_Error_Bad_Parameter; + break; + } + } + + if (prof->group != previous_prof->group || prof->group == 0) { + if (tfa->tfa_family == 2) + TFA_SET_BF_VOLATILE(tfa, MANSCONF, 1); + + /* Leave powerdown state */ + err = tfa_cf_powerup(tfa); + if (err) return err; + + err = show_current_state(tfa); + + if (tfa->tfa_family == 2) { + /* Reset SBSL to 0 (workaround of enbl_powerswitch=0) */ + TFA_SET_BF_VOLATILE(tfa, SBSL, 0); + /* Sending commands to DSP we need to make sure RST is 0 (otherwise we get no response)*/ + TFA_SET_BF(tfa, RST,0); + } + } + + /* Check if there are sample rate changes */ + err = get_sample_rate_info(tfa, prof, previous_prof, fs_previous_profile); + if (err) return err; + + + /* Write files from previous profile (default section) + * Should only be used for the patch&trap patch (file) + */ + if(tfa->ext_dsp != 0) { + if (tfa->tfa_family == 2) { + for(i=0;ilength;i++) { + /* Search for the default section */ + if(i == 0) { + while(previous_prof->list[i].type != dscDefault && i < previous_prof->length) { + i++; + } + i++; + } + + /* Only if we found the default section try writing the file */ + if(i < previous_prof->length) { + if(previous_prof->list[i].type == dscFile || previous_prof->list[i].type == dscPatch) { + /* Only write this once */ + if ( tfa->verbose && k==0) { + pr_debug("---------- files default profile: %s (%d) ---------- \n", + tfaContGetString(tfa->cnt, &previous_prof->name), prof_idx); + k++; + } + file = (nxpTfaFileDsc_t *)(previous_prof->list[i].offset+(uint8_t *)tfa->cnt); + err = tfaContWriteFile(tfa, file, vstep_idx, TFA_MAX_VSTEP_MSG_MARKER); + } + } + } + } + + if ( tfa->verbose) { + pr_debug("---------- files new profile: %s (%d) ---------- \n", + tfaContGetString(tfa->cnt, &prof->name), prof_idx); + } + } + + /* write everything until end or the default section starts + * Start where we currenly left */ + for(i=j;ilength;i++) { + /* We only want to write the values before the default section when we switch profile */ + + if(prof->list[i].type == dscDefault) { + break; + } + + switch (prof->list[i].type) { + case dscFile: + case dscPatch: + /* For tiberius stereo 1 device does not have a dsp! */ + if(tfa->ext_dsp != 0){ + file = (nxpTfaFileDsc_t *)(prof->list[i].offset+(uint8_t *)tfa->cnt); + err = tfaContWriteFile(tfa, file, vstep_idx, TFA_MAX_VSTEP_MSG_MARKER); + } + break; + case dscSetInputSelect: + case dscSetOutputSelect: + case dscSetProgramConfig: + case dscSetLagW: + case dscSetGains: + case dscSetvBatFactors: + case dscSetSensesCal: + case dscSetSensesDelay: + case dscSetMBDrc: + case dscSetFwkUseCase: + case dscSetVddpConfig: + /* For tiberius stereo 1 device does not have a dsp! */ + if(tfa->ext_dsp != 0) { + create_dsp_buffer_msg(tfa, (nxpTfaMsg_t *) + ( prof->list[i].offset+(char*)tfa->cnt), buffer, &size); + err = dsp_msg(tfa, size, buffer); + + if (tfa->verbose) { + pr_debug("command: %s=0x%02x%02x%02x \n", + tfaContGetCommandString(prof->list[i].type), + (unsigned char)buffer[0], (unsigned char)buffer[1], (unsigned char)buffer[2]); + } + } + break; + case dscCmd: + /* For tiberius stereo 1 device does not have a dsp! */ + if(tfa->ext_dsp != 0) { + size = *(uint16_t *)(prof->list[i].offset+(char*)tfa->cnt); + err = dsp_msg(tfa, size, prof->list[i].offset+2+(char*)tfa->cnt); + if (tfa->verbose) { + const char *cmd_id = prof->list[i].offset+2+(char*)tfa->cnt; + pr_debug("Writing cmd=0x%02x%02x%02x \n", (uint8_t)cmd_id[0], (uint8_t)cmd_id[1], (uint8_t)cmd_id[2]); + } + } + break; + default: + /* This allows us to write bitfield, registers or xmem after files */ + if (tfaContWriteItem(tfa, &prof->list[i]) != Tfa98xx_Error_Ok) { + return Tfa98xx_Error_Bad_Parameter; + } + break; + } + + if (err != Tfa98xx_Error_Ok) { + return err; + } + } + + if ((prof->group != previous_prof->group || prof->group == 0) && (tfa->tfa_family == 2)) { + if (TFA_GET_BF(tfa, REFCKSEL) == 0) { + /* set SBSL to go to operation mode */ + TFA_SET_BF_VOLATILE(tfa, SBSL, 1); + } + } + + return err; +} + +/* + * process only vstep in the profilelist + * + */ +enum Tfa98xx_Error tfaContWriteFilesVstep(struct tfa_device *tfa, int prof_idx, int vstep_idx) +{ + nxpTfaProfileList_t *prof = tfaContGetDevProfList(tfa->cnt, tfa->dev_idx, prof_idx); + unsigned int i; + nxpTfaFileDsc_t *file; + nxpTfaHeader_t *hdr; + nxpTfaHeaderType_t type; + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + + if ( !prof ) + return Tfa98xx_Error_Bad_Parameter; + + if (tfa->verbose) + tfa98xx_trace_printk("device:%s profile:%s vstep:%d\n", tfaContDeviceName(tfa->cnt, tfa->dev_idx), + tfaContProfileName(tfa->cnt, tfa->dev_idx,prof_idx),vstep_idx); + + /* write vstep file only! */ + for(i=0;ilength;i++) { + if ( prof->list[i].type == dscFile ) { + file = (nxpTfaFileDsc_t *)(prof->list[i].offset+(uint8_t *)tfa->cnt); + hdr = (nxpTfaHeader_t *)file->data; + type = (nxpTfaHeaderType_t) hdr->id; + + switch (type) { + case volstepHdr: + if ( tfaContWriteFile(tfa, file, vstep_idx, TFA_MAX_VSTEP_MSG_MARKER) ) + return Tfa98xx_Error_Bad_Parameter; + break; + default: + break; + } + } + } + + return err; +} + +char *tfaContGetString(nxpTfaContainer_t *cnt, nxpTfaDescPtr_t *dsc) +{ + if ( dsc->type != dscString) + return "Undefined string"; + + return dsc->offset+(char*)cnt; +} + +char *tfaContGetCommandString(uint32_t type) +{ + if(type == dscSetInputSelect) + return "SetInputSelector"; + else if(type == dscSetOutputSelect) + return "SetOutputSelector"; + else if(type == dscSetProgramConfig) + return "SetProgramConfig"; + else if(type == dscSetLagW) + return "SetLagW"; + else if(type == dscSetGains) + return "SetGains"; + else if(type == dscSetvBatFactors) + return "SetvBatFactors"; + else if(type == dscSetSensesCal) + return "SetSensesCal"; + else if(type == dscSetSensesDelay) + return "SetSensesDelay"; + else if(type == dscSetMBDrc) + return "SetMBDrc"; + else if(type == dscSetFwkUseCase) + return "SetFwkUseCase"; + else if(type == dscSetVddpConfig) + return "SetVddpConfig"; + else if(type == dscFilter) + return "filter"; + else + return "Undefined string"; +} + +/* + * Get the name of the device at a certain index in the container file + * return device name + */ +char *tfaContDeviceName(nxpTfaContainer_t *cnt, int dev_idx) +{ + nxpTfaDeviceList_t *dev; + + dev = tfaContDevice(cnt, dev_idx); + if (dev == NULL) + return "!ERROR!"; + + return tfaContGetString(cnt, &dev->name); +} + +/* + * Get the application name from the container file application field + * note that the input stringbuffer should be sizeof(application field)+1 + * + */ +int tfa_cnt_get_app_name(struct tfa_device *tfa, char *name) +{ + unsigned int i; + int len = 0; + + for(i=0; icnt->application); i++) { + if (isalnum(tfa->cnt->application[i])) /* copy char if valid */ + name[len++] = tfa->cnt->application[i]; + if (tfa->cnt->application[i]=='\0') + break; + } + name[len++] = '\0'; + + return len; +} + +/* + * Get profile index of the calibration profile. + * Returns: (profile index) if found, (-2) if no + * calibration profile is found or (-1) on error + */ +int tfaContGetCalProfile(struct tfa_device *tfa) +{ + int prof, cal_idx = -2; + + if ( (tfa->dev_idx < 0) || (tfa->dev_idx >= tfa->cnt->ndev) ) + return -1; + + /* search for the calibration profile in the list of profiles */ + for (prof = 0; prof < tfa->cnt->nprof; prof++) { + if(strstr(tfaContProfileName(tfa->cnt, tfa->dev_idx, prof), ".cal") != NULL) { + cal_idx = prof; + pr_debug("Using calibration profile: '%s'\n", tfaContProfileName(tfa->cnt, tfa->dev_idx, prof)); + break; + } + } + + return cal_idx; +} + +/** + * Is the profile a tap profile + */ +int tfaContIsTapProfile(struct tfa_device *tfa, int prof_idx) +{ + if ((tfa->dev_idx < 0) || (tfa->dev_idx >= tfa->cnt->ndev)) + return -1; + + /* Check if next profile is tap profile */ + if (strstr(tfaContProfileName(tfa->cnt, tfa->dev_idx, prof_idx), ".tap") != NULL) { + pr_debug("Using Tap profile: '%s'\n", tfaContProfileName(tfa->cnt, tfa->dev_idx, prof_idx)); + return 1; + } + + return 0; +} + +/* + * Get the name of the profile at certain index for a device in the container file + * return profile name + */ +char *tfaContProfileName(nxpTfaContainer_t *cnt, int dev_idx, int prof_idx) +{ + nxpTfaProfileList_t *prof = NULL; + + /* the Nth profiles for this device */ + prof = tfaContGetDevProfList(cnt, dev_idx, prof_idx); + + /* If the index is out of bound */ + if (prof == NULL) + return "NONE"; + + return tfaContGetString(cnt, &prof->name); +} + +/* + * return 1st profile list + */ +nxpTfaProfileList_t *tfaContGet1stProfList(nxpTfaContainer_t * cont) +{ + nxpTfaProfileList_t *prof; + uint8_t *b = (uint8_t *) cont; + + int maxdev = 0; + nxpTfaDeviceList_t *dev; + + // get nr of devlists + maxdev = cont->ndev; + // get last devlist + dev = tfaContGetDevList(cont, maxdev - 1); + if(dev == NULL) + return NULL; + // the 1st profile starts after the last device list + b = (uint8_t *) dev + sizeof(nxpTfaDeviceList_t) + dev->length * (sizeof(nxpTfaDescPtr_t)); + prof = (nxpTfaProfileList_t *) b; + return prof; +} + +/* + * return 1st livedata list + */ +nxpTfaLiveDataList_t *tfaContGet1stLiveDataList(nxpTfaContainer_t * cont) +{ + nxpTfaLiveDataList_t *ldata; + nxpTfaProfileList_t *prof; + nxpTfaDeviceList_t *dev; + uint8_t *b = (uint8_t *) cont; + int maxdev, maxprof; + + // get nr of devlists+1 + maxdev = cont->ndev; + // get nr of proflists + maxprof = cont->nprof; + + // get last devlist + dev = tfaContGetDevList(cont, maxdev - 1); + // the 1st livedata starts after the last device list + b = (uint8_t *) dev + sizeof(nxpTfaDeviceList_t) + + dev->length * (sizeof(nxpTfaDescPtr_t)); + + while(maxprof != 0) { + // get last proflist + prof = (nxpTfaProfileList_t *) b; + b += sizeof(nxpTfaProfileList_t) + + ((prof->length-1) * (sizeof(nxpTfaDescPtr_t))); + maxprof--; + } + + /* Else the marker falls off */ + b += 4; //bytes + + ldata = (nxpTfaLiveDataList_t *) b; + return ldata; +} + +/* + * return the device list pointer + */ +nxpTfaDeviceList_t *tfaContDevice(nxpTfaContainer_t *cnt, int dev_idx) +{ + return tfaContGetDevList(cnt, dev_idx); +} + +/* + * return the next profile: + * - assume that all profiles are adjacent + * - calculate the total length of the input + * - the input profile + its length is the next profile + */ +nxpTfaProfileList_t* tfaContNextProfile(nxpTfaProfileList_t* prof) { + uint8_t *this, *next; /* byte pointers for byte pointer arithmetic */ + nxpTfaProfileList_t* nextprof; + int listlength; /* total length of list in bytes */ + + if(prof == NULL) + return NULL; + + if (prof->ID != TFA_PROFID) + return NULL; /* invalid input */ + + this = (uint8_t *)prof; + /* nr of items in the list, length includes name dsc so - 1*/ + listlength = (prof->length - 1)*sizeof(nxpTfaDescPtr_t); + /* the sizeof(nxpTfaProfileList_t) includes the list[0] length */ + next = this + listlength + sizeof(nxpTfaProfileList_t);// - sizeof(nxpTfaDescPtr_t); + nextprof = (nxpTfaProfileList_t *)next; + + if (nextprof->ID != TFA_PROFID) + return NULL; + + return nextprof; +} + +/* + * return the next livedata + */ +nxpTfaLiveDataList_t* tfaContNextLiveData(nxpTfaLiveDataList_t* livedata) { + nxpTfaLiveDataList_t* nextlivedata = (nxpTfaLiveDataList_t *)( (char*)livedata + (livedata->length*4) + + sizeof(nxpTfaLiveDataList_t) -4); + + if (nextlivedata->ID == TFA_LIVEDATAID) + return nextlivedata; + + return NULL; +} + +/* + * check CRC for container + * CRC is calculated over the bytes following the CRC field + * + * return non zero value on error + */ +int tfaContCrcCheckContainer(nxpTfaContainer_t *cont) +{ + uint8_t *base; + size_t size; + uint32_t crc; + + base = (uint8_t *)&cont->CRC + 4; // ptr to bytes following the CRC field + size = (size_t)(cont->size - (base - (uint8_t *)cont)); // nr of bytes following the CRC field + crc = ~crc32_le(~0u, base, size); + + return crc != cont->CRC; +} + +static void get_all_features_from_cnt(struct tfa_device *tfa, int *hw_feature_register, int sw_feature_register[2]) +{ + nxpTfaFeatures_t *features; + int i; + + nxpTfaDeviceList_t *dev = tfaContDevice(tfa->cnt, tfa->dev_idx); + + /* Init values in case no keyword is defined in cnt file: */ + *hw_feature_register = -1; + sw_feature_register[0] = -1; + sw_feature_register[1] = -1; + + if(dev == NULL) + return; + + // process the device list + for(i=0;ilength;i++) { + if (dev->list[i].type == dscFeatures) { + features = (nxpTfaFeatures_t *)(dev->list[i].offset+(uint8_t *)tfa->cnt); + *hw_feature_register = features->value[0]; + sw_feature_register[0] = features->value[1]; + sw_feature_register[1] = features->value[2]; + break; + } + } +} + +/* wrapper function */ +void get_hw_features_from_cnt(struct tfa_device *tfa, int *hw_feature_register) +{ + int sw_feature_register[2]; + get_all_features_from_cnt(tfa, hw_feature_register, sw_feature_register); +} + +/* wrapper function */ +void get_sw_features_from_cnt(struct tfa_device *tfa, int sw_feature_register[2]) +{ + int hw_feature_register; + get_all_features_from_cnt(tfa, &hw_feature_register, sw_feature_register); +} + +enum Tfa98xx_Error tfa98xx_factory_trimmer(struct tfa_device *tfa) +{ + return (tfa->dev_ops.factory_trimmer)(tfa); +} + +enum Tfa98xx_Error tfa_set_filters(struct tfa_device *tfa, int prof_idx) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + nxpTfaProfileList_t *prof = tfaContGetDevProfList(tfa->cnt, tfa->dev_idx, prof_idx); + unsigned int i; + + if ( !prof ) + return Tfa98xx_Error_Bad_Parameter; + + /* If we are in powerdown there is no need to set filters */ + if (TFA_GET_BF(tfa, PWDN) == 1) + return Tfa98xx_Error_Ok; + + /* loop the profile to find filter settings */ + for(i=0;ilength;i++) { + /* We only want to write the values before the default section */ + if(prof->list[i].type == dscDefault) + break; + + /* write all filter settings */ + if ( prof->list[i].type == dscFilter) { + if (tfaContWriteItem(tfa, &prof->list[i]) != Tfa98xx_Error_Ok) + return err; + } + } + + return err; +} + +int tfa_tib_dsp_msgmulti(struct tfa_device *tfa, int length, const char *buffer) +{ + uint8_t *buf = (uint8_t *)buffer; + static uint8_t *blob = NULL, *blobptr; /* TODO: not multi-thread safe */ + static int total = 0; /* TODO: not multi-thread safe */ + int post_len = 0; + + /* checks for 24b_BE or 32_LE */ + int len_word_in_bytes = (tfa->convert_dsp32) ? 4 : 3; + /* TODO: get rid of these magic constants max size should depend on the tfa device type */ + int tfadsp_max_msg_size = (tfa->convert_dsp32) ? 5336 : 4000; + + /* No data found*/ + if(length == -1 && blob == NULL) { + return -1; + } + + if (length == -1) { + int i; + /* set last length field to zero */ + for (i = total; i < (total + len_word_in_bytes); i++) { + blob[i] = 0; + } + total += len_word_in_bytes; + memcpy(buf, blob, total); + + kfree(blob); + blob = NULL; /* Set to NULL pointer, otherwise no new malloc is done! */ + return total; + } + + if (blob == NULL) { + if (tfa->verbose) + pr_debug("%s, Creating the multi-message \n\n", __FUNCTION__); + + blob = kmalloc(tfadsp_max_msg_size, GFP_KERNEL); + /* add command ID for multi-msg = 0x008015 */ + if (tfa->convert_dsp32) { + blob[0] = 0x15; + blob[1] = 0x80; + blob[2] = 0x0; + blob[3] = 0x0; + } + else { + blob[0] = 0x0; + blob[1] = 0x80; + blob[2] = 0x15; + } + blobptr = blob; + blobptr += len_word_in_bytes; + total = len_word_in_bytes; + } + + if (tfa->verbose) { + pr_debug("%s, id:0x%02x%02x%02x, length:%d \n", __FUNCTION__, buf[0], buf[1], buf[2], length); + } + + /* check total message size after concatination */ + post_len = total+length+(2*len_word_in_bytes); + if (post_len > tfadsp_max_msg_size) { + //pr_debug("New multi-message too large! (%d >= %d (max.)), current length: %d\n", post_len, tfadsp_max_msg_size, total); + return Tfa98xx_Error_Buffer_too_small; + } + + /* add length field (length in words) to the multi message */ + if (tfa->convert_dsp32) { + *blobptr++ = (uint8_t)((length/len_word_in_bytes) & 0xff); /* lsb */ + *blobptr++ = (uint8_t)(((length/len_word_in_bytes) & 0xff00) >> 8); /* msb */ + *blobptr++ = 0x0; + *blobptr++ = 0x0; + } + else { + *blobptr++ = 0x0; + *blobptr++ = (uint8_t)(((length/len_word_in_bytes) & 0xff00) >> 8); /* msb */ + *blobptr++ = (uint8_t)((length/len_word_in_bytes) & 0xff); /* lsb */ + } + memcpy(blobptr, buf, length); + blobptr += length; + total += (length + len_word_in_bytes); + + /* SetRe25 message is always the last message of the multi-msg */ + if (tfa->convert_dsp32) { + if (buf[1] == 0x81 && buf[0] == SB_PARAM_SET_RE25C) { + return 1; /* 1 means last message is done! */ + } + } else { + if (buf[1] == 0x81 && buf[2] == SB_PARAM_SET_RE25C) { + return 1; /* 1 means last message is done! */ + } + } + + return 0; +} diff --git a/techpack/audio/asoc/codecs/tfa9874/tfa_container.h b/techpack/audio/asoc/codecs/tfa9874/tfa_container.h new file mode 100644 index 000000000000..c35cba467ec7 --- /dev/null +++ b/techpack/audio/asoc/codecs/tfa9874/tfa_container.h @@ -0,0 +1,364 @@ +/* + * Copyright 2013-2017 NXP Semiconductors + * + * 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. + */ + +/* + * tfaContainer.h + * + * Created on: Sep 11, 2013 + * Author: wim + */ + +#ifndef TFACONTAINER_H_ +#define TFACONTAINER_H_ + +/* static limits */ +#define TFACONT_MAXDEVS (4) /* maximum nr of devices */ +#define TFACONT_MAXPROFS (16) /* maximum nr of profiles */ + +#include "tfa98xx_parameters.h" + +/** +* Pass the container buffer, initialize and allocate internal memory. +* +* @param cnt pointer to the start of the buffer holding the container file +* @param length of the data in bytes +* @return +* - tfa_error_ok if normal +* - tfa_error_container invalid container data +* - tfa_error_bad_param invalid parameter +* +*/ +enum tfa_error tfa_load_cnt(void *cnt, int length); + +/** + * Return the descriptor string + * @param cnt pointer to the container struct + * @param dsc pointer to nxpTfa descriptor + * @return descriptor string + */ +char *tfaContGetString(nxpTfaContainer_t *cnt, nxpTfaDescPtr_t *dsc); + +/** + * Gets the string for the given command type number + * @param type number representing a command + * @return string of a command + */ +char *tfaContGetCommandString(uint32_t type); + +/** + * get the device type from the patch in this devicelist + * - find the patch file for this devidx + * - return the devid from the patch or 0 if not found + * @param cnt pointer to container file + * @param dev_idx device index + * @return descriptor string + */ +int tfa_cnt_get_devid(nxpTfaContainer_t *cnt, int dev_idx); + +/** + * Get the slave for the device if it exists. + * @param tfa the device struct pointer + * @param slave_addr the index of the device + * @return Tfa98xx_Error + */ +enum Tfa98xx_Error tfaContGetSlave(struct tfa_device *tfa, uint8_t *slave_addr); + +void tfaContSetSlave(uint8_t slave_addr); + +/** + * Get the index for a skave address. + * @param tfa the device struct pointer + * @return the device index + */ +int tfa_cont_get_idx(struct tfa_device *tfa); + +/** + * Write reg and bitfield items in the devicelist to the target. + * @param tfa the device struct pointer + * @return Tfa98xx_Error + */ +enum Tfa98xx_Error tfaContWriteRegsDev(struct tfa_device *tfa); + +/** + * Write reg and bitfield items in the profilelist to the target. + * @param tfa the device struct pointer + * @param prof_idx the profile index + * @return Tfa98xx_Error + */ +enum Tfa98xx_Error tfaContWriteRegsProf(struct tfa_device *tfa, int prof_idx); + +/** + * Write a patchfile in the devicelist to the target. + * @param tfa the device struct pointer + * @return Tfa98xx_Error + */ +enum Tfa98xx_Error tfaContWritePatch(struct tfa_device *tfa); + +/** + * Write all param files in the devicelist to the target. + * @param tfa the device struct pointer + * @return Tfa98xx_Error + */ +enum Tfa98xx_Error tfaContWriteFiles(struct tfa_device *tfa); + +/** + * Get sample rate from passed profile index + * @param tfa the device struct pointer + * @param prof_idx the index of the profile + * @return sample rate value + */ +unsigned int tfa98xx_get_profile_sr(struct tfa_device *tfa, unsigned int prof_idx); + +/** + * Get the device name string + * @param cnt the pointer to the container struct + * @param dev_idx the index of the device + * @return device name string or error string if not found + */ +char *tfaContDeviceName(nxpTfaContainer_t *cnt, int dev_idx); + +/** + * Get the application name from the container file application field + * @param tfa the device struct pointer + * @param name the input stringbuffer with size: sizeof(application field)+1 + * @return actual string length + */ +int tfa_cnt_get_app_name(struct tfa_device *tfa, char *name); + +/** + * Get profile index of the calibration profile + * @param tfa the device struct pointer + * @return profile index, -2 if no calibration profile is found or -1 on error + */ +int tfaContGetCalProfile(struct tfa_device *tfa); + +/** + * Is the profile a tap profile ? + * @param tfa the device struct pointer + * @param prof_idx the index of the profile + * @return 1 if the profile is a tap profile or 0 if not + */ +int tfaContIsTapProfile(struct tfa_device *tfa, int prof_idx); + +/** + * Get the name of the profile at certain index for a device in the container file + * @param cnt the pointer to the container struct + * @param dev_idx the index of the device + * @param prof_idx the index of the profile + * @return profile name string or error string if not found + */ +char *tfaContProfileName(nxpTfaContainer_t *cnt, int dev_idx, int prof_idx); + +/** + * Process all items in the profilelist + * NOTE an error return during processing will leave the device muted + * @param tfa the device struct pointer + * @param prof_idx index of the profile + * @param vstep_idx index of the vstep + * @return Tfa98xx_Error + */ +enum Tfa98xx_Error tfaContWriteProfile(struct tfa_device *tfa, int prof_idx, int vstep_idx); + +/** + * Specify the speaker configurations (cmd id) (Left, right, both, none) + * @param dev_idx index of the device + * @param configuration name string of the configuration + */ +void tfa98xx_set_spkr_select(int dev_idx, char *configuration); + +enum Tfa98xx_Error tfa_cont_write_filterbank(struct tfa_device *tfa, nxpTfaFilter_t *filter); + +/** + * Write all param files in the profilelist to the target + * this is used during startup when maybe ACS is set + * @param tfa the device struct pointer + * @param prof_idx the index of the profile + * @param vstep_idx the index of the vstep + * @return Tfa98xx_Error + */ +enum Tfa98xx_Error tfaContWriteFilesProf(struct tfa_device *tfa, int prof_idx, int vstep_idx); +enum Tfa98xx_Error tfaContWriteFilesVstep(struct tfa_device *tfa, int prof_idx, int vstep_idx); +enum Tfa98xx_Error tfaContWriteDrcFile(struct tfa_device *tfa, int size, uint8_t data[]); + +/** + * Get the device list dsc from the tfaContainer + * @param cont pointer to the tfaContainer + * @param dev_idx the index of the device + * @return device list pointer + */ +nxpTfaDeviceList_t *tfaContGetDevList(nxpTfaContainer_t *cont, int dev_idx); + +/** + * Get the Nth profile for the Nth device + * @param cont pointer to the tfaContainer + * @param dev_idx the index of the device + * @param prof_idx the index of the profile + * @return profile list pointer + */ +nxpTfaProfileList_t *tfaContGetDevProfList(nxpTfaContainer_t *cont, int dev_idx, int prof_idx); + +/** + * Get the number of profiles for device from contaienr + * @param cont pointer to the tfaContainer + * @param dev_idx the index of the device + * @return device list pointer + */ +int tfa_cnt_get_dev_nprof(struct tfa_device *tfa); + + +/** + * Get the Nth livedata for the Nth device + * @param cont pointer to the tfaContainer + * @param dev_idx the index of the device + * @param livedata_idx the index of the livedata + * @return livedata list pointer + */ +nxpTfaLiveDataList_t *tfaContGetDevLiveDataList(nxpTfaContainer_t *cont, int dev_idx, int livedata_idx); + +/** + * Check CRC for container + * @param cont pointer to the tfaContainer + * @return error value 0 on error + */ +int tfaContCrcCheckContainer(nxpTfaContainer_t *cont); + +/** + * Get the device list pointer + * @param cnt pointer to the container struct + * @param dev_idx the index of the device + * @return pointer to device list + */ +nxpTfaDeviceList_t *tfaContDevice(nxpTfaContainer_t *cnt, int dev_idx); + +/** + * Return the pointer to the first profile in a list from the tfaContainer + * @param cont pointer to the tfaContainer + * @return pointer to first profile in profile list + */ +nxpTfaProfileList_t *tfaContGet1stProfList(nxpTfaContainer_t *cont); + +/** + * Return the pointer to the next profile in a list + * @param prof is the pointer to the profile list + * @return profile list pointer + */ +nxpTfaProfileList_t* tfaContNextProfile(nxpTfaProfileList_t *prof); + +/** + * Return the pointer to the first livedata in a list from the tfaContainer + * @param cont pointer to the tfaContainer + * @return pointer to first livedata in profile list + */ +nxpTfaLiveDataList_t *tfaContGet1stLiveDataList(nxpTfaContainer_t *cont); + +/** + * Return the pointer to the next livedata in a list + * @param livedata_idx is the pointer to the livedata list + * @return livedata list pointer + */ +nxpTfaLiveDataList_t* tfaContNextLiveData(nxpTfaLiveDataList_t *livedata_idx); + +/** + * Write a bit field + * @param tfa the device struct pointer + * @param bf bitfield to write + * @return Tfa98xx_Error + */ +enum Tfa98xx_Error tfaRunWriteBitfield(struct tfa_device *tfa, nxpTfaBitfield_t bf); + +/** + * Write a parameter file to the device + * @param tfa the device struct pointer + * @param file filedescriptor pointer + * @param vstep_idx index to vstep + * @param vstep_msg_idx index to vstep message + * @return Tfa98xx_Error + */ +enum Tfa98xx_Error tfaContWriteFile(struct tfa_device *tfa, nxpTfaFileDsc_t *file, int vstep_idx, int vstep_msg_idx); + +/** + * Get the max volume step associated with Nth profile for the Nth device + * @param tfa the device struct pointer + * @param prof_idx profile index + * @return the number of vsteps + */ +int tfacont_get_max_vstep(struct tfa_device *tfa, int prof_idx); + +/** + * Get the file contents associated with the device or profile + * Search within the device tree, if not found, search within the profile + * tree. There can only be one type of file within profile or device. + * @param tfa the device struct pointer + * @param prof_idx I2C profile index in the device + * @param type file type + * @return 0 NULL if file type is not found + * @return 1 file contents + */ +nxpTfaFileDsc_t *tfacont_getfiledata(struct tfa_device *tfa, int prof_idx, enum nxpTfaHeaderType type); + +/** + * Dump the contents of the file header + * @param hdr pointer to file header data + */ +void tfaContShowHeader(nxpTfaHeader_t *hdr); + +/** + * Read a bit field + * @param tfa the device struct pointer + * @param bf bitfield to read out + * @return Tfa98xx_Error + */ +enum Tfa98xx_Error tfaRunReadBitfield(struct tfa_device *tfa, nxpTfaBitfield_t *bf); + +/** + * Get hw feature bits from container file + * @param tfa the device struct pointer + * @param hw_feature_register pointer to where hw features are stored + */ +void get_hw_features_from_cnt(struct tfa_device *tfa, int *hw_feature_register); + +/** + * Get sw feature bits from container file + * @param tfa the device struct pointer + * @param sw_feature_register pointer to where sw features are stored + */ +void get_sw_features_from_cnt(struct tfa_device *tfa, int sw_feature_register[2]); + +/** + * Factory trimming for the Boost converter + * check if there is a correction needed + * @param tfa the device struct pointer + */ +enum Tfa98xx_Error tfa98xx_factory_trimmer(struct tfa_device *tfa); + +/** + * Search for filters settings and if found then write them to the device + * @param tfa the device struct pointer + * @param prof_idx profile to look in + * @return Tfa98xx_Error + */ +enum Tfa98xx_Error tfa_set_filters(struct tfa_device *tfa, int prof_idx); + +/** + * Get the firmware version from the patch in the container file + * @param tfa the device struct pointer + * @return firmware version + */ +int tfa_cnt_get_patch_version(struct tfa_device *tfa); + +int tfa_tib_dsp_msgmulti(struct tfa_device *tfa, int length, const char *buffer); + +#endif /* TFACONTAINER_H_ */ diff --git a/techpack/audio/asoc/codecs/tfa9874/tfa_debug.c b/techpack/audio/asoc/codecs/tfa9874/tfa_debug.c new file mode 100644 index 000000000000..d6227262e77f --- /dev/null +++ b/techpack/audio/asoc/codecs/tfa9874/tfa_debug.c @@ -0,0 +1,416 @@ +/* + * Copyright 2014-2017 NXP Semiconductors + * + * 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 "dbgprint.h" +#include "tfa_service.h" +#include "tfa98xx_tfafieldnames.h" + +/* support for error code translation into text */ +static char latest_errorstr[64]; + +const char* tfa98xx_get_error_string(enum Tfa98xx_Error error) +{ + const char* pErrStr; + + switch (error) + { + case Tfa98xx_Error_Ok: + pErrStr = "Ok"; + break; + case Tfa98xx_Error_DSP_not_running: + pErrStr = "DSP_not_running"; + break; + case Tfa98xx_Error_Bad_Parameter: + pErrStr = "Bad_Parameter"; + break; + case Tfa98xx_Error_NotOpen: + pErrStr = "NotOpen"; + break; + case Tfa98xx_Error_InUse: + pErrStr = "InUse"; + break; + case Tfa98xx_Error_RpcBusy: + pErrStr = "RpcBusy"; + break; + case Tfa98xx_Error_RpcModId: + pErrStr = "RpcModId"; + break; + case Tfa98xx_Error_RpcParamId: + pErrStr = "RpcParamId"; + break; + case Tfa98xx_Error_RpcInvalidCC: + pErrStr = "RpcInvalidCC"; + break; + case Tfa98xx_Error_RpcInvalidSeq: + pErrStr = "RpcInvalidSeq"; + break; + case Tfa98xx_Error_RpcInvalidParam: + pErrStr = "RpcInvalidParam"; + break; + case Tfa98xx_Error_RpcBufferOverflow: + pErrStr = "RpcBufferOverflow"; + break; + case Tfa98xx_Error_RpcCalibBusy: + pErrStr = "RpcCalibBusy"; + break; + case Tfa98xx_Error_RpcCalibFailed: + pErrStr = "RpcCalibFailed"; + break; + case Tfa98xx_Error_Not_Supported: + pErrStr = "Not_Supported"; + break; + case Tfa98xx_Error_I2C_Fatal: + pErrStr = "I2C_Fatal"; + break; + case Tfa98xx_Error_I2C_NonFatal: + pErrStr = "I2C_NonFatal"; + break; + case Tfa98xx_Error_StateTimedOut: + pErrStr = "WaitForState_TimedOut"; + break; + default: + sprintf(latest_errorstr, "Unspecified error (%d)", (int)error); + pErrStr = latest_errorstr; + } + return pErrStr; +} +/*****************************************************************************/ +/* bitfield lookups */ +/* + * generic table lookup functions + */ +/** + * lookup bf in table + * return 'unkown' if not found + */ +static char *tfa_bf2name(tfaBfName_t *table, uint16_t bf) { + int n=0; + + do { + if ((table[n].bfEnum & 0xfff0 ) == (bf & 0xfff0 )) { + return table[n].bfName; + } + } + while( table[n++].bfEnum != 0xffff); + + return table[n-1].bfName; /* last name says unkown */ +} +/** + * lookup name in table + * return 0xffff if not found + */ +static uint16_t tfa_name2bf(tfaBfName_t *table,const char *name) { + int n = 0; + + do { + if (strcasecmp(name, table[n].bfName)==0) + return table[n].bfEnum; + } while (table[n++].bfEnum != 0xffff); + + return 0xffff; +} + +/* + * tfa2 bitfield name table + */ +TFA2_NAMETABLE +TFA2_BITNAMETABLE + +/* + * tfa1 bitfield name tables + */ +TFA1_NAMETABLE +TFA9896_NAMETABLE +TFA9872_NAMETABLE +TFA9874_NAMETABLE +TFA9890_NAMETABLE +TFA9891_NAMETABLE +TFA9887_NAMETABLE +TFA1_BITNAMETABLE +TFA9912_NAMETABLE +TFA9894_NAMETABLE +TFA9896_BITNAMETABLE +TFA9872_BITNAMETABLE +TFA9874_BITNAMETABLE +TFA9912_BITNAMETABLE +TFA9890_BITNAMETABLE +TFA9891_BITNAMETABLE +TFA9887_BITNAMETABLE +TFA9894_BITNAMETABLE + +char *tfaContBitName(uint16_t num, unsigned short rev) +{ + char *name; + /* end of list for the unknown string */ + int tableLength = sizeof(Tfa1DatasheetNames)/sizeof(tfaBfName_t); + const char *unknown=Tfa1DatasheetNames[tableLength-1].bfName; + + switch (rev & 0xff) { + case 0x88: + name = tfa_bf2name(Tfa2BitNames, num); + break; + case 0x97: + name = tfa_bf2name(Tfa1BitNames, num); + break; + case 0x96: + name = tfa_bf2name(Tfa9896BitNames, num); + break; + case 0x72: + name = tfa_bf2name(Tfa9872BitNames, num); + break; + case 0x74: + name = tfa_bf2name(Tfa9874BitNames, num); + break; + case 0x92: + name = tfa_bf2name(Tfa9891BitNames, num); + break; + case 0x91: + case 0x80: + case 0x81: + name = tfa_bf2name(Tfa9890BitNames, num); /* my tabel 1st */ + if (strcmp(unknown, name)==0) + name = tfa_bf2name(Tfa1BitNames, num); /* try generic table */ + break; + case 0x12: + name = tfa_bf2name(Tfa9887BitNames, num); /* my tabel 1st */ + if (strcmp(unknown, name)==0) + name = tfa_bf2name(Tfa1BitNames, num); /* try generic table */ + break; + case 0x13: + name = tfa_bf2name(Tfa9912BitNames, num); + break; + case 0x94: + name = tfa_bf2name(Tfa9894BitNames, num); + break; + default: + PRINT_ERROR("unknown REVID:0x%0x\n", rev); + tableLength = sizeof(Tfa1BitNames)/sizeof(tfaBfName_t); /* end of list */ + name = (char *)unknown; + break; + } + return name; +} + +char *tfaContDsName(uint16_t num, unsigned short rev) +{ + char *name; + /* end of list for the unknown string */ + int tableLength = sizeof(Tfa1DatasheetNames)/sizeof(tfaBfName_t); + const char *unknown=Tfa1DatasheetNames[tableLength-1].bfName; + + switch (rev & 0xff) { + case 0x88: + name = tfa_bf2name(Tfa2DatasheetNames, num); + break; + case 0x97: + name = tfa_bf2name(Tfa1DatasheetNames, num); + break; + case 0x96: + name = tfa_bf2name(Tfa9896DatasheetNames, num); + break; + case 0x72: + name = tfa_bf2name(Tfa9872DatasheetNames, num); + break; + case 0x74: + name = tfa_bf2name(Tfa9874DatasheetNames, num); + break; + case 0x92: + name = tfa_bf2name(Tfa9891DatasheetNames, num); + break; + case 0x91: + case 0x80: + case 0x81: + name = tfa_bf2name(Tfa9890DatasheetNames, num); /* my tabel 1st */ + if (strcmp(unknown, name)==0) + name = tfa_bf2name(Tfa1DatasheetNames, num); /* try generic table */ + break; + case 0x12: + name = tfa_bf2name(Tfa9887DatasheetNames, num); /* my tabel 1st */ + if (strcmp(unknown, name)==0) + name = tfa_bf2name(Tfa1DatasheetNames, num); /* try generic table */ + break; + case 0x13: + name = tfa_bf2name(Tfa9912DatasheetNames, num); + break; + case 0x94: + name = tfa_bf2name(Tfa9894DatasheetNames, num); + break; + default: + PRINT_ERROR("unknown REVID:0x%0x\n", rev); + tableLength = sizeof(Tfa1DatasheetNames)/sizeof(tfaBfName_t); /* end of list */ + name = (char *)unknown; + break; + } + return name; +} + +char *tfaContBfName(uint16_t num, unsigned short rev) +{ + char *name; + /* end of list for the unknown string */ + int tableLength = sizeof(Tfa1DatasheetNames)/sizeof(tfaBfName_t); + const char *unknown=Tfa1DatasheetNames[tableLength-1].bfName; + + /* if datasheet name does not exist look for bitfieldname */ + name = tfaContDsName(num, rev); + if (strcmp(unknown, name)==0) + name = tfaContBitName(num, rev); + + return name; +} + +uint16_t tfaContBfEnum(const char *name, unsigned short rev) +{ + uint16_t bfnum; + + switch (rev & 0xff) { + case 0x88: + bfnum = tfa_name2bf(Tfa2DatasheetNames, name); + if (bfnum==0xffff) + bfnum = tfa_name2bf(Tfa2BitNames, name);/* try long bitname table */ + break; + case 0x97: + bfnum = tfa_name2bf(Tfa1DatasheetNames, name); + if (bfnum==0xffff) + bfnum = tfa_name2bf(Tfa1BitNames, name);/* try generic table */ + break; + case 0x96: + bfnum = tfa_name2bf(Tfa9896DatasheetNames, name); + if (bfnum==0xffff) + bfnum = tfa_name2bf(Tfa9896BitNames, name);/* try generic table */ + break; + case 0x72: + bfnum = tfa_name2bf(Tfa9872DatasheetNames, name); + if (bfnum==0xffff) + bfnum = tfa_name2bf(Tfa9872BitNames, name);/* try long bitname table */ + break; + case 0x74: + bfnum = tfa_name2bf(Tfa9874DatasheetNames, name); + if (bfnum==0xffff) + bfnum = tfa_name2bf(Tfa9874BitNames, name);/* try long bitname table */ + break; + case 0x92: + bfnum = tfa_name2bf(Tfa9891DatasheetNames, name); + if (bfnum==0xffff) + bfnum = tfa_name2bf(Tfa9891BitNames, name);/* try long bitname table */ + break; + case 0x91: + case 0x80: + case 0x81: + bfnum = tfa_name2bf(Tfa9890DatasheetNames, name); /* my tabel 1st */ + if (bfnum==0xffff) + bfnum = tfa_name2bf(Tfa1DatasheetNames, name);/* try generic table */ + if (bfnum==0xffff) + bfnum = tfa_name2bf(Tfa1BitNames, name); /* try 2nd generic table */ + break; + case 0x12: + bfnum = tfa_name2bf(Tfa9887DatasheetNames, name); /* my tabel 1st */ + if (bfnum==0xffff) + bfnum = tfa_name2bf(Tfa1DatasheetNames, name);/* try generic table */ + if (bfnum==0xffff) + bfnum = tfa_name2bf(Tfa1BitNames, name);/* try 2nd generic table */ + break; + case 0x13: + bfnum = tfa_name2bf(Tfa9912DatasheetNames, name); + if (bfnum==0xffff) + bfnum = tfa_name2bf(Tfa9912BitNames, name);/* try long bitname table */ + break; + case 0x94: + bfnum = tfa_name2bf(Tfa9894DatasheetNames, name); + if (bfnum==0xffff) + bfnum = tfa_name2bf(Tfa9894BitNames, name);/* try long bitname table */ + break; + + default: + PRINT_ERROR("unknown REVID:0x%0x\n", rev); + bfnum=0xffff; + break; + } + + return bfnum; +} + +/* + * check all lists for a hit + * this is for the parser to know if it's an existing bitname + */ +uint16_t tfaContBfEnumAny(const char *name) +{ + uint16_t bfnum; + + /* datasheet names first */ + bfnum = tfa_name2bf(Tfa2DatasheetNames, name); + if (bfnum!=0xffff) + return bfnum; + bfnum = tfa_name2bf(Tfa1DatasheetNames, name); + if (bfnum!=0xffff) + return bfnum; + bfnum = tfa_name2bf(Tfa9891DatasheetNames, name); + if (bfnum!=0xffff) + return bfnum; + bfnum = tfa_name2bf(Tfa9890DatasheetNames, name); + if (bfnum!=0xffff) + return bfnum; + bfnum = tfa_name2bf(Tfa9887DatasheetNames, name); + if (bfnum!=0xffff) + return bfnum; + bfnum = tfa_name2bf(Tfa9872DatasheetNames, name); + if (bfnum!=0xffff) + return bfnum; + bfnum = tfa_name2bf(Tfa9874DatasheetNames, name); + if (bfnum!=0xffff) + return bfnum; + bfnum = tfa_name2bf(Tfa9896DatasheetNames, name); + if (bfnum!=0xffff) + return bfnum; + bfnum = tfa_name2bf(Tfa9912DatasheetNames, name); + if (bfnum!=0xffff) + return bfnum; + bfnum = tfa_name2bf(Tfa9894DatasheetNames, name); + if (bfnum!=0xffff) + return bfnum; + /* and then bitfield names */ + bfnum = tfa_name2bf(Tfa2BitNames, name); + if (bfnum!=0xffff) + return bfnum; + bfnum = tfa_name2bf(Tfa1BitNames, name); + if (bfnum!=0xffff) + return bfnum; + bfnum = tfa_name2bf(Tfa9891BitNames, name); + if (bfnum!=0xffff) + return bfnum; + bfnum = tfa_name2bf(Tfa9890BitNames, name); + if (bfnum!=0xffff) + return bfnum; + bfnum = tfa_name2bf(Tfa9887BitNames, name); + if (bfnum!=0xffff) + return bfnum; + bfnum = tfa_name2bf(Tfa9872BitNames, name); + if (bfnum!=0xffff) + return bfnum; + bfnum = tfa_name2bf(Tfa9874BitNames, name); + if (bfnum!=0xffff) + return bfnum; + bfnum = tfa_name2bf(Tfa9896BitNames, name); + if (bfnum!=0xffff) + return bfnum; + bfnum = tfa_name2bf(Tfa9912BitNames, name); + if (bfnum!=0xffff) + return bfnum; + bfnum = tfa_name2bf(Tfa9894BitNames, name); + + return bfnum; +} diff --git a/techpack/audio/asoc/codecs/tfa9874/tfa_device.h b/techpack/audio/asoc/codecs/tfa9874/tfa_device.h new file mode 100644 index 000000000000..732f4cc1a533 --- /dev/null +++ b/techpack/audio/asoc/codecs/tfa9874/tfa_device.h @@ -0,0 +1,296 @@ +/* + * Copyright 2014-2017 NXP Semiconductors + * + * 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. + */ + + +/**\file + * + * The tfa_device interface controls a single I2C device instance by + * referencing to the device specific context provided by means of the + * tfa_device structure pointer. + * Multiple instances of tfa_device structures will be created and maintained + * by the caller. + * + * The API is functionally grouped as: + * - tfa_dev basic codec interface to probe, start/stop and control the device state + * - access to internal MTP storage + * - abstraction for interrupt bits and handling + * - container reading support + */ +#ifndef __TFA_DEVICE_H__ +#define __TFA_DEVICE_H__ + +#include "config.h" + +struct tfa_device; + +/* + * hw/sw feature bit settings in MTP + */ +enum featureSupport { + supportNotSet, /**< default means not set yet */ + supportNo, /**< no support */ + supportYes /**< supported */ +}; +/* + * supported Digital Audio Interfaces bitmap + */ +enum Tfa98xx_DAI { + Tfa98xx_DAI_I2S = 0x01, /**< I2S only */ + Tfa98xx_DAI_TDM = 0x02, /**< TDM, I2S */ + Tfa98xx_DAI_PDM = 0x04, /**< PDM */ + }; + +/* + * device ops function structure + */ +struct tfa_device_ops { + enum Tfa98xx_Error(*dsp_msg)(struct tfa_device *tfa, int length, const char *buf); + enum Tfa98xx_Error(*dsp_msg_read)(struct tfa_device *tfa, int length, unsigned char *bytes); + enum Tfa98xx_Error(*reg_read)(struct tfa_device *tfa, unsigned char subaddress, unsigned short *value); + enum Tfa98xx_Error(*reg_write)(struct tfa_device *tfa, unsigned char subaddress, unsigned short value); + enum Tfa98xx_Error(*mem_read)(struct tfa_device *tfa, unsigned int start_offset, int num_words, int *pValues); + enum Tfa98xx_Error(*mem_write)(struct tfa_device *tfa, unsigned short address, int value, int memtype); + + enum Tfa98xx_Error (*tfa_init)(struct tfa_device *tfa); /**< init typically for loading optimal settings */ + enum Tfa98xx_Error (*dsp_reset)(struct tfa_device *tfa, int state); /**< reset the coolflux dsp */ + enum Tfa98xx_Error (*dsp_system_stable)(struct tfa_device *tfa, int *ready); /**< ready when clocks are stable to allow DSP subsystem access */ + enum Tfa98xx_Error (*dsp_write_tables)(struct tfa_device *tfa, int sample_rate); /**< write the device/type specific delaytables */ + enum Tfa98xx_Error (*auto_copy_mtp_to_iic)(struct tfa_device *tfa); /**< Set auto_copy_mtp_to_iic */ + enum Tfa98xx_Error (*factory_trimmer)(struct tfa_device *tfa); /**< Factory trimming for the Boost converter */ + int (*set_swprof)(struct tfa_device *tfa, unsigned short new_value); /**< Set the sw profile in the struct and the hw register */ + int (*get_swprof)(struct tfa_device *tfa); /**< Get the sw profile from the hw register */ + int(*set_swvstep)(struct tfa_device *tfa, unsigned short new_value); /**< Set the sw vstep in the struct and the hw register */ + int(*get_swvstep)(struct tfa_device *tfa); /**< Get the sw vstep from the hw register */ + int(*get_mtpb)(struct tfa_device *tfa); /**< get status of MTB busy bit*/ + enum Tfa98xx_Error (*set_mute)(struct tfa_device *tfa, int mute); /**< set mute */ + enum Tfa98xx_Error (*faim_protect)(struct tfa_device *tfa, int state); /**< Protect FAIM from being corrupted */ + enum Tfa98xx_Error(*set_osc_powerdown)(struct tfa_device *tfa, int state); /**< Allow to change internal osc. gating settings */ +}; + +/** + * Device states and modifier flags to allow a device/type independent fine + * grained control of the internal state.\n + * Values below 0x10 are referred to as base states which can be or-ed with + * state modifiers, from 0x10 and higher. + * + */ +enum tfa_state { + TFA_STATE_UNKNOWN, /**< unknown or invalid */ + TFA_STATE_POWERDOWN, /**< PLL in powerdown, Algo is up/warm */ + TFA_STATE_INIT_HW, /**< load I2C/PLL hardware setting (~wait2srcsettings) */ + TFA_STATE_INIT_CF, /**< coolflux HW access possible (~initcf) */ + TFA_STATE_INIT_FW, /**< DSP framework active (~patch loaded) */ + TFA_STATE_OPERATING, /**< Amp and Algo running */ + TFA_STATE_FAULT, /**< An alarm or error occurred */ + TFA_STATE_RESET, /**< I2C reset and ACS set */ + /* --sticky state modifiers-- */ + TFA_STATE_MUTE=0x10, /**< Algo & Amp mute */ + TFA_STATE_UNMUTE=0x20, /**< Algo & Amp unmute */ + TFA_STATE_CLOCK_ALWAYS=0x40, /**< PLL connect to internal oscillator */ + TFA_STATE_CLOCK_AUDIO=0x80, /**< PLL connect to audio clock (BCK/FS) */ + TFA_STATE_LOW_POWER=0x100, /**< lowest possible power state */ +}; + +/** + * This is the main tfa device context structure, it will carry all information + * that is needed to handle a single I2C device instance. + * All functions dealing with the device will need access to the fields herein. + */ +struct tfa_device { + int dev_idx; /**< device container index */ + int in_use; + int buffer_size; /**< lowest level max buffer size */ + int has_msg; /**< support direct dsp messaging */ + unsigned char slave_address; /**< I2C slave address (not shifted) */ + unsigned short rev; /**< full revid of this device */ + unsigned char tfa_family; /**< tfa1/tfa2 */ + enum featureSupport supportDrc; + enum featureSupport supportFramework; + enum featureSupport support_saam; + int sw_feature_bits[2]; /**< cached copy of sw feature bits */ + int hw_feature_bits; /**< cached copy of hw feature bits */ + int profile; /**< active profile */ + int vstep; /**< active vstep */ + unsigned char spkr_count; + unsigned char spkr_select; + unsigned char support_tcoef;/**< legacy tfa9887, will be removed */ + enum Tfa98xx_DAI daimap; /**< supported audio interface types */ + int mohm[3]; /**< speaker calibration values in milli ohms -1 is error */ + struct tfa_device_ops dev_ops; + uint16_t interrupt_enable[3]; + uint16_t interrupt_status[3]; + int ext_dsp; /**< respond to external DSP: -1:none, 0:no_dsp, 1:cold, 2:warm */ + int bus; /* TODO fix ext_dsp and bus handling */ + int tfadsp_event; /**< enum tfadsp_event_en is for external registry */ + int verbose; /**< verbosity level for debug print output */ + enum tfa_state state; /**< last known state or-ed with optional state_modifier */ + struct nxpTfaContainer *cnt;/**< the loaded container file */ + struct nxpTfaVolumeStepRegisterInfo *p_regInfo; /**< remember vstep for partial updates */ + int partial_enable; /**< enable partial updates */ + void *data; /**< typically pointing to Linux driver structure owning this device */ + int convert_dsp32; /**< convert 24 bit DSP messages to 32 bit */ + int sync_iv_delay; /**< synchronize I/V delay at cold start */ + int is_probus_device; /**< probus device: device without internal DSP */ + int needs_reset; /**< add the reset trigger for SetAlgoParams and SetMBDrc commands */ + struct kmem_cache *cachep; /**< Memory allocator handle */ +}; + +/** + * The tfa_dev_probe is called before accessing any device accessing functions. + * Access to the tfa device register 3 is attempted and will record the + * returned id for further use. If no device responds the function will abort. + * The recorded id will by used by the query functions to fill the remaining + * relevant data fields of the device structure. + * Data such as MTP features that requires device access will only be read when + * explicitly called and the result will be then cached in the struct. + * + * A structure pointer passed to this device needs to refer to existing memory + * space allocated by the caller. + * + * @param slave = I2C slave address of the target device (not shifted) + * @param tfa struct = points to memory that holds the context for this device + * instance + * + * @return + * - 0 if the I2C device responded to a read of register address 3\n + * when the device responds but with an unknown id a warning will be printed + * - -1 if no response from the I2C device + * + */ +int tfa_dev_probe(int slave, struct tfa_device *tfa); + +/** + * Start this instance at the profile and vstep as provided. + * The profile and vstep will be loaded first in case the current value differs + * from the requested values. + * Note that this call will not change the mute state of the tfa, which means + * that of this instance was called in muted state the caller will have to + * unmute in order to get audio. + * + * @param tfa struct = pointer to context of this device instance + * @param profile the selected profile to run + * @param vstep the selected vstep to use + * @return tfa_error enum + */ +enum tfa_error tfa_dev_start(struct tfa_device *tfa, int profile, int vstep); + + +/** + * Stop audio for this instance as gracefully as possible. + * Audio will be muted and the PLL will be shutdown together with any other + * device/type specific settings needed to prevent audio artifacts or + * workarounds. + * + * Note that this call will change state of the tfa to mute and powered down. + * + * @param tfa struct = pointer to context of this device instance + * @return tfa_error enum + */ +enum tfa_error tfa_dev_stop(struct tfa_device *tfa); + +/** + * This interface allows a device/type independent fine grained control of the + * internal state of the instance. + * Whenever a base state is requested an attempt is made to actively bring the device + * into this state. However this may depend on external conditions beyond control of + * this software layer. Therefore in case the state cannot be set an erro will + * be returned and the current state remains unchanged. + * The base states, lower values below 0x10, are all mutually exclusive, they higher ones + * can also function as a sticky modifier which means for example that operating + * state could be in either muted or unmuted state. Or in case of init_cf it can be + * internal clock (always) or external audio clock. + * This function is intended to be used for device mute/unmute synchronization + * when called from higher layers. Mostly internal calls will use this to control + * the startup and profile transitions in a device/type independent way. + * + * @param tfa struct = pointer to context of this device instance + * @param state struct = desired device state after function return + * @return tfa_error enum + */ +enum tfa_error tfa_dev_set_state(struct tfa_device *tfa, enum tfa_state state); + +/** + * Retrieve the current state of this instance in an active way. + * The state field in tfa structure will reflect the result unless an error is + * returned. + * Note that the hardware state may change on external events an as such this + * field should be treated as volatile. + * + * @param tfa struct = pointer to context of this device instance + * @return tfa_error enum + * + */ +enum tfa_state tfa_dev_get_state(struct tfa_device *tfa); + + +/*****************************************************************************/ +/*****************************************************************************/ +/** + * MTP support functions + */ +enum tfa_mtp { + TFA_MTP_OTC, /**< */ + TFA_MTP_EX, /**< */ + TFA_MTP_RE25, /**< */ + TFA_MTP_RE25_PRIM, /**< */ + TFA_MTP_RE25_SEC, /**< */ + TFA_MTP_LOCK, /**< */ +}; + +/** + * + */ +int tfa_dev_mtp_get(struct tfa_device *tfa, enum tfa_mtp item); + +/** + * + */ +enum tfa_error tfa_dev_mtp_set(struct tfa_device *tfa, enum tfa_mtp item, int value); + + +//irq +/* tfa2 interrupt support + * !!! enum tfa9912_irq !!!*/ +/* + * interrupt bit function to clear + */ +int tfa_irq_clear(struct tfa_device *tfa, int bit); +/* + * return state of irq or -1 if illegal bit + */ +int tfa_irq_get(struct tfa_device *tfa, int bit); +/* + * interrupt bit function that operates on the shadow regs in the handle + */ +int tfa_irq_ena(struct tfa_device *tfa, int bit, int state); +/* + * interrupt bit function that sets the polarity + */ +int tfa_irq_set_pol(struct tfa_device *tfa, int bit, int state); + +/* + * mask interrupts by disabling them + */ +int tfa_irq_mask(struct tfa_device *tfa); +/* + * unmask interrupts by enabling them again + */ +int tfa_irq_unmask(struct tfa_device *tfa); +//cnt read +//debug? + +#endif /* __TFA_DEVICE_H__ */ + diff --git a/techpack/audio/asoc/codecs/tfa9874/tfa_dsp.c b/techpack/audio/asoc/codecs/tfa9874/tfa_dsp.c new file mode 100644 index 000000000000..4589778500c7 --- /dev/null +++ b/techpack/audio/asoc/codecs/tfa9874/tfa_dsp.c @@ -0,0 +1,3910 @@ +/* + * Copyright 2014-2017 NXP Semiconductors + * + * 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 "dbgprint.h" +#include "tfa_container.h" +#include "tfa.h" +#include "tfa98xx_tfafieldnames.h" +#include "tfa_internal.h" + +/* handle macro for bitfield */ +#define TFA_MK_BF(reg, pos, len) ((reg<<8)|(pos<<4)|(len-1)) + +/* abstract family for register */ +#define FAM_TFA98XX_CF_CONTROLS (TFA_FAM(tfa,RST) >> 8) +#define FAM_TFA98XX_CF_MEM (TFA_FAM(tfa,MEMA)>> 8) +#define FAM_TFA98XX_MTP0 (TFA_FAM(tfa,MTPOTC) >> 8) +#define FAM_TFA98xx_INT_EN (TFA_FAM(tfa,INTENVDDS) >> 8) + +#define CF_STATUS_I2C_CMD_ACK 0x01 + +/* Defines below are used for irq function (this removed the genregs include) */ +#define TFA98XX_INTERRUPT_ENABLE_REG1 0x48 +#define TFA98XX_INTERRUPT_IN_REG1 0x44 +#define TFA98XX_INTERRUPT_OUT_REG1 0x40 +#define TFA98XX_STATUS_POLARITY_REG1 0x4c +#define TFA98XX_KEY2_PROTECTED_MTP0_MTPEX_MSK 0x2 +#define TFA98XX_KEY2_PROTECTED_MTP0_MTPOTC_MSK 0x1 +#define TFA98XX_KEY2_PROTECTED_MTP0_MTPEX_POS 1 +#define TFA98XX_KEY2_PROTECTED_MTP0_MTPOTC_POS 0 + +void tfanone_ops(struct tfa_device_ops *ops); +void tfa9872_ops(struct tfa_device_ops *ops); +void tfa9874_ops(struct tfa_device_ops *ops); +void tfa9912_ops(struct tfa_device_ops *ops); +void tfa9888_ops(struct tfa_device_ops *ops); +void tfa9891_ops(struct tfa_device_ops *ops); +void tfa9897_ops(struct tfa_device_ops *ops); +void tfa9896_ops(struct tfa_device_ops *ops); +void tfa9890_ops(struct tfa_device_ops *ops); +void tfa9895_ops(struct tfa_device_ops *ops); +void tfa9894_ops(struct tfa_device_ops *ops); + +#ifndef MIN +#define MIN(A,B) (Amohm[channel]; +} + +/* return sign extended tap pattern */ +int tfa_get_tap_pattern(struct tfa_device *tfa) +{ + int value = tfa_get_bf(tfa, TFA9912_BF_CFTAPPAT ); + int bitshift; + uint8_t field_len = 1 + (TFA9912_BF_CFTAPPAT & 0x0f); /* length of bitfield */ + + bitshift = 8*sizeof(int)-field_len; + /* signextend */ + value = (value << bitshift) >> bitshift; + + return value; +} +/* + * interrupt bit function to clear + */ +int tfa_irq_clear(struct tfa_device *tfa, enum tfa9912_irq bit) +{ + unsigned char reg; + + /* make bitfield enum */ + if ( bit == tfa9912_irq_all) { + /* operate on all bits */ + for(reg=TFA98XX_INTERRUPT_IN_REG1; reg>4)); + reg_write(tfa, reg, 1<<(bit & 0x0f)); /* only this bit */ + } else + return -1; + + return 0; +} +/* + * return state of irq or -1 if illegal bit + */ +int tfa_irq_get(struct tfa_device *tfa, enum tfa9912_irq bit) +{ + uint16_t value; + int reg, mask; + + if (bit < tfa9912_irq_max) { + /* only this bit */ + reg = TFA98XX_INTERRUPT_OUT_REG1 + (bit>>4); + mask = 1<<(bit & 0x0f); + reg_read(tfa, (unsigned char)reg, &value); + } else + return -1; + + return (value & mask) !=0 ; +} +/* + * interrupt bit function that operates on the shadow regs in the handle + */ + +int tfa_irq_ena(struct tfa_device *tfa, enum tfa9912_irq bit, int state) +{ + uint16_t value, new_value; + int reg=0, mask; + /* */ + if ( bit == tfa9912_irq_all) { + /* operate on all bits */ + for(reg=TFA98XX_INTERRUPT_ENABLE_REG1; reg<=TFA98XX_INTERRUPT_ENABLE_REG1+tfa9912_irq_max/16; reg++) { + reg_write(tfa, (unsigned char)reg, state ? 0xffff : 0); /* all bits */ + tfa->interrupt_enable[reg-TFA98XX_INTERRUPT_ENABLE_REG1] = state ? 0xffff : 0; /* all bits */ + } + } else if (bit < tfa9912_irq_max) { + /* only this bit */ + reg = TFA98XX_INTERRUPT_ENABLE_REG1 + (bit>>4); + mask = 1<<(bit & 0x0f); + reg_read(tfa, (unsigned char)reg, &value); + if (state) //set + new_value = (uint16_t)(value | mask); + else // clear + new_value = value & ~mask; + if ( new_value != value) { + reg_write(tfa, (unsigned char)reg, new_value); /* only this bit */ + tfa->interrupt_enable[reg-TFA98XX_INTERRUPT_ENABLE_REG1] = new_value; + } + } else + return -1; + + return 0; +} + +/* + * mask interrupts by disabling them + */ +int tfa_irq_mask(struct tfa_device *tfa) +{ + int reg; + + /* operate on all bits */ + for (reg=TFA98XX_INTERRUPT_ENABLE_REG1; reg<=TFA98XX_INTERRUPT_ENABLE_REG1+tfa9912_irq_max/16; reg++) + reg_write(tfa, (unsigned char)reg, 0); + + return 0; +} + +/* + * unmask interrupts by enabling them again + */ +int tfa_irq_unmask(struct tfa_device *tfa) +{ + int reg; + + /* operate on all bits */ + for (reg=TFA98XX_INTERRUPT_ENABLE_REG1; reg<=TFA98XX_INTERRUPT_ENABLE_REG1+tfa9912_irq_max/16; reg++) + reg_write(tfa, (unsigned char)reg, tfa->interrupt_enable[reg-TFA98XX_INTERRUPT_ENABLE_REG1]); + + return 0; +} + +/* + * interrupt bit function that sets the polarity + */ + +int tfa_irq_set_pol(struct tfa_device *tfa, enum tfa9912_irq bit, int state) +{ + uint16_t value, new_value; + int reg=0, mask; + + if (bit == tfa9912_irq_all) { + /* operate on all bits */ + for(reg=TFA98XX_STATUS_POLARITY_REG1; reg<=TFA98XX_STATUS_POLARITY_REG1+tfa9912_irq_max/16; reg++) { + reg_write(tfa, (unsigned char)reg, state ? 0xffff : 0); /* all bits */ + } + } else if (bit < tfa9912_irq_max) { + /* only this bit */ + reg = TFA98XX_STATUS_POLARITY_REG1 + (bit>>4); + mask = 1<<(bit & 0x0f); + reg_read(tfa, (unsigned char)reg, &value); + if (state) /* Active High */ + new_value = (uint16_t)(value | mask); + else /* Active Low */ + new_value = value & ~mask; + if ( new_value != value) { + reg_write(tfa, (unsigned char)reg, new_value); /* only this bit */ + } + } else + return -1; + + return 0; +} + +/* + * set device info and register device ops + */ +void tfa_set_query_info(struct tfa_device *tfa) +{ + /* invalidate device struct cached values */ + tfa->hw_feature_bits = -1; + tfa->sw_feature_bits[0] = -1; + tfa->sw_feature_bits[1] = -1; + tfa->profile = -1; + tfa->vstep = -1; + /* defaults */ + tfa->is_probus_device = 0; + tfa->tfa_family = 1; + tfa->daimap = Tfa98xx_DAI_I2S; /* all others */ + tfa->spkr_count = 1; + tfa->spkr_select = 0; + tfa->support_tcoef = supportYes; + tfa->supportDrc = supportNotSet; + tfa->support_saam = supportNotSet; + tfa->ext_dsp = -1; /* respond to external DSP: -1:none, 0:no_dsp, 1:cold, 2:warm */ + tfa->bus=0; + tfa->partial_enable = 0; + tfa->convert_dsp32 = 0; + tfa->sync_iv_delay = 0; + + /* TODO use the getfeatures() for retrieving the features [artf103523] + tfa->supportDrc = supportNotSet;*/ + + switch (tfa->rev & 0xff) { + case 0: /* tfanone : non-i2c external DSP device */ + /* e.g. qc adsp */ + tfa->supportDrc = supportYes; + tfa->tfa_family = 0; + tfa->spkr_count = 0; + tfa->daimap = 0; + tfanone_ops(&tfa->dev_ops); /* register device operations via tfa hal*/ + tfa->bus=1; + break; + case 0x72: + /* tfa9872 */ + tfa->supportDrc = supportYes; + tfa->tfa_family = 2; + tfa->spkr_count = 1; + tfa->is_probus_device = 1; + tfa->daimap = Tfa98xx_DAI_TDM; + tfa9872_ops(&tfa->dev_ops); /* register device operations */ + break; + case 0x74: + /* tfa9874 */ + tfa->supportDrc = supportYes; + tfa->tfa_family = 2; + tfa->spkr_count = 1; + tfa->is_probus_device = 1; + tfa->daimap = Tfa98xx_DAI_TDM; + tfa9874_ops(&tfa->dev_ops); /* register device operations */ + break; + case 0x88: + /* tfa9888 */ + tfa->tfa_family = 2; + tfa->spkr_count = 2; + tfa->daimap = Tfa98xx_DAI_TDM; + tfa9888_ops(&tfa->dev_ops); /* register device operations */ + break; + case 0x97: + /* tfa9897 */ + tfa->supportDrc = supportNo; + tfa->spkr_count = 1; + tfa->daimap = Tfa98xx_DAI_TDM; + tfa9897_ops(&tfa->dev_ops); /* register device operations */ + break; + case 0x96: + /* tfa9896 */ + tfa->supportDrc = supportNo; + tfa->spkr_count = 1; + tfa->daimap = Tfa98xx_DAI_TDM; + tfa9896_ops(&tfa->dev_ops); /* register device operations */ + break; + case 0x92: + /* tfa9891 */ + tfa->spkr_count = 1; + tfa->daimap = ( Tfa98xx_DAI_PDM | Tfa98xx_DAI_I2S ); + tfa9891_ops(&tfa->dev_ops); /* register device operations */ + break; + case 0x91: + /* tfa9890B */ + tfa->spkr_count = 1; + tfa->daimap = ( Tfa98xx_DAI_PDM | Tfa98xx_DAI_I2S ); + break; + case 0x80: + case 0x81: + /* tfa9890 */ + tfa->spkr_count = 1; + tfa->daimap = Tfa98xx_DAI_I2S; + tfa->supportDrc = supportNo; + tfa->supportFramework = supportNo; + tfa9890_ops(&tfa->dev_ops); /* register device operations */ + break; + case 0x12: + /* tfa9895 */ + tfa->spkr_count = 1; + tfa->daimap = Tfa98xx_DAI_I2S; + tfa9895_ops(&tfa->dev_ops); /* register device operations */ + break; + case 0x13: + /* tfa9912 */ + tfa->tfa_family = 2; + tfa->spkr_count = 1; + tfa->daimap = Tfa98xx_DAI_TDM; + tfa9912_ops(&tfa->dev_ops); /* register device operations */ + break; + case 0x94: + /* tfa9894 */ + tfa->tfa_family = 2; + tfa->spkr_count = 1; + tfa->daimap = Tfa98xx_DAI_TDM; + tfa9894_ops(&tfa->dev_ops); /* register device operations */ + break; + + default: + pr_err("unknown device type : 0x%02x\n", tfa->rev); + _ASSERT(0); + break; + } +} + +/* + * lookup the device type and return the family type + */ +int tfa98xx_dev2family(int dev_type) +{ + /* only look at the die ID part (lsb byte) */ + switch(dev_type & 0xff) { + case 0x12: + case 0x80: + case 0x81: + case 0x91: + case 0x92: + case 0x97: + case 0x96: + return 1; + case 0x88: + case 0x72: + case 0x13: + case 0x74: + case 0x94: + return 2; + case 0x50: + return 3; + default: + return 0; + } +} + +/* + * return the target address for the filter on this device + + filter_index: + [0..9] reserved for EQ (not deployed, calc. is available) + [10..12] anti-alias filter + [13] integrator filter + + */ +enum Tfa98xx_DMEM tfa98xx_filter_mem(struct tfa_device *tfa, int filter_index, unsigned short *address, int channel) +{ + enum Tfa98xx_DMEM dmem=-1; + int idx; + unsigned short bq_table[7][4] ={ + /* index: 10, 11, 12, 13 */ + {346,351,356,288}, //87 BRA_MAX_MRA4-2_7.00 + {346,351,356,288}, //90 BRA_MAX_MRA6_9.02 + {467,472,477,409}, //95 BRA_MAX_MRA7_10.02 + {406,411,416,348}, //97 BRA_MAX_MRA9_12.01 + {467,472,477,409}, //91 BRA_MAX_MRAA_13.02 + {8832, 8837, 8842, 8847}, //88 part1 + {8853, 8858, 8863, 8868} //88 part2 + /* Since the 88 is stereo we have 2 parts. + * Every index has 5 values except index 13 this one has 6 values + */ + }; + + if ( (10 <= filter_index) && (filter_index <= 13) ) { + dmem = Tfa98xx_DMEM_YMEM; /* for all devices */ + idx = filter_index-10; + + switch (tfa->rev & 0xff ) { // only compare lower byte + case 0x12: + *address = bq_table[2][idx]; + break; + case 0x97: + *address = bq_table[3][idx]; + break; + case 0x96: + *address = bq_table[3][idx]; + break; + case 0x80: + case 0x81: // for the RAM version + case 0x91: + *address = bq_table[1][idx]; + break; + case 0x92: + *address = bq_table[4][idx]; + break; + case 0x88: + /* Channel 1 = primary, 2 = secondary */ + if(channel == 1) + *address = bq_table[5][idx]; + else + *address = bq_table[6][idx]; + break; + case 0x72: + case 0x74: + case 0x13: + default: + /* unsupported case, possibly intermediate version */ + return -1; + _ASSERT(0); + } + } + return dmem; +} + +/************************ query functions ********************************************************/ +/** +* return revision +* Used by the LTT +*/ +void tfa98xx_rev(int *major, int *minor, int *revision) +{ + char version_str[] = TFA98XX_API_REV_STR; + sscanf(version_str, "v%d.%d.%d", major, minor, revision); +} + +/** + * tfa_supported_speakers + * returns the number of the supported speaker count + */ +enum Tfa98xx_Error tfa_supported_speakers(struct tfa_device *tfa, int* spkr_count) +{ + if (tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + else + *spkr_count = tfa->spkr_count; + + return Tfa98xx_Error_Ok; +} + +/* + * tfa98xx_supported_saam + * returns the supportedspeaker as microphone feature + */ +enum Tfa98xx_Error tfa98xx_supported_saam(struct tfa_device *tfa, enum Tfa98xx_saam *saam) +{ + int features; + enum Tfa98xx_Error error; + + if (tfa->support_saam == supportNotSet) { + error = tfa98xx_dsp_get_hw_feature_bits(tfa, &features); + if (error!=Tfa98xx_Error_Ok) + return error; + tfa->support_saam = + (features & 0x8000)? supportYes : supportNo; /* SAAM is bit15 */ + } + *saam = tfa->support_saam == supportYes ? Tfa98xx_saam : Tfa98xx_saam_none ; + + return Tfa98xx_Error_Ok; +} + +/* + * tfa98xx_compare_features + * Obtains features_from_MTP and features_from_cnt + */ +enum Tfa98xx_Error tfa98xx_compare_features(struct tfa_device *tfa, int features_from_MTP[3], int features_from_cnt[3]) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + uint32_t value; + uint16_t mtpbf; + unsigned char bytes[3 * 2]; + int status; + + tfa98xx_dsp_system_stable(tfa, &status); + if (!status) + return Tfa98xx_Error_NoClock; // Only test when we have a clock. + + /* Set proper MTP location per device: */ + if (tfa->tfa_family == 1) { + mtpbf=0x850f; /* MTP5 for tfa1,16 bits */ + } else { + mtpbf=0xf907; /* MTP9 for tfa2, 8 bits */ + } + + /* Read HW features from MTP: */ + value = tfa_read_reg(tfa, mtpbf) & 0xffff; + features_from_MTP[0] = tfa->hw_feature_bits = value; + + /* Read SW features: */ + error = tfa_dsp_cmd_id_write_read(tfa, MODULE_FRAMEWORK, FW_PAR_ID_GET_FEATURE_INFO, sizeof(bytes), bytes); + if (error != Tfa98xx_Error_Ok) + return error; /* old ROM code may respond with Tfa98xx_Error_RpcParamId */ + + tfa98xx_convert_bytes2data(sizeof(bytes), bytes, &features_from_MTP[1]); + + /* check if feature bits from MTP match feature bits from cnt file: */ + get_hw_features_from_cnt(tfa, &features_from_cnt[0]); + get_sw_features_from_cnt(tfa, &features_from_cnt[1]); + + return error; +} + +/********************************* device specific ops ************************************************/ +/* the wrapper for DspReset, in case of full */ +enum Tfa98xx_Error tfa98xx_dsp_reset(struct tfa_device *tfa, int state) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + + error = (tfa->dev_ops.dsp_reset)(tfa, state); + + return error; +} + +/* the ops wrapper for tfa98xx_dsp_SystemStable */ +enum Tfa98xx_Error tfa98xx_dsp_system_stable(struct tfa_device *tfa, int *ready) +{ + return (tfa->dev_ops.dsp_system_stable)(tfa, ready); +} + +/* the ops wrapper for tfa98xx_dsp_system_stable */ +enum Tfa98xx_Error tfa98xx_auto_copy_mtp_to_iic(struct tfa_device *tfa) +{ + return (tfa->dev_ops.auto_copy_mtp_to_iic)(tfa); +} + +/* the ops wrapper for tfa98xx_faim_protect */ +enum Tfa98xx_Error tfa98xx_faim_protect(struct tfa_device *tfa, int state) +{ + return (tfa->dev_ops.faim_protect)(tfa, state); +} + +/* + * bring the device into a state similar to reset + */ +enum Tfa98xx_Error tfa98xx_init(struct tfa_device *tfa) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + uint16_t value=0; + + /* reset all i2C registers to default + * Write the register directly to avoid the read in the bitfield function. + * The I2CR bit may overwrite the full register because it is reset anyway. + * This will save a reg read transaction. + */ + TFA_SET_BF_VALUE(tfa, I2CR, 1, &value ); + TFA_WRITE_REG(tfa, I2CR, value); + + /* Put DSP in reset */ + tfa98xx_dsp_reset(tfa, 1); /* in pair of tfaRunStartDSP() */ + + /* some other registers must be set for optimal amplifier behaviour + * This is implemented in a file specific for the type number + */ + if (tfa->dev_ops.tfa_init) + error = (tfa->dev_ops.tfa_init)(tfa); + + return error; +} + +enum Tfa98xx_Error tfa98xx_dsp_write_tables(struct tfa_device *tfa, int sample_rate) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + + error = (tfa->dev_ops.dsp_write_tables)(tfa, sample_rate); + + return error; +} + +/** Set internal oscillator into power down mode. +* +* @param[in] tfa device description structure +* @param[in] state new state 0 - oscillator is on, 1 oscillator is off. +* +* @return Tfa98xx_Error_Ok when successfull, error otherwise. +*/ +enum Tfa98xx_Error tfa98xx_set_osc_powerdown(struct tfa_device *tfa, int state) +{ + if (tfa->dev_ops.set_osc_powerdown) { + return tfa->dev_ops.set_osc_powerdown(tfa, state); + } + + return Tfa98xx_Error_Not_Implemented; +} + +/** Check presence of powerswitch=1 in configuration and optimal setting. +* +* @param[in] tfa device description structure +* +* @return -1 when error, 0 or 1 depends on switch settings. +*/ +int tfa98xx_powerswitch_is_enabled(struct tfa_device *tfa) +{ + uint16_t value; + enum Tfa98xx_Error ret; + + if (((tfa->rev & 0xff) == 0x13) || ((tfa->rev & 0xff) == 0x88)) { + ret = reg_read(tfa, 0xc6, &value); + if (ret != Tfa98xx_Error_Ok) { + return -1; + } + /* PLMA5539: Check actual value of powerswitch. TODO: regmap v1.40 should make this bit public. */ + + return (int)(value & (1u << 6)); + } + + return 1; +} + +/********************* new tfa2 *********************************************************************/ +/* newly added messaging for tfa2 tfa1? */ +enum Tfa98xx_Error tfa98xx_dsp_get_memory(struct tfa_device *tfa, int memoryType, + int offset, int length, unsigned char bytes[]) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + char msg[4*3]; + int nr = 0; + + msg[nr++] = 8; + msg[nr++] = MODULE_FRAMEWORK + 128; + msg[nr++] = FW_PAR_ID_GET_MEMORY; + + msg[nr++] = 0; + msg[nr++] = 0; + msg[nr++] = (char)memoryType; + + msg[nr++] = 0; + msg[nr++] = (offset>>8) & 0xff; + msg[nr++] = offset & 0xff; + + msg[nr++] = 0; + msg[nr++] = (length>>8) & 0xff; + msg[nr++] = length & 0xff; + + /* send msg */ + error = dsp_msg(tfa, nr, (char *)msg); + + if (error != Tfa98xx_Error_Ok) + return error; + + /* read the data from the device (length * 3) */ + error = dsp_msg_read(tfa, length * 3, bytes); + + return error; +} + +enum Tfa98xx_Error tfa98xx_dsp_set_memory(struct tfa_device *tfa, int memoryType, + int offset, int length, int value) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + int nr = 0; + char msg[5*3]; + + msg[nr++] = 8; + msg[nr++] = MODULE_FRAMEWORK + 128; + msg[nr++] = FW_PAR_ID_SET_MEMORY; + + msg[nr++] = 0; + msg[nr++] = 0; + msg[nr++] = (char)memoryType; + + msg[nr++] = 0; + msg[nr++] = (offset>>8) & 0xff; + msg[nr++] = offset & 0xff; + + msg[nr++] = 0; + msg[nr++] = (length>>8) & 0xff; + msg[nr++] = length & 0xff; + + msg[nr++] = (value>>16) & 0xff; + msg[nr++] = (value>>8) & 0xff; + msg[nr++] = value & 0xff; + + /* send msg */ + error = dsp_msg(tfa, nr, (char *)msg); + + return error; +} +/****************************** calibration support **************************/ +/* + * get/set the mtp with user controllable values + * + * check if the relevant clocks are available + */ +enum Tfa98xx_Error tfa98xx_get_mtp(struct tfa_device *tfa, uint16_t *value) +{ + int status; + int result; + + /* not possible if PLL in powerdown */ + if ( TFA_GET_BF(tfa, PWDN) ) { + pr_debug("PLL in powerdown\n"); + return Tfa98xx_Error_NoClock; + } + + tfa98xx_dsp_system_stable(tfa, &status); + if (status==0) { + pr_debug("PLL not running\n"); + return Tfa98xx_Error_NoClock; + } + + result = TFA_READ_REG(tfa, MTP0); + if (result < 0) { + return -result; + } + *value = (uint16_t)result; + + return Tfa98xx_Error_Ok; +} + +/* + * lock or unlock KEY2 + * lock = 1 will lock + * lock = 0 will unlock + * + * note that on return all the hidden key will be off + */ +void tfa98xx_key2(struct tfa_device *tfa, int lock) +{ + /* unhide lock registers */ + reg_write(tfa, (tfa->tfa_family == 1) ? 0x40 :0x0F, 0x5A6B); + /* lock/unlock key2 MTPK */ + TFA_WRITE_REG(tfa, MTPKEY2, lock? 0 :0x5A ); + /* unhide lock registers */ + reg_write(tfa, (tfa->tfa_family == 1) ? 0x40 :0x0F, 0); +} +void tfa2_manual_mtp_cpy(struct tfa_device *tfa, uint16_t reg_row_to_keep,uint16_t reg_row_to_set ,uint8_t row)///MCH_TO_TEST +{ + uint16_t value; + enum Tfa98xx_Error error; + /* Assure FAIM is enabled (enable it when neccesery) */ + error = tfa98xx_faim_protect(tfa, 1); + if (tfa->verbose) { + pr_debug("FAIM enabled (err:%d).\n", error); + } + reg_read(tfa, (unsigned char)reg_row_to_keep, &value); + if (!row) { + reg_write(tfa, 0xA7, value); + reg_write(tfa, 0xA8, reg_row_to_set); + } else { + reg_write(tfa, 0xA7, reg_row_to_set); + reg_write(tfa, 0xA8, value); + } + reg_write(tfa, 0xA3, 0x10|row); + + error = tfa98xx_faim_protect(tfa, 0); + if (tfa->verbose) { + pr_debug("FAIM disabled (err:%d).\n", error); + } +} + +enum Tfa98xx_Error tfa98xx_set_mtp(struct tfa_device *tfa, uint16_t value, uint16_t mask) +{ + unsigned short mtp_old, mtp_new; + int loop, status; + enum Tfa98xx_Error error; + + error = tfa98xx_get_mtp(tfa, &mtp_old); + + if (error != Tfa98xx_Error_Ok) + return error; + + mtp_new = (value & mask) | (mtp_old & ~mask); + + if ( mtp_old == mtp_new) /* no change */ { + if (tfa->verbose) + pr_info("No change in MTP. Value not written! \n"); + return Tfa98xx_Error_Ok; + } + + /* Assure FAIM is enabled (enable it when neccesery) */ + error = tfa98xx_faim_protect(tfa, 1); + if (error) { + return error; + } + if (tfa->verbose) { + pr_debug("MTP clock enabled.\n"); + } + + /* assure that the clock is up, else we can't write MTP */ + error = tfa98xx_dsp_system_stable(tfa, &status); + if (error){ + return error; + } + if (status==0){ + return Tfa98xx_Error_NoClock; + } + + tfa98xx_key2(tfa, 0); /* unlock */ + TFA_WRITE_REG(tfa, MTP0, mtp_new); /* write to i2c shadow reg */ + /* CIMTP=1 start copying all the data from i2c regs_mtp to mtp*/ + if (tfa->tfa_family == 2) + tfa2_manual_mtp_cpy(tfa, 0xF1, mtp_new, 0); + else + TFA_SET_BF(tfa, CIMTP, 1); + + /* no check for MTPBUSY here, i2c delay assumed to be enough */ + tfa98xx_key2(tfa, 1); /* lock */ + + /* wait until MTP write is done */ + error = Tfa98xx_Error_StateTimedOut; + for(loop=0; loop<100 /*x10ms*/ ;loop++) { + msleep_interruptible(10); /* wait 10ms to avoid busload */ + if (tfa_dev_get_mtpb(tfa) == 0) { + error = Tfa98xx_Error_Ok; + break; + } + } + /* MTP setting failed due to timeout ?*/ + if (error) { + return error; + } + + /* Disable the FAIM, if this is neccessary */ + error = tfa98xx_faim_protect(tfa, 0); + if (error) { + return error; + } + if (tfa->verbose) { + pr_debug("MTP clock disabled.\n"); + } + + return error; +} +/* + * clear mtpex + * set ACS + * start tfa + */ +int tfa_calibrate(struct tfa_device *tfa) +{ + enum Tfa98xx_Error error; + + /* clear mtpex */ + error = tfa98xx_set_mtp(tfa, 0, TFA98XX_KEY2_PROTECTED_MTP0_MTPEX_MSK); + if (error) + return error ; + + /* set RST=1 to put the DSP in Reset */ + TFA_SET_BF(tfa, RST, 1); + + /* set ACS/coldboot state */ + error = tfaRunColdboot(tfa, 1); + + /* start tfa by playing */ + return error; +} + +static short twos(short x) +{ + return (x<0)? x+512 : x; +} + +void tfa98xx_set_exttemp(struct tfa_device *tfa, short ext_temp) +{ + if ((-256 <= ext_temp) && (ext_temp <= 255)) { + /* make twos complement */ + pr_debug("Using ext temp %d C\n", twos(ext_temp)); + TFA_SET_BF(tfa, TROS, 1); + TFA_SET_BF(tfa, EXTTS, twos(ext_temp)); + } else { + pr_debug("Clearing ext temp settings\n"); + TFA_SET_BF(tfa, TROS, 0); + } +} +short tfa98xx_get_exttemp(struct tfa_device *tfa) +{ + short ext_temp = (short)TFA_GET_BF(tfa, EXTTS); + return (twos(ext_temp)); +} + +/************************** tfa simple bitfield interfacing ***************************************/ +/* convenience functions */ +enum Tfa98xx_Error tfa98xx_set_volume_level(struct tfa_device *tfa, unsigned short vol) +{ + if(tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + + if (vol > 255) /* restricted to 8 bits */ + vol = 255; + + /* 0x00 -> 0.0 dB + * 0x01 -> -0.5 dB + * ... + * 0xFE -> -127dB + * 0xFF -> muted + */ + + /* volume value is in the top 8 bits of the register */ + return -TFA_SET_BF(tfa, VOL, (uint16_t)vol); +} + +static enum Tfa98xx_Error +tfa98xx_set_mute_tfa2(struct tfa_device *tfa, enum Tfa98xx_Mute mute) +{ + enum Tfa98xx_Error error; + + if (tfa->dev_ops.set_mute == NULL) + return Tfa98xx_Error_Not_Supported; + + switch (mute) { + case Tfa98xx_Mute_Off: + error = tfa->dev_ops.set_mute(tfa, 0); + TFA_SET_BF(tfa, AMPE, 1); + break; + case Tfa98xx_Mute_Amplifier: + case Tfa98xx_Mute_Digital: + error = tfa->dev_ops.set_mute(tfa, 1); + TFA_SET_BF(tfa, AMPE, 0); + break; + default: + return Tfa98xx_Error_Bad_Parameter; + } + + return error; +} + +static enum Tfa98xx_Error +tfa98xx_set_mute_tfa1(struct tfa_device *tfa, enum Tfa98xx_Mute mute) +{ + enum Tfa98xx_Error error; + unsigned short audioctrl_value; + unsigned short sysctrl_value; + int value; + + value = TFA_READ_REG(tfa, CFSM); /* audio control register */ + if (value < 0) + return -value; + audioctrl_value = (unsigned short)value; + value = TFA_READ_REG(tfa, AMPE); /* system control register */ + if (value < 0) + return -value; + sysctrl_value = (unsigned short)value; + + switch (mute) { + case Tfa98xx_Mute_Off: + /* previous state can be digital or amplifier mute, + * clear the cf_mute and set the enbl_amplifier bits + * + * To reduce PLOP at power on it is needed to switch the + * amplifier on with the DCDC in follower mode + * (enbl_boost = 0 ?). + * This workaround is also needed when toggling the + * powerdown bit! + */ + TFA_SET_BF_VALUE(tfa, CFSM, 0, &audioctrl_value); + TFA_SET_BF_VALUE(tfa, AMPE, 1, &sysctrl_value); + TFA_SET_BF_VALUE(tfa, DCA, 1, &sysctrl_value); + break; + case Tfa98xx_Mute_Digital: + /* expect the amplifier to run */ + /* set the cf_mute bit */ + TFA_SET_BF_VALUE(tfa, CFSM, 1, &audioctrl_value); + /* set the enbl_amplifier bit */ + TFA_SET_BF_VALUE(tfa, AMPE, 1, &sysctrl_value); + /* clear active mode */ + TFA_SET_BF_VALUE(tfa, DCA, 0, &sysctrl_value); + break; + case Tfa98xx_Mute_Amplifier: + /* clear the cf_mute bit */ + TFA_SET_BF_VALUE(tfa, CFSM, 0, &audioctrl_value); + /* clear the enbl_amplifier bit and active mode */ + TFA_SET_BF_VALUE(tfa, AMPE, 0, &sysctrl_value); + TFA_SET_BF_VALUE(tfa, DCA, 0, &sysctrl_value); + break; + default: + return Tfa98xx_Error_Bad_Parameter; + } + + error = -TFA_WRITE_REG(tfa, CFSM, audioctrl_value); + if (error) + return error; + error = -TFA_WRITE_REG(tfa, AMPE, sysctrl_value); + return error; +} + +enum Tfa98xx_Error +tfa98xx_set_mute(struct tfa_device *tfa, enum Tfa98xx_Mute mute) +{ + if (tfa->in_use == 0) { + pr_err("device is not opened \n"); + return Tfa98xx_Error_NotOpen; + } + + if (tfa->tfa_family == 1) + return tfa98xx_set_mute_tfa1(tfa, mute); + else + return tfa98xx_set_mute_tfa2(tfa, mute); +} + +/****************** patching **********************************************************/ +static enum Tfa98xx_Error +tfa98xx_process_patch_file(struct tfa_device *tfa, int length, + const unsigned char *bytes) +{ + unsigned short size; + int index = 0; + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + + while (index < length) { + size = bytes[index] + bytes[index + 1] * 256; + index += 2; + if ((index + size) > length) { + /* outside the buffer, error in the input data */ + return Tfa98xx_Error_Bad_Parameter; + } + + if (size > tfa->buffer_size) { + /* too big, must fit buffer */ + return Tfa98xx_Error_Bad_Parameter; + } + + error = tfa98xx_write_raw(tfa, size, &bytes[index]); + if (error != Tfa98xx_Error_Ok) + break; + index += size; + } + return error; +} + + + +/* the patch contains a header with the following + * IC revision register: 1 byte, 0xFF means don't care + * XMEM address to check: 2 bytes, big endian, 0xFFFF means don't care + * XMEM value to expect: 3 bytes, big endian + */ +static enum Tfa98xx_Error +tfa98xx_check_ic_rom_version(struct tfa_device *tfa, const unsigned char patchheader[]) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + unsigned short checkrev, revid; + unsigned char lsb_revid; + unsigned short checkaddress; + int checkvalue; + int value = 0; + int status; + checkrev = patchheader[0]; + lsb_revid = tfa->rev & 0xff; /* only compare lower byte */ + + if ((checkrev != 0xFF) && (checkrev != lsb_revid)) + return Tfa98xx_Error_Not_Supported; + + checkaddress = (patchheader[1] << 8) + patchheader[2]; + checkvalue = + (patchheader[3] << 16) + (patchheader[4] << 8) + patchheader[5]; + if (checkaddress != 0xFFFF) { + /* before reading XMEM, check if we can access the DSP */ + error = tfa98xx_dsp_system_stable(tfa, &status); + if (error == Tfa98xx_Error_Ok) { + if (!status) { + /* DSP subsys not running */ + error = Tfa98xx_Error_DSP_not_running; + } + } + /* read register to check the correct ROM version */ + if (error == Tfa98xx_Error_Ok) { + error = mem_read(tfa, checkaddress, 1, &value); + } + if (error == Tfa98xx_Error_Ok) { + if (value != checkvalue) { + pr_err("patch file romid type check failed [0x%04x]: expected 0x%02x, actual 0x%02x\n", + checkaddress, value, checkvalue); + error = Tfa98xx_Error_Not_Supported; + } + } + } else { /* == 0xffff */ + /* check if the revid subtype is in there */ + if ( checkvalue != 0xFFFFFF && checkvalue != 0) { + revid = patchheader[5]<<8 | patchheader[0]; /* full revid */ + if ( revid != tfa->rev) { + pr_err("patch file device type check failed: expected 0x%02x, actual 0x%02x\n", + tfa->rev, revid); + return Tfa98xx_Error_Not_Supported; + } + } + } + + return error; +} + + +#define PATCH_HEADER_LENGTH 6 +enum Tfa98xx_Error +tfa_dsp_patch(struct tfa_device *tfa, int patchLength, + const unsigned char *patchBytes) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + int status; + if(tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + + if (patchLength < PATCH_HEADER_LENGTH) + return Tfa98xx_Error_Bad_Parameter; + + error = tfa98xx_check_ic_rom_version(tfa, patchBytes); + if (Tfa98xx_Error_Ok != error) { + return error; + } + tfa98xx_dsp_system_stable(tfa, &status); + if (!status) + return Tfa98xx_Error_NoClock; + if (error == Tfa98xx_Error_Ok) { + pr_info("tfa cold boot patch\n"); + error = tfaRunColdboot(tfa, 1); + if (error) { + pr_err("tfa_dsp_patch DSP_not_running\n"); + return Tfa98xx_Error_DSP_not_running; + } + } + + error = + tfa98xx_process_patch_file(tfa, patchLength - PATCH_HEADER_LENGTH, + patchBytes + PATCH_HEADER_LENGTH); + + return error; +} + +/****************** end patching **********************************************************/ + +TFA_INTERNAL enum Tfa98xx_Error +tfa98xx_wait_result(struct tfa_device *tfa, int wait_retry_count) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + int cf_status; /* the contents of the CF_STATUS register */ + int tries = 0; + do { + cf_status = TFA_GET_BF(tfa, ACK); + if (cf_status < 0) + error = -cf_status; + tries++; + } + // i2c_cmd_ack + /* don't wait forever, DSP is pretty quick to respond (< 1ms) */ + while ((error == Tfa98xx_Error_Ok) && ((cf_status & CF_STATUS_I2C_CMD_ACK) == 0) + && (tries < wait_retry_count)); + if (tries >= wait_retry_count) { + /* something wrong with communication with DSP */ + error = Tfa98xx_Error_DSP_not_running; + } + return error; +} + +/* + * * support functions for data conversion + */ +/** + convert memory bytes to signed 24 bit integers + input: bytes contains "num_bytes" byte elements + output: data contains "num_bytes/3" int24 elements +*/ +void tfa98xx_convert_bytes2data(int num_bytes, const unsigned char bytes[], + int data[]) +{ + int i; /* index for data */ + int k; /* index for bytes */ + int d; + int num_data = num_bytes / 3; + _ASSERT((num_bytes % 3) == 0); + for (i = 0, k = 0; i < num_data; ++i, k += 3) { + d = (bytes[k] << 16) | (bytes[k + 1] << 8) | (bytes[k + 2]); + _ASSERT(d >= 0); + _ASSERT(d < (1 << 24)); /* max 24 bits in use */ + if (bytes[k] & 0x80) /* sign bit was set */ + d = -((1 << 24) - d); + + data[i] = d; + } +} + + +/** + convert signed 32 bit integers to 24 bit aligned bytes + input: data contains "num_data" int elements + output: bytes contains "3 * num_data" byte elements +*/ +void tfa98xx_convert_data2bytes(int num_data, const int data[], + unsigned char bytes[]) +{ + int i; /* index for data */ + int k; /* index for bytes */ + int d; + /* note: cannot just take the lowest 3 bytes from the 32 bit + * integer, because also need to take care of clipping any + * value > 2&23 */ + for (i = 0, k = 0; i < num_data; ++i, k += 3) { + if (data[i] >= 0) + d = MIN(data[i], (1 << 23) - 1); + else { + /* 2's complement */ + d = (1 << 24) - MIN(-data[i], 1 << 23); + } + _ASSERT(d >= 0); + _ASSERT(d < (1 << 24)); /* max 24 bits in use */ + bytes[k] = (d >> 16) & 0xFF; /* MSB */ + bytes[k + 1] = (d >> 8) & 0xFF; + bytes[k + 2] = (d) & 0xFF; /* LSB */ + } +} + +/* + * DSP RPC message support functions + * depending on framework to be up and running + * need base i2c of memaccess (tfa1=0x70/tfa2=0x90) + */ + + +/* write dsp messages in function tfa_dsp_msg() */ +/* note the 'old' write_parameter() was more efficient because all i2c was in one burst transaction */ + +//TODO properly handle bitfields: state should be restored! (now it will change eg dmesg field to xmem) +enum Tfa98xx_Error tfa_dsp_msg_write(struct tfa_device *tfa, int length, const char *buffer) +{ + int offset = 0; + int chunk_size = ROUND_DOWN(tfa->buffer_size, 3); /* XMEM word size */ + int remaining_bytes = length; + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + uint16_t cfctl; + int value; + + value = TFA_READ_REG(tfa, DMEM); + if (value < 0) { + error = -value; + return error; + } + cfctl = (uint16_t)value; + /* assume no I2C errors from here */ + + TFA_SET_BF_VALUE(tfa, DMEM, (uint16_t)Tfa98xx_DMEM_XMEM, &cfctl); /* set cf ctl to DMEM */ + TFA_SET_BF_VALUE(tfa, AIF, 0, &cfctl ); /* set to autoincrement */ + TFA_WRITE_REG(tfa, DMEM, cfctl); + + /* xmem[1] is start of message + * direct write to register to save cycles avoiding read-modify-write + */ + TFA_WRITE_REG(tfa, MADD, 1); + + /* due to autoincrement in cf_ctrl, next write will happen at + * the next address */ + while ((error == Tfa98xx_Error_Ok) && (remaining_bytes > 0)) { + if (remaining_bytes < chunk_size) + chunk_size = remaining_bytes; + /* else chunk_size remains at initialize value above */ + error = tfa98xx_write_data(tfa, FAM_TFA98XX_CF_MEM, + chunk_size, (const unsigned char *)buffer + offset); + remaining_bytes -= chunk_size; + offset += chunk_size; + } + + /* notify the DSP */ + if (error == Tfa98xx_Error_Ok) { + /* cf_int=0, cf_aif=0, cf_dmem=XMEM=01, cf_rst_dsp=0 */ + /* set the cf_req1 and cf_int bit */ + TFA_SET_BF_VALUE(tfa, REQCMD, 0x01, &cfctl ); /* bit 0 */ + TFA_SET_BF_VALUE(tfa, CFINT, 1, &cfctl ); + error = -TFA_WRITE_REG(tfa, CFINT, cfctl); + } + + return error; +} + +enum Tfa98xx_Error tfa_dsp_msg_write_id(struct tfa_device *tfa, int length, const char *buffer, uint8_t cmdid[3]) +{ + int offset = 0; + int chunk_size = ROUND_DOWN(tfa->buffer_size, 3); /* XMEM word size */ + int remaining_bytes = length; + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + uint16_t cfctl; + int value; + + value = TFA_READ_REG(tfa, DMEM); + if (value < 0) { + error = -value; + return error; + } + cfctl = (uint16_t)value; + /* assume no I2C errors from here */ + + TFA_SET_BF_VALUE(tfa, DMEM, (uint16_t)Tfa98xx_DMEM_XMEM, &cfctl); /* set cf ctl to DMEM */ + TFA_SET_BF_VALUE(tfa, AIF, 0, &cfctl ); /* set to autoincrement */ + TFA_WRITE_REG(tfa, DMEM, cfctl); + + /* xmem[1] is start of message + * direct write to register to save cycles avoiding read-modify-write + */ + TFA_WRITE_REG(tfa, MADD, 1); + + /* write cmd-id */ + error = tfa98xx_write_data(tfa, FAM_TFA98XX_CF_MEM, 3, (const unsigned char *)cmdid); + + /* due to autoincrement in cf_ctrl, next write will happen at + * the next address */ + while ((error == Tfa98xx_Error_Ok) && (remaining_bytes > 0)) { + if (remaining_bytes < chunk_size) + chunk_size = remaining_bytes; + /* else chunk_size remains at initialize value above */ + error = tfa98xx_write_data(tfa, FAM_TFA98XX_CF_MEM, + chunk_size, (const unsigned char *)buffer + offset); + remaining_bytes -= chunk_size; + offset += chunk_size; + } + + /* notify the DSP */ + if (error == Tfa98xx_Error_Ok) { + /* cf_int=0, cf_aif=0, cf_dmem=XMEM=01, cf_rst_dsp=0 */ + /* set the cf_req1 and cf_int bit */ + TFA_SET_BF_VALUE(tfa, REQCMD, 0x01, &cfctl ); /* bit 0 */ + TFA_SET_BF_VALUE(tfa, CFINT, 1, &cfctl ); + error = -TFA_WRITE_REG(tfa, CFINT, cfctl); + } + + return error; +} + +/* +* status function used by tfa_dsp_msg() to retrieve command/msg status: +* return a <0 status of the DSP did not ACK. +*/ +enum Tfa98xx_Error tfa_dsp_msg_status(struct tfa_device *tfa, int *pRpcStatus) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + + error = tfa98xx_wait_result(tfa, 2); /* 2 is only one try */ + if (error == Tfa98xx_Error_DSP_not_running) { + *pRpcStatus = -1; + return Tfa98xx_Error_Ok; + } + else if (error != Tfa98xx_Error_Ok) + return error; + + error = tfa98xx_check_rpc_status(tfa, pRpcStatus); + + return error; +} + +const char* tfa98xx_get_i2c_status_id_string(int status) +{ + const char* p_id_str; + + switch (status) + { + case Tfa98xx_DSP_Not_Running: + p_id_str = "No response from DSP"; + break; + case Tfa98xx_I2C_Req_Done: + p_id_str = "Ok"; + break; + case Tfa98xx_I2C_Req_Busy: + p_id_str = "Request is being processed"; + break; + case Tfa98xx_I2C_Req_Invalid_M_ID: + p_id_str = "Provided M-ID does not fit in valid rang [0..2]"; + break; + case Tfa98xx_I2C_Req_Invalid_P_ID: + p_id_str = "Provided P-ID is not valid in the given M-ID context"; + break; + case Tfa98xx_I2C_Req_Invalid_CC: + p_id_str = "Invalid channel configuration bits (SC|DS|DP|DC) combination"; + break; + case Tfa98xx_I2C_Req_Invalid_Seq: + p_id_str = "Invalid sequence of commands, in case the DSP expects some commands in a specific order"; + break; + case Tfa98xx_I2C_Req_Invalid_Param: + p_id_str = "Generic error, invalid parameter"; + break; + case Tfa98xx_I2C_Req_Buffer_Overflow: + p_id_str = "I2C buffer has overflowed: host has sent too many parameters, memory integrity is not guaranteed"; + break; + case Tfa98xx_I2C_Req_Calib_Busy: + p_id_str = "Calibration not completed"; + break; + case Tfa98xx_I2C_Req_Calib_Failed: + p_id_str = "Calibration failed"; + break; + + default: + p_id_str = "Unspecified error"; + } + + return p_id_str; +} + +enum Tfa98xx_Error tfa_dsp_msg_read(struct tfa_device *tfa, int length, unsigned char *bytes) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + int burst_size; /* number of words per burst size */ + int bytes_per_word = 3; + int num_bytes; + int offset = 0; + unsigned short start_offset=2; /* msg starts @xmem[2] ,[1]=cmd */ + + if ( length > TFA2_MAX_PARAM_SIZE) + return Tfa98xx_Error_Bad_Parameter; + + TFA_SET_BF(tfa, DMEM, (uint16_t)Tfa98xx_DMEM_XMEM); + error = -TFA_WRITE_REG(tfa, MADD, start_offset); + if (error != Tfa98xx_Error_Ok) + return error; + + num_bytes = length; /* input param */ + while (num_bytes > 0) { + burst_size = ROUND_DOWN(tfa->buffer_size, bytes_per_word); + if (num_bytes < burst_size) + burst_size = num_bytes; + error = tfa98xx_read_data(tfa, FAM_TFA98XX_CF_MEM, burst_size, bytes + offset); + if (error != Tfa98xx_Error_Ok) + return error; + + num_bytes -= burst_size; + offset += burst_size; + } + + return error; +} + +enum Tfa98xx_Error dsp_msg(struct tfa_device *tfa, int length24, const char *buf24) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + int lastmessage=0; + uint8_t *blob; + int i; + int *intbuf = NULL; + char* buf = (char *)buf24; + int length = length24; + + if (tfa->convert_dsp32) { + int idx = 0; + + length = 4 * length24 / 3; + intbuf = kmem_cache_alloc(tfa->cachep, GFP_KERNEL); + buf = (char *)intbuf; + + /* convert 24 bit DSP messages to a 32 bit integer */ + for (i=0; i> 8; + } + } + + /* Only create multi-msg when the dsp is cold */ + if(tfa->ext_dsp == 1) { + /* Creating the multi-msg */ + error = tfa_tib_dsp_msgmulti(tfa, length, buf); + if(error == Tfa98xx_Error_Fail) + return Tfa98xx_Error_Fail; + + /* if the buffer is full we need to send the existing message and add the current message */ + if(error == Tfa98xx_Error_Buffer_too_small) { + int len; + + /* (a) send the existing (full) message */ + blob = kmalloc(64*1024, GFP_KERNEL); // max length is 64k + len = tfa_tib_dsp_msgmulti(tfa, -1, (const char*)blob); + if (tfa->verbose) { + pr_debug("Multi-message buffer full. Sending multi-message, length=%d \n", len); + } + if (tfa->has_msg==0 ) /* via i2c */ { + /* Send tot the target selected */ + error = (tfa->dev_ops.dsp_msg)(tfa, len, (const char*)blob); + } else { /* via msg hal */ + error = tfa98xx_write_dsp(tfa, len, (const char*)blob); + } + kfree(blob); + + /* (b) add the current DSP message to a new multi-message */ + error = tfa_tib_dsp_msgmulti(tfa, length, buf); + if(error == Tfa98xx_Error_Fail) { + return Tfa98xx_Error_Fail; + } + } + + lastmessage = error; + + /* When the lastmessage is done we can send the multi-msg to the target */ + if(lastmessage == 1) { + + /* Get the full multi-msg data */ + blob = kmalloc(64*1024, GFP_KERNEL); //max length is 64k + length = tfa_tib_dsp_msgmulti(tfa, -1, (const char*)blob); + + if (tfa->verbose) + pr_debug("Last message for the multi-message received. Multi-message length=%d \n", length); + + if (tfa->has_msg==0 ) /* via i2c */ { + /* Send tot the target selected */ + error = (tfa->dev_ops.dsp_msg)(tfa, length, (const char*)blob); + } else { /* via msg hal */ + error = tfa98xx_write_dsp(tfa, length, (const char*)blob); + } + + kfree(blob); /* Free the kmalloc blob */ + lastmessage = 0; /* reset to be able to re-start */ + } + } else { + if (tfa->has_msg==0 ) /* via i2c */ { + error = (tfa->dev_ops.dsp_msg)(tfa, length, buf); + } else { /* via msg hal */ + error = tfa98xx_write_dsp(tfa, length, (const char*)buf); + } + } + + if(error != Tfa98xx_Error_Ok) + error = (enum Tfa98xx_Error) (error + Tfa98xx_Error_RpcBase); /* Get actual error code from softDSP */ + + /* DSP verbose has argument 0x04 */ + if((tfa->verbose & 0x04)!=0) { + pr_debug("DSP w [%d]: ", length); + for(i=0; iconvert_dsp32) { + kmem_cache_free(tfa->cachep, intbuf); + } + + return error; +} + +enum Tfa98xx_Error dsp_msg_read(struct tfa_device *tfa, int length24, unsigned char *bytes24) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + int i; + int length = length24; + unsigned char *bytes = bytes24; + + if (tfa->convert_dsp32) { + length = 4 * length24 / 3; + bytes = kmem_cache_alloc(tfa->cachep, GFP_KERNEL); + } + + if (tfa->has_msg==0) /* via i2c */ { + error = (tfa->dev_ops.dsp_msg_read)(tfa, length, bytes); + } else { /* via msg hal */ + error = tfa98xx_read_dsp(tfa, length, bytes); + } + + if(error != Tfa98xx_Error_Ok) + error = (enum Tfa98xx_Error) (error + Tfa98xx_Error_RpcBase); /* Get actual error code from softDSP */ + + /* DSP verbose has argument 0x04 */ + if((tfa->verbose & 0x04)!=0) { + pr_debug("DSP R [%d]: ", length); + for(i=0; iconvert_dsp32) { + int idx = 0; + + /* convert 32 bit LE to 24 bit BE */ + for (i=0; icachep, bytes); + } + + return error; +} + +enum Tfa98xx_Error reg_read(struct tfa_device *tfa, unsigned char subaddress, unsigned short *value) +{ + enum Tfa98xx_Error error; + + error = (tfa->dev_ops.reg_read)(tfa, subaddress, value); + if(error != Tfa98xx_Error_Ok) + error = (enum Tfa98xx_Error) (error + Tfa98xx_Error_RpcBase); /* Get actual error code from softDSP */ + + return error; +} + +enum Tfa98xx_Error reg_write(struct tfa_device *tfa, unsigned char subaddress, unsigned short value) +{ + enum Tfa98xx_Error error; + + error = (tfa->dev_ops.reg_write)(tfa, subaddress, value); + if(error != Tfa98xx_Error_Ok) + error = (enum Tfa98xx_Error) (error + Tfa98xx_Error_RpcBase); /* Get actual error code from softDSP */ + + return error; +} + +enum Tfa98xx_Error mem_read(struct tfa_device *tfa, unsigned int start_offset, int num_words, int *pValues) +{ + enum Tfa98xx_Error error; + + error = (tfa->dev_ops.mem_read)(tfa, start_offset, num_words, pValues); + if(error != Tfa98xx_Error_Ok) + error = (enum Tfa98xx_Error) (error + Tfa98xx_Error_RpcBase); /* Get actual error code from softDSP */ + + return error; +} + +enum Tfa98xx_Error mem_write(struct tfa_device *tfa, unsigned short address, int value, int memtype) +{ + enum Tfa98xx_Error error; + + error = (tfa->dev_ops.mem_write)(tfa, address, value, memtype); + if(error != Tfa98xx_Error_Ok) + error = (enum Tfa98xx_Error) (error + Tfa98xx_Error_RpcBase); /* Get actual error code from softDSP */ + + return error; +} + + +/* + * write/read raw msg functions : + * the buffer is provided in little endian format, each word occupying 3 bytes, length is in bytes. + * The functions will return immediately and do not not wait for DSP reponse. + */ +#define MAX_WORDS (300) +enum Tfa98xx_Error tfa_dsp_msg(struct tfa_device *tfa, int length, const char *buf) +{ + enum Tfa98xx_Error error; + int tries, rpc_status = Tfa98xx_I2C_Req_Done; + + /* write the message and notify the DSP */ + error = tfa_dsp_msg_write(tfa, length, buf); + if( error != Tfa98xx_Error_Ok) + return error; + + /* get the result from the DSP (polling) */ + for(tries=TFA98XX_WAITRESULT_NTRIES; tries>0;tries--) { + error = tfa_dsp_msg_status(tfa, &rpc_status); + if (error == Tfa98xx_Error_Ok && rpc_status == Tfa98xx_I2C_Req_Done) + break; + /* If the rpc status is a specific error we want to know it. + * If it is busy or not running it should retry + */ + if(rpc_status != Tfa98xx_I2C_Req_Busy && rpc_status != Tfa98xx_DSP_Not_Running) + break; + } + + if (rpc_status != Tfa98xx_I2C_Req_Done) { + /* DSP RPC call returned an error */ + error = (enum Tfa98xx_Error) (rpc_status + Tfa98xx_Error_RpcBase); + pr_debug("DSP msg status: %d (%s)\n", rpc_status, tfa98xx_get_i2c_status_id_string(rpc_status)); + } + return error; +} + +/** + * write/read raw msg functions: + * the buffer is provided in little endian format, each word occupying 3 bytes, length is in bytes. + * The functions will return immediately and do not not wait for DSP reponse. + * An ID is added to modify the command-ID + */ +enum Tfa98xx_Error tfa_dsp_msg_id(struct tfa_device *tfa, int length, const char *buf, uint8_t cmdid[3]) +{ + enum Tfa98xx_Error error; + int tries, rpc_status = Tfa98xx_I2C_Req_Done; + + /* write the message and notify the DSP */ + error = tfa_dsp_msg_write_id(tfa, length, buf, cmdid); + if( error != Tfa98xx_Error_Ok) + return error; + + /* get the result from the DSP (polling) */ + for(tries=TFA98XX_WAITRESULT_NTRIES; tries>0;tries--) { + error = tfa_dsp_msg_status(tfa, &rpc_status); + if (error == Tfa98xx_Error_Ok && rpc_status == Tfa98xx_I2C_Req_Done) + break; + } + + if (rpc_status != Tfa98xx_I2C_Req_Done) { + /* DSP RPC call returned an error */ + error = (enum Tfa98xx_Error) (rpc_status + Tfa98xx_Error_RpcBase); + pr_debug("DSP msg status: %d (%s)\n", rpc_status, tfa98xx_get_i2c_status_id_string(rpc_status)); + } + return error; +} + +/* read the return code for the RPC call */ +TFA_INTERNAL enum Tfa98xx_Error +tfa98xx_check_rpc_status(struct tfa_device *tfa, int *pRpcStatus) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + /* the value to sent to the * CF_CONTROLS register: cf_req=00000000, + * cf_int=0, cf_aif=0, cf_dmem=XMEM=01, cf_rst_dsp=0 */ + unsigned short cf_ctrl = 0x0002; + /* memory address to be accessed (0: Status, 1: ID, 2: parameters) */ + unsigned short cf_mad = 0x0000; + + if(tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + if (pRpcStatus == NULL) + return Tfa98xx_Error_Bad_Parameter; + + /* 1) write DMEM=XMEM to the DSP XMEM */ + { + /* minimize the number of I2C transactions by making use of the autoincrement in I2C */ + unsigned char buffer[4]; + /* first the data for CF_CONTROLS */ + buffer[0] = (unsigned char)((cf_ctrl >> 8) & 0xFF); + buffer[1] = (unsigned char)(cf_ctrl & 0xFF); + /* write the contents of CF_MAD which is the subaddress following CF_CONTROLS */ + buffer[2] = (unsigned char)((cf_mad >> 8) & 0xFF); + buffer[3] = (unsigned char)(cf_mad & 0xFF); + error = tfa98xx_write_data(tfa, FAM_TFA98XX_CF_CONTROLS, sizeof(buffer), buffer); + } + if (error == Tfa98xx_Error_Ok) { + /* read 1 word (24 bit) from XMEM */ + error = tfa98xx_dsp_read_mem(tfa, 0, 1, pRpcStatus); + } + + return error; +} + +/***************************** xmem only **********************************/ +enum Tfa98xx_Error +tfa98xx_dsp_read_mem(struct tfa_device *tfa, + unsigned int start_offset, int num_words, int *pValues) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + unsigned char *bytes; + int burst_size; /* number of words per burst size */ + const int bytes_per_word = 3; + int dmem; + int num_bytes; + int *p; + + bytes = (unsigned char *)kmem_cache_alloc(tfa->cachep, GFP_KERNEL); + if (bytes == NULL) + return Tfa98xx_Error_Fail; + + /* If no offset is given, assume XMEM! */ + if(((start_offset>>16) & 0xf) > 0 ) + dmem = (start_offset>>16) & 0xf; + else + dmem = Tfa98xx_DMEM_XMEM; + + /* Remove offset from adress */ + start_offset = start_offset & 0xffff; + num_bytes = num_words * bytes_per_word; + p = pValues; + + TFA_SET_BF(tfa, DMEM, (uint16_t)dmem); + error = -TFA_WRITE_REG(tfa, MADD, (unsigned short)start_offset); + if (error != Tfa98xx_Error_Ok) + goto tfa98xx_dsp_read_mem_exit; + + for (; num_bytes > 0;) { + burst_size = ROUND_DOWN(tfa->buffer_size, bytes_per_word); + if (num_bytes < burst_size) + burst_size = num_bytes; + + _ASSERT(burst_size <= sizeof(bytes)); + error = tfa98xx_read_data(tfa, FAM_TFA98XX_CF_MEM, burst_size, bytes); + if (error != Tfa98xx_Error_Ok) + goto tfa98xx_dsp_read_mem_exit; + + tfa98xx_convert_bytes2data(burst_size, bytes, p); + + num_bytes -= burst_size; + p += burst_size / bytes_per_word; + } + +tfa98xx_dsp_read_mem_exit: + kmem_cache_free(tfa->cachep, bytes); + + return error; +} + + +enum Tfa98xx_Error +tfa98xx_dsp_write_mem_word(struct tfa_device *tfa, unsigned short address, int value, int memtype) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + unsigned char bytes[3]; + + TFA_SET_BF(tfa, DMEM, (uint16_t)memtype); + + error = -TFA_WRITE_REG(tfa, MADD, address); + if (error != Tfa98xx_Error_Ok) + return error; + + tfa98xx_convert_data2bytes(1, &value, bytes); + error = tfa98xx_write_data(tfa, FAM_TFA98XX_CF_MEM, 3, bytes); + + return error; +} + +enum Tfa98xx_Error tfa_cont_write_filterbank(struct tfa_device *tfa, nxpTfaFilter_t *filter) +{ + unsigned char biquad_index; + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + + for(biquad_index=0;biquad_index<10;biquad_index++) { + if (filter[biquad_index].enabled ) { + error = tfa_dsp_cmd_id_write(tfa, MODULE_BIQUADFILTERBANK, + biquad_index+1, //start @1 + sizeof(filter[biquad_index].biquad.bytes), + filter[biquad_index].biquad.bytes); + } else { + error = Tfa98xx_DspBiquad_Disable(tfa, biquad_index+1); + } + if (error) return error; + + } + + return error; +} + +enum Tfa98xx_Error +Tfa98xx_DspBiquad_Disable(struct tfa_device *tfa, int biquad_index) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + int coeff_buffer[BIQUAD_COEFF_SIZE]; + unsigned char bytes[3 + BIQUAD_COEFF_SIZE * 3]; + int nr = 0; + + if (biquad_index > TFA98XX_BIQUAD_NUM) + return Tfa98xx_Error_Bad_Parameter; + if (biquad_index < 1) + return Tfa98xx_Error_Bad_Parameter; + + /* make opcode */ + bytes[nr++] = 0; + bytes[nr++] = MODULE_BIQUADFILTERBANK+128; + bytes[nr++] = (unsigned char)biquad_index; + + + /* set in correct order and format for the DSP */ + coeff_buffer[0] = (int) - 8388608; /* -1.0f */ + coeff_buffer[1] = 0; + coeff_buffer[2] = 0; + coeff_buffer[3] = 0; + coeff_buffer[4] = 0; + coeff_buffer[5] = 0; + + /* convert to packed 24 */ + tfa98xx_convert_data2bytes(BIQUAD_COEFF_SIZE, coeff_buffer, &bytes[nr]); + nr += BIQUAD_COEFF_SIZE * 3; + + error = dsp_msg(tfa, nr, (char *)bytes); + + return error; +} + +/* wrapper for dsp_msg that adds opcode */ +enum Tfa98xx_Error tfa_dsp_cmd_id_write(struct tfa_device *tfa, + unsigned char module_id, + unsigned char param_id, int num_bytes, + const unsigned char data[]) +{ + enum Tfa98xx_Error error; + unsigned char *buffer; + int nr = 0; + + buffer = kmem_cache_alloc(tfa->cachep, GFP_KERNEL); + if (buffer == NULL) + return Tfa98xx_Error_Fail; + + buffer[nr++] = tfa->spkr_select; + buffer[nr++] = module_id + 128; + buffer[nr++] = param_id; + + memcpy(&buffer[nr], data, num_bytes); + nr += num_bytes; + + error = dsp_msg(tfa, nr, (char *)buffer); + + kmem_cache_free(tfa->cachep, buffer); + + return error; +} + +/* wrapper for dsp_msg that adds opcode */ +/* this is as the former tfa98xx_dsp_get_param() */ +enum Tfa98xx_Error tfa_dsp_cmd_id_write_read(struct tfa_device *tfa, + unsigned char module_id, + unsigned char param_id, int num_bytes, + unsigned char data[]) +{ + enum Tfa98xx_Error error; + unsigned char buffer[3]; + int nr = 0; + + if (num_bytes <= 0) { + pr_debug("Error: The number of READ bytes is smaller or equal to 0! \n"); + return Tfa98xx_Error_Fail; + } + + if ((tfa->is_probus_device) && (tfa->cnt->ndev == 1) && + (param_id == SB_PARAM_GET_RE25C || + param_id == SB_PARAM_GET_LSMODEL || + param_id == SB_PARAM_GET_ALGO_PARAMS)) { + /* Modifying the ID for GetRe25C */ + buffer[nr++] = 4; + } else { + buffer[nr++] = tfa->spkr_select; + } + buffer[nr++] = module_id + 128; + buffer[nr++] = param_id; + + error = dsp_msg(tfa, nr, (char *)buffer); + if (error != Tfa98xx_Error_Ok) + return error; + + /* read the data from the dsp */ + error = dsp_msg_read(tfa, num_bytes, data); + return error; +} + +/* wrapper for dsp_msg that adds opcode and 3 bytes required for coefs */ +enum Tfa98xx_Error tfa_dsp_cmd_id_coefs(struct tfa_device *tfa, + unsigned char module_id, + unsigned char param_id, int num_bytes, + unsigned char data[]) +{ + enum Tfa98xx_Error error; + unsigned char buffer[2*3]; + int nr = 0; + + buffer[nr++] = tfa->spkr_select; + buffer[nr++] = module_id + 128; + buffer[nr++] = param_id; + + buffer[nr++] = 0; + buffer[nr++] = 0; + buffer[nr++] = 0; + + error = dsp_msg(tfa, nr, (char *)buffer); + if (error != Tfa98xx_Error_Ok) + return error; + + /* read the data from the dsp */ + error = dsp_msg_read(tfa, num_bytes, data); + + return error; +} + +/* wrapper for dsp_msg that adds opcode and 3 bytes required for MBDrcDynamics */ +enum Tfa98xx_Error tfa_dsp_cmd_id_MBDrc_dynamics(struct tfa_device *tfa, + unsigned char module_id, + unsigned char param_id, int index_subband, + int num_bytes, unsigned char data[]) +{ + enum Tfa98xx_Error error; + unsigned char buffer[2 * 3]; + int nr = 0; + + buffer[nr++] = tfa->spkr_select; + buffer[nr++] = module_id + 128; + buffer[nr++] = param_id; + + buffer[nr++] = 0; + buffer[nr++] = 0; + buffer[nr++] = (unsigned char)index_subband; + + error = dsp_msg(tfa, nr, (char *)buffer); + if(error != Tfa98xx_Error_Ok) + return error; + + /* read the data from the dsp */ + error = dsp_msg_read(tfa, num_bytes, data); + + return error; +} + +enum Tfa98xx_Error +tfa98xx_dsp_write_preset(struct tfa_device *tfa, int length, + const unsigned char *p_preset_bytes) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + if (p_preset_bytes != NULL) { + /* by design: keep the data opaque and no + * interpreting/calculation */ + error = tfa_dsp_cmd_id_write(tfa, MODULE_SPEAKERBOOST, + SB_PARAM_SET_PRESET, length, + p_preset_bytes); + } else { + error = Tfa98xx_Error_Bad_Parameter; + } + return error; +} + +/* + * get features from MTP + */ +enum Tfa98xx_Error +tfa98xx_dsp_get_hw_feature_bits(struct tfa_device *tfa, int *features) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + uint32_t value; + uint16_t mtpbf; + + /* return the cache data if it's valid */ + if (tfa->hw_feature_bits != -1) { + *features = tfa->hw_feature_bits; + } else { + /* for tfa1 check if we have clock */ + if (tfa->tfa_family == 1) { + int status; + tfa98xx_dsp_system_stable(tfa, &status); + if (!status) { + get_hw_features_from_cnt(tfa, features); + /* skip reading MTP: */ + return (*features == -1) ? Tfa98xx_Error_Fail : Tfa98xx_Error_Ok; + } + mtpbf=0x850f; /* MTP5 for tfa1,16 bits */ + } else + mtpbf=0xf907; /* MTP9 for tfa2, 8 bits */ + value = tfa_read_reg(tfa, mtpbf) & 0xffff; + *features = tfa->hw_feature_bits = value; + } + + return error; +} + +enum Tfa98xx_Error +tfa98xx_dsp_get_sw_feature_bits(struct tfa_device *tfa, int features[2]) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + const int byte_size = 2 * 3; + unsigned char bytes[2 * 3]; + + /* return the cache data if it's valid */ + if (tfa->sw_feature_bits[0] != -1) { + features[0] = tfa->sw_feature_bits[0]; + features[1] = tfa->sw_feature_bits[1]; + } else { + /* for tfa1 check if we have clock */ + if (tfa->tfa_family == 1) { + int status; + tfa98xx_dsp_system_stable(tfa, &status); + if (!status) { + get_sw_features_from_cnt(tfa, features); + /* skip reading MTP: */ + return (features[0] == -1) ? Tfa98xx_Error_Fail : Tfa98xx_Error_Ok; + } + } + error = tfa_dsp_cmd_id_write_read(tfa, MODULE_FRAMEWORK, + FW_PAR_ID_GET_FEATURE_INFO, byte_size, bytes); + + if (error != Tfa98xx_Error_Ok) { + /* old ROM code may respond with Tfa98xx_Error_RpcParamId */ + return error; + } + + tfa98xx_convert_bytes2data(byte_size, bytes, features); + } + return error; +} + +enum Tfa98xx_Error tfa98xx_dsp_get_state_info(struct tfa_device *tfa, unsigned char bytes[], unsigned int *statesize) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + int bSupportFramework = 0; + unsigned int stateSize = 9; + + err = tfa98xx_dsp_support_framework(tfa, &bSupportFramework); + if (err == Tfa98xx_Error_Ok) { + if (bSupportFramework) { + err = tfa_dsp_cmd_id_write_read(tfa, MODULE_FRAMEWORK, + FW_PARAM_GET_STATE, 3 * stateSize, bytes); + } else { + /* old ROM code, ask SpeakerBoost and only do first portion */ + stateSize = 8; + err = tfa_dsp_cmd_id_write_read(tfa, MODULE_SPEAKERBOOST, + SB_PARAM_GET_STATE, 3 * stateSize, bytes); + } + } + + *statesize = stateSize; + + return err; +} + +enum Tfa98xx_Error tfa98xx_dsp_support_drc(struct tfa_device *tfa, int *pbSupportDrc) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + + *pbSupportDrc = 0; + + if(tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + if (tfa->supportDrc != supportNotSet) { + *pbSupportDrc = (tfa->supportDrc == supportYes); + } else { + int featureBits[2]; + + error = tfa98xx_dsp_get_sw_feature_bits(tfa, featureBits); + if (error == Tfa98xx_Error_Ok) { + /* easy case: new API available */ + /* bit=0 means DRC enabled */ + *pbSupportDrc = (featureBits[0] & FEATURE1_DRC) == 0; + } else if (error == Tfa98xx_Error_RpcParamId) { + /* older ROM code, doesn't support it */ + *pbSupportDrc = 0; + error = Tfa98xx_Error_Ok; + } + /* else some other error, return transparently */ + /* pbSupportDrc only changed when error == Tfa98xx_Error_Ok */ + + if (error == Tfa98xx_Error_Ok) { + tfa->supportDrc = *pbSupportDrc ? supportYes : supportNo; + } + } + return error; +} + +enum Tfa98xx_Error +tfa98xx_dsp_support_framework(struct tfa_device *tfa, int *pbSupportFramework) +{ + int featureBits[2] = { 0, 0 }; + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + + _ASSERT(pbSupportFramework != 0); + + if(tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + + if (tfa->supportFramework != supportNotSet) { + if(tfa->supportFramework == supportNo) + *pbSupportFramework = 0; + else + *pbSupportFramework = 1; + } else { + error = tfa98xx_dsp_get_sw_feature_bits(tfa, featureBits); + if (error == Tfa98xx_Error_Ok) { + *pbSupportFramework = 1; + tfa->supportFramework = supportYes; + } else { + *pbSupportFramework = 0; + tfa->supportFramework = supportNo; + error = Tfa98xx_Error_Ok; + } + } + + /* *pbSupportFramework only changed when error == Tfa98xx_Error_Ok */ + return error; +} + +enum Tfa98xx_Error +tfa98xx_dsp_write_speaker_parameters(struct tfa_device *tfa, + int length, const unsigned char *p_speaker_bytes) +{ + enum Tfa98xx_Error error; + int bSupportDrc; + + if (p_speaker_bytes != NULL) { + /* by design: keep the data opaque and no + * interpreting/calculation */ + /* Use long WaitResult retry count */ + error = tfa_dsp_cmd_id_write( + tfa, + MODULE_SPEAKERBOOST, + SB_PARAM_SET_LSMODEL, length, + p_speaker_bytes); + } else { + error = Tfa98xx_Error_Bad_Parameter; + } + + if (error != Tfa98xx_Error_Ok) + return error; + + error = tfa98xx_dsp_support_drc(tfa, &bSupportDrc); + if (error != Tfa98xx_Error_Ok) + return error; + + if (bSupportDrc) { + /* Need to set AgcGainInsert back to PRE, + * as the SetConfig forces it to POST */ + uint8_t bytes[3] = {0, 0, 0}; + + error = tfa_dsp_cmd_id_write(tfa, + MODULE_SPEAKERBOOST, + SB_PARAM_SET_AGCINS, + 3, + bytes); + } + + return error; +} + +enum Tfa98xx_Error +tfa98xx_dsp_write_config(struct tfa_device *tfa, int length, + const unsigned char *p_config_bytes) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + int bSupportDrc; + + error = tfa_dsp_cmd_id_write(tfa, + MODULE_SPEAKERBOOST, + SB_PARAM_SET_CONFIG, length, + p_config_bytes); + if (error != Tfa98xx_Error_Ok) + return error; + + error = tfa98xx_dsp_support_drc(tfa, &bSupportDrc); + if (error != Tfa98xx_Error_Ok) + return error; + + if (bSupportDrc) { + /* Need to set AgcGainInsert back to PRE, + * as the SetConfig forces it to POST */ + uint8_t bytes[3] = {0, 0, 0}; + + error = tfa_dsp_cmd_id_write(tfa, + MODULE_SPEAKERBOOST, + SB_PARAM_SET_AGCINS, + 3, + bytes); + } + + return error; +} + +/* load all the parameters for the DRC settings from a file */ +enum Tfa98xx_Error tfa98xx_dsp_write_drc(struct tfa_device *tfa, + int length, const unsigned char *p_drc_bytes) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + if (p_drc_bytes != NULL) { + error = tfa_dsp_cmd_id_write(tfa, + MODULE_SPEAKERBOOST, + SB_PARAM_SET_DRC, length, + p_drc_bytes); + + } else { + error = Tfa98xx_Error_Bad_Parameter; + } + return error; +} + +enum Tfa98xx_Error tfa98xx_powerdown(struct tfa_device *tfa, int powerdown) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + + if (tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + + error = TFA_SET_BF(tfa, PWDN, (uint16_t)powerdown); + + if (powerdown) { + /* Workaround for ticket PLMA5337 */ + if (tfa->tfa_family == 2) { + TFA_SET_BF_VOLATILE(tfa, AMPE, 0); + } + } + + return error; +} + +enum Tfa98xx_Error +tfa98xx_select_mode(struct tfa_device *tfa, enum Tfa98xx_Mode mode) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + + if(tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + + if (error == Tfa98xx_Error_Ok) { + switch (mode) { + + default: + error = Tfa98xx_Error_Bad_Parameter; + } + } + + return error; +} + +int tfa_set_bf(struct tfa_device *tfa, const uint16_t bf, const uint16_t value) +{ + enum Tfa98xx_Error err; + uint16_t regvalue, msk, oldvalue; + + /* + * bitfield enum: + * - 0..3 : len + * - 4..7 : pos + * - 8..15 : address + */ + uint8_t len = bf & 0x0f; + uint8_t pos = (bf >> 4) & 0x0f; + uint8_t address = (bf >> 8) & 0xff; + + err = reg_read(tfa, address, ®value); + if (err) { + pr_err("Error getting bf :%d \n", -err); + return -err; + } + + oldvalue = regvalue; + msk = ((1<<(len+1))-1)<> 4) & 0x0f; + uint8_t address = (bf >> 8) & 0xff; + + err = reg_read(tfa, address, ®value); + if (err) { + pr_err("Error getting bf :%d \n", -err); + return -err; + } + + msk = ((1<<(len+1))-1)<> 4) & 0x0f; + uint8_t address = (bf >> 8) & 0xff; + + err = reg_read(tfa, address, ®value); + if (err) { + pr_err("Error getting bf :%d \n", -err); + return -err; + } + + msk = ((1<<(len+1))-1)<>pos; + + return value; +} + +int tfa_set_bf_value(const uint16_t bf, const uint16_t bf_value, uint16_t *p_reg_value) +{ + uint16_t regvalue, msk; + + /* + * bitfield enum: + * - 0..3 : len + * - 4..7 : pos + * - 8..15 : address + */ + uint8_t len = bf & 0x0f; + uint8_t pos = (bf >> 4) & 0x0f; + + regvalue = *p_reg_value; + + msk = ((1<<(len+1))-1)<> 4) & 0x0f; + + msk = ((1<<(len+1))-1)<> pos; + + return value; +} + + +int tfa_write_reg(struct tfa_device *tfa, const uint16_t bf, const uint16_t reg_value) +{ + enum Tfa98xx_Error err; + + /* bitfield enum - 8..15 : address */ + uint8_t address = (bf >> 8) & 0xff; + + err = reg_write(tfa, address, reg_value); + if (err) + return -err; + + return 0; +} + +int tfa_read_reg(struct tfa_device *tfa, const uint16_t bf) +{ + enum Tfa98xx_Error err; + uint16_t regvalue; + + /* bitfield enum - 8..15 : address */ + uint8_t address = (bf >> 8) & 0xff; + + err = reg_read(tfa, address, ®value); + if (err) + return -err; + + return regvalue; +} + +/* + * powerup the coolflux subsystem and wait for it + */ +enum Tfa98xx_Error tfa_cf_powerup(struct tfa_device *tfa) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + int tries, status; + + /* power on the sub system */ + TFA_SET_BF_VOLATILE(tfa, PWDN, 0); + + // wait until everything is stable, in case clock has been off + if (tfa->verbose) + pr_info("Waiting for DSP system stable...\n"); + for ( tries=CFSTABLE_TRIES; tries > 0; tries-- ) { + err = tfa98xx_dsp_system_stable(tfa, &status); + _ASSERT(err == Tfa98xx_Error_Ok); + if ( status ) + break; + else + msleep_interruptible(10); /* wait 10ms to avoid busload */ + } + if (tries==0) {// timedout + pr_err("DSP subsystem start timed out\n"); + return Tfa98xx_Error_StateTimedOut; + } + + return err; +} + +/* + * Enable/Disable the I2S output for TFA1 devices + * without TDM interface + */ +static enum Tfa98xx_Error tfa98xx_aec_output(struct tfa_device *tfa, int enable) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + + if ((tfa->daimap & Tfa98xx_DAI_TDM) == Tfa98xx_DAI_TDM) + return err; + + if (tfa->tfa_family == 1) + err = -tfa_set_bf(tfa, TFA1_BF_I2SDOE, (enable!=0)); + else { + pr_err("I2SDOE on unsupported family\n"); + err = Tfa98xx_Error_Not_Supported; + } + + return err; +} + +/* + * Print the current state of the hardware manager + * Device manager status information, man_state from TFA9888_N1B_I2C_regmap_V12 + */ +enum Tfa98xx_Error show_current_state(struct tfa_device *tfa) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + int manstate = -1; + + if (tfa->tfa_family == 2 && tfa->verbose) { + manstate = TFA_GET_BF(tfa, MANSTATE); + if (manstate < 0) + return -manstate; + + pr_debug("Current HW manager state: "); + + switch(manstate) { + case 0: pr_debug("power_down_state \n"); + break; + case 1: pr_debug("wait_for_source_settings_state \n"); + break; + case 2: pr_debug("connnect_pll_input_state \n"); + break; + case 3: pr_debug("disconnect_pll_input_state \n"); + break; + case 4: pr_debug("enable_pll_state \n"); + break; + case 5: pr_debug("enable_cgu_state \n"); + break; + case 6: pr_debug("init_cf_state \n"); + break; + case 7: pr_debug("enable_amplifier_state \n"); + break; + case 8: pr_debug("alarm_state \n"); + break; + case 9: pr_debug("operating_state \n"); + break; + case 10: pr_debug("mute_audio_state \n"); + break; + case 11: pr_debug("disable_cgu_pll_state \n"); + break; + default: + pr_debug("Unable to find current state \n"); + break; + } + } + + return err; +} + +/* + * start the speakerboost algorithm + * this implies a full system startup when the system was not already started + * + */ +enum Tfa98xx_Error tfaRunSpeakerBoost(struct tfa_device *tfa, int force, int profile) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + int value; + + if (force) { + err= tfaRunColdStartup(tfa, profile); + if ( err ) return err; + } + + /* Returns 1 when device is "cold" and 0 when device is warm */ + value = tfa_is_cold(tfa); + + pr_debug("Startup of device [%s] is a %sstart\n", tfaContDeviceName(tfa->cnt, tfa->dev_idx), value ? "cold" : "warm"); + + /* cold start and not tap profile */ + if (value) { + /* Run startup and write all files */ + err = tfaRunSpeakerStartup(tfa, force, profile); + if ( err ) return err; + + /* Save the current profile and set the vstep to 0 */ + /* This needs to be overwriten even in CF bypass */ + tfa_dev_set_swprof(tfa, (unsigned short)profile); + tfa_dev_set_swvstep(tfa, 0); + + /* Synchonize I/V delay on 96/97 at cold start */ + if ((tfa->tfa_family == 1) && (tfa->daimap == Tfa98xx_DAI_TDM)) + tfa->sync_iv_delay = 1; + } + + return err; +} + +enum Tfa98xx_Error tfaRunSpeakerStartup(struct tfa_device *tfa, int force, int profile) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + + if ( !force ) { // in case of force CF already runnning + err = tfaRunStartup(tfa, profile); + PRINT_ASSERT(err); + if ( err ) + return err; + + /* Startup with CF in bypass then return here */ + if (tfa_cf_enabled(tfa) == 0) + return err; + + /* respond to external DSP: -1:none, 0:no_dsp, 1:cold, 2:warm */ + if(tfa->ext_dsp == -1) { + err = tfaRunStartDSP(tfa); + if ( err ) + return err; + } + } + + /* Set auto_copy_mtp_to_iic (bit 5 of A3) to 1 */ + tfa98xx_auto_copy_mtp_to_iic(tfa); + + /* write all the files from the device list */ + err = tfaContWriteFiles(tfa); + if (err) { + pr_debug("[%s] tfaContWriteFiles error = %d \n", __FUNCTION__, err); + return err; + } + + /* write all the files from the profile list (use volumstep 0) */ + err = tfaContWriteFilesProf(tfa, profile, 0); + if (err) { + pr_debug("[%s] tfaContWriteFilesProf error = %d \n", __FUNCTION__, err); + return err; + } + + return err; +} + +/* + * Run calibration + */ +enum Tfa98xx_Error tfaRunSpeakerCalibration(struct tfa_device *tfa) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + int calibrateDone; + + /* return if there is no audio running */ + if ((tfa->tfa_family == 2) && TFA_GET_BF(tfa, NOCLK)) + return Tfa98xx_Error_NoClock; + + /* When MTPOTC is set (cal=once) unlock key2 */ + if (TFA_GET_BF(tfa, MTPOTC) == 1) { + tfa98xx_key2(tfa, 0); + } + + /* await calibration, this should return ok */ + err = tfaRunWaitCalibration(tfa, &calibrateDone); + if (err == Tfa98xx_Error_Ok) { + err = tfa_dsp_get_calibration_impedance(tfa); + PRINT_ASSERT(err); + } + + /* When MTPOTC is set (cal=once) re-lock key2 */ + if (TFA_GET_BF(tfa, MTPOTC) == 1) { + tfa98xx_key2(tfa, 1); + } + + return err; +} + +enum Tfa98xx_Error tfaRunColdboot(struct tfa_device *tfa, int state) +{ +#define CF_CONTROL 0x8100 + enum Tfa98xx_Error err=Tfa98xx_Error_Ok; + int tries = 10; + + /* repeat set ACS bit until set as requested */ + while ( state != TFA_GET_BF(tfa, ACS)) { + /* set colstarted in CF_CONTROL to force ACS */ + err = mem_write(tfa, CF_CONTROL, state, Tfa98xx_DMEM_IOMEM); + PRINT_ASSERT(err); + + if (tries-- == 0) { + pr_debug("coldboot (ACS) did not %s\n", state ? "set":"clear"); + return Tfa98xx_Error_Other; + } + } + + return err; +} + + + +/* + * load the patch if any + * else tell no loaded + */ +static enum Tfa98xx_Error tfa_run_load_patch(struct tfa_device *tfa) +{ + return tfaContWritePatch(tfa); +} + +/* + * this will load the patch witch will implicitly start the DSP + * if no patch is available the DPS is started immediately + */ +enum Tfa98xx_Error tfaRunStartDSP(struct tfa_device *tfa) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + + err = tfa_run_load_patch(tfa); + if (err) { /* patch load is fatal so return immediately*/ + return err; + } + + /* Clear count_boot, should be reset to 0 before the DSP reset is released */ + err = mem_write(tfa, 512, 0, Tfa98xx_DMEM_XMEM); + PRINT_ASSERT(err); + + /* Reset DSP once for sure after initializing */ + if ( err == Tfa98xx_Error_Ok) { + err = tfa98xx_dsp_reset(tfa, 0); + PRINT_ASSERT(err); + } + + /* Sample rate is needed to set the correct tables */ + err = tfa98xx_dsp_write_tables(tfa, TFA_GET_BF(tfa, AUDFS)); + PRINT_ASSERT(err); + + return err; +} + +/* + * start the clocks and wait until the AMP is switching + * on return the DSP sub system will be ready for loading + */ +enum Tfa98xx_Error tfaRunStartup(struct tfa_device *tfa, int profile) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + nxpTfaDeviceList_t *dev = tfaContDevice(tfa->cnt, tfa->dev_idx); + int i, noinit=0; + + if(dev == NULL) + return Tfa98xx_Error_Fail; + + if(dev->bus) /* no i2c device, do nothing */ + return Tfa98xx_Error_Ok; + + /* process the device list to see if the user implemented the noinit */ + for(i=0;ilength;i++) { + if (dev->list[i].type == dscNoInit) { + noinit=1; + break; + } + } + + if(!noinit) { + /* load the optimal TFA98XX in HW settings */ + err = tfa98xx_init(tfa); + PRINT_ASSERT(err); + } else { + pr_debug("\nWarning: No init keyword found in the cnt file. Init is skipped! \n"); + } + + /* I2S settings to define the audio input properties + * these must be set before the subsys is up */ + // this will run the list until a non-register item is encountered + err = tfaContWriteRegsDev(tfa); // write device register settings + PRINT_ASSERT(err); + // also write register the settings from the default profile + // NOTE we may still have ACS=1 so we can switch sample rate here + err = tfaContWriteRegsProf(tfa, profile); + PRINT_ASSERT(err); + + /* Factory trimming for the Boost converter */ + tfa98xx_factory_trimmer(tfa); + + /* Go to the initCF state */ + tfa_dev_set_state(tfa, TFA_STATE_INIT_CF); + + err = show_current_state(tfa); + + return err; +} + +/* + * run the startup/init sequence and set ACS bit + */ +enum Tfa98xx_Error tfaRunColdStartup(struct tfa_device *tfa, int profile) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + + err = tfaRunStartup(tfa, profile); + PRINT_ASSERT(err); + if (err) + return err; + + if(!tfa->is_probus_device) { + /* force cold boot */ + err = tfaRunColdboot(tfa, 1); // set ACS + PRINT_ASSERT(err); + if (err) + return err; + } + + /* start */ + err = tfaRunStartDSP(tfa); + PRINT_ASSERT(err); + + return err; +} + +/* + * + */ +enum Tfa98xx_Error tfaRunMute(struct tfa_device *tfa) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + int status; + int tries = 0; + + /* signal the TFA98XX to mute */ + if (tfa->tfa_family == 1) { + err = tfa98xx_set_mute(tfa, Tfa98xx_Mute_Amplifier); + + if(err == Tfa98xx_Error_Ok) { + /* now wait for the amplifier to turn off */ + do { + status = TFA_GET_BF(tfa, SWS); + if (status != 0) + msleep_interruptible(10); /* wait 10ms to avoid busload */ + else + break; + tries++; + } while (tries < AMPOFFWAIT_TRIES); + + + if (tfa->verbose) + pr_debug("-------------------- muted --------------------\n"); + + /*The amplifier is always switching*/ + if (tries == AMPOFFWAIT_TRIES) + return Tfa98xx_Error_Other; + } + } + + return err; +} +/* + * + */ +enum Tfa98xx_Error tfaRunUnmute(struct tfa_device *tfa) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + + /* signal the TFA98XX to mute */ + err = tfa98xx_set_mute(tfa, Tfa98xx_Mute_Off); + + if (tfa->verbose) + pr_debug("-------------------unmuted ------------------\n"); + + return err; +} + +static void individual_calibration_results(struct tfa_device *tfa) +{ + int value_P, value_S; + + /* Read the calibration result in xmem (529=primary channel) (530=secondary channel) */ + mem_read(tfa, 529, 1, &value_P); + mem_read(tfa, 530, 1, &value_S); + + if(value_P != 1 && value_S != 1) + pr_debug("Calibration failed on both channels! \n"); + else if(value_P != 1) { + pr_debug("Calibration failed on Primary (Left) channel! \n"); + TFA_SET_BF_VOLATILE(tfa, SSLEFTE, 0); /* Disable the sound for the left speaker */ + } + else if(value_S != 1) { + pr_debug("Calibration failed on Secondary (Right) channel! \n"); + TFA_SET_BF_VOLATILE(tfa, SSRIGHTE, 0); /* Disable the sound for the right speaker */ + } + + TFA_SET_BF_VOLATILE(tfa, AMPINSEL, 0); /* Set amplifier input to TDM */ + TFA_SET_BF_VOLATILE(tfa, SBSL, 1); +} + +/* + * wait for calibrateDone + */ +enum Tfa98xx_Error tfaRunWaitCalibration(struct tfa_device *tfa, int *calibrateDone) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + int tries = 0, mtp_busy = 1, tries_mtp_busy = 0; + + *calibrateDone = 0; + + /* in case of calibrate once wait for MTPEX */ + if (TFA_GET_BF(tfa, MTPOTC)) { + // Check if MTP_busy is clear! + while (tries_mtp_busy < MTPBWAIT_TRIES) + { + mtp_busy = tfa_dev_get_mtpb(tfa); + if (mtp_busy == 1) + msleep_interruptible(10); /* wait 10ms to avoid busload */ + else + break; + tries_mtp_busy++; + } + + if (tries_mtp_busy < MTPBWAIT_TRIES) { + /* Because of the msleep TFA98XX_API_WAITRESULT_NTRIES is way to long! + * Setting this to 25 will take it atleast 25*50ms = 1.25 sec + */ + while ((*calibrateDone == 0) && (tries < MTPEX_WAIT_NTRIES)) { + *calibrateDone = TFA_GET_BF(tfa, MTPEX); + if (*calibrateDone == 1) + break; + msleep_interruptible(50); /* wait 50ms to avoid busload */ + tries++; + } + + if (tries >= MTPEX_WAIT_NTRIES) { + tries = TFA98XX_API_WAITRESULT_NTRIES; + } + } else { + pr_err("MTP bussy after %d tries\n", MTPBWAIT_TRIES); + } + } + + /* poll xmem for calibrate always + * calibrateDone = 0 means "calibrating", + * calibrateDone = -1 (or 0xFFFFFF) means "fails" + * calibrateDone = 1 means calibration done + */ + while ((*calibrateDone != 1) && (triestfa_family == 2) && (TFA_GET_BF(tfa, REFCKSEL) == 1)) { + pr_err("Unable to calibrate the device with the internal clock! \n"); + } + } + + /* Check which speaker calibration failed. Only for 88C */ + if ((err != Tfa98xx_Error_Ok) && ((tfa->rev & 0x0FFF) == 0xc88)) { + individual_calibration_results(tfa); + } + + return err; +} + +/* + * tfa_dev_start will only do the basics: Going from powerdown to operating or a profile switch. + * for calibrating or akoustic shock handling use the tfa98xxCalibration function. + */ +enum tfa_error tfa_dev_start(struct tfa_device *tfa, int next_profile, int vstep) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + int active_profile = -1; + + pr_info("tfa_dev_start enter\n"); + + /* Get currentprofile */ + active_profile = tfa_dev_get_swprof(tfa); + if (active_profile == 0xff) + active_profile = -1; + + /* TfaRun_SpeakerBoost implies un-mute */ + pr_debug("Active_profile:%s, next_profile:%s\n", + tfaContProfileName(tfa->cnt, tfa->dev_idx, active_profile), + tfaContProfileName(tfa->cnt, tfa->dev_idx, next_profile)); + + err = show_current_state(tfa); + + if ( tfa->tfa_family == 1 ) { /* TODO move this to ini file */ + /* Enable I2S output on TFA1 devices without TDM */ + err = tfa98xx_aec_output(tfa, 1); + if ( err != Tfa98xx_Error_Ok) + goto error_exit; + } + + if ( tfa->bus != 0 ) { /* non i2c */ +#ifndef __KERNEL__ + tfadsp_fw_start(tfa, next_profile, vstep); +#endif /* __KERNEL__ */ + } else { + /* Check if we need coldstart or ACS is set */ + err = tfaRunSpeakerBoost(tfa, 0, next_profile); + if ( err != Tfa98xx_Error_Ok) + goto error_exit; + + /* Make sure internal oscillator is running for DSP devices (non-dsp and max1 this is no-op) */ + tfa98xx_set_osc_powerdown(tfa, 0); + + /* Go to the Operating state */ + tfa_dev_set_state(tfa, TFA_STATE_OPERATING); + } + active_profile = tfa_dev_get_swprof(tfa); + + /* Profile switching */ + if ((next_profile != active_profile && active_profile >= 0)) { + err = tfaContWriteProfile(tfa, next_profile, vstep); + if (err!=Tfa98xx_Error_Ok) + goto error_exit; + } + + /* If the profile contains the .standby suffix go to powerdown + * else we should be in operating state + */ + if(strstr(tfaContProfileName(tfa->cnt, tfa->dev_idx, next_profile), ".standby") != NULL) { + tfa_dev_set_swprof(tfa, (unsigned short)next_profile); + tfa_dev_set_swvstep(tfa, (unsigned short)tfa->vstep); + goto error_exit; + } + + err = show_current_state(tfa); + + tfa->vstep = tfa_dev_get_swvstep(tfa); + if ((TFA_GET_BF(tfa, CFE) != 0) && (vstep != tfa->vstep) && (vstep != -1)) { + err = tfaContWriteFilesVstep(tfa, next_profile, vstep); + if ( err != Tfa98xx_Error_Ok) + goto error_exit; + } + + /* Always search and apply filters after a startup */ + err = tfa_set_filters(tfa, next_profile); + if (err!=Tfa98xx_Error_Ok) + goto error_exit; + + tfa_dev_set_swprof(tfa, (unsigned short)next_profile); + tfa_dev_set_swvstep(tfa, (unsigned short)tfa->vstep); + + /* PLMA5539: Gives information about current setting of powerswitch */ + if (tfa->verbose) { + if (!tfa98xx_powerswitch_is_enabled(tfa)) + pr_info("Device start without powerswitch enabled!\n"); + } + +error_exit: + show_current_state(tfa); + + return err; +} + +enum tfa_error tfa_dev_stop(struct tfa_device *tfa) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + int times = 0, ready; + /* mute */ + tfaRunMute(tfa); + + /* Make sure internal oscillator is not running for DSP devices (non-dsp and max1 this is no-op) */ + tfa98xx_set_osc_powerdown(tfa, 1); + + /* powerdown CF */ + err = tfa98xx_powerdown(tfa, 1 ); + if ( err != Tfa98xx_Error_Ok) + return err; + + /* disable I2S output on TFA1 devices without TDM */ + err = tfa98xx_aec_output(tfa, 0); + + while ((TFA_GET_BF(tfa, MANSTATE) != 0) && (times++ < 20)) { + pr_info("tfa stop wait state machine goto powerdown mode.\n"); + err = tfa98xx_dsp_system_stable(tfa, &ready); + if (err != Tfa98xx_Error_Ok || !ready) { + pr_err("tfa stop: No I2S CLK\n"); + break; + } + msleep_interruptible(5); + } + + if (times < 20) { + pr_debug("tfa stop: already in PowerDown\n"); + } else { + pr_debug("tfa stop: Not in PowerDown\n"); + } + + return (enum tfa_error)err; //liuhaituo modify +} + +/* + * int registers and coldboot dsp + */ +int tfa_reset(struct tfa_device *tfa) +{ + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + + err = -TFA_SET_BF_VOLATILE(tfa, I2CR, 1); + if(err) return err; + + if (tfa->tfa_family == 2) { + /* restore MANSCONF to POR state */ + TFA_SET_BF_VOLATILE(tfa, MANSCONF, 0); + } + + if( !tfa->is_probus_device ) { + if (tfa->tfa_family == 2) { + /* restore MANCOLD to POR state */ + TFA_SET_BF_VOLATILE(tfa, MANCOLD, 1); + } + + /* powerup CF to access CF io */ + tfa98xx_powerdown(tfa, 0 ); + /* for clock */ + err = tfa_cf_powerup(tfa); + PRINT_ASSERT(err); + + /* force cold boot */ + err = tfaRunColdboot(tfa, 1); // set ACS + PRINT_ASSERT(err); + + /* reset all i2C registers to default */ + err = -TFA_SET_BF(tfa, I2CR, 1); + PRINT_ASSERT(err); + } else { + if (tfa->ext_dsp > 0) + tfa98xx_init_dsp(tfa); + } + + return err; +} + +/* + * Write all the bytes specified by num_bytes and data + */ +enum Tfa98xx_Error +tfa98xx_write_data(struct tfa_device *tfa, + unsigned char subaddress, int num_bytes, + const unsigned char data[]) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + /* subaddress followed by data */ + const int bytes2write = num_bytes + 1; + unsigned char *write_data; + + if (num_bytes > TFA2_MAX_PARAM_SIZE) + return Tfa98xx_Error_Bad_Parameter; + + write_data = (unsigned char *)kmem_cache_alloc(tfa->cachep, GFP_KERNEL); + if (write_data == NULL) + return Tfa98xx_Error_Fail; + + write_data[0] = subaddress; + memcpy(&write_data[1], data, num_bytes); + + error = tfa98xx_write_raw(tfa, bytes2write, write_data); + + kmem_cache_free(tfa->cachep, write_data); + return error; +} + +/* + * fill the calibration value as milli ohms in the struct + * + * assume that the device has been calibrated + */ +enum Tfa98xx_Error tfa_dsp_get_calibration_impedance(struct tfa_device *tfa) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + unsigned char bytes[3*2] = {0}; + int nr_bytes, i, data[2], calibrateDone, spkr_count=0, cal_idx=0; + unsigned int scaled_data; + int tries=0; + + error = tfa_supported_speakers(tfa, &spkr_count); + + if (tfa_dev_mtp_get(tfa, TFA_MTP_OTC)) { + pr_debug("Getting calibration values from MTP\n"); + + if((tfa->rev & 0xFF) == 0x88) { + for(i=0; imohm[i] = tfa_dev_mtp_get(tfa, TFA_MTP_RE25_PRIM); + else + tfa->mohm[i] = tfa_dev_mtp_get(tfa, TFA_MTP_RE25_SEC); + } + } else { + tfa->mohm[0] = tfa_dev_mtp_get(tfa, TFA_MTP_RE25); + } + } else { + pr_debug("Getting calibration values from Speakerboost\n"); + + /* Make sure the calibrateDone bit is set before getting the values from speakerboost! + * This does not work for 72 (because the dsp cannot set this bit) + */ + if (!tfa->is_probus_device) { + /* poll xmem for calibrate always + * calibrateDone = 0 means "calibrating", + * calibrateDone = -1 (or 0xFFFFFF) means "fails" + * calibrateDone = 1 means calibration done + */ + calibrateDone = 0; + while ((calibrateDone != 1) && (tries < TFA98XX_API_WAITRESULT_NTRIES)) { + error = mem_read(tfa, TFA_FW_XMEM_CALIBRATION_DONE, 1, &calibrateDone); + if (calibrateDone == 1) + break; + tries++; + } + + if (calibrateDone != 1) { + pr_err("Calibration failed! \n"); + error = Tfa98xx_Error_Bad_Parameter; + } + else if (tries == TFA98XX_API_WAITRESULT_NTRIES) { + pr_debug("Calibration has timedout! \n"); + error = Tfa98xx_Error_StateTimedOut; + } + } + /* SoftDSP interface differs from hw-dsp interfaces */ + if(tfa->is_probus_device && tfa->cnt->ndev > 1) { + spkr_count = tfa->cnt->ndev; + } + + nr_bytes = spkr_count * 3; + error = tfa_dsp_cmd_id_write_read(tfa, MODULE_SPEAKERBOOST, SB_PARAM_GET_RE25C, nr_bytes, bytes); + if (error == Tfa98xx_Error_Ok) { + tfa98xx_convert_bytes2data(nr_bytes, bytes, data); + + for(i=0; iis_probus_device && tfa->dev_idx >= 1) ) { + cal_idx=0; + } + + /* signed data has a limit of 30 Ohm */ + scaled_data = data[i]; + + if(tfa->tfa_family == 2) + tfa->mohm[cal_idx] = (scaled_data*1000)/TFA2_FW_ReZ_SCALE; + else + tfa->mohm[cal_idx] = (scaled_data*1000)/TFA1_FW_ReZ_SCALE; + } + } + } + + return error; +} + +/* start count from 1, 0 is invalid */ +int tfa_dev_get_swprof(struct tfa_device *tfa) +{ + return (tfa->dev_ops.get_swprof)(tfa); +} + +int tfa_dev_set_swprof(struct tfa_device *tfa, unsigned short new_value) +{ + return (tfa->dev_ops.set_swprof)(tfa, new_value+1); +} + +/* same value for all channels + * start count from 1, 0 is invalid */ +int tfa_dev_get_swvstep(struct tfa_device *tfa) +{ + return (tfa->dev_ops.get_swvstep)(tfa); +} + +int tfa_dev_set_swvstep(struct tfa_device *tfa, unsigned short new_value) +{ + return (tfa->dev_ops.set_swvstep)(tfa, new_value + 1); +} + +/* + function overload for MTPB + */ +int tfa_dev_get_mtpb(struct tfa_device *tfa) +{ + return (tfa->dev_ops.get_mtpb)(tfa); +} + +int tfa_is_cold(struct tfa_device *tfa) +{ + int value; + + /* + * check for cold boot status + */ + if (tfa->is_probus_device) { + if (tfa->ext_dsp > 0) { + if (tfa->ext_dsp == 2) + value = 0; // warm + else /* no dsp or cold */ + value = 1; // cold + } else { + value = (TFA_GET_BF(tfa, MANSCONF) == 0); + } + } else { + value = TFA_GET_BF(tfa, ACS); + } + + return value; +} + +int tfa_needs_reset(struct tfa_device *tfa) +{ + int value; + + /* checks if the DSP commands SetAlgoParams and SetMBDrc + * need a DSP reset (now: at coldstart or during calibration) + */ + if (tfa_is_cold(tfa) == 1 || tfa->needs_reset == 1) + value = 1; + else + value = 0; + + return value; +} + +int tfa_cf_enabled(struct tfa_device *tfa) +{ + int value; + + /* For 72 there is no CF */ + if(tfa->is_probus_device) { + value = (tfa->ext_dsp != 0); + } else { + value = TFA_GET_BF(tfa, CFE); + } + + return value; +} + +#define NR_COEFFS 6 +#define NR_BIQUADS 28 +#define BQ_SIZE (3 * NR_COEFFS) +#define DSP_MSG_OVERHEAD 27 + +#pragma pack (push, 1) +struct dsp_msg_all_coeff { + uint8_t select_eq[3]; + uint8_t biquad[NR_BIQUADS][NR_COEFFS][3]; +}; +#pragma pack (pop) + +/* number of biquads for each equalizer */ +static const int eq_biquads[] = { + 10, 10, 2, 2, 2, 2 +}; + +#define NR_EQ (int)(sizeof(eq_biquads) / sizeof(int)) + +enum Tfa98xx_Error dsp_partial_coefficients(struct tfa_device *tfa, uint8_t *prev, uint8_t *next) +{ + uint8_t bq, eq; + int eq_offset; + int new_cost, old_cost; + uint32_t eq_biquad_mask[NR_EQ]; + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; + struct dsp_msg_all_coeff *data1 = (struct dsp_msg_all_coeff *)prev; + struct dsp_msg_all_coeff *data2 = (struct dsp_msg_all_coeff *)next; + + old_cost = DSP_MSG_OVERHEAD + 3 + sizeof(struct dsp_msg_all_coeff); + new_cost = 0; + + eq_offset = 0; + for (eq=0; eqbiquad[eq_offset][0][0]; + uint8_t *eq2 = &data2->biquad[eq_offset][0][0]; + + eq_biquad_mask[eq] = 0; + + if (memcmp(eq1, eq2, BQ_SIZE*eq_biquads[eq]) != 0) { + int nr_bq = 0; + int bq_sz, eq_sz; + + for (bq=0; bq < eq_biquads[eq]; bq++) { + uint8_t *bq1 = &eq1[bq*BQ_SIZE]; + uint8_t *bq2 = &eq2[bq*BQ_SIZE]; + + if (memcmp(bq1, bq2, BQ_SIZE) != 0) { + eq_biquad_mask[eq] |= (1<= eq_sz) { + eq_biquad_mask[eq] = 0xffffffff; + + new_cost += eq_sz; + + } else { + new_cost += bq_sz; + } + } + pr_debug("eq_biquad_mask[%d] = 0x%.8x\n", eq, eq_biquad_mask[eq]); + + eq_offset += eq_biquads[eq]; + } + + pr_debug("cost for writing all coefficients = %d\n", old_cost); + pr_debug("cost for writing changed coefficients = %d\n", new_cost); + + if (new_cost >= old_cost) { + const int buffer_sz = 3 + sizeof(struct dsp_msg_all_coeff); + uint8_t *buffer; + + buffer = kmalloc(buffer_sz, GFP_KERNEL); + if (buffer == NULL) + return Tfa98xx_Error_Fail; + + /* cmd id */ + buffer[0] = 0x00; + buffer[1] = 0x82; + buffer[2] = 0x00; + + /* parameters */ + memcpy(&buffer[3], data2, sizeof(struct dsp_msg_all_coeff)); + + err = dsp_msg(tfa, buffer_sz, (const char *)buffer); + + kfree(buffer); + if (err) + return err; + + } else { + eq_offset = 0; + for (eq=0; eqbiquad[eq_offset][0][0]; + + if (eq_biquad_mask[eq] == 0xffffffff) { + const int msg_sz = 6 + BQ_SIZE * eq_biquads[eq]; + uint8_t *msg; + + msg = kmalloc(msg_sz, GFP_KERNEL); + if (msg == NULL) + return Tfa98xx_Error_Fail; + + /* cmd id */ + msg[0] = 0x00; + msg[1] = 0x82; + msg[2] = 0x00; + + /* select eq and bq */ + msg[3] = 0x00; + msg[4] = eq+1; + msg[5] = 0x00; /* all biquads */ + + /* biquad parameters */ + memcpy(&msg[6], eq2, BQ_SIZE * eq_biquads[eq]); + + err = dsp_msg(tfa, msg_sz, (const char *)msg); + + kfree(msg); + if (err) + return err; + + } else if (eq_biquad_mask[eq] != 0) { + for(bq=0; bq < eq_biquads[eq]; bq++) { + + if (eq_biquad_mask[eq] & (1<cachep, GFP_KERNEL); + if (msg == NULL) + return Tfa98xx_Error_Fail; + + /* cmd id */ + msg[0] = 0x00; + msg[1] = 0x82; + msg[2] = 0x00; + + /* select eq and bq*/ + msg[3] = 0x00; + msg[4] = eq+1; + msg[5] = bq+1; + + /* biquad parameters */ + memcpy(&msg[6], bq2, BQ_SIZE); + + err = dsp_msg(tfa, msg_sz, (const char *)msg); + + kmem_cache_free(tfa->cachep, msg); + if (err) + return err; + } + } + } + eq_offset += eq_biquads[eq]; + } + } + + return err; +} + +/* fill context info */ +int tfa_dev_probe(int slave, struct tfa_device *tfa) +{ + uint16_t rev; + + tfa->slave_address = (unsigned char)slave; + + /* read revid via low level hal, register 3 */ + if (tfa98xx_read_register16(tfa, 3, &rev) != Tfa98xx_Error_Ok) { + PRINT("\nError: Unable to read revid from slave:0x%02x \n", slave); + return -1; + } + + tfa->rev = rev; + tfa->dev_idx = -1; + tfa->state = TFA_STATE_UNKNOWN; + tfa->p_regInfo = NULL; + + tfa_set_query_info(tfa); + + tfa->in_use = 1; + + return 0; +} + +enum tfa_error tfa_dev_set_state(struct tfa_device *tfa, enum tfa_state state) +{ + enum tfa_error err = tfa_error_ok; + int loop = 50, ready = 0; + int count; + + /* Base states */ + /* Do not change the order of setting bits as this is important! */ + switch (state & 0x0f) { + case TFA_STATE_POWERDOWN: /* PLL in powerdown, Algo up */ + break; + case TFA_STATE_INIT_HW: /* load I2C/PLL hardware setting (~wait2srcsettings) */ + break; + case TFA_STATE_INIT_CF: /* coolflux HW access possible (~initcf) */ + /* Start with SBSL=0 to stay in initCF state */ + TFA_SET_BF(tfa, SBSL, 0); + + /* We want to leave Wait4SrcSettings state for max2 */ + if (tfa->tfa_family == 2) + TFA_SET_BF(tfa, MANSCONF, 1); + + /* And finally set PWDN to 0 to leave powerdown state */ + TFA_SET_BF(tfa, PWDN, 0); + + /* Make sure the DSP is running! */ + do { + err = tfa98xx_dsp_system_stable(tfa, &ready); + if (err != tfa_error_ok) + return err; + if (ready) + break; + } while (loop--); + /* Enable FAIM when clock is stable, to avoid MTP corruption */ + err = tfa98xx_faim_protect(tfa, 1); + if (tfa->verbose) { + pr_debug("FAIM enabled (err:%d).\n", err); + } + break; + case TFA_STATE_INIT_FW: /* DSP framework active (~patch loaded) */ + break; + case TFA_STATE_OPERATING: /* Amp and Algo running */ + /* Depending on our previous state we need to set 3 bits */ + TFA_SET_BF(tfa, PWDN, 0); /* Coming from state 0 */ + TFA_SET_BF(tfa, MANSCONF, 1); /* Coming from state 1 */ + TFA_SET_BF(tfa, SBSL, 1); /* Coming from state 6 */ + + /* + * Disable MTP clock to protect memory. + * However in case of calibration wait for DSP! (This should be case only during calibration). + */ + if (TFA_GET_BF(tfa, MTPOTC) == 1) { + count = MTPEX_WAIT_NTRIES * 4; /* Calibration takes a lot of time */ + while ((TFA_GET_BF(tfa, MTPEX) != 1) && count) { + msleep_interruptible(10); + count--; + } + } + err = tfa98xx_faim_protect(tfa, 0); + if (tfa->verbose) { + pr_debug("FAIM disabled (err:%d).\n", err); + } + + /* Synchonize I/V delay on 96/97 at cold start */ + if (tfa->sync_iv_delay) { + if (tfa->verbose) + pr_debug("syncing I/V delay for %x\n", + (tfa->rev & 0xff)); + + /* wait for ACS to be cleared */ + count = 10; + while ((TFA_GET_BF(tfa, ACS) == 1) && + (count-- > 0)) { + msleep_interruptible(1); + } + + tfa98xx_dsp_reset(tfa, 1); + tfa98xx_dsp_reset(tfa, 0); + tfa->sync_iv_delay = 0; + } + break; + case TFA_STATE_FAULT: /* An alarm or error occurred */ + break; + case TFA_STATE_RESET: /* I2C reset and ACS set */ + tfa98xx_init(tfa); + break; + default: + if (state & 0x0f) + return tfa_error_bad_param; + } + + /* state modifiers */ + + if (state & TFA_STATE_MUTE) + tfa98xx_set_mute(tfa, Tfa98xx_Mute_Amplifier); + + if (state & TFA_STATE_UNMUTE) + tfa98xx_set_mute(tfa, Tfa98xx_Mute_Off); + + tfa->state = state; + + return tfa_error_ok; +} + +enum tfa_state tfa_dev_get_state(struct tfa_device *tfa) +{ + int cold = TFA_GET_BF(tfa, ACS); + int manstate; + + /* different per family type */ + if ( tfa->tfa_family == 1 ) { + if ( cold && TFA_GET_BF(tfa, PWDN) ) + tfa->state = TFA_STATE_RESET; + else if ( !cold && TFA_GET_BF(tfa, SWS)) + tfa->state = TFA_STATE_OPERATING; + } else /* family 2 */ { + manstate = TFA_GET_BF(tfa, MANSTATE); + switch(manstate) { + case 0: + tfa->state = cold ? TFA_STATE_RESET : TFA_STATE_POWERDOWN; + break; + case 8: /* if dsp reset if off assume framework is running */ + tfa->state = TFA_GET_BF(tfa, RST) ? TFA_STATE_INIT_CF : TFA_STATE_INIT_FW; + break; + case 9: + tfa->state = TFA_STATE_OPERATING; + break; + default: + break; + } + } + + return tfa->state; +} + +int tfa_dev_mtp_get(struct tfa_device *tfa, enum tfa_mtp item) +{ + int value = 0; + + switch (item) { + case TFA_MTP_OTC: + value = TFA_GET_BF(tfa, MTPOTC); + break; + case TFA_MTP_EX: + value = TFA_GET_BF(tfa, MTPEX); + break; + case TFA_MTP_RE25: + case TFA_MTP_RE25_PRIM: + if(tfa->tfa_family == 2) { + if((tfa->rev & 0xFF) == 0x88) + value = TFA_GET_BF(tfa, R25CL); + else if((tfa->rev & 0xFF) == 0x13) + value = tfa_get_bf(tfa, TFA9912_BF_R25C); + else + value = TFA_GET_BF(tfa, R25C); + } else { + reg_read(tfa, 0x83, (unsigned short*)&value); + } + break; + case TFA_MTP_RE25_SEC: + if((tfa->rev & 0xFF) == 0x88) { + value = TFA_GET_BF(tfa, R25CR); + } else { + pr_debug("Error: Current device has no secondary Re25 channel \n"); + } + break; + case TFA_MTP_LOCK: + break; + } + + return value; +} + +enum tfa_error tfa_dev_mtp_set(struct tfa_device *tfa, enum tfa_mtp item, int value) +{ + enum tfa_error err = tfa_error_ok; + + switch (item) { + case TFA_MTP_OTC: + err = tfa98xx_set_mtp(tfa, (uint16_t)value, TFA98XX_KEY2_PROTECTED_MTP0_MTPOTC_MSK); + break; + case TFA_MTP_EX: + err = tfa98xx_set_mtp(tfa, (uint16_t)value, TFA98XX_KEY2_PROTECTED_MTP0_MTPEX_MSK); + break; + case TFA_MTP_RE25: + case TFA_MTP_RE25_PRIM: + if(tfa->tfa_family == 2) { + if((tfa->rev & 0xFF) == 0x88) + TFA_SET_BF(tfa, R25CL, (uint16_t)value); + else + TFA_SET_BF(tfa, R25C, (uint16_t)value); + } + break; + case TFA_MTP_RE25_SEC: + if((tfa->rev & 0xFF) == 0x88) { + TFA_SET_BF(tfa, R25CR, (uint16_t)value); + } else { + pr_debug("Error: Current device has no secondary Re25 channel \n"); + err = tfa_error_bad_param; + } + break; + case TFA_MTP_LOCK: + break; + } + + return err; +} + +int tfa_get_pga_gain(struct tfa_device *tfa) +{ + return TFA_GET_BF(tfa, SAAMGAIN); +} + +int tfa_set_pga_gain(struct tfa_device *tfa, uint16_t value) +{ + + return TFA_SET_BF(tfa, SAAMGAIN, value); +} + +int tfa_get_noclk(struct tfa_device *tfa) +{ + return TFA_GET_BF(tfa, NOCLK); +} + + +enum Tfa98xx_Error tfa_status(struct tfa_device *tfa) +{ + int value; + uint16_t val; + + /* + * check IC status bits: cold start + * and DSP watch dog bit to re init + */ + value = TFA_READ_REG(tfa, VDDS); /* STATUSREG */ + if (value < 0) + return -value; + val = (uint16_t)value; + + /* pr_debug("SYS_STATUS0: 0x%04x\n", val); */ + if (TFA_GET_BF_VALUE(tfa, ACS, val) || + TFA_GET_BF_VALUE(tfa, WDS, val)) { + + if (TFA_GET_BF_VALUE(tfa, ACS, val)) + pr_err("ERROR: ACS\n"); + if (TFA_GET_BF_VALUE(tfa, WDS, val)) + pr_err("ERROR: WDS\n"); + + return Tfa98xx_Error_DSP_not_running; + } + + if (TFA_GET_BF_VALUE(tfa, SPKS, val)) + pr_err("ERROR: SPKS\n"); + if (!TFA_GET_BF_VALUE(tfa, SWS, val)) + pr_err("ERROR: SWS\n"); + + /* Check secondary errors */ + if (!TFA_GET_BF_VALUE(tfa, CLKS, val) || + !TFA_GET_BF_VALUE(tfa, UVDS, val) || + !TFA_GET_BF_VALUE(tfa, OVDS, val) || + !TFA_GET_BF_VALUE(tfa, OTDS, val) || + !TFA_GET_BF_VALUE(tfa, PLLS, val) || + (!(tfa->daimap & Tfa98xx_DAI_TDM) && + !TFA_GET_BF_VALUE(tfa, VDDS, val)) ) + pr_err("Misc errors detected: STATUS_FLAG0 = 0x%x\n", val); + + if ((tfa->daimap & Tfa98xx_DAI_TDM) && (tfa->tfa_family == 2)) { + value = TFA_READ_REG(tfa, TDMERR); /* STATUS_FLAGS1 */ + if (value < 0) + return -value; + val = (uint16_t)value; + if (TFA_GET_BF_VALUE(tfa, TDMERR, val) || + TFA_GET_BF_VALUE(tfa, TDMLUTER, val)) + pr_err("TDM related errors: STATUS_FLAG1 = 0x%x\n", val); + } + + return Tfa98xx_Error_Ok; +} + +int tfa_plop_noise_interrupt(struct tfa_device *tfa, int profile, int vstep) +{ + enum Tfa98xx_Error err; + int no_clk=0; + + /* Remove sticky bit by reading it once */ + TFA_GET_BF(tfa, NOCLK); + + /* No clock detected */ + if (tfa_irq_get(tfa, tfa9912_irq_stnoclk)) { + no_clk = TFA_GET_BF(tfa, NOCLK); + + /* Detect for clock is lost! (clock is not stable) */ + if (no_clk == 1) { + /* Clock is lost. Set I2CR to remove POP noise */ + pr_info("No clock detected. Resetting the I2CR to avoid pop on 72! \n"); + err = tfa_dev_start(tfa, profile, vstep); + if (err != Tfa98xx_Error_Ok) { + pr_err("Error loading i2c registers (tfa_dev_start), err=%d\n", err); + } else { + pr_info("Setting i2c registers after I2CR succesfull\n"); + tfa_dev_set_state(tfa, TFA_STATE_UNMUTE); + } + + /* Remove sticky bit by reading it once */ + tfa_get_noclk(tfa); + + /* This is only for SAAM on the 72. + Since the NOCLK interrupt is only enabled for 72 this is the place + However: Not tested yet! But also does not harm normal flow! + */ + if (strstr(tfaContProfileName(tfa->cnt, tfa->dev_idx, profile), ".saam")) { + pr_info("Powering down from a SAAM profile, workaround PLMA4766 used! \n"); + TFA_SET_BF(tfa, PWDN, 1); + TFA_SET_BF(tfa, AMPE, 0); + TFA_SET_BF(tfa, SAMMODE, 0); + } + } + + /* If clk is stable set polarity to check for LOW (no clock)*/ + tfa_irq_set_pol(tfa, tfa9912_irq_stnoclk, (no_clk == 0)); + + /* clear interrupt */ + tfa_irq_clear(tfa, tfa9912_irq_stnoclk); + } + + /* return no_clk to know we called tfa_dev_start */ + return no_clk; +} + +void tfa_lp_mode_interrupt(struct tfa_device *tfa) +{ + const int irq_stclp0 = 36; /* FIXME: this 72 interrupt does not excist for 9912 */ + int lp0, lp1; + + if (tfa_irq_get(tfa, irq_stclp0)) { + lp0 = TFA_GET_BF(tfa, LP0); + if (lp0 > 0) { + pr_info("lowpower mode 0 detected\n"); + } else { + pr_info("lowpower mode 0 not detected\n"); + } + + tfa_irq_set_pol(tfa, irq_stclp0, (lp0 == 0)); + + /* clear interrupt */ + tfa_irq_clear(tfa, irq_stclp0); + } + + if (tfa_irq_get(tfa, tfa9912_irq_stclpr)) { + lp1 = TFA_GET_BF(tfa, LP1); + if (lp1 > 0) { + pr_info("lowpower mode 1 detected\n"); + } else { + pr_info("lowpower mode 1 not detected\n"); + } + + tfa_irq_set_pol(tfa, tfa9912_irq_stclpr, (lp1 == 0)); + + /* clear interrupt */ + tfa_irq_clear(tfa, tfa9912_irq_stclpr); + } +} diff --git a/techpack/audio/asoc/codecs/tfa9874/tfa_dsp_fw.h b/techpack/audio/asoc/codecs/tfa9874/tfa_dsp_fw.h new file mode 100644 index 000000000000..ce7340f70fee --- /dev/null +++ b/techpack/audio/asoc/codecs/tfa9874/tfa_dsp_fw.h @@ -0,0 +1,168 @@ +/* + * Copyright 2014-2017 NXP Semiconductors + * + * 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 TFA98XX_INTERNALS_H +#define TFA98XX_INTERNALS_H + +#include "config.h" + +#include "tfa_service.h" //TODO cleanup for enum Tfa98xx_Status_ID +/* + * tfadsp_fw_api.c + */ +/** + * Return a text version of the firmware status ID code + * @param status the given status ID code + * @return the firmware status ID string + */ +const char *tfadsp_fw_status_string(enum Tfa98xx_Status_ID status); +int tfadsp_fw_start(struct tfa_device *tfa, int prof_idx, int vstep_idx); +int tfadsp_fw_get_api_version(struct tfa_device *tfa, uint8_t *buffer); +#define FW_MAXTAG 150 +int tfadsp_fw_get_tag(struct tfa_device *tfa, uint8_t *buffer); +int tfadsp_fw_get_status_change(struct tfa_device *tfa, uint8_t *buffer); +int tfadsp_fw_set_re25(struct tfa_device *tfa, int prim, int sec ); +int tfadsp_fw_get_re25(struct tfa_device *tfa, uint8_t *buffer); + +/* + * the order matches the ACK bits order in TFA98XX_CF_STATUS + */ +enum tfa_fw_event { /* not all available on each device */ + tfa_fw_i2c_cmd_ack, + tfa_fw_reset_start, + tfa_fw_short_on_mips, + tfa_fw_soft_mute_ready, + tfa_fw_volume_ready, + tfa_fw_error_damage, + tfa_fw_calibrate_done, + tfa_fw_max +}; + +/* the following type mappings are compiler specific */ +#define subaddress_t unsigned char + +/* module Ids */ +#define MODULE_FRAMEWORK 0 +#define MODULE_SPEAKERBOOST 1 +#define MODULE_BIQUADFILTERBANK 2 +#define MODULE_TAPTRIGGER 5 +#define MODULE_SETRE 9 + +/* RPC commands */ +/* SET */ +#define FW_PAR_ID_SET_MEMORY 0x03 +#define FW_PAR_ID_SET_SENSES_DELAY 0x04 +#define FW_PAR_ID_SETSENSESCAL 0x05 +#define FW_PAR_ID_SET_INPUT_SELECTOR 0x06 +#define FW_PAR_ID_SET_OUTPUT_SELECTOR 0x08 +#define FW_PAR_ID_SET_PROGRAM_CONFIG 0x09 +#define FW_PAR_ID_SET_GAINS 0x0A +#define FW_PAR_ID_SET_MEMTRACK 0x0B +#define FW_PAR_ID_SET_FWKUSECASE 0x11 +#define TFA1_FW_PAR_ID_SET_CURRENT_DELAY 0x03 +#define TFA1_FW_PAR_ID_SET_CURFRAC_DELAY 0x06 +/* GET */ +#define FW_PAR_ID_GET_MEMORY 0x83 +#define FW_PAR_ID_GLOBAL_GET_INFO 0x84 +#define FW_PAR_ID_GET_FEATURE_INFO 0x85 +#define FW_PAR_ID_GET_MEMTRACK 0x8B +#define FW_PAR_ID_GET_TAG 0xFF +#define FW_PAR_ID_GET_API_VERSION 0xFE +#define FW_PAR_ID_GET_STATUS_CHANGE 0x8D + +/* Load a full model into SpeakerBoost. */ +/* SET */ +#define SB_PARAM_SET_ALGO_PARAMS 0x00 +#define SB_PARAM_SET_LAGW 0x01 +#define SB_PARAM_SET_ALGO_PARAMS_WITHOUT_RESET 0x02 +#define SB_PARAM_SET_RE25C 0x05 +#define SB_PARAM_SET_LSMODEL 0x06 +#define SB_PARAM_SET_MBDRC 0x07 +#define SB_PARAM_SET_MBDRC_WITHOUT_RESET 0x08 +#define SB_PARAM_SET_EXCURSION_FILTERS 0x0A +#define SB_PARAM_SET_DRC 0x0F +/* GET */ +#define SB_PARAM_GET_ALGO_PARAMS 0x80 +#define SB_PARAM_GET_LAGW 0x81 +#define SB_PARAM_GET_RE25C 0x85 +#define SB_PARAM_GET_LSMODEL 0x86 +#define SB_PARAM_GET_MBDRC 0x87 +#define SB_PARAM_GET_MBDRC_DYNAMICS 0x89 +#define SB_PARAM_GET_EXCURSION_FILTERS 0x8A +#define SB_PARAM_GET_TAG 0xFF + +#define SB_PARAM_SET_EQ 0x0A /* 2 Equaliser Filters. */ +#define SB_PARAM_SET_PRESET 0x0D /* Load a preset */ +#define SB_PARAM_SET_CONFIG 0x0E /* Load a config */ +#define SB_PARAM_SET_AGCINS 0x10 +#define SB_PARAM_SET_CURRENT_DELAY 0x03 +#define SB_PARAM_GET_STATE 0xC0 +#define SB_PARAM_GET_XMODEL 0xC1 /* Gets current Excursion Model. */ +#define SB_PARAM_GET_XMODEL_COEFFS 0x8C /* Get coefficients for XModel */ +#define SB_PARAM_GET_EXCURSION_FILTERS 0x8A /* Get excursion filters */ +#define SB_PARAM_SET_EXCURSION_FILTERS 0x0A /* Set excursion filters */ + +/* SET: TAPTRIGGER */ +#define TAP_PARAM_SET_ALGO_PARAMS 0x01 +#define TAP_PARAM_SET_DECIMATION_PARAMS 0x02 + +/* GET: TAPTRIGGER*/ +#define TAP_PARAM_GET_ALGO_PARAMS 0x81 +#define TAP_PARAM_GET_TAP_RESULTS 0x84 + +/* sets the speaker calibration impedance (@25 degrees celsius) */ +#define SB_PARAM_SET_RE0 0x89 + +#define BFB_PAR_ID_SET_COEFS 0x00 +#define BFB_PAR_ID_GET_COEFS 0x80 +#define BFB_PAR_ID_GET_CONFIG 0x81 + +/* for compatibility */ +#define FW_PARAM_GET_STATE FW_PAR_ID_GLOBAL_GET_INFO +#define FW_PARAM_GET_FEATURE_BITS FW_PAR_ID_GET_FEATURE_BITS + +/* RPC Status results */ +#define STATUS_OK 0 +#define STATUS_INVALID_MODULE_ID 2 +#define STATUS_INVALID_PARAM_ID 3 +#define STATUS_INVALID_INFO_ID 4 + +/* the maximum message length in the communication with the DSP */ +#define TFA2_MAX_PARAM_SIZE (507*3) /* TFA2 */ +#define TFA1_MAX_PARAM_SIZE (145*3) /* TFA1 */ + +#define ROUND_DOWN(a,n) (((a)/(n))*(n)) + +/* feature bits */ +#define FEATURE1_TCOEF 0x100 /* bit8 set means tCoefA expected */ +#define FEATURE1_DRC 0x200 /* bit9 NOT set means DRC expected */ + +/* DSP firmware xmem defines */ +#define TFA1_FW_XMEM_CALIBRATION_DONE 231 +#define TFA2_FW_XMEM_CALIBRATION_DONE 516 +#define TFA1_FW_XMEM_COUNT_BOOT 0xa1 +#define TFA2_FW_XMEM_COUNT_BOOT 512 +#define TFA2_FW_XMEM_CMD_COUNT 520 + +/* note that the following defs rely on the handle variable */ +#define TFA_FW_XMEM_CALIBRATION_DONE TFA_FAM_FW(tfa,XMEM_CALIBRATION_DONE) +#define TFA_FW_XMEM_COUNT_BOOT TFA_FAM_FW(tfa,XMEM_COUNT_BOOT) +#define TFA_FW_XMEM_CMD_COUNT TFA_FAM_FW(tfa,XMEM_CMD_COUNT) + +#define TFA2_FW_ReZ_SCALE 65536 +#define TFA1_FW_ReZ_SCALE 16384 + +#endif /* TFA98XX_INTERNALS_H */ diff --git a/techpack/audio/asoc/codecs/tfa9874/tfa_ext.h b/techpack/audio/asoc/codecs/tfa9874/tfa_ext.h new file mode 100644 index 000000000000..da68f779bbe2 --- /dev/null +++ b/techpack/audio/asoc/codecs/tfa9874/tfa_ext.h @@ -0,0 +1,57 @@ +/* + * Copyright 2016-2017 NXP Semiconductors + * + * 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. + */ +/* + * tfa_ext.h + * + * Created on: Jun 8, 2016 + * Author: wim + */ + +#ifndef TFA_SRC_TFA_EXT_H_ +#define TFA_SRC_TFA_EXT_H_ + +#include "tfa_device.h" + +/* + * events + */ +/** Maximum value for enumerator */ +#define LVM_MAXENUM (0xffff) +/** +This enum type specifies the different events that may trigger a callback. +*/ +enum tfadsp_event_en +{ + TFADSP_CMD_ACK = 1, /**< Command handling is completed */ + TFADSP_SOFT_MUTE_READY = 8, /**< Muting completed */ + TFADSP_VOLUME_READY = 16, /**< Volume change completed */ + TFADSP_DAMAGED_SPEAKER = 32, /**< Damaged speaker was detected */ + TFADSP_CALIBRATE_DONE = 64, /**< Calibration is completed */ + TFADSP_SPARSESIG_DETECTED = 128, /**< Sparse signal detected */ + TFADSP_CMD_READY = 256, /**< Ready to receive commands */ + TFADSP_EXT_PWRUP = 0x8000,/**< DSP API has started, powered up */ + TFADSP_EXT_PWRDOWN = 0x8001,/**< DSP API stopped, power down */ + TFADSP_EVENT_DUMMY = LVM_MAXENUM +} ; + +typedef int (*tfa_event_handler_t)(struct tfa_device *tfa, enum tfadsp_event_en tfadsp_event); +typedef int (*dsp_send_message_t)(struct tfa_device *tfa, int length, const char *buf); +typedef int (*dsp_read_message_t)(struct tfa_device *tfa, int length, char *buf); +typedef int (*dsp_write_reg_t)(struct tfa_device *tfa, unsigned char subaddress, unsigned short value); + +int tfa_ext_register(dsp_write_reg_t tfa_write_reg, dsp_send_message_t tfa_send_message, dsp_read_message_t tfa_read_message, tfa_event_handler_t *tfa_event_handler); + +#endif /* TFA_SRC_TFA_EXT_H_ */ diff --git a/techpack/audio/asoc/codecs/tfa9874/tfa_init.c b/techpack/audio/asoc/codecs/tfa9874/tfa_init.c new file mode 100644 index 000000000000..54e462cac2f7 --- /dev/null +++ b/techpack/audio/asoc/codecs/tfa9874/tfa_init.c @@ -0,0 +1,1674 @@ +/* + * Copyright 2014-2017 NXP Semiconductors + * + * 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 "dbgprint.h" +#include "tfa_service.h" +#include "tfa_internal.h" +#include "tfa_container.h" +#include "tfa98xx_tfafieldnames.h" + +/* The CurrentSense4 registers are not in the datasheet */ +#define TFA98XX_CURRENTSENSE4_CTRL_CLKGATECFOFF (1<<2) +#define TFA98XX_CURRENTSENSE4 0x49 + +/***********************************************************************************/ +/* GLOBAL (Defaults) */ +/***********************************************************************************/ +static enum Tfa98xx_Error no_overload_function_available(struct tfa_device *tfa, int not_used) +{ + (void)tfa; + (void)not_used; + + return Tfa98xx_Error_Ok; +} + +static enum Tfa98xx_Error no_overload_function_available2(struct tfa_device *tfa) +{ + (void)tfa; + + return Tfa98xx_Error_Ok; +} + +/* tfa98xx_dsp_system_stable +* return: *ready = 1 when clocks are stable to allow DSP subsystem access +*/ +static enum Tfa98xx_Error tfa_dsp_system_stable(struct tfa_device *tfa, int *ready) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + unsigned short status; + int value; + + /* check the contents of the STATUS register */ + value = TFA_READ_REG(tfa, AREFS); + if (value < 0) { + error = -value; + *ready = 0; + _ASSERT(error); /* an error here can be fatal */ + return error; + } + status = (unsigned short)value; + + /* check AREFS and CLKS: not ready if either is clear */ + *ready = !((TFA_GET_BF_VALUE(tfa, AREFS, status) == 0) + || (TFA_GET_BF_VALUE(tfa, CLKS, status) == 0)); + + return error; +} + +/* tfa98xx_toggle_mtp_clock + * Allows to stop clock for MTP/FAim needed for PLMA5505 */ +static enum Tfa98xx_Error tfa_faim_protect(struct tfa_device *tfa, int state) +{ + (void)tfa; + (void)state; + + return Tfa98xx_Error_Ok; +} + +/** Set internal oscillator into power down mode. + * + * This function is a worker for tfa98xx_set_osc_powerdown(). + * + * @param[in] tfa device description structure + * @param[in] state new state 0 - oscillator is on, 1 oscillator is off. + * + * @return Tfa98xx_Error_Ok when successfull, error otherwise. + */ +static enum Tfa98xx_Error tfa_set_osc_powerdown(struct tfa_device *tfa, int state) +{ + /* This function has no effect in general case, only for tfa9912 */ + (void)tfa; + (void)state; + + return Tfa98xx_Error_Ok; +} + +static enum Tfa98xx_Error tfa_dsp_reset(struct tfa_device *tfa, int state) +{ + /* generic function */ + TFA_SET_BF_VOLATILE(tfa, RST, (uint16_t)state); + + return Tfa98xx_Error_Ok; +} + +int tfa_set_swprofile(struct tfa_device *tfa, unsigned short new_value) +{ + int mtpk, active_value = tfa->profile; + + /* Also set real profile index in the struct */ + tfa->profile = new_value - 1; + + /* for TFA1 devices */ + /* it's in MTP shadow, so unlock if not done already */ + mtpk = TFA_GET_BF(tfa, MTPK); /* get current key */ + TFA_SET_BF_VOLATILE(tfa, MTPK, 0x5a); + TFA_SET_BF_VOLATILE(tfa, SWPROFIL, new_value); /* set current profile */ + TFA_SET_BF_VOLATILE(tfa, MTPK, (uint16_t)mtpk); /* restore key */ + + return active_value; +} + +static int tfa_get_swprofile(struct tfa_device *tfa) +{ + return TFA_GET_BF(tfa, SWPROFIL) - 1; +} + +static int tfa_set_swvstep(struct tfa_device *tfa, unsigned short new_value) +{ + int mtpk, active_value = tfa->vstep; + + /* Also set the new value in the struct */ + tfa->vstep = new_value-1; + + /* for TFA1 devices */ + /* it's in MTP shadow, so unlock if not done already */ + mtpk = TFA_GET_BF(tfa, MTPK); /* get current key */ + TFA_SET_BF_VOLATILE(tfa, MTPK, 0x5a); + TFA_SET_BF_VOLATILE(tfa, SWVSTEP, new_value); /* set current vstep */ + TFA_SET_BF_VOLATILE(tfa, MTPK, (uint16_t)mtpk); /* restore key */ + + return active_value; +} + +static int tfa_get_swvstep(struct tfa_device *tfa) +{ + int value = 0; + /* Set the new value in the hw register */ + value = TFA_GET_BF(tfa, SWVSTEP); + + /* Also set the new value in the struct */ + tfa->vstep = value; + + return value - 1; /* invalid if 0 */ +} + +static int tfa_get_mtpb(struct tfa_device *tfa) { + + int value=0; + + /* Set the new value in the hw register */ + value = TFA_GET_BF(tfa, MTPB); + + return value; +} + +static enum Tfa98xx_Error +tfa_set_mute_nodsp(struct tfa_device *tfa, int mute) +{ + (void)tfa; + (void)mute; + + return Tfa98xx_Error_Ok; +} + +void set_ops_defaults(struct tfa_device_ops *ops) +{ + /* defaults */ + ops->reg_read = tfa98xx_read_register16; + ops->reg_write = tfa98xx_write_register16; + ops->mem_read = tfa98xx_dsp_read_mem; + ops->mem_write = tfa98xx_dsp_write_mem_word; + ops->dsp_msg = tfa_dsp_msg; + ops->dsp_msg_read = tfa_dsp_msg_read; + ops->dsp_write_tables = no_overload_function_available; + ops->dsp_reset = tfa_dsp_reset; + ops->dsp_system_stable = tfa_dsp_system_stable; + ops->auto_copy_mtp_to_iic = no_overload_function_available2; + ops->factory_trimmer = no_overload_function_available2; + ops->set_swprof = tfa_set_swprofile; + ops->get_swprof = tfa_get_swprofile; + ops->set_swvstep = tfa_set_swvstep; + ops->get_swvstep = tfa_get_swvstep; + ops->get_mtpb = tfa_get_mtpb; + ops->set_mute = tfa_set_mute_nodsp; + ops->faim_protect = tfa_faim_protect; + ops->set_osc_powerdown = tfa_set_osc_powerdown; +} + +/***********************************************************************************/ +/* no TFA + * external DSP SB instance */ +/***********************************************************************************/ +static short tfanone_swvstep, swprof; //TODO emulate in hal plugin +static enum Tfa98xx_Error tfanone_dsp_system_stable(struct tfa_device *tfa, int *ready) +{ + (void)tfa; /* suppress warning */ + *ready = 1; /* assume always ready */ + + return Tfa98xx_Error_Ok; +} + +static int tfanone_set_swprofile(struct tfa_device *tfa, unsigned short new_value) +{ + int active_value = tfa_dev_get_swprof(tfa); + + /* Set the new value in the struct */ + tfa->profile = new_value - 1; + + /* Set the new value in the hw register */ + swprof = new_value; + + return active_value; +} + +static int tfanone_get_swprofile(struct tfa_device *tfa) +{ + (void)tfa; /* suppress warning */ + return swprof; +} + +static int tfanone_set_swvstep(struct tfa_device *tfa, unsigned short new_value) +{ + /* Set the new value in the struct */ + tfa->vstep = new_value-1; + + /* Set the new value in the hw register */ + tfanone_swvstep = new_value; + + return new_value; +} + +static int tfanone_get_swvstep(struct tfa_device *tfa) +{ + (void)tfa; /* suppress warning */ + return tfanone_swvstep; +} + +void tfanone_ops(struct tfa_device_ops *ops) +{ + /* Set defaults for ops */ + set_ops_defaults(ops); + + ops->dsp_system_stable = tfanone_dsp_system_stable; + ops->set_swprof = tfanone_set_swprofile; + ops->get_swprof = tfanone_get_swprofile; + ops->set_swvstep = tfanone_set_swvstep; + ops->get_swvstep = tfanone_get_swvstep; + +} + +/***********************************************************************************/ +/* TFA9912 */ +/***********************************************************************************/ +static enum Tfa98xx_Error tfa9912_faim_protect(struct tfa_device *tfa, int status) +{ + enum Tfa98xx_Error ret = Tfa98xx_Error_Fail; + + if (tfa) { + if (status == 0 || status == 1) { + ret = -(tfa_set_bf(tfa, TFA9912_BF_SSFAIME, (uint16_t)status)); + } + } + + return ret; +} + +static enum Tfa98xx_Error tfa9912_specific(struct tfa_device *tfa) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + unsigned short value, xor; + + if (tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + + /* Unlock keys to write settings */ + error = reg_write(tfa, 0x0F, 0x5A6B); + error = reg_read(tfa, 0xFB, &value); + xor = value ^ 0x005A; + error = reg_write(tfa, 0xA0, xor); + + /* The optimal settings */ + if (tfa->rev == 0x1a13) { + + /* ----- generated code start ----- */ + /* ----- version 1.41 ----- */ + reg_write(tfa, 0x00, 0x0255); //POR=0x0245 + reg_write(tfa, 0x01, 0x838a); //POR=0x83ca + reg_write(tfa, 0x02, 0x2dc8); //POR=0x2828 + reg_write(tfa, 0x05, 0x762a); //POR=0x766a + reg_write(tfa, 0x22, 0x543c); //POR=0x545c + reg_write(tfa, 0x26, 0x0100); //POR=0x0010 + reg_write(tfa, 0x51, 0x0000); //POR=0x0080 + reg_write(tfa, 0x52, 0x551c); //POR=0x1afc + reg_write(tfa, 0x53, 0x003e); //POR=0x001e + reg_write(tfa, 0x61, 0x000c); //POR=0x0018 + reg_write(tfa, 0x63, 0x0a96); //POR=0x0a9a + reg_write(tfa, 0x65, 0x0a82); //POR=0x0a8b + reg_write(tfa, 0x66, 0x0701); //POR=0x0700 + reg_write(tfa, 0x6c, 0x00d5); //POR=0x02d5 + reg_write(tfa, 0x70, 0x26f8); //POR=0x06e0 + reg_write(tfa, 0x71, 0x3074); //POR=0x2074 + reg_write(tfa, 0x75, 0x4484); //POR=0x4585 + reg_write(tfa, 0x76, 0x72ea); //POR=0x54a2 + reg_write(tfa, 0x83, 0x0716); //POR=0x0617 + reg_write(tfa, 0x89, 0x0013); //POR=0x0014 + reg_write(tfa, 0xb0, 0x4c08); //POR=0x4c00 + reg_write(tfa, 0xc6, 0x004e); //POR=0x000e /* PLMA5539: Please make sure bit 6 is always on! */ + /* ----- generated code end ----- */ + + /* PLMA5505: MTP key open makes vulanable for MTP corruption */ + tfa9912_faim_protect(tfa, 0); + } else { + pr_info("Warning: Optimal settings not found for device with revid = 0x%x \n", tfa->rev); + } + + return error; +} + +static enum Tfa98xx_Error tfa9912_tfa_dsp_write_tables(struct tfa_device *tfa, int sample_rate) +{ + unsigned char buffer[15] = { 0 }; + int size = 15 * sizeof(char); + + /* Write the fractional delay in the hardware register 'cs_frac_delay' */ + switch (sample_rate) { + case 0: /* 8kHz */ + TFA_SET_BF(tfa, FRACTDEL, 40); + break; + case 1: /* 11.025KHz */ + TFA_SET_BF(tfa, FRACTDEL, 38); + break; + case 2: /* 12kHz */ + TFA_SET_BF(tfa, FRACTDEL, 37); + break; + case 3: /* 16kHz */ + TFA_SET_BF(tfa, FRACTDEL, 59); + break; + case 4: /* 22.05KHz */ + TFA_SET_BF(tfa, FRACTDEL, 56); + break; + case 5: /* 24kHz */ + TFA_SET_BF(tfa, FRACTDEL, 56); + break; + case 6: /* 32kHz */ + TFA_SET_BF(tfa, FRACTDEL, 52); + break; + case 7: /* 44.1kHz */ + TFA_SET_BF(tfa, FRACTDEL, 48); + break; + case 8: + default:/* 48kHz */ + TFA_SET_BF(tfa, FRACTDEL, 46); + break; + } + + /* First copy the msg_id to the buffer */ + buffer[0] = (uint8_t)0; + buffer[1] = (uint8_t)MODULE_FRAMEWORK + 128; + buffer[2] = (uint8_t)FW_PAR_ID_SET_SENSES_DELAY; + + /* Required for all FS exept 8kHz (8kHz is all zero) */ + if (sample_rate != 0) { + buffer[5] = 1; /* Vdelay_P */ + buffer[8] = 0; /* Idelay_P */ + buffer[11] = 1; /* Vdelay_S */ + buffer[14] = 0; /* Idelay_S */ + } + + /* send SetSensesDelay msg */ + return dsp_msg(tfa, size, (char *)buffer); +} + +static enum Tfa98xx_Error tfa9912_factory_trimmer(struct tfa_device *tfa) +{ + unsigned short currentValue, delta; + int result; + + /* Factory trimming for the Boost converter */ + /* check if there is a correction needed */ + result = TFA_GET_BF(tfa, DCMCCAPI); + if (result) { + /* Get currentvalue of DCMCC and the Delta value */ + currentValue = (unsigned short)TFA_GET_BF(tfa, DCMCC); + delta = (unsigned short)TFA_GET_BF(tfa, USERDEF); + + /* check the sign bit (+/-) */ + result = TFA_GET_BF(tfa, DCMCCSB); + if (result == 0) { + /* Do not exceed the maximum value of 15 */ + if (currentValue + delta < 15) { + TFA_SET_BF_VOLATILE(tfa, DCMCC, currentValue + delta); + if (tfa->verbose) + pr_debug("Max coil current is set to: %d \n", currentValue + delta); + } + else { + TFA_SET_BF_VOLATILE(tfa, DCMCC, 15); + if (tfa->verbose) + pr_debug("Max coil current is set to: 15 \n"); + } + } + else if (result == 1) { + /* Do not exceed the minimum value of 0 */ + if (currentValue - delta > 0) { + TFA_SET_BF_VOLATILE(tfa, DCMCC, currentValue - delta); + if (tfa->verbose) + pr_debug("Max coil current is set to: %d \n", currentValue - delta); + } + else { + TFA_SET_BF_VOLATILE(tfa, DCMCC, 0); + if (tfa->verbose) + pr_debug("Max coil current is set to: 0 \n"); + } + } + } + + return Tfa98xx_Error_Ok; +} + +static enum Tfa98xx_Error tfa9912_auto_copy_mtp_to_iic(struct tfa_device *tfa) +{ + /* Set auto_copy_mtp_to_iic (bit 5 of A3) to 1. Workaround for 72, 88 and 9912/9892(see PLMA5290) */ + return reg_write(tfa, 0xA3, 0x20); +} + +static int tfa9912_set_swprofile(struct tfa_device *tfa, unsigned short new_value) +{ + int active_value = tfa_dev_get_swprof(tfa); + + /* Set the new value in the struct */ + tfa->profile = new_value - 1; + + /* Set the new value in the hw register */ + tfa_set_bf_volatile(tfa, TFA9912_BF_SWPROFIL, new_value); + + return active_value; +} + +static int tfa9912_get_swprofile(struct tfa_device *tfa) +{ + return tfa_get_bf(tfa, TFA9912_BF_SWPROFIL) - 1; +} + +static int tfa9912_set_swvstep(struct tfa_device *tfa, unsigned short new_value) +{ + /* Set the new value in the struct */ + tfa->vstep = new_value-1; + + /* Set the new value in the hw register */ + tfa_set_bf_volatile(tfa, TFA9912_BF_SWVSTEP, new_value); + + return new_value; +} + +static int tfa9912_get_swvstep(struct tfa_device *tfa) +{ + return tfa_get_bf(tfa, TFA9912_BF_SWVSTEP) - 1; +} + +static enum Tfa98xx_Error +tfa9912_set_mute(struct tfa_device *tfa, int mute) +{ + tfa_set_bf(tfa, TFA9912_BF_CFSM, (const uint16_t)mute); + + return Tfa98xx_Error_Ok; +} + +/* Maksimum value for combination of boost_voltage and vout calibration offset (see PLMA5322, PLMA5528). */ +#define TFA9912_VBOOST_MAX 57 +#define TFA9912_CALIBR_BOOST_MAX 63 +#define TFA9912_DCDCCNT6_REG (TFA9912_BF_DCVOF >> 8) +#define TFA9912_CALIBR_REG 0xf1 + +static uint16_t tfa9912_vboost_fixup(struct tfa_device *tfa, uint16_t dcdc_cnt6) +{ + unsigned short cal_offset; + unsigned short boost_v_1st, boost_v_2nd; + uint16_t new_dcdc_cnt6; + + /* Get current calibr_vout_offset, this register is not supported by bitfields */ + reg_read(tfa, TFA9912_CALIBR_REG, &cal_offset); + cal_offset = (cal_offset & 0x001f); + new_dcdc_cnt6 = dcdc_cnt6; + + /* Get current boost_volatage values */ + boost_v_1st = tfa_get_bf_value(TFA9912_BF_DCVOF, new_dcdc_cnt6); + boost_v_2nd = tfa_get_bf_value(TFA9912_BF_DCVOS, new_dcdc_cnt6); + + /* Check boost voltages */ + if (boost_v_1st > TFA9912_VBOOST_MAX) + boost_v_1st = TFA9912_VBOOST_MAX; + + if (boost_v_2nd > TFA9912_VBOOST_MAX) + boost_v_2nd = TFA9912_VBOOST_MAX; + + /* Recalculate values, max for the sum is TFA9912_CALIBR_BOOST_MAX */ + if (boost_v_1st + cal_offset > TFA9912_CALIBR_BOOST_MAX) + boost_v_1st = TFA9912_CALIBR_BOOST_MAX - cal_offset; + + if (boost_v_2nd + cal_offset > TFA9912_CALIBR_BOOST_MAX) + boost_v_2nd = TFA9912_CALIBR_BOOST_MAX - cal_offset; + + tfa_set_bf_value(TFA9912_BF_DCVOF, boost_v_1st, &new_dcdc_cnt6); + tfa_set_bf_value(TFA9912_BF_DCVOS, boost_v_2nd, &new_dcdc_cnt6); + + /* Change register value only when it's neccesary */ + if (new_dcdc_cnt6 != dcdc_cnt6) { + if (tfa->verbose) + pr_debug("tfa9912: V boost fixup applied. Old 0x%04x, new 0x%04x\n", + dcdc_cnt6, new_dcdc_cnt6); + dcdc_cnt6 = new_dcdc_cnt6; + } + + return dcdc_cnt6; +} + +/* PLMA5322, PLMA5528 - Limit values of DCVOS and DCVOF to range specified in datasheet. */ +enum Tfa98xx_Error tfa9912_reg_write(struct tfa_device *tfa, unsigned char subaddress, unsigned short value) +{ + if (subaddress == TFA9912_DCDCCNT6_REG) { + /* Correct V boost (first and secondary) to ensure 12V is not exceeded. */ + value = tfa9912_vboost_fixup(tfa, value); + } + + return tfa98xx_write_register16(tfa, subaddress, value); +} + +/** Set internal oscillator into power down mode for TFA9912. +* +* This function is a worker for tfa98xx_set_osc_powerdown(). +* +* @param[in] tfa device description structure +* @param[in] state new state 0 - oscillator is on, 1 oscillator is off. +* +* @return Tfa98xx_Error_Ok when successfull, error otherwise. +*/ +static enum Tfa98xx_Error tfa9912_set_osc_powerdown(struct tfa_device *tfa, int state) +{ + if (state == 1 || state == 0) { + return -tfa_set_bf(tfa, TFA9912_BF_MANAOOSC, (uint16_t) state); + } + + return Tfa98xx_Error_Bad_Parameter; +} + +void tfa9912_ops(struct tfa_device_ops *ops) +{ + /* Set defaults for ops */ + set_ops_defaults(ops); + + ops->tfa_init = tfa9912_specific; + /* PLMA5322, PLMA5528 - Limits values of DCVOS and DCVOF. */ + ops->reg_write = tfa9912_reg_write; + ops->dsp_write_tables = tfa9912_tfa_dsp_write_tables; + ops->factory_trimmer = tfa9912_factory_trimmer; + ops->auto_copy_mtp_to_iic = tfa9912_auto_copy_mtp_to_iic; + ops->set_swprof = tfa9912_set_swprofile; + ops->get_swprof = tfa9912_get_swprofile; + ops->set_swvstep = tfa9912_set_swvstep; + ops->get_swvstep = tfa9912_get_swvstep; + ops->set_mute = tfa9912_set_mute; + ops->faim_protect = tfa9912_faim_protect; + ops->set_osc_powerdown = tfa9912_set_osc_powerdown; +} + +/***********************************************************************************/ +/* TFA9872 */ +/***********************************************************************************/ +static enum Tfa98xx_Error tfa9872_specific(struct tfa_device *tfa) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + uint16_t MANAOOSC = 0x0140; /* version 17 */ + unsigned short value, xor; + + if (tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + + /* Unlock key 1 and 2 */ + error = reg_write(tfa, 0x0F, 0x5A6B); + error = reg_read(tfa, 0xFB, &value); + xor = value ^ 0x005A; + error = reg_write(tfa, 0xA0, xor); + tfa98xx_key2(tfa, 0); + + switch (tfa->rev) { + case 0x1a72: + case 0x2a72: + /* ----- generated code start ----- */ + /* ----- version 26 ----- */ + reg_write(tfa, 0x00, 0x1801); //POR=0x0001 + reg_write(tfa, 0x02, 0x2dc8); //POR=0x2028 + reg_write(tfa, 0x20, 0x0890); //POR=0x2890 + reg_write(tfa, 0x22, 0x043c); //POR=0x045c + reg_write(tfa, 0x51, 0x0000); //POR=0x0080 + reg_write(tfa, 0x52, 0x1a1c); //POR=0x7ae8 + reg_write(tfa, 0x58, 0x161c); //POR=0x101c + reg_write(tfa, 0x61, 0x0198); //POR=0x0000 + reg_write(tfa, 0x65, 0x0a8b); //POR=0x0a9a + reg_write(tfa, 0x70, 0x07f5); //POR=0x06e6 + reg_write(tfa, 0x74, 0xcc84); //POR=0xd823 + reg_write(tfa, 0x82, 0x01ed); //POR=0x000d + reg_write(tfa, 0x83, 0x0014); //POR=0x0013 + reg_write(tfa, 0x84, 0x0021); //POR=0x0020 + reg_write(tfa, 0x85, 0x0001); //POR=0x0003 + /* ----- generated code end ----- */ + break; + case 0x1b72: + case 0x2b72: + case 0x3b72: + /* ----- generated code start ----- */ + /* ----- TFA9872 Probus Registers map N1B2 - Version 21 (10/19/2016) ----- */ + reg_write(tfa, 0x02, 0x2dc8); //POR=0x2828 + reg_write(tfa, 0x20, 0x0890); //POR=0x2890 + reg_write(tfa, 0x22, 0x043c); //POR=0x045c + reg_write(tfa, 0x23, 0x0001); //POR=0x0003 + reg_write(tfa, 0x51, 0x0000); //POR=0x0080 + reg_write(tfa, 0x52, 0x5a1c); //POR=0x7a08 + reg_write(tfa, 0x61, 0x0198); //POR=0x0000 + reg_write(tfa, 0x63, 0x0a9a); //POR=0x0a93 + reg_write(tfa, 0x65, 0x0a82); //POR=0x0a8d + reg_write(tfa, 0x6f, 0x01e3); //POR=0x02e4 + reg_write(tfa, 0x70, 0x06fd); //POR=0x06e6 + reg_write(tfa, 0x71, 0x307e); //POR=0x207e + reg_write(tfa, 0x74, 0xcc84); //POR=0xd913 + reg_write(tfa, 0x75, 0x1132); //POR=0x118a + reg_write(tfa, 0x82, 0x01ed); //POR=0x000d + reg_write(tfa, 0x83, 0x001a); //POR=0x0013 + /* ----- generated code end ----- */ + break; + default: + pr_info("\nWarning: Optimal settings not found for device with revid = 0x%x \n", tfa->rev); + break; + } + + /* Turn off the osc1m to save power: PLMA4928 */ + error = tfa_set_bf(tfa, MANAOOSC, 1); + + /* Bypass OVP by setting bit 3 from register 0xB0 (bypass_ovp=1): PLMA5258 */ + error = reg_read(tfa, 0xB0, &value); + value |= 1 << 3; + error = reg_write(tfa, 0xB0, value); + + return error; +} + +static enum Tfa98xx_Error tfa9872_auto_copy_mtp_to_iic(struct tfa_device *tfa) +{ + /* Set auto_copy_mtp_to_iic (bit 5 of A3) to 1. Workaround for 72 and 88 (see PLMA5290) */ + return reg_write(tfa, 0xA3, 0x20); +} + +static int tfa9872_set_swprofile(struct tfa_device *tfa, unsigned short new_value) +{ + int active_value = tfa_dev_get_swprof(tfa); + + /* Set the new value in the struct */ + tfa->profile = new_value - 1; + + /* Set the new value in the hw register */ + tfa_set_bf_volatile(tfa, TFA9872_BF_SWPROFIL, new_value); + + return active_value; +} + +static int tfa9872_get_swprofile(struct tfa_device *tfa) +{ + return tfa_get_bf(tfa, TFA9872_BF_SWPROFIL) - 1; +} + +static int tfa9872_set_swvstep(struct tfa_device *tfa, unsigned short new_value) +{ + + /* Set the new value in the struct */ + tfa->vstep = new_value-1; + + /* Set the new value in the hw register */ + tfa_set_bf_volatile(tfa, TFA9872_BF_SWVSTEP, new_value); + + return new_value; +} + +static int tfa9872_get_swvstep(struct tfa_device *tfa) +{ + return tfa_get_bf(tfa, TFA9872_BF_SWVSTEP) - 1; +} + +void tfa9872_ops(struct tfa_device_ops *ops) +{ + /* Set defaults for ops */ + set_ops_defaults(ops); + + ops->tfa_init = tfa9872_specific; + ops->auto_copy_mtp_to_iic = tfa9872_auto_copy_mtp_to_iic; + ops->set_swprof = tfa9872_set_swprofile; + ops->get_swprof = tfa9872_get_swprofile; + ops->set_swvstep = tfa9872_set_swvstep; + ops->get_swvstep = tfa9872_get_swvstep; + ops->set_mute = tfa_set_mute_nodsp; +} + +/***********************************************************************************/ +/* TFA9874 */ +/***********************************************************************************/ + +static enum Tfa98xx_Error tfa9874_faim_protect(struct tfa_device *tfa, int status) +{ + enum Tfa98xx_Error ret = Tfa98xx_Error_Ok; + /* 0b = FAIM protection enabled 1b = FAIM protection disabled*/ + ret = tfa_set_bf_volatile(tfa, TFA9874_BF_OPENMTP, (uint16_t)(status)); + return ret; +} + + +static enum Tfa98xx_Error tfa9874_specific(struct tfa_device *tfa) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + unsigned short value, xor; + + if (tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + + /* Unlock key 1 and 2 */ + error = reg_write(tfa, 0x0F, 0x5A6B); + error = reg_read(tfa, 0xFB, &value); + xor = value ^ 0x005A; + error = reg_write(tfa, 0xA0, xor); + tfa98xx_key2(tfa, 0); + + switch (tfa->rev) { + case 0x0a74: /* Initial revision ID */ + /* ----- generated code start ----- */ + /* V25 */ + reg_write(tfa, 0x02, 0x22a8); //POR=0x25c8 + reg_write(tfa, 0x51, 0x0020); //POR=0x0000 + reg_write(tfa, 0x52, 0x57dc); //POR=0x56dc + reg_write(tfa, 0x58, 0x16a4); //POR=0x1614 + reg_write(tfa, 0x61, 0x0110); //POR=0x0198 + reg_write(tfa, 0x66, 0x0701); //POR=0x0700 + reg_write(tfa, 0x6f, 0x00a3); //POR=0x01a3 + reg_write(tfa, 0x70, 0x07f8); //POR=0x06f8 + reg_write(tfa, 0x73, 0x0007); //POR=0x0005 + reg_write(tfa, 0x74, 0x5068); //POR=0xcc80 + reg_write(tfa, 0x75, 0x0d28); //POR=0x1138 + reg_write(tfa, 0x83, 0x0594); //POR=0x061a + reg_write(tfa, 0x84, 0x0001); //POR=0x0021 + reg_write(tfa, 0x85, 0x0001); //POR=0x0003 + reg_write(tfa, 0x88, 0x0000); //POR=0x0002 + reg_write(tfa, 0xc4, 0x2001); //POR=0x0001 + /* ----- generated code end ----- */ + break; + case 0x0b74: + /* ----- generated code start ----- */ + /* V1.6 */ + reg_write(tfa, 0x02, 0x22a8); //POR=0x25c8 + reg_write(tfa, 0x51, 0x0020); //POR=0x0000 + reg_write(tfa, 0x52, 0x57dc); //POR=0x56dc + reg_write(tfa, 0x58, 0x16a4); //POR=0x1614 + reg_write(tfa, 0x61, 0x0110); //POR=0x0198 + reg_write(tfa, 0x66, 0x0701); //POR=0x0700 + reg_write(tfa, 0x6f, 0x00a3); //POR=0x01a3 + reg_write(tfa, 0x70, 0x07f8); //POR=0x06f8 + reg_write(tfa, 0x73, 0x0047); //POR=0x0045 + reg_write(tfa, 0x74, 0x5068); //POR=0xcc80 + reg_write(tfa, 0x75, 0x0d28); //POR=0x1138 + reg_write(tfa, 0x83, 0x0595); //POR=0x061a + reg_write(tfa, 0x84, 0x0001); //POR=0x0021 + reg_write(tfa, 0x85, 0x0001); //POR=0x0003 + reg_write(tfa, 0x88, 0x0000); //POR=0x0002 + reg_write(tfa, 0xc4, 0x2001); //POR=0x0001 + /* ----- generated code end ----- */ + break; + case 0x0c74: + /* ----- generated code start ----- */ + /* V1.14 */ + reg_write(tfa, 0x02, 0x22c8); //POR=0x25c8 + reg_write(tfa, 0x52, 0x57dc); //POR=0x56dc + reg_write(tfa, 0x53, 0x003e); //POR=0x001e + reg_write(tfa, 0x56, 0x0400); //POR=0x0600 + reg_write(tfa, 0x61, 0x0110); //POR=0x0198 + reg_write(tfa, 0x6f, 0x00a5); //POR=0x01a3 + reg_write(tfa, 0x70, 0x07f8); //POR=0x06f8 + reg_write(tfa, 0x73, 0x0047); //POR=0x0045 + reg_write(tfa, 0x74, 0x5098); //POR=0xcc80 + reg_write(tfa, 0x75, 0x8d28); //POR=0x1138 + reg_write(tfa, 0x80, 0x0000); //POR=0x0003 + reg_write(tfa, 0x83, 0x0799); //POR=0x061a + reg_write(tfa, 0x84, 0x0081); //POR=0x0021 + /* ----- generated code end ----- */ + break; + default: + pr_info("\nWarning: Optimal settings not found for device with revid = 0x%x \n", tfa->rev); + break; + } + + return error; +} + +static int tfa9874_set_swprofile(struct tfa_device *tfa, unsigned short new_value) +{ + int active_value = tfa_dev_get_swprof(tfa); + + /* Set the new value in the struct */ + tfa->profile = new_value - 1; + + /* Set the new value in the hw register */ + tfa_set_bf_volatile(tfa, TFA9874_BF_SWPROFIL, new_value); + + return active_value; +} + +static int tfa9874_get_swprofile(struct tfa_device *tfa) +{ + return tfa_get_bf(tfa, TFA9874_BF_SWPROFIL) - 1; +} + +static int tfa9874_set_swvstep(struct tfa_device *tfa, unsigned short new_value) +{ + + /* Set the new value in the struct */ + tfa->vstep = new_value-1; + + /* Set the new value in the hw register */ + tfa_set_bf_volatile(tfa, TFA9874_BF_SWVSTEP, new_value); + + return new_value; +} + +static int tfa9874_get_swvstep(struct tfa_device *tfa) +{ + return tfa_get_bf(tfa, TFA9874_BF_SWVSTEP) - 1; +} + +/* tfa98xx_dsp_system_stable +* return: *ready = 1 when clocks are stable to allow DSP subsystem access +*/ +static enum Tfa98xx_Error tfa9874_dsp_system_stable(struct tfa_device *tfa, int *ready) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + + /* check CLKS: ready if set */ + *ready = tfa_get_bf(tfa, TFA9874_BF_CLKS)==1; + + return error; +} + +static int tfa9874_get_mtpb(struct tfa_device *tfa) { + + int value; + value = tfa_get_bf(tfa, TFA9874_BF_MTPB); + return value; +} + +void tfa9874_ops(struct tfa_device_ops *ops) +{ + /* Set defaults for ops */ + set_ops_defaults(ops); + + ops->tfa_init = tfa9874_specific; + ops->set_swprof = tfa9874_set_swprofile; + ops->get_swprof = tfa9874_get_swprofile; + ops->set_swvstep = tfa9874_set_swvstep; + ops->get_swvstep = tfa9874_get_swvstep; + ops->dsp_system_stable = tfa9874_dsp_system_stable; + ops->faim_protect = tfa9874_faim_protect; + ops->get_mtpb = tfa9874_get_mtpb; + ops->set_mute = tfa_set_mute_nodsp; +} + +/***********************************************************************************/ +/* TFA9888 */ +/***********************************************************************************/ +static enum Tfa98xx_Error tfa9888_specific(struct tfa_device *tfa) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + unsigned short value, xor; + int patch_version; + + if (tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + + /* Unlock keys to write settings */ + error = reg_write(tfa, 0x0F, 0x5A6B); + error = reg_read(tfa, 0xFB, &value); + xor = value ^ 0x005A; + error = reg_write(tfa, 0xA0, xor); + + /* Only N1C2 is supported */ + /* ----- generated code start ----- */ + /* --------- Version v1 ---------- */ + if (tfa->rev == 0x2c88) { + reg_write(tfa, 0x00, 0x164d); //POR=0x064d + reg_write(tfa, 0x01, 0x828b); //POR=0x92cb + reg_write(tfa, 0x02, 0x1dc8); //POR=0x1828 + reg_write(tfa, 0x0e, 0x0080); //POR=0x0000 + reg_write(tfa, 0x20, 0x089e); //POR=0x0890 + reg_write(tfa, 0x22, 0x543c); //POR=0x545c + reg_write(tfa, 0x23, 0x0006); //POR=0x0000 + reg_write(tfa, 0x24, 0x0014); //POR=0x0000 + reg_write(tfa, 0x25, 0x000a); //POR=0x0000 + reg_write(tfa, 0x26, 0x0100); //POR=0x0000 + reg_write(tfa, 0x28, 0x1000); //POR=0x0000 + reg_write(tfa, 0x51, 0x0000); //POR=0x00c0 + reg_write(tfa, 0x52, 0xfafe); //POR=0xbaf6 + reg_write(tfa, 0x70, 0x3ee4); //POR=0x3ee6 + reg_write(tfa, 0x71, 0x1074); //POR=0x3074 + reg_write(tfa, 0x83, 0x0014); //POR=0x0013 + /* ----- generated code end ----- */ + } else { + pr_info("Warning: Optimal settings not found for device with revid = 0x%x \n", tfa->rev); + } + + patch_version = tfa_cnt_get_patch_version(tfa); + if (patch_version >= 0x060401) + tfa->partial_enable = 1; + + return error; +} + +static enum Tfa98xx_Error tfa9888_tfa_dsp_write_tables(struct tfa_device *tfa, int sample_rate) +{ + unsigned char buffer[15] = { 0 }; + int size = 15 * sizeof(char); + + /* Write the fractional delay in the hardware register 'cs_frac_delay' */ + switch (sample_rate) { + case 0: /* 8kHz */ + TFA_SET_BF(tfa, FRACTDEL, 40); + break; + case 1: /* 11.025KHz */ + TFA_SET_BF(tfa, FRACTDEL, 38); + break; + case 2: /* 12kHz */ + TFA_SET_BF(tfa, FRACTDEL, 37); + break; + case 3: /* 16kHz */ + TFA_SET_BF(tfa, FRACTDEL, 59); + break; + case 4: /* 22.05KHz */ + TFA_SET_BF(tfa, FRACTDEL, 56); + break; + case 5: /* 24kHz */ + TFA_SET_BF(tfa, FRACTDEL, 56); + break; + case 6: /* 32kHz */ + TFA_SET_BF(tfa, FRACTDEL, 52); + break; + case 7: /* 44.1kHz */ + TFA_SET_BF(tfa, FRACTDEL, 48); + break; + case 8: + default:/* 48kHz */ + TFA_SET_BF(tfa, FRACTDEL, 46); + break; + } + + /* First copy the msg_id to the buffer */ + buffer[0] = (uint8_t)0; + buffer[1] = (uint8_t)MODULE_FRAMEWORK + 128; + buffer[2] = (uint8_t)FW_PAR_ID_SET_SENSES_DELAY; + + /* Required for all FS exept 8kHz (8kHz is all zero) */ + if (sample_rate != 0) { + buffer[5] = 1; /* Vdelay_P */ + buffer[8] = 0; /* Idelay_P */ + buffer[11] = 1; /* Vdelay_S */ + buffer[14] = 0; /* Idelay_S */ + } + + /* send SetSensesDelay msg */ + return dsp_msg(tfa, size, (char *)buffer); +} + +static enum Tfa98xx_Error tfa9888_auto_copy_mtp_to_iic(struct tfa_device *tfa) +{ + /* Set auto_copy_mtp_to_iic (bit 5 of A3) to 1. Workaround for 72 and 88 (see PLMA5290) */ + return reg_write(tfa, 0xA3, 0x20); +} + +static enum Tfa98xx_Error tfa9888_factory_trimmer(struct tfa_device *tfa) +{ + unsigned short currentValue, delta; + int result; + + /* Factory trimming for the Boost converter */ + /* check if there is a correction needed */ + result = TFA_GET_BF(tfa, DCMCCAPI); + if (result) { + /* Get currentvalue of DCMCC and the Delta value */ + currentValue = (unsigned short)TFA_GET_BF(tfa, DCMCC); + delta = (unsigned short)TFA_GET_BF(tfa, USERDEF); + + /* check the sign bit (+/-) */ + result = TFA_GET_BF(tfa, DCMCCSB); + if (result == 0) { + /* Do not exceed the maximum value of 15 */ + if (currentValue + delta < 15) { + TFA_SET_BF_VOLATILE(tfa, DCMCC, currentValue + delta); + if (tfa->verbose) + pr_debug("Max coil current is set to: %d \n", currentValue + delta); + } + else { + TFA_SET_BF_VOLATILE(tfa, DCMCC, 15); + if (tfa->verbose) + pr_debug("Max coil current is set to: 15 \n"); + } + } + else if (result == 1) { + /* Do not exceed the minimum value of 0 */ + if (currentValue - delta > 0) { + TFA_SET_BF_VOLATILE(tfa, DCMCC, currentValue - delta); + if (tfa->verbose) + pr_debug("Max coil current is set to: %d \n", currentValue - delta); + } + else { + TFA_SET_BF_VOLATILE(tfa, DCMCC, 0); + if (tfa->verbose) + pr_debug("Max coil current is set to: 0 \n"); + } + } + } + + return Tfa98xx_Error_Ok; +} + +static enum Tfa98xx_Error +tfa9888_set_mute(struct tfa_device *tfa, int mute) +{ + TFA_SET_BF(tfa, CFSMR, (const uint16_t)mute); + TFA_SET_BF(tfa, CFSML, (const uint16_t)mute); + + return Tfa98xx_Error_Ok; +} + +void tfa9888_ops(struct tfa_device_ops *ops) +{ + /* Set defaults for ops */ + set_ops_defaults(ops); + + ops->tfa_init = tfa9888_specific; + ops->dsp_write_tables = tfa9888_tfa_dsp_write_tables; + ops->auto_copy_mtp_to_iic = tfa9888_auto_copy_mtp_to_iic; + ops->factory_trimmer = tfa9888_factory_trimmer; + ops->set_mute = tfa9888_set_mute; +} + +/***********************************************************************************/ +/* TFA9896 */ +/***********************************************************************************/ +static enum Tfa98xx_Error tfa9896_faim_protect(struct tfa_device *tfa, int status) +{ + enum Tfa98xx_Error ret = Tfa98xx_Error_Ok; + + if ( (tfa->rev == 0x2b96) || (tfa->rev == 0x3b96) ) { + ret = tfa_set_bf_volatile(tfa, TFA9896_BF_OPENMTP, (uint16_t)status); + } + + return ret; +} + +/***********************************************************************************/ +/* TFA9896 */ +/***********************************************************************************/ +static enum Tfa98xx_Error tfa9896_specific(struct tfa_device *tfa) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + unsigned short check_value; + + if (tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + + /* all i2C registers must already set to default POR value */ + + /* $48:[3] - 1 ==> 0; iddqtestbst - default value changed. + * When Iddqtestbst is set to "0", the slewrate is reduced. + * This will lower the overshoot on IN-B to avoid NMOS damage of booster. + */ + if (tfa->rev == 0x1b96) { + /* ----- generated code start v17 ----- */ + reg_write(tfa, 0x06, 0x000b); //POR=0x0001 + reg_write(tfa, 0x07, 0x3e7f); //POR=0x1e7f + reg_write(tfa, 0x0a, 0x0d8a); //POR=0x0592 + reg_write(tfa, 0x48, 0x0300); //POR=0x0308 + reg_write(tfa, 0x88, 0x0100); //POR=0x0000 + /* ----- generated code end ----- */ + } + else if (tfa->rev == 0x2b96) { + /* ----- generated code start ----- v1*/ + reg_write(tfa, 0x06, 0x000b); //POR=0x0001 + reg_write(tfa, 0x07, 0x3e7f); //POR=0x1e7f + reg_write(tfa, 0x0a, 0x0d8a); //POR=0x0592 + reg_write(tfa, 0x48, 0x0300); //POR=0x0308 + reg_write(tfa, 0x88, 0x0100); //POR=0x0000 + /* ----- generated code end ----- */ + } + else if (tfa->rev == 0x3b96) { + /* ----- generated code start ----- v1*/ + reg_write(tfa, 0x06, 0x000b); //POR=0x0001 + reg_write(tfa, 0x07, 0x3e7f); //POR=0x1e7f + reg_write(tfa, 0x0a, 0x0d8a); //POR=0x0592 + reg_write(tfa, 0x48, 0x0300); //POR=0x0308 + reg_write(tfa, 0x88, 0x0100); //POR=0x0000 + /* ----- generated code end ----- */ + } + /* $49:[0] - 1 ==> 0; CLIP - default value changed. 0 means CLIPPER on */ + error = reg_read(tfa, 0x49, &check_value); + check_value &= ~0x1; + error = reg_write(tfa, 0x49, check_value); + return error; +} + +/* +* the int24 values for the vsfw delay table +*/ +static unsigned char tfa9896_vsfwdelay_table[] = { + 0,0,2, /* Index 0 - Current/Volt Fractional Delay for 8KHz */ + 0,0,0, /* Index 1 - Current/Volt Fractional Delay for 11KHz */ + 0,0,0, /* Index 2 - Current/Volt Fractional Delay for 12KHz */ + 0,0,2, /* Index 3 - Current/Volt Fractional Delay for 16KHz */ + 0,0,2, /* Index 4 - Current/Volt Fractional Delay for 22KHz */ + 0,0,2, /* Index 5 - Current/Volt Fractional Delay for 24KHz */ + 0,0,2, /* Index 6 - Current/Volt Fractional Delay for 32KHz */ + 0,0,2, /* Index 7 - Current/Volt Fractional Delay for 44KHz */ + 0,0,3 /* Index 8 - Current/Volt Fractional Delay for 48KHz */ +}; + +/* +* TODO make this tfa98xx +* Note that the former products write this table via the patch +* so moving this to the tfa98xx API requires also updating all patches +*/ +static enum Tfa98xx_Error tfa9896_dsp_write_vsfwdelay_table(struct tfa_device *tfa) +{ + return tfa_dsp_cmd_id_write(tfa, MODULE_FRAMEWORK, TFA1_FW_PAR_ID_SET_CURRENT_DELAY, sizeof(tfa9896_vsfwdelay_table), tfa9896_vsfwdelay_table); +} + +/* +* The int24 values for the fracdelay table +* For now applicable only for 8 and 48 kHz +*/ +static unsigned char tfa9896_cvfracdelay_table[] = { + 0,0,51, /* Index 0 - Current/Volt Fractional Delay for 8KHz */ + 0,0, 0, /* Index 1 - Current/Volt Fractional Delay for 11KHz */ + 0,0, 0, /* Index 2 - Current/Volt Fractional Delay for 12KHz */ + 0,0,38, /* Index 3 - Current/Volt Fractional Delay for 16KHz */ + 0,0,34, /* Index 4 - Current/Volt Fractional Delay for 22KHz */ + 0,0,33, /* Index 5 - Current/Volt Fractional Delay for 24KHz */ + 0,0,11, /* Index 6 - Current/Volt Fractional Delay for 32KHz */ + 0,0,2, /* Index 7 - Current/Volt Fractional Delay for 44KHz */ + 0,0,62 /* Index 8 - Current/Volt Fractional Delay for 48KHz */ +}; + +static enum Tfa98xx_Error tfa9896_dsp_write_cvfracdelay_table(struct tfa_device *tfa) +{ + return tfa_dsp_cmd_id_write(tfa, MODULE_FRAMEWORK, TFA1_FW_PAR_ID_SET_CURFRAC_DELAY, sizeof(tfa9896_cvfracdelay_table), tfa9896_cvfracdelay_table);; +} + +static enum Tfa98xx_Error tfa9896_tfa_dsp_write_tables(struct tfa_device *tfa, int sample_rate) +{ + enum Tfa98xx_Error error; + + /* Not used for max1! */ + (void)sample_rate; + + error = tfa9896_dsp_write_vsfwdelay_table(tfa); + if (error == Tfa98xx_Error_Ok) { + error = tfa9896_dsp_write_cvfracdelay_table(tfa); + } + + return error; +} + +void tfa9896_ops(struct tfa_device_ops *ops) +{ + /* Set defaults for ops */ + set_ops_defaults(ops); + + ops->tfa_init = tfa9896_specific; + ops->dsp_write_tables = tfa9896_tfa_dsp_write_tables; + ops->faim_protect = tfa9896_faim_protect; +} + +/***********************************************************************************/ +/* TFA9897 */ +/***********************************************************************************/ +static enum Tfa98xx_Error tfa9897_specific(struct tfa_device *tfa) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + unsigned short check_value; + + if (tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + + /* all i2C registers must already set to default POR value */ + + /* $48:[3] - 1 ==> 0; iddqtestbst - default value changed. + * When Iddqtestbst is set to "0", the slewrate is reduced. + * This will lower the overshoot on IN-B to avoid NMOS damage of booster */ + error = reg_write(tfa, 0x48, 0x0300); /* POR value = 0x308 */ + + /* $49:[0] - 1 ==> 0; CLIP - default value changed. 0 means CLIPPER on */ + error = reg_read(tfa, 0x49, &check_value); + check_value &= ~0x1; + error = reg_write(tfa, 0x49, check_value); + + return error; +} + +/* +* the int24 values for the vsfw delay table +*/ +static unsigned char tfa9897_vsfwdelay_table[] = { + 0,0,2, /* Index 0 - Current/Volt Fractional Delay for 8KHz */ + 0,0,0, /* Index 1 - Current/Volt Fractional Delay for 11KHz */ + 0,0,0, /* Index 2 - Current/Volt Fractional Delay for 12KHz */ + 0,0,2, /* Index 3 - Current/Volt Fractional Delay for 16KHz */ + 0,0,2, /* Index 4 - Current/Volt Fractional Delay for 22KHz */ + 0,0,2, /* Index 5 - Current/Volt Fractional Delay for 24KHz */ + 0,0,2, /* Index 6 - Current/Volt Fractional Delay for 32KHz */ + 0,0,2, /* Index 7 - Current/Volt Fractional Delay for 44KHz */ + 0,0,3 /* Index 8 - Current/Volt Fractional Delay for 48KHz */ +}; + +/* +* TODO make this tfa98xx +* Note that the former products write this table via the patch +* so moving this to the tfa98xx API requires also updating all patches +*/ +static enum Tfa98xx_Error tfa9897_dsp_write_vsfwdelay_table(struct tfa_device *tfa) +{ + return tfa_dsp_cmd_id_write(tfa, MODULE_FRAMEWORK, TFA1_FW_PAR_ID_SET_CURRENT_DELAY, sizeof(tfa9897_vsfwdelay_table), tfa9897_vsfwdelay_table);; +} + +/* +* The int24 values for the fracdelay table +* For now applicable only for 8 and 48 kHz +*/ +static unsigned char tfa9897_cvfracdelay_table[] = { + 0,0,51, /* Index 0 - Current/Volt Fractional Delay for 8KHz */ + 0,0, 0, /* Index 1 - Current/Volt Fractional Delay for 11KHz */ + 0,0, 0, /* Index 2 - Current/Volt Fractional Delay for 12KHz */ + 0,0,38, /* Index 3 - Current/Volt Fractional Delay for 16KHz */ + 0,0,34, /* Index 4 - Current/Volt Fractional Delay for 22KHz */ + 0,0,33, /* Index 5 - Current/Volt Fractional Delay for 24KHz */ + 0,0,11, /* Index 6 - Current/Volt Fractional Delay for 32KHz */ + 0,0,2, /* Index 7 - Current/Volt Fractional Delay for 44KHz */ + 0,0,62 /* Index 8 - Current/Volt Fractional Delay for 48KHz */ +}; + +static enum Tfa98xx_Error tfa9897_dsp_write_cvfracdelay_table(struct tfa_device *tfa) +{ + return tfa_dsp_cmd_id_write(tfa, MODULE_FRAMEWORK, TFA1_FW_PAR_ID_SET_CURFRAC_DELAY, sizeof(tfa9897_cvfracdelay_table), tfa9897_cvfracdelay_table);; +} + +static enum Tfa98xx_Error tfa9897_tfa_dsp_write_tables(struct tfa_device *tfa, int sample_rate) +{ + enum Tfa98xx_Error error; + + /* Not used for max1! */ + (void)sample_rate; + + error = tfa9897_dsp_write_vsfwdelay_table(tfa); + if (error == Tfa98xx_Error_Ok) { + error = tfa9897_dsp_write_cvfracdelay_table(tfa); + } + + return error; +} + +void tfa9897_ops(struct tfa_device_ops *ops) +{ + /* Set defaults for ops */ + set_ops_defaults(ops); + + ops->tfa_init = tfa9897_specific; + ops->dsp_write_tables = tfa9897_tfa_dsp_write_tables; +} + +/***********************************************************************************/ +/* TFA9895 */ +/***********************************************************************************/ +static enum Tfa98xx_Error tfa9895_specific(struct tfa_device *tfa) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + int result; + + if(tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + + /* all i2C registers are already set to default */ + + result = TFA_SET_BF(tfa, AMPE, 1); + if (result < 0) + return -result; + + /* some other registers must be set for optimal amplifier behaviour */ + reg_write(tfa, 0x05, 0x13AB); + reg_write(tfa, 0x06, 0x001F); + /* peak voltage protection is always on, but may be written */ + reg_write(tfa, 0x08, 0x3C4E); + /*TFA98XX_SYSCTRL_DCA=0*/ + reg_write(tfa, 0x09, 0x024D); + reg_write(tfa, 0x41, 0x0308); + error = reg_write(tfa, 0x49, 0x0E82); + + return error; +} + +void tfa9895_ops(struct tfa_device_ops *ops) +{ + /* Set defaults for ops */ + set_ops_defaults(ops); + + ops->tfa_init = tfa9895_specific; +} + +/***********************************************************************************/ +/* TFA9891 */ +/***********************************************************************************/ +static enum Tfa98xx_Error tfa9891_specific(struct tfa_device *tfa) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + + if (tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + + /* ----- generated code start ----- */ + /* ----- version 18.0 ----- */ + reg_write(tfa, 0x09, 0x025d); //POR=0x024d + reg_write(tfa, 0x10, 0x0018); //POR=0x0024 + reg_write(tfa, 0x22, 0x0003); //POR=0x0023 + reg_write(tfa, 0x25, 0x0001); //POR=0x0000 + reg_write(tfa, 0x46, 0x0000); //POR=0x4000 + reg_write(tfa, 0x55, 0x3ffb); //POR=0x7fff + /* ----- generated code end ----- */ + + return error; +} + +void tfa9891_ops(struct tfa_device_ops *ops) +{ + /* Set defaults for ops */ + set_ops_defaults(ops); + + ops->tfa_init = tfa9891_specific; +} + +/***********************************************************************************/ +/* TFA9890 */ +/***********************************************************************************/ +static enum Tfa98xx_Error tfa9890_specific(struct tfa_device *tfa) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + unsigned short regRead = 0; + + if(tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + + /* all i2C registers are already set to default for N1C2 */ + + /* some PLL registers must be set optimal for amplifier behaviour */ + error = reg_write(tfa, 0x40, 0x5a6b); + if (error) + return error; + reg_read(tfa, 0x59, ®Read); + regRead |= 0x3; + reg_write(tfa, 0x59, regRead); + error = reg_write(tfa, 0x40, 0x0000); + error = reg_write(tfa, 0x47, 0x7BE1); + + return error; +} + +/* +* Disable clock gating +*/ +static enum Tfa98xx_Error tfa9890_clockgating(struct tfa_device *tfa, int on) +{ + enum Tfa98xx_Error error; + unsigned short value; + + /* for TFA9890 temporarily disable clock gating when dsp reset is used */ + error = reg_read(tfa, TFA98XX_CURRENTSENSE4, &value); + if (error) return error; + + if (Tfa98xx_Error_Ok == error) { + if (on) /* clock gating on - clear the bit */ + value &= ~TFA98XX_CURRENTSENSE4_CTRL_CLKGATECFOFF; + else /* clock gating off - set the bit */ + value |= TFA98XX_CURRENTSENSE4_CTRL_CLKGATECFOFF; + + error = reg_write(tfa, TFA98XX_CURRENTSENSE4, value); + } + + return error; +} + +/* +* Tfa9890_DspReset will deal with clock gating control in order +* to reset the DSP for warm state restart +*/ +static enum Tfa98xx_Error tfa9890_dsp_reset(struct tfa_device *tfa, int state) +{ + enum Tfa98xx_Error error; + + /* for TFA9890 temporarily disable clock gating + when dsp reset is used */ + tfa9890_clockgating(tfa, 0); + + TFA_SET_BF(tfa, RST, (uint16_t)state); + + /* clock gating restore */ + error = tfa9890_clockgating(tfa, 1); + + return error; +} + +/* + * Tfa9890_DspSystemStable will compensate for the wrong behavior of CLKS + * to determine if the DSP subsystem is ready for patch and config loading. + * + * A MTP calibration register is checked for non-zero. + * + * Note: This only works after i2c reset as this will clear the MTP contents. + * When we are configured then the DSP communication will synchronize access. + * + */ +static enum Tfa98xx_Error tfa9890_dsp_system_stable(struct tfa_device *tfa, int *ready) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + unsigned short status, mtp0; + int result, tries; + + /* check the contents of the STATUS register */ + result = TFA_READ_REG(tfa, AREFS); + if (result < 0) { + error = -result; + goto errorExit; + } + status = (unsigned short)result; + + /* if AMPS is set then we were already configured and running + * no need to check further + */ + *ready = (TFA_GET_BF_VALUE(tfa, AMPS, status) == 1); + if (*ready) /* if ready go back */ + return error; /* will be Tfa98xx_Error_Ok */ + + /* check AREFS and CLKS: not ready if either is clear */ + *ready = !((TFA_GET_BF_VALUE(tfa, AREFS, status) == 0) + || (TFA_GET_BF_VALUE(tfa, CLKS, status) == 0)); + if (!*ready) /* if not ready go back */ + return error; /* will be Tfa98xx_Error_Ok */ + + /* check MTPB + * mtpbusy will be active when the subsys copies MTP to I2C + * 2 times retry avoids catching this short mtpbusy active period + */ + for (tries = 2; tries > 0; tries--) { + result = TFA_GET_BF(tfa, MTPB);/*TODO_MTPB*/ + if (result < 0) { + error = -result; + goto errorExit; + } + status = (unsigned short)result; + + /* check the contents of the STATUS register */ + *ready = (result == 0); + if (*ready) /* if ready go on */ + break; + } + if (tries == 0) /* ready will be 0 if retries exausted */ + return Tfa98xx_Error_Ok; + + /* check the contents of MTP register for non-zero, + * this indicates that the subsys is ready */ + + error = reg_read(tfa, 0x84, &mtp0); + if (error) + goto errorExit; + + *ready = (mtp0 != 0); /* The MTP register written? */ + + return error; + +errorExit: + *ready = 0; + return error; +} + +void tfa9890_ops(struct tfa_device_ops *ops) +{ + /* Set defaults for ops */ + set_ops_defaults(ops); + + ops->tfa_init = tfa9890_specific; + ops->dsp_reset = tfa9890_dsp_reset; + ops->dsp_system_stable = tfa9890_dsp_system_stable; +} + +/***********************************************************************************/ +/* TFA9894 */ +/***********************************************************************************/ +static int tfa9894_set_swprofile(struct tfa_device *tfa, unsigned short new_value) +{ + int active_value = tfa_dev_get_swprof(tfa); + + /* Set the new value in the struct */ + tfa->profile = new_value - 1; + + /* Set the new value in the hw register */ + tfa_set_bf_volatile(tfa, TFA9894_BF_SWPROFIL, new_value); + + return active_value; +} + +static int tfa9894_get_swprofile(struct tfa_device *tfa) +{ + return tfa_get_bf(tfa, TFA9894_BF_SWPROFIL) - 1; +} + +static int tfa9894_set_swvstep(struct tfa_device *tfa, unsigned short new_value) +{ + /* Set the new value in the struct */ + tfa->vstep = new_value-1; + + /* Set the new value in the hw register */ + tfa_set_bf_volatile(tfa, TFA9894_BF_SWVSTEP, new_value); + + return new_value; +} + +static int tfa9894_get_swvstep(struct tfa_device *tfa) +{ + return tfa_get_bf(tfa, TFA9894_BF_SWVSTEP) - 1; +} + +static int tfa9894_get_mtpb(struct tfa_device *tfa) { + + int value = 0; + + /* Set the new value in the hw register */ + value = tfa_get_bf(tfa, TFA9894_BF_MTPB); + + return value; +} + +/** Set internal oscillator into power down mode for TFA9894. +* +* This function is a worker for tfa98xx_set_osc_powerdown(). +* +* @param[in] tfa device description structure +* @param[in] state new state 0 - oscillator is on, 1 oscillator is off. +* +* @return Tfa98xx_Error_Ok when successfull, error otherwise. +*/ +static enum Tfa98xx_Error tfa9894_set_osc_powerdown(struct tfa_device *tfa, int state) +{ + if (state == 1 || state == 0) { + return -tfa_set_bf(tfa, TFA9894_BF_MANAOOSC, (uint16_t)state); + } + + return Tfa98xx_Error_Bad_Parameter; +} + +static enum Tfa98xx_Error tfa9894_faim_protect(struct tfa_device *tfa, int status) +{ + enum Tfa98xx_Error ret = Tfa98xx_Error_Ok; + /* 0b = FAIM protection enabled 1b = FAIM protection disabled*/ + ret = tfa_set_bf_volatile(tfa, TFA9894_BF_OPENMTP, (uint16_t)(status)); + return ret; +} + +static enum Tfa98xx_Error tfa9894_specific(struct tfa_device *tfa) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + unsigned short value, xor; + + if (tfa->in_use == 0) + return Tfa98xx_Error_NotOpen; + + /* Unlock keys to write settings */ + error = reg_write(tfa, 0x0F, 0x5A6B); + error = reg_read(tfa, 0xFB, &value); + xor = value ^ 0x005A; + error = reg_write(tfa, 0xA0, xor); + + /* The optimal settings */ + if (tfa->rev == 0x0a94) { + /* V36 */ + /* ----- generated code start ----- */ + reg_write(tfa, 0x00, 0xa245); //POR=0x8245 + reg_write(tfa, 0x02, 0x51e8); //POR=0x55c8 + reg_write(tfa, 0x52, 0xbe17); //POR=0xb617 + reg_write(tfa, 0x57, 0x0344); //POR=0x0366 + reg_write(tfa, 0x61, 0x0033); //POR=0x0073 + reg_write(tfa, 0x71, 0x00cf); //POR=0x018d + reg_write(tfa, 0x72, 0x34a9); //POR=0x44e8 + reg_write(tfa, 0x73, 0x3808); //POR=0x3806 + reg_write(tfa, 0x76, 0x0067); //POR=0x0065 + reg_write(tfa, 0x80, 0x0000); //POR=0x0003 + reg_write(tfa, 0x81, 0x5715); //POR=0x561a + reg_write(tfa, 0x82, 0x0104); //POR=0x0044 + /* ----- generated code end ----- */ + } else if (tfa->rev == 0x1a94) { + /* V14 */ + /* ----- generated code start ----- */ + reg_write(tfa, 0x00, 0xa245); //POR=0x8245 + reg_write(tfa, 0x01, 0x15da); //POR=0x11ca + reg_write(tfa, 0x02, 0x5288); //POR=0x55c8 + reg_write(tfa, 0x52, 0xbe17); //POR=0xb617 + reg_write(tfa, 0x53, 0x0dbe); //POR=0x0d9e + reg_write(tfa, 0x56, 0x05c3); //POR=0x07c3 + reg_write(tfa, 0x57, 0x0344); //POR=0x0366 + reg_write(tfa, 0x61, 0x0032); //POR=0x0073 + reg_write(tfa, 0x71, 0x00cf); //POR=0x018d + reg_write(tfa, 0x72, 0x34a9); //POR=0x44e8 + reg_write(tfa, 0x73, 0x38c8); //POR=0x3806 + reg_write(tfa, 0x76, 0x0067); //POR=0x0065 + reg_write(tfa, 0x80, 0x0000); //POR=0x0003 + reg_write(tfa, 0x81, 0x5799); //POR=0x561a + reg_write(tfa, 0x82, 0x0104); //POR=0x0044 + /* ----- generated code end ----- */ + + } + + return error; +} + +static enum Tfa98xx_Error +tfa9894_set_mute(struct tfa_device *tfa, int mute) +{ + tfa_set_bf(tfa, TFA9894_BF_CFSM, (const uint16_t)mute); + + return Tfa98xx_Error_Ok; +} + +static enum Tfa98xx_Error tfa9894_dsp_system_stable(struct tfa_device *tfa, int *ready) +{ + enum Tfa98xx_Error error = Tfa98xx_Error_Ok; + + /* check CLKS: ready if set */ + *ready = tfa_get_bf(tfa, TFA9894_BF_CLKS)==1; + + return error; +} + +void tfa9894_ops(struct tfa_device_ops *ops) +{ + /* Set defaults for ops */ + set_ops_defaults(ops); + + ops->tfa_init = tfa9894_specific; + ops->dsp_system_stable = tfa9894_dsp_system_stable; + ops->set_mute = tfa9894_set_mute; + ops->faim_protect = tfa9894_faim_protect; + ops->get_mtpb = tfa9894_get_mtpb; + ops->set_swprof = tfa9894_set_swprofile; + ops->get_swprof = tfa9894_get_swprofile; + ops->set_swvstep = tfa9894_set_swvstep; + ops->get_swvstep = tfa9894_get_swvstep; + //ops->auto_copy_mtp_to_iic = tfa9894_auto_copy_mtp_to_iic; + ops->set_osc_powerdown = tfa9894_set_osc_powerdown; +} diff --git a/techpack/audio/asoc/codecs/tfa9874/tfa_internal.h b/techpack/audio/asoc/codecs/tfa9874/tfa_internal.h new file mode 100644 index 000000000000..9e8b35d3be76 --- /dev/null +++ b/techpack/audio/asoc/codecs/tfa9874/tfa_internal.h @@ -0,0 +1,39 @@ +/* + * Copyright 2014-2017 NXP Semiconductors + * + * 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. + */ + +/* + internal functions for TFA layer (not shared with SRV and HAL layer!) +*/ + +#ifndef __TFA_INTERNAL_H__ +#define __TFA_INTERNAL_H__ + +#include "tfa_dsp_fw.h" +#include "tfa_ext.h" + +#if __GNUC__ >= 4 + #define TFA_INTERNAL __attribute__ ((visibility ("hidden"))) +#else + #define TFA_INTERNAL +#endif + +#define TFA98XX_GENERIC_SLAVE_ADDRESS 0x1C + +TFA_INTERNAL enum Tfa98xx_Error tfa98xx_check_rpc_status(struct tfa_device *tfa, int *pRpcStatus); +TFA_INTERNAL enum Tfa98xx_Error tfa98xx_wait_result(struct tfa_device *tfa, int waitRetryCount); + +#endif /* __TFA_INTERNAL_H__ */ + diff --git a/techpack/audio/asoc/codecs/tfa9874/tfa_service.h b/techpack/audio/asoc/codecs/tfa9874/tfa_service.h new file mode 100644 index 000000000000..64ae22f27984 --- /dev/null +++ b/techpack/audio/asoc/codecs/tfa9874/tfa_service.h @@ -0,0 +1,1021 @@ +/* + * Copyright 2014-2017 NXP Semiconductors + * + * 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 TFA_SERVICE_H +#define TFA_SERVICE_H + +//#include "config.h" +// workaround for Visual Studio: +// fatal error C1083: Cannot open include file: 'config.h': No such file or directory +#ifdef __KERNEL__ +#include +#else +#include +#endif +#ifdef __cplusplus +extern "C" { +#include "NXP_I2C.h" +#endif + +/* Linux kernel module defines TFA98XX_GIT_VERSIONS in the linux_driver/Makefile */ +#if !defined(TFA98XX_GIT_VERSIONS) +#include "versions.h" +#endif +#ifdef TFA98XX_GIT_VERSIONS + #define TFA98XX_API_REV_STR TFA98XX_GIT_VERSIONS +#else + #define TFA98XX_API_REV_STR "v6.5.2" +#endif + +#include "tfa_device.h" + +/* + * data previously defined in Tfa9888_dsp.h + */ +#define MEMTRACK_MAX_WORDS 150 +#define LSMODEL_MAX_WORDS 150 +#define TFA98XX_MAXTAG (150) +#define FW_VAR_API_VERSION (521) + +/* Indexes and scaling factors of GetLSmodel */ +#define tfa9888_fs_IDX 128 +#define tfa9888_leakageFactor_IDX 130 +#define tfa9888_ReCorrection_IDX 131 +#define tfa9888_Bl_IDX 132 +#define ReZ_IDX 147 + +#define tfa9872_leakageFactor_IDX 128 +#define tfa9872_ReCorrection_IDX 129 +#define tfa9872_Bl_IDX 130 + +#define fs_SCALE (double)1 +#define leakageFactor_SCALE (double)8388608 +#define ReCorrection_SCALE (double)8388608 +#define Bl_SCALE (double)2097152 +#define tCoef_SCALE (double)8388608 + +/* ---------------------------- Max1 ---------------------------- */ +/* Headroom applied to the main input signal */ +#define SPKRBST_HEADROOM 7 +/* Exponent used for AGC Gain related variables */ +#define SPKRBST_AGCGAIN_EXP SPKRBST_HEADROOM +#define SPKRBST_TEMPERATURE_EXP 9 +/* Exponent used for Gain Corection related variables */ +#define SPKRBST_LIMGAIN_EXP 4 +#define SPKRBST_TIMECTE_EXP 1 +#define DSP_MAX_GAIN_EXP 7 +/* -------------------------------------------------------------- */ + +/* speaker related parameters */ +#define TFA2_SPEAKERPARAMETER_LENGTH (3*151) /* MAX2=450 */ +#define TFA1_SPEAKERPARAMETER_LENGTH (3*141) /* MAX1=423 */ + +/* vstep related parameters */ +#define TFA2_ALGOPARAMETER_LENGTH (3*304) /* N1B = (304) 305 is including the cmd-id */ +#define TFA72_ALGOPARAMETER_LENGTH_MONO (3*183) +#define TFA72_ALGOPARAMETER_LENGTH_STEREO (3*356) +#define TFA2_MBDRCPARAMETER_LENGTH (3*152) /* 154 is including the cmd-id */ +#define TFA72_MBDRCPARAMETER_LENGTH (3*98) +#define TFA1_PRESET_LENGTH 87 +#define TFA1_DRC_LENGTH 381 /* 127 words */ +#define TFA2_FILTERCOEFSPARAMETER_LENGTH (3*168) /* 170 is including the cmd-id */ +#define TFA72_FILTERCOEFSPARAMETER_LENGTH (3*156) + +/* Maximum number of retries for DSP result + * Keep this value low! + * If certain calls require longer wait conditions, the + * application should poll, not the API + * The total wait time depends on device settings. Those + * are application specific. + */ +#define TFA98XX_WAITRESULT_NTRIES 40 +#define TFA98XX_WAITRESULT_NTRIES_LONG 2000 + +/* following lengths are in bytes */ +#define TFA98XX_PRESET_LENGTH 87 +#define TFA98XX_CONFIG_LENGTH 201 +#define TFA98XX_DRC_LENGTH 381 /* 127 words */ + +typedef unsigned char Tfa98xx_Config_t[TFA98XX_CONFIG_LENGTH]; +typedef unsigned char Tfa98xx_Preset_t[TFA98XX_PRESET_LENGTH]; +typedef unsigned char Tfa98xx_DrcParameters_t[TFA98XX_DRC_LENGTH]; + +/* Type containing all the possible errors that can occur + * + */ +enum Tfa98xx_Error { + Tfa98xx_Error_Ok = 0, + Tfa98xx_Error_Device, /* 1. Currently only used to keep in sync with tfa_error */ + Tfa98xx_Error_Bad_Parameter, /* 2. */ + Tfa98xx_Error_Fail, /* 3. generic failure, avoid mislead message */ + Tfa98xx_Error_NoClock, /* 4. no clock detected */ + Tfa98xx_Error_StateTimedOut, /* 5. */ + Tfa98xx_Error_DSP_not_running, /* 6. communication with the DSP failed */ + Tfa98xx_Error_AmpOn, /* 7. amp is still running */ + Tfa98xx_Error_NotOpen, /* 8. the given handle is not open */ + Tfa98xx_Error_InUse, /* 9. too many handles */ + Tfa98xx_Error_Buffer_too_small, /* 10. if a buffer is too small */ + /* the expected response did not occur within the expected time */ + Tfa98xx_Error_RpcBase = 100, + Tfa98xx_Error_RpcBusy = 101, + Tfa98xx_Error_RpcModId = 102, + Tfa98xx_Error_RpcParamId = 103, + Tfa98xx_Error_RpcInvalidCC = 104, + Tfa98xx_Error_RpcInvalidSeq = 105, + Tfa98xx_Error_RpcInvalidParam = 106, + Tfa98xx_Error_RpcBufferOverflow = 107, + Tfa98xx_Error_RpcCalibBusy = 108, + Tfa98xx_Error_RpcCalibFailed = 109, + Tfa98xx_Error_Not_Implemented, + Tfa98xx_Error_Not_Supported, + Tfa98xx_Error_I2C_Fatal, /* Fatal I2C error occurred */ + /* Nonfatal I2C error, and retry count reached */ + Tfa98xx_Error_I2C_NonFatal, + Tfa98xx_Error_Other = 1000 +}; + +/* + * Type containing all the possible msg returns DSP can give + * //TODO move to tfa_dsp_fw.h + */ +enum Tfa98xx_Status_ID { + Tfa98xx_DSP_Not_Running = -1, /* No response from DSP */ + Tfa98xx_I2C_Req_Done = 0, /* Request executed correctly and result, if any, is available for download */ + Tfa98xx_I2C_Req_Busy = 1, /* Request is being processed, just wait for result */ + Tfa98xx_I2C_Req_Invalid_M_ID = 2, /* Provided M-ID does not fit in valid rang [0..2] */ + Tfa98xx_I2C_Req_Invalid_P_ID = 3, /* Provided P-ID isn�t valid in the given M-ID context */ + Tfa98xx_I2C_Req_Invalid_CC = 4, /* Invalid channel configuration bits (SC|DS|DP|DC) combination */ + Tfa98xx_I2C_Req_Invalid_Seq = 5, /* Invalid sequence of commands, in case the DSP expects some commands in a specific order */ + Tfa98xx_I2C_Req_Invalid_Param = 6, /* Generic error */ + Tfa98xx_I2C_Req_Buffer_Overflow = 7, /* I2C buffer has overflowed: host has sent too many parameters, memory integrity is not guaranteed */ + Tfa98xx_I2C_Req_Calib_Busy = 8, /* Calibration not finished */ + Tfa98xx_I2C_Req_Calib_Failed = 9 /* Calibration failed */ +}; + +/* + * speaker as microphone + */ +enum Tfa98xx_saam { + Tfa98xx_saam_none, /*< SAAM feature not available */ + Tfa98xx_saam /*< SAAM feature available */ +}; + +/* + * config file subtypes + */ +enum Tfa98xx_config_type { + Tfa98xx_config_generic, + Tfa98xx_config_sub1, + Tfa98xx_config_sub2, + Tfa98xx_config_sub3, +}; + +enum Tfa98xx_AmpInputSel { + Tfa98xx_AmpInputSel_I2SLeft, + Tfa98xx_AmpInputSel_I2SRight, + Tfa98xx_AmpInputSel_DSP +}; + +enum Tfa98xx_OutputSel { + Tfa98xx_I2SOutputSel_CurrentSense, + Tfa98xx_I2SOutputSel_DSP_Gain, + Tfa98xx_I2SOutputSel_DSP_AEC, + Tfa98xx_I2SOutputSel_Amp, + Tfa98xx_I2SOutputSel_DataI3R, + Tfa98xx_I2SOutputSel_DataI3L, + Tfa98xx_I2SOutputSel_DcdcFFwdCur, +}; + +enum Tfa98xx_StereoGainSel { + Tfa98xx_StereoGainSel_Left, + Tfa98xx_StereoGainSel_Right +}; + +#define TFA98XX_MAXPATCH_LENGTH (3*1024) + +/* the number of biquads supported */ +#define TFA98XX_BIQUAD_NUM 10 + +enum Tfa98xx_Channel { + Tfa98xx_Channel_L, + Tfa98xx_Channel_R, + Tfa98xx_Channel_L_R, + Tfa98xx_Channel_Stereo +}; + +enum Tfa98xx_Mode { + Tfa98xx_Mode_Normal = 0, + Tfa98xx_Mode_RCV +}; + +enum Tfa98xx_Mute { + Tfa98xx_Mute_Off, + Tfa98xx_Mute_Digital, + Tfa98xx_Mute_Amplifier +}; + +enum Tfa98xx_SpeakerBoostStatusFlags { + Tfa98xx_SpeakerBoost_Activity = 0, /* Input signal activity. */ + Tfa98xx_SpeakerBoost_S_Ctrl, /* S Control triggers the limiter */ + Tfa98xx_SpeakerBoost_Muted, /* 1 when signal is muted */ + Tfa98xx_SpeakerBoost_X_Ctrl, /* X Control triggers the limiter */ + Tfa98xx_SpeakerBoost_T_Ctrl, /* T Control triggers the limiter */ + Tfa98xx_SpeakerBoost_NewModel, /* New model is available */ + Tfa98xx_SpeakerBoost_VolumeRdy, /* 0:stable vol, 1:still smoothing */ + Tfa98xx_SpeakerBoost_Damaged, /* Speaker Damage detected */ + Tfa98xx_SpeakerBoost_SignalClipping /* input clipping detected */ +}; + +struct Tfa98xx_DrcStateInfo { + float GRhighDrc1[2]; + float GRhighDrc2[2]; + float GRmidDrc1[2]; + float GRmidDrc2[2]; + float GRlowDrc1[2]; + float GRlowDrc2[2]; + float GRpostDrc1[2]; + float GRpostDrc2[2]; + float GRblDrc[2]; +}; +struct Tfa98xx_StateInfo { + /* SpeakerBoost State */ + float agcGain; /* Current AGC Gain value */ + float limGain; /* Current Limiter Gain value */ + float sMax; /* Current Clip/Lim threshold */ + int T; /* Current Speaker Temperature value */ + int statusFlag; /* Masked bit word */ + float X1; /* estimated excursion caused by Spkrboost gain ctrl */ + float X2; /* estimated excursion caused by manual gain setting */ + float Re; /* Loudspeaker blocked resistance */ + /* Framework state */ + /* increments each time a MIPS problem is detected on the DSP */ + int shortOnMips; + struct Tfa98xx_DrcStateInfo drcState; /* DRC state, when enabled */ +}; + +typedef struct nxpTfaMsg { + uint8_t msg_size; + unsigned char cmdId[3]; + int data[9]; +} nxpTfaMsg_t; + +typedef struct nxp_vstep_msg { + int fw_version; + uint8_t no_of_vsteps; + uint16_t reg_no; + uint8_t *msg_reg; + uint8_t msg_no; + uint32_t algo_param_length; + uint8_t *msg_algo_param; + uint32_t filter_coef_length; + uint8_t *msg_filter_coef; + uint32_t mbdrc_length; + uint8_t *msg_mbdrc; +} nxp_vstep_msg_t; + +typedef struct nxpTfaGroup { + uint8_t msg_size; + uint8_t profileId[64]; +} nxpTfaGroup_t; + + +struct nxpTfa98xx_Memtrack_data { + int length; + float mValues[MEMTRACK_MAX_WORDS]; + int mAdresses[MEMTRACK_MAX_WORDS]; + int trackers[MEMTRACK_MAX_WORDS]; + int scalingFactor[MEMTRACK_MAX_WORDS]; +}; + +/* possible memory values for DMEM in CF_CONTROLs */ +enum Tfa98xx_DMEM { + Tfa98xx_DMEM_ERR = -1, + Tfa98xx_DMEM_PMEM = 0, + Tfa98xx_DMEM_XMEM = 1, + Tfa98xx_DMEM_YMEM = 2, + Tfa98xx_DMEM_IOMEM = 3, +}; + +/** + * lookup the device type and return the family type + */ +int tfa98xx_dev2family(int dev_type); + +/** + * register definition structure + */ +struct regdef { + unsigned char offset; /**< subaddress offset */ + unsigned short pwronDefault; /**< register contents after poweron */ + unsigned short pwronTestmask; /**< mask of bits not test */ + char *name; /**< short register name */ +}; + +enum Tfa98xx_DMEM tfa98xx_filter_mem(struct tfa_device *tfa, int filter_index, unsigned short *address, int channel); + +/** + * Load the default HW settings in the device + * @param tfa the device struct pointer + */ +enum Tfa98xx_Error tfa98xx_init(struct tfa_device *tfa); + +/** + * If needed, this function can be used to get a text version of the status ID code + * @param status the given status ID code + * @return the I2C status ID string + */ +const char *tfa98xx_get_i2c_status_id_string(int status); + +/* control the powerdown bit + * @param tfa the device struct pointer + * @param powerdown must be 1 or 0 + */ +enum Tfa98xx_Error tfa98xx_powerdown(struct tfa_device *tfa, int powerdown); + +/* indicates on which channel of DATAI2 the gain from the IC is set + * @param tfa the device struct pointer + * @param gain_sel, see Tfa98xx_StereoGainSel_t + */ +enum Tfa98xx_Error tfa98xx_select_stereo_gain_channel(struct tfa_device *tfa, + enum Tfa98xx_StereoGainSel gain_sel); + +/** + * set the mtp with user controllable values + * @param tfa the device struct pointer + * @param value to be written + * @param mask to be applied toi the bits affected + */ +enum Tfa98xx_Error tfa98xx_set_mtp(struct tfa_device *tfa, uint16_t value, uint16_t mask); +enum Tfa98xx_Error tfa98xx_get_mtp(struct tfa_device *tfa, uint16_t *value); + +/** + * lock or unlock KEY2 + * lock = 1 will lock + * lock = 0 will unlock + * note that on return all the hidden key will be off + */ +void tfa98xx_key2(struct tfa_device *tfa, int lock); + +int tfa_calibrate(struct tfa_device *tfa) ; +void tfa98xx_set_exttemp(struct tfa_device *tfa, short ext_temp); +short tfa98xx_get_exttemp(struct tfa_device *tfa); + +/* control the volume of the DSP + * @param vol volume in bit field. It must be between 0 and 255 + */ +enum Tfa98xx_Error tfa98xx_set_volume_level(struct tfa_device *tfa, + unsigned short vol); + +/* set the input channel to use + * @param channel see Tfa98xx_Channel_t enumeration + */ +enum Tfa98xx_Error tfa98xx_select_channel(struct tfa_device *tfa, + enum Tfa98xx_Channel channel); + +/* set the mode for normal or receiver mode + * @param mode see Tfa98xx_Mode enumeration + */ +enum Tfa98xx_Error tfa98xx_select_mode(struct tfa_device *tfa, enum Tfa98xx_Mode mode ); + +/* mute/unmute the audio + * @param mute see Tfa98xx_Mute_t enumeration + */ +enum Tfa98xx_Error tfa98xx_set_mute(struct tfa_device *tfa, + enum Tfa98xx_Mute mute); + +/* + * tfa_supported_speakers - required for SmartStudio initialization + * returns the number of the supported speaker count + */ +enum Tfa98xx_Error tfa_supported_speakers(struct tfa_device *tfa, int* spkr_count); + +/** +* Return the tfa revision +*/ +void tfa98xx_rev(int *major, int *minor, int *revision); + +/* + * Return the feature bits from MTP and cnt file for comparison + */ +enum Tfa98xx_Error +tfa98xx_compare_features(struct tfa_device *tfa, int features_from_MTP[3], int features_from_cnt[3]); + +/* + * return feature bits + */ +enum Tfa98xx_Error +tfa98xx_dsp_get_sw_feature_bits(struct tfa_device *tfa, int features[2]); +enum Tfa98xx_Error +tfa98xx_dsp_get_hw_feature_bits(struct tfa_device *tfa, int *features); + +/* + * tfa98xx_supported_saam + * returns the speaker as microphone feature + * @param saam enum pointer + * @return error code + */ +enum Tfa98xx_Error tfa98xx_supported_saam(struct tfa_device *tfa, enum Tfa98xx_saam *saam); + +/* load the tables to the DSP + * called after patch load is done + * @return error code + */ +enum Tfa98xx_Error tfa98xx_dsp_write_tables(struct tfa_device *tfa, int sample_rate); + + +/* set or clear DSP reset signal + * @param new state + * @return error code + */ +enum Tfa98xx_Error tfa98xx_dsp_reset(struct tfa_device *tfa, int state); + +/* check the state of the DSP subsystem + * return ready = 1 when clocks are stable to allow safe DSP subsystem access + * @param tfa the device struct pointer + * @param ready pointer to state flag, non-zero if clocks are not stable + * @return error code + */ +enum Tfa98xx_Error tfa98xx_dsp_system_stable(struct tfa_device *tfa, int *ready); + +enum Tfa98xx_Error tfa98xx_auto_copy_mtp_to_iic(struct tfa_device *tfa); + +/** + * check the state of the DSP coolflux + * @param tfa the device struct pointer + * @return the value of CFE + */ +int tfa_cf_enabled(struct tfa_device *tfa); + +/* The following functions can only be called when the DSP is running + * - I2S clock must be active, + * - IC must be in operating mode + */ + +/** + * patch the ROM code of the DSP + * @param tfa the device struct pointer + * @param patchLength the number of bytes of patchBytes + * @param patchBytes pointer to the bytes to patch + */ +enum Tfa98xx_Error tfa_dsp_patch(struct tfa_device *tfa, + int patchLength, + const unsigned char *patchBytes); + +/** + * load explicitly the speaker parameters in case of free speaker, + * or when using a saved speaker model + */ +enum Tfa98xx_Error tfa98xx_dsp_write_speaker_parameters( + struct tfa_device *tfa, + int length, + const unsigned char *pSpeakerBytes); + +/** + * read the speaker parameters as used by the SpeakerBoost processing + */ +enum Tfa98xx_Error tfa98xx_dsp_read_speaker_parameters( + struct tfa_device *tfa, + int length, + unsigned char *pSpeakerBytes); + +/** + * read the current status of the DSP, typically used for development, + * not essential to be used in a product + */ +enum Tfa98xx_Error tfa98xx_dsp_get_state_info( + struct tfa_device *tfa, + unsigned char bytes[], + unsigned int *statesize); + +/** + * Check whether the DSP supports DRC + * pbSupportDrc=1 when DSP supports DRC, + * pbSupportDrc=0 when DSP doesn't support it + */ +enum Tfa98xx_Error tfa98xx_dsp_support_drc(struct tfa_device *tfa, + int *pbSupportDrc); + +enum Tfa98xx_Error +tfa98xx_dsp_support_framework(struct tfa_device *tfa, int *pbSupportFramework); + +/** + * read the speaker excursion model as used by SpeakerBoost processing + */ +enum Tfa98xx_Error tfa98xx_dsp_read_excursion_model( + struct tfa_device *tfa, + int length, + unsigned char *pSpeakerBytes); + +/** + * load all the parameters for a preset from a file + */ +enum Tfa98xx_Error tfa98xx_dsp_write_preset(struct tfa_device *tfa, + int length, const unsigned char + *pPresetBytes); + +/** + * wrapper for dsp_msg that adds opcode and only writes + */ +enum Tfa98xx_Error tfa_dsp_cmd_id_write(struct tfa_device *tfa, + unsigned char module_id, + unsigned char param_id, int num_bytes, + const unsigned char data[]); + +/** + * wrapper for dsp_msg that writes opcode and reads back the data + */ +enum Tfa98xx_Error tfa_dsp_cmd_id_write_read(struct tfa_device *tfa, + unsigned char module_id, + unsigned char param_id, int num_bytes, + unsigned char data[]); + +/** + * wrapper for dsp_msg that adds opcode and 3 bytes required for coefs + */ +enum Tfa98xx_Error tfa_dsp_cmd_id_coefs(struct tfa_device *tfa, + unsigned char module_id, + unsigned char param_id, int num_bytes, + unsigned char data[]); + +/** + * wrapper for dsp_msg that adds opcode and 3 bytes required for MBDrcDynamics + */ +enum Tfa98xx_Error tfa_dsp_cmd_id_MBDrc_dynamics(struct tfa_device *tfa, + unsigned char module_id, + unsigned char param_id, int index_subband, + int num_bytes, unsigned char data[]); + +/** + * Disable a certain biquad. + * @param tfa the device struct pointer + * @param biquad_index: 1-10 of the biquad that needs to be adressed +*/ +enum Tfa98xx_Error Tfa98xx_DspBiquad_Disable(struct tfa_device *tfa, + int biquad_index); + +/** + * fill the calibration value as milli ohms in the struct + * assume that the device has been calibrated + */ +enum Tfa98xx_Error +tfa_dsp_get_calibration_impedance(struct tfa_device *tfa); + +/* + * return the mohm value + */ +int tfa_get_calibration_info(struct tfa_device *tfa, int channel); + +/* + * return sign extended tap pattern + */ +int tfa_get_tap_pattern(struct tfa_device *tfa); + +/** + * Reads a number of words from dsp memory + * @param tfa the device struct pointer + * @param subaddress write address to set in address register + * @param pValue pointer to read data +*/ +enum Tfa98xx_Error tfa98xx_read_register16(struct tfa_device *tfa, + unsigned char subaddress, + unsigned short *pValue); + +/** + * Reads a number of words from dsp memory + * @param tfa the device struct pointer + * @param subaddress write address to set in address register + * @param value value to write int the memory +*/ +enum Tfa98xx_Error tfa98xx_write_register16(struct tfa_device *tfa, + unsigned char subaddress, + unsigned short value); + +/** + * Intialise the dsp + * @param tfa the device struct pointer + * @return tfa error enum +*/ +enum Tfa98xx_Error +tfa98xx_init_dsp(struct tfa_device *tfa); + +/** + * Get the status of the external DSP + * @param tfa the device struct pointer + * @return status +*/ +int tfa98xx_get_dsp_status(struct tfa_device *tfa); + +/** + * Write a command message (RPC) to the dsp + * @param tfa the device struct pointer + * @param num_bytes command buffer size in bytes + * @param command_buffer + * @return tfa error enum +*/ +enum Tfa98xx_Error +tfa98xx_write_dsp(struct tfa_device *tfa, int num_bytes, const char *command_buffer); + +/** + * Read the result from the last message from the dsp + * @param tfa the device struct pointer + * @param num_bytes result buffer size in bytes + * @param result_buffer + * @return tfa error enum +*/ +enum Tfa98xx_Error +tfa98xx_read_dsp(struct tfa_device *tfa, int num_bytes, unsigned char *result_buffer); + +/** + * Write a command message (RPC) to the dsp and return the result + * @param tfa the device struct pointer + * @param command_length command buffer size in bytes + * @param command_buffer command buffer + * @param result_length result buffer size in bytes + * @param result_buffer result buffer + * @return tfa error enum +*/ +enum Tfa98xx_Error +tfa98xx_writeread_dsp(struct tfa_device *tfa, int command_length, void *command_buffer, + int result_length, void *result_buffer); + +/** + * Reads a number of words from dsp memory + * @param tfa the device struct pointer + * @param start_offset offset from where to start reading + * @param num_words number of words to read + * @param pValues pointer to read data +*/ +enum Tfa98xx_Error tfa98xx_dsp_read_mem(struct tfa_device *tfa, + unsigned int start_offset, + int num_words, int *pValues); +/** + * Write a value to dsp memory + * @param tfa the device struct pointer + * @param address write address to set in address register + * @param value value to write int the memory + * @param memtype type of memory to write to +*/ +enum Tfa98xx_Error tfa98xx_dsp_write_mem_word(struct tfa_device *tfa, + unsigned short address, int value, int memtype); + +/** + * Read data from dsp memory + * @param tfa the device struct pointer + * @param subaddress write address to set in address register + * @param num_bytes number of bytes to read from dsp + * @param data the unsigned char buffer to read data into +*/ +enum Tfa98xx_Error tfa98xx_read_data(struct tfa_device *tfa, + unsigned char subaddress, + int num_bytes, unsigned char data[]); + +/** + * Write all the bytes specified by num_bytes and data to dsp memory + * @param tfa the device struct pointer + * @param subaddress the subaddress to write to + * @param num_bytes number of bytes to write + * @param data actual data to write +*/ +enum Tfa98xx_Error tfa98xx_write_data(struct tfa_device *tfa, + unsigned char subaddress, + int num_bytes, + const unsigned char data[]); + +enum Tfa98xx_Error tfa98xx_write_raw(struct tfa_device *tfa, + int num_bytes, + const unsigned char data[]); + +/* support for converting error codes into text */ +const char *tfa98xx_get_error_string(enum Tfa98xx_Error error); + +/** + * convert signed 24 bit integers to 32bit aligned bytes + * input: data contains "num_bytes/3" int24 elements + * output: bytes contains "num_bytes" byte elements + * @param num_data length of the input data array + * @param data input data as integer array + * @param bytes output data as unsigned char array +*/ +void tfa98xx_convert_data2bytes(int num_data, const int data[], + unsigned char bytes[]); + +/** + * convert memory bytes to signed 24 bit integers + * input: bytes contains "num_bytes" byte elements + * output: data contains "num_bytes/3" int24 elements + * @param num_bytes length of the input data array + * @param bytes input data as unsigned char array + * @param data output data as integer array +*/ +void tfa98xx_convert_bytes2data(int num_bytes, const unsigned char bytes[], + int data[]); + +/** + * Read a part of the dsp memory + * @param tfa the device struct pointer + * @param memoryType indicator to the memory type + * @param offset from where to start reading + * @param length the number of bytes to read + * @param bytes output data as unsigned char array +*/ +enum Tfa98xx_Error tfa98xx_dsp_get_memory(struct tfa_device *tfa, int memoryType, + int offset, int length, unsigned char bytes[]); + +/** + * Write a value to the dsp memory + * @param tfa the device struct pointer + * @param memoryType indicator to the memory type + * @param offset from where to start writing + * @param length the number of bytes to write + * @param value the value to write to the dsp +*/ +enum Tfa98xx_Error tfa98xx_dsp_set_memory(struct tfa_device *tfa, int memoryType, + int offset, int length, int value); + +enum Tfa98xx_Error tfa98xx_dsp_write_config(struct tfa_device *tfa, int length, const unsigned char *p_config_bytes); +enum Tfa98xx_Error tfa98xx_dsp_write_drc(struct tfa_device *tfa, int length, const unsigned char *p_drc_bytes); + +/** + * write/read raw msg functions : + * the buffer is provided in little endian format, each word occupying 3 bytes, length is in bytes. + * The functions will return immediately and do not not wait for DSP reponse. + * @param tfa the device struct pointer + * @param length length of the character buffer to write + * @param buf character buffer to write +*/ +enum Tfa98xx_Error tfa_dsp_msg(struct tfa_device *tfa, int length, const char *buf); + + +/** + * The wrapper functions to call the dsp msg, register and memory function for tfa or probus + */ +enum Tfa98xx_Error dsp_msg(struct tfa_device *tfa, int length, const char *buf); +enum Tfa98xx_Error dsp_msg_read(struct tfa_device *tfa, int length, unsigned char *bytes); +enum Tfa98xx_Error reg_write(struct tfa_device *tfa, unsigned char subaddress, unsigned short value); +enum Tfa98xx_Error reg_read(struct tfa_device *tfa, unsigned char subaddress, unsigned short *value); +enum Tfa98xx_Error mem_write(struct tfa_device *tfa, unsigned short address, int value, int memtype); +enum Tfa98xx_Error mem_read(struct tfa_device *tfa, unsigned int start_offset, int num_words, int *pValues); + +enum Tfa98xx_Error dsp_partial_coefficients(struct tfa_device *tfa, uint8_t *prev, uint8_t *next); + +/** + * write/read raw msg functions: + * the buffer is provided in little endian format, each word occupying 3 bytes, length is in bytes. + * The functions will return immediately and do not not wait for DSP reponse. + * An ID is added to modify the command-ID + * @param tfa the device struct pointer + * @param length length of the character buffer to write + * @param buf character buffer to write + * @param cmdid command identifier +*/ +enum Tfa98xx_Error tfa_dsp_msg_id(struct tfa_device *tfa, int length, const char *buf, uint8_t cmdid[3]); + +/** + * write raw dsp msg functions + * @param tfa the device struct pointer + * @param length length of the character buffer to write + * @param buffer character buffer to write +*/ +enum Tfa98xx_Error tfa_dsp_msg_write(struct tfa_device *tfa, int length, const char *buffer); + +/** + * write raw dsp msg functions + * @param tfa the device struct pointer + * @param length length of the character buffer to write + * @param buffer character buffer to write + * @param cmdid command identifier +*/ +enum Tfa98xx_Error tfa_dsp_msg_write_id(struct tfa_device *tfa, int length, const char *buffer, uint8_t cmdid[3]); + +/** + * status function used by tfa_dsp_msg() to retrieve command/msg status: + * return a <0 status of the DSP did not ACK. + * @param tfa the device struct pointer + * @param pRpcStatus status for remote processor communication +*/ +enum Tfa98xx_Error tfa_dsp_msg_status(struct tfa_device *tfa, int *pRpcStatus); + +/** + * Read a message from dsp + * @param tfa the device struct pointer + * @param length number of bytes of the message + * @param bytes pointer to unsigned char buffer +*/ +enum Tfa98xx_Error tfa_dsp_msg_read(struct tfa_device *tfa,int length, unsigned char *bytes); + +int tfa_set_bf(struct tfa_device *tfa, const uint16_t bf, const uint16_t value); +int tfa_set_bf_volatile(struct tfa_device *tfa, const uint16_t bf, const uint16_t value); + +/** + * Get the value of a given bitfield + * @param tfa the device struct pointer + * @param bf the value indicating which bitfield + */ +int tfa_get_bf(struct tfa_device *tfa, const uint16_t bf); + +/** + * Set the value of a given bitfield + * @param bf the value indicating which bitfield + * @param bf_value the value of the bitfield + * @param p_reg_value a pointer to the register where to write the bitfield value + */ +int tfa_set_bf_value(const uint16_t bf, const uint16_t bf_value, uint16_t *p_reg_value); + +uint16_t tfa_get_bf_value(const uint16_t bf, const uint16_t reg_value); +int tfa_write_reg(struct tfa_device *tfa, const uint16_t bf, const uint16_t reg_value); +int tfa_read_reg(struct tfa_device *tfa, const uint16_t bf); + +/* bitfield */ +/** + * get the datasheet or bitfield name corresponding to the bitfield number + * @param num is the number for which to get the bitfield name + * @param rev is the device type + */ +char *tfaContBfName(uint16_t num, unsigned short rev); + +/** + * get the datasheet name corresponding to the bitfield number + * @param num is the number for which to get the bitfield name + * @param rev is the device type + */ +char *tfaContDsName(uint16_t num, unsigned short rev); + +/** + * get the bitfield name corresponding to the bitfield number + * @param num is the number for which to get the bitfield name + * @param rev is the device type + */ +char *tfaContBitName(uint16_t num, unsigned short rev); + +/** + * get the bitfield number corresponding to the bitfield name + * @param name is the bitfield name for which to get the bitfield number + * @param rev is the device type + */ +uint16_t tfaContBfEnum(const char *name, unsigned short rev); + +/** +* get the bitfield number corresponding to the bitfield name, checks for all devices +* @param name is the bitfield name for which to get the bitfield number + */ +uint16_t tfaContBfEnumAny(const char *name); + +#define TFA_FAM(tfa, fieldname) ((tfa->tfa_family == 1) ? TFA1_BF_##fieldname : TFA2_BF_##fieldname) +#define TFA_FAM_FW(tfa, fwname) ((tfa->tfa_family == 1) ? TFA1_FW_##fwname : TFA2_FW_##fwname) + +/* set/get bit fields to HW register*/ +#define TFA_SET_BF(tfa, fieldname, value) tfa_set_bf(tfa, TFA_FAM(tfa, fieldname), value) +#define TFA_SET_BF_VOLATILE(tfa, fieldname, value) tfa_set_bf_volatile(tfa, TFA_FAM(tfa, fieldname), value) +#define TFA_GET_BF(tfa, fieldname) tfa_get_bf(tfa, TFA_FAM(tfa, fieldname)) + +/* set/get bit field in variable */ +#define TFA_SET_BF_VALUE(tfa, fieldname, bf_value, p_reg_value) tfa_set_bf_value(TFA_FAM(tfa, fieldname), bf_value, p_reg_value) +#define TFA_GET_BF_VALUE(tfa, fieldname, reg_value) tfa_get_bf_value(TFA_FAM(tfa, fieldname), reg_value) + +/* write/read registers using a bit field name to determine the register address */ +#define TFA_WRITE_REG(tfa, fieldname, value) tfa_write_reg(tfa, TFA_FAM(tfa, fieldname), value) +#define TFA_READ_REG(tfa, fieldname) tfa_read_reg(tfa, TFA_FAM(tfa, fieldname)) + +/* FOR CALIBRATION RETRIES */ +#define TFA98XX_API_WAITRESULT_NTRIES 3000 // defined in API + +/** + * run the startup/init sequence and set ACS bit + * @param tfa the device struct pointer + * @param state the cold start state that is requested + */ +enum Tfa98xx_Error tfaRunColdboot(struct tfa_device *tfa, int state); +enum Tfa98xx_Error tfaRunMute(struct tfa_device *tfa); +enum Tfa98xx_Error tfaRunUnmute(struct tfa_device *tfa); + +/** + * wait for calibrateDone + * @param tfa the device struct pointer + * @param calibrateDone pointer to status of calibration + */ +enum Tfa98xx_Error tfaRunWaitCalibration(struct tfa_device *tfa, int *calibrateDone); + +/** + * run the startup/init sequence and set ACS bit + * @param tfa the device struct pointer + * @param profile the profile that should be loaded + */ +enum Tfa98xx_Error tfaRunColdStartup(struct tfa_device *tfa, int profile); + +/** + * this will load the patch witch will implicitly start the DSP + * if no patch is available the DPS is started immediately + * @param tfa the device struct pointer + */ +enum Tfa98xx_Error tfaRunStartDSP(struct tfa_device *tfa); + +/** + * start the clocks and wait until the AMP is switching + * on return the DSP sub system will be ready for loading + * @param tfa the device struct pointer + * @param profile the profile that should be loaded on startup + */ +enum Tfa98xx_Error tfaRunStartup(struct tfa_device *tfa, int profile); + +/** + * start the maximus speakerboost algorithm + * this implies a full system startup when the system was not already started + * @param tfa the device struct pointer + * @param force indicates wether a full system startup should be allowed + * @param profile the profile that should be loaded + */ +enum Tfa98xx_Error tfaRunSpeakerBoost(struct tfa_device *tfa, int force, int profile); + +/** + * Startup the device and write all files from device and profile section + * @param tfa the device struct pointer + * @param force indicates wether a full system startup should be allowed + * @param profile the profile that should be loaded on speaker startup + */ +enum Tfa98xx_Error tfaRunSpeakerStartup(struct tfa_device *tfa, int force, int profile); + +/** + * Run calibration + * @param tfa the device struct pointer + */ +enum Tfa98xx_Error tfaRunSpeakerCalibration(struct tfa_device *tfa); + +/** + * startup all devices. all step until patch loading is handled + * @param tfa the device struct pointer + */ +int tfaRunStartupAll(struct tfa_device *tfa); + +/** + * powerup the coolflux subsystem and wait for it + * @param tfa the device struct pointer + */ +enum Tfa98xx_Error tfa_cf_powerup(struct tfa_device *tfa); + +/* + * print the current device manager state + * @param tfa the device struct pointer + */ +enum Tfa98xx_Error show_current_state(struct tfa_device *tfa); + +/** + * Init registers and coldboot dsp + * @param tfa the device struct pointer + */ +int tfa_reset(struct tfa_device *tfa); + +/** + * Get profile from a register + * @param tfa the device struct pointer + */ +int tfa_dev_get_swprof(struct tfa_device *tfa); + +/** + * Save profile in a register + */ +int tfa_dev_set_swprof(struct tfa_device *tfa, unsigned short new_value); + +int tfa_dev_get_swvstep(struct tfa_device *tfa); + +int tfa_dev_set_swvstep(struct tfa_device *tfa, unsigned short new_value); + +int tfa_needs_reset(struct tfa_device *tfa); + +int tfa_is_cold(struct tfa_device *tfa); + +void tfa_set_query_info(struct tfa_device *tfa); + +int tfa_get_pga_gain(struct tfa_device *tfa); +int tfa_set_pga_gain(struct tfa_device *tfa, uint16_t value); +int tfa_get_noclk(struct tfa_device *tfa); + +/** + * Status of used for monitoring + * @param tfa the device struct pointer + * @return tfa error enum + */ + +enum Tfa98xx_Error tfa_status(struct tfa_device *tfa); + +/* + * function overload for flag_mtp_busy + */ +int tfa_dev_get_mtpb(struct tfa_device *tfa); + +#ifdef __cplusplus +} +#endif +#endif /* TFA_SERVICE_H */ diff --git a/techpack/audio/asoc/codecs/tfa9874/versions.h b/techpack/audio/asoc/codecs/tfa9874/versions.h new file mode 100644 index 000000000000..37e14f450a4e --- /dev/null +++ b/techpack/audio/asoc/codecs/tfa9874/versions.h @@ -0,0 +1,3 @@ +#ifndef _VERSIONS_H +#define _VERSIONS_H +#endif diff --git a/techpack/audio/asoc/codecs/wcd-mbhc-adc.c b/techpack/audio/asoc/codecs/wcd-mbhc-adc.c index 5865af3dfc9b..3093e0b3a070 100644 --- a/techpack/audio/asoc/codecs/wcd-mbhc-adc.c +++ b/techpack/audio/asoc/codecs/wcd-mbhc-adc.c @@ -23,9 +23,9 @@ #include #include -#define WCD_MBHC_ADC_HS_THRESHOLD_MV 1700 +#define WCD_MBHC_ADC_HS_THRESHOLD_MV 1800 #define WCD_MBHC_ADC_HPH_THRESHOLD_MV 75 -#define WCD_MBHC_ADC_MICBIAS_MV 1800 +#define WCD_MBHC_ADC_MICBIAS_MV 2700 #define WCD_MBHC_FAKE_INS_RETRY 4 static int wcd_mbhc_get_micbias(struct wcd_mbhc *mbhc) @@ -958,6 +958,8 @@ static void wcd_correct_swch_plug(struct work_struct *work) if (mbhc->mbhc_cb->mbhc_micbias_control) wcd_mbhc_adc_update_fsm_source(mbhc, plug_type); exit: + if (plug_type == MBHC_PLUG_TYPE_HEADSET) + mbhc->micbias_enable = true; if (mbhc->mbhc_cb->mbhc_micbias_control && !mbhc->micbias_enable) mbhc->mbhc_cb->mbhc_micbias_control(component, MIC_BIAS_2, @@ -1026,7 +1028,10 @@ static irqreturn_t wcd_mbhc_adc_hs_rem_irq(int irq, void *data) timeout = jiffies + msecs_to_jiffies(WCD_FAKE_REMOVAL_MIN_PERIOD_MS); - adc_threshold = wcd_mbhc_adc_get_hs_thres(mbhc); + /* liuhaituo@MM.Audio 2018/6/8 modify adc_threshold is consistent with OMR1 */ + adc_threshold = ((WCD_MBHC_ADC_HS_THRESHOLD_MV * + wcd_mbhc_get_micbias(mbhc)) / + WCD_MBHC_ADC_MICBIAS_MV); do { retry++; diff --git a/techpack/audio/asoc/codecs/wcd-mbhc-v2.c b/techpack/audio/asoc/codecs/wcd-mbhc-v2.c index b74ca861c904..732f5b50f6ff 100644 --- a/techpack/audio/asoc/codecs/wcd-mbhc-v2.c +++ b/techpack/audio/asoc/codecs/wcd-mbhc-v2.c @@ -547,6 +547,92 @@ void wcd_mbhc_hs_elec_irq(struct wcd_mbhc *mbhc, int irq_type, } EXPORT_SYMBOL(wcd_mbhc_hs_elec_irq); +/* liuhaituo@MM.Audio add new function to adapt headset volume */ +bool headset_imp_enable = false; +EXPORT_SYMBOL_GPL(headset_imp_enable); + +static enum { + LOW_Z = 0, + HIGH_Z, + NONE_Z, +}current_imp = NONE_Z; +static int hp_volume_gain[3] ={80 /* LOW_Z_gain */, + 85 /* HIGH_Z_gain */, + 80 /* NONE_Z_gain */}; +static int original_imp = NONE_Z; +#define HIGH_Z_THR 55 //The actual threshold impedance is 45, phone own impedance ~10 +#define HIGH_Z_MIN_THR (HIGH_Z_THR - 3) +#define HIGH_Z_MAX_THR (HIGH_Z_THR + 3) + +static int adapt_headset_volume(struct wcd_mbhc *mbhc, int volume) +{ + int ret = 0; + struct snd_soc_component *component = mbhc->component; + int mask = (1 << (fls(40 - 84) -1)) - 1; + //because volume from -84 to 40; + volume -= 84; + + /* set RX1 Mix Digital Volume */ + ret = snd_soc_component_update_bits(component, 0xb5c, mask, volume); + if (ret < 0) + return ret; + + /* set RX2 Mix Digital Volume */ + ret = snd_soc_component_update_bits(component, 0xb70, mask, volume); + if (ret < 0) + return ret; + + /* set RX1 Digital Volume */ + ret = snd_soc_component_update_bits(component, 0xb59, mask, volume); + if (ret < 0) + return ret; + + /* set RX2 Digital Volume */ + ret = snd_soc_component_update_bits(component, 0xb6d, mask, volume); + if (ret < 0) + return ret; + + pr_info("%s: set %d success!\n", __func__, volume); + + return ret; +} + +static void judge_headset_impedance(struct wcd_mbhc *mbhc) +{ + int ret = 0; + int left_z = mbhc->zl; + int right_z = mbhc->zr; + + pr_err("%s: left_z is %d, right_z is %d\n", __func__, left_z, right_z); + + if ((original_imp != NONE_Z) && + (left_z > HIGH_Z_MIN_THR) && (left_z < HIGH_Z_MAX_THR) && + (right_z > HIGH_Z_MIN_THR) && (right_z < HIGH_Z_MAX_THR)) { + current_imp = original_imp; + } else if ((left_z < HIGH_Z_THR) || (right_z < HIGH_Z_THR)) { + if (((left_z == 0) || (right_z == 0)) && (original_imp != NONE_Z)) + current_imp = original_imp; + else { + current_imp = LOW_Z; + original_imp = current_imp; + } + } else { + current_imp = HIGH_Z; + original_imp = current_imp; + } + + pr_err("%s: current_imp is %d, original_imp is %d\n", + __func__, + current_imp, + original_imp); + + ret = adapt_headset_volume(mbhc, hp_volume_gain[current_imp]); + if (ret < 0) + pr_err("%s: set headset volume fail\n", __func__); + + return; +} + void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion, enum snd_jack_types jack_type) { @@ -732,6 +818,9 @@ void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion, } mbhc->hph_status |= jack_type; + /* liuhaituo@MM.Audio add new function to adapt headset volume */ + if (headset_imp_enable) + judge_headset_impedance(mbhc); if (jack_type == SND_JACK_HEADPHONE && mbhc->mbhc_cb->mbhc_micb_ramp_control) diff --git a/techpack/audio/asoc/codecs/wcd934x/wcd934x-mbhc.c b/techpack/audio/asoc/codecs/wcd934x/wcd934x-mbhc.c index d777d8d56446..af9f97336eb5 100644 --- a/techpack/audio/asoc/codecs/wcd934x/wcd934x-mbhc.c +++ b/techpack/audio/asoc/codecs/wcd934x/wcd934x-mbhc.c @@ -982,6 +982,36 @@ static const struct snd_kcontrol_new impedance_detect_controls[] = { tavil_hph_impedance_get, NULL), }; +/* liuhaituo@MM.Audio 2018/7/17 add for headset impedance detect */ +extern bool headset_imp_enable; + +static int headset_imp_feature_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int type = ucontrol->value.integer.value[0]; + if (type != 0) + headset_imp_enable = true; + + pr_info("%s: headset_imp_feature is %d\n", + __func__, headset_imp_enable); + + return 0; +} + +static int headset_imp_feature_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = (int)headset_imp_enable; + pr_info("%s: get success!\n", __func__); + + return 0; +} + +static const struct snd_kcontrol_new headset_feature_controls[] = { + SOC_SINGLE_EXT("headset_imp_feature", 0, 0, 1, 0, + headset_imp_feature_get, headset_imp_feature_put), +}; + /* * tavil_mbhc_get_impedance: get impedance of headphone left and right channels * @wcd934x_mbhc: handle to struct wcd934x_mbhc * @@ -1156,6 +1186,9 @@ int tavil_mbhc_init(struct wcd934x_mbhc **mbhc, ARRAY_SIZE(impedance_detect_controls)); snd_soc_add_component_controls(component, hph_type_detect_controls, ARRAY_SIZE(hph_type_detect_controls)); + /* liuhaituo@MM.Audio 2018/7/17 add for headset impedance detect */ + snd_soc_add_component_controls(component, headset_feature_controls, + ARRAY_SIZE(headset_feature_controls)); if (wcd_mbhc->mbhc_detection_logic == WCD_DETECTION_LEGACY) { snd_soc_component_update_bits(component, WCD934X_MBHC_NEW_CTL_1, diff --git a/techpack/audio/asoc/codecs/wcd934x/wcd934x-regmap.c b/techpack/audio/asoc/codecs/wcd934x/wcd934x-regmap.c index a9642091a66e..5ae66a598224 100644 --- a/techpack/audio/asoc/codecs/wcd934x/wcd934x-regmap.c +++ b/techpack/audio/asoc/codecs/wcd934x/wcd934x-regmap.c @@ -365,7 +365,8 @@ static const struct reg_default wcd934x_defaults[] = { { WCD934X_INTR_LEVEL2, 0x94 }, { WCD934X_INTR_LEVEL3, 0x80 }, { WCD934X_INTR_BYPASS0, 0x00 }, - { WCD934X_INTR_BYPASS1, 0x00 }, + /* Bypass "Elect remove irq" and "Elect insert irq" */ + { WCD934X_INTR_BYPASS1, 0x12 }, { WCD934X_INTR_BYPASS2, 0x00 }, { WCD934X_INTR_BYPASS3, 0x00 }, { WCD934X_INTR_SET0, 0x00 }, diff --git a/techpack/audio/asoc/codecs/wcd934x/wcd934x.c b/techpack/audio/asoc/codecs/wcd934x/wcd934x.c index 49f164c9d9ff..967d9fd7d026 100644 --- a/techpack/audio/asoc/codecs/wcd934x/wcd934x.c +++ b/techpack/audio/asoc/codecs/wcd934x/wcd934x.c @@ -4429,6 +4429,11 @@ static void tavil_codec_set_tx_hold(struct snd_soc_component *component, case WCD934X_ANA_AMIC2: snd_soc_component_update_bits(component, WCD934X_ANA_AMIC2, mask, val); + // suzhiguang,sleep 150ms to avoid mic pop. + if (amic_reg == WCD934X_ANA_AMIC2) { + pr_err("begin to sleep 150 ms\n"); + usleep_range(150 * 1000, 150 * 1010); + } break; case WCD934X_ANA_AMIC3: case WCD934X_ANA_AMIC4: diff --git a/techpack/audio/asoc/msm-pcm-routing-v2.c b/techpack/audio/asoc/msm-pcm-routing-v2.c index 6eafbd0c3627..6b4ec1ccb0e7 100644 --- a/techpack/audio/asoc/msm-pcm-routing-v2.c +++ b/techpack/audio/asoc/msm-pcm-routing-v2.c @@ -3575,7 +3575,7 @@ static const char *const be_name[] = { "RX_CDC_DMA_RX_6", "RX_CDC_DMA_RX_7", "PRI_SPDIF_TX", "SEC_SPDIF_RX", "SEC_SPDIF_TX", "SLIM_9_RX", "SLIM_9_TX", "AFE_LOOPBACK_TX", "PRI_META_MI2S_RX", -"SEC_META_MI2S_RX", "PROXY_RX", "PROXY_TX", "HDMI_RX_MS" +"SEC_META_MI2S_RX", "PROXY_RX", "PROXY_TX", "HDMI_RX_MS","USB_AUDIO_TX" }; static SOC_ENUM_SINGLE_DECL(mm1_channel_mux, @@ -29705,6 +29705,8 @@ static const struct snd_soc_dapm_route intercon_tdm[] = { {"AUDIO_REF_EC_UL1 MUX", "QUIN_TDM_TX_0", "QUIN_TDM_TX_0"}, {"AUDIO_REF_EC_UL1 MUX", "PRI_TDM_RX_0", "PRI_TDM_RX_0"}, {"AUDIO_REF_EC_UL1 MUX", "PRI_TDM_TX_0", "PRI_TDM_TX_0"}, + {"AUDIO_REF_EC_UL1 MUX", "SLIM_6_RX", "SLIM_6_RX"}, + {"AUDIO_REF_EC_UL1 MUX", "USB_AUDIO_RX", "USB_AUDIO_RX"}, {"AUDIO_REF_EC_UL10 MUX", "QUAT_TDM_TX_1", "QUAT_TDM_TX_1"}, {"AUDIO_REF_EC_UL10 MUX", "QUAT_TDM_RX_0", "QUAT_TDM_RX_0"}, @@ -30381,7 +30383,8 @@ static const struct snd_soc_dapm_route intercon_mi2s[] = { {"TERT_MI2S_RX_DL_HL", "Switch", "TERT_MI2S_DL_HL"}, {"TERT_MI2S_RX", NULL, "TERT_MI2S_RX_DL_HL"}, - {"QUAT_MI2S_RX_DL_HL", "Switch", "QUAT_MI2S_DL_HL"}, + /* liuhaituo@MultiMedia 2018/4/18 add echo_test route */ + {"QUAT_MI2S_RX_DL_HL", "Switch", "SLIM0_DL_HL"}, {"QUAT_MI2S_RX", NULL, "QUAT_MI2S_RX_DL_HL"}, {"QUIN_MI2S_RX_DL_HL", "Switch", "QUIN_MI2S_DL_HL"}, {"QUIN_MI2S_RX", NULL, "QUIN_MI2S_RX_DL_HL"}, diff --git a/techpack/audio/asoc/sdm845.c b/techpack/audio/asoc/sdm845.c index d55708813afd..fa28a29b6f83 100644 --- a/techpack/audio/asoc/sdm845.c +++ b/techpack/audio/asoc/sdm845.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "msm-pcm-routing-v2.h" #include #include "codecs/wcd934x/wcd934x.h" @@ -169,6 +170,7 @@ struct msm_asoc_mach_data { u32 mclk_freq; int us_euro_gpio; /* used by gpio driver API */ int usbc_en2_gpio; /* used by gpio driver API */ + int us_euro_gpio_value; struct device_node *us_euro_gpio_p; /* used by pinctrl API */ struct pinctrl *usbc_en2_gpio_p; /* used by pinctrl API */ struct device_node *hph_en1_gpio_p; /* used by pinctrl API */ @@ -445,7 +447,7 @@ static struct dev_config mi2s_tx_cfg[] = { [PRIM_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, [SEC_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, [TERT_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, - [QUAT_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, + [QUAT_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, }; static struct dev_config aux_pcm_rx_cfg[] = { @@ -597,6 +599,13 @@ static struct snd_soc_aux_dev *msm_aux_dev; static struct snd_soc_codec_conf *msm_codec_conf; static struct msm_asoc_wcd93xx_codec msm_codec_fn; +int usb_sw_gpio = -1; +int hp_sw_gpio = -1; +int mbhc_sw_gpio = -1; +int ldo_sw_gpio = -1; +extern int smartpa_present; +extern bool fsa4480_enable; +extern bool audio_adapter_flag; static void *def_tavil_mbhc_cal(void); static int msm_snd_enable_codec_ext_clk(struct snd_soc_component *component, int enable, bool dapm); @@ -614,9 +623,9 @@ static struct wcd_mbhc_config wcd_mbhc_cfg = { .swap_gnd_mic = NULL, .hs_ext_micbias = true, .key_code[0] = KEY_MEDIA, - .key_code[1] = KEY_VOICECOMMAND, - .key_code[2] = KEY_VOLUMEUP, - .key_code[3] = KEY_VOLUMEDOWN, + .key_code[1] = KEY_VOLUMEUP, + .key_code[2] = KEY_VOLUMEDOWN, + .key_code[3] = 0, .key_code[4] = 0, .key_code[5] = 0, .key_code[6] = 0, @@ -3868,9 +3877,12 @@ static bool msm_usbc_swap_gnd_mic(struct snd_soc_component *component, bool acti return ret; } +extern void setHpSwGpioPin(int value); static bool msm_swap_gnd_mic(struct snd_soc_component *component, bool active) { +#if 0 int value = 0; +#endif int ret = 0; struct snd_soc_card *card = component->card; struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); @@ -3880,6 +3892,7 @@ static bool msm_swap_gnd_mic(struct snd_soc_component *component, bool active) if (!wcd_mbhc_cfg.enable_usbc_analog) { /* if usbc is not defined, swap using us_euro_gpio_p */ +#if 0 if (pdata->us_euro_gpio_p) { value = msm_cdc_pinctrl_get_state( pdata->us_euro_gpio_p); @@ -3897,6 +3910,16 @@ static bool msm_swap_gnd_mic(struct snd_soc_component *component, bool active) } pr_debug("%s: swap select switch %d to %d\n", __func__, value, !value); +#else + if (pdata->us_euro_gpio_value == 0) { + pdata->us_euro_gpio_value = 1; + } else { + pdata->us_euro_gpio_value = 0; + } + setHpSwGpioPin(pdata->us_euro_gpio_value); + pr_err("%s set us_euro_gpio %d active = %d\n", __func__, + pdata->us_euro_gpio_value, active); +#endif ret = true; } else { /* if usbc is defined, swap using usbc_en2 */ @@ -4251,7 +4274,12 @@ static void *def_tavil_mbhc_cal(void) return NULL; #define S(X, Y) ((WCD_MBHC_CAL_PLUG_TYPE_PTR(tavil_wcd_cal)->X) = (Y)) +#if 0 +/*wangdongdong@AudioDrv,2018-06-14,avoid JBL lock device not to enter standby*/ S(v_hs_max, 1600); +#else + S(v_hs_max, 1700); +#endif #undef S #define S(X, Y) ((WCD_MBHC_CAL_BTN_DET_PTR(tavil_wcd_cal)->X) = (Y)) S(num_btn, WCD_MBHC_DEF_BUTTONS); @@ -4261,6 +4289,17 @@ static void *def_tavil_mbhc_cal(void) btn_high = ((void *)&btn_cfg->_v_btn_low) + (sizeof(btn_cfg->_v_btn_low[0]) * btn_cfg->num_btn); +#if 1 +/*wangdongdong@AudioDrv,20180113,modify for headset button*/ + btn_high[0] = 112; + btn_high[1] = 220; + btn_high[2] = 437; + btn_high[3] = 600; + btn_high[4] = 600; + btn_high[5] = 600; + btn_high[6] = 600; + btn_high[7] = 600; +#else btn_high[0] = 75; btn_high[1] = 150; btn_high[2] = 237; @@ -4269,6 +4308,7 @@ static void *def_tavil_mbhc_cal(void) btn_high[5] = 500; btn_high[6] = 500; btn_high[7] = 500; +#endif return tavil_wcd_cal; } @@ -5639,6 +5679,21 @@ static struct snd_soc_dai_link msm_common_dai_links[] = { .codec_dai_name = "snd-soc-dummy-dai", .codec_name = "snd-soc-dummy", }, + { + .name = "Quaternary MI2S_TX Hostless", + .stream_name = "Quaternary MI2S_TX Hostless", + .cpu_dai_name = "QUAT_MI2S_TX_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, }; static struct snd_soc_dai_link msm_tavil_fe_dai_links[] = { @@ -6306,6 +6361,8 @@ static struct snd_soc_dai_link ext_disp_be_dai_link[] = { }, }; +#if 1 +// suzhiguang,different projects use different smartpa,2018-04-10 static struct snd_soc_dai_link msm_mi2s_be_dai_links[] = { { .name = LPASS_BE_PRI_MI2S_RX, @@ -6433,6 +6490,269 @@ static struct snd_soc_dai_link msm_mi2s_be_dai_links[] = { }, }; +static struct snd_soc_dai_link msm_mi2s_be_dai_links_max[] = { + { + .name = LPASS_BE_PRI_MI2S_RX, + .stream_name = "Primary MI2S Playback", + .cpu_dai_name = "msm-dai-q6-mi2s.0", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .dynamic_be = 1, + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_PRI_MI2S_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_mi2s_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + }, + { + .name = LPASS_BE_PRI_MI2S_TX, + .stream_name = "Primary MI2S Capture", + .cpu_dai_name = "msm-dai-q6-mi2s.0", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .dynamic_be = 1, + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_PRI_MI2S_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_mi2s_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_SEC_MI2S_RX, + .stream_name = "Secondary MI2S Playback", + .cpu_dai_name = "msm-dai-q6-mi2s.1", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .dynamic_be = 1, + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_mi2s_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + }, + { + .name = LPASS_BE_SEC_MI2S_TX, + .stream_name = "Secondary MI2S Capture", + .cpu_dai_name = "msm-dai-q6-mi2s.1", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .dynamic_be = 1, + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_SECONDARY_MI2S_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_mi2s_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_TERT_MI2S_RX, + .stream_name = "Tertiary MI2S Playback", + .cpu_dai_name = "msm-dai-q6-mi2s.2", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .dynamic_be = 1, + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_mi2s_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + }, + { + .name = LPASS_BE_TERT_MI2S_TX, + .stream_name = "Tertiary MI2S Capture", + .cpu_dai_name = "msm-dai-q6-mi2s.2", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .dynamic_be = 1, + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_TERTIARY_MI2S_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_mi2s_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_QUAT_MI2S_RX, + .stream_name = "Quaternary MI2S Playback", + .cpu_dai_name = "msm-dai-q6-mi2s.3", + .platform_name = "msm-pcm-routing", + .codec_name = "max98927", //"msm-stub-codec.1", + .codec_dai_name = "max98927-aif1", //"msm-stub-rx", + .dynamic_be = 1, + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_mi2s_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + }, + { + .name = LPASS_BE_QUAT_MI2S_TX, + .stream_name = "Quaternary MI2S Capture", + .cpu_dai_name = "msm-dai-q6-mi2s.3", + .platform_name = "msm-pcm-routing", + .codec_name = "max98927", //"msm-stub-codec.1", + .codec_dai_name = "max98927-aif1", //"msm-stub-tx", + .dynamic_be = 1, + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_mi2s_be_ops, + .ignore_suspend = 1, + }, +}; + +static struct snd_soc_dai_link_component tfa98xx_dai_link_component[]= +{ + { + .name= "tfa98xx.2-0034", + .dai_name="tfa98xx-aif-2-34", + }, +}; + +static struct snd_soc_dai_link msm_mi2s_be_dai_links_tfa[] = { + { + .name = LPASS_BE_PRI_MI2S_RX, + .stream_name = "Primary MI2S Playback", + .cpu_dai_name = "msm-dai-q6-mi2s.0", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .dynamic_be = 1, + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_PRI_MI2S_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_mi2s_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + }, + { + .name = LPASS_BE_PRI_MI2S_TX, + .stream_name = "Primary MI2S Capture", + .cpu_dai_name = "msm-dai-q6-mi2s.0", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .dynamic_be = 1, + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_PRI_MI2S_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_mi2s_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_SEC_MI2S_RX, + .stream_name = "Secondary MI2S Playback", + .cpu_dai_name = "msm-dai-q6-mi2s.1", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .dynamic_be = 1, + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_SECONDARY_MI2S_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_mi2s_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + }, + { + .name = LPASS_BE_SEC_MI2S_TX, + .stream_name = "Secondary MI2S Capture", + .cpu_dai_name = "msm-dai-q6-mi2s.1", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .dynamic_be = 1, + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_SECONDARY_MI2S_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_mi2s_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_TERT_MI2S_RX, + .stream_name = "Tertiary MI2S Playback", + .cpu_dai_name = "msm-dai-q6-mi2s.2", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .dynamic_be = 1, + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_TERTIARY_MI2S_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_mi2s_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + }, + { + .name = LPASS_BE_TERT_MI2S_TX, + .stream_name = "Tertiary MI2S Capture", + .cpu_dai_name = "msm-dai-q6-mi2s.2", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .dynamic_be = 1, + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_TERTIARY_MI2S_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_mi2s_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_QUAT_MI2S_RX, + .stream_name = "Quaternary MI2S Playback", + .cpu_dai_name = "msm-dai-q6-mi2s.3", + .platform_name = "msm-pcm-routing", + .codecs = tfa98xx_dai_link_component, + .num_codecs = ARRAY_SIZE(tfa98xx_dai_link_component), + .dynamic_be = 1, + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_mi2s_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + }, + { + .name = LPASS_BE_QUAT_MI2S_TX, + .stream_name = "Quaternary MI2S Capture", + .cpu_dai_name = "msm-dai-q6-mi2s.3", + .platform_name = "msm-pcm-routing", + .codecs = tfa98xx_dai_link_component, + .num_codecs = ARRAY_SIZE(tfa98xx_dai_link_component), + .dynamic_be = 1, + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_QUATERNARY_MI2S_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_mi2s_be_ops, + .ignore_suspend = 1, + }, +}; +#endif + static struct snd_soc_dai_link msm_auxpcm_be_dai_links[] = { /* Primary AUX PCM Backend DAI Links */ { @@ -6723,6 +7043,7 @@ static int msm_prepare_us_euro(struct snd_soc_card *card) snd_soc_card_get_drvdata(card); int ret = 0; +#if 0 if (pdata->us_euro_gpio >= 0) { dev_dbg(card->dev, "%s: us_euro gpio request %d", __func__, pdata->us_euro_gpio); @@ -6735,6 +7056,12 @@ static int msm_prepare_us_euro(struct snd_soc_card *card) } return ret; +#else + pdata->us_euro_gpio_value = 1; + setHpSwGpioPin(pdata->us_euro_gpio_value); + + return ret; +#endif } static int msm_audrx_stub_init(struct snd_soc_pcm_runtime *rtd) @@ -6875,6 +7202,94 @@ static const struct of_device_id sdm845_asoc_machine_of_match[] = { {}, }; +#if 1 +/*2018/06/14 @bsp add for support notify audio adapter switch*/ +static int cc_audio_adapter_detect_callback(struct notifier_block *nb, + unsigned long value, void *data) +{ + + if (value == 1) { + pr_err("%s:audio_adapter attached!\n", __func__); + + if (gpio_is_valid(ldo_sw_gpio)) { + gpio_set_value_cansleep(ldo_sw_gpio, 1); + pr_err("ldo_sw_gpio set to 1\n"); + } else { + pr_err("ldo_sw_gpio gpio_is_valid failed\n"); + } + msleep_interruptible(20); + + if (gpio_is_valid(usb_sw_gpio)) { + gpio_set_value_cansleep(usb_sw_gpio, 1); + pr_err("usb_sw_gpio set to 1\n"); + } else { + pr_err("usb_sw_gpio gpio_is_valid failed\n"); + } + + if (gpio_is_valid(mbhc_sw_gpio)) { + gpio_set_value_cansleep(mbhc_sw_gpio, 0); + pr_err("mbhc_sw_gpio set to 0\n"); + } else { + pr_err("mbhc_sw_gpio gpio_is_valid failed\n"); + } + + } else if (value == 0) { + pr_err("%s:audio_adapter removal!\n", __func__); + + if (gpio_is_valid(mbhc_sw_gpio)) { + gpio_set_value_cansleep(mbhc_sw_gpio, 1); + pr_err("mbhc_sw_gpio set to 1\n"); + } else { + pr_err("mbhc_sw_gpio gpio_is_valid failed\n"); + } + + if (gpio_is_valid(usb_sw_gpio)) { + gpio_set_value_cansleep(usb_sw_gpio, 0); + } else { + pr_err("usb_sw_gpio gpio_is_valid failed\n"); + } + + if (gpio_is_valid(ldo_sw_gpio)) { + gpio_set_value_cansleep(ldo_sw_gpio, 0); + pr_err("ldo_sw_gpio set to 0\n"); + } else { + pr_err("ldo_sw_gpio gpio_is_valid failed\n"); + } + + } else + pr_err("%s:audio adapter value = %lu\n", __func__, value); + + return NOTIFY_OK; +} + +static struct notifier_block typec_cc_notifier = { + .notifier_call = cc_audio_adapter_detect_callback, +}; +#endif + +// suzhiguang,for usb sw/hp sw control +void setUsbSwGpioPin(int value) +{ + if (gpio_is_valid(usb_sw_gpio)) { + gpio_set_value_cansleep(usb_sw_gpio, value); + pr_err("%s usb_sw_gpio set to %d\n", __func__, value); + } else { + pr_err("%s usb_sw_gpio gpio_is_valid failed\n", __func__); + } +} +EXPORT_SYMBOL(setUsbSwGpioPin); + +void setHpSwGpioPin(int value) +{ + if (gpio_is_valid(hp_sw_gpio)) { + gpio_set_value_cansleep(hp_sw_gpio, value); + pr_err("%s hp_sw_gpio set to %d\n", __func__, value); + } else { + pr_err("%s hp_sw_gpio gpio_is_valid failed\n", __func__); + } +} +EXPORT_SYMBOL(setHpSwGpioPin); + static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev) { struct snd_soc_card *card = NULL; @@ -6884,6 +7299,7 @@ static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev) int rc = 0; u32 val = 0; const struct of_device_id *match; + const char *smartpa_type; match = of_match_node(sdm845_asoc_machine_of_match, dev->of_node); if (!match) { @@ -6933,6 +7349,7 @@ static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev) sizeof(ext_disp_be_dai_link)); total_links += ARRAY_SIZE(ext_disp_be_dai_link); } +#if 0 if (of_property_read_bool(dev->of_node, "qcom,mi2s-audio-intf")) { memcpy(msm_tavil_snd_card_dai_links + total_links, @@ -6940,6 +7357,46 @@ static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev) sizeof(msm_mi2s_be_dai_links)); total_links += ARRAY_SIZE(msm_mi2s_be_dai_links); } +#else + // suzhiguang,config smartpa dailink + if (of_property_read_bool(dev->of_node, + "qcom,mi2s-audio-intf")) { + rc = of_property_read_string(dev->of_node, + "op,smartpa", &smartpa_type); + if (rc) { + pr_err("read smartpa type error\n"); + } else { + pr_err("smartpa dts config is %s\n", smartpa_type); + if (smartpa_present) { + pr_err("smartpa_present\n"); + if (!strcmp(smartpa_type, "max98927")) { + memcpy(msm_tavil_snd_card_dai_links + total_links, + msm_mi2s_be_dai_links_max, + sizeof(msm_mi2s_be_dai_links_max)); + total_links += ARRAY_SIZE(msm_mi2s_be_dai_links_max); + } else if (!strcmp(smartpa_type, "tfa98xx")) { + memcpy(msm_tavil_snd_card_dai_links + total_links, + msm_mi2s_be_dai_links_tfa, + sizeof(msm_mi2s_be_dai_links_tfa)); + total_links += ARRAY_SIZE(msm_mi2s_be_dai_links_tfa); + } else { + memcpy(msm_tavil_snd_card_dai_links + total_links, + msm_mi2s_be_dai_links, + sizeof(msm_mi2s_be_dai_links)); + total_links += ARRAY_SIZE(msm_mi2s_be_dai_links); + pr_err("no smartpa dts config match,use default\n"); + } + } else { + memcpy(msm_tavil_snd_card_dai_links + total_links, + msm_mi2s_be_dai_links, + sizeof(msm_mi2s_be_dai_links)); + total_links += ARRAY_SIZE(msm_mi2s_be_dai_links); + pr_err("no smartpa found,use default\n"); + } + } + } +#endif + if (of_property_read_bool(dev->of_node, "qcom,auxpcm-audio-intf")) { memcpy(msm_tavil_snd_card_dai_links + total_links, @@ -7266,11 +7723,14 @@ static int msm_asoc_machine_probe(struct platform_device *pdev) const struct of_device_id *match; int ret; const char *usb_c_dt = "qcom,msm-mbhc-usbc-audio-supported"; + // suzhiguang,add for parse dt. + struct device_node *np; if (!pdev->dev.of_node) { dev_err(&pdev->dev, "No platform supplied from device tree\n"); return -EINVAL; } + np = pdev->dev.of_node; pdata = devm_kzalloc(&pdev->dev, sizeof(struct msm_asoc_mach_data), GFP_KERNEL); @@ -7418,6 +7878,73 @@ static int msm_asoc_machine_probe(struct platform_device *pdev) if (of_find_property(pdev->dev.of_node, usb_c_dt, NULL)) wcd_mbhc_cfg.swap_gnd_mic = msm_swap_gnd_mic; +#if 1 + /*2018/06/14 @bsp add for support notify audio adapter switch*/ + pr_err("%s: fsa4480_enable is %s\n", __func__, fsa4480_enable ? "true": "false"); + if (of_property_read_bool(np, "op,usb_sw") && !fsa4480_enable) { + pr_err("%s usb_sw find\n", __func__); + if (audio_adapter_flag) + pr_err("%s audio_adapter_flag = %d\n",__func__,audio_adapter_flag); + + mbhc_sw_gpio = of_get_named_gpio(np, "mbhc_sw", 0); + if (mbhc_sw_gpio < 0){ + pr_err("mbhc_sw_gpio of get gpio failed\n"); + } else { + gpio_free(mbhc_sw_gpio); + ret = devm_gpio_request_one(&pdev->dev, mbhc_sw_gpio, + GPIOF_OUT_INIT_HIGH, "mbhc sw gpio"); + if (ret) { + pr_err("%s devm_gpio_request_one mbhc_sw_gpio failed\n",__func__); + } + } + + usb_sw_gpio = of_get_named_gpio(np, "usb_sw", 0); + if (usb_sw_gpio < 0){ + pr_err("usb_sw_gpio of get gpio failed\n"); + } else { + gpio_free(usb_sw_gpio); + ret = devm_gpio_request_one(&pdev->dev, usb_sw_gpio, + GPIOF_OUT_INIT_LOW, "usb sw gpio"); + if (ret) { + pr_err("%s devm_gpio_request_one usb sw gpio failed\n",__func__); + } + } + + hp_sw_gpio = of_get_named_gpio(np, "hp_sw", 0); + if (hp_sw_gpio < 0){ + pr_err("hp_sw_gpio of get gpio failed\n"); + } else { + pr_err("hp_sw_gpio of get gpio success\n"); + gpio_free(hp_sw_gpio); + ret = devm_gpio_request_one(&pdev->dev, hp_sw_gpio, + GPIOF_OUT_INIT_LOW, "hp sw gpio"); + if (ret) { + pr_err("%s devm_gpio_request_one hp_sw_gpio failed\n",__func__); + } + } + + ldo_sw_gpio = of_get_named_gpio(np, "ldo_sw", 0); + if (ldo_sw_gpio < 0){ + pr_err("ldo_sw_gpio of get gpio failed\n"); + } else { + pr_err("ldo_sw_gpio of get gpio success\n"); + gpio_free(ldo_sw_gpio); + ret = devm_gpio_request_one(&pdev->dev, ldo_sw_gpio, + GPIOF_OUT_INIT_LOW, "ldo sw gpio"); + if (ret) { + pr_err("%s devm_gpio_request_one ldo_sw_gpio failed\n",__func__); + } + } + + register_cc_notifier_client(&typec_cc_notifier); + if (audio_adapter_flag) { + pr_err("%s audio_adapter_flag init to handle usbtypeC headset\n",__func__); + cc_audio_adapter_detect_callback(NULL, 1, NULL); + } + } +#endif + + wcd_mbhc_cfg.swap_gnd_mic = msm_swap_gnd_mic; ret = msm_prepare_us_euro(card); if (ret) dev_dbg(&pdev->dev, "msm_prepare_us_euro failed (%d)\n", diff --git a/techpack/audio/config/sdm845auto.conf b/techpack/audio/config/sdm845auto.conf index 9933bc303cd0..ef914eb6fd1f 100644 --- a/techpack/audio/config/sdm845auto.conf +++ b/techpack/audio/config/sdm845auto.conf @@ -36,3 +36,6 @@ export CONFIG_WCD_DSP_GLINK=y export CONFIG_MSM_AVTIMER=y export CONFIG_SND_SOC_MSM_HDMI_CODEC_RX=y export CONFIG_WCD_SPI_DMA_MASKING=y +export CONFIG_SND_SOC_FSA4840=y +export CONFIG_SND_SOC_MAX98927=y +export CONFIG_SND_SOC_TFA98XX=y diff --git a/techpack/audio/config/sdm845autoconf.h b/techpack/audio/config/sdm845autoconf.h index 709b07e0fd7e..831cd20aeedb 100644 --- a/techpack/audio/config/sdm845autoconf.h +++ b/techpack/audio/config/sdm845autoconf.h @@ -40,3 +40,6 @@ #define CONFIG_MSM_AVTIMER 1 #define CONFIG_SND_SOC_MSM_HDMI_CODEC_RX 1 #define CONFIG_WCD_SPI_DMA_MASKING 1 +#define CONFIG_SND_SOC_FSA4840 1 +#define CONFIG_SND_SOC_MAX98927 1 +#define CONFIG_SND_SOC_TFA98XX 1 diff --git a/techpack/audio/dsp/q6afe.c b/techpack/audio/dsp/q6afe.c index 490f1708d372..2e505aec821b 100644 --- a/techpack/audio/dsp/q6afe.c +++ b/techpack/audio/dsp/q6afe.c @@ -252,6 +252,9 @@ struct afe_ctl { uint32_t cps_ch_mask; struct afe_cps_hw_intf_cfg *cps_config; int lsm_afe_ports[MAX_LSM_SESSIONS]; +#ifdef CONFIG_SND_SOC_MAX98927 + uint8_t *dsm_payload; +#endif }; struct afe_clkinfo_per_port { @@ -915,6 +918,33 @@ static int32_t sp_make_afe_callback(uint32_t opcode, uint32_t *payload, atomic_set(&this_afe.state, -1); } +#ifdef CONFIG_SND_SOC_MAX98927 + if ( + param_id == AFE_PARAM_ID_DSM_CFG || + param_id == AFE_PARAM_ID_DSM_INFO || + param_id == AFE_PARAM_ID_CALIB){ + struct afe_dsm_get_resp *dsm_resp = + (struct afe_dsm_get_resp *) payload; + + if (payload_size < sizeof(*dsm_resp)) { + pr_err("%s: Error: received size %d, afe_dsm_get_resp size %zu\n", + __func__, payload_size, sizeof(*dsm_resp)); + return -EINVAL; + } + + if (this_afe.dsm_payload) + memcpy(this_afe.dsm_payload, dsm_resp->payload, + payload_size - sizeof(*dsm_resp)); + + if (!dsm_resp->status) { + atomic_set(&this_afe.state, 0); + } else { + pr_debug("%s: dsm resp status: %d", __func__, dsm_resp->status); + atomic_set(&this_afe.state, -1); + } + } +#endif + return 0; } @@ -2402,6 +2432,200 @@ static int afe_send_cps_config(int src_port) return ret; } +#ifdef CONFIG_SND_SOC_MAX98927 +int afe_dsm_setget_params(uint8_t *payload, int size, int dir, uint32_t dst_port, uint32_t mod_id, uint32_t param_id) +{ + struct afe_dsm_set_command *set = NULL; + struct afe_dsm_get_command *get = NULL; + uint32_t *config = NULL; + int index = 0, ret = -EINVAL; + + if (!payload || size <= 0) { + pr_err("%s: Invalid params\n", __func__); + goto fail_cmd; + } + ret = q6audio_validate_port(dst_port); + if (ret < 0) { + pr_err("%s: Invalid src port 0x%x ret %d", + __func__, dst_port, ret); + ret = -EINVAL; + goto fail_cmd; + } + + index = q6audio_get_port_index(dst_port); + if (index < 0 || index > AFE_MAX_PORTS) { + pr_err("%s: AFE port index[%d] invalid!\n", + __func__, index); + ret = -EINVAL; + goto fail_cmd; + } + + if (dir){ + get = (struct afe_dsm_get_command *) (payload - sizeof(*get)); + + memset(get, 0 , sizeof(*get)); + + get->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, + APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER); + get->hdr.pkt_size = size + sizeof(*get); + get->hdr.token = index; + get->hdr.opcode = AFE_PORT_CMD_GET_PARAM_V2; + get->param.port_id = q6audio_get_port_id(dst_port); + get->param.payload_size = size + sizeof(struct afe_port_param_data_v2); + get->param.module_id = mod_id; + get->param.param_id = param_id; + get->pdata.module_id = mod_id; + get->pdata.param_id = param_id; + get->pdata.param_size = size; + + this_afe.dsm_payload = payload; + + config = (uint32_t *)get; + } + else{ + set = (struct afe_dsm_set_command *) (payload - sizeof(*set)); + + memset(set, 0 , sizeof(*set)); + + set->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, + APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER); + set->hdr.pkt_size = size + sizeof(*set); + set->hdr.token = index; + set->hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2; + set->param.port_id = q6audio_get_port_id(dst_port); + set->param.payload_size = size + sizeof(struct afe_port_param_data_v2); + set->pdata.module_id = mod_id; + set->pdata.param_id = param_id; + set->pdata.param_size = size; + + config = (uint32_t *)set; + } + + atomic_set(&this_afe.state, 1); + atomic_set(&this_afe.status, 0); + ret = apr_send_pkt(this_afe.apr, config); + if (ret < 0) { + pr_err("%s: port = 0x%x failed %d\n", __func__, dst_port, ret); + goto fail_cmd; + } + ret = wait_event_timeout(this_afe.wait[index], + (atomic_read(&this_afe.state) == 0), + msecs_to_jiffies(TIMEOUT_MS)); + if (!ret) { + pr_err("%s: wait_event timeout\n", __func__); + ret = -EINVAL; + goto fail_cmd; + } + if (atomic_read(&this_afe.status) > 0) { + pr_err("%s: config cmd failed [%s]\n", + __func__, adsp_err_get_err_str( + atomic_read(&this_afe.status))); + ret = adsp_err_get_lnx_err_code( + atomic_read(&this_afe.status)); + goto fail_cmd; + } + + ret = 0; + +fail_cmd: + pr_debug("%s: status %d 0x%x\n",__func__, ret, dst_port); + + this_afe.dsm_payload = NULL; + + return ret; +} +// below export to 98928 driver +int afe_dsm_ramp_dn_cfg(uint8_t *payload, int delay_in_ms) +{ + uint32_t *params = (uint32_t *)payload; + *(params) = 0; + *(params + 1) = 3; //three command will be sent + *(params + 2) = 0x03000063; // fade out time + *(params + 3) = 50; //5; // 5ms suzhiguang,change to 50 to avoid pop + *(params + 4) = 0x03000064; // mute time + *(params + 5) = 200; // 5s mute time will make sure silence output till PA software shutdown. + *(params + 6) = 0x03000066; // start fade + *(params + 7) = 1; + + afe_dsm_setget_params(payload, 8*sizeof(uint32_t), 0, DSM_RX_PORT_ID, AFE_MODULE_DSM_RX, AFE_PARAM_ID_DSM_CFG); + + usleep_range(delay_in_ms*1000, delay_in_ms*1000 + 10); + return 0; +} + +int afe_dsm_rx_set_params(uint8_t *payload, int size) +{ + return afe_dsm_setget_params(payload, size, 0, DSM_RX_PORT_ID, AFE_MODULE_DSM_RX, AFE_PARAM_ID_DSM_CFG); +} + +int afe_dsm_rx_get_params(uint8_t *payload, int size) +{ + return afe_dsm_setget_params(payload, size, 1, DSM_RX_PORT_ID, AFE_MODULE_DSM_RX, AFE_PARAM_ID_DSM_CFG); +} + +int afe_dsm_set_calib(uint8_t* payload) +{ + return afe_dsm_setget_params(payload, sizeof(uint32_t)*3, 0, DSM_TX_PORT_ID, AFE_MODULE_DSM_TX, AFE_PARAM_ID_CALIB); +} + +int afe_dsm_pre_calib(uint8_t* payload) +{ + uint32_t *params = (uint32_t *)payload; + *(params) = 0; + *(params + 1) = 1; //count + *(params + 2) = 0x03000001; // enable flag + *(params + 3) = 4; // mode 0: disable, 1: enable, 2: bypass and pilot tone, 4: pilot tone only + afe_dsm_setget_params(payload, 4*sizeof(uint32_t), 0, DSM_RX_PORT_ID, AFE_MODULE_DSM_RX, AFE_PARAM_ID_DSM_CFG); + usleep_range(1000*1000, 1000*1000 + 10); //make the stable iv data + return 0; +} + +int afe_dsm_post_calib(uint8_t* payload) +{ + uint32_t *params = (uint32_t *)payload; + *(params) = 0; + *(params + 1) = 1; //count + *(params + 2) = 0x03000001; // enable flag + *(params + 3) = 1; // mode 0: disable, 1: enable, 2: bypass and pilot tone, 4: pilot tone only + return afe_dsm_setget_params(payload, 4*sizeof(uint32_t), 0, DSM_RX_PORT_ID, AFE_MODULE_DSM_RX, AFE_PARAM_ID_DSM_CFG); +} + +int afe_dsm_get_calib(uint8_t* payload){ + return afe_dsm_setget_params(payload, sizeof(uint32_t)*14, 1, DSM_TX_PORT_ID, AFE_MODULE_DSM_TX, AFE_PARAM_ID_CALIB); +} + +int afe_dsm_get_average_calib(uint8_t* payload) +{ + uint32_t *params = (uint32_t *)payload; + uint64_t sum_rdc[2] ={0, 0}; + int i, rc = 0; + for (i = 0; i < 4; i++) { + rc = afe_dsm_setget_params(payload, sizeof(uint32_t)*14, 1, DSM_TX_PORT_ID, AFE_MODULE_DSM_TX, AFE_PARAM_ID_CALIB); + if (rc != 0) { + sum_rdc[0] = 0; + sum_rdc[1] = 0; + goto failed; + } + sum_rdc[0] += params[0]; + sum_rdc[1] += params[1]; + usleep_range(50 * 1000, 50 * 1000 + 10); + } + +failed: + params[0] = (sum_rdc[0] >> 2); + params[1] = (sum_rdc[1] >> 2); + return rc; +} + +int afe_dsm_get_libary_info(uint32_t* payload, int size) +{ + return afe_dsm_setget_params((int8_t*) payload, 4 * 100, 1, + DSM_TX_PORT_ID, AFE_MODULE_DSM_TX, + AFE_PARAM_ID_DSM_INFO); +} + +#endif + static int afe_spk_prot_prepare(int src_port, int dst_port, int param_id, union afe_spkr_prot_config *prot_config, uint32_t param_size) { diff --git a/techpack/audio/include/asoc/wcd9xxx-slimslave.h b/techpack/audio/include/asoc/wcd9xxx-slimslave.h index 70b9a4c92bbd..5f9d43acd635 100644 --- a/techpack/audio/include/asoc/wcd9xxx-slimslave.h +++ b/techpack/audio/include/asoc/wcd9xxx-slimslave.h @@ -7,6 +7,8 @@ #include #include "core.h" +/*2018/06/14 @bsp add for support notify audio adapter switch*/ +#include /* @@ -108,4 +110,7 @@ int wcd9xxx_rx_vport_validation(u32 port_id, int wcd9xxx_tx_vport_validation(u32 vtable, u32 port_id, struct wcd9xxx_codec_dai_data *codec_dai, u32 num_codec_dais); +/*2018/06/14 @bsp add for support notify audio adapter switch*/ +extern int register_cc_notifier_client(struct notifier_block *nb); +extern int unregister_cc_notifier_client(struct notifier_block *nb); #endif /* __WCD9XXX_SLIMSLAVE_H_ */ diff --git a/techpack/audio/include/dsp/apr_audio-v2.h b/techpack/audio/include/dsp/apr_audio-v2.h index ea72c8148471..fcc277e23d12 100644 --- a/techpack/audio/include/dsp/apr_audio-v2.h +++ b/techpack/audio/include/dsp/apr_audio-v2.h @@ -11484,6 +11484,45 @@ union afe_spkr_prot_config { struct afe_sp_v4_param_vi_channel_map_cfg v4_ch_map_cfg; } __packed; +#ifdef CONFIG_SND_SOC_MAX98927 +/*Maxim DSM module and parameters IDs*/ +#define AFE_RX_TOPOLOGY_ID_DSM 0x10001061 +#define AFE_TX_TOPOLOGY_ID_DSM 0x10001060 +#define AFE_MODULE_DSM_TX 0x10001068 +#define AFE_MODULE_DSM_RX 0x10001062 +#define AFE_PARAM_ID_DSM_ENABLE 0x10001063 +#define AFE_PARAM_ID_CALIB 0x10001065 +#define AFE_PARAM_ID_DSM_CFG 0x10001066 +#define AFE_PARAM_ID_DSM_INFO 0x10001067 + +#define DSM_RX_PORT_ID AFE_PORT_ID_QUATERNARY_MI2S_RX +#define DSM_TX_PORT_ID AFE_PORT_ID_QUATERNARY_MI2S_TX + +struct afe_dsm_param_array { + uint32_t count; + uint32_t flagToWrite; + uint32_t Reserve[2]; + uint32_t params[100]; +}; + +struct afe_dsm_set_command { + struct apr_hdr hdr; + struct afe_port_cmd_set_param_v2 param; + struct afe_port_param_data_v2 pdata; +} __packed; + +struct afe_dsm_get_command { + struct apr_hdr hdr; + struct afe_port_cmd_get_param_v2 param; + struct afe_port_param_data_v2 pdata; +} __packed; + +struct afe_dsm_get_resp { + uint32_t status; + struct afe_port_param_data_v2 pdata; + uint32_t payload[0]; +} __packed; +#endif /* SRS TRUMEDIA start */ /* topology */ From 587e42590f1205d9c7af6076b70bd62ffd98c086 Mon Sep 17 00:00:00 2001 From: Marc Bourgoin Date: Wed, 22 Dec 2021 01:03:55 -0700 Subject: [PATCH 311/356] techpack: audio: tfa9874: fix implicit conversion from enumeration type Change-Id: I1dda02b652cd9dfec3d518697143098399e353de --- techpack/audio/asoc/codecs/tfa9874/tfa98xx.c | 46 +++++++++---------- .../audio/asoc/codecs/tfa9874/tfa_device.h | 16 +++---- techpack/audio/asoc/codecs/tfa9874/tfa_dsp.c | 24 +++++----- 3 files changed, 43 insertions(+), 43 deletions(-) diff --git a/techpack/audio/asoc/codecs/tfa9874/tfa98xx.c b/techpack/audio/asoc/codecs/tfa9874/tfa98xx.c index 4be3f0acc67a..6cb85220a8ad 100644 --- a/techpack/audio/asoc/codecs/tfa9874/tfa98xx.c +++ b/techpack/audio/asoc/codecs/tfa9874/tfa98xx.c @@ -143,17 +143,17 @@ static inline char *tfa_cont_profile_name(struct tfa98xx *tfa98xx, int prof_idx) return tfaContProfileName(tfa98xx->tfa->cnt, tfa98xx->tfa->dev_idx, prof_idx); } -static enum tfa_error tfa98xx_write_re25(struct tfa_device *tfa, int value) +static enum Tfa98xx_Error tfa98xx_write_re25(struct tfa_device *tfa, int value) { - enum tfa_error err; + enum Tfa98xx_Error err; /* clear MTPEX */ err = tfa_dev_mtp_set(tfa, TFA_MTP_EX, 0); - if (err == tfa_error_ok) { + if (err == Tfa98xx_Error_Ok) { /* set RE25 in shadow regiser */ err = tfa_dev_mtp_set(tfa, TFA_MTP_RE25_PRIM, value); } - if (err == tfa_error_ok) { + if (err == Tfa98xx_Error_Ok) { /* set MTPEX to copy RE25 into MTP */ err = tfa_dev_mtp_set(tfa, TFA_MTP_EX, 2); } @@ -162,9 +162,9 @@ static enum tfa_error tfa98xx_write_re25(struct tfa_device *tfa, int value) } /* Wrapper for tfa start */ -static enum tfa_error tfa98xx_tfa_start(struct tfa98xx *tfa98xx, int next_profile, int vstep) +static enum Tfa98xx_Error tfa98xx_tfa_start(struct tfa98xx *tfa98xx, int next_profile, int vstep) { - enum tfa_error err; + enum Tfa98xx_Error err; ktime_t start_time, stop_time; u64 delta_time; @@ -184,10 +184,10 @@ static enum tfa_error tfa98xx_tfa_start(struct tfa98xx *tfa98xx, int next_profil next_profile, vstep, delta_time); } - if ((err == tfa_error_ok) && (tfa98xx->set_mtp_cal)) { - enum tfa_error err_cal; + if ((err == Tfa98xx_Error_Ok) && (tfa98xx->set_mtp_cal)) { + enum Tfa98xx_Error err_cal; err_cal = tfa98xx_write_re25(tfa98xx->tfa, tfa98xx->cal_data); - if (err_cal != tfa_error_ok) { + if (err_cal != Tfa98xx_Error_Ok) { pr_err("Error, setting calibration value in mtp, err=%d\n", err_cal); } else { tfa98xx->set_mtp_cal = false; @@ -372,7 +372,7 @@ static int tfa98xx_dbgfs_otc_set(void *data, u64 val) { struct i2c_client *i2c = (struct i2c_client *)data; struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); - enum tfa_error err; + enum Tfa98xx_Error err; if (val != 0 && val != 1) { pr_err("[0x%x] Unexpected value %llu\n", tfa98xx->i2c->addr, val); @@ -383,7 +383,7 @@ static int tfa98xx_dbgfs_otc_set(void *data, u64 val) err = tfa_dev_mtp_set(tfa98xx->tfa, TFA_MTP_OTC, val); mutex_unlock(&tfa98xx->dsp_lock); - if (err != tfa_error_ok) { + if (err != Tfa98xx_Error_Ok) { pr_err("[0x%x] Unable to check DSP access: %d\n", tfa98xx->i2c->addr, err); return -EIO; } @@ -419,7 +419,7 @@ static int tfa98xx_dbgfs_mtpex_set(void *data, u64 val) { struct i2c_client *i2c = (struct i2c_client *)data; struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); - enum tfa_error err; + enum Tfa98xx_Error err; if (val != 0) { pr_err("[0x%x] Can only clear MTPEX (0 value expected)\n", tfa98xx->i2c->addr); @@ -430,7 +430,7 @@ static int tfa98xx_dbgfs_mtpex_set(void *data, u64 val) err = tfa_dev_mtp_set(tfa98xx->tfa, TFA_MTP_EX, val); mutex_unlock(&tfa98xx->dsp_lock); - if (err != tfa_error_ok) { + if (err != Tfa98xx_Error_Ok) { pr_err("[0x%x] Unable to check DSP access: %d\n", tfa98xx->i2c->addr, err); return -EIO; } @@ -474,7 +474,7 @@ static ssize_t tfa98xx_dbgfs_start_set(struct file *file, { struct i2c_client *i2c = file->private_data; struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); - enum tfa_error ret; + enum Tfa98xx_Error ret; char buf[32]; const char ref[] = "please calibrate now"; int buf_size; @@ -494,10 +494,10 @@ static ssize_t tfa98xx_dbgfs_start_set(struct file *file, mutex_lock(&tfa98xx->dsp_lock); ret = tfa_calibrate(tfa98xx->tfa); - if (ret == tfa_error_ok) + if (ret == Tfa98xx_Error_Ok) ret = tfa98xx_tfa_start(tfa98xx, tfa98xx->profile, tfa98xx->vstep); - if (ret == tfa_error_ok) - tfa_dev_set_state(tfa98xx->tfa, TFA_STATE_UNMUTE); + if (ret == Tfa98xx_Error_Ok) + tfa_dev_set_state(tfa98xx->tfa, TFA_STATE_UNMUTE); mutex_unlock(&tfa98xx->dsp_lock); if (ret) { @@ -624,7 +624,7 @@ static ssize_t tfa98xx_dbgfs_dsp_state_set(struct file *file, { struct i2c_client *i2c = file->private_data; struct tfa98xx *tfa98xx = i2c_get_clientdata(i2c); - enum tfa_error ret; + enum Tfa98xx_Error ret; char buf[32]; const char start_cmd[] = "start"; const char stop_cmd[] = "stop"; @@ -1326,14 +1326,14 @@ static int tfa98xx_set_cal_ctl(struct snd_kcontrol *kcontrol, mutex_lock(&tfa98xx_mutex); list_for_each_entry(tfa98xx, &tfa98xx_device_list, list) { - enum tfa_error err; + enum Tfa98xx_Error err; int i = tfa98xx->tfa->dev_idx; tfa98xx->cal_data = (uint16_t)ucontrol->value.integer.value[i]; mutex_lock(&tfa98xx->dsp_lock); err = tfa98xx_write_re25(tfa98xx->tfa, tfa98xx->cal_data); - tfa98xx->set_mtp_cal = (err != tfa_error_ok); + tfa98xx->set_mtp_cal = (err != Tfa98xx_Error_Ok); if (tfa98xx->set_mtp_cal == false) { pr_info("Calibration value (%d) set in mtp\n", tfa98xx->cal_data); @@ -1961,7 +1961,7 @@ static void tfa98xx_container_loaded(const struct firmware *cont, void *context) { nxpTfaContainer_t *container; struct tfa98xx *tfa98xx = context; - enum tfa_error tfa_err; + enum Tfa98xx_Error tfa_err; int container_size; int ret; @@ -1995,8 +1995,8 @@ static void tfa98xx_container_loaded(const struct firmware *cont, void *context) pr_info("%d ndev\n", container->ndev); pr_info("%d nprof\n", container->nprof); - tfa_err = tfa_load_cnt(container, container_size); - if (tfa_err != tfa_error_ok) { + tfa_err = (enum Tfa98xx_Error)(tfa_load_cnt(container, container_size)); + if (tfa_err != Tfa98xx_Error_Ok) { mutex_unlock(&tfa98xx_mutex); kfree(container); dev_err(tfa98xx->dev, "Cannot load container file, aborting\n"); diff --git a/techpack/audio/asoc/codecs/tfa9874/tfa_device.h b/techpack/audio/asoc/codecs/tfa9874/tfa_device.h index 732f4cc1a533..5b7bc6708e84 100644 --- a/techpack/audio/asoc/codecs/tfa9874/tfa_device.h +++ b/techpack/audio/asoc/codecs/tfa9874/tfa_device.h @@ -183,9 +183,9 @@ int tfa_dev_probe(int slave, struct tfa_device *tfa); * @param tfa struct = pointer to context of this device instance * @param profile the selected profile to run * @param vstep the selected vstep to use - * @return tfa_error enum + * @return Tfa98xx_Error enum */ -enum tfa_error tfa_dev_start(struct tfa_device *tfa, int profile, int vstep); +enum Tfa98xx_Error tfa_dev_start(struct tfa_device *tfa, int profile, int vstep); /** @@ -197,9 +197,9 @@ enum tfa_error tfa_dev_start(struct tfa_device *tfa, int profile, int vstep); * Note that this call will change state of the tfa to mute and powered down. * * @param tfa struct = pointer to context of this device instance - * @return tfa_error enum + * @return Tfa98xx_Error enum */ -enum tfa_error tfa_dev_stop(struct tfa_device *tfa); +enum Tfa98xx_Error tfa_dev_stop(struct tfa_device *tfa); /** * This interface allows a device/type independent fine grained control of the @@ -218,9 +218,9 @@ enum tfa_error tfa_dev_stop(struct tfa_device *tfa); * * @param tfa struct = pointer to context of this device instance * @param state struct = desired device state after function return - * @return tfa_error enum + * @return Tfa98xx_Error enum */ -enum tfa_error tfa_dev_set_state(struct tfa_device *tfa, enum tfa_state state); +enum Tfa98xx_Error tfa_dev_set_state(struct tfa_device *tfa, enum tfa_state state); /** * Retrieve the current state of this instance in an active way. @@ -230,7 +230,7 @@ enum tfa_error tfa_dev_set_state(struct tfa_device *tfa, enum tfa_state state); * field should be treated as volatile. * * @param tfa struct = pointer to context of this device instance - * @return tfa_error enum + * @return Tfa98xx_Error enum * */ enum tfa_state tfa_dev_get_state(struct tfa_device *tfa); @@ -258,7 +258,7 @@ int tfa_dev_mtp_get(struct tfa_device *tfa, enum tfa_mtp item); /** * */ -enum tfa_error tfa_dev_mtp_set(struct tfa_device *tfa, enum tfa_mtp item, int value); +enum Tfa98xx_Error tfa_dev_mtp_set(struct tfa_device *tfa, enum tfa_mtp item, int value); //irq diff --git a/techpack/audio/asoc/codecs/tfa9874/tfa_dsp.c b/techpack/audio/asoc/codecs/tfa9874/tfa_dsp.c index 4589778500c7..4406d3fdcc62 100644 --- a/techpack/audio/asoc/codecs/tfa9874/tfa_dsp.c +++ b/techpack/audio/asoc/codecs/tfa9874/tfa_dsp.c @@ -2981,7 +2981,7 @@ enum Tfa98xx_Error tfaRunWaitCalibration(struct tfa_device *tfa, int *calibrateD * tfa_dev_start will only do the basics: Going from powerdown to operating or a profile switch. * for calibrating or akoustic shock handling use the tfa98xxCalibration function. */ -enum tfa_error tfa_dev_start(struct tfa_device *tfa, int next_profile, int vstep) +enum Tfa98xx_Error tfa_dev_start(struct tfa_device *tfa, int next_profile, int vstep) { enum Tfa98xx_Error err = Tfa98xx_Error_Ok; int active_profile = -1; @@ -3067,10 +3067,10 @@ enum tfa_error tfa_dev_start(struct tfa_device *tfa, int next_profile, int vstep error_exit: show_current_state(tfa); - return err; + return (enum Tfa98xx_Error)(err); } -enum tfa_error tfa_dev_stop(struct tfa_device *tfa) +enum Tfa98xx_Error tfa_dev_stop(struct tfa_device *tfa) { enum Tfa98xx_Error err = Tfa98xx_Error_Ok; int times = 0, ready; @@ -3104,7 +3104,7 @@ enum tfa_error tfa_dev_stop(struct tfa_device *tfa) pr_debug("tfa stop: Not in PowerDown\n"); } - return (enum tfa_error)err; //liuhaituo modify + return (enum Tfa98xx_Error)err; //liuhaituo modify } /* @@ -3547,9 +3547,9 @@ int tfa_dev_probe(int slave, struct tfa_device *tfa) return 0; } -enum tfa_error tfa_dev_set_state(struct tfa_device *tfa, enum tfa_state state) +enum Tfa98xx_Error tfa_dev_set_state(struct tfa_device *tfa, enum tfa_state state) { - enum tfa_error err = tfa_error_ok; + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; int loop = 50, ready = 0; int count; @@ -3574,7 +3574,7 @@ enum tfa_error tfa_dev_set_state(struct tfa_device *tfa, enum tfa_state state) /* Make sure the DSP is running! */ do { err = tfa98xx_dsp_system_stable(tfa, &ready); - if (err != tfa_error_ok) + if (err != Tfa98xx_Error_Ok) return err; if (ready) break; @@ -3634,7 +3634,7 @@ enum tfa_error tfa_dev_set_state(struct tfa_device *tfa, enum tfa_state state) break; default: if (state & 0x0f) - return tfa_error_bad_param; + return Tfa98xx_Error_Bad_Parameter; } /* state modifiers */ @@ -3647,7 +3647,7 @@ enum tfa_error tfa_dev_set_state(struct tfa_device *tfa, enum tfa_state state) tfa->state = state; - return tfa_error_ok; + return Tfa98xx_Error_Ok; } enum tfa_state tfa_dev_get_state(struct tfa_device *tfa) @@ -3719,9 +3719,9 @@ int tfa_dev_mtp_get(struct tfa_device *tfa, enum tfa_mtp item) return value; } -enum tfa_error tfa_dev_mtp_set(struct tfa_device *tfa, enum tfa_mtp item, int value) +enum Tfa98xx_Error tfa_dev_mtp_set(struct tfa_device *tfa, enum tfa_mtp item, int value) { - enum tfa_error err = tfa_error_ok; + enum Tfa98xx_Error err = Tfa98xx_Error_Ok; switch (item) { case TFA_MTP_OTC: @@ -3744,7 +3744,7 @@ enum tfa_error tfa_dev_mtp_set(struct tfa_device *tfa, enum tfa_mtp item, int va TFA_SET_BF(tfa, R25CR, (uint16_t)value); } else { pr_debug("Error: Current device has no secondary Re25 channel \n"); - err = tfa_error_bad_param; + err = Tfa98xx_Error_Bad_Parameter; } break; case TFA_MTP_LOCK: From f367f3abdb24c493ef80d37749827d1c77ba1924 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Fri, 14 Apr 2023 21:08:11 +0000 Subject: [PATCH 312/356] techpack: audio: max98927: Update for 4.19 --- .../audio/asoc/codecs/max98927/max98927.c | 145 +++++++++--------- .../audio/asoc/codecs/max98927/max98927.h | 2 +- techpack/audio/dsp/q6afe.c | 6 +- techpack/audio/include/dsp/apr_audio-v2.h | 24 +++ 4 files changed, 100 insertions(+), 77 deletions(-) diff --git a/techpack/audio/asoc/codecs/max98927/max98927.c b/techpack/audio/asoc/codecs/max98927/max98927.c index 3a63ea9660bd..0c5ae34c39fd 100644 --- a/techpack/audio/asoc/codecs/max98927/max98927.c +++ b/techpack/audio/asoc/codecs/max98927/max98927.c @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -973,8 +974,8 @@ void max98927_wrap_update_bits(struct max98927_priv *max98927, static int max98927_reg_get_w(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct max98927_priv *max98927 = snd_soc_component_get_drvdata(component); struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; int reg = mc->reg; @@ -999,8 +1000,8 @@ static int max98927_reg_get_w(struct snd_kcontrol *kcontrol, static int max98927_reg_put_w(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct max98927_priv *max98927 = snd_soc_component_get_drvdata(component); struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; int reg = mc->reg; @@ -1024,8 +1025,8 @@ static int max98927_reg_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol, unsigned int reg, unsigned int mask, unsigned int shift) { - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct max98927_priv *max98927 = snd_soc_component_get_drvdata(component); int data; max98927_wrapper_read(max98927, 0, reg, &data); @@ -1038,8 +1039,8 @@ static int max98927_reg_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol, unsigned int reg, unsigned int mask, unsigned int shift) { - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct max98927_priv *max98927 = snd_soc_component_get_drvdata(component); unsigned int sel = ucontrol->value.integer.value[0]; max98927_wrap_update_bits(max98927, reg, mask, sel << shift); @@ -1051,8 +1052,8 @@ static int max98927_reg_put(struct snd_kcontrol *kcontrol, static int max98927_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) { - struct snd_soc_codec *codec = codec_dai->codec; - struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *component = codec_dai->component; + struct max98927_priv *max98927 = snd_soc_component_get_drvdata(component); pr_info("%s: fmt 0x%08X\n", __func__, fmt); switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { @@ -1169,8 +1170,8 @@ static int max98927_dai_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { - struct snd_soc_codec *codec = dai->codec; - struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *component = dai->component; + struct max98927_priv *max98927 = snd_soc_component_get_drvdata(component); int sampling_rate = 0; switch (snd_pcm_format_width(params_format(params))) { @@ -1270,8 +1271,8 @@ static int max98927_dai_hw_params(struct snd_pcm_substream *substream, static int max98927_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int freq, int dir) { - struct snd_soc_codec *codec = dai->codec; - struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *component = dai->component; + struct max98927_priv *max98927 = snd_soc_component_get_drvdata(component); pr_info("%s: clk_id %d, freq %d, dir %d\n", __func__, clk_id, freq, dir); max98927->sysclk = freq; @@ -1280,8 +1281,8 @@ static int max98927_dai_set_sysclk(struct snd_soc_dai *dai, static int max98927_stream_mute(struct snd_soc_dai *codec_dai, int mute, int stream) { - struct snd_soc_codec *codec = codec_dai->codec; - struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *component = codec_dai->component; + struct max98927_priv *max98927 = snd_soc_component_get_drvdata(component); uint32_t* payload = (uint32_t *)&gParam[PKG_HEADER]; int rc = 0; uint32_t impedance = 0; @@ -1373,9 +1374,9 @@ static int max98927_feedforward_event(struct snd_soc_dapm_widget *w, int event) { u32 ret = 0; - //struct snd_soc_codec *codec = w->codec; - struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); - struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + //struct snd_soc_component *component = w->component; + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct max98927_priv *max98927 = snd_soc_component_get_drvdata(component); /* uint32_t* payload = (uint32_t *)&gParam[PKG_HEADER]; */ if(!max98927){ @@ -1402,9 +1403,9 @@ static int max98927_feedback_event(struct snd_soc_dapm_widget *w, int event) { u32 ret = 0; - //struct snd_soc_codec *codec = w->codec; - struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); - struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + //struct snd_soc_component *component = w->component; + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct max98927_priv *max98927 = snd_soc_component_get_drvdata(component); if(!max98927){ pr_err("%s------priv data null pointer\n", __func__); return ret; @@ -1452,8 +1453,8 @@ static int max98927_info_rivision_ctl(struct snd_kcontrol *kcontrol, static int max98927_get_rivision_ctl(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct max98927_priv *max98927 = snd_soc_component_get_drvdata(component); int ret; unsigned int reg; @@ -1483,8 +1484,8 @@ static DECLARE_TLV_DB_SCALE(max98927_digital_tlv, -1600, 25, 0); static int max98927_spk_gain_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct max98927_priv *max98927 = snd_soc_component_get_drvdata(component); ucontrol->value.integer.value[0] = max98927->spk_gain; pr_info("max98927_spk_gain_get: spk_gain setting returned %d\n", @@ -1496,8 +1497,8 @@ static int max98927_spk_gain_get(struct snd_kcontrol *kcontrol, static int max98927_spk_gain_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct max98927_priv *max98927 = snd_soc_component_get_drvdata(component); unsigned int sel = ucontrol->value.integer.value[0]; pr_info("max98927_spk_gain_put: %d\n",sel); @@ -1512,8 +1513,8 @@ static int max98927_spk_gain_put(struct snd_kcontrol *kcontrol, static int max98927_digital_gain_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct max98927_priv *max98927 = snd_soc_component_get_drvdata(component); ucontrol->value.integer.value[0] = max98927->digital_gain; pr_info("%s: spk_gain setting returned %d\n", __func__, @@ -1524,8 +1525,8 @@ static int max98927_digital_gain_get(struct snd_kcontrol *kcontrol, static int max98927_digital_gain_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct max98927_priv *max98927 = snd_soc_component_get_drvdata(component); unsigned int sel = ucontrol->value.integer.value[0]; pr_info("max98927_digital_gain_put: %d\n",sel); @@ -1596,8 +1597,8 @@ static int max98927_mono_out_put(struct snd_kcontrol *kcontrol, static int max98927_mono_out_get_l(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct max98927_priv *max98927 = snd_soc_component_get_drvdata(component); int data = 0; if(i2c_states & MAX98927_CH0){ regmap_read(max98927->regmap[MAX98927L], MAX98927_PCM_to_speaker_monomix_A, &data); @@ -1612,8 +1613,8 @@ static int max98927_mono_out_get_l(struct snd_kcontrol *kcontrol, static int max98927_mono_out_put_l(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct max98927_priv *max98927 = snd_soc_component_get_drvdata(component); unsigned int sel = ucontrol->value.integer.value[0]; if(i2c_states & MAX98927_CH0){ @@ -1631,8 +1632,8 @@ static int max98927_mono_out_put_l(struct snd_kcontrol *kcontrol, static int max98927_mono_out_get_r(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct max98927_priv *max98927 = snd_soc_component_get_drvdata(component); int data = 0; if(i2c_states & MAX98927_CH1){ @@ -1647,8 +1648,8 @@ static int max98927_mono_out_get_r(struct snd_kcontrol *kcontrol, static int max98927_mono_out_put_r(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct max98927_priv *max98927 = snd_soc_component_get_drvdata(component); unsigned int sel = ucontrol->value.integer.value[0]; if(i2c_states & MAX98927_CH1){ regmap_update_bits(max98927->regmap[MAX98927R], MAX98927_PCM_to_speaker_monomix_A, @@ -1665,8 +1666,8 @@ static int max98927_mono_out_put_r(struct snd_kcontrol *kcontrol, static int max98927_feedback_en_get_l(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct max98927_priv *max98927 = snd_soc_component_get_drvdata(component); int data = 0; if(i2c_states & MAX98927_CH0){ @@ -1681,8 +1682,8 @@ static int max98927_feedback_en_get_l(struct snd_kcontrol *kcontrol, static int max98927_feedback_en_put_l(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct max98927_priv *max98927 = snd_soc_component_get_drvdata(component); unsigned int sel = ucontrol->value.integer.value[0]; if(i2c_states & MAX98927_CH0){ @@ -1696,8 +1697,8 @@ static int max98927_feedback_en_put_l(struct snd_kcontrol *kcontrol, static int max98927_feedback_en_get_r(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct max98927_priv *max98927 = snd_soc_component_get_drvdata(component); int data = 0; if(i2c_states & MAX98927_CH1){ @@ -1711,8 +1712,8 @@ static int max98927_feedback_en_get_r(struct snd_kcontrol *kcontrol, static int max98927_feedback_en_put_r(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct max98927_priv *max98927 = snd_soc_component_get_drvdata(component); unsigned int sel = ucontrol->value.integer.value[0]; if(i2c_states & MAX98927_CH1){ regmap_write(max98927->regmap[MAX98927R], MAX98927_Measurement_enables, sel); @@ -1727,8 +1728,8 @@ static int max98927_feedback_en_put_r(struct snd_kcontrol *kcontrol, static int max98927_left_channel_enable_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct max98927_priv *max98927 = snd_soc_component_get_drvdata(component); int data_global = 0; int data_amp = 0; //int data = 0; @@ -1747,8 +1748,8 @@ static int max98927_left_channel_enable_get(struct snd_kcontrol *kcontrol, static int max98927_left_channel_enable_set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct max98927_priv *max98927 = snd_soc_component_get_drvdata(component); unsigned int sel = ucontrol->value.integer.value[0]; max98927->spk_mode &= ~0x1; max98927->spk_mode |= sel; @@ -1761,8 +1762,8 @@ static int max98927_left_channel_enable_set(struct snd_kcontrol *kcontrol, static int max98927_right_channel_enable_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct max98927_priv *max98927 = snd_soc_component_get_drvdata(component); int data_global = 0; int data_amp = 0; @@ -1780,8 +1781,8 @@ static int max98927_right_channel_enable_get(struct snd_kcontrol *kcontrol, static int max98927_right_channel_enable_set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct max98927_priv *max98927 = snd_soc_component_get_drvdata(component); unsigned int sel = ucontrol->value.integer.value[0]; max98927->spk_mode &= ~0x2; max98927->spk_mode |= sel<<0x1; @@ -1934,21 +1935,21 @@ static struct snd_soc_dai_driver max98927_dai[] = { } }; -static int max98927_probe(struct snd_soc_codec *codec) +static int max98927_probe(struct snd_soc_component *component) { - struct max98927_priv *max98927 = snd_soc_codec_get_drvdata(codec); + struct max98927_priv *max98927 = snd_soc_component_get_drvdata(component); //struct snd_soc_dapm_context *dapm = &codec->dapm; - struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); pr_info("%s: enter\n", __func__); - max98927->codec = codec; + max98927->component = component; snd_soc_dapm_ignore_suspend(dapm, "MAX98927_OUT"); snd_soc_dapm_ignore_suspend(dapm, "MAX98927_IN"); snd_soc_dapm_ignore_suspend(dapm, "HiFi Playback"); snd_soc_dapm_ignore_suspend(dapm, "HiFi Capture"); - snd_soc_add_codec_controls(max98927->codec, max98927_at_controls, + snd_soc_add_component_controls(max98927->component, max98927_at_controls, ARRAY_SIZE(max98927_at_controls)); @@ -1958,16 +1959,14 @@ static int max98927_probe(struct snd_soc_codec *codec) return 0; } -static const struct snd_soc_codec_driver soc_codec_dev_max98927 = { +static const struct snd_soc_component_driver soc_codec_dev_max98927 = { .probe = max98927_probe, - .component_driver = { - .dapm_routes = max98927_audio_map, - .num_dapm_routes = ARRAY_SIZE(max98927_audio_map), - .dapm_widgets = max98927_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(max98927_dapm_widgets), - .controls = max98927_snd_controls, - .num_controls = ARRAY_SIZE(max98927_snd_controls), - }, + .dapm_routes = max98927_audio_map, + .num_dapm_routes = ARRAY_SIZE(max98927_audio_map), + .dapm_widgets = max98927_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(max98927_dapm_widgets), + .controls = max98927_snd_controls, + .num_controls = ARRAY_SIZE(max98927_snd_controls), }; static const struct regmap_config max98927_regmap = { @@ -2137,9 +2136,9 @@ static int max98927_i2c_probe(struct i2c_client *i2c, smartpa_present = 1; if(max98927->dev == NULL){ dev_set_name(&i2c->dev, "%s", "max98927"); //rename the i2c clinet name for easy to use. - ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_max98927, + ret = snd_soc_register_component(&i2c->dev, &soc_codec_dev_max98927, max98927_dai, ARRAY_SIZE(max98927_dai)); - pr_err("****** %s snd_soc_register_codec id =%d\n",__func__,(int)(id->driver_data)); + pr_err("****** %s snd_soc_register_component id =%d\n",__func__,(int)(id->driver_data)); if (ret < 0) { pr_err("max98927 Failed to register codec: %d\n", ret); i2c_states = 0; @@ -2176,7 +2175,7 @@ static int max98927_i2c_remove(struct i2c_client *client) struct max98927_priv *max98927 = i2c_get_clientdata(client); if(max98927) { if(max98927->dev == &client->dev) { - snd_soc_unregister_codec(&client->dev); + snd_soc_unregister_component(&client->dev); i2c_set_clientdata(client, NULL); #ifdef CONFIG_DEBUG_FS max989xx_debug_remove(max98927); diff --git a/techpack/audio/asoc/codecs/max98927/max98927.h b/techpack/audio/asoc/codecs/max98927/max98927.h index eea40a7e4ee5..061882ba458e 100644 --- a/techpack/audio/asoc/codecs/max98927/max98927.h +++ b/techpack/audio/asoc/codecs/max98927/max98927.h @@ -1176,7 +1176,7 @@ typedef enum{ struct max98927_priv { struct device *dev; struct regmap *regmap[MAX_CHANNEL_NUM]; - struct snd_soc_codec *codec; + struct snd_soc_component *component; struct max98927_pdata *pdata; unsigned int spk_mode; unsigned int spk_gain; diff --git a/techpack/audio/dsp/q6afe.c b/techpack/audio/dsp/q6afe.c index 2e505aec821b..9afe132e3f9d 100644 --- a/techpack/audio/dsp/q6afe.c +++ b/techpack/audio/dsp/q6afe.c @@ -920,9 +920,9 @@ static int32_t sp_make_afe_callback(uint32_t opcode, uint32_t *payload, #ifdef CONFIG_SND_SOC_MAX98927 if ( - param_id == AFE_PARAM_ID_DSM_CFG || - param_id == AFE_PARAM_ID_DSM_INFO || - param_id == AFE_PARAM_ID_CALIB){ + param_hdr.param_id == AFE_PARAM_ID_DSM_CFG || + param_hdr.param_id == AFE_PARAM_ID_DSM_INFO || + param_hdr.param_id == AFE_PARAM_ID_CALIB){ struct afe_dsm_get_resp *dsm_resp = (struct afe_dsm_get_resp *) payload; diff --git a/techpack/audio/include/dsp/apr_audio-v2.h b/techpack/audio/include/dsp/apr_audio-v2.h index fcc277e23d12..fdbd28b0cfa6 100644 --- a/techpack/audio/include/dsp/apr_audio-v2.h +++ b/techpack/audio/include/dsp/apr_audio-v2.h @@ -2047,6 +2047,30 @@ struct afe_port_cmd_set_param_v2 { u8 param_data[0]; } __packed; +struct afe_port_param_data_v2 { + u32 module_id; +/* ID of the module to be configured. + * Supported values: Valid module ID + */ + +u32 param_id; +/* ID of the parameter corresponding to the supported parameters + * for the module ID. + * Supported values: Valid parameter ID + */ + +u16 param_size; +/* Actual size of the data for the + * module_id/param_id pair. The size is a + * multiple of four bytes. + * Supported values: > 0 + */ + +u16 reserved; +/* This field must be set to zero. + */ +} __packed; + #define AFE_PORT_CMD_SET_PARAM_V3 0x000100FA struct afe_port_cmd_set_param_v3 { /* APR Header */ From 3c74297b4a1a8b2470cc4739c19dfd0b26e49851 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Fri, 14 Apr 2023 21:08:35 +0000 Subject: [PATCH 313/356] techpack: audio: tfa9874: Update for 4.19 --- techpack/audio/asoc/codecs/tfa9874/tfa98xx.c | 133 +++++++------------ techpack/audio/asoc/codecs/tfa9874/tfa98xx.h | 2 +- 2 files changed, 52 insertions(+), 83 deletions(-) diff --git a/techpack/audio/asoc/codecs/tfa9874/tfa98xx.c b/techpack/audio/asoc/codecs/tfa9874/tfa98xx.c index 6cb85220a8ad..163e38f4a9e3 100644 --- a/techpack/audio/asoc/codecs/tfa9874/tfa98xx.c +++ b/techpack/audio/asoc/codecs/tfa9874/tfa98xx.c @@ -213,7 +213,7 @@ static enum Tfa98xx_Error tfa98xx_tfa_start(struct tfa98xx *tfa98xx, int next_pr static int tfa98xx_input_open(struct input_dev *dev) { struct tfa98xx *tfa98xx = input_get_drvdata(dev); - dev_info(tfa98xx->codec->dev, "opening device file\n"); + dev_info(tfa98xx->component->dev, "opening device file\n"); /* note: open function is called only once by the framework. * No need to count number of open file instances. @@ -235,7 +235,7 @@ static void tfa98xx_input_close(struct input_dev *dev) { struct tfa98xx *tfa98xx = input_get_drvdata(dev); - dev_info(tfa98xx->codec->dev, "closing device file\n"); + dev_info(tfa98xx->component->dev, "closing device file\n"); /* Note: close function is called if the device is unregistered */ @@ -251,7 +251,7 @@ static int tfa98xx_register_inputdev(struct tfa98xx *tfa98xx) input = input_allocate_device(); if (!input) { - dev_err(tfa98xx->codec->dev, "Unable to allocate input device\n"); + dev_err(tfa98xx->component->dev, "Unable to allocate input device\n"); return -ENOMEM; } @@ -277,11 +277,11 @@ static int tfa98xx_register_inputdev(struct tfa98xx *tfa98xx) err = input_register_device(input); if (err) { - dev_err(tfa98xx->codec->dev, "Unable to register input device\n"); + dev_err(tfa98xx->component->dev, "Unable to register input device\n"); goto err_free_dev; } - dev_dbg(tfa98xx->codec->dev, "Input device for tap-detection registered: %s\n", + dev_dbg(tfa98xx->component->dev, "Input device for tap-detection registered: %s\n", input->name); tfa98xx->input = input; return 0; @@ -305,7 +305,7 @@ static void __tfa98xx_inputdev_check_register(struct tfa98xx *tfa98xx, bool unre if (strstr(tfa_cont_profile_name(tfa98xx, i), ".tap")) { tap_profile = true; tfa98xx->tapdet_profiles |= 1 << i; - dev_info(tfa98xx->codec->dev, + dev_info(tfa98xx->component->dev, "found a tap-detection profile (%d - %s)\n", i, tfa_cont_profile_name(tfa98xx, i)); } @@ -328,7 +328,7 @@ static void __tfa98xx_inputdev_check_register(struct tfa98xx *tfa98xx, bool unre /* input device required */ if (tfa98xx->input) - dev_info(tfa98xx->codec->dev, "Input device already registered, skipping\n"); + dev_info(tfa98xx->component->dev, "Input device already registered, skipping\n"); else tfa98xx_register_inputdev(tfa98xx); } @@ -1022,18 +1022,11 @@ static int add_sr_to_profile(struct tfa98xx *tfa98xx, char *basename, int len, i return 0; } -#if LINUX_VERSION_CODE < KERNEL_VERSION(3,16,0) -static struct snd_soc_codec *snd_soc_kcontrol_codec(struct snd_kcontrol *kcontrol) -{ - return snd_kcontrol_chip(kcontrol); -} -#endif - static int tfa98xx_get_vstep(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct tfa98xx *tfa98xx = snd_soc_component_get_drvdata(component); int mixer_profile = kcontrol->private_value; int ret = 0; int profile; @@ -1060,8 +1053,8 @@ static int tfa98xx_get_vstep(struct snd_kcontrol *kcontrol, static int tfa98xx_set_vstep(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct tfa98xx *tfa98xx = snd_soc_component_get_drvdata(component); int mixer_profile = kcontrol->private_value; int profile; int err = 0; @@ -1138,8 +1131,8 @@ static int tfa98xx_set_vstep(struct snd_kcontrol *kcontrol, static int tfa98xx_info_vstep(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct tfa98xx *tfa98xx = snd_soc_component_get_drvdata(component); int mixer_profile = tfa98xx_mixer_profile; int profile = get_profile_id_for_sr(mixer_profile, tfa98xx->rate); @@ -1172,8 +1165,8 @@ static int tfa98xx_get_profile(struct snd_kcontrol *kcontrol, static int tfa98xx_set_profile(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct tfa98xx *tfa98xx = snd_soc_component_get_drvdata(component); int change = 0; int new_profile; int prof_idx; @@ -1386,13 +1379,13 @@ static int tfa98xx_create_controls(struct tfa98xx *tfa98xx) nr_controls++; /* Playback Volume control */ } - tfa98xx_controls = devm_kzalloc(tfa98xx->codec->dev, + tfa98xx_controls = devm_kzalloc(tfa98xx->component->dev, nr_controls * sizeof(tfa98xx_controls[0]), GFP_KERNEL); if (!tfa98xx_controls) return -ENOMEM; /* Create a mixer item for selecting the active profile */ - name = devm_kzalloc(tfa98xx->codec->dev, MAX_CONTROL_NAME, GFP_KERNEL); + name = devm_kzalloc(tfa98xx->component->dev, MAX_CONTROL_NAME, GFP_KERNEL); if (!name) return -ENOMEM; scnprintf(name, MAX_CONTROL_NAME, "%s Profile", tfa98xx->fw.name); @@ -1408,7 +1401,7 @@ static int tfa98xx_create_controls(struct tfa98xx *tfa98xx) /* create mixer items for each profile that has volume */ for (prof = 0; prof < nprof; prof++) { /* create an new empty profile */ - bprofile = devm_kzalloc(tfa98xx->codec->dev, sizeof(*bprofile), GFP_KERNEL); + bprofile = devm_kzalloc(tfa98xx->component->dev, sizeof(*bprofile), GFP_KERNEL); if (!bprofile) return -ENOMEM; @@ -1434,7 +1427,7 @@ static int tfa98xx_create_controls(struct tfa98xx *tfa98xx) pr_info("profile added [%d]: %s\n", bprofile->item_id, bprofile->basename); if (tfacont_get_max_vstep(tfa98xx->tfa, prof)) { - name = devm_kzalloc(tfa98xx->codec->dev, MAX_CONTROL_NAME, GFP_KERNEL); + name = devm_kzalloc(tfa98xx->component->dev, MAX_CONTROL_NAME, GFP_KERNEL); if (!name) return -ENOMEM; @@ -1460,7 +1453,7 @@ static int tfa98xx_create_controls(struct tfa98xx *tfa98xx) tfa98xx_mixer_profiles = id; /* Create a mixer item for stop control on TFA1 */ - name = devm_kzalloc(tfa98xx->codec->dev, MAX_CONTROL_NAME, GFP_KERNEL); + name = devm_kzalloc(tfa98xx->component->dev, MAX_CONTROL_NAME, GFP_KERNEL); if (!name) return -ENOMEM; @@ -1473,7 +1466,7 @@ static int tfa98xx_create_controls(struct tfa98xx *tfa98xx) mix_index++; if (tfa98xx->flags & TFA98XX_FLAG_CALIBRATION_CTL) { - name = devm_kzalloc(tfa98xx->codec->dev, MAX_CONTROL_NAME, GFP_KERNEL); + name = devm_kzalloc(tfa98xx->component->dev, MAX_CONTROL_NAME, GFP_KERNEL); if (!name) return -ENOMEM; @@ -1486,7 +1479,7 @@ static int tfa98xx_create_controls(struct tfa98xx *tfa98xx) mix_index++; } - return snd_soc_add_codec_controls(tfa98xx->codec, + return snd_soc_add_component_controls(tfa98xx->component, tfa98xx_controls, mix_index); } @@ -1591,16 +1584,9 @@ static const struct snd_soc_dapm_route tfa9888_input_dapm_routes[] = { { "AIF OUT", NULL, "DMIC4" }, }; -#if LINUX_VERSION_CODE < KERNEL_VERSION(4,2,0) -static struct snd_soc_dapm_context *snd_soc_codec_get_dapm(struct snd_soc_codec *codec) -{ - return &codec->dapm; -} -#endif - static void tfa98xx_add_widgets(struct tfa98xx *tfa98xx) { - struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(tfa98xx->codec); + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(tfa98xx->component); struct snd_soc_dapm_widget *widgets; unsigned int num_dapm_widgets = ARRAY_SIZE(tfa98xx_dapm_widgets_common); @@ -1920,14 +1906,14 @@ static void tfa98xx_tapdet_check_update(struct tfa98xx *tfa98xx) &tfa98xx->tapdet_work, HZ/10); else cancel_delayed_work_sync(&tfa98xx->tapdet_work); - dev_dbg(tfa98xx->codec->dev, + dev_dbg(tfa98xx->component->dev, "Polling for tap-detection: %s (%d; 0x%x, %d)\n", enable? "enabled":"disabled", tfa98xx->tapdet_open, tfa98xx->tapdet_profiles, tfa98xx->profile); } else { - dev_dbg(tfa98xx->codec->dev, + dev_dbg(tfa98xx->component->dev, "Interrupt for tap-detection: %s (%d; 0x%x, %d)\n", enable? "enabled":"disabled", tfa98xx->tapdet_open, tfa98xx->tapdet_profiles, @@ -2327,8 +2313,8 @@ static void tfa98xx_interrupt(struct work_struct *work) static int tfa98xx_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct snd_soc_codec *codec = dai->codec; - struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *component = dai->component; + struct tfa98xx *tfa98xx = snd_soc_component_get_drvdata(component); unsigned int sr; int len, prof, nprof, idx = 0; char *basename; @@ -2366,7 +2352,7 @@ static int tfa98xx_startup(struct snd_pcm_substream *substream, return 0; if (tfa98xx->dsp_fw_state != TFA98XX_DSP_FW_OK) { - dev_info(codec->dev, "Container file not loaded\n"); + dev_info(component->dev, "Container file not loaded\n"); return -EINVAL; } @@ -2391,10 +2377,10 @@ static int tfa98xx_startup(struct snd_pcm_substream *substream, */ sr = tfa98xx_get_profile_sr(tfa98xx->tfa, prof); if (!sr) - dev_info(codec->dev, "Unable to identify supported sample rate\n"); + dev_info(component->dev, "Unable to identify supported sample rate\n"); if (tfa98xx->rate_constraint.count >= TFA98XX_NUM_RATES) { - dev_err(codec->dev, "too many sample rates\n"); + dev_err(component->dev, "too many sample rates\n"); } else { tfa98xx->rate_constraint_list[idx++] = sr; tfa98xx->rate_constraint.count += 1; @@ -2414,7 +2400,8 @@ return 0; static int tfa98xx_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id, unsigned int freq, int dir) { - struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(codec_dai->codec); + struct snd_soc_component *component = codec_dai->component; + struct tfa98xx *tfa98xx = snd_soc_component_get_drvdata(component); tfa98xx->sysclk = freq; return 0; @@ -2429,8 +2416,8 @@ static int tfa98xx_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, static int tfa98xx_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { - struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(dai->codec); - struct snd_soc_codec *codec = dai->codec; + struct snd_soc_component *component = dai->component; + struct tfa98xx *tfa98xx = snd_soc_component_get_drvdata(component); pr_info("fmt=0x%x\n", fmt); @@ -2438,14 +2425,14 @@ static int tfa98xx_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) { - dev_err(codec->dev, "Invalid Codec master mode\n"); + dev_err(component->dev, "Invalid Codec master mode\n"); return -EINVAL; } break; case SND_SOC_DAIFMT_PDM: break; default: - dev_err(codec->dev, "Unsupported DAI format %d\n", + dev_err(component->dev, "Unsupported DAI format %d\n", fmt & SND_SOC_DAIFMT_FORMAT_MASK); return -EINVAL; } @@ -2470,8 +2457,8 @@ static int tfa98xx_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { - struct snd_soc_codec *codec = dai->codec; - struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *component = dai->component; + struct tfa98xx *tfa98xx = snd_soc_component_get_drvdata(component); unsigned int rate; int prof_idx; @@ -2504,8 +2491,8 @@ static int tfa98xx_hw_params(struct snd_pcm_substream *substream, static int tfa98xx_mute(struct snd_soc_dai *dai, int mute, int stream) { - struct snd_soc_codec *codec = dai->codec; - struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *component = dai->component; + struct tfa98xx *tfa98xx = snd_soc_component_get_drvdata(component); dev_info(&tfa98xx->i2c->dev, "%s: state: %d\n", __func__, mute); @@ -2594,9 +2581,9 @@ static struct snd_soc_dai_driver tfa98xx_dai[] = { }, }; -static int tfa98xx_probe(struct snd_soc_codec *codec) +static int tfa98xx_probe(struct snd_soc_component *component) { - struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(codec); + struct tfa98xx *tfa98xx = snd_soc_component_get_drvdata(component); int ret; pr_debug("\n"); @@ -2611,22 +2598,14 @@ static int tfa98xx_probe(struct snd_soc_codec *codec) INIT_DELAYED_WORK(&tfa98xx->interrupt_work, tfa98xx_interrupt); INIT_DELAYED_WORK(&tfa98xx->tapdet_work, tfa98xx_tapdet_work); - tfa98xx->codec = codec; + tfa98xx->component = component; ret = tfa98xx_load_container(tfa98xx); pr_info("Container loading requested: %d\n", ret); -#if LINUX_VERSION_CODE < KERNEL_VERSION(3,16,0) - codec->control_data = tfa98xx->regmap; - ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP); - if (ret != 0) { - dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); - return ret; - } -#endif tfa98xx_add_widgets(tfa98xx); - dev_info(codec->dev, "tfa98xx codec registered (%s)", + dev_info(component->dev, "tfa98xx codec registered (%s)", tfa98xx->fw.name); //suzhiguang,store for calibration @@ -2634,9 +2613,9 @@ static int tfa98xx_probe(struct snd_soc_codec *codec) return ret; } -static int tfa98xx_remove(struct snd_soc_codec *codec) +static void tfa98xx_remove(struct snd_soc_component *component) { - struct tfa98xx *tfa98xx = snd_soc_codec_get_drvdata(codec); + struct tfa98xx *tfa98xx = snd_soc_component_get_drvdata(component); pr_debug("\n"); tfa98xx_interrupt_enable(tfa98xx, false); @@ -2651,23 +2630,13 @@ static int tfa98xx_remove(struct snd_soc_codec *codec) if (tfa98xx->tfa98xx_wq) destroy_workqueue(tfa98xx->tfa98xx_wq); - return 0; + return; } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,16,0) -static struct regmap *tfa98xx_get_regmap(struct device *dev) -{ - struct tfa98xx *tfa98xx = dev_get_drvdata(dev); - - return tfa98xx->regmap; -} -#endif -static struct snd_soc_codec_driver soc_codec_dev_tfa98xx = { +static struct snd_soc_component_driver soc_codec_dev_tfa98xx = { + .name = "tfa98xx_codec", .probe = tfa98xx_probe, .remove = tfa98xx_remove, -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,16,0) - .get_regmap = tfa98xx_get_regmap, -#endif }; @@ -3163,7 +3132,7 @@ static int tfa98xx_i2c_probe(struct i2c_client *i2c, dai, ARRAY_SIZE(tfa98xx_dai)); - ret = snd_soc_register_codec(&i2c->dev, + ret = snd_soc_register_component(&i2c->dev, &soc_codec_dev_tfa98xx, dai, ARRAY_SIZE(tfa98xx_dai)); @@ -3243,7 +3212,7 @@ static int tfa98xx_i2c_remove(struct i2c_client *i2c) tfa98xx_debug_remove(tfa98xx); #endif - snd_soc_unregister_codec(&i2c->dev); + snd_soc_unregister_component(&i2c->dev); if (gpio_is_valid(tfa98xx->irq_gpio)) devm_gpio_free(&i2c->dev, tfa98xx->irq_gpio); diff --git a/techpack/audio/asoc/codecs/tfa9874/tfa98xx.h b/techpack/audio/asoc/codecs/tfa9874/tfa98xx.h index 07940b3610cb..82285c6c6fac 100644 --- a/techpack/audio/asoc/codecs/tfa9874/tfa98xx.h +++ b/techpack/audio/asoc/codecs/tfa9874/tfa98xx.h @@ -77,7 +77,7 @@ struct tfa98xx { struct regmap *regmap; struct i2c_client *i2c; struct regulator *vdd; - struct snd_soc_codec *codec; + struct snd_soc_component *component; struct workqueue_struct *tfa98xx_wq; struct delayed_work init_work; struct delayed_work monitor_work; From 56241429ba0686a2e5b3be45e81e98f1179509b6 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Fri, 14 Apr 2023 08:44:42 +0000 Subject: [PATCH 314/356] media: Update camera stack for 4.19 Bring in minimal changes from camera-kernel --- .../msm/camera_oneplus/cam_cdm/cam_cdm.h | 5 +- .../cam_cdm/cam_cdm_core_common.c | 2 - .../camera_oneplus/cam_cdm/cam_cdm_hw_core.c | 35 +- .../msm/camera_oneplus/cam_cdm/cam_cdm_intf.c | 4 +- .../camera_oneplus/cam_cdm/cam_cdm_intf_api.h | 6 +- .../msm/camera_oneplus/cam_cdm/cam_cdm_soc.c | 2 - .../cam_cdm/cam_cdm_virtual_core.c | 15 +- .../msm/camera_oneplus/cam_core/cam_context.c | 34 +- .../msm/camera_oneplus/cam_core/cam_context.h | 18 +- .../cam_core/cam_context_utils.c | 81 +- .../camera_oneplus/cam_core/cam_hw_mgr_intf.h | 19 + .../msm/camera_oneplus/cam_core/cam_node.c | 18 +- .../camera_oneplus/cam_cpas/cam_cpas_intf.c | 4 +- .../cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c | 54 +- .../camera_oneplus/cam_icp/cam_icp_subdev.c | 29 +- .../camera_oneplus/cam_icp/fw_inc/hfi_intf.h | 8 +- .../cam_icp/icp_hw/a5_hw/a5_soc.c | 1 - .../cam_icp/icp_hw/bps_hw/bps_core.h | 1 - .../cam_icp/icp_hw/bps_hw/bps_soc.c | 1 - .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 99 ++- .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h | 3 + .../icp_hw/include/cam_icp_hw_mgr_intf.h | 2 +- .../cam_icp/icp_hw/ipe_hw/ipe_core.h | 1 - .../cam_icp/icp_hw/ipe_hw/ipe_soc.c | 1 - .../camera_oneplus/cam_isp/cam_isp_context.c | 32 +- .../msm/camera_oneplus/cam_isp/cam_isp_dev.c | 29 +- .../cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 24 +- .../cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h | 3 +- .../cam_isp/isp_hw_mgr/cam_isp_hw_mgr.c | 4 +- .../isp_hw_mgr/include/cam_isp_hw_mgr_intf.h | 4 +- .../camera_oneplus/cam_jpeg/cam_jpeg_dev.c | 27 +- .../cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c | 43 +- .../jpeg_hw/include/cam_jpeg_hw_mgr_intf.h | 2 +- .../jpeg_hw/jpeg_dma_hw/jpeg_dma_core.h | 1 - .../jpeg_hw/jpeg_dma_hw/jpeg_dma_soc.c | 1 - .../jpeg_hw/jpeg_enc_hw/jpeg_enc_core.h | 1 - .../jpeg_hw/jpeg_enc_hw/jpeg_enc_soc.c | 1 - .../cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c | 36 +- .../lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c | 9 - .../camera_oneplus/cam_req_mgr/cam_mem_mgr.c | 746 +++++++++++------- .../camera_oneplus/cam_req_mgr/cam_mem_mgr.h | 16 +- .../cam_req_mgr/cam_mem_mgr_api.h | 10 +- .../cam_req_mgr/cam_req_mgr_core.c | 5 +- .../cam_req_mgr/cam_req_mgr_dev.c | 69 +- .../cam_req_mgr/cam_req_mgr_timer.c | 19 +- .../cam_req_mgr/cam_req_mgr_timer.h | 19 +- .../cam_actuator/cam_actuator_core.c | 22 +- .../cam_actuator/cam_actuator_dev.h | 1 - .../cam_sensor_module/cam_cci/cam_cci_dev.h | 1 - .../cam_csiphy/cam_csiphy_core.c | 28 +- .../cam_csiphy/cam_csiphy_dev.h | 1 - .../cam_eeprom/cam_eeprom_core.c | 47 +- .../cam_eeprom/cam_eeprom_soc.c | 20 +- .../cam_flash/cam_flash_core.c | 19 +- .../cam_flash/cam_flash_dev.c | 10 +- .../cam_sensor_module/cam_ois/cam_ois_core.c | 26 +- .../cam_sensor_module/cam_ois/cam_ois_core.h | 1 - .../cam_sensor/cam_sensor_core.c | 33 +- .../cam_sensor/cam_sensor_dev.h | 1 - .../cam_sensor_io/cam_sensor_qup_i2c.c | 17 +- .../cam_sensor_io/cam_sensor_spi.c | 5 +- .../cam_sensor_io/cam_sensor_spi.h | 1 - .../cam_sensor_utils/cam_sensor_util.c | 4 +- .../msm/camera_oneplus/cam_smmu/Makefile | 2 + .../camera_oneplus/cam_smmu/cam_smmu_api.c | 737 +++++++++++++---- .../camera_oneplus/cam_smmu/cam_smmu_api.h | 71 +- .../msm/camera_oneplus/cam_sync/cam_sync.c | 65 +- .../camera_oneplus/cam_sync/cam_sync_api.h | 23 + .../cam_sync/cam_sync_private.h | 2 + .../cam_utils/cam_common_util.h | 19 + .../camera_oneplus/cam_utils/cam_debug_util.c | 11 +- .../camera_oneplus/cam_utils/cam_debug_util.h | 35 +- .../cam_utils/cam_packet_util.c | 21 +- .../msm/camera_oneplus/cam_utils/cam_trace.h | 23 + include/uapi/media/cam_req_mgr.h | 1 + 75 files changed, 1933 insertions(+), 858 deletions(-) diff --git a/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm.h b/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm.h index 03f6e0c4d5c8..ee7b442561bb 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm.h +++ b/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm.h @@ -13,7 +13,6 @@ #ifndef _CAM_CDM_H_ #define _CAM_CDM_H_ -#include #include #include #include @@ -195,11 +194,11 @@ struct cam_cdm_hw_intf_cmd_submit_bl { struct cam_cdm_bl_request *data; }; -/* struct cam_cdm_hw_mem - CDM hw memory.struct */ +/* struct cam_cdm_hw_mem - CDM hw memory struct */ struct cam_cdm_hw_mem { int32_t handle; uint32_t vaddr; - uint64_t kmdvaddr; + uintptr_t kmdvaddr; size_t size; }; diff --git a/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_core_common.c b/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_core_common.c index 6d699cf965eb..c57853cb04e7 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_core_common.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_core_common.c @@ -14,8 +14,6 @@ #include #include #include -#include -#include #include #include diff --git a/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_hw_core.c b/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_hw_core.c index 29de3159e5a7..61ade5ce7c62 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_hw_core.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_hw_core.c @@ -14,8 +14,6 @@ #include #include #include -#include -#include #include #include @@ -422,7 +420,7 @@ int cam_hw_cdm_submit_bl(struct cam_hw_info *cdm_hw, } for (i = 0; i < req->data->cmd_arrary_count ; i++) { - uint64_t hw_vaddr_ptr = 0; + dma_addr_t hw_vaddr_ptr = 0; size_t len = 0; if ((!cdm_cmd->cmd[i].len) && @@ -482,6 +480,17 @@ int cam_hw_cdm_submit_bl(struct cam_hw_info *cdm_hw, 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)) @@ -509,8 +518,8 @@ int cam_hw_cdm_submit_bl(struct cam_hw_info *cdm_hw, if (!rc) { CAM_DBG(CAM_CDM, - "write BL success for cnt=%d with tag=%d", - i, core->bl_tag); + "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)) { @@ -624,7 +633,8 @@ static void cam_hw_cdm_work(struct work_struct *work) } static void cam_hw_cdm_iommu_fault_handler(struct iommu_domain *domain, - struct device *dev, unsigned long iova, int flags, void *token) + 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; @@ -910,14 +920,9 @@ int cam_hw_cdm_probe(struct platform_device *pdev) CAM_ERR(CAM_CDM, "cpas-cdm get iommu handle failed"); goto unlock_release_mem; } - cam_smmu_reg_client_page_fault_handler(cdm_core->iommu_hdl.non_secure, + cam_smmu_set_client_page_fault_handler(cdm_core->iommu_hdl.non_secure, cam_hw_cdm_iommu_fault_handler, cdm_hw); - rc = cam_smmu_ops(cdm_core->iommu_hdl.non_secure, CAM_SMMU_ATTACH); - if (rc < 0) { - CAM_ERR(CAM_CDM, "Attach iommu non secure handle failed"); - goto destroy_non_secure_hdl; - } cdm_core->iommu_hdl.secure = -1; cdm_core->work_queue = alloc_workqueue(cdm_core->name, @@ -1034,7 +1039,7 @@ int cam_hw_cdm_probe(struct platform_device *pdev) flush_workqueue(cdm_core->work_queue); destroy_workqueue(cdm_core->work_queue); destroy_non_secure_hdl: - cam_smmu_reg_client_page_fault_handler(cdm_core->iommu_hdl.non_secure, + 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"); @@ -1106,8 +1111,8 @@ int cam_hw_cdm_remove(struct platform_device *pdev) if (cam_smmu_destroy_handle(cdm_core->iommu_hdl.non_secure)) CAM_ERR(CAM_CDM, "Release iommu secure hdl failed"); - cam_smmu_reg_client_page_fault_handler(cdm_core->iommu_hdl.non_secure, - NULL, cdm_hw); + 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); diff --git a/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_intf.c b/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_intf.c index f44adc45add1..da4fc3cc587a 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_intf.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_intf.c @@ -14,8 +14,6 @@ #include #include #include -#include -#include #include #include @@ -166,7 +164,7 @@ int cam_cdm_acquire(struct cam_cdm_acquire_data *data) struct cam_hw_intf *hw; uint32_t hw_index = 0; - if (!data || !data->base_array_cnt) + if ((!data) || (!data->base_array_cnt)) return -EINVAL; if (get_cdm_mgr_refcount()) { diff --git a/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_intf_api.h b/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_intf_api.h index 2b00a87544fa..6aa6e6d2bc4c 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_intf_api.h +++ b/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_intf_api.h @@ -105,10 +105,10 @@ struct cam_cdm_bl_cmd { union { int32_t mem_handle; uint32_t *hw_iova; - void *kernel_iova; + uintptr_t kernel_iova; } bl_addr; - uint32_t offset; - uint32_t len; + uint32_t offset; + uint32_t len; }; /** diff --git a/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_soc.c b/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_soc.c index f8b0d3dffcae..92ab9a7df4a7 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_soc.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_soc.c @@ -14,8 +14,6 @@ #include #include #include -#include -#include #include #include diff --git a/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_virtual_core.c b/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_virtual_core.c index d76f344c1efa..2ac2504c8bd5 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_virtual_core.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_cdm/cam_cdm_virtual_core.c @@ -14,8 +14,6 @@ #include #include #include -#include -#include #include #include @@ -87,7 +85,7 @@ int cam_virtual_cdm_submit_bl(struct cam_hw_info *cdm_hw, mutex_lock(&client->lock); for (i = 0; i < req->data->cmd_arrary_count ; i++) { - uint64_t vaddr_ptr = 0; + uintptr_t vaddr_ptr = 0; size_t len = 0; if ((!cdm_cmd->cmd[i].len) && @@ -106,8 +104,7 @@ int cam_virtual_cdm_submit_bl(struct cam_hw_info *cdm_hw, } else if (req->data->type == CAM_CDM_BL_CMD_TYPE_KERNEL_IOVA) { rc = 0; - vaddr_ptr = - (uint64_t)cdm_cmd->cmd[i].bl_addr.kernel_iova; + 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, @@ -119,6 +116,14 @@ int cam_virtual_cdm_submit_bl(struct cam_hw_info *cdm_hw, 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, diff --git a/drivers/media/platform/msm/camera_oneplus/cam_core/cam_context.c b/drivers/media/platform/msm/camera_oneplus/cam_core/cam_context.c index 2b9decf48840..cedf9417b8a4 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_core/cam_context.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_core/cam_context.c @@ -12,6 +12,8 @@ #include #include +#include + #include "cam_context.h" #include "cam_debug_util.h" #include "cam_node.h" @@ -220,6 +222,32 @@ int cam_context_handle_crm_process_evt(struct cam_context *ctx, 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; + } + + mutex_lock(&ctx->ctx_mutex); + 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); + } + } + mutex_unlock(&ctx->ctx_mutex); + + return rc; +} + int cam_context_handle_acquire_dev(struct cam_context *ctx, struct cam_acquire_dev_cmd *cmd) { @@ -479,7 +507,7 @@ 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, atomic_read(&(ctx->refcount.refcount)), + ctx->dev_hdl, refcount_read(&(ctx->refcount.refcount)), ctx->dev_name); } @@ -487,10 +515,10 @@ void cam_context_getref(struct cam_context *ctx) { if (kref_get_unless_zero(&ctx->refcount) == 0) { /* should never happen */ - WARN(1, "cam_context_getref fail\n"); + WARN(1, "%s fail\n", __func__); } CAM_DBG(CAM_CORE, "ctx device hdl %ld, ref count %d, dev_name %s", - ctx->dev_hdl, atomic_read(&(ctx->refcount.refcount)), + ctx->dev_hdl, refcount_read(&(ctx->refcount.refcount)), ctx->dev_name); } diff --git a/drivers/media/platform/msm/camera_oneplus/cam_core/cam_context.h b/drivers/media/platform/msm/camera_oneplus/cam_core/cam_context.h index 8324e78d9e0e..25bcd8a2541a 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_core/cam_context.h +++ b/drivers/media/platform/msm/camera_oneplus/cam_core/cam_context.h @@ -70,7 +70,7 @@ struct cam_ctx_request { 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; - uint32_t num_in_acked; + atomic_t num_in_acked; uint32_t num_out_acked; int flushed; struct cam_context *ctx; @@ -135,12 +135,15 @@ struct cam_ctx_crm_ops { * @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 * */ 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; }; /** @@ -291,6 +294,19 @@ int cam_context_handle_crm_flush_req(struct cam_context *ctx, 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() * diff --git a/drivers/media/platform/msm/camera_oneplus/cam_core/cam_context_utils.c b/drivers/media/platform/msm/camera_oneplus/cam_core/cam_context_utils.c index 71561c0fddd1..310ce94c0a0a 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_core/cam_context_utils.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_core/cam_context_utils.c @@ -91,10 +91,19 @@ int cam_context_buf_done_from_hw(struct cam_context *ctx, */ list_del_init(&req->list); spin_unlock(&ctx->lock); - if (!bubble_state) + if (!bubble_state) { result = CAM_SYNC_STATE_SIGNALED_SUCCESS; - else + } 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); @@ -189,8 +198,7 @@ static void cam_context_sync_callback(int32_t sync_obj, int status, void *data) return; } - req->num_in_acked++; - if (req->num_in_acked == req->num_in_map_entries) { + 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 @@ -264,22 +272,20 @@ int32_t cam_context_prepare_dev_to_hw(struct cam_context *ctx, int rc = 0; struct cam_ctx_request *req = NULL; struct cam_hw_prepare_update_args cfg; - uint64_t packet_addr; + uintptr_t packet_addr; struct cam_packet *packet; size_t len = 0; - int32_t i = 0; + int32_t i = 0, j = 0; if (!ctx || !cmd) { CAM_ERR(CAM_CTXT, "Invalid input params %pK %pK", ctx, cmd); - rc = -EINVAL; - goto end; + return -EINVAL; } 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; + return -EFAULT; } rc = cam_context_validate_thread(); if (rc) @@ -296,8 +302,7 @@ int32_t cam_context_prepare_dev_to_hw(struct cam_context *ctx, if (!req) { CAM_ERR(CAM_CTXT, "[%s][%d] No more request obj free", ctx->dev_name, ctx->ctx_id); - rc = -ENOMEM; - goto end; + return -ENOMEM; } memset(req, 0, sizeof(*req)); @@ -307,8 +312,7 @@ int32_t cam_context_prepare_dev_to_hw(struct cam_context *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, - (uint64_t *) &packet_addr, - &len); + &packet_addr, &len); if (rc != 0) { CAM_ERR(CAM_CTXT, "[%s][%d] Can not get packet address", ctx->dev_name, ctx->ctx_id); @@ -316,7 +320,8 @@ int32_t cam_context_prepare_dev_to_hw(struct cam_context *ctx, goto free_req; } - packet = (struct cam_packet *) (packet_addr + cmd->offset); + packet = (struct cam_packet *) ((uint8_t *)packet_addr + + (uint32_t)cmd->offset); /* preprocess the configuration */ memset(&cfg, 0, sizeof(cfg)); @@ -342,10 +347,20 @@ int32_t cam_context_prepare_dev_to_hw(struct cam_context *ctx, 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); @@ -356,17 +371,17 @@ int32_t cam_context_prepare_dev_to_hw(struct cam_context *ctx, "[%s][%d] : Moving req[%llu] from free_list to pending_list", ctx->dev_name, ctx->ctx_id, req->request_id); - for (i = 0; i < req->num_in_map_entries; i++) { + 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[i].sync_id); + 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[i].sync_id, rc); + req->in_map_entries[j].sync_id, rc); spin_lock(&ctx->lock); list_del_init(&req->list); spin_unlock(&ctx->lock); @@ -377,24 +392,29 @@ int32_t cam_context_prepare_dev_to_hw(struct cam_context *ctx, ctx->dev_name, ctx->ctx_id, req->request_id); - cam_context_putref(ctx); - - goto free_req; + goto put_ctx_ref; } CAM_DBG(CAM_CTXT, "register in fence cb: %d ret = %d", - req->in_map_entries[i].sync_id, rc); + req->in_map_entries[j].sync_id, rc); } - goto end; } 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); -end: + return rc; } @@ -481,6 +501,7 @@ int32_t cam_context_acquire_dev_to_hw(struct cam_context *ctx, 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; } @@ -490,11 +511,12 @@ 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; - bool free_req = false; 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 @@ -538,8 +560,7 @@ int32_t cam_context_flush_ctx_to_hw(struct cam_context *ctx) req->in_map_entries[i].sync_id); if (!rc) { cam_context_putref(ctx); - req->num_in_acked = req->num_in_acked + 1; - if (req->num_in_acked == + if (atomic_inc_return(&req->num_in_acked) == req->num_in_map_entries) free_req = true; } @@ -662,6 +683,7 @@ int32_t cam_context_flush_req_to_hw(struct cam_context *ctx, 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); @@ -721,8 +743,7 @@ int32_t cam_context_flush_req_to_hw(struct cam_context *ctx, continue; cam_context_putref(ctx); - req->num_in_acked = req->num_in_acked + 1; - if (req->num_in_acked == + if (atomic_inc_return(&req->num_in_acked) == req->num_in_map_entries) free_req = true; } diff --git a/drivers/media/platform/msm/camera_oneplus/cam_core/cam_hw_mgr_intf.h b/drivers/media/platform/msm/camera_oneplus/cam_core/cam_hw_mgr_intf.h index f7990b6d5d4a..c950336b3c61 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_core/cam_hw_mgr_intf.h +++ b/drivers/media/platform/msm/camera_oneplus/cam_core/cam_hw_mgr_intf.h @@ -25,10 +25,29 @@ /* maximum buf done irqs */ #define CAM_NUM_OUT_PER_COMP_IRQ_MAX 12 +/** + * 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 * diff --git a/drivers/media/platform/msm/camera_oneplus/cam_core/cam_node.c b/drivers/media/platform/msm/camera_oneplus/cam_core/cam_node.c index 7433ef6eff08..9fe331de53a5 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_core/cam_node.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_core/cam_node.c @@ -462,7 +462,7 @@ int cam_node_handle_ioctl(struct cam_node *node, struct cam_control *cmd) case CAM_QUERY_CAP: { struct cam_query_cap_cmd query; - if (copy_from_user(&query, (void __user *)cmd->handle, + if (copy_from_user(&query, u64_to_user_ptr(cmd->handle), sizeof(query))) { rc = -EFAULT; break; @@ -475,7 +475,7 @@ int cam_node_handle_ioctl(struct cam_node *node, struct cam_control *cmd) break; } - if (copy_to_user((void __user *)cmd->handle, &query, + if (copy_to_user(u64_to_user_ptr(cmd->handle), &query, sizeof(query))) rc = -EFAULT; @@ -484,7 +484,7 @@ int cam_node_handle_ioctl(struct cam_node *node, struct cam_control *cmd) case CAM_ACQUIRE_DEV: { struct cam_acquire_dev_cmd acquire; - if (copy_from_user(&acquire, (void __user *)cmd->handle, + if (copy_from_user(&acquire, u64_to_user_ptr(cmd->handle), sizeof(acquire))) { rc = -EFAULT; break; @@ -495,7 +495,7 @@ int cam_node_handle_ioctl(struct cam_node *node, struct cam_control *cmd) rc); break; } - if (copy_to_user((void __user *)cmd->handle, &acquire, + if (copy_to_user(u64_to_user_ptr(cmd->handle), &acquire, sizeof(acquire))) rc = -EFAULT; break; @@ -503,7 +503,7 @@ int cam_node_handle_ioctl(struct cam_node *node, struct cam_control *cmd) case CAM_START_DEV: { struct cam_start_stop_dev_cmd start; - if (copy_from_user(&start, (void __user *)cmd->handle, + if (copy_from_user(&start, u64_to_user_ptr(cmd->handle), sizeof(start))) rc = -EFAULT; else { @@ -517,7 +517,7 @@ int cam_node_handle_ioctl(struct cam_node *node, struct cam_control *cmd) case CAM_STOP_DEV: { struct cam_start_stop_dev_cmd stop; - if (copy_from_user(&stop, (void __user *)cmd->handle, + if (copy_from_user(&stop, u64_to_user_ptr(cmd->handle), sizeof(stop))) rc = -EFAULT; else { @@ -531,7 +531,7 @@ int cam_node_handle_ioctl(struct cam_node *node, struct cam_control *cmd) case CAM_CONFIG_DEV: { struct cam_config_dev_cmd config; - if (copy_from_user(&config, (void __user *)cmd->handle, + if (copy_from_user(&config, u64_to_user_ptr(cmd->handle), sizeof(config))) rc = -EFAULT; else { @@ -545,7 +545,7 @@ int cam_node_handle_ioctl(struct cam_node *node, struct cam_control *cmd) case CAM_RELEASE_DEV: { struct cam_release_dev_cmd release; - if (copy_from_user(&release, (void __user *)cmd->handle, + if (copy_from_user(&release, u64_to_user_ptr(cmd->handle), sizeof(release))) rc = -EFAULT; else { @@ -559,7 +559,7 @@ int cam_node_handle_ioctl(struct cam_node *node, struct cam_control *cmd) case CAM_FLUSH_REQ: { struct cam_flush_dev_cmd flush; - if (copy_from_user(&flush, (void __user *)cmd->handle, + if (copy_from_user(&flush, u64_to_user_ptr(cmd->handle), sizeof(flush))) rc = -EFAULT; else { diff --git a/drivers/media/platform/msm/camera_oneplus/cam_cpas/cam_cpas_intf.c b/drivers/media/platform/msm/camera_oneplus/cam_cpas/cam_cpas_intf.c index 0187a6400275..95b550a9eeae 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_cpas/cam_cpas_intf.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_cpas/cam_cpas_intf.c @@ -367,7 +367,7 @@ int cam_cpas_subdev_cmd(struct cam_cpas_intf *cpas_intf, case CAM_QUERY_CAP: { struct cam_cpas_query_cap query; - rc = copy_from_user(&query, (void __user *) cmd->handle, + 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", @@ -381,7 +381,7 @@ int cam_cpas_subdev_cmd(struct cam_cpas_intf *cpas_intf, if (rc) break; - rc = copy_to_user((void __user *) cmd->handle, &query, + 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); diff --git a/drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c b/drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c index a15ccdcf2dcc..a080028edeea 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_fd/fd_hw_mgr/cam_fd_hw_mgr.c @@ -534,10 +534,11 @@ static int cam_fd_mgr_util_prepare_io_buf_info(int32_t iommu_hdl, struct cam_fd_hw_io_buffer *output_buf, uint32_t io_buf_size) { int rc = -EINVAL; - uint32_t i, j, plane, num_out_buf, num_in_buf; + uint32_t plane, num_out_buf, num_in_buf; + int i, j; struct cam_buf_io_cfg *io_cfg; - uint64_t io_addr[CAM_PACKET_MAX_PLANES]; - uint64_t cpu_addr[CAM_PACKET_MAX_PLANES]; + 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; @@ -583,15 +584,25 @@ static int cam_fd_mgr_util_prepare_io_buf_info(int32_t iommu_hdl, rc = cam_mem_get_io_buf( io_cfg[i].mem_handle[plane], iommu_hdl, &io_addr[plane], &size); - if ((rc) || (io_addr[plane] >> 32)) { + if (rc) { CAM_ERR(CAM_FD, - "Invalid io buf %d %d %d %d", + "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]; } @@ -599,7 +610,8 @@ static int cam_fd_mgr_util_prepare_io_buf_info(int32_t iommu_hdl, rc = cam_mem_get_cpu_buf( io_cfg[i].mem_handle[plane], &cpu_addr[plane], &size); - if (rc) { + if (rc || ((io_addr[plane] & 0xFFFFFFFF) + != io_addr[plane])) { CAM_ERR(CAM_FD, "Invalid cpu buf %d %d %d %d", io_cfg[i].direction, @@ -607,7 +619,14 @@ static int cam_fd_mgr_util_prepare_io_buf_info(int32_t iommu_hdl, 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]; } @@ -655,14 +674,14 @@ static int cam_fd_mgr_util_prepare_io_buf_info(int32_t iommu_hdl, default: CAM_ERR(CAM_FD, "Unsupported io direction %d", io_cfg[i].direction); - return -EINVAL; + rc = -EINVAL; + break; } } prepare->num_in_map_entries = num_in_buf; prepare->num_out_map_entries = num_out_buf; - - return 0; + return rc; } static int cam_fd_mgr_util_prepare_hw_update_entries( @@ -1088,8 +1107,10 @@ static int cam_fd_mgr_hw_get_caps(void *hw_mgr_priv, void *hw_get_caps_args) 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, (void __user *)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; @@ -1106,7 +1127,7 @@ static int cam_fd_mgr_hw_get_caps(void *hw_mgr_priv, void *hw_get_caps_args) query_fd.hw_caps.wrapper_version.major, query_fd.hw_caps.wrapper_version.minor); - if (copy_to_user((void __user *)query->caps_handle, &query_fd, + if (copy_to_user(caps_handle, &query_fd, sizeof(struct cam_fd_query_cap_cmd))) rc = -EFAULT; @@ -1725,7 +1746,6 @@ int cam_fd_hw_mgr_deinit(struct device_node *of_node) cam_req_mgr_workq_destroy(&g_fd_hw_mgr.work); - cam_smmu_ops(g_fd_hw_mgr.device_iommu.non_secure, CAM_SMMU_DETACH); cam_smmu_destroy_handle(g_fd_hw_mgr.device_iommu.non_secure); g_fd_hw_mgr.device_iommu.non_secure = -1; @@ -1843,12 +1863,6 @@ int cam_fd_hw_mgr_init(struct device_node *of_node, goto destroy_mutex; } - rc = cam_smmu_ops(g_fd_hw_mgr.device_iommu.non_secure, CAM_SMMU_ATTACH); - if (rc) { - CAM_ERR(CAM_FD, "FD attach iommu handle failed, rc=%d", rc); - goto destroy_smmu; - } - 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"); @@ -1927,8 +1941,6 @@ int cam_fd_hw_mgr_init(struct device_node *of_node, return rc; detach_smmu: - cam_smmu_ops(g_fd_hw_mgr.device_iommu.non_secure, CAM_SMMU_DETACH); -destroy_smmu: cam_smmu_destroy_handle(g_fd_hw_mgr.device_iommu.non_secure); g_fd_hw_mgr.device_iommu.non_secure = -1; destroy_mutex: diff --git a/drivers/media/platform/msm/camera_oneplus/cam_icp/cam_icp_subdev.c b/drivers/media/platform/msm/camera_oneplus/cam_icp/cam_icp_subdev.c index 4f91f734e989..25bfc5a2182a 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_icp/cam_icp_subdev.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_icp/cam_icp_subdev.c @@ -35,6 +35,7 @@ #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" @@ -55,6 +56,25 @@ static const struct of_device_id cam_icp_dt_match[] = { {} }; +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) { @@ -135,6 +155,7 @@ 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"); @@ -158,7 +179,8 @@ static int cam_icp_probe(struct platform_device *pdev) goto hw_alloc_fail; } - rc = cam_icp_hw_mgr_init(pdev->dev.of_node, (uint64_t *)hw_mgr_intf); + 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; @@ -181,9 +203,14 @@ static int cam_icp_probe(struct platform_device *pdev) 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: diff --git a/drivers/media/platform/msm/camera_oneplus/cam_icp/fw_inc/hfi_intf.h b/drivers/media/platform/msm/camera_oneplus/cam_icp/fw_inc/hfi_intf.h index f5567801d95f..cff838653e8c 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_icp/fw_inc/hfi_intf.h +++ b/drivers/media/platform/msm/camera_oneplus/cam_icp/fw_inc/hfi_intf.h @@ -23,10 +23,10 @@ * @reserved: reserved field */ struct hfi_mem { - uint64_t len; - uint64_t kva; - uint32_t iova; - uint32_t reserved; + uint64_t len; + uintptr_t kva; + uint32_t iova; + uint32_t reserved; }; /** diff --git a/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/a5_hw/a5_soc.c b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/a5_hw/a5_soc.c index 31775135d024..f38e4089825b 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/a5_hw/a5_soc.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/a5_hw/a5_soc.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include "a5_soc.h" diff --git a/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/bps_hw/bps_core.h b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/bps_hw/bps_core.h index d97932141fb0..8d775487c179 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/bps_hw/bps_core.h +++ b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/bps_hw/bps_core.h @@ -17,7 +17,6 @@ #include #include #include -#include #define BPS_COLLAPSE_MASK 0x1 #define BPS_PWR_ON_MASK 0x2 diff --git a/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/bps_hw/bps_soc.c b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/bps_hw/bps_soc.c index 9d36cf44d76e..f3bfdf1b4d12 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/bps_hw/bps_soc.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/bps_hw/bps_soc.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include "bps_soc.h" diff --git a/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c index 569ac098c68d..4e84f1330d24 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c @@ -454,12 +454,13 @@ static int32_t cam_icp_ctx_timer(void *priv, void *data) return 0; } -static void cam_icp_ctx_timer_cb(unsigned long data) +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 = (struct cam_req_mgr_timer *)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); @@ -478,12 +479,13 @@ static void cam_icp_ctx_timer_cb(unsigned long data) spin_unlock_irqrestore(&icp_hw_mgr.hw_mgr_lock, flags); } -static void cam_icp_device_timer_cb(unsigned long data) +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 = (struct cam_req_mgr_timer *)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); @@ -1941,7 +1943,7 @@ static int cam_icp_alloc_shared_mem(struct cam_mem_mgr_memory_desc *qtbl) static int cam_icp_allocate_fw_mem(void) { int rc; - uint64_t kvaddr; + uintptr_t kvaddr; size_t len; dma_addr_t iova; @@ -1955,7 +1957,7 @@ static int cam_icp_allocate_fw_mem(void) 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: %llX, iova: %llx, len: %zu", + CAM_DBG(CAM_ICP, "kva: %zX, iova: %llx, len: %zu", kvaddr, iova, len); return rc; @@ -1981,6 +1983,28 @@ static int cam_icp_allocate_qdss_mem(void) 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; @@ -2035,7 +2059,15 @@ static int cam_icp_allocate_hfi_mem(void) 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.dbg_q); dbg_q_alloc_failed: @@ -2994,10 +3026,11 @@ static int cam_icp_mgr_process_cmd_desc(struct cam_icp_hw_mgr *hw_mgr, { int rc = 0; int i, j, k; - uint64_t addr; + int num_cmd_buf = 0; + dma_addr_t addr; size_t len; struct cam_cmd_buf_desc *cmd_desc = NULL; - uint64_t cpu_addr = 0; + uintptr_t cpu_addr = 0; struct ipe_frame_process_data *frame_process_data = NULL; struct bps_frame_process_data *bps_frame_process_data = NULL; @@ -3005,32 +3038,56 @@ static int cam_icp_mgr_process_cmd_desc(struct cam_icp_hw_mgr *hw_mgr, ((uint32_t *) &packet->payload + packet->cmd_buf_offset/4); *fw_cmd_buf_iova_addr = 0; - for (i = 0; i < packet->num_cmd_buf; i++) { + 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) { + 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 cpu addr"); + CAM_ERR(CAM_ICP, "invalid number of cmd buf"); return -EINVAL; } @@ -3808,7 +3865,7 @@ 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; - uint64_t io_buf_addr; + 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; @@ -3971,7 +4028,7 @@ static int cam_icp_mgr_get_hw_caps(void *hw_mgr_priv, void *hw_caps_args) mutex_lock(&hw_mgr->hw_mgr_mutex); if (copy_from_user(&icp_hw_mgr.icp_caps, - (void __user *)query_cap->caps_handle, + 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; @@ -3985,7 +4042,7 @@ static int cam_icp_mgr_get_hw_caps(void *hw_mgr_priv, void *hw_caps_args) 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((void __user *)query_cap->caps_handle, + 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; @@ -4205,7 +4262,8 @@ static int cam_icp_mgr_create_wq(void) return rc; } -int cam_icp_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl) +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; @@ -4255,12 +4313,6 @@ int cam_icp_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl) goto icp_get_hdl_failed; } - rc = cam_smmu_ops(icp_hw_mgr.iommu_hdl, CAM_SMMU_ATTACH); - if (rc) { - CAM_ERR(CAM_ICP, "icp attach failed: %d", rc); - goto icp_attach_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); @@ -4271,6 +4323,9 @@ int cam_icp_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl) 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; @@ -4278,8 +4333,6 @@ int cam_icp_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl) cam_smmu_destroy_handle(icp_hw_mgr.iommu_sec_hdl); icp_hw_mgr.iommu_sec_hdl = -1; secure_hdl_failed: - cam_smmu_ops(icp_hw_mgr.iommu_hdl, CAM_SMMU_DETACH); -icp_attach_failed: cam_smmu_destroy_handle(icp_hw_mgr.iommu_hdl); icp_hw_mgr.iommu_hdl = -1; icp_get_hdl_failed: diff --git a/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h index c94550d770b1..25f51fbb343b 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h +++ b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h @@ -79,6 +79,8 @@ * @sec_heap: Memory info of secondary heap * @fw_buf: Memory info of firmware * @qdss_buf: Memory info of qdss + * @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; @@ -89,6 +91,7 @@ struct icp_hfi_mem_info { struct cam_mem_mgr_memory_desc fw_buf; struct cam_mem_mgr_memory_desc qdss_buf; struct cam_smmu_region_info shmem; + struct cam_smmu_region_info io_mem; }; /** diff --git a/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h index 771c4ed7c55c..7bb9b9ed18a2 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h +++ b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h @@ -28,7 +28,7 @@ #define CPAS_IPE1_BIT 0x2000 int cam_icp_hw_mgr_init(struct device_node *of_node, - uint64_t *hw_mgr_hdl); + uint64_t *hw_mgr_hdl, int *iommu_hdl); /** * struct cam_icp_cpas_vote diff --git a/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/ipe_hw/ipe_core.h b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/ipe_hw/ipe_core.h index 65d349050f01..e04dece956b7 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/ipe_hw/ipe_core.h +++ b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/ipe_hw/ipe_core.h @@ -17,7 +17,6 @@ #include #include #include -#include #define IPE_COLLAPSE_MASK 0x1 #define IPE_PWR_ON_MASK 0x2 diff --git a/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/ipe_hw/ipe_soc.c b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/ipe_hw/ipe_soc.c index 838be2a58de1..c1d02f4a9710 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/ipe_hw/ipe_soc.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/ipe_hw/ipe_soc.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include "ipe_soc.h" diff --git a/drivers/media/platform/msm/camera_oneplus/cam_isp/cam_isp_context.c b/drivers/media/platform/msm/camera_oneplus/cam_isp/cam_isp_context.c index f6e1ff7f5e29..92fdf1cac415 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_isp/cam_isp_context.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/cam_isp_context.c @@ -1819,10 +1819,10 @@ static int __cam_isp_ctx_release_dev_in_top_state(struct cam_context *ctx, static int __cam_isp_ctx_config_dev_in_top_state( struct cam_context *ctx, struct cam_config_dev_cmd *cmd) { - int rc = 0; + int rc = 0, i; struct cam_ctx_request *req = NULL; struct cam_isp_ctx_req *req_isp; - uint64_t packet_addr; + uintptr_t packet_addr; struct cam_packet *packet; size_t len = 0; struct cam_hw_prepare_update_args cfg; @@ -1843,8 +1843,7 @@ static int __cam_isp_ctx_config_dev_in_top_state( if (!req) { CAM_ERR(CAM_ISP, "No more request obj free"); - rc = -ENOMEM; - goto end; + return -ENOMEM; } req_isp = (struct cam_isp_ctx_req *) req->req_priv; @@ -1852,14 +1851,14 @@ static int __cam_isp_ctx_config_dev_in_top_state( /* for config dev, only memory handle is supported */ /* map packet from the memhandle */ rc = cam_mem_get_cpu_buf((int32_t) cmd->packet_handle, - (uint64_t *) &packet_addr, &len); + &packet_addr, &len); if (rc != 0) { CAM_ERR(CAM_ISP, "Can not get packet address"); rc = -EINVAL; goto free_req; } - packet = (struct cam_packet *) (packet_addr + 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%llx", packet_addr); CAM_DBG(CAM_ISP, "packet with length %zu, offset 0x%llx", @@ -1895,6 +1894,15 @@ static int __cam_isp_ctx_config_dev_in_top_state( req_isp->num_fence_map_in = cfg.num_in_map_entries; req_isp->num_acked = 0; + 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); @@ -1936,18 +1944,24 @@ static int __cam_isp_ctx_config_dev_in_top_state( } } if (rc) - goto free_req; + goto put_ref; CAM_DBG(CAM_ISP, "Preprocessing Config %lld successful", req->request_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); -end: + return rc; } @@ -1997,7 +2011,7 @@ static int __cam_isp_ctx_acquire_dev_in_available(struct cam_context *ctx, CAM_DBG(CAM_ISP, "start copy %d resources from user", cmd->num_resources); - if (copy_from_user(isp_res, (void __user *)cmd->resource_hdl, + if (copy_from_user(isp_res, u64_to_user_ptr(cmd->resource_hdl), sizeof(*isp_res)*cmd->num_resources)) { rc = -EFAULT; goto free_res; diff --git a/drivers/media/platform/msm/camera_oneplus/cam_isp/cam_isp_dev.c b/drivers/media/platform/msm/camera_oneplus/cam_isp/cam_isp_dev.c index e775daac6fbe..fac8f857dae7 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_isp/cam_isp_dev.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/cam_isp_dev.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -26,9 +25,29 @@ #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" @@ -82,9 +101,10 @@ static int cam_isp_dev_probe(struct platform_device *pdev) 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; - /* Initialze the v4l2 subdevice first. (create cam_node) */ + /* 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) { @@ -94,7 +114,7 @@ static int cam_isp_dev_probe(struct platform_device *pdev) 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); + 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; @@ -119,6 +139,9 @@ static int cam_isp_dev_probe(struct platform_device *pdev) goto unregister; } + cam_smmu_set_client_page_fault_handler(iommu_hdl, + cam_isp_dev_iommu_fault_handler, node); + CAM_INFO(CAM_ISP, "Camera ISP probe complete"); return 0; diff --git a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index d84256cac629..0004d28fd4d8 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -94,7 +94,8 @@ static int cam_ife_mgr_get_hw_caps(void *hw_mgr_priv, CAM_DBG(CAM_ISP, "enter"); - if (copy_from_user(&query_isp, (void __user *)query->caps_handle, + if (copy_from_user(&query_isp, + u64_to_user_ptr(query->caps_handle), sizeof(struct cam_isp_query_cap_cmd))) { rc = -EFAULT; return rc; @@ -113,8 +114,8 @@ static int cam_ife_mgr_get_hw_caps(void *hw_mgr_priv, query_isp.dev_caps[i].hw_version.reserved = 0; } - if (copy_to_user((void __user *)query->caps_handle, &query_isp, - sizeof(struct cam_isp_query_cap_cmd))) + 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); @@ -1419,7 +1420,8 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, isp_resource[i].res_hdl, isp_resource[i].length); - in_port = memdup_user((void __user *)isp_resource[i].res_hdl, + in_port = memdup_user( + u64_to_user_ptr(isp_resource[i].res_hdl), isp_resource[i].length); if (in_port > 0) { rc = cam_ife_mgr_acquire_hw_for_ctx(ife_ctx, in_port, @@ -4030,7 +4032,7 @@ static int cam_ife_hw_mgr_debug_register(void) return -ENOMEM; } -int cam_ife_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf) +int cam_ife_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl) { int rc = -EFAULT; int i, j; @@ -4102,12 +4104,6 @@ int cam_ife_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf) return -EINVAL; } - if (cam_smmu_ops(g_ife_hw_mgr.mgr_common.img_iommu_hdl, - CAM_SMMU_ATTACH)) { - CAM_ERR(CAM_ISP, "Attach iommu handle failed."); - goto attach_fail; - } - 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"); @@ -4198,6 +4194,9 @@ int cam_ife_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf) hw_mgr_intf->hw_config = cam_ife_mgr_config_hw; hw_mgr_intf->hw_cmd = cam_ife_mgr_cmd; + 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"); @@ -4216,9 +4215,6 @@ int cam_ife_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf) 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_ops(g_ife_hw_mgr.mgr_common.img_iommu_hdl, - CAM_SMMU_DETACH); -attach_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/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h index 0e678b4584cd..914a9dead43b 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h @@ -201,9 +201,10 @@ struct cam_ife_hw_mgr { * 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 cam_ife_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl); /** * cam_ife_mgr_do_tasklet_buf_done() diff --git a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/cam_isp_hw_mgr.c b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/cam_isp_hw_mgr.c index 2f18895c2402..398b9323417a 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/cam_isp_hw_mgr.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/cam_isp_hw_mgr.c @@ -16,7 +16,7 @@ int cam_isp_hw_mgr_init(struct device_node *of_node, - struct cam_hw_mgr_intf *hw_mgr) + struct cam_hw_mgr_intf *hw_mgr, int *iommu_hdl) { int rc = 0; const char *compat_str = NULL; @@ -25,7 +25,7 @@ int cam_isp_hw_mgr_init(struct device_node *of_node, (const char **)&compat_str); if (strnstr(compat_str, "ife", strlen(compat_str))) - rc = cam_ife_hw_mgr_init(hw_mgr); + rc = cam_ife_hw_mgr_init(hw_mgr, iommu_hdl); else { CAM_ERR(CAM_ISP, "Invalid ISP hw type"); rc = -EINVAL; diff --git a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h index 2601190d0f41..406888a125f8 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h @@ -205,9 +205,9 @@ struct cam_isp_hw_cmd_args { * @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); + struct cam_hw_mgr_intf *hw_mgr, int *iommu_hdl); #endif /* __CAM_ISP_HW_MGR_INTF_H__ */ diff --git a/drivers/media/platform/msm/camera_oneplus/cam_jpeg/cam_jpeg_dev.c b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/cam_jpeg_dev.c index 60feeacde477..0a4135979b78 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_jpeg/cam_jpeg_dev.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/cam_jpeg_dev.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include "cam_node.h" @@ -22,11 +21,31 @@ #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" @@ -78,6 +97,7 @@ static int cam_jpeg_dev_probe(struct platform_device *pdev) 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, @@ -89,7 +109,7 @@ static int cam_jpeg_dev_probe(struct platform_device *pdev) node = (struct cam_node *)g_jpeg_dev.sd.token; rc = cam_jpeg_hw_mgr_init(pdev->dev.of_node, - (uint64_t *)&hw_mgr_intf); + (uint64_t *)&hw_mgr_intf, &iommu_hdl); if (rc) { CAM_ERR(CAM_JPEG, "Can not initialize JPEG HWmanager %d", rc); goto unregister; @@ -114,6 +134,9 @@ static int cam_jpeg_dev_probe(struct platform_device *pdev) 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"); diff --git a/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c index 32f11a7f7833..1542890b731b 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c @@ -49,14 +49,15 @@ 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; - uint32_t dev_type = 0; - uint64_t kaddr; + 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; @@ -144,10 +145,9 @@ static int cam_jpeg_mgr_process_irq(void *priv, void *data) return rc; } - rc = cam_mem_get_cpu_buf( - p_cfg_req->hw_cfg_args. - hw_update_entries[CAM_JPEG_PARAM].handle, - (uint64_t *)&kaddr, &cmd_buf_len); + 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); @@ -156,6 +156,14 @@ static int cam_jpeg_mgr_process_irq(void *priv, void *data) 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))); @@ -263,7 +271,7 @@ static int cam_jpeg_insert_cdm_change_base( struct cam_cdm_bl_request *cdm_cmd; uint32_t size; uint32_t mem_cam_base; - uint64_t iova_addr; + uintptr_t iova_addr; uint32_t *ch_base_iova_addr; size_t ch_base_len; @@ -275,6 +283,12 @@ static int cam_jpeg_insert_cdm_change_base( "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); @@ -1155,7 +1169,7 @@ static int cam_jpeg_mgr_get_hw_caps(void *hw_mgr_priv, void *hw_caps_args) mutex_lock(&hw_mgr->hw_mgr_mutex); - if (copy_to_user((void __user *)query_cap->caps_handle, + 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"); @@ -1376,7 +1390,8 @@ static int cam_jpeg_init_devices(struct device_node *of_node, return rc; } -int cam_jpeg_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl) +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; @@ -1420,11 +1435,6 @@ int cam_jpeg_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl) } CAM_DBG(CAM_JPEG, "mmu handle :%d", g_jpeg_hw_mgr.iommu_hdl); - rc = cam_smmu_ops(g_jpeg_hw_mgr.iommu_hdl, CAM_SMMU_ATTACH); - if (rc) { - CAM_ERR(CAM_JPEG, "jpeg attach failed: %d", rc); - goto jpeg_attach_failed; - } rc = cam_cdm_get_iommu_handle("jpegenc", &cdm_handles); if (rc) { @@ -1461,12 +1471,13 @@ int cam_jpeg_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl) goto cdm_iommu_failed; } + if (iommu_hdl) + *iommu_hdl = g_jpeg_hw_mgr.iommu_hdl; + return rc; cdm_iommu_failed: - cam_smmu_ops(g_jpeg_hw_mgr.iommu_hdl, CAM_SMMU_DETACH); cam_smmu_destroy_handle(g_jpeg_hw_mgr.iommu_hdl); -jpeg_attach_failed: g_jpeg_hw_mgr.iommu_hdl = 0; smmu_get_failed: mutex_destroy(&g_jpeg_hw_mgr.hw_mgr_mutex); diff --git a/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_mgr_intf.h b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_mgr_intf.h index 5fb4e3ad3399..64778b7b0014 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_mgr_intf.h +++ b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_mgr_intf.h @@ -19,6 +19,6 @@ int cam_jpeg_hw_mgr_init(struct device_node *of_node, - uint64_t *hw_mgr_hdl); + uint64_t *hw_mgr_hdl, int *iommu_hdl); #endif /* CAM_JPEG_HW_MGR_INTF_H */ diff --git a/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.h b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.h index a4d5d89e705e..0ef4572d34f0 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.h +++ b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.h @@ -17,7 +17,6 @@ #include #include #include -#include #include "cam_jpeg_hw_intf.h" diff --git a/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_soc.c b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_soc.c index 63d54fdf7d80..2feac6b05834 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_soc.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_soc.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include diff --git a/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.h b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.h index 5fa8f21f6b23..ca4d2692a455 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.h +++ b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.h @@ -17,7 +17,6 @@ #include #include #include -#include #include "cam_jpeg_hw_intf.h" diff --git a/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_soc.c b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_soc.c index ddf246560534..fd34bee08b22 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_soc.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_soc.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include diff --git a/drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c b/drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c index 4c93968b599c..1ed7fb10a485 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/cam_lrme_hw_mgr.c @@ -150,7 +150,7 @@ static int cam_lrme_mgr_util_prepare_io_buffer(int32_t iommu_hdl, int rc = -EINVAL; uint32_t num_in_buf, num_out_buf, i, j, plane; struct cam_buf_io_cfg *io_cfg; - uint64_t io_addr[CAM_PACKET_MAX_PLANES]; + dma_addr_t io_addr[CAM_PACKET_MAX_PLANES]; size_t size; num_in_buf = 0; @@ -166,13 +166,6 @@ static int cam_lrme_mgr_util_prepare_io_buffer(int32_t iommu_hdl, 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_LRME, "Invalid number of buffers %d %d %d", - num_in_buf, num_out_buf, io_buf_size); - return -EINVAL; - } - memset(io_addr, 0, sizeof(io_addr)); for (plane = 0; plane < CAM_PACKET_MAX_PLANES; plane++) { if (!io_cfg[i].mem_handle[plane]) @@ -186,20 +179,26 @@ static int cam_lrme_mgr_util_prepare_io_buffer(int32_t iommu_hdl, return -ENOMEM; } - io_addr[plane] += io_cfg[i].offsets[plane]; - - if (io_addr[plane] >> 32) { - CAM_ERR(CAM_LRME, "Invalid io addr 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 = @@ -215,6 +214,12 @@ static int cam_lrme_mgr_util_prepare_io_buffer(int32_t iommu_hdl, 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 = @@ -575,7 +580,8 @@ static int cam_lrme_mgr_get_caps(void *hw_mgr_priv, void *hw_get_caps_args) return -EFAULT; } - if (copy_to_user((void __user *)args->caps_handle, &(hw_mgr->lrme_caps), + 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; diff --git a/drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c b/drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c index da42c84f3835..6825ef6bedf3 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_lrme/lrme_hw_mgr/lrme_hw/cam_lrme_hw_dev.c @@ -161,12 +161,6 @@ static int cam_lrme_hw_dev_probe(struct platform_device *pdev) goto release_cdm; } - rc = cam_smmu_ops(lrme_core->device_iommu.non_secure, CAM_SMMU_ATTACH); - if (rc) { - CAM_ERR(CAM_LRME, "LRME attach iommu handle failed, rc=%d", rc); - goto destroy_smmu; - } - rc = cam_lrme_hw_start(lrme_hw, NULL, 0); if (rc) { CAM_ERR(CAM_LRME, "Failed to hw init, rc=%d", rc); @@ -224,8 +218,6 @@ static int cam_lrme_hw_dev_probe(struct platform_device *pdev) return rc; detach_smmu: - cam_smmu_ops(lrme_core->device_iommu.non_secure, CAM_SMMU_DETACH); -destroy_smmu: cam_smmu_destroy_handle(lrme_core->device_iommu.non_secure); release_cdm: cam_cdm_release(lrme_core->hw_cdm_info->cdm_handle); @@ -265,7 +257,6 @@ static int cam_lrme_hw_dev_remove(struct platform_device *pdev) goto deinit_platform_res; } - cam_smmu_ops(lrme_core->device_iommu.non_secure, CAM_SMMU_DETACH); 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); diff --git a/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_mem_mgr.c b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_mem_mgr.c index 643b0afce740..54bdb5cc5d2f 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_mem_mgr.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_mem_mgr.c @@ -15,33 +15,19 @@ #include #include #include -#include +#include +#include +#include #include "cam_req_mgr_util.h" #include "cam_mem_mgr.h" #include "cam_smmu_api.h" #include "cam_debug_util.h" +#include "cam_trace.h" +#include "cam_common_util.h" static struct cam_mem_table tbl; - -static int cam_mem_util_map_cpu_va(struct ion_handle *hdl, - uint64_t *vaddr, - size_t *len) -{ - *vaddr = (uintptr_t)ion_map_kernel(tbl.client, hdl); - if (IS_ERR_OR_NULL((void *)*vaddr)) { - CAM_ERR(CAM_CRM, "kernel map fail"); - return -ENOSPC; - } - - if (ion_handle_get_size(tbl.client, hdl, len)) { - CAM_ERR(CAM_CRM, "kernel get len failed"); - ion_unmap_kernel(tbl.client, hdl); - return -ENOSPC; - } - - return 0; -} +static atomic_t cam_mem_mgr_state = ATOMIC_INIT(CAM_MEM_MGR_UNINITIALIZED); static int cam_mem_util_get_dma_dir(uint32_t flags) { @@ -59,45 +45,122 @@ static int cam_mem_util_get_dma_dir(uint32_t flags) return rc; } -static int cam_mem_util_client_create(void) +static int cam_mem_util_map_cpu_va(struct dma_buf *dmabuf, + uintptr_t *vaddr, + size_t *len) { - int rc = 0; + 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; + } - tbl.client = msm_ion_client_create("camera_global_pool"); - if (IS_ERR_OR_NULL(tbl.client)) { - CAM_ERR(CAM_CRM, "fail to create client"); - rc = -EINVAL; + /* + * 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; -static void cam_mem_util_client_destroy(void) + 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; +} + +static int cam_mem_mgr_create_debug_fs(void) { - ion_client_destroy(tbl.client); - tbl.client = NULL; + tbl.dentry = debugfs_create_dir("camera_memmgr", NULL); + if (!tbl.dentry) { + CAM_ERR(CAM_MEM, "failed to create dentry"); + return -ENOMEM; + } + + if (!debugfs_create_bool("alloc_profile_enable", + 0644, + tbl.dentry, + &tbl.alloc_profile_enable)) { + CAM_ERR(CAM_MEM, + "failed to create alloc_profile_enable"); + goto err; + } + + return 0; +err: + debugfs_remove_recursive(tbl.dentry); + return -ENOMEM; } int cam_mem_mgr_init(void) { - int rc; int i; int bitmap_size; memset(tbl.bufq, 0, sizeof(tbl.bufq)); - rc = cam_mem_util_client_create(); - if (rc < 0) { - CAM_ERR(CAM_CRM, "fail to create ion client"); - goto client_fail; - } - bitmap_size = BITS_TO_LONGS(CAM_MEM_BUFQ_MAX) * sizeof(long); tbl.bitmap = kzalloc(bitmap_size, GFP_KERNEL); - if (!tbl.bitmap) { - rc = -ENOMEM; - goto bitmap_fail; - } + 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 */ @@ -108,12 +171,12 @@ int cam_mem_mgr_init(void) tbl.bufq[i].buf_handle = -1; } mutex_init(&tbl.m_lock); - return rc; -bitmap_fail: - cam_mem_util_client_destroy(); -client_fail: - return rc; + atomic_set(&cam_mem_mgr_state, CAM_MEM_MGR_INITIALIZED); + + cam_mem_mgr_create_debug_fs(); + + return 0; } static int32_t cam_mem_get_slot(void) @@ -121,18 +184,22 @@ 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) { + if (tbl.bitmap) { + 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 -ENOMEM; + return idx; } - set_bit(idx, tbl.bitmap); - tbl.bufq[idx].active = true; - mutex_init(&tbl.bufq[idx].q_lock); mutex_unlock(&tbl.m_lock); - - return idx; + return -EINVAL; } static void cam_mem_put_slot(int32_t idx) @@ -147,16 +214,23 @@ static void cam_mem_put_slot(int32_t idx) } int cam_mem_get_io_buf(int32_t buf_handle, int32_t mmu_handle, - uint64_t *iova_ptr, size_t *len_ptr) + 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 -EINVAL; + return -ENOENT; if (!tbl.bufq[idx].active) - return -EINVAL; + return -EAGAIN; mutex_lock(&tbl.bufq[idx].q_lock); if (buf_handle != tbl.bufq[idx].buf_handle) { @@ -174,22 +248,35 @@ int cam_mem_get_io_buf(int32_t buf_handle, int32_t mmu_handle, tbl.bufq[idx].fd, iova_ptr, len_ptr); - if (rc < 0) - CAM_ERR(CAM_CRM, "fail to get buf hdl :%d", buf_handle); + 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, uint64_t *vaddr_ptr, size_t *len) +int cam_mem_get_cpu_buf(int32_t buf_handle, uintptr_t *vaddr_ptr, size_t *len) { - int rc = 0; int idx; - struct ion_handle *ion_hdl = NULL; - uint64_t kvaddr = 0; - size_t klen = 0; + + 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; @@ -201,46 +288,35 @@ int cam_mem_get_cpu_buf(int32_t buf_handle, uint64_t *vaddr_ptr, size_t *len) if (!tbl.bufq[idx].active) return -EPERM; - mutex_lock(&tbl.bufq[idx].q_lock); - if (buf_handle != tbl.bufq[idx].buf_handle) { - rc = -EINVAL; - goto exit_func; - } + if (buf_handle != tbl.bufq[idx].buf_handle) + return -EINVAL; - ion_hdl = tbl.bufq[idx].i_hdl; - if (!ion_hdl) { - CAM_ERR(CAM_CRM, "Invalid ION handle"); - rc = -EINVAL; - goto exit_func; - } + if (!(tbl.bufq[idx].flags & CAM_MEM_FLAG_KMD_ACCESS)) + return -EINVAL; - if (tbl.bufq[idx].flags & CAM_MEM_FLAG_KMD_ACCESS) { - if (!tbl.bufq[idx].kmdvaddr) { - rc = cam_mem_util_map_cpu_va(ion_hdl, - &kvaddr, &klen); - if (rc) - goto exit_func; - tbl.bufq[idx].kmdvaddr = kvaddr; - } + if (tbl.bufq[idx].kmdvaddr) { + *vaddr_ptr = tbl.bufq[idx].kmdvaddr; + *len = tbl.bufq[idx].len; } else { - rc = -EINVAL; - goto exit_func; + CAM_ERR(CAM_MEM, "No KMD access was requested for 0x%x handle", + buf_handle); + return -EINVAL; } - *vaddr_ptr = tbl.bufq[idx].kmdvaddr; - *len = tbl.bufq[idx].len; - -exit_func: - mutex_unlock(&tbl.bufq[idx].q_lock); - return rc; + 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 ion_cache_ops; - unsigned long ion_flag = 0; + 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; @@ -253,127 +329,140 @@ int cam_mem_mgr_cache_ops(struct cam_mem_cache_ops_cmd *cmd) if (!tbl.bufq[idx].active) { rc = -EINVAL; - goto fail; + goto end; } if (cmd->buf_handle != tbl.bufq[idx].buf_handle) { rc = -EINVAL; - goto fail; + goto end; } - rc = ion_handle_get_flags(tbl.client, tbl.bufq[idx].i_hdl, - &ion_flag); + rc = dma_buf_get_flags(tbl.bufq[idx].dma_buf, &dmabuf_flag); if (rc) { - CAM_ERR(CAM_CRM, "cache get flags failed %d", rc); - goto fail; + CAM_ERR(CAM_MEM, "cache get flags failed %d", rc); + goto end; } - if (ION_IS_CACHED(ion_flag)) { + if (dmabuf_flag & ION_FLAG_CACHED) { switch (cmd->mem_cache_ops) { case CAM_MEM_CLEAN_CACHE: - ion_cache_ops = ION_IOC_CLEAN_CACHES; + cache_dir = DMA_TO_DEVICE; break; case CAM_MEM_INV_CACHE: - ion_cache_ops = ION_IOC_INV_CACHES; + cache_dir = DMA_FROM_DEVICE; break; case CAM_MEM_CLEAN_INV_CACHE: - ion_cache_ops = ION_IOC_CLEAN_INV_CACHES; + cache_dir = DMA_BIDIRECTIONAL; break; default: - CAM_ERR(CAM_CRM, + CAM_ERR(CAM_MEM, "invalid cache ops :%d", cmd->mem_cache_ops); rc = -EINVAL; - goto fail; + 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 = msm_ion_do_cache_op(tbl.client, - tbl.bufq[idx].i_hdl, - (void *)tbl.bufq[idx].vaddr, - tbl.bufq[idx].len, - ion_cache_ops); - if (rc) - CAM_ERR(CAM_CRM, "cache operation failed %d", rc); + 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; } -fail: + +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, - size_t align, unsigned int heap_id_mask, unsigned int flags, - struct ion_handle **hdl, struct dma_buf **buf) { int rc = 0; - if (!hdl || !buf) { - CAM_ERR(CAM_CRM, "Invalid params"); + if (!buf) { + CAM_ERR(CAM_MEM, "Invalid params"); return -EINVAL; } - *hdl = ion_alloc(tbl.client, len, align, heap_id_mask, flags); - if (IS_ERR_OR_NULL(*hdl)) + *buf = ion_alloc(len, heap_id_mask, flags); + if (IS_ERR_OR_NULL(*buf)) return -ENOMEM; - *buf = ion_share_dma_buf(tbl.client, *hdl); - if (IS_ERR_OR_NULL(*buf)) { - CAM_ERR(CAM_CRM, "get dma buf fail"); - rc = -EINVAL; - goto get_buf_fail; - } - return rc; - -get_buf_fail: - ion_free(tbl.client, *hdl); - 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 ion_handle **hdl, + struct dma_buf **buf, int *fd) { + struct dma_buf *dmabuf = NULL; int rc = 0; - if (!hdl || !fd) { - CAM_ERR(CAM_CRM, "Invalid params"); + if (!buf || !fd) { + CAM_ERR(CAM_MEM, "Invalid params, buf=%pK, fd=%pK", buf, fd); return -EINVAL; } - *hdl = ion_alloc(tbl.client, len, align, heap_id_mask, flags); - if (IS_ERR_OR_NULL(*hdl)) + *buf = ion_alloc(len, heap_id_mask, flags); + if (IS_ERR_OR_NULL(*buf)) return -ENOMEM; - *fd = ion_share_dma_buf_fd(tbl.client, *hdl); + *fd = dma_buf_fd(*buf, O_CLOEXEC); if (*fd < 0) { - CAM_ERR(CAM_CRM, "get fd fail"); + 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: - ion_free(tbl.client, *hdl); + dma_buf_put(*buf); return rc; } static int cam_mem_util_ion_alloc(struct cam_mem_mgr_alloc_cmd *cmd, - struct ion_handle **hdl, + 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) { + 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 { @@ -390,29 +479,24 @@ static int cam_mem_util_ion_alloc(struct cam_mem_mgr_alloc_cmd *cmd, cmd->align, heap_id, ion_flag, - hdl, + dmabuf, fd); return rc; } -static int cam_mem_util_check_flags(struct cam_mem_mgr_alloc_cmd *cmd) +static int cam_mem_util_check_alloc_flags(struct cam_mem_mgr_alloc_cmd *cmd) { - if (!cmd->flags) { - CAM_ERR(CAM_CRM, "Invalid flags"); - return -EINVAL; - } - if (cmd->num_hdl > CAM_MEM_MMU_MAX_HANDLE) { - CAM_ERR(CAM_CRM, "Num of mmu hdl exceeded maximum(%d)", + 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_CRM, "Kernel mapping in secure mode not allowed"); + CAM_ERR(CAM_MEM, "Kernel mapping in secure mode not allowed"); return -EINVAL; } @@ -422,24 +506,26 @@ static int cam_mem_util_check_flags(struct cam_mem_mgr_alloc_cmd *cmd) static int cam_mem_util_check_map_flags(struct cam_mem_mgr_map_cmd *cmd) { if (!cmd->flags) { - CAM_ERR(CAM_CRM, "Invalid flags"); + CAM_ERR(CAM_MEM, "Invalid flags"); return -EINVAL; } if (cmd->num_hdl > CAM_MEM_MMU_MAX_HANDLE) { - CAM_ERR(CAM_CRM, "Num of mmu hdl exceeded maximum(%d)", - 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_CRM, "Kernel mapping in secure mode not allowed"); + 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_CRM, + CAM_ERR(CAM_MEM, "Shared memory buffers are not allowed to be mapped"); return -EINVAL; } @@ -458,24 +544,32 @@ static int cam_mem_util_map_hw_va(uint32_t flags, 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_CRM, "fail to map DMA direction"); + 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, - tbl.client, - (ion_phys_addr_t *)hw_vaddr, + hw_vaddr, len); if (rc < 0) { - CAM_ERR(CAM_CRM, - "Failed to securely map to smmu"); + 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; } } @@ -483,13 +577,16 @@ static int cam_mem_util_map_hw_va(uint32_t flags, 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_CRM, "Failed to map to smmu"); + 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; } } @@ -513,37 +610,49 @@ int cam_mem_mgr_alloc_and_map(struct cam_mem_mgr_alloc_cmd *cmd) { int rc; int32_t idx; - struct ion_handle *ion_hdl; - int ion_fd; + 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_CRM, " Invalid argument"); + CAM_ERR(CAM_MEM, " Invalid argument"); return -EINVAL; } len = cmd->len; - rc = cam_mem_util_check_flags(cmd); + rc = cam_mem_util_check_alloc_flags(cmd); if (rc) { - CAM_ERR(CAM_CRM, "Invalid flags: flags = %X", cmd->flags); + CAM_ERR(CAM_MEM, "Invalid flags: flags = 0x%X, rc=%d", + cmd->flags, rc); return rc; } rc = cam_mem_util_ion_alloc(cmd, - &ion_hdl, - &ion_fd); + &dmabuf, + &fd); if (rc) { - CAM_ERR(CAM_CRM, "Ion allocation failed"); + 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; } + mutex_lock(&tbl.m_lock); if ((cmd->flags & CAM_MEM_FLAG_HW_READ_WRITE) || (cmd->flags & CAM_MEM_FLAG_HW_SHARED_ACCESS) || (cmd->flags & CAM_MEM_FLAG_PROTECTED_MODE)) { @@ -557,33 +666,48 @@ int cam_mem_mgr_alloc_and_map(struct cam_mem_mgr_alloc_cmd *cmd) 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, - ion_fd, + fd, &hw_vaddr, &len, region); - if (rc) + + if (rc) { + CAM_ERR(CAM_MEM, + "Failed in map_hw_va, len=%llu, flags=0x%x, fd=%d, region=%d, num_hdl=%d, rc=%d", + len, cmd->flags, fd, region, + cmd->num_hdl, rc); + mutex_unlock(&tbl.m_lock); goto map_hw_fail; + } } - + mutex_unlock(&tbl.m_lock); mutex_lock(&tbl.bufq[idx].q_lock); - tbl.bufq[idx].fd = ion_fd; + 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, ion_fd); + 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); - tbl.bufq[idx].kmdvaddr = 0; - if (cmd->num_hdl > 0) - tbl.bufq[idx].vaddr = hw_vaddr; - else - tbl.bufq[idx].vaddr = 0; + 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].i_hdl = ion_hdl; - tbl.bufq[idx].len = cmd->len; + tbl.bufq[idx].kmdvaddr = kvaddr; + tbl.bufq[idx].vaddr = hw_vaddr; + 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); @@ -594,16 +718,19 @@ int cam_mem_mgr_alloc_and_map(struct cam_mem_mgr_alloc_cmd *cmd) cmd->out.fd = tbl.bufq[idx].fd; cmd->out.vaddr = 0; - CAM_DBG(CAM_CRM, "buf handle: %x, fd: %d, len: %zu", - cmd->out.buf_handle, cmd->out.fd, + 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: - ion_free(tbl.client, ion_hdl); + dma_buf_put(dmabuf); return rc; } @@ -611,30 +738,39 @@ int cam_mem_mgr_map(struct cam_mem_mgr_map_cmd *cmd) { int32_t idx; int rc; - struct ion_handle *ion_hdl; + 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_CRM, "Invalid argument"); + CAM_ERR(CAM_MEM, "Invalid argument"); return -EINVAL; } - if (cmd->num_hdl > CAM_MEM_MMU_MAX_HANDLE) + 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_CRM, "Invalid flags: flags = %X", cmd->flags); + CAM_ERR(CAM_MEM, "Invalid flags: flags = %X", cmd->flags); return rc; } - ion_hdl = ion_import_dma_buf_fd(tbl.client, cmd->fd); - if (IS_ERR_OR_NULL((void *)(ion_hdl))) { - CAM_ERR(CAM_CRM, "Failed to import ion fd"); + 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; } + mutex_lock(&tbl.m_lock); 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, @@ -644,9 +780,16 @@ int cam_mem_mgr_map(struct cam_mem_mgr_map_cmd *cmd) &hw_vaddr, &len, CAM_SMMU_REGION_IO); - if (rc) + 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); + mutex_unlock(&tbl.m_lock); goto map_fail; + } } + mutex_unlock(&tbl.m_lock); idx = cam_mem_get_slot(); if (idx < 0) { @@ -668,7 +811,7 @@ int cam_mem_mgr_map(struct cam_mem_mgr_map_cmd *cmd) else tbl.bufq[idx].vaddr = 0; - tbl.bufq[idx].i_hdl = ion_hdl; + 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, @@ -679,10 +822,15 @@ int cam_mem_mgr_map(struct cam_mem_mgr_map_cmd *cmd) 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: - ion_free(tbl.client, ion_hdl); + dma_buf_put(dmabuf); return rc; } @@ -695,11 +843,11 @@ static int cam_mem_util_unmap_hw_va(int32_t idx, int32_t *mmu_hdls; int num_hdls; int fd; - int rc = -EINVAL; + int rc = 0; if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) { - CAM_ERR(CAM_CRM, "Incorrect index"); - return rc; + CAM_ERR(CAM_MEM, "Incorrect index"); + return -EINVAL; } flags = tbl.bufq[idx].flags; @@ -707,35 +855,47 @@ static int cam_mem_util_unmap_hw_va(int32_t idx, 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) + 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); + 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_CRM, + CAM_ERR(CAM_MEM, "invalid caller for unmapping : %d", client); rc = -EINVAL; } - if (rc < 0) + 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_CRM, "unmapping failed"); + CAM_ERR(CAM_MEM, "unmapping failed"); return rc; } @@ -758,20 +918,20 @@ static int cam_mem_mgr_cleanup_table(void) mutex_lock(&tbl.m_lock); for (i = 1; i < CAM_MEM_BUFQ_MAX; i++) { if (!tbl.bufq[i].active) { - CAM_DBG(CAM_CRM, + CAM_DBG(CAM_MEM, "Buffer inactive at idx=%d, continuing", i); continue; } else { - CAM_DBG(CAM_CRM, + 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].i_hdl) { - ion_free(tbl.client, tbl.bufq[i].i_hdl); - tbl.bufq[i].i_hdl = NULL; + 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; @@ -781,11 +941,12 @@ static int cam_mem_mgr_cleanup_table(void) memset(tbl.bufq[i].hdls, 0, sizeof(int32_t) * tbl.bufq[i].num_hdl); tbl.bufq[i].num_hdl = 0; - tbl.bufq[i].i_hdl = NULL; + 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); @@ -796,12 +957,12 @@ static int cam_mem_mgr_cleanup_table(void) 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; - cam_mem_util_client_destroy(); mutex_unlock(&tbl.m_lock); mutex_destroy(&tbl.m_lock); } @@ -813,25 +974,32 @@ static int cam_mem_util_unmap(int32_t idx, enum cam_smmu_region_id region = CAM_SMMU_REGION_SHARED; if (idx >= CAM_MEM_BUFQ_MAX || idx <= 0) { - CAM_ERR(CAM_CRM, "Incorrect index"); + CAM_ERR(CAM_MEM, "Incorrect index"); return -EINVAL; } - CAM_DBG(CAM_CRM, "Flags = %X idx %d", tbl.bufq[idx].flags, idx); + 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_CRM, "Buffer at idx=%d is already unmapped,", + 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].i_hdl && tbl.bufq[idx].kmdvaddr) - ion_unmap_kernel(tbl.client, tbl.bufq[idx].i_hdl); + 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) { @@ -843,9 +1011,13 @@ static int cam_mem_util_unmap(int32_t idx, 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)) - rc = cam_mem_util_unmap_hw_va(idx, region, client); - + (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; @@ -854,16 +1026,14 @@ static int cam_mem_util_unmap(int32_t idx, memset(tbl.bufq[idx].hdls, 0, sizeof(int32_t) * CAM_MEM_MMU_MAX_HANDLE); - CAM_DBG(CAM_CRM, - "Ion handle at idx = %d freeing = %pK, fd = %d, imported %d dma_buf %pK", - idx, tbl.bufq[idx].i_hdl, tbl.bufq[idx].fd, + 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].i_hdl) { - ion_free(tbl.client, tbl.bufq[idx].i_hdl); - tbl.bufq[idx].i_hdl = NULL; - } + 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; @@ -884,29 +1054,36 @@ 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_CRM, "Invalid argument"); + 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_CRM, "Incorrect index extracted from mem handle"); + CAM_ERR(CAM_MEM, "Incorrect index %d extracted from mem handle", + idx); return -EINVAL; } if (!tbl.bufq[idx].active) { - CAM_ERR(CAM_CRM, "Released buffer state should be 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_CRM, - "Released buf handle not matching within table"); + 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_CRM, "Releasing hdl = %u", cmd->buf_handle); + 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; @@ -915,13 +1092,12 @@ int cam_mem_mgr_release(struct cam_mem_mgr_release_cmd *cmd) int cam_mem_mgr_request_mem(struct cam_mem_mgr_request_desc *inp, struct cam_mem_mgr_memory_desc *out) { - struct ion_handle *hdl; struct dma_buf *buf = NULL; int ion_fd = -1; int rc = 0; uint32_t heap_id; int32_t ion_flag = 0; - uint64_t kvaddr; + uintptr_t kvaddr; dma_addr_t iova = 0; size_t request_len = 0; uint32_t mem_handle; @@ -931,15 +1107,20 @@ int cam_mem_mgr_request_mem(struct cam_mem_mgr_request_desc *inp, 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_CRM, "Invalid params"); + 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_CRM, "Invalid flags for request mem"); + CAM_ERR(CAM_MEM, "Invalid flags for request mem"); return -EINVAL; } @@ -952,27 +1133,30 @@ int cam_mem_mgr_request_mem(struct cam_mem_mgr_request_desc *inp, ION_HEAP(ION_CAMERA_HEAP_ID); rc = cam_mem_util_get_dma_buf(inp->size, - inp->align, heap_id, ion_flag, - &hdl, &buf); if (rc) { - CAM_ERR(CAM_CRM, "ION alloc failed for shared buffer"); + CAM_ERR(CAM_MEM, "ION alloc failed for shared buffer"); goto ion_fail; } else { - CAM_DBG(CAM_CRM, "Got dma_buf = %pK, hdl = %pK", buf, hdl); + CAM_DBG(CAM_MEM, "Got dma_buf = %pK", buf); } - rc = cam_mem_util_map_cpu_va(hdl, &kvaddr, &request_len); + /* + * 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_CRM, "Failed to get kernel vaddr"); + CAM_ERR(CAM_MEM, "Failed to get kernel vaddr"); goto map_fail; } if (!inp->smmu_hdl) { - CAM_ERR(CAM_CRM, "Invalid SMMU handle"); + CAM_ERR(CAM_MEM, "Invalid SMMU handle"); rc = -EINVAL; goto smmu_fail; } @@ -993,7 +1177,7 @@ int cam_mem_mgr_request_mem(struct cam_mem_mgr_request_desc *inp, region); if (rc < 0) { - CAM_ERR(CAM_CRM, "SMMU mapping failed"); + CAM_ERR(CAM_MEM, "SMMU mapping failed"); goto smmu_fail; } @@ -1016,7 +1200,6 @@ int cam_mem_mgr_request_mem(struct cam_mem_mgr_request_desc *inp, tbl.bufq[idx].vaddr = iova; - tbl.bufq[idx].i_hdl = hdl; tbl.bufq[idx].len = inp->size; tbl.bufq[idx].num_hdl = num_hdl; memcpy(tbl.bufq[idx].hdls, &smmu_hdl, @@ -1034,11 +1217,11 @@ int cam_mem_mgr_request_mem(struct cam_mem_mgr_request_desc *inp, return rc; slot_fail: cam_smmu_unmap_kernel_iova(inp->smmu_hdl, - buf, region); + buf, region); smmu_fail: - ion_unmap_kernel(tbl.client, hdl); + cam_mem_util_unmap_cpu_va(buf, kvaddr); map_fail: - ion_free(tbl.client, hdl); + dma_buf_put(buf); ion_fail: return rc; } @@ -1049,33 +1232,38 @@ 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_CRM, "Invalid argument"); + 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_CRM, "Incorrect index extracted from mem handle"); + 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_CRM, "buffer is released already"); + CAM_ERR(CAM_MEM, "buffer is released already"); return 0; } - CAM_ERR(CAM_CRM, "Released buffer state should be active"); + CAM_ERR(CAM_MEM, "Released buffer state should be active"); return -EINVAL; } if (tbl.bufq[idx].buf_handle != inp->mem_handle) { - CAM_ERR(CAM_CRM, + CAM_ERR(CAM_MEM, "Released buf handle not matching within table"); return -EINVAL; } - CAM_DBG(CAM_CRM, "Releasing hdl = %X", inp->mem_handle); + CAM_DBG(CAM_MEM, "Releasing hdl = %X", inp->mem_handle); rc = cam_mem_util_unmap(idx, CAM_SMMU_MAPPING_KERNEL); return rc; @@ -1086,7 +1274,6 @@ 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 ion_handle *hdl; struct dma_buf *buf = NULL; int rc = 0; int ion_fd = -1; @@ -1098,35 +1285,38 @@ int cam_mem_mgr_reserve_memory_region(struct cam_mem_mgr_request_desc *inp, 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_CRM, "Invalid param(s)"); + CAM_ERR(CAM_MEM, "Invalid param(s)"); return -EINVAL; } if (!inp->smmu_hdl) { - CAM_ERR(CAM_CRM, "Invalid SMMU handle"); + CAM_ERR(CAM_MEM, "Invalid SMMU handle"); return -EINVAL; } if (region != CAM_SMMU_REGION_SECHEAP) { - CAM_ERR(CAM_CRM, "Only secondary heap supported"); + 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, - inp->align, heap_id, 0, - &hdl, &buf); if (rc) { - CAM_ERR(CAM_CRM, "ION alloc failed for sec heap buffer"); + CAM_ERR(CAM_MEM, "ION alloc failed for sec heap buffer"); goto ion_fail; } else { - CAM_DBG(CAM_CRM, "Got dma_buf = %pK, hdl = %pK", buf, hdl); + CAM_DBG(CAM_MEM, "Got dma_buf = %pK", buf); } rc = cam_smmu_reserve_sec_heap(inp->smmu_hdl, @@ -1135,7 +1325,7 @@ int cam_mem_mgr_reserve_memory_region(struct cam_mem_mgr_request_desc *inp, &request_len); if (rc) { - CAM_ERR(CAM_CRM, "Reserving secondary heap failed"); + CAM_ERR(CAM_MEM, "Reserving secondary heap failed"); goto smmu_fail; } @@ -1158,7 +1348,6 @@ int cam_mem_mgr_reserve_memory_region(struct cam_mem_mgr_request_desc *inp, tbl.bufq[idx].vaddr = iova; - tbl.bufq[idx].i_hdl = hdl; tbl.bufq[idx].len = request_len; tbl.bufq[idx].num_hdl = num_hdl; memcpy(tbl.bufq[idx].hdls, &smmu_hdl, @@ -1178,7 +1367,7 @@ int cam_mem_mgr_reserve_memory_region(struct cam_mem_mgr_request_desc *inp, slot_fail: cam_smmu_release_sec_heap(smmu_hdl); smmu_fail: - ion_free(tbl.client, hdl); + dma_buf_put(buf); ion_fail: return rc; } @@ -1190,39 +1379,44 @@ int cam_mem_mgr_free_memory_region(struct cam_mem_mgr_memory_desc *inp) 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_CRM, "Invalid argument"); + CAM_ERR(CAM_MEM, "Invalid argument"); return -EINVAL; } if (inp->region != CAM_SMMU_REGION_SECHEAP) { - CAM_ERR(CAM_CRM, "Only secondary heap supported"); + 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_CRM, "Incorrect index extracted from mem handle"); + 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_CRM, "buffer is released already"); + CAM_ERR(CAM_MEM, "buffer is released already"); return 0; } - CAM_ERR(CAM_CRM, "Released buffer state should be active"); + CAM_ERR(CAM_MEM, "Released buffer state should be active"); return -EINVAL; } if (tbl.bufq[idx].buf_handle != inp->mem_handle) { - CAM_ERR(CAM_CRM, + CAM_ERR(CAM_MEM, "Released buf handle not matching within table"); return -EINVAL; } if (tbl.bufq[idx].num_hdl != 1) { - CAM_ERR(CAM_CRM, + CAM_ERR(CAM_MEM, "Sec heap region should have only one smmu hdl"); return -ENODEV; } @@ -1230,22 +1424,22 @@ int cam_mem_mgr_free_memory_region(struct cam_mem_mgr_memory_desc *inp) memcpy(&smmu_hdl, tbl.bufq[idx].hdls, sizeof(int32_t)); if (inp->smmu_hdl != smmu_hdl) { - CAM_ERR(CAM_CRM, + 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_CRM, + CAM_ERR(CAM_MEM, "Sec heap region release failed"); return -ENODEV; } - CAM_DBG(CAM_CRM, "Releasing hdl = %X", inp->mem_handle); + 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_CRM, "unmapping secondary heap failed"); + CAM_ERR(CAM_MEM, "unmapping secondary heap failed"); return rc; } diff --git a/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_mem_mgr.h b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_mem_mgr.h index 83727d20e685..3b91933f673a 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_mem_mgr.h +++ b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_mem_mgr.h @@ -20,6 +20,12 @@ #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, @@ -29,7 +35,6 @@ enum cam_smmu_mapping_client { /** * struct cam_mem_buf_queue * - * @i_hdl: ion handle for the buffer * @dma_buf: pointer to the allocated dma_buf in the table * @q_lock: mutex lock for buffer * @hdls: list of mapped handles @@ -45,7 +50,6 @@ enum cam_smmu_mapping_client { * @is_imported: Flag indicating if buffer is imported from an FD in user space */ struct cam_mem_buf_queue { - struct ion_handle *i_hdl; struct dma_buf *dma_buf; struct mutex q_lock; int32_t hdls[CAM_MEM_MMU_MAX_HANDLE]; @@ -56,7 +60,7 @@ struct cam_mem_buf_queue { size_t len; uint32_t flags; uint64_t vaddr; - uint64_t kmdvaddr; + uintptr_t kmdvaddr; bool active; bool is_imported; }; @@ -67,15 +71,17 @@ struct cam_mem_buf_queue { * @m_lock: mutex lock for table * @bitmap: bitmap of the mem mgr utility * @bits: max bits of the utility - * @client: ion client pointer * @bufq: array of buffers + * @dentry: Debugfs entry + * @alloc_profile_enable: Whether to enable alloc profiling */ struct cam_mem_table { struct mutex m_lock; void *bitmap; size_t bits; - struct ion_client *client; struct cam_mem_buf_queue bufq[CAM_MEM_BUFQ_MAX]; + struct dentry *dentry; + bool alloc_profile_enable; }; /** diff --git a/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_mem_mgr_api.h b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_mem_mgr_api.h index 7588c179f4a5..fc6a628a20bb 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_mem_mgr_api.h +++ b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_mem_mgr_api.h @@ -43,7 +43,7 @@ struct cam_mem_mgr_request_desc { * @region : Region to which allocated memory belongs */ struct cam_mem_mgr_memory_desc { - uint64_t kva; + uintptr_t kva; uint32_t iova; int32_t smmu_hdl; uint32_t mem_handle; @@ -82,9 +82,11 @@ int cam_mem_mgr_release_mem(struct cam_mem_mgr_memory_desc *inp); * @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, - uint64_t *iova_ptr, size_t *len_ptr); + dma_addr_t *iova_ptr, size_t *len_ptr); + /** - * @brief: Returns CPU address information about buffer + * @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 @@ -92,7 +94,7 @@ int cam_mem_get_io_buf(int32_t buf_handle, int32_t mmu_handle, * * @return Status of operation. Negative in case of error. Zero otherwise. */ -int cam_mem_get_cpu_buf(int32_t buf_handle, uint64_t *vaddr_ptr, +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) diff --git a/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_core.c b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_core.c index ef0cdc3d7baf..d94663b3bb13 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_core.c @@ -1077,9 +1077,10 @@ static int __cam_req_mgr_reset_in_q(struct cam_req_mgr_req_data *req) * @data : timer pointer * */ -static void __cam_req_mgr_sof_freeze(unsigned long data) +static void __cam_req_mgr_sof_freeze(struct timer_list *timer_data) { - struct cam_req_mgr_timer *timer = (struct cam_req_mgr_timer *)data; + struct cam_req_mgr_timer *timer = + container_of(timer_data, struct cam_req_mgr_timer, sys_timer); struct cam_req_mgr_core_link *link = NULL; struct cam_req_mgr_core_session *session = NULL; struct cam_req_mgr_message msg; diff --git a/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_dev.c b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_dev.c index 9a93feba1ac5..223cfc6f6ca4 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_dev.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_dev.c @@ -153,6 +153,12 @@ static unsigned int cam_req_mgr_poll(struct file *f, 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) { @@ -161,6 +167,17 @@ static int cam_req_mgr_close(struct file *filep) } 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); @@ -220,15 +237,17 @@ static long cam_private_ioctl(struct file *file, void *fh, return -EINVAL; if (copy_from_user(&ses_info, - (void *)k_ioctl->handle, + u64_to_user_ptr(k_ioctl->handle), k_ioctl->size)) { return -EFAULT; } rc = cam_req_mgr_create_session(&ses_info); if (!rc) - if (copy_to_user((void *)k_ioctl->handle, - &ses_info, k_ioctl->size)) + if (copy_to_user( + u64_to_user_ptr(k_ioctl->handle), + &ses_info, + k_ioctl->size)) rc = -EFAULT; } break; @@ -240,7 +259,7 @@ static long cam_private_ioctl(struct file *file, void *fh, return -EINVAL; if (copy_from_user(&ses_info, - (void *)k_ioctl->handle, + u64_to_user_ptr(k_ioctl->handle), k_ioctl->size)) { return -EFAULT; } @@ -256,15 +275,17 @@ static long cam_private_ioctl(struct file *file, void *fh, return -EINVAL; if (copy_from_user(&link_info, - (void *)k_ioctl->handle, + u64_to_user_ptr(k_ioctl->handle), k_ioctl->size)) { return -EFAULT; } rc = cam_req_mgr_link(&link_info); if (!rc) - if (copy_to_user((void *)k_ioctl->handle, - &link_info, k_ioctl->size)) + if (copy_to_user( + u64_to_user_ptr(k_ioctl->handle), + &link_info, + k_ioctl->size)) rc = -EFAULT; } break; @@ -276,7 +297,7 @@ static long cam_private_ioctl(struct file *file, void *fh, return -EINVAL; if (copy_from_user(&unlink_info, - (void *)k_ioctl->handle, + u64_to_user_ptr(k_ioctl->handle), k_ioctl->size)) { return -EFAULT; } @@ -292,7 +313,7 @@ static long cam_private_ioctl(struct file *file, void *fh, return -EINVAL; if (copy_from_user(&sched_req, - (void *)k_ioctl->handle, + u64_to_user_ptr(k_ioctl->handle), k_ioctl->size)) { return -EFAULT; } @@ -308,7 +329,7 @@ static long cam_private_ioctl(struct file *file, void *fh, return -EINVAL; if (copy_from_user(&flush_info, - (void *)k_ioctl->handle, + u64_to_user_ptr(k_ioctl->handle), k_ioctl->size)) { return -EFAULT; } @@ -324,7 +345,7 @@ static long cam_private_ioctl(struct file *file, void *fh, return -EINVAL; if (copy_from_user(&sync_info, - (void *)k_ioctl->handle, + u64_to_user_ptr(k_ioctl->handle), k_ioctl->size)) { return -EFAULT; } @@ -339,7 +360,7 @@ static long cam_private_ioctl(struct file *file, void *fh, return -EINVAL; if (copy_from_user(&cmd, - (void *)k_ioctl->handle, + u64_to_user_ptr(k_ioctl->handle), k_ioctl->size)) { rc = -EFAULT; break; @@ -347,7 +368,8 @@ static long cam_private_ioctl(struct file *file, void *fh, rc = cam_mem_mgr_alloc_and_map(&cmd); if (!rc) - if (copy_to_user((void *)k_ioctl->handle, + if (copy_to_user( + u64_to_user_ptr(k_ioctl->handle), &cmd, k_ioctl->size)) { rc = -EFAULT; break; @@ -361,7 +383,7 @@ static long cam_private_ioctl(struct file *file, void *fh, return -EINVAL; if (copy_from_user(&cmd, - (void *)k_ioctl->handle, + u64_to_user_ptr(k_ioctl->handle), k_ioctl->size)) { rc = -EFAULT; break; @@ -369,7 +391,8 @@ static long cam_private_ioctl(struct file *file, void *fh, rc = cam_mem_mgr_map(&cmd); if (!rc) - if (copy_to_user((void *)k_ioctl->handle, + if (copy_to_user( + u64_to_user_ptr(k_ioctl->handle), &cmd, k_ioctl->size)) { rc = -EFAULT; break; @@ -383,7 +406,7 @@ static long cam_private_ioctl(struct file *file, void *fh, return -EINVAL; if (copy_from_user(&cmd, - (void *)k_ioctl->handle, + u64_to_user_ptr(k_ioctl->handle), k_ioctl->size)) { rc = -EFAULT; break; @@ -399,7 +422,7 @@ static long cam_private_ioctl(struct file *file, void *fh, return -EINVAL; if (copy_from_user(&cmd, - (void *)k_ioctl->handle, + u64_to_user_ptr(k_ioctl->handle), k_ioctl->size)) { rc = -EFAULT; break; @@ -417,7 +440,7 @@ static long cam_private_ioctl(struct file *file, void *fh, return -EINVAL; if (copy_from_user(&cmd, - (void __user *)k_ioctl->handle, + u64_to_user_ptr(k_ioctl->handle), k_ioctl->size)) { rc = -EFAULT; break; @@ -584,13 +607,13 @@ EXPORT_SYMBOL(cam_unregister_subdev); static int cam_req_mgr_remove(struct platform_device *pdev) { cam_req_mgr_core_device_deinit(); - cam_mem_mgr_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; } @@ -623,12 +646,6 @@ static int cam_req_mgr_probe(struct platform_device *pdev) goto req_mgr_util_fail; } - rc = cam_mem_mgr_init(); - if (rc) { - CAM_ERR(CAM_CRM, "mem mgr init failed"); - goto mem_mgr_init_fail; - } - rc = cam_req_mgr_core_device_init(); if (rc) { CAM_ERR(CAM_CRM, "core device setup failed"); @@ -653,8 +670,6 @@ static int cam_req_mgr_probe(struct platform_device *pdev) return rc; req_mgr_core_fail: - cam_mem_mgr_deinit(); -mem_mgr_init_fail: cam_req_mgr_util_deinit(); req_mgr_util_fail: mutex_destroy(&g_dev.dev_lock); diff --git a/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_timer.c b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_timer.c index 124b336dd265..4d8a2ec32f9b 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_timer.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_timer.c @@ -13,6 +13,8 @@ #include "cam_req_mgr_timer.h" #include "cam_debug_util.h" +extern struct kmem_cache *g_cam_req_mgr_timer_cachep; + void crm_timer_reset(struct cam_req_mgr_timer *crm_timer) { if (!crm_timer) @@ -23,10 +25,10 @@ void crm_timer_reset(struct cam_req_mgr_timer *crm_timer) (jiffies + msecs_to_jiffies(crm_timer->expires))); } -void crm_timer_callback(unsigned long data) +void crm_timer_callback(struct timer_list *timer_data) { - struct cam_req_mgr_timer *timer = (struct cam_req_mgr_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; @@ -46,7 +48,7 @@ void crm_timer_modify(struct cam_req_mgr_timer *crm_timer, } int crm_timer_init(struct cam_req_mgr_timer **timer, - int32_t expires, void *parent, void (*timer_cb)(unsigned long)) + int32_t expires, void *parent, void (*timer_cb)(struct timer_list *)) { int ret = 0; struct cam_req_mgr_timer *crm_timer = NULL; @@ -54,9 +56,7 @@ int crm_timer_init(struct cam_req_mgr_timer **timer, CAM_DBG(CAM_CRM, "init timer %d %pK", expires, *timer); if (*timer == NULL) { if (g_cam_req_mgr_timer_cachep) { - crm_timer = (struct cam_req_mgr_timer *) - kmem_cache_alloc( - 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; @@ -76,8 +76,8 @@ int crm_timer_init(struct cam_req_mgr_timer **timer, crm_timer->expires = expires; crm_timer->parent = parent; - setup_timer(&crm_timer->sys_timer, - crm_timer->timer_cb, (unsigned long)crm_timer); + timer_setup(&crm_timer->sys_timer, + crm_timer->timer_cb, 0); crm_timer_reset(crm_timer); *timer = crm_timer; } else { @@ -97,4 +97,3 @@ void crm_timer_exit(struct cam_req_mgr_timer **crm_timer) *crm_timer = NULL; } } - diff --git a/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_timer.h b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_timer.h index b3e473a56daa..587e17f5e0b0 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_timer.h +++ b/drivers/media/platform/msm/camera_oneplus/cam_req_mgr/cam_req_mgr_timer.h @@ -19,16 +19,18 @@ #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 + * @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; + int32_t expires; + struct timer_list sys_timer; void *parent; - void (*timer_cb)(unsigned long data); + void (*timer_cb)(struct timer_list *timer_data); + bool pause_timer; }; /** @@ -58,7 +60,7 @@ void crm_timer_reset(struct cam_req_mgr_timer *timer); * will use default. */ int crm_timer_init(struct cam_req_mgr_timer **timer, - int32_t expires, void *parent, void (*timer_cb)(unsigned long)); + int32_t expires, void *parent, void (*timer_cb)(struct timer_list *)); /** * crm_timer_exit() @@ -67,5 +69,4 @@ int crm_timer_init(struct cam_req_mgr_timer **timer, */ void crm_timer_exit(struct cam_req_mgr_timer **timer); -extern struct kmem_cache *g_cam_req_mgr_timer_cachep; #endif diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_actuator/cam_actuator_core.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_actuator/cam_actuator_core.c index 89ce797c3e6f..fcd90fb288ad 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_actuator/cam_actuator_core.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_actuator/cam_actuator_core.c @@ -386,7 +386,8 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, size_t len_of_buff = 0; uint32_t *offset = NULL; uint32_t *cmd_buf = NULL; - uint64_t generic_ptr; + 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; @@ -409,13 +410,13 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, power_info = &soc_private->power_info; ioctl_ctrl = (struct cam_control *)arg; - - if (copy_from_user(&config, (void __user *) ioctl_ctrl->handle, + 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, - (uint64_t *)&generic_ptr, &len_of_buff); + &generic_pkt_ptr, &len_of_buff); if (rc < 0) { CAM_ERR(CAM_ACTUATOR, "Error in converting command Handle %d", rc); @@ -429,7 +430,8 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, return -EINVAL; } - csl_packet = (struct cam_packet *)(generic_ptr + config.offset); + csl_packet = (struct cam_packet *) + (generic_pkt_ptr + (uint32_t)config.offset); CAM_DBG(CAM_ACTUATOR, "Pkt opcode: %d", csl_packet->header.op_code); switch (csl_packet->header.op_code & 0xFFFFFF) { @@ -444,7 +446,7 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, if (!total_cmd_buf_in_bytes) continue; rc = cam_mem_get_cpu_buf(cmd_desc[i].mem_handle, - (uint64_t *)&generic_ptr, &len_of_buff); + &generic_ptr, &len_of_buff); if (rc < 0) { CAM_ERR(CAM_ACTUATOR, "Failed to get cpu buf"); return rc; @@ -658,7 +660,7 @@ int32_t cam_actuator_driver_cmd(struct cam_actuator_ctrl_t *a_ctrl, } rc = copy_from_user(&actuator_acq_dev, - (void __user *) cmd->handle, + u64_to_user_ptr(cmd->handle), sizeof(actuator_acq_dev)); if (rc < 0) { CAM_ERR(CAM_ACTUATOR, "Failed Copying from user\n"); @@ -679,7 +681,8 @@ int32_t cam_actuator_driver_cmd(struct cam_actuator_ctrl_t *a_ctrl, CAM_DBG(CAM_ACTUATOR, "Device Handle: %d", actuator_acq_dev.device_handle); - if (copy_to_user((void __user *) cmd->handle, &actuator_acq_dev, + 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; @@ -726,7 +729,8 @@ int32_t cam_actuator_driver_cmd(struct cam_actuator_ctrl_t *a_ctrl, struct cam_actuator_query_cap actuator_cap = {0}; actuator_cap.slot_info = a_ctrl->soc_info.index; - if (copy_to_user((void __user *) cmd->handle, &actuator_cap, + 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; diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_actuator/cam_actuator_dev.h b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_actuator/cam_actuator_dev.h index c4333a023607..3b54baddc630 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_actuator/cam_actuator_dev.h +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_actuator/cam_actuator_dev.h @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci/cam_cci_dev.h b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci/cam_cci_dev.h index 8730c6d8b963..12386fd3508f 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci/cam_cci_dev.h +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_cci/cam_cci_dev.h @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_csiphy/cam_csiphy_core.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_csiphy/cam_csiphy_core.c index 8b092b664f2c..04e52fd660af 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_csiphy/cam_csiphy_core.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_csiphy/cam_csiphy_core.c @@ -81,7 +81,8 @@ int32_t cam_cmd_buf_parser(struct csiphy_device *csiphy_dev, struct cam_config_dev_cmd *cfg_dev) { int32_t rc = 0; - uint64_t generic_ptr; + 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; @@ -94,7 +95,7 @@ int32_t cam_cmd_buf_parser(struct csiphy_device *csiphy_dev, } rc = cam_mem_get_cpu_buf((int32_t) cfg_dev->packet_handle, - (uint64_t *)&generic_ptr, &len); + &generic_pkt_ptr, &len); if (rc < 0) { CAM_ERR(CAM_CSIPHY, "Failed to get packet Mem address: %d", rc); return rc; @@ -107,14 +108,15 @@ int32_t cam_cmd_buf_parser(struct csiphy_device *csiphy_dev, return -EINVAL; } - csl_packet = (struct cam_packet *)(generic_ptr + cfg_dev->offset); + csl_packet = (struct cam_packet *) + (generic_pkt_ptr + (uint32_t)cfg_dev->offset); 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, - (uint64_t *)&generic_ptr, &len); + &generic_ptr, &len); if (rc < 0) { CAM_ERR(CAM_CSIPHY, "Failed to get cmd buf Mem address : %d", rc); @@ -411,7 +413,7 @@ static int32_t cam_csiphy_external_cmd(struct csiphy_device *csiphy_dev, int32_t rc = 0; if (copy_from_user(&cam_cmd_csiphy_info, - (void __user *)p_submit_cmd->packet_handle, + 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; @@ -470,7 +472,7 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, struct cam_create_dev_hdl bridge_params; rc = copy_from_user(&csiphy_acq_dev, - (void __user *)cmd->handle, + u64_to_user_ptr(cmd->handle), sizeof(csiphy_acq_dev)); if (rc < 0) { CAM_ERR(CAM_CSIPHY, "Failed copying from User"); @@ -480,7 +482,7 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, csiphy_acq_params.combo_mode = 0; if (copy_from_user(&csiphy_acq_params, - (void __user *)csiphy_acq_dev.info_handle, + u64_to_user_ptr(csiphy_acq_dev.info_handle), sizeof(csiphy_acq_params))) { CAM_ERR(CAM_CSIPHY, "Failed copying from User"); @@ -537,7 +539,7 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, session_hdl[csiphy_acq_params.combo_mode] = csiphy_acq_dev.session_handle; - if (copy_to_user((void __user *)cmd->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"); @@ -555,7 +557,7 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, struct cam_csiphy_query_cap csiphy_cap = {0}; cam_csiphy_query_cap(csiphy_dev, &csiphy_cap); - if (copy_to_user((void __user *)cmd->handle, + 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; @@ -605,7 +607,8 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, goto release_mutex; } - if (copy_from_user(&release, (void __user *) cmd->handle, + if (copy_from_user(&release, + u64_to_user_ptr(cmd->handle), sizeof(release))) { rc = -EFAULT; goto release_mutex; @@ -636,7 +639,8 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, case CAM_CONFIG_DEV: { struct cam_config_dev_cmd config; - if (copy_from_user(&config, (void __user *)cmd->handle, + if (copy_from_user(&config, + u64_to_user_ptr(cmd->handle), sizeof(config))) { rc = -EFAULT; } else { @@ -702,7 +706,7 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, struct cam_config_dev_cmd submit_cmd; if (copy_from_user(&submit_cmd, - (void __user *)cmd->handle, + u64_to_user_ptr(cmd->handle), sizeof(struct cam_config_dev_cmd))) { CAM_ERR(CAM_CSIPHY, "failed copy config ext\n"); rc = -EFAULT; diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h index afe4239b2d71..04a3243d1fcd 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_csiphy/cam_csiphy_dev.h @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_eeprom/cam_eeprom_core.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_eeprom/cam_eeprom_core.c index 8b3c7024bcbb..bcde06d80306 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_eeprom/cam_eeprom_core.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_eeprom/cam_eeprom_core.c @@ -372,8 +372,8 @@ int32_t cam_eeprom_parse_read_memory_map(struct device_node *of_node, power_down: cam_eeprom_power_down(e_ctrl); data_mem_free: - kvfree(e_ctrl->cal_data.mapdata); - kfree(e_ctrl->cal_data.map); + 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; @@ -398,8 +398,8 @@ static int32_t cam_eeprom_get_dev_handle(struct cam_eeprom_ctrl_t *e_ctrl, CAM_ERR(CAM_EEPROM, "Device is already acquired"); return -EFAULT; } - - if (copy_from_user(&eeprom_acq_dev, (void __user *) cmd->handle, + 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"); @@ -418,8 +418,8 @@ static int32_t cam_eeprom_get_dev_handle(struct cam_eeprom_ctrl_t *e_ctrl, 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((void __user *) cmd->handle, &eeprom_acq_dev, - sizeof(struct cam_sensor_acquire_dev))) { + 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; } @@ -588,7 +588,7 @@ static int32_t cam_eeprom_init_pkt_parser(struct cam_eeprom_ctrl_t *e_ctrl, struct cam_cmd_buf_desc *cmd_desc = NULL; uint32_t *offset = NULL; uint32_t *cmd_buf = NULL; - uint64_t generic_pkt_addr; + uintptr_t generic_pkt_addr; size_t pkt_len = 0; uint32_t total_cmd_buf_in_bytes = 0; uint32_t processed_cmd_buf_in_bytes = 0; @@ -601,9 +601,9 @@ static int32_t cam_eeprom_init_pkt_parser(struct cam_eeprom_ctrl_t *e_ctrl, (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 = kcalloc((MSM_EEPROM_MEMORY_MAP_MAX_SIZE * - MSM_EEPROM_MAX_MEM_MAP_CNT), - (sizeof(struct cam_eeprom_memory_map_t)), GFP_KERNEL); + 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"); @@ -622,7 +622,7 @@ static int32_t cam_eeprom_init_pkt_parser(struct cam_eeprom_ctrl_t *e_ctrl, if (!total_cmd_buf_in_bytes) continue; rc = cam_mem_get_cpu_buf(cmd_desc[i].mem_handle, - (uint64_t *)&generic_pkt_addr, &pkt_len); + &generic_pkt_addr, &pkt_len); if (rc) { CAM_ERR(CAM_EEPROM, "Failed to get cpu buf"); return rc; @@ -699,7 +699,7 @@ static int32_t cam_eeprom_get_cal_data(struct cam_eeprom_ctrl_t *e_ctrl, struct cam_buf_io_cfg *io_cfg; uint32_t i = 0; int rc = 0; - uint64_t buf_addr; + uintptr_t buf_addr; size_t buf_size; uint8_t *read_buffer; @@ -714,7 +714,7 @@ static int32_t cam_eeprom_get_cal_data(struct cam_eeprom_ctrl_t *e_ctrl, 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], - (uint64_t *)&buf_addr, &buf_size); + &buf_addr, &buf_size); CAM_DBG(CAM_EEPROM, "buf_addr : %pK, buf_size : %zu\n", (void *)buf_addr, buf_size); @@ -757,7 +757,7 @@ 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; - uint64_t generic_pkt_addr; + uintptr_t generic_pkt_addr; size_t pkt_len; struct cam_packet *csl_packet = NULL; struct cam_eeprom_soc_private *soc_private = @@ -766,11 +766,12 @@ static int32_t cam_eeprom_pkt_parse(struct cam_eeprom_ctrl_t *e_ctrl, void *arg) ioctl_ctrl = (struct cam_control *)arg; - if (copy_from_user(&dev_config, (void __user *) ioctl_ctrl->handle, + 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, - (uint64_t *)&generic_pkt_addr, &pkt_len); + &generic_pkt_addr, &pkt_len); if (rc) { CAM_ERR(CAM_EEPROM, "error in converting command Handle Error: %d", rc); @@ -796,8 +797,8 @@ static int32_t cam_eeprom_pkt_parse(struct cam_eeprom_ctrl_t *e_ctrl, void *arg) return rc; } rc = cam_eeprom_get_cal_data(e_ctrl, csl_packet); - kvfree(e_ctrl->cal_data.mapdata); - kfree(e_ctrl->cal_data.map); + 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, @@ -847,8 +848,8 @@ static int32_t cam_eeprom_pkt_parse(struct cam_eeprom_ctrl_t *e_ctrl, void *arg) 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; - kvfree(e_ctrl->cal_data.mapdata); - kfree(e_ctrl->cal_data.map); + 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; break; @@ -859,11 +860,11 @@ static int32_t cam_eeprom_pkt_parse(struct cam_eeprom_ctrl_t *e_ctrl, void *arg) power_down: cam_eeprom_power_down(e_ctrl); memdata_free: - kvfree(e_ctrl->cal_data.mapdata); + vfree(e_ctrl->cal_data.mapdata); error: kfree(power_info->power_setting); kfree(power_info->power_down_setting); - kfree(e_ctrl->cal_data.map); + 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_INIT; @@ -935,7 +936,7 @@ int32_t cam_eeprom_driver_cmd(struct cam_eeprom_ctrl_t *e_ctrl, void *arg) else eeprom_cap.eeprom_kernel_probe = false; - if (copy_to_user((void __user *) cmd->handle, + 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"); diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_eeprom/cam_eeprom_soc.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_eeprom/cam_eeprom_soc.c index 3280899bb3e2..d93a7ae41304 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_eeprom/cam_eeprom_soc.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_eeprom/cam_eeprom_soc.c @@ -135,7 +135,7 @@ int cam_eeprom_parse_dt_memory_map(struct device_node *node, return rc; } - map = kzalloc((sizeof(*map) * data->num_map), GFP_KERNEL); + map = vzalloc((sizeof(*map) * data->num_map)); if (!map) { rc = -ENOMEM; return rc; @@ -184,23 +184,15 @@ int cam_eeprom_parse_dt_memory_map(struct device_node *node, data->num_data += map[i].mem.valid_size; } - if (data->num_data < PAGE_SIZE) { - data->mapdata = kzalloc(data->num_data, GFP_KERNEL); - if (!data->mapdata) { - rc = -ENOMEM; - goto ERROR; - } - } else { - data->mapdata = vzalloc(data->num_data); - if (!data->mapdata) { - rc = -ENOMEM; - goto ERROR; - } + data->mapdata = vzalloc(data->num_data); + if (!data->mapdata) { + rc = -ENOMEM; + goto ERROR; } return rc; ERROR: - kfree(data->map); + vfree(data->map); memset(data, 0, sizeof(*data)); return rc; } diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_flash/cam_flash_core.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_flash/cam_flash_core.c index 00e44b8d9b27..be6f6ff78284 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_flash/cam_flash_core.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_flash/cam_flash_core.c @@ -538,7 +538,7 @@ int cam_flash_apply_setting(struct cam_flash_ctrl *fctrl, int cam_flash_parser(struct cam_flash_ctrl *fctrl, void *arg) { int rc = 0, i = 0; - uint64_t generic_ptr; + uintptr_t generic_ptr; uint32_t *cmd_buf = NULL; uint32_t *offset = NULL; uint32_t frame_offset = 0; @@ -561,7 +561,8 @@ int cam_flash_parser(struct cam_flash_ctrl *fctrl, void *arg) /* getting CSL Packet */ ioctl_ctrl = (struct cam_control *)arg; - if (copy_from_user((&config), (void __user *) ioctl_ctrl->handle, + 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; @@ -569,7 +570,7 @@ int cam_flash_parser(struct cam_flash_ctrl *fctrl, void *arg) } rc = cam_mem_get_cpu_buf(config.packet_handle, - (uint64_t *)&generic_ptr, &len_of_buffer); + &generic_ptr, &len_of_buffer); if (rc) { CAM_ERR(CAM_FLASH, "Failed in getting the buffer : %d", rc); return rc; @@ -594,8 +595,8 @@ int cam_flash_parser(struct cam_flash_ctrl *fctrl, void *arg) fctrl->flash_init_setting.cmn_attr.is_settings_valid = true; cmd_desc = (struct cam_cmd_buf_desc *)(offset); rc = cam_mem_get_cpu_buf(cmd_desc->mem_handle, - (uint64_t *)&generic_ptr, &len_of_buffer); - cmd_buf = (uint32_t *)((uint8_t *)generic_ptr + + &generic_ptr, &len_of_buffer); + cmd_buf = (uint32_t *)(generic_ptr + cmd_desc->offset); cam_flash_info = (struct cam_flash_init *)cmd_buf; @@ -665,8 +666,8 @@ int cam_flash_parser(struct cam_flash_ctrl *fctrl, void *arg) true; cmd_desc = (struct cam_cmd_buf_desc *)(offset); rc = cam_mem_get_cpu_buf(cmd_desc->mem_handle, - (uint64_t *)&generic_ptr, &len_of_buffer); - cmd_buf = (uint32_t *)((uint8_t *)generic_ptr + + &generic_ptr, &len_of_buffer); + cmd_buf = (uint32_t *)(generic_ptr + cmd_desc->offset); if (!cmd_buf) @@ -721,8 +722,8 @@ int cam_flash_parser(struct cam_flash_ctrl *fctrl, void *arg) 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, - (uint64_t *)&generic_ptr, &len_of_buffer); - cmd_buf = (uint32_t *)((uint8_t *)generic_ptr + + &generic_ptr, &len_of_buffer); + cmd_buf = (uint32_t *)(generic_ptr + cmd_desc->offset); cmn_hdr = (struct common_header *)cmd_buf; diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_flash/cam_flash_dev.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_flash/cam_flash_dev.c index c69c70b8440a..5d33054d7af6 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_flash/cam_flash_dev.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_flash/cam_flash_dev.c @@ -58,7 +58,8 @@ static int32_t cam_flash_driver_cmd(struct cam_flash_ctrl *fctrl, goto release_mutex; } - rc = copy_from_user(&flash_acq_dev, (void __user *)cmd->handle, + 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"); @@ -78,7 +79,8 @@ static int32_t cam_flash_driver_cmd(struct cam_flash_ctrl *fctrl, fctrl->bridge_intf.session_hdl = flash_acq_dev.session_handle; - rc = copy_to_user((void __user *) cmd->handle, &flash_acq_dev, + 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", @@ -131,8 +133,8 @@ static int32_t cam_flash_driver_cmd(struct cam_flash_ctrl *fctrl, flash_cap.max_current_torch[i] = soc_private->torch_max_current[i]; - if (copy_to_user((void __user *) cmd->handle, &flash_cap, - sizeof(struct cam_flash_query_cap_info))) { + 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; diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ois/cam_ois_core.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ois/cam_ois_core.c index 0c1730aa61b3..1f7b080a3591 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ois/cam_ois_core.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ois/cam_ois_core.c @@ -12,6 +12,7 @@ #include #include +#include #include #include "cam_ois_core.h" #include "cam_ois_soc.h" @@ -77,8 +78,7 @@ static int cam_ois_get_dev_handle(struct cam_ois_ctrl_t *o_ctrl, CAM_ERR(CAM_OIS, "Device is already acquired"); return -EFAULT; } - - if (copy_from_user(&ois_acq_dev, (void __user *) cmd->handle, + if (copy_from_user(&ois_acq_dev, u64_to_user_ptr(cmd->handle), sizeof(ois_acq_dev))) return -EFAULT; @@ -94,7 +94,7 @@ static int cam_ois_get_dev_handle(struct cam_ois_ctrl_t *o_ctrl, 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((void __user *) cmd->handle, &ois_acq_dev, + 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; @@ -338,7 +338,7 @@ static int cam_ois_fw_download(struct cam_ois_ctrl_t *o_ctrl) 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); + fw_size, 0, GFP_KERNEL); if (!page) { CAM_ERR(CAM_OIS, "Failed in allocating i2c_array"); release_firmware(fw); @@ -383,7 +383,7 @@ static int cam_ois_fw_download(struct cam_ois_ctrl_t *o_ctrl) 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); + fw_size, 0, GFP_KERNEL); if (!page) { CAM_ERR(CAM_OIS, "Failed in allocating i2c_array"); release_firmware(fw); @@ -428,12 +428,12 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) int32_t i = 0; uint32_t total_cmd_buf_in_bytes = 0; struct common_header *cmm_hdr = NULL; - uint64_t generic_ptr; + 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; - uint64_t generic_pkt_addr; + uintptr_t generic_pkt_addr; size_t pkt_len; struct cam_packet *csl_packet = NULL; size_t len_of_buff = 0; @@ -447,12 +447,13 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) uint32_t red_reg_data = 0; ioctl_ctrl = (struct cam_control *)arg; - if (copy_from_user(&dev_config, (void __user *) ioctl_ctrl->handle, + 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, - (uint64_t *)&generic_pkt_addr, &pkt_len); + &generic_pkt_addr, &pkt_len); if (rc) { CAM_ERR(CAM_OIS, "error in converting command Handle Error: %d", rc); @@ -467,7 +468,8 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) } csl_packet = (struct cam_packet *) - (generic_pkt_addr + dev_config.offset); + (generic_pkt_addr + (uint32_t)dev_config.offset); + switch (csl_packet->header.op_code & 0xFFFFFF) { case CAM_OIS_PACKET_OPCODE_INIT: offset = (uint32_t *)&csl_packet->payload; @@ -481,7 +483,7 @@ static int cam_ois_pkt_parse(struct cam_ois_ctrl_t *o_ctrl, void *arg) continue; rc = cam_mem_get_cpu_buf(cmd_desc[i].mem_handle, - (uint64_t *)&generic_ptr, &len_of_buff); + &generic_ptr, &len_of_buff); if (rc < 0) { CAM_ERR(CAM_OIS, "Failed to get cpu buf"); return rc; @@ -803,7 +805,7 @@ int cam_ois_driver_cmd(struct cam_ois_ctrl_t *o_ctrl, void *arg) case CAM_QUERY_CAP: ois_cap.slot_info = o_ctrl->soc_info.index; - if (copy_to_user((void __user *) cmd->handle, + 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"); diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ois/cam_ois_core.h b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ois/cam_ois_core.h index 908f9d27963b..3f961a8a0042 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ois/cam_ois_core.h +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_ois/cam_ois_core.h @@ -13,7 +13,6 @@ #define _CAM_OIS_CORE_H_ #include -#include #include "cam_ois_dev.h" /** diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/cam_sensor_core.c index ee3039910343..e7747d873c76 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/cam_sensor_core.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/cam_sensor_core.c @@ -228,7 +228,7 @@ static int32_t cam_sensor_i2c_pkt_parse(struct cam_sensor_ctrl_t *s_ctrl, void *arg) { int32_t rc = 0; - uint64_t generic_ptr; + uintptr_t generic_ptr; struct cam_control *ioctl_ctrl = NULL; struct cam_packet *csl_packet = NULL; struct cam_cmd_buf_desc *cmd_desc = NULL; @@ -245,13 +245,14 @@ static int32_t cam_sensor_i2c_pkt_parse(struct cam_sensor_ctrl_t *s_ctrl, return -EINVAL; } - if (copy_from_user(&config, (void __user *) ioctl_ctrl->handle, + 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, - (uint64_t *)&generic_ptr, + &generic_ptr, &len_of_buff); if (rc < 0) { CAM_ERR(CAM_SENSOR, "Failed in getting the buffer: %d", rc); @@ -259,7 +260,8 @@ static int32_t cam_sensor_i2c_pkt_parse(struct cam_sensor_ctrl_t *s_ctrl, } csl_packet = (struct cam_packet *)(generic_ptr + - config.offset); + (uint32_t)config.offset); + if (config.offset > len_of_buff) { CAM_ERR(CAM_SENSOR, "offset is out of bounds: off: %lld len: %zu", @@ -563,15 +565,16 @@ int32_t cam_handle_cmd_buffers_for_probe(void *cmd_buf, int32_t cam_handle_mem_ptr(uint64_t handle, struct cam_sensor_ctrl_t *s_ctrl) { int rc = 0, i; - void *packet = NULL, *cmd_buf1 = NULL; uint32_t *cmd_buf; void *ptr; size_t len; - struct cam_packet *pkt; - struct cam_cmd_buf_desc *cmd_desc; + struct cam_packet *pkt = NULL; + struct cam_cmd_buf_desc *cmd_desc = NULL; + uintptr_t cmd_buf1 = 0; + uintptr_t packet = 0; rc = cam_mem_get_cpu_buf(handle, - (uint64_t *)&packet, &len); + &packet, &len); if (rc < 0) { CAM_ERR(CAM_SENSOR, "Failed to get the command Buffer"); return -EINVAL; @@ -592,7 +595,7 @@ int32_t cam_handle_mem_ptr(uint64_t handle, struct cam_sensor_ctrl_t *s_ctrl) if (!(cmd_desc[i].length)) continue; rc = cam_mem_get_cpu_buf(cmd_desc[i].mem_handle, - (uint64_t *)&cmd_buf1, &len); + &cmd_buf1, &len); if (rc < 0) { CAM_ERR(CAM_SENSOR, "Failed to parse the command Buffer Header"); @@ -941,7 +944,8 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, } rc = copy_from_user(&sensor_acq_dev, - (void __user *) cmd->handle, sizeof(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; @@ -960,7 +964,8 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, CAM_DBG(CAM_SENSOR, "Device Handle: %d", sensor_acq_dev.device_handle); - if (copy_to_user((void __user *) cmd->handle, &sensor_acq_dev, + 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; @@ -1025,8 +1030,8 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, struct cam_sensor_query_cap sensor_cap; cam_sensor_query_cap(s_ctrl, &sensor_cap); - if (copy_to_user((void __user *) cmd->handle, &sensor_cap, - sizeof(struct cam_sensor_query_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; @@ -1136,7 +1141,7 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, CAM_ERR(CAM_SENSOR, "fuse_id is empty"); rc = -EFAULT; goto release_mutex; - } else if (copy_to_user((void __user *) cmd->handle, &fuse_id, + } else if (copy_to_user(u64_to_user_ptr(cmd->handle), &fuse_id, sizeof(fuse_id))) { CAM_ERR(CAM_SENSOR, "Failed Copy to User"); rc = -EFAULT; diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/cam_sensor_dev.h b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/cam_sensor_dev.h index cc6070cdc1b6..37b08d918936 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/cam_sensor_dev.h +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/cam_sensor_dev.h @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io/cam_sensor_qup_i2c.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io/cam_sensor_qup_i2c.c index 1c6ab0b1d94b..05e3b7a5cdf5 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io/cam_sensor_qup_i2c.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io/cam_sensor_qup_i2c.c @@ -245,9 +245,15 @@ static int32_t cam_qup_i2c_write(struct camera_io_master *client, enum camera_sensor_i2c_type data_type) { int32_t rc = 0; - unsigned char buf[I2C_REG_MAX_BUF_SIZE]; + 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) { @@ -273,7 +279,8 @@ static int32_t cam_qup_i2c_write(struct camera_io_master *client, len = 4; } else { CAM_ERR(CAM_SENSOR, "Invalid I2C addr type"); - return -EINVAL; + rc = -EINVAL; + goto deallocate_buffer; } CAM_DBG(CAM_SENSOR, "Data: 0x%x", reg_setting->reg_data); @@ -307,12 +314,16 @@ static int32_t cam_qup_i2c_write(struct camera_io_master *client, len += 4; } else { CAM_ERR(CAM_SENSOR, "Invalid Data Type"); - return -EINVAL; + 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; } diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io/cam_sensor_spi.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io/cam_sensor_spi.c index 626b2630a3e5..6cc96391abdd 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io/cam_sensor_spi.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io/cam_sensor_spi.c @@ -10,6 +10,7 @@ * GNU General Public License for more details. */ +#include #include "cam_sensor_spi.h" #include "cam_debug_util.h" @@ -133,7 +134,7 @@ static int32_t cam_spi_tx_helper(struct camera_io_master *client, } else { txr = PAGE_ALIGN(len) >> PAGE_SHIFT; page_tx = cma_alloc(dev_get_cma_area(dev), - txr, 0); + txr, 0, GFP_KERNEL); if (!page_tx) return -ENOMEM; @@ -146,7 +147,7 @@ static int32_t cam_spi_tx_helper(struct camera_io_master *client, } else { rxr = PAGE_ALIGN(len) >> PAGE_SHIFT; page_rx = cma_alloc(dev_get_cma_area(dev), - rxr, 0); + rxr, 0, GFP_KERNEL); if (!page_rx) { if (!tx) cma_release(dev_get_cma_area(dev), diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io/cam_sensor_spi.h b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io/cam_sensor_spi.h index 8ce45d8e9a4e..86f775c51791 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io/cam_sensor_spi.h +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io/cam_sensor_spi.h @@ -15,7 +15,6 @@ #include #include -#include #include #include "cam_sensor_i2c.h" diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c index 3179b74d364d..9b8af7056d20 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c @@ -289,7 +289,7 @@ int cam_sensor_i2c_command_parser(struct i2c_settings_array *i2c_reg_settings, { int16_t rc = 0, i = 0; size_t len_of_buff = 0; - uint64_t generic_ptr; + uintptr_t generic_ptr; for (i = 0; i < num_cmd_buffers; i++) { uint32_t *cmd_buf = NULL; @@ -311,7 +311,7 @@ int cam_sensor_i2c_command_parser(struct i2c_settings_array *i2c_reg_settings, continue; rc = cam_mem_get_cpu_buf(cmd_desc[i].mem_handle, - (uint64_t *)&generic_ptr, &len_of_buff); + &generic_ptr, &len_of_buff); cmd_buf = (uint32_t *)generic_ptr; if (rc < 0) { CAM_ERR(CAM_SENSOR, diff --git a/drivers/media/platform/msm/camera_oneplus/cam_smmu/Makefile b/drivers/media/platform/msm/camera_oneplus/cam_smmu/Makefile index cc0d20d44e1f..45b06c420f3b 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_smmu/Makefile +++ b/drivers/media/platform/msm/camera_oneplus/cam_smmu/Makefile @@ -1,3 +1,5 @@ +ccflags-y += -I$(srctree)/techpack/camera/include/uapi ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_utils +ccflags-y += -Idrivers/media/platform/msm/camera_oneplus/cam_req_mgr obj-$(CONFIG_SPECTRA_CAMERA) += cam_smmu_api.o diff --git a/drivers/media/platform/msm/camera_oneplus/cam_smmu/cam_smmu_api.c b/drivers/media/platform/msm/camera_oneplus/cam_smmu/cam_smmu_api.c index 6b1f6e85400e..e2883c8f79ea 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_smmu/cam_smmu_api.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_smmu/cam_smmu_api.c @@ -12,7 +12,6 @@ #include #include -#include #include #include #include @@ -21,8 +20,12 @@ #include #include #include +#include +#include + #include #include +#include #include "cam_smmu_api.h" #include "cam_debug_util.h" @@ -39,6 +42,9 @@ #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; @@ -96,7 +102,7 @@ struct secheap_buf_info { struct cam_context_bank_info { struct device *dev; - struct dma_iommu_mapping *mapping; + struct iommu_domain *domain; dma_addr_t va_start; size_t va_len; const char *name; @@ -129,12 +135,18 @@ struct cam_context_bank_info { int handle; enum cam_smmu_ops_param state; - void (*handler[CAM_SMMU_CB_MAX])(struct iommu_domain *, - struct device *, unsigned long, - int, void*); + 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 { @@ -145,7 +157,8 @@ struct cam_iommu_cb_set { struct mutex payload_list_lock; struct list_head payload_list; u32 non_fatal_fault; - u32 enable_iova_guard; + struct dentry *dentry; + bool cb_dump_enable; }; static const struct of_device_id msm_cam_smmu_dt_match[] = { @@ -171,8 +184,7 @@ struct cam_dma_buff_info { }; struct cam_sec_buff_info { - struct ion_handle *i_hdl; - struct ion_client *i_client; + struct dma_buf *buf; enum dma_data_direction dir; int ref_count; dma_addr_t paddr; @@ -219,8 +231,9 @@ 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, - 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, 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, @@ -244,6 +257,8 @@ 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); @@ -252,13 +267,14 @@ static void cam_smmu_print_table(void); static int cam_smmu_probe(struct platform_device *pdev); -static void cam_smmu_check_vaddr_in_range(int idx, void *vaddr); +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)) { @@ -275,8 +291,10 @@ static void cam_smmu_page_fault_work(struct work_struct *work) /* Dereference the payload to call the handler */ idx = payload->idx; - mutex_lock(&iommu_cb_set.cb_info[idx].lock); - cam_smmu_check_vaddr_in_range(idx, (void *)payload->iova); + 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]( @@ -284,13 +302,58 @@ static void cam_smmu_page_fault_work(struct work_struct *work) payload->dev, payload->iova, payload->flags, - iommu_cb_set.cb_info[idx].token[j]); + iommu_cb_set.cb_info[idx].token[j], + buf_info); } } - mutex_unlock(&iommu_cb_set.cb_info[idx].lock); + 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; @@ -333,10 +396,13 @@ static void cam_smmu_print_table(void) } } -static void cam_smmu_check_vaddr_in_range(int idx, void *vaddr) +static uint32_t cam_smmu_find_closest_mapping(int idx, void *vaddr) { - struct cam_dma_buff_info *mapping; + 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, @@ -344,31 +410,52 @@ static void cam_smmu_check_vaddr_in_range(int idx, void *vaddr) start_addr = (unsigned long)mapping->paddr; end_addr = (unsigned long)mapping->paddr + mapping->len; - if (start_addr <= current_addr && current_addr < end_addr) { - CAM_ERR(CAM_SMMU, - "va %pK valid: range:%pK-%pK, fd = %d cb: %s", - vaddr, (void *)start_addr, (void *)end_addr, - mapping->ion_fd, + 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, - "va %pK is not in this range: %pK-%pK, fd = %d", - vaddr, (void *)start_addr, (void *)end_addr, - mapping->ion_fd); + "approx va %lx not in range: %lx-%lx fd = %0x", + current_addr, start_addr, + end_addr, mapping->ion_fd); } } - CAM_ERR(CAM_SMMU, - "Cannot find vaddr:%pK in SMMU %s uses invalid virt address", - vaddr, iommu_cb_set.cb_info[idx].name); -end: - return; -} -void cam_smmu_reg_client_page_fault_handler(int handle, - void (*client_page_fault_handler)(struct iommu_domain *, - struct device *, unsigned long, - int, void*), void *token) +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; @@ -394,7 +481,7 @@ void cam_smmu_reg_client_page_fault_handler(int handle, return; } - if (client_page_fault_handler) { + 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", @@ -402,12 +489,14 @@ void cam_smmu_reg_client_page_fault_handler(int handle, 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] = - client_page_fault_handler; + handler_cb; break; } } @@ -429,6 +518,47 @@ void cam_smmu_reg_client_page_fault_handler(int handle, 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) @@ -459,6 +589,13 @@ static int cam_smmu_iommu_fault_handler(struct iommu_domain *domain, 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; @@ -474,7 +611,7 @@ static int cam_smmu_iommu_fault_handler(struct iommu_domain *domain, list_add_tail(&payload->list, &iommu_cb_set.payload_list); mutex_unlock(&iommu_cb_set.payload_list_lock); - schedule_work(&iommu_cb_set.smmu_work); + cam_smmu_page_fault_work(&iommu_cb_set.smmu_work); return -EINVAL; } @@ -528,6 +665,7 @@ void cam_smmu_reset_iommu_table(enum cam_smmu_init_dir ops) 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; @@ -581,7 +719,7 @@ static int cam_smmu_attach_device(int idx) struct cam_context_bank_info *cb = &iommu_cb_set.cb_info[idx]; /* attach the mapping to device */ - rc = arm_iommu_attach_device(cb->dev, cb->mapping); + rc = iommu_attach_device(cb->domain, cb->dev); if (rc < 0) { CAM_ERR(CAM_SMMU, "Error: ARM IOMMU attach failed. ret = %d", rc); @@ -602,11 +740,6 @@ static int cam_smmu_create_add_handle_in_table(char *name, 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) { - CAM_ERR(CAM_SMMU, - "Error: %s already got handle 0x%x", - name, - iommu_cb_set.cb_info[i].handle); - if (iommu_cb_set.cb_info[i].is_secure) iommu_cb_set.cb_info[i].secure_count++; @@ -615,6 +748,11 @@ static int cam_smmu_create_add_handle_in_table(char *name, *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; } @@ -918,7 +1056,7 @@ static int cam_smmu_detach_device(int idx) 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) { - arm_iommu_detach_device(cb->dev); + iommu_detach_device(cb->domain, cb->dev); iommu_cb_set.cb_info[idx].state = CAM_SMMU_DETACH; } @@ -1009,7 +1147,7 @@ static int cam_smmu_free_iova(uint32_t addr, size_t size, int cam_smmu_alloc_firmware(int32_t smmu_hdl, dma_addr_t *iova, - uint64_t *cpuva, + uintptr_t *cpuva, size_t *len) { int rc; @@ -1063,7 +1201,7 @@ int cam_smmu_alloc_firmware(int32_t smmu_hdl, icp_fw.fw_kva, (void *)icp_fw.fw_dma_hdl); } - domain = iommu_cb_set.cb_info[idx].mapping->domain; + domain = iommu_cb_set.cb_info[idx].domain; rc = iommu_map(domain, firmware_start, icp_fw.fw_dma_hdl, @@ -1078,7 +1216,7 @@ int cam_smmu_alloc_firmware(int32_t smmu_hdl, iommu_cb_set.cb_info[idx].is_fw_allocated = true; *iova = iommu_cb_set.cb_info[idx].firmware_info.iova_start; - *cpuva = (uint64_t)icp_fw.fw_kva; + *cpuva = (uintptr_t)icp_fw.fw_kva; *len = firmware_len; mutex_unlock(&iommu_cb_set.cb_info[idx].lock); @@ -1136,7 +1274,7 @@ int cam_smmu_dealloc_firmware(int32_t smmu_hdl) 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].mapping->domain; + domain = iommu_cb_set.cb_info[idx].domain; unmapped = iommu_unmap(domain, firmware_start, firmware_len); @@ -1209,7 +1347,7 @@ int cam_smmu_alloc_qdss(int32_t smmu_hdl, 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].mapping->domain; + domain = iommu_cb_set.cb_info[idx].domain; rc = iommu_map(domain, qdss_start, qdss_phy_addr, @@ -1276,7 +1414,7 @@ int cam_smmu_dealloc_qdss(int32_t smmu_hdl) 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].mapping->domain; + domain = iommu_cb_set.cb_info[idx].domain; unmapped = iommu_unmap(domain, qdss_start, qdss_len); if (unmapped != qdss_len) { @@ -1295,6 +1433,49 @@ int cam_smmu_dealloc_qdss(int32_t smmu_hdl) } 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) @@ -1446,7 +1627,7 @@ int cam_smmu_reserve_sec_heap(int32_t smmu_hdl, 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].mapping->domain, + size = iommu_map_sg(iommu_cb_set.cb_info[idx].domain, sec_heap_iova, secheap_buf->table->sgl, secheap_buf->table->nents, @@ -1510,7 +1691,7 @@ int cam_smmu_release_sec_heap(int32_t smmu_hdl) 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].mapping->domain, + size = iommu_unmap(iommu_cb_set.cb_info[idx].domain, sec_heap_iova, sec_heap_iova_len); if (size != sec_heap_iova_len) { @@ -1533,7 +1714,7 @@ 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, - struct cam_dma_buff_info **mapping_info) + bool dis_delayed_unmap, struct cam_dma_buff_info **mapping_info) { struct dma_buf_attachment *attach = NULL; struct sg_table *table = NULL; @@ -1562,15 +1743,15 @@ static int cam_smmu_map_buffer_validate(struct dma_buf *buf, goto err_put; } - table = dma_buf_map_attachment(attach, dma_dir); - if (IS_ERR_OR_NULL(table)) { - rc = PTR_ERR(table); - CAM_ERR(CAM_SMMU, "Error: dma buf map attachment failed"); - goto err_detach; - } - if (region_id == CAM_SMMU_REGION_SHARED) { - domain = iommu_cb_set.cb_info[idx].mapping->domain; + 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; @@ -1582,7 +1763,9 @@ static int cam_smmu_map_buffer_validate(struct dma_buf *buf, if (rc < 0) { CAM_ERR(CAM_SMMU, - "IOVA alloc failed for shared memory"); + "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; } @@ -1598,28 +1781,37 @@ static int cam_smmu_map_buffer_validate(struct dma_buf *buf, rc = -ENOMEM; goto err_unmap_sg; } else { - CAM_DBG(CAM_SMMU, "iommu_map_sg returned %zu", size); + 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) { - rc = msm_dma_map_sg_lazy(iommu_cb_set.cb_info[idx].dev, - table->sgl, table->nents, dma_dir, buf); - - if (rc != table->nents) { - CAM_ERR(CAM_SMMU, "Error: msm_dma_map_sg_lazy failed"); - rc = -ENOMEM; - goto err_unmap_sg; - } else { - *paddr_ptr = sg_dma_address(table->sgl); - *len_ptr = (size_t)sg_dma_len(table->sgl); + 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", @@ -1654,11 +1846,12 @@ static int cam_smmu_map_buffer_validate(struct dma_buf *buf, 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, "dma_buf = %pK, dev = %pK, paddr= %pK, len = %u", - buf, (void *)iommu_cb_set.cb_info[idx].dev, + 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; @@ -1669,15 +1862,9 @@ static int cam_smmu_map_buffer_validate(struct dma_buf *buf, size, iommu_cb_set.cb_info[idx].handle); - iommu_unmap(iommu_cb_set.cb_info[idx].mapping->domain, + iommu_unmap(iommu_cb_set.cb_info[idx].domain, *paddr_ptr, *len_ptr); - } else if (region_id == CAM_SMMU_REGION_IO) { - msm_dma_unmap_sg(iommu_cb_set.cb_info[idx].dev, - table->sgl, - table->nents, - dma_dir, - buf); } err_unmap_sg: dma_buf_unmap_attachment(attach, table, dma_dir); @@ -1691,8 +1878,9 @@ static int cam_smmu_map_buffer_validate(struct dma_buf *buf, static int cam_smmu_map_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, enum cam_smmu_region_id region_id) + 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; @@ -1702,7 +1890,7 @@ static int cam_smmu_map_buffer_and_add_to_list(int idx, int ion_fd, buf = dma_buf_get(ion_fd); rc = cam_smmu_map_buffer_validate(buf, idx, dma_dir, paddr_ptr, len_ptr, - region_id, &mapping_info); + region_id, dis_delayed_unmap, &mapping_info); if (rc) { CAM_ERR(CAM_SMMU, "buffer validation failure"); @@ -1726,7 +1914,7 @@ static int cam_smmu_map_kernel_buffer_and_add_to_list(int idx, struct cam_dma_buff_info *mapping_info = NULL; rc = cam_smmu_map_buffer_validate(buf, idx, dma_dir, paddr_ptr, len_ptr, - region_id, &mapping_info); + region_id, false, &mapping_info); if (rc) { CAM_ERR(CAM_SMMU, "buffer validation failure"); @@ -1763,12 +1951,17 @@ static int cam_smmu_unmap_buf_and_remove_from_list( 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].mapping->domain; + domain = iommu_cb_set.cb_info[idx].domain; size = iommu_unmap(domain, mapping_info->paddr, @@ -1788,10 +1981,10 @@ static int cam_smmu_unmap_buf_and_remove_from_list( 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) { - msm_dma_unmap_sg(iommu_cb_set.cb_info[idx].dev, - mapping_info->table->sgl, mapping_info->table->nents, - mapping_info->dir, mapping_info->buf); + iommu_cb_set.cb_info[idx].io_mapping_size -= mapping_info->len; } dma_buf_unmap_attachment(mapping_info->attach, @@ -1848,6 +2041,25 @@ static enum cam_smmu_buf_state cam_smmu_check_secure_fd_in_list(int idx, { 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) { @@ -1979,7 +2191,7 @@ static int cam_smmu_alloc_scratch_buffer_add_to_list(int idx, /* Get the domain from within our cb_set struct and map it*/ - domain = iommu_cb_set.cb_info[idx].mapping->domain; + 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); @@ -2051,7 +2263,7 @@ static int cam_smmu_free_scratch_buffer_remove_from_list( int rc = 0; size_t unmapped; struct iommu_domain *domain = - iommu_cb_set.cb_info[idx].mapping->domain; + iommu_cb_set.cb_info[idx].domain; struct scratch_mapping *scratch_map = &iommu_cb_set.cb_info[idx].scratch_map; @@ -2245,60 +2457,92 @@ int cam_smmu_put_scratch_iova(int handle, } static int cam_smmu_map_stage2_buffer_and_add_to_list(int idx, int ion_fd, - enum dma_data_direction dma_dir, struct ion_client *client, - dma_addr_t *paddr_ptr, + enum dma_data_direction dma_dir, dma_addr_t *paddr_ptr, size_t *len_ptr) { int rc = 0; - struct ion_handle *i_handle = NULL; + 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; - i_handle = ion_import_dma_buf_fd(client, ion_fd); - if (IS_ERR_OR_NULL((void *)(i_handle))) { - CAM_ERR(CAM_SMMU, "ion import dma buffer failed"); - return -EINVAL; + 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; } - /* return addr and len to client */ - rc = ion_phys(client, i_handle, paddr_ptr, len_ptr); - if (rc) { - CAM_ERR(CAM_SMMU, "ION Get Physical failed, rc: %d", - rc); - return rc; + /* + * 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) - return -ENOMEM; + 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->i_hdl = i_handle; - mapping_info->i_client = client; + mapping_info->buf = dmabuf; - CAM_DBG(CAM_SMMU, "ion_fd = %d, dev = %pK, paddr= %pK, len = %u", - ion_fd, + 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, - struct ion_client *client, ion_phys_addr_t *paddr_ptr, - size_t *len_ptr) + dma_addr_t *paddr_ptr, size_t *len_ptr) { int idx, rc; enum dma_data_direction dma_dir; @@ -2333,15 +2577,16 @@ int cam_smmu_map_stage2_iova(int handle, if (!iommu_cb_set.cb_info[idx].is_secure) { CAM_ERR(CAM_SMMU, - "Error: can't map secure mem to non secure cb"); + "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, table_hdl = %x, hdl = %x", - iommu_cb_set.cb_info[idx].handle, handle); + "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; } @@ -2349,15 +2594,18 @@ int cam_smmu_map_stage2_iova(int handle, 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, give same addr back", - ion_fd); + 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, - client, paddr_ptr, len_ptr); + paddr_ptr, len_ptr); if (rc < 0) { - CAM_ERR(CAM_SMMU, "Error: mapping or add list fail"); + 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; } @@ -2375,7 +2623,7 @@ static int cam_smmu_secure_unmap_buf_and_remove_from_list( CAM_ERR(CAM_SMMU, "Error: List doesn't exist"); return -EINVAL; } - ion_free(mapping_info->i_client, mapping_info->i_hdl); + 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); @@ -2426,6 +2674,16 @@ int cam_smmu_unmap_stage2_iova(int handle, int ion_fd) 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) { @@ -2478,7 +2736,7 @@ static int cam_smmu_map_iova_validate_params(int handle, return rc; } -int cam_smmu_map_user_iova(int handle, int ion_fd, +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) { @@ -2493,19 +2751,21 @@ int cam_smmu_map_user_iova(int handle, int ion_fd, return rc; } - dma_dir = cam_smmu_translate_dir(dir); + 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"); + "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, table_hdl = %x, hdl = %x", - 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; } @@ -2521,15 +2781,20 @@ int cam_smmu_map_user_iova(int handle, int ion_fd, 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, - "ion_fd: %d already in the list", ion_fd); + "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, dma_dir, - paddr_ptr, len_ptr, region_id); - if (rc < 0) - CAM_ERR(CAM_SMMU, "mapping or add list fail"); + 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); @@ -2696,7 +2961,7 @@ int cam_smmu_get_stage2_iova(int handle, int ion_fd, goto get_addr_end; } - buf_state = cam_smmu_check_secure_fd_in_list(idx, + buf_state = cam_smmu_validate_secure_fd_in_list(idx, ion_fd, paddr_ptr, len_ptr); @@ -2949,11 +3214,8 @@ EXPORT_SYMBOL(cam_smmu_destroy_handle); static void cam_smmu_deinit_cb(struct cam_context_bank_info *cb) { - arm_iommu_detach_device(cb->dev); - - if (cb->io_support && cb->mapping) { - arm_iommu_release_mapping(cb->mapping); - cb->mapping = NULL; + if (cb->io_support && cb->domain) { + cb->domain = NULL; } if (cb->shared_support) { @@ -3033,31 +3295,20 @@ static int cam_smmu_setup_cb(struct cam_context_bank_info *cb, /* create a virtual mapping */ if (cb->io_support) { - cb->mapping = arm_iommu_create_mapping(&platform_bus_type, - cb->io_info.iova_start, cb->io_info.iova_len); - if (IS_ERR(cb->mapping)) { - CAM_ERR(CAM_SMMU, "Error: create mapping Failed"); + 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_cb_set.non_fatal_fault = 1; - if (iommu_domain_set_attr(cb->mapping->domain, - DOMAIN_ATTR_NON_FATAL_FAULTS, - &iommu_cb_set.non_fatal_fault) < 0) { - CAM_ERR(CAM_SMMU, - "Error: failed to set non fatal fault attribute"); - } + iommu_dma_enable_best_fit_algo(dev); - if (!strcmp(cb->name, "icp")) { - iommu_cb_set.enable_iova_guard = 1; - if (iommu_domain_set_attr(cb->mapping->domain, - DOMAIN_ATTR_FORCE_IOVA_GUARD_PAGE, - &iommu_cb_set.enable_iova_guard) < 0) { - CAM_ERR(CAM_SMMU, - "Failed to set iova guard pagei attr"); - } - } + 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; @@ -3123,6 +3374,52 @@ static int cam_alloc_smmu_context_banks(struct device *dev) 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) { @@ -3221,6 +3518,16 @@ static int cam_smmu_get_memory_regions_info(struct device_node *of_node, 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; @@ -3245,6 +3552,60 @@ static int cam_smmu_get_memory_regions_info(struct device_node *of_node, 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) { @@ -3295,6 +3656,7 @@ static int cam_populate_smmu_context_banks(struct device *dev, if (cb->is_secure) { /* increment count to next bank */ + cb->dev = dev; iommu_cb_set.cb_init_count++; return 0; } @@ -3314,24 +3676,65 @@ static int cam_populate_smmu_context_banks(struct device *dev, CAM_ERR(CAM_SMMU, "Error: failed to setup cb : %s", cb->name); goto cb_init_fail; } - if (cb->io_support && cb->mapping) - iommu_set_fault_handler(cb->mapping->domain, + 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) { @@ -3343,6 +3746,7 @@ static int cam_smmu_probe(struct platform_device *pdev) 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; @@ -3374,15 +3778,26 @@ static int cam_smmu_probe(struct platform_device *pdev) 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; } diff --git a/drivers/media/platform/msm/camera_oneplus/cam_smmu/cam_smmu_api.h b/drivers/media/platform/msm/camera_oneplus/cam_smmu/cam_smmu_api.h index 254e382a99ad..15671e7cd12a 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_smmu/cam_smmu_api.h +++ b/drivers/media/platform/msm/camera_oneplus/cam_smmu/cam_smmu_api.h @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include @@ -50,15 +49,34 @@ enum cam_smmu_region_id { 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 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; }; /** @@ -91,6 +109,8 @@ int cam_smmu_ops(int handle, enum cam_smmu_ops_param op); * * @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 @@ -100,9 +120,8 @@ int cam_smmu_ops(int handle, enum cam_smmu_ops_param op); * @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, enum cam_smmu_map_dir dir, - dma_addr_t *dma_addr, size_t *len_ptr, +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); /** @@ -215,13 +234,19 @@ 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 client_page_fault_handler: It is triggered in IOMMU page fault + * @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_reg_client_page_fault_handler(int handle, - void (*client_page_fault_handler)(struct iommu_domain *, - struct device *, unsigned long, - int, void*), void *token); +void cam_smmu_unset_client_page_fault_handler(int handle, void *token); /** * @brief Maps memory from an ION fd into IOVA space @@ -248,6 +273,7 @@ int cam_smmu_get_iova(int handle, int ion_fd, */ 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 * @@ -264,15 +290,14 @@ int cam_smmu_put_iova(int handle, int ion_fd); * @param handle: SMMU handle identifying secure context bank * @param ion_fd: ION fd to map securely * @param dir: DMA Direction for the mapping - * @param client: Ion client passed by caller * @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, struct ion_client *client, - ion_phys_addr_t *dma_addr, size_t *len_ptr); + 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 @@ -284,7 +309,6 @@ int cam_smmu_map_stage2_iova(int handle, */ int cam_smmu_unmap_stage2_iova(int handle, int ion_fd); - /** * @brief Allocates firmware for context bank * @@ -297,7 +321,7 @@ int cam_smmu_unmap_stage2_iova(int handle, int ion_fd); */ int cam_smmu_alloc_firmware(int32_t smmu_hdl, dma_addr_t *iova, - uint64_t *kvaddr, + uintptr_t *kvaddr, size_t *len); /** @@ -368,4 +392,19 @@ int cam_smmu_alloc_qdss(int32_t smmu_hdl, */ 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/drivers/media/platform/msm/camera_oneplus/cam_sync/cam_sync.c b/drivers/media/platform/msm/camera_oneplus/cam_sync/cam_sync.c index d625a20d6ad5..e5b83c302757 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_sync/cam_sync.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_sync/cam_sync.c @@ -364,8 +364,49 @@ int cam_sync_merge(int32_t *sync_obj, uint32_t num_objs, int32_t *merged_obj) 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); } @@ -428,7 +469,7 @@ static int cam_sync_handle_create(struct cam_private_ioctl_arg *k_ioctl) return -EINVAL; if (copy_from_user(&sync_create, - (void *)k_ioctl->ioctl_ptr, + u64_to_user_ptr(k_ioctl->ioctl_ptr), k_ioctl->size)) return -EFAULT; @@ -436,7 +477,8 @@ static int cam_sync_handle_create(struct cam_private_ioctl_arg *k_ioctl) sync_create.name); if (!result) - if (copy_to_user((void *)k_ioctl->ioctl_ptr, + if (copy_to_user( + u64_to_user_ptr(k_ioctl->ioctl_ptr), &sync_create, k_ioctl->size)) return -EFAULT; @@ -455,7 +497,7 @@ static int cam_sync_handle_signal(struct cam_private_ioctl_arg *k_ioctl) return -EINVAL; if (copy_from_user(&sync_signal, - (void *)k_ioctl->ioctl_ptr, + u64_to_user_ptr(k_ioctl->ioctl_ptr), k_ioctl->size)) return -EFAULT; @@ -478,7 +520,7 @@ static int cam_sync_handle_merge(struct cam_private_ioctl_arg *k_ioctl) return -EINVAL; if (copy_from_user(&sync_merge, - (void *)k_ioctl->ioctl_ptr, + u64_to_user_ptr(k_ioctl->ioctl_ptr), k_ioctl->size)) return -EFAULT; @@ -492,8 +534,8 @@ static int cam_sync_handle_merge(struct cam_private_ioctl_arg *k_ioctl) return -ENOMEM; if (copy_from_user(sync_objs, - (void *)sync_merge.sync_objs, - sizeof(uint32_t) * sync_merge.num_objs)) { + u64_to_user_ptr(sync_merge.sync_objs), + sizeof(uint32_t) * sync_merge.num_objs)) { kfree(sync_objs); return -EFAULT; } @@ -505,7 +547,8 @@ static int cam_sync_handle_merge(struct cam_private_ioctl_arg *k_ioctl) &sync_merge.merged); if (!result) - if (copy_to_user((void *)k_ioctl->ioctl_ptr, + if (copy_to_user( + u64_to_user_ptr(k_ioctl->ioctl_ptr), &sync_merge, k_ioctl->size)) { kfree(sync_objs); @@ -528,7 +571,7 @@ static int cam_sync_handle_wait(struct cam_private_ioctl_arg *k_ioctl) return -EINVAL; if (copy_from_user(&sync_wait, - (void *)k_ioctl->ioctl_ptr, + u64_to_user_ptr(k_ioctl->ioctl_ptr), k_ioctl->size)) return -EFAULT; @@ -549,7 +592,7 @@ static int cam_sync_handle_destroy(struct cam_private_ioctl_arg *k_ioctl) return -EINVAL; if (copy_from_user(&sync_create, - (void *)k_ioctl->ioctl_ptr, + u64_to_user_ptr(k_ioctl->ioctl_ptr), k_ioctl->size)) return -EFAULT; @@ -573,7 +616,7 @@ static int cam_sync_handle_register_user_payload( return -EINVAL; if (copy_from_user(&userpayload_info, - (void *)k_ioctl->ioctl_ptr, + u64_to_user_ptr(k_ioctl->ioctl_ptr), k_ioctl->size)) return -EFAULT; @@ -654,7 +697,7 @@ static int cam_sync_handle_deregister_user_payload( } if (copy_from_user(&userpayload_info, - (void *)k_ioctl->ioctl_ptr, + u64_to_user_ptr(k_ioctl->ioctl_ptr), k_ioctl->size)) return -EFAULT; diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sync/cam_sync_api.h b/drivers/media/platform/msm/camera_oneplus/cam_sync/cam_sync_api.h index 9646887e9184..297f53af84fd 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_sync/cam_sync_api.h +++ b/drivers/media/platform/msm/camera_oneplus/cam_sync/cam_sync_api.h @@ -100,6 +100,29 @@ int cam_sync_signal(int32_t sync_obj, uint32_t status); */ 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 * diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sync/cam_sync_private.h b/drivers/media/platform/msm/camera_oneplus/cam_sync/cam_sync_private.h index 5ae707a2b6e7..7872064df5d0 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_sync/cam_sync_private.h +++ b/drivers/media/platform/msm/camera_oneplus/cam_sync/cam_sync_private.h @@ -138,6 +138,7 @@ struct sync_user_payload { * @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]; @@ -152,6 +153,7 @@ struct sync_table_row { struct completion signaled; struct list_head callback_list; struct list_head user_payload_list; + atomic_t ref_cnt; }; /** diff --git a/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_common_util.h b/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_common_util.h index d6a11b75b993..9f4a68b01052 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_common_util.h +++ b/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_common_util.h @@ -15,6 +15,25 @@ #define CAM_BITS_MASK_SHIFT(x, mask, shift) (((x) & (mask)) >> shift) +#define CAM_GET_TIMESTAMP(timestamp) ktime_get_real_ts64(&(timestamp)) +#define CAM_GET_TIMESTAMP_DIFF_IN_MICRO(ts_start, ts_end, diff_microsec) \ +({ \ + diff_microsec = 0; \ + if (ts_end.tv_nsec >= ts_start.tv_nsec) { \ + diff_microsec = \ + (ts_end.tv_nsec - ts_start.tv_nsec) / 1000; \ + diff_microsec += \ + (ts_end.tv_sec - ts_start.tv_sec) * 1000 * 1000; \ + } else { \ + diff_microsec = \ + (ts_end.tv_nsec + \ + (1000*1000*1000 - ts_start.tv_nsec)) / 1000; \ + diff_microsec += \ + (ts_end.tv_sec - ts_start.tv_sec - 1) * 1000 * 1000; \ + } \ +}) + + /** * cam_common_util_get_string_index() * diff --git a/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_debug_util.c b/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_debug_util.c index 26f2ba12be9f..9b63d00e9a63 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_debug_util.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_debug_util.c @@ -30,7 +30,7 @@ const char *cam_get_module_name(unsigned int module_id) name = "CAM-CORE"; break; case CAM_CRM: - name = "CAM_CRM"; + name = "CAM-CRM"; break; case CAM_CPAS: name = "CAM-CPAS"; @@ -86,6 +86,9 @@ const char *cam_get_module_name(unsigned int module_id) case CAM_OIS: name = "CAM-OIS"; break; + case CAM_REQ: + name = "CAM-REQ"; + break; default: name = "CAM"; break; @@ -104,9 +107,11 @@ void cam_debug_log(unsigned int module_id, const char *func, const int line, if (debug_mdl & module_id) { vsnprintf(str_buffer, STR_BUFFER_MAX_LENGTH, fmt, args); - pr_info("CAM_DBG: %s: %s: %d: %s\n", + 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); } + + va_end(args); } diff --git a/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_debug_util.h b/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_debug_util.h index 4e97100bfb6a..14a6d1b04c42 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_debug_util.h +++ b/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_debug_util.h @@ -10,6 +10,9 @@ * GNU General Public License for more details. */ +#include +#include + #ifndef _CAM_DEBUG_UTIL_H_ #define _CAM_DEBUG_UTIL_H_ @@ -35,6 +38,10 @@ #define CAM_CTXT (1 << 19) #define CAM_OIS (1 << 20) #define CAM_RES (1 << 21) +#define CAM_MEM (1 << 22) + +/* CAM_REQ: Tracks a request submitted to KMD */ +#define CAM_REQ (1 << 24) #define STR_BUFFER_MAX_LENGTH 1024 @@ -72,7 +79,8 @@ const char *cam_get_module_name(unsigned int module_id); * @args : Arguments which needs to be print in log */ #define CAM_ERR(__module, fmt, args...) \ - pr_err("CAM_ERR: %s: %s: %d " fmt "\n", \ + 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 @@ -83,7 +91,8 @@ const char *cam_get_module_name(unsigned int module_id); * @args : Arguments which needs to be print in log */ #define CAM_WARN(__module, fmt, args...) \ - pr_warn("CAM_WARN: %s: %s: %d " fmt "\n", \ + 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 @@ -94,11 +103,25 @@ const char *cam_get_module_name(unsigned int module_id); * @args : Arguments which needs to be print in log */ #define CAM_INFO(__module, fmt, args...) \ - pr_info("CAM_INFO: %s: %s: %d " fmt "\n", \ + 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 + * @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 @@ -109,10 +132,10 @@ const char *cam_get_module_name(unsigned int module_id); /* * CAM_ERR_RATE_LIMIT - * @brief : This Macro will prevent error print logs with ratelimit + * @brief : This Macro will print error print logs with ratelimit */ #define CAM_ERR_RATE_LIMIT(__module, fmt, args...) \ - pr_err_ratelimited("CAM_ERR: %s: %s: %d " fmt "\n", \ + pr_info_ratelimited("CAM_ERR: %s: %s: %d " fmt "\n", \ cam_get_module_name(__module), __func__, __LINE__, ##args) #endif /* _CAM_DEBUG_UTIL_H_ */ diff --git a/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_packet_util.c b/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_packet_util.c index 30ab0754c47f..8bccc55f73d1 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_packet_util.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_packet_util.c @@ -21,7 +21,7 @@ int cam_packet_util_get_cmd_mem_addr(int handle, uint32_t **buf_addr, size_t *len) { int rc = 0; - uint64_t kmd_buf_addr = 0; + uintptr_t kmd_buf_addr = 0; rc = cam_mem_get_cpu_buf(handle, &kmd_buf_addr, len); if (rc) { @@ -39,6 +39,12 @@ int cam_packet_util_get_cmd_mem_addr(int handle, uint32_t **buf_addr, int cam_packet_util_validate_cmd_desc(struct cam_cmd_buf_desc *cmd_desc) { + + if (!cmd_desc) { + CAM_ERR(CAM_UTIL, "Invalid cmd desc"); + return -EINVAL; + } + if ((cmd_desc->length > cmd_desc->size) || (cmd_desc->mem_handle <= 0)) { CAM_ERR(CAM_UTIL, "invalid cmd arg %d %d %d %d", @@ -127,8 +133,8 @@ 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; - uint64_t iova_addr; - uint64_t cpu_addr; + dma_addr_t iova_addr; + uintptr_t cpu_addr = 0; uint32_t temp; uint32_t *dst_cpu_addr; uint32_t *src_buf_iova_addr; @@ -161,7 +167,7 @@ int cam_packet_util_process_patches(struct cam_packet *packet, rc = cam_mem_get_cpu_buf(patch_desc[i].dst_buf_hdl, &cpu_addr, &dst_buf_len); - if (rc < 0) { + if (rc < 0 || !cpu_addr || (dst_buf_len == 0)) { CAM_ERR(CAM_UTIL, "unable to get dst buf address"); return rc; } @@ -190,8 +196,8 @@ 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; - uint64_t cpu_addr; + int rc = 0; + uintptr_t cpu_addr = 0; size_t buf_size; uint32_t *blob_ptr; uint32_t blob_type, blob_size, blob_block_size, len_read; @@ -215,7 +221,8 @@ int cam_packet_util_process_generic_cmd_buffer( return rc; } - blob_ptr = (uint32_t *)((uint8_t *)cpu_addr + cmd_buf->offset); + blob_ptr = (uint32_t *)(((uint8_t *)cpu_addr) + + cmd_buf->offset); CAM_DBG(CAM_UTIL, "GenericCmdBuffer cpuaddr=%pK, blobptr=%pK, len=%d", diff --git a/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_trace.h b/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_trace.h index 90ec5666941e..c5cb117e5119 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_trace.h +++ b/drivers/media/platform/msm/camera_oneplus/cam_utils/cam_trace.h @@ -71,6 +71,29 @@ TRACE_EVENT(cam_isp_activated_irq, ) ); +TRACE_EVENT(cam_log_event, + TP_PROTO(const char *string1, const char *string2, + uint64_t val1, uint64_t val2), + TP_ARGS(string1, string2, val1, val2), + TP_STRUCT__entry( + __string(string1, string1) + __string(string2, string2) + __field(uint64_t, val1) + __field(uint64_t, val2) + ), + TP_fast_assign( + __assign_str(string1, string1); + __assign_str(string2, string2); + __entry->val1 = val1; + __entry->val2 = val2; + ), + TP_printk( + "%s: %s val1=%llu val2=%llu", + __get_str(string1), __get_str(string2), + __entry->val1, __entry->val2 + ) +); + TRACE_EVENT(cam_icp_fw_dbg, TP_PROTO(char *dbg_message), TP_ARGS(dbg_message), diff --git a/include/uapi/media/cam_req_mgr.h b/include/uapi/media/cam_req_mgr.h index defed877b52d..eb1dcc6e5452 100644 --- a/include/uapi/media/cam_req_mgr.h +++ b/include/uapi/media/cam_req_mgr.h @@ -262,6 +262,7 @@ struct cam_req_mgr_link_control { #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 From 84edf6f35b426312360fff43448d70d451c71910 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Sat, 22 Apr 2023 15:20:14 +0000 Subject: [PATCH 315/356] ARM64: enchilada: Build camera driver --- arch/arm64/configs/vendor/enchilada_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/vendor/enchilada_defconfig b/arch/arm64/configs/vendor/enchilada_defconfig index b927ae521ac9..e98f6b7fc171 100644 --- a/arch/arm64/configs/vendor/enchilada_defconfig +++ b/arch/arm64/configs/vendor/enchilada_defconfig @@ -418,6 +418,7 @@ CONFIG_MEDIA_USB_SUPPORT=y CONFIG_USB_VIDEO_CLASS=y CONFIG_V4L_PLATFORM_DRIVERS=y CONFIG_MSM_VIDC_LEGACY_V4L2=y +CONFIG_SPECTRA_CAMERA=y CONFIG_VIDEO_V4L2_VIDEOBUF2_CORE=y CONFIG_DRM=y CONFIG_BACKLIGHT_LCD_SUPPORT=y From 89a603a848f1e3606d36850a757cb6a749b80680 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Fri, 7 Apr 2023 03:27:20 +0000 Subject: [PATCH 316/356] ARM64: enchilada: Enable PSTORE --- arch/arm64/configs/vendor/enchilada_defconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/configs/vendor/enchilada_defconfig b/arch/arm64/configs/vendor/enchilada_defconfig index e98f6b7fc171..3d86276e12f5 100644 --- a/arch/arm64/configs/vendor/enchilada_defconfig +++ b/arch/arm64/configs/vendor/enchilada_defconfig @@ -664,6 +664,10 @@ CONFIG_SDCARD_FS=y CONFIG_EROFS_FS=y CONFIG_EROFS_FS_PCPU_KTHREAD=y CONFIG_EROFS_FS_PCPU_KTHREAD_HIPRI=y +CONFIG_PSTORE=y +CONFIG_PSTORE_CONSOLE=y +CONFIG_PSTORE_PMSG=y +CONFIG_PSTORE_RAM=y CONFIG_NLS_CODEPAGE_437=y CONFIG_NLS_ISO8859_1=y CONFIG_UNICODE=y From ce3b6960a86c02db9af4c3609fd5830bf4b9ae02 Mon Sep 17 00:00:00 2001 From: Luca Stefani Date: Sat, 28 Jul 2018 10:28:57 +0200 Subject: [PATCH 317/356] drivers: extcon: Import tri-state-key driver Change-Id: Iba891aaa1c456457f813098372510abe2629d7ec --- drivers/extcon/Kconfig | 6 + drivers/extcon/Makefile | 1 + drivers/extcon/tri_state_key.c | 367 +++++++++++++++++++++++++++++++++ 3 files changed, 374 insertions(+) create mode 100644 drivers/extcon/tri_state_key.c diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig index 19a1e32c3a7e..7bd411789557 100644 --- a/drivers/extcon/Kconfig +++ b/drivers/extcon/Kconfig @@ -159,4 +159,10 @@ config EXTCON_USBC_CROS_EC Say Y here to enable USB Type C cable detection extcon support when using Chrome OS EC based USB Type-C ports. +config TRI_STATE_KEY + default n + tristate "switch Profiles by this triple key" + help + Say Y here if you want to enable the feature. + endif diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile index 0888fdeded72..3b47d428144a 100644 --- a/drivers/extcon/Makefile +++ b/drivers/extcon/Makefile @@ -22,3 +22,4 @@ obj-$(CONFIG_EXTCON_RT8973A) += extcon-rt8973a.o obj-$(CONFIG_EXTCON_SM5502) += extcon-sm5502.o obj-$(CONFIG_EXTCON_USB_GPIO) += extcon-usb-gpio.o obj-$(CONFIG_EXTCON_USBC_CROS_EC) += extcon-usbc-cros-ec.o +obj-$(CONFIG_TRI_STATE_KEY) += tri_state_key.o diff --git a/drivers/extcon/tri_state_key.c b/drivers/extcon/tri_state_key.c new file mode 100644 index 000000000000..e777ed98e79f --- /dev/null +++ b/drivers/extcon/tri_state_key.c @@ -0,0 +1,367 @@ +/* + * + * 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 + +#define DRV_NAME "tri-state-key" + +/* + * + * 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); +} + + +static void extcon_dev_work(struct work_struct *work) +{ + int key[3]={0,0,0}; + int hw_version=0; + /*hw 13 use special tri state key no use key2*/ + hw_version=get_hw_version(); + pr_err("%s ,hw_version=%d\n",__func__, hw_version); + if (hw_version == 13) + { + key[0] = gpio_get_value(extcon_data->key1_gpio); + key[2] = gpio_get_value(extcon_data->key3_gpio); + + pr_err("%s ,key[0]=%d,key[1]=%d,key[2]=%d\n", + __func__, 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); + + pr_err("%s ,key[0]=%d,key[1]=%d,key[2]=%d\n", + __func__, key[0], key[1], key[2]); + 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]); + } + +} + + +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; + pr_err("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; + pr_err("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; + pr_err("extcon_data->key1_gpio=%d\n", extcon_data->key1_gpio); + + return 0; +} +#else +static inline int +extcon_dev_get_devtree_pdata(struct device *dev) +{ + pr_info("%s inline function", __func__); + return 0; +} +#endif + +static int tristate_dev_probe(struct platform_device *pdev) +{ + struct device *dev; + int ret = 0; + + 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)) { + dev_err(extcon_data->dev, "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)) { + dev_err(extcon_data->dev, "Failed to lookup_state\n"); + goto err_extcon_dev_register; + } + + set_gpio_by_pinctrl(); + + ret = extcon_dev_get_devtree_pdata(dev); + if (ret) { + dev_err(dev, "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"); + From cb3c676fc68fb2efbc452f4409b2d5c6546193d5 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Sun, 23 Apr 2023 02:02:15 +0000 Subject: [PATCH 318/356] extcon: tri-state-key: Fix build on 4.19 --- drivers/extcon/tri_state_key.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/extcon/tri_state_key.c b/drivers/extcon/tri_state_key.c index e777ed98e79f..d9bb8a27a344 100644 --- a/drivers/extcon/tri_state_key.c +++ b/drivers/extcon/tri_state_key.c @@ -16,6 +16,7 @@ #include #include #include +#include "extcon.h" #include #include @@ -144,7 +145,7 @@ static irqreturn_t extcon_dev_interrupt(int irq, void *_dev) return IRQ_HANDLED; } -static void timer_handle(unsigned long arg) +static void timer_handle(struct timer_list *t) { schedule_work(&extcon_data->work); } @@ -297,8 +298,8 @@ static int tristate_dev_probe(struct platform_device *pdev) INIT_WORK(&extcon_data->work, extcon_dev_work); - init_timer(&extcon_data->s_timer); - extcon_data->s_timer.function = &timer_handle; + __init_timer(&extcon_data->s_timer, timer_handle, 0); + //extcon_data->s_timer.function = &timer_handle; extcon_data->s_timer.expires = jiffies + 5*HZ; add_timer(&extcon_data->s_timer); From f5fd8a32bbcb3a0d15a3f67f3ef58bb7d62390d0 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Sun, 23 Apr 2023 00:16:29 +0000 Subject: [PATCH 319/356] ARM64: enchilada: Enable tri-state-key driver --- arch/arm64/configs/vendor/enchilada_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/vendor/enchilada_defconfig b/arch/arm64/configs/vendor/enchilada_defconfig index 3d86276e12f5..8d076a80e2a8 100644 --- a/arch/arm64/configs/vendor/enchilada_defconfig +++ b/arch/arm64/configs/vendor/enchilada_defconfig @@ -615,6 +615,7 @@ CONFIG_ARM_QCOM_DEVFREQ_FW=y CONFIG_DEVFREQ_SIMPLE_DEV=y CONFIG_QCOM_DEVFREQ_DEVBW=y CONFIG_EXTCON_USB_GPIO=y +CONFIG_TRI_STATE_KEY=y CONFIG_IIO=y CONFIG_QCOM_SPMI_ADC5=y CONFIG_QCOM_RRADC=y From d5a3e03eb810dad4279ee890f7e3810e6084113f Mon Sep 17 00:00:00 2001 From: LuK1337 Date: Mon, 6 Jun 2022 21:51:12 +0200 Subject: [PATCH 320/356] arm64: dts: Switch to nq-nci driver Change-Id: Ic4e4208c7211e8a9b8c4a451f7829e257263ab88 --- arch/arm64/boot/dts/qcom/enchilada.dtsi | 30 ------------------------- arch/arm64/boot/dts/qcom/fajita.dtsi | 29 ------------------------ 2 files changed, 59 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/enchilada.dtsi b/arch/arm64/boot/dts/qcom/enchilada.dtsi index aeb00dd6c30d..53ce55853b44 100644 --- a/arch/arm64/boot/dts/qcom/enchilada.dtsi +++ b/arch/arm64/boot/dts/qcom/enchilada.dtsi @@ -1946,33 +1946,3 @@ status = "disabled"; }; }; -&qupv3_se3_i2c { - - nq@28 { - status = "disabled"; - }; - - pn5xx@28 { - compatible = "nxp,pn544"; - reg = <0x28>; - nxp,pn544-irq = <&tlmm 63 0x00>; - nxp,pn544-ven = <&tlmm 12 0x00>; - nxp,pn544-fw-dwnld = <&tlmm 62 0x00>; - nxp,pn544-clk-gpio = <&pm8998_gpios 21 0x00>; - nxp,pn544-ese-pwr = <&tlmm 116 0x00>; - nfc_voltage_s4-supply = <&pm8998_s4>; - nxp,pn544-wake-up = <&tlmm 129 0x00>; - interrupt-parent = <&tlmm>; - qcom,clk-src = "BBCLK3"; - interrupts = <63 0>; - interrupt-names = "nfc_irq"; - pinctrl-names = "nfc_active", "nfc_suspend"; - pinctrl-0 = <&nfc_int_active - &nfc_enable_active - &nfc_clk_default>; - pinctrl-1 = <&nfc_int_suspend &nfc_enable_suspend>; - clocks = <&clock_rpmh RPMH_LN_BB_CLK3>; - clock-names = "ref_clk"; - }; -}; - diff --git a/arch/arm64/boot/dts/qcom/fajita.dtsi b/arch/arm64/boot/dts/qcom/fajita.dtsi index 0f37e409c51d..6775608478bd 100644 --- a/arch/arm64/boot/dts/qcom/fajita.dtsi +++ b/arch/arm64/boot/dts/qcom/fajita.dtsi @@ -2238,32 +2238,3 @@ status = "disabled"; }; }; -&qupv3_se3_i2c { - - nq@28 { - status = "disabled"; - }; - - pn5xx@28 { - compatible = "nxp,pn544"; - reg = <0x28>; - nxp,pn544-irq = <&tlmm 63 0x00>; - nxp,pn544-ven = <&tlmm 12 0x00>; - nxp,pn544-fw-dwnld = <&tlmm 62 0x00>; - nxp,pn544-clk-gpio = <&pm8998_gpios 21 0x00>; - nxp,pn544-ese-pwr = <&tlmm 116 0x00>; - nfc_voltage_s4-supply = <&pm8998_s4>; - nxp,pn544-wake-up = <&tlmm 129 0x00>; - interrupt-parent = <&tlmm>; - qcom,clk-src = "BBCLK3"; - interrupts = <63 0>; - interrupt-names = "nfc_irq"; - pinctrl-names = "nfc_active", "nfc_suspend"; - pinctrl-0 = <&nfc_int_active - &nfc_enable_active - &nfc_clk_default>; - pinctrl-1 = <&nfc_int_suspend &nfc_enable_suspend>; - clocks = <&clock_rpmh RPMH_LN_BB_CLK3>; - clock-names = "ref_clk"; - }; -}; From 1b11c21c9a1f6f4373d1a48223fb461a414e3724 Mon Sep 17 00:00:00 2001 From: Pavel Dubrova Date: Mon, 3 Jul 2023 04:08:53 +0300 Subject: [PATCH 321/356] techpack: display: Disable SDE encoder during cont splash This change prevents the 3 fps behavior until the first cycle of turning the display off/on. Reference https://github.com/sonyxperiadev/kernel-copyleft/blob/52.0.A.3.xxx/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c#L388-L390 Signed-off-by: Pavel Dubrova --- techpack/display/msm/sde/sde_encoder_phys_cmd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/techpack/display/msm/sde/sde_encoder_phys_cmd.c b/techpack/display/msm/sde/sde_encoder_phys_cmd.c index 545b2e3284fa..f871f28c67ed 100644 --- a/techpack/display/msm/sde/sde_encoder_phys_cmd.c +++ b/techpack/display/msm/sde/sde_encoder_phys_cmd.c @@ -404,7 +404,9 @@ static void sde_encoder_phys_cmd_cont_splash_mode_set( } phys_enc->cached_mode = *adj_mode; +#ifndef CONFIG_ARCH_SDM845 phys_enc->enable_state = SDE_ENC_ENABLED; +#endif if (!phys_enc->hw_ctl || !phys_enc->hw_pp) { SDE_DEBUG("invalid ctl:%d pp:%d\n", From 00e69363f9cc22e08b206bc5da14e2d511d09d38 Mon Sep 17 00:00:00 2001 From: Davide Garberi Date: Wed, 4 Mar 2020 13:21:46 +0100 Subject: [PATCH 322/356] ARM64: dts: Rework ramoops Change-Id: Ibe09c864898398dcf3cb07c3db4b8dc902654389 --- .../boot/dts/qcom/sdm845_enchilada_soc.dtsi | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845_enchilada_soc.dtsi b/arch/arm64/boot/dts/qcom/sdm845_enchilada_soc.dtsi index 7bccd60405c6..0ea3067f85b7 100644 --- a/arch/arm64/boot/dts/qcom/sdm845_enchilada_soc.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845_enchilada_soc.dtsi @@ -21,15 +21,13 @@ reg = <0 0xAC200000 0 0x00100000>; label = "param_mem"; }; - ramoops: ramoops@0xAC300000 { - compatible = "ramoops"; - reg = <0 0xAC300000 0 0x00400000>; - record-size = <0x40000>; /*256x1024*/ - console-size = <0x40000>; - ftrace-size = <0x40000>; - pmsg-size= <0x200000>; - devinfo-size= <0x01000>; - ecc-size= <0x0>; + ramoops { + compatible = "removed-dma-pool", "ramoops"; + no-map; + reg = <0x0 0xAC300000 0x0 0x00400000>; + status = "ok"; + console-size = <0x200000>; + pmsg-size = <0x200000>; }; mtp_mem: mtp_mem@ac700000 { reg = <0 0xAC700000 0 0x00B00000>; From d95e69ed6ff68e7245caa7446b5b8486518e3e83 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Sun, 16 Jul 2023 22:46:34 +0000 Subject: [PATCH 323/356] power: reset: msm: Disable dload mode Dumping kmsg from edl is broken on 4.19. Disable dload mode so we can get logs from pstore when panic occurs --- drivers/power/reset/msm-poweroff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/reset/msm-poweroff.c b/drivers/power/reset/msm-poweroff.c index c1b0799963e6..a63ce0b4c826 100644 --- a/drivers/power/reset/msm-poweroff.c +++ b/drivers/power/reset/msm-poweroff.c @@ -62,7 +62,7 @@ static void scm_disable_sdi(void); * There is no API from TZ to re-enable the registers. * So the SDI cannot be re-enabled when it already by-passed. */ -static int download_mode = 1; +static int download_mode = 0; static struct kobject dload_kobj; static int in_panic; From f51fdd34dc89811176ebe0e9216f3c65827fb01b Mon Sep 17 00:00:00 2001 From: Michael Bestas Date: Fri, 30 May 2025 17:28:51 +0300 Subject: [PATCH 324/356] power: reset: Force a warm reboot when in panic Change-Id: I68697d292aaa770a7eb1424a1e423f339628acf7 --- drivers/power/reset/msm-poweroff.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/power/reset/msm-poweroff.c b/drivers/power/reset/msm-poweroff.c index a63ce0b4c826..79740f0f07c8 100644 --- a/drivers/power/reset/msm-poweroff.c +++ b/drivers/power/reset/msm-poweroff.c @@ -489,6 +489,9 @@ static void msm_restart_prepare(const char *cmd) if (force_warm_reboot) pr_info("Forcing a warm reset of the system\n"); + if (in_panic) + need_warm_reset = true; + /* Hard reset the PMIC unless memory contents must be maintained. */ if (force_warm_reboot || need_warm_reset) qpnp_pon_system_pwr_off(PON_POWER_OFF_WARM_RESET); From 0147bdafe3e09ed6e2307a2ce91a2ffb7b71ea1d Mon Sep 17 00:00:00 2001 From: me-cafebabe Date: Mon, 6 Mar 2023 17:49:49 +0800 Subject: [PATCH 325/356] power: reset: msm-poweroff: Reboot to recovery when kernel panics Change-Id: Iebfdb0b893614cb8fb3b58307ea6e4f635b97e3d --- drivers/power/reset/msm-poweroff.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/power/reset/msm-poweroff.c b/drivers/power/reset/msm-poweroff.c index 79740f0f07c8..de98700c63bd 100644 --- a/drivers/power/reset/msm-poweroff.c +++ b/drivers/power/reset/msm-poweroff.c @@ -498,6 +498,14 @@ static void msm_restart_prepare(const char *cmd) else qpnp_pon_system_pwr_off(PON_POWER_OFF_HARD_RESET); + if (in_panic) { + // Reboot to recovery + qpnp_pon_set_restart_reason( + PON_RESTART_REASON_RECOVERY); + __raw_writel(0x77665502, restart_reason); + goto finish_set_restart_reason; + } + if (cmd != NULL) { if (!strncmp(cmd, "bootloader", 10)) { qpnp_pon_set_restart_reason( @@ -538,6 +546,7 @@ static void msm_restart_prepare(const char *cmd) } } +finish_set_restart_reason: flush_cache_all(); /*outer_flush_all is not supported by 64bit kernel*/ From b4d2ad25cdf05f1d7ddc657ab40cb17032f173e1 Mon Sep 17 00:00:00 2001 From: Fenglin Wu Date: Mon, 12 Mar 2018 14:29:57 +0800 Subject: [PATCH 326/356] leds: led-qpnp-haptics: Add a snapshot of QPNP haptics LED driver This is the snapshot of QPNP haptics LED driver taken as of msm-4.9 commit 6378b629bafc ("Merge "board: msm: Add board support for msm8909 chipset""). Change-Id: I71e7d290a4f541e344076ee0e97e08867fc4bafd Signed-off-by: Fenglin Wu --- drivers/leds/Kconfig | 10 + drivers/leds/Makefile | 1 + drivers/leds/leds-qpnp-haptics.c | 2506 ++++++++++++++++++++++++++++++ 3 files changed, 2517 insertions(+) create mode 100644 drivers/leds/leds-qpnp-haptics.c diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index e2b8820d125b..9a49d5c2f9f5 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -798,6 +798,16 @@ config LEDS_QPNP_FLASH_V2 flash LED target current for several independent channels. It also supports various over current and over temperature mitigation features. +config LEDS_QPNP_HAPTICS + tristate "Haptics support for QPNP PMIC" + depends on LEDS_CLASS && MFD_SPMI_PMIC + help + This option enables device driver support for the haptics peripheral + found on Qualcomm Technologies, Inc. QPNP PMICs. The haptic + peripheral is capable of driving both LRA and ERM vibrators. This + module provides haptic feedback for user actions such as a long press + on the touch screen. + config LEDS_QPNP_VIBRATOR_LDO tristate "Vibrator-LDO support for QPNP PMIC" depends on LEDS_CLASS && MFD_SPMI_PMIC diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index b306664b7932..485a5973e4d3 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -82,6 +82,7 @@ obj-$(CONFIG_LEDS_SC27XX_BLTC) += leds-sc27xx-bltc.o obj-$(CONFIG_LEDS_LM3601X) += leds-lm3601x.o obj-$(CONFIG_LEDS_QTI_TRI_LED) += leds-qti-tri-led.o obj-$(CONFIG_LEDS_QPNP_FLASH_V2) += leds-qpnp-flash-v2.o leds-qpnp-flash-common.o +obj-$(CONFIG_LEDS_QPNP_HAPTICS) += leds-qpnp-haptics.o obj-$(CONFIG_LEDS_QPNP_VIBRATOR_LDO) += leds-qpnp-vibrator-ldo.o obj-$(CONFIG_LEDS_QPNP_VIBRATOR) += leds-qpnp-vibrator.o diff --git a/drivers/leds/leds-qpnp-haptics.c b/drivers/leds/leds-qpnp-haptics.c new file mode 100644 index 000000000000..764657abeed0 --- /dev/null +++ b/drivers/leds/leds-qpnp-haptics.c @@ -0,0 +1,2506 @@ +/* Copyright (c) 2014-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 pr_fmt(fmt) "haptics: %s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Register definitions */ +#define HAP_STATUS_1_REG(chip) (chip->base + 0x0A) +#define HAP_BUSY_BIT BIT(1) +#define SC_FLAG_BIT BIT(3) +#define AUTO_RES_ERROR_BIT BIT(4) + +#define HAP_LRA_AUTO_RES_LO_REG(chip) (chip->base + 0x0B) +#define HAP_LRA_AUTO_RES_HI_REG(chip) (chip->base + 0x0C) + +#define HAP_INT_RT_STS_REG(chip) (chip->base + 0x10) +#define SC_INT_RT_STS_BIT BIT(0) +#define PLAY_INT_RT_STS_BIT BIT(1) + +#define HAP_EN_CTL_REG(chip) (chip->base + 0x46) +#define HAP_EN_BIT BIT(7) + +#define HAP_EN_CTL2_REG(chip) (chip->base + 0x48) +#define BRAKE_EN_BIT BIT(0) + +#define HAP_AUTO_RES_CTRL_REG(chip) (chip->base + 0x4B) +#define AUTO_RES_EN_BIT BIT(7) +#define AUTO_RES_ERR_RECOVERY_BIT BIT(3) + +#define HAP_CFG1_REG(chip) (chip->base + 0x4C) +#define HAP_ACT_TYPE_MASK BIT(0) +#define HAP_LRA 0 +#define HAP_ERM 1 + +#define HAP_CFG2_REG(chip) (chip->base + 0x4D) +#define HAP_WAVE_SINE 0 +#define HAP_WAVE_SQUARE 1 +#define HAP_LRA_RES_TYPE_MASK BIT(0) + +#define HAP_SEL_REG(chip) (chip->base + 0x4E) +#define HAP_WF_SOURCE_MASK GENMASK(5, 4) +#define HAP_WF_SOURCE_SHIFT 4 + +#define HAP_LRA_AUTO_RES_REG(chip) (chip->base + 0x4F) +/* For pmi8998 */ +#define LRA_AUTO_RES_MODE_MASK GENMASK(6, 4) +#define LRA_AUTO_RES_MODE_SHIFT 4 +#define LRA_HIGH_Z_MASK GENMASK(3, 2) +#define LRA_HIGH_Z_SHIFT 2 +#define LRA_RES_CAL_MASK GENMASK(1, 0) +#define HAP_RES_CAL_PERIOD_MIN 4 +#define HAP_RES_CAL_PERIOD_MAX 32 +/* For pm660 */ +#define PM660_AUTO_RES_MODE_BIT BIT(7) +#define PM660_AUTO_RES_MODE_SHIFT 7 +#define PM660_CAL_DURATION_MASK GENMASK(6, 5) +#define PM660_CAL_DURATION_SHIFT 5 +#define PM660_QWD_DRIVE_DURATION_BIT BIT(4) +#define PM660_QWD_DRIVE_DURATION_SHIFT 4 +#define PM660_CAL_EOP_BIT BIT(3) +#define PM660_CAL_EOP_SHIFT 3 +#define PM660_LRA_RES_CAL_MASK GENMASK(2, 0) +#define HAP_PM660_RES_CAL_PERIOD_MAX 256 + +#define HAP_VMAX_CFG_REG(chip) (chip->base + 0x51) +#define HAP_VMAX_OVD_BIT BIT(6) +#define HAP_VMAX_MASK GENMASK(5, 1) +#define HAP_VMAX_SHIFT 1 +#define HAP_VMAX_MIN_MV 116 +#define HAP_VMAX_MAX_MV 3596 + +#define HAP_ILIM_CFG_REG(chip) (chip->base + 0x52) +#define HAP_ILIM_SEL_MASK BIT(0) +#define HAP_ILIM_400_MA 0 +#define HAP_ILIM_800_MA 1 + +#define HAP_SC_DEB_REG(chip) (chip->base + 0x53) +#define HAP_SC_DEB_MASK GENMASK(2, 0) +#define HAP_SC_DEB_CYCLES_MIN 0 +#define HAP_DEF_SC_DEB_CYCLES 8 +#define HAP_SC_DEB_CYCLES_MAX 32 + +#define HAP_RATE_CFG1_REG(chip) (chip->base + 0x54) +#define HAP_RATE_CFG1_MASK GENMASK(7, 0) + +#define HAP_RATE_CFG2_REG(chip) (chip->base + 0x55) +#define HAP_RATE_CFG2_MASK GENMASK(3, 0) +/* Shift needed to convert drive period upper bits [11:8] */ +#define HAP_RATE_CFG2_SHIFT 8 + +#define HAP_INT_PWM_REG(chip) (chip->base + 0x56) +#define INT_PWM_FREQ_SEL_MASK GENMASK(1, 0) +#define INT_PWM_FREQ_253_KHZ 0 +#define INT_PWM_FREQ_505_KHZ 1 +#define INT_PWM_FREQ_739_KHZ 2 +#define INT_PWM_FREQ_1076_KHZ 3 + +#define HAP_EXT_PWM_REG(chip) (chip->base + 0x57) +#define EXT_PWM_FREQ_SEL_MASK GENMASK(1, 0) +#define EXT_PWM_FREQ_25_KHZ 0 +#define EXT_PWM_FREQ_50_KHZ 1 +#define EXT_PWM_FREQ_75_KHZ 2 +#define EXT_PWM_FREQ_100_KHZ 3 + +#define HAP_PWM_CAP_REG(chip) (chip->base + 0x58) + +#define HAP_SC_CLR_REG(chip) (chip->base + 0x59) +#define SC_CLR_BIT BIT(0) + +#define HAP_BRAKE_REG(chip) (chip->base + 0x5C) +#define HAP_BRAKE_PAT_MASK 0x3 + +#define HAP_WF_REPEAT_REG(chip) (chip->base + 0x5E) +#define WF_REPEAT_MASK GENMASK(6, 4) +#define WF_REPEAT_SHIFT 4 +#define WF_REPEAT_MIN 1 +#define WF_REPEAT_MAX 128 +#define WF_S_REPEAT_MASK GENMASK(1, 0) +#define WF_S_REPEAT_MIN 1 +#define WF_S_REPEAT_MAX 8 + +#define HAP_WF_S1_REG(chip) (chip->base + 0x60) +#define HAP_WF_SIGN_BIT BIT(7) +#define HAP_WF_OVD_BIT BIT(6) +#define HAP_WF_SAMP_MAX GENMASK(5, 1) +#define HAP_WF_SAMPLE_LEN 8 + +#define HAP_PLAY_REG(chip) (chip->base + 0x70) +#define PLAY_BIT BIT(7) +#define PAUSE_BIT BIT(0) + +#define HAP_SEC_ACCESS_REG(chip) (chip->base + 0xD0) + +#define HAP_TEST2_REG(chip) (chip->base + 0xE3) +#define HAP_EXT_PWM_DTEST_MASK GENMASK(6, 4) +#define HAP_EXT_PWM_DTEST_SHIFT 4 +#define PWM_MAX_DTEST_LINES 4 +#define HAP_EXT_PWM_PEAK_DATA 0x7F +#define HAP_EXT_PWM_HALF_DUTY 50 +#define HAP_EXT_PWM_FULL_DUTY 100 +#define HAP_EXT_PWM_DATA_FACTOR 39 + +/* Other definitions */ +#define HAP_BRAKE_PAT_LEN 4 +#define HAP_WAVE_SAMP_LEN 8 +#define NUM_WF_SET 4 +#define HAP_WAVE_SAMP_SET_LEN (HAP_WAVE_SAMP_LEN * NUM_WF_SET) +#define HAP_RATE_CFG_STEP_US 5 +#define HAP_WAVE_PLAY_RATE_US_MIN 0 +#define HAP_DEF_WAVE_PLAY_RATE_US 5715 +#define HAP_WAVE_PLAY_RATE_US_MAX 20475 +#define HAP_MAX_PLAY_TIME_MS 15000 + +enum hap_brake_pat { + NO_BRAKE = 0, + BRAKE_VMAX_4, + BRAKE_VMAX_2, + BRAKE_VMAX, +}; + +enum hap_auto_res_mode { + HAP_AUTO_RES_NONE, + HAP_AUTO_RES_ZXD, + HAP_AUTO_RES_QWD, + HAP_AUTO_RES_MAX_QWD, + HAP_AUTO_RES_ZXD_EOP, +}; + +enum hap_pm660_auto_res_mode { + HAP_PM660_AUTO_RES_ZXD, + HAP_PM660_AUTO_RES_QWD, +}; + +/* high Z option lines */ +enum hap_high_z { + HAP_LRA_HIGH_Z_NONE, /* opt0 for PM660 */ + HAP_LRA_HIGH_Z_OPT1, + HAP_LRA_HIGH_Z_OPT2, + HAP_LRA_HIGH_Z_OPT3, +}; + +/* play modes */ +enum hap_mode { + HAP_DIRECT, + HAP_BUFFER, + HAP_AUDIO, + HAP_PWM, +}; + +/* wave/sample repeat */ +enum hap_rep_type { + HAP_WAVE_REPEAT = 1, + HAP_WAVE_SAMP_REPEAT, +}; + +/* status flags */ +enum hap_status { + AUTO_RESONANCE_ENABLED = BIT(0), +}; + +enum hap_play_control { + HAP_STOP, + HAP_PAUSE, + HAP_PLAY, +}; + +/* pwm channel parameters */ +struct pwm_param { + struct pwm_device *pwm_dev; + u32 duty_us; + u32 period_us; +}; + +/* + * hap_lra_ares_param - Haptic auto_resonance parameters + * @ lra_qwd_drive_duration - LRA QWD drive duration + * @ calibrate_at_eop - Calibrate at EOP + * @ lra_res_cal_period - LRA resonance calibration period + * @ auto_res_mode - auto resonace mode + * @ lra_high_z - high z option line + */ +struct hap_lra_ares_param { + int lra_qwd_drive_duration; + int calibrate_at_eop; + enum hap_high_z lra_high_z; + u16 lra_res_cal_period; + u8 auto_res_mode; +}; + +/* + * hap_chip - Haptics data structure + * @ pdev - platform device pointer + * @ regmap - regmap pointer + * @ bus_lock - spin lock for bus read/write + * @ play_lock - mutex lock for haptics play/enable control + * @ haptics_work - haptics worker + * @ stop_timer - hrtimer for stopping haptics + * @ auto_res_err_poll_timer - hrtimer for auto-resonance error + * @ base - base address + * @ play_irq - irq for play + * @ sc_irq - irq for short circuit + * @ pwm_data - pwm configuration + * @ ares_cfg - auto resonance configuration + * @ play_time_ms - play time set by the user in ms + * @ max_play_time_ms - max play time in ms + * @ vmax_mv - max voltage in mv + * @ ilim_ma - limiting current in ma + * @ sc_deb_cycles - short circuit debounce cycles + * @ wave_play_rate_us - play rate for waveform + * @ last_rate_cfg - Last rate config updated + * @ wave_rep_cnt - waveform repeat count + * @ wave_s_rep_cnt - waveform sample repeat count + * @ wf_samp_len - waveform sample length + * @ ext_pwm_freq_khz - external pwm frequency in KHz + * @ ext_pwm_dtest_line - DTEST line for external pwm + * @ status_flags - status + * @ play_mode - play mode + * @ act_type - actuator type + * @ wave_shape - waveform shape + * @ wave_samp_idx - wave sample id used to refer start of a sample set + * @ wave_samp - array of wave samples + * @ brake_pat - pattern for active breaking + * @ en_brake - brake state + * @ misc_clk_trim_error_reg - MISC clock trim error register if present + * @ clk_trim_error_code - MISC clock trim error code + * @ drive_period_code_max_limit - calculated drive period code with + percentage variation on the higher side. + * @ drive_period_code_min_limit - calculated drive period code with + percentage variation on the lower side + * @ drive_period_code_max_var_pct - maximum limit of percentage variation of + drive period code + * @ drive_period_code_min_var_pct - minimum limit of percentage variation of + drive period code + * @ last_sc_time - Last time short circuit was detected + * @ sc_count - counter to determine the duration of short circuit + condition + * @ perm_disable - Flag to disable module permanently + * @ state - current state of haptics + * @ module_en - module enable status of haptics + * @ lra_auto_mode - Auto mode selection + * @ play_irq_en - Play interrupt enable status + * @ auto_res_err_recovery_hw - Enable auto resonance error recovery by HW + */ +struct hap_chip { + struct platform_device *pdev; + struct regmap *regmap; + struct pmic_revid_data *revid; + struct led_classdev cdev; + spinlock_t bus_lock; + struct mutex play_lock; + struct mutex param_lock; + struct work_struct haptics_work; + struct hrtimer stop_timer; + struct hrtimer auto_res_err_poll_timer; + u16 base; + int play_irq; + int sc_irq; + struct pwm_param pwm_data; + struct hap_lra_ares_param ares_cfg; + u32 play_time_ms; + u32 max_play_time_ms; + u32 vmax_mv; + u8 ilim_ma; + u32 sc_deb_cycles; + u32 wave_play_rate_us; + u16 last_rate_cfg; + u32 wave_rep_cnt; + u32 wave_s_rep_cnt; + u32 wf_samp_len; + u32 ext_pwm_freq_khz; + u8 ext_pwm_dtest_line; + u32 status_flags; + enum hap_mode play_mode; + u8 act_type; + u8 wave_shape; + u8 wave_samp_idx; + u32 wave_samp[HAP_WAVE_SAMP_SET_LEN]; + u32 brake_pat[HAP_BRAKE_PAT_LEN]; + bool en_brake; + u32 misc_clk_trim_error_reg; + u8 clk_trim_error_code; + u16 drive_period_code_max_limit; + u16 drive_period_code_min_limit; + u8 drive_period_code_max_var_pct; + u8 drive_period_code_min_var_pct; + ktime_t last_sc_time; + u8 sc_count; + bool perm_disable; + atomic_t state; + bool module_en; + bool lra_auto_mode; + bool play_irq_en; + bool auto_res_err_recovery_hw; +}; + +static int qpnp_haptics_parse_buffer_dt(struct hap_chip *chip); +static int qpnp_haptics_parse_pwm_dt(struct hap_chip *chip); + +static int qpnp_haptics_read_reg(struct hap_chip *chip, u16 addr, u8 *val, + int len) +{ + int rc; + + rc = regmap_bulk_read(chip->regmap, addr, val, len); + if (rc < 0) + pr_err("Error reading address: 0x%x - rc %d\n", addr, rc); + + return rc; +} + +static inline bool is_secure(u16 addr) +{ + return ((addr & 0xFF) > 0xD0); +} + +static int qpnp_haptics_write_reg(struct hap_chip *chip, u16 addr, u8 *val, + int len) +{ + unsigned long flags; + unsigned int unlock = 0xA5; + int rc = 0, i; + + spin_lock_irqsave(&chip->bus_lock, flags); + + if (is_secure(addr)) { + for (i = 0; i < len; i++) { + rc = regmap_write(chip->regmap, + HAP_SEC_ACCESS_REG(chip), unlock); + if (rc < 0) { + pr_err("Error writing unlock code - rc %d\n", + rc); + goto out; + } + + rc = regmap_write(chip->regmap, addr + i, val[i]); + if (rc < 0) { + pr_err("Error writing address 0x%x - rc %d\n", + addr + i, rc); + goto out; + } + } + } else { + if (len > 1) + rc = regmap_bulk_write(chip->regmap, addr, val, len); + else + rc = regmap_write(chip->regmap, addr, *val); + } + + if (rc < 0) + pr_err("Error writing address: 0x%x - rc %d\n", addr, rc); + +out: + spin_unlock_irqrestore(&chip->bus_lock, flags); + return rc; +} + +static int qpnp_haptics_masked_write_reg(struct hap_chip *chip, u16 addr, + u8 mask, u8 val) +{ + unsigned long flags; + unsigned int unlock = 0xA5; + int rc; + + spin_lock_irqsave(&chip->bus_lock, flags); + if (is_secure(addr)) { + rc = regmap_write(chip->regmap, HAP_SEC_ACCESS_REG(chip), + unlock); + if (rc < 0) { + pr_err("Error writing unlock code - rc %d\n", rc); + goto out; + } + } + + rc = regmap_update_bits(chip->regmap, addr, mask, val); + if (rc < 0) + pr_err("Error writing address: 0x%x - rc %d\n", addr, rc); + + if (!rc) + pr_debug("wrote to address 0x%x = 0x%x\n", addr, val); +out: + spin_unlock_irqrestore(&chip->bus_lock, flags); + return rc; +} + +static inline int get_buffer_mode_duration(struct hap_chip *chip) +{ + int sample_count, sample_duration; + + sample_count = chip->wave_rep_cnt * chip->wave_s_rep_cnt * + chip->wf_samp_len; + sample_duration = sample_count * chip->wave_play_rate_us; + pr_debug("sample_count: %d sample_duration: %d\n", sample_count, + sample_duration); + + return (sample_duration / 1000); +} + +static bool is_sw_lra_auto_resonance_control(struct hap_chip *chip) +{ + if (chip->act_type != HAP_LRA) + return false; + + if (chip->auto_res_err_recovery_hw) + return false; + + /* + * For short pattern in auto mode, we use buffer mode and auto + * resonance is not needed. + */ + if (chip->lra_auto_mode && chip->play_mode == HAP_BUFFER) + return false; + + return true; +} + +#define HAPTICS_BACK_EMF_DELAY_US 20000 +static int qpnp_haptics_auto_res_enable(struct hap_chip *chip, bool enable) +{ + int rc = 0; + u32 delay_us = HAPTICS_BACK_EMF_DELAY_US; + u8 val; + bool auto_res_mode_qwd; + + if (chip->act_type != HAP_LRA) + return 0; + + if (chip->revid->pmic_subtype == PM660_SUBTYPE) + auto_res_mode_qwd = (chip->ares_cfg.auto_res_mode == + HAP_PM660_AUTO_RES_QWD); + else + auto_res_mode_qwd = (chip->ares_cfg.auto_res_mode == + HAP_AUTO_RES_QWD); + + /* + * Do not enable auto resonance if auto mode is enabled and auto + * resonance mode is QWD, meaning long pattern. + */ + if (chip->lra_auto_mode && auto_res_mode_qwd && enable) { + pr_debug("auto_mode enabled, not enabling auto_res\n"); + return 0; + } + + /* + * For auto resonance detection to work properly, sufficient back-emf + * has to be generated. In general, back-emf takes some time to build + * up. When the auto resonance mode is chosen as QWD, high-z will be + * applied for every LRA cycle and hence there won't be enough back-emf + * at the start-up. Hence, the motor needs to vibrate for few LRA cycles + * after the PLAY bit is asserted. Enable the auto resonance after + * 'time_required_to_generate_back_emf_us' is completed. + */ + + if (auto_res_mode_qwd && enable) + usleep_range(delay_us, delay_us + 1); + + val = enable ? AUTO_RES_EN_BIT : 0; + + if (chip->revid->pmic_subtype == PM660_SUBTYPE) + rc = qpnp_haptics_masked_write_reg(chip, + HAP_AUTO_RES_CTRL_REG(chip), + AUTO_RES_EN_BIT, val); + else + rc = qpnp_haptics_masked_write_reg(chip, HAP_TEST2_REG(chip), + AUTO_RES_EN_BIT, val); + if (rc < 0) + return rc; + + if (enable) + chip->status_flags |= AUTO_RESONANCE_ENABLED; + else + chip->status_flags &= ~AUTO_RESONANCE_ENABLED; + + pr_debug("auto_res %sabled\n", enable ? "en" : "dis"); + return rc; +} + +static int qpnp_haptics_update_rate_cfg(struct hap_chip *chip, u16 play_rate) +{ + int rc; + u8 val[2]; + + if (chip->last_rate_cfg == play_rate) { + pr_debug("Same rate_cfg %x\n", play_rate); + return 0; + } + + val[0] = play_rate & HAP_RATE_CFG1_MASK; + val[1] = (play_rate >> HAP_RATE_CFG2_SHIFT) & HAP_RATE_CFG2_MASK; + rc = qpnp_haptics_write_reg(chip, HAP_RATE_CFG1_REG(chip), val, 2); + if (rc < 0) + return rc; + + pr_debug("Play rate code 0x%x\n", play_rate); + chip->last_rate_cfg = play_rate; + return 0; +} + +static void qpnp_haptics_update_lra_frequency(struct hap_chip *chip) +{ + u8 lra_auto_res[2], val; + u32 play_rate_code; + u16 rate_cfg; + int rc; + + rc = qpnp_haptics_read_reg(chip, HAP_LRA_AUTO_RES_LO_REG(chip), + lra_auto_res, 2); + if (rc < 0) { + pr_err("Error in reading LRA_AUTO_RES_LO/HI, rc=%d\n", rc); + return; + } + + play_rate_code = + (lra_auto_res[1] & 0xF0) << 4 | (lra_auto_res[0] & 0xFF); + + pr_debug("lra_auto_res_lo = 0x%x lra_auto_res_hi = 0x%x play_rate_code = 0x%x\n", + lra_auto_res[0], lra_auto_res[1], play_rate_code); + + rc = qpnp_haptics_read_reg(chip, HAP_STATUS_1_REG(chip), &val, 1); + if (rc < 0) + return; + + /* + * If the drive period code read from AUTO_RES_LO and AUTO_RES_HI + * registers is more than the max limit percent variation or less + * than the min limit percent variation specified through DT, then + * auto-resonance is disabled. + */ + + if ((val & AUTO_RES_ERROR_BIT) || + ((play_rate_code <= chip->drive_period_code_min_limit) || + (play_rate_code >= chip->drive_period_code_max_limit))) { + if (val & AUTO_RES_ERROR_BIT) + pr_debug("Auto-resonance error %x\n", val); + else + pr_debug("play rate %x out of bounds [min: 0x%x, max: 0x%x]\n", + play_rate_code, + chip->drive_period_code_min_limit, + chip->drive_period_code_max_limit); + rc = qpnp_haptics_auto_res_enable(chip, false); + if (rc < 0) + pr_debug("Auto-resonance disable failed\n"); + return; + } + + /* + * bits[7:4] of AUTO_RES_HI should be written to bits[3:0] of RATE_CFG2 + */ + lra_auto_res[1] >>= 4; + rate_cfg = lra_auto_res[1] << 8 | lra_auto_res[0]; + rc = qpnp_haptics_update_rate_cfg(chip, rate_cfg); + if (rc < 0) + pr_debug("Error in updating rate_cfg\n"); +} + +#define MAX_RETRIES 5 +#define HAP_CYCLES 4 +static bool is_haptics_idle(struct hap_chip *chip) +{ + unsigned long wait_time_us; + int rc, i; + u8 val; + + rc = qpnp_haptics_read_reg(chip, HAP_STATUS_1_REG(chip), &val, 1); + if (rc < 0) + return false; + + if (!(val & HAP_BUSY_BIT)) + return true; + + if (chip->play_time_ms <= 20) + wait_time_us = chip->play_time_ms * 1000; + else + wait_time_us = chip->wave_play_rate_us * HAP_CYCLES; + + for (i = 0; i < MAX_RETRIES; i++) { + /* wait for play_rate cycles */ + usleep_range(wait_time_us, wait_time_us + 1); + + if (chip->play_mode == HAP_DIRECT || + chip->play_mode == HAP_PWM) + return true; + + rc = qpnp_haptics_read_reg(chip, HAP_STATUS_1_REG(chip), &val, + 1); + if (rc < 0) + return false; + + if (!(val & HAP_BUSY_BIT)) + return true; + } + + if (i >= MAX_RETRIES && (val & HAP_BUSY_BIT)) { + pr_debug("Haptics Busy after %d retries\n", i); + return false; + } + + return true; +} + +static int qpnp_haptics_mod_enable(struct hap_chip *chip, bool enable) +{ + u8 val; + int rc; + + if (chip->module_en == enable) + return 0; + + if (!enable) { + if (!is_haptics_idle(chip)) + pr_debug("Disabling module forcibly\n"); + } + + val = enable ? HAP_EN_BIT : 0; + rc = qpnp_haptics_write_reg(chip, HAP_EN_CTL_REG(chip), &val, 1); + if (rc < 0) + return rc; + + chip->module_en = enable; + return 0; +} + +static int qpnp_haptics_play_control(struct hap_chip *chip, + enum hap_play_control ctrl) +{ + u8 val; + int rc; + + switch (ctrl) { + case HAP_STOP: + val = 0; + break; + case HAP_PAUSE: + val = PAUSE_BIT; + break; + case HAP_PLAY: + val = PLAY_BIT; + break; + default: + return 0; + } + + rc = qpnp_haptics_write_reg(chip, HAP_PLAY_REG(chip), &val, 1); + if (rc < 0) { + pr_err("Error in writing to PLAY_REG, rc=%d\n", rc); + return rc; + } + + pr_debug("haptics play ctrl: %d\n", ctrl); + return rc; +} + +#define AUTO_RES_ERR_POLL_TIME_NS (20 * NSEC_PER_MSEC) +static int qpnp_haptics_play(struct hap_chip *chip, bool enable) +{ + int rc = 0, time_ms = chip->play_time_ms; + + if (chip->perm_disable && enable) + return 0; + + mutex_lock(&chip->play_lock); + + if (enable) { + if (chip->play_mode == HAP_PWM) { + rc = pwm_enable(chip->pwm_data.pwm_dev); + if (rc < 0) { + pr_err("Error in enabling PWM, rc=%d\n", rc); + goto out; + } + } + + rc = qpnp_haptics_auto_res_enable(chip, false); + if (rc < 0) { + pr_err("Error in disabling auto_res, rc=%d\n", rc); + goto out; + } + + rc = qpnp_haptics_mod_enable(chip, true); + if (rc < 0) { + pr_err("Error in enabling module, rc=%d\n", rc); + goto out; + } + + rc = qpnp_haptics_play_control(chip, HAP_PLAY); + if (rc < 0) { + pr_err("Error in enabling play, rc=%d\n", rc); + goto out; + } + + if (chip->play_mode == HAP_BUFFER) + time_ms = get_buffer_mode_duration(chip); + hrtimer_start(&chip->stop_timer, + ktime_set(time_ms / MSEC_PER_SEC, + (time_ms % MSEC_PER_SEC) * NSEC_PER_MSEC), + HRTIMER_MODE_REL); + + rc = qpnp_haptics_auto_res_enable(chip, true); + if (rc < 0) { + pr_err("Error in enabling auto_res, rc=%d\n", rc); + goto out; + } + + if (is_sw_lra_auto_resonance_control(chip)) + hrtimer_start(&chip->auto_res_err_poll_timer, + ktime_set(0, AUTO_RES_ERR_POLL_TIME_NS), + HRTIMER_MODE_REL); + } else { + rc = qpnp_haptics_play_control(chip, HAP_STOP); + if (rc < 0) { + pr_err("Error in disabling play, rc=%d\n", rc); + goto out; + } + + if (is_sw_lra_auto_resonance_control(chip)) { + if (chip->status_flags & AUTO_RESONANCE_ENABLED) + qpnp_haptics_update_lra_frequency(chip); + hrtimer_cancel(&chip->auto_res_err_poll_timer); + } + + if (chip->play_mode == HAP_PWM) + pwm_disable(chip->pwm_data.pwm_dev); + + if (chip->play_mode == HAP_BUFFER) + chip->wave_samp_idx = 0; + } + +out: + mutex_unlock(&chip->play_lock); + return rc; +} + +static void qpnp_haptics_work(struct work_struct *work) +{ + struct hap_chip *chip = container_of(work, struct hap_chip, + haptics_work); + int rc; + bool enable; + + enable = atomic_read(&chip->state); + pr_debug("state: %d\n", enable); + rc = qpnp_haptics_play(chip, enable); + if (rc < 0) + pr_err("Error in %sing haptics, rc=%d\n", + enable ? "play" : "stopp", rc); +} + +static enum hrtimer_restart hap_stop_timer(struct hrtimer *timer) +{ + struct hap_chip *chip = container_of(timer, struct hap_chip, + stop_timer); + + atomic_set(&chip->state, 0); + schedule_work(&chip->haptics_work); + + return HRTIMER_NORESTART; +} + +static enum hrtimer_restart hap_auto_res_err_poll_timer(struct hrtimer *timer) +{ + struct hap_chip *chip = container_of(timer, struct hap_chip, + auto_res_err_poll_timer); + + if (!(chip->status_flags & AUTO_RESONANCE_ENABLED)) + return HRTIMER_NORESTART; + + qpnp_haptics_update_lra_frequency(chip); + hrtimer_forward(&chip->auto_res_err_poll_timer, ktime_get(), + ktime_set(0, AUTO_RES_ERR_POLL_TIME_NS)); + + return HRTIMER_NORESTART; +} + +static int qpnp_haptics_suspend(struct device *dev) +{ + struct hap_chip *chip = dev_get_drvdata(dev); + int rc; + + rc = qpnp_haptics_play(chip, false); + if (rc < 0) + pr_err("Error in stopping haptics, rc=%d\n", rc); + + rc = qpnp_haptics_mod_enable(chip, false); + if (rc < 0) + pr_err("Error in disabling module, rc=%d\n", rc); + + return 0; +} + +static int qpnp_haptics_wave_rep_config(struct hap_chip *chip, + enum hap_rep_type type) +{ + int rc; + u8 val = 0, mask = 0; + + if (type & HAP_WAVE_REPEAT) { + if (chip->wave_rep_cnt < WF_REPEAT_MIN) + chip->wave_rep_cnt = WF_REPEAT_MIN; + else if (chip->wave_rep_cnt > WF_REPEAT_MAX) + chip->wave_rep_cnt = WF_REPEAT_MAX; + mask = WF_REPEAT_MASK; + val = ilog2(chip->wave_rep_cnt) << WF_REPEAT_SHIFT; + } + + if (type & HAP_WAVE_SAMP_REPEAT) { + if (chip->wave_s_rep_cnt < WF_S_REPEAT_MIN) + chip->wave_s_rep_cnt = WF_S_REPEAT_MIN; + else if (chip->wave_s_rep_cnt > WF_S_REPEAT_MAX) + chip->wave_s_rep_cnt = WF_S_REPEAT_MAX; + mask |= WF_S_REPEAT_MASK; + val |= ilog2(chip->wave_s_rep_cnt); + } + + rc = qpnp_haptics_masked_write_reg(chip, HAP_WF_REPEAT_REG(chip), + mask, val); + return rc; +} + +/* configuration api for buffer mode */ +static int qpnp_haptics_buffer_config(struct hap_chip *chip, u32 *wave_samp, + bool overdrive) +{ + u8 buf[HAP_WAVE_SAMP_LEN]; + u32 *ptr; + int rc, i; + + if (wave_samp) { + ptr = wave_samp; + } else { + if (chip->wave_samp_idx >= ARRAY_SIZE(chip->wave_samp)) { + pr_err("Incorrect wave_samp_idx %d\n", + chip->wave_samp_idx); + return -EINVAL; + } + + ptr = &chip->wave_samp[chip->wave_samp_idx]; + } + + /* Don't set override bit in waveform sample for PM660 */ + if (chip->revid->pmic_subtype == PM660_SUBTYPE) + overdrive = false; + + /* Configure WAVE_SAMPLE1 to WAVE_SAMPLE8 register */ + for (i = 0; i < HAP_WAVE_SAMP_LEN; i++) { + buf[i] = ptr[i]; + if (buf[i]) + buf[i] |= (overdrive ? HAP_WF_OVD_BIT : 0); + } + + rc = qpnp_haptics_write_reg(chip, HAP_WF_S1_REG(chip), buf, + HAP_WAVE_SAMP_LEN); + return rc; +} + +/* configuration api for pwm */ +static int qpnp_haptics_pwm_config(struct hap_chip *chip) +{ + u8 val = 0; + int rc; + + if (chip->ext_pwm_freq_khz == 0) + return 0; + + /* Configure the EXTERNAL_PWM register */ + if (chip->ext_pwm_freq_khz <= EXT_PWM_FREQ_25_KHZ) { + chip->ext_pwm_freq_khz = EXT_PWM_FREQ_25_KHZ; + val = 0; + } else if (chip->ext_pwm_freq_khz <= EXT_PWM_FREQ_50_KHZ) { + chip->ext_pwm_freq_khz = EXT_PWM_FREQ_50_KHZ; + val = 1; + } else if (chip->ext_pwm_freq_khz <= EXT_PWM_FREQ_75_KHZ) { + chip->ext_pwm_freq_khz = EXT_PWM_FREQ_75_KHZ; + val = 2; + } else { + chip->ext_pwm_freq_khz = EXT_PWM_FREQ_100_KHZ; + val = 3; + } + + rc = qpnp_haptics_masked_write_reg(chip, HAP_EXT_PWM_REG(chip), + EXT_PWM_FREQ_SEL_MASK, val); + if (rc < 0) + return rc; + + if (chip->ext_pwm_dtest_line < 0 || + chip->ext_pwm_dtest_line > PWM_MAX_DTEST_LINES) { + pr_err("invalid dtest line\n"); + return -EINVAL; + } + + if (chip->ext_pwm_dtest_line > 0) { + /* disable auto res for PWM mode */ + val = chip->ext_pwm_dtest_line << HAP_EXT_PWM_DTEST_SHIFT; + rc = qpnp_haptics_masked_write_reg(chip, HAP_TEST2_REG(chip), + HAP_EXT_PWM_DTEST_MASK | AUTO_RES_EN_BIT, val); + if (rc < 0) + return rc; + } + + rc = pwm_config(chip->pwm_data.pwm_dev, + chip->pwm_data.duty_us * NSEC_PER_USEC, + chip->pwm_data.period_us * NSEC_PER_USEC); + if (rc < 0) { + pr_err("pwm_config failed, rc=%d\n", rc); + return rc; + } + + return 0; +} + +static int qpnp_haptics_lra_auto_res_config(struct hap_chip *chip, + struct hap_lra_ares_param *tmp_cfg) +{ + struct hap_lra_ares_param *ares_cfg; + int rc; + u8 val = 0, mask = 0; + + /* disable auto resonance for ERM */ + if (chip->act_type == HAP_ERM) { + val = 0x00; + rc = qpnp_haptics_write_reg(chip, HAP_LRA_AUTO_RES_REG(chip), + &val, 1); + return rc; + } + + if (chip->auto_res_err_recovery_hw) { + rc = qpnp_haptics_masked_write_reg(chip, + HAP_AUTO_RES_CTRL_REG(chip), + AUTO_RES_ERR_RECOVERY_BIT, AUTO_RES_ERR_RECOVERY_BIT); + if (rc < 0) + return rc; + } + + if (tmp_cfg) + ares_cfg = tmp_cfg; + else + ares_cfg = &chip->ares_cfg; + + if (ares_cfg->lra_res_cal_period < HAP_RES_CAL_PERIOD_MIN) + ares_cfg->lra_res_cal_period = HAP_RES_CAL_PERIOD_MIN; + + if (chip->revid->pmic_subtype == PM660_SUBTYPE) { + if (ares_cfg->lra_res_cal_period > + HAP_PM660_RES_CAL_PERIOD_MAX) + ares_cfg->lra_res_cal_period = + HAP_PM660_RES_CAL_PERIOD_MAX; + + if (ares_cfg->auto_res_mode == HAP_PM660_AUTO_RES_QWD) + ares_cfg->lra_res_cal_period = 0; + + if (ares_cfg->lra_res_cal_period) + val = ilog2(ares_cfg->lra_res_cal_period / + HAP_RES_CAL_PERIOD_MIN) + 1; + } else { + if (ares_cfg->lra_res_cal_period > HAP_RES_CAL_PERIOD_MAX) + ares_cfg->lra_res_cal_period = + HAP_RES_CAL_PERIOD_MAX; + + if (ares_cfg->lra_res_cal_period) + val = ilog2(ares_cfg->lra_res_cal_period / + HAP_RES_CAL_PERIOD_MIN); + } + + if (chip->revid->pmic_subtype == PM660_SUBTYPE) { + val |= ares_cfg->auto_res_mode << PM660_AUTO_RES_MODE_SHIFT; + mask = PM660_AUTO_RES_MODE_BIT; + val |= ares_cfg->lra_high_z << PM660_CAL_DURATION_SHIFT; + mask |= PM660_CAL_DURATION_MASK; + if (ares_cfg->lra_qwd_drive_duration != -EINVAL) { + val |= ares_cfg->lra_qwd_drive_duration << + PM660_QWD_DRIVE_DURATION_SHIFT; + mask |= PM660_QWD_DRIVE_DURATION_BIT; + } + if (ares_cfg->calibrate_at_eop != -EINVAL) { + val |= ares_cfg->calibrate_at_eop << + PM660_CAL_EOP_SHIFT; + mask |= PM660_CAL_EOP_BIT; + } + mask |= PM660_LRA_RES_CAL_MASK; + } else { + val |= (ares_cfg->auto_res_mode << LRA_AUTO_RES_MODE_SHIFT); + val |= (ares_cfg->lra_high_z << LRA_HIGH_Z_SHIFT); + mask = LRA_AUTO_RES_MODE_MASK | LRA_HIGH_Z_MASK | + LRA_RES_CAL_MASK; + } + + pr_debug("mode: %d hi_z period: %d cal_period: %d\n", + ares_cfg->auto_res_mode, ares_cfg->lra_high_z, + ares_cfg->lra_res_cal_period); + + rc = qpnp_haptics_masked_write_reg(chip, HAP_LRA_AUTO_RES_REG(chip), + mask, val); + return rc; +} + +/* configuration api for play mode */ +static int qpnp_haptics_play_mode_config(struct hap_chip *chip) +{ + u8 val = 0; + int rc; + + if (!is_haptics_idle(chip)) + return -EBUSY; + + val = chip->play_mode << HAP_WF_SOURCE_SHIFT; + rc = qpnp_haptics_masked_write_reg(chip, HAP_SEL_REG(chip), + HAP_WF_SOURCE_MASK, val); + if (!rc) { + if (chip->play_mode == HAP_BUFFER && !chip->play_irq_en) { + enable_irq(chip->play_irq); + chip->play_irq_en = true; + } else if (chip->play_mode != HAP_BUFFER && chip->play_irq_en) { + disable_irq(chip->play_irq); + chip->play_irq_en = false; + } + } + return rc; +} + +/* configuration api for max voltage */ +static int qpnp_haptics_vmax_config(struct hap_chip *chip, int vmax_mv, + bool overdrive) +{ + u8 val = 0; + int rc; + + if (vmax_mv < 0) + return -EINVAL; + + /* Allow setting override bit in VMAX_CFG only for PM660 */ + if (chip->revid->pmic_subtype != PM660_SUBTYPE) + overdrive = false; + + if (vmax_mv < HAP_VMAX_MIN_MV) + vmax_mv = HAP_VMAX_MIN_MV; + else if (vmax_mv > HAP_VMAX_MAX_MV) + vmax_mv = HAP_VMAX_MAX_MV; + + val = DIV_ROUND_CLOSEST(vmax_mv, HAP_VMAX_MIN_MV); + val <<= HAP_VMAX_SHIFT; + if (overdrive) + val |= HAP_VMAX_OVD_BIT; + + rc = qpnp_haptics_masked_write_reg(chip, HAP_VMAX_CFG_REG(chip), + HAP_VMAX_MASK | HAP_VMAX_OVD_BIT, val); + return rc; +} + +/* configuration api for ilim */ +static int qpnp_haptics_ilim_config(struct hap_chip *chip) +{ + int rc; + + if (chip->ilim_ma < HAP_ILIM_400_MA) + chip->ilim_ma = HAP_ILIM_400_MA; + else if (chip->ilim_ma > HAP_ILIM_800_MA) + chip->ilim_ma = HAP_ILIM_800_MA; + + rc = qpnp_haptics_masked_write_reg(chip, HAP_ILIM_CFG_REG(chip), + HAP_ILIM_SEL_MASK, chip->ilim_ma); + return rc; +} + +/* configuration api for short circuit debounce */ +static int qpnp_haptics_sc_deb_config(struct hap_chip *chip) +{ + u8 val = 0; + int rc; + + if (chip->sc_deb_cycles < HAP_SC_DEB_CYCLES_MIN) + chip->sc_deb_cycles = HAP_SC_DEB_CYCLES_MIN; + else if (chip->sc_deb_cycles > HAP_SC_DEB_CYCLES_MAX) + chip->sc_deb_cycles = HAP_SC_DEB_CYCLES_MAX; + + if (chip->sc_deb_cycles != HAP_SC_DEB_CYCLES_MIN) + val = ilog2(chip->sc_deb_cycles / + HAP_DEF_SC_DEB_CYCLES) + 1; + else + val = HAP_SC_DEB_CYCLES_MIN; + + rc = qpnp_haptics_masked_write_reg(chip, HAP_SC_DEB_REG(chip), + HAP_SC_DEB_MASK, val); + + return rc; +} + +static int qpnp_haptics_brake_config(struct hap_chip *chip, u32 *brake_pat) +{ + int rc, i; + u32 temp, *ptr; + u8 val; + + /* Configure BRAKE register */ + rc = qpnp_haptics_masked_write_reg(chip, HAP_EN_CTL2_REG(chip), + BRAKE_EN_BIT, (u8)chip->en_brake); + if (rc < 0) + return rc; + + /* If braking is not enabled, skip configuring brake pattern */ + if (!chip->en_brake) + return 0; + + if (!brake_pat) + ptr = chip->brake_pat; + else + ptr = brake_pat; + + for (i = HAP_BRAKE_PAT_LEN - 1, val = 0; i >= 0; i--) { + ptr[i] &= HAP_BRAKE_PAT_MASK; + temp = i << 1; + val |= ptr[i] << temp; + } + + rc = qpnp_haptics_write_reg(chip, HAP_BRAKE_REG(chip), &val, 1); + if (rc < 0) + return rc; + + return 0; +} + +static int qpnp_haptics_auto_mode_config(struct hap_chip *chip, int time_ms) +{ + struct hap_lra_ares_param ares_cfg; + enum hap_mode old_play_mode; + u8 old_ares_mode; + u32 brake_pat[HAP_BRAKE_PAT_LEN] = {0}; + u32 wave_samp[HAP_WAVE_SAMP_LEN] = {0}; + int rc, vmax_mv; + + if (!chip->lra_auto_mode) + return false; + + /* For now, this is for LRA only */ + if (chip->act_type == HAP_ERM) + return 0; + + old_ares_mode = chip->ares_cfg.auto_res_mode; + old_play_mode = chip->play_mode; + pr_debug("auto_mode, time_ms: %d\n", time_ms); + if (time_ms <= 20) { + wave_samp[0] = HAP_WF_SAMP_MAX; + wave_samp[1] = HAP_WF_SAMP_MAX; + chip->wf_samp_len = 2; + if (time_ms > 15) { + wave_samp[2] = HAP_WF_SAMP_MAX; + chip->wf_samp_len = 3; + } + + /* short pattern */ + rc = qpnp_haptics_parse_buffer_dt(chip); + if (!rc) { + rc = qpnp_haptics_wave_rep_config(chip, + HAP_WAVE_REPEAT | HAP_WAVE_SAMP_REPEAT); + if (rc < 0) { + pr_err("Error in configuring wave_rep config %d\n", + rc); + return rc; + } + + rc = qpnp_haptics_buffer_config(chip, wave_samp, true); + if (rc < 0) { + pr_err("Error in configuring buffer mode %d\n", + rc); + return rc; + } + } + + ares_cfg.lra_high_z = HAP_LRA_HIGH_Z_OPT1; + ares_cfg.lra_res_cal_period = HAP_RES_CAL_PERIOD_MIN; + if (chip->revid->pmic_subtype == PM660_SUBTYPE) { + ares_cfg.auto_res_mode = HAP_PM660_AUTO_RES_QWD; + ares_cfg.lra_qwd_drive_duration = 0; + ares_cfg.calibrate_at_eop = 0; + } else { + ares_cfg.auto_res_mode = HAP_AUTO_RES_ZXD_EOP; + ares_cfg.lra_qwd_drive_duration = -EINVAL; + ares_cfg.calibrate_at_eop = -EINVAL; + } + + vmax_mv = HAP_VMAX_MAX_MV; + rc = qpnp_haptics_vmax_config(chip, vmax_mv, true); + if (rc < 0) + return rc; + + /* enable play_irq for buffer mode */ + if (chip->play_irq >= 0 && !chip->play_irq_en) { + enable_irq(chip->play_irq); + chip->play_irq_en = true; + } + + brake_pat[0] = BRAKE_VMAX; + chip->play_mode = HAP_BUFFER; + chip->wave_shape = HAP_WAVE_SQUARE; + } else { + /* long pattern */ + ares_cfg.lra_high_z = HAP_LRA_HIGH_Z_OPT1; + if (chip->revid->pmic_subtype == PM660_SUBTYPE) { + ares_cfg.auto_res_mode = HAP_PM660_AUTO_RES_ZXD; + ares_cfg.lra_res_cal_period = + HAP_PM660_RES_CAL_PERIOD_MAX; + ares_cfg.lra_qwd_drive_duration = 0; + ares_cfg.calibrate_at_eop = 1; + } else { + ares_cfg.auto_res_mode = HAP_AUTO_RES_QWD; + ares_cfg.lra_res_cal_period = HAP_RES_CAL_PERIOD_MAX; + ares_cfg.lra_qwd_drive_duration = -EINVAL; + ares_cfg.calibrate_at_eop = -EINVAL; + } + + vmax_mv = chip->vmax_mv; + rc = qpnp_haptics_vmax_config(chip, vmax_mv, false); + if (rc < 0) + return rc; + + /* enable play_irq for direct mode */ + if (chip->play_irq >= 0 && chip->play_irq_en) { + disable_irq(chip->play_irq); + chip->play_irq_en = false; + } + + chip->play_mode = HAP_DIRECT; + chip->wave_shape = HAP_WAVE_SINE; + } + + chip->ares_cfg.auto_res_mode = ares_cfg.auto_res_mode; + rc = qpnp_haptics_lra_auto_res_config(chip, &ares_cfg); + if (rc < 0) { + chip->ares_cfg.auto_res_mode = old_ares_mode; + return rc; + } + + rc = qpnp_haptics_play_mode_config(chip); + if (rc < 0) { + chip->play_mode = old_play_mode; + return rc; + } + + rc = qpnp_haptics_brake_config(chip, brake_pat); + if (rc < 0) + return rc; + + rc = qpnp_haptics_masked_write_reg(chip, HAP_CFG2_REG(chip), + HAP_LRA_RES_TYPE_MASK, chip->wave_shape); + if (rc < 0) + return rc; + + return 0; +} + +static irqreturn_t qpnp_haptics_play_irq_handler(int irq, void *data) +{ + struct hap_chip *chip = data; + int rc; + + if (chip->play_mode != HAP_BUFFER) + goto irq_handled; + + if (chip->wave_samp[chip->wave_samp_idx + HAP_WAVE_SAMP_LEN] > 0) { + chip->wave_samp_idx += HAP_WAVE_SAMP_LEN; + if (chip->wave_samp_idx >= ARRAY_SIZE(chip->wave_samp)) { + pr_debug("Samples over\n"); + } else { + pr_debug("moving to next sample set %d\n", + chip->wave_samp_idx); + + /* Moving to next set of wave sample */ + rc = qpnp_haptics_buffer_config(chip, NULL, false); + if (rc < 0) { + pr_err("Error in configuring buffer, rc=%d\n", + rc); + goto irq_handled; + } + } + } + +irq_handled: + return IRQ_HANDLED; +} + +#define SC_MAX_COUNT 5 +#define SC_COUNT_RST_DELAY_US 1000000 +static irqreturn_t qpnp_haptics_sc_irq_handler(int irq, void *data) +{ + struct hap_chip *chip = data; + int rc; + u8 val; + s64 sc_delta_time_us; + ktime_t temp; + + rc = qpnp_haptics_read_reg(chip, HAP_STATUS_1_REG(chip), &val, 1); + if (rc < 0) + goto irq_handled; + + if (!(val & SC_FLAG_BIT)) { + chip->sc_count = 0; + goto irq_handled; + } + + pr_debug("SC irq fired\n"); + temp = ktime_get(); + sc_delta_time_us = ktime_us_delta(temp, chip->last_sc_time); + chip->last_sc_time = temp; + + if (sc_delta_time_us > SC_COUNT_RST_DELAY_US) + chip->sc_count = 0; + else + chip->sc_count++; + + val = SC_CLR_BIT; + rc = qpnp_haptics_write_reg(chip, HAP_SC_CLR_REG(chip), &val, 1); + if (rc < 0) { + pr_err("Error in writing to SC_CLR_REG, rc=%d\n", rc); + goto irq_handled; + } + + /* Permanently disable module if SC condition persists */ + if (chip->sc_count > SC_MAX_COUNT) { + pr_crit("SC persists, permanently disabling haptics\n"); + rc = qpnp_haptics_mod_enable(chip, false); + if (rc < 0) { + pr_err("Error in disabling module, rc=%d\n", rc); + goto irq_handled; + } + chip->perm_disable = true; + } + +irq_handled: + return IRQ_HANDLED; +} + +/* All sysfs show/store functions below */ + +#define HAP_STR_SIZE 128 +static int parse_string(const char *in_buf, char *out_buf) +{ + int i; + + if (snprintf(out_buf, HAP_STR_SIZE, "%s", in_buf) > HAP_STR_SIZE) + return -EINVAL; + + for (i = 0; i < strlen(out_buf); i++) { + if (out_buf[i] == ' ' || out_buf[i] == '\n' || + out_buf[i] == '\t') { + out_buf[i] = '\0'; + break; + } + } + + return 0; +} + +static ssize_t qpnp_haptics_show_state(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct hap_chip *chip = container_of(cdev, struct hap_chip, cdev); + + return snprintf(buf, PAGE_SIZE, "%d\n", chip->module_en); +} + +static ssize_t qpnp_haptics_store_state(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + + /* At present, nothing to do with setting state */ + return count; +} + +static ssize_t qpnp_haptics_show_duration(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct hap_chip *chip = container_of(cdev, struct hap_chip, cdev); + ktime_t time_rem; + s64 time_us = 0; + + if (hrtimer_active(&chip->stop_timer)) { + time_rem = hrtimer_get_remaining(&chip->stop_timer); + time_us = ktime_to_us(time_rem); + } + + return snprintf(buf, PAGE_SIZE, "%lld\n", div_s64(time_us, 1000)); +} + +static ssize_t qpnp_haptics_store_duration(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct hap_chip *chip = container_of(cdev, struct hap_chip, cdev); + u32 val; + int rc; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return rc; + + /* setting 0 on duration is NOP for now */ + if (val <= 0) + return count; + + if (val > chip->max_play_time_ms) + return -EINVAL; + + mutex_lock(&chip->param_lock); + rc = qpnp_haptics_auto_mode_config(chip, val); + if (rc < 0) { + pr_err("Unable to do auto mode config\n"); + mutex_unlock(&chip->param_lock); + return rc; + } + + chip->play_time_ms = val; + mutex_unlock(&chip->param_lock); + + return count; +} + +static ssize_t qpnp_haptics_show_activate(struct device *dev, + struct device_attribute *attr, char *buf) +{ + /* For now nothing to show */ + return snprintf(buf, PAGE_SIZE, "%d\n", 0); +} + +static ssize_t qpnp_haptics_store_activate(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct hap_chip *chip = container_of(cdev, struct hap_chip, cdev); + u32 val; + int rc; + + rc = kstrtouint(buf, 0, &val); + if (rc < 0) + return rc; + + if (val != 0 && val != 1) + return count; + + if (val) { + hrtimer_cancel(&chip->stop_timer); + if (is_sw_lra_auto_resonance_control(chip)) + hrtimer_cancel(&chip->auto_res_err_poll_timer); + cancel_work_sync(&chip->haptics_work); + + atomic_set(&chip->state, 1); + schedule_work(&chip->haptics_work); + } else { + rc = qpnp_haptics_mod_enable(chip, false); + if (rc < 0) { + pr_err("Error in disabling module, rc=%d\n", rc); + return rc; + } + } + + return count; +} + +static ssize_t qpnp_haptics_show_play_mode(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct hap_chip *chip = container_of(cdev, struct hap_chip, cdev); + char *str; + + if (chip->play_mode == HAP_BUFFER) + str = "buffer"; + else if (chip->play_mode == HAP_DIRECT) + str = "direct"; + else if (chip->play_mode == HAP_AUDIO) + str = "audio"; + else if (chip->play_mode == HAP_PWM) + str = "pwm"; + else + return -EINVAL; + + return snprintf(buf, PAGE_SIZE, "%s\n", str); +} + +static ssize_t qpnp_haptics_store_play_mode(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct hap_chip *chip = container_of(cdev, struct hap_chip, cdev); + char str[HAP_STR_SIZE + 1]; + int rc = 0, temp, old_mode; + + rc = parse_string(buf, str); + if (rc < 0) + return rc; + + if (strcmp(str, "buffer") == 0) + temp = HAP_BUFFER; + else if (strcmp(str, "direct") == 0) + temp = HAP_DIRECT; + else if (strcmp(str, "audio") == 0) + temp = HAP_AUDIO; + else if (strcmp(str, "pwm") == 0) + temp = HAP_PWM; + else + return -EINVAL; + + if (temp == chip->play_mode) + return count; + + if (temp == HAP_BUFFER) { + rc = qpnp_haptics_parse_buffer_dt(chip); + if (!rc) { + rc = qpnp_haptics_wave_rep_config(chip, + HAP_WAVE_REPEAT | HAP_WAVE_SAMP_REPEAT); + if (rc < 0) { + pr_err("Error in configuring wave_rep config %d\n", + rc); + return rc; + } + } + + rc = qpnp_haptics_buffer_config(chip, NULL, true); + } else if (temp == HAP_PWM) { + rc = qpnp_haptics_parse_pwm_dt(chip); + if (!rc) + rc = qpnp_haptics_pwm_config(chip); + } + + if (rc < 0) + return rc; + + rc = qpnp_haptics_mod_enable(chip, false); + if (rc < 0) + return rc; + + old_mode = chip->play_mode; + chip->play_mode = temp; + rc = qpnp_haptics_play_mode_config(chip); + if (rc < 0) { + chip->play_mode = old_mode; + return rc; + } + + if (chip->play_mode == HAP_AUDIO) { + rc = qpnp_haptics_mod_enable(chip, true); + if (rc < 0) { + chip->play_mode = old_mode; + return rc; + } + } + + return count; +} + +static ssize_t qpnp_haptics_show_wf_samp(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct hap_chip *chip = container_of(cdev, struct hap_chip, cdev); + char str[HAP_STR_SIZE + 1]; + char *ptr = str; + int i, len = 0; + + for (i = 0; i < ARRAY_SIZE(chip->wave_samp); i++) { + len = scnprintf(ptr, HAP_STR_SIZE, "%x ", chip->wave_samp[i]); + ptr += len; + } + ptr[len] = '\0'; + + return snprintf(buf, PAGE_SIZE, "%s\n", str); +} + +static ssize_t qpnp_haptics_store_wf_samp(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct hap_chip *chip = container_of(cdev, struct hap_chip, cdev); + u8 samp[HAP_WAVE_SAMP_SET_LEN] = {0}; + int bytes_read, rc; + unsigned int data, pos = 0, i = 0; + + while (pos < count && i < ARRAY_SIZE(samp) && + sscanf(buf + pos, "%x%n", &data, &bytes_read) == 1) { + /* bit 0 is not used in WF_Sx */ + samp[i++] = data & GENMASK(7, 1); + pos += bytes_read; + } + + chip->wf_samp_len = i; + for (i = 0; i < ARRAY_SIZE(chip->wave_samp); i++) + chip->wave_samp[i] = samp[i]; + + rc = qpnp_haptics_buffer_config(chip, NULL, false); + if (rc < 0) { + pr_err("Error in configuring buffer mode %d\n", rc); + return rc; + } + + return count; +} + +static ssize_t qpnp_haptics_show_wf_rep_count(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct hap_chip *chip = container_of(cdev, struct hap_chip, cdev); + + return snprintf(buf, PAGE_SIZE, "%d\n", chip->wave_rep_cnt); +} + +static ssize_t qpnp_haptics_store_wf_rep_count(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct hap_chip *chip = container_of(cdev, struct hap_chip, cdev); + int data, rc, old_wave_rep_cnt; + + rc = kstrtoint(buf, 10, &data); + if (rc < 0) + return rc; + + old_wave_rep_cnt = chip->wave_rep_cnt; + chip->wave_rep_cnt = data; + rc = qpnp_haptics_wave_rep_config(chip, HAP_WAVE_REPEAT); + if (rc < 0) { + chip->wave_rep_cnt = old_wave_rep_cnt; + return rc; + } + + return count; +} + +static ssize_t qpnp_haptics_show_wf_s_rep_count(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct hap_chip *chip = container_of(cdev, struct hap_chip, cdev); + + return snprintf(buf, PAGE_SIZE, "%d\n", chip->wave_s_rep_cnt); +} + +static ssize_t qpnp_haptics_store_wf_s_rep_count(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct hap_chip *chip = container_of(cdev, struct hap_chip, cdev); + int data, rc, old_wave_s_rep_cnt; + + rc = kstrtoint(buf, 10, &data); + if (rc < 0) + return rc; + + old_wave_s_rep_cnt = chip->wave_s_rep_cnt; + chip->wave_s_rep_cnt = data; + rc = qpnp_haptics_wave_rep_config(chip, HAP_WAVE_SAMP_REPEAT); + if (rc < 0) { + chip->wave_s_rep_cnt = old_wave_s_rep_cnt; + return rc; + } + + return count; +} + +static ssize_t qpnp_haptics_show_vmax(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct hap_chip *chip = container_of(cdev, struct hap_chip, cdev); + + return snprintf(buf, PAGE_SIZE, "%d\n", chip->vmax_mv); +} + +static ssize_t qpnp_haptics_store_vmax(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct hap_chip *chip = container_of(cdev, struct hap_chip, cdev); + int data, rc, old_vmax_mv; + + rc = kstrtoint(buf, 10, &data); + if (rc < 0) + return rc; + + old_vmax_mv = chip->vmax_mv; + chip->vmax_mv = data; + rc = qpnp_haptics_vmax_config(chip, chip->vmax_mv, false); + if (rc < 0) { + chip->vmax_mv = old_vmax_mv; + return rc; + } + + return count; +} + +static ssize_t qpnp_haptics_show_lra_auto_mode(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct hap_chip *chip = container_of(cdev, struct hap_chip, cdev); + + return snprintf(buf, PAGE_SIZE, "%d\n", chip->lra_auto_mode); +} + +static ssize_t qpnp_haptics_store_lra_auto_mode(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct hap_chip *chip = container_of(cdev, struct hap_chip, cdev); + int rc, data; + + rc = kstrtoint(buf, 10, &data); + if (rc < 0) + return rc; + + if (data != 0 && data != 1) + return count; + + chip->lra_auto_mode = !!data; + return count; +} + +static struct device_attribute qpnp_haptics_attrs[] = { + __ATTR(state, 0664, qpnp_haptics_show_state, qpnp_haptics_store_state), + __ATTR(duration, 0664, qpnp_haptics_show_duration, + qpnp_haptics_store_duration), + __ATTR(activate, 0664, qpnp_haptics_show_activate, + qpnp_haptics_store_activate), + __ATTR(play_mode, 0664, qpnp_haptics_show_play_mode, + qpnp_haptics_store_play_mode), + __ATTR(wf_samp, 0664, qpnp_haptics_show_wf_samp, + qpnp_haptics_store_wf_samp), + __ATTR(wf_rep_count, 0664, qpnp_haptics_show_wf_rep_count, + qpnp_haptics_store_wf_rep_count), + __ATTR(wf_s_rep_count, 0664, qpnp_haptics_show_wf_s_rep_count, + qpnp_haptics_store_wf_s_rep_count), + __ATTR(vmax_mv, 0664, qpnp_haptics_show_vmax, qpnp_haptics_store_vmax), + __ATTR(lra_auto_mode, 0664, qpnp_haptics_show_lra_auto_mode, + qpnp_haptics_store_lra_auto_mode), +}; + +/* Dummy functions for brightness */ +static +enum led_brightness qpnp_haptics_brightness_get(struct led_classdev *cdev) +{ + return 0; +} + +static void qpnp_haptics_brightness_set(struct led_classdev *cdev, + enum led_brightness level) +{ +} + +static int qpnp_haptics_config(struct hap_chip *chip) +{ + u8 rc_clk_err_deci_pct; + u16 play_rate = 0; + int rc; + + /* Configure the CFG1 register for actuator type */ + rc = qpnp_haptics_masked_write_reg(chip, HAP_CFG1_REG(chip), + HAP_ACT_TYPE_MASK, chip->act_type); + if (rc < 0) + return rc; + + /* Configure auto resonance parameters */ + rc = qpnp_haptics_lra_auto_res_config(chip, NULL); + if (rc < 0) + return rc; + + /* Configure the PLAY MODE register */ + rc = qpnp_haptics_play_mode_config(chip); + if (rc < 0) + return rc; + + /* Configure the VMAX register */ + rc = qpnp_haptics_vmax_config(chip, chip->vmax_mv, false); + if (rc < 0) + return rc; + + /* Configure the ILIM register */ + rc = qpnp_haptics_ilim_config(chip); + if (rc < 0) + return rc; + + /* Configure the short circuit debounce register */ + rc = qpnp_haptics_sc_deb_config(chip); + if (rc < 0) + return rc; + + /* Configure the WAVE SHAPE register */ + rc = qpnp_haptics_masked_write_reg(chip, HAP_CFG2_REG(chip), + HAP_LRA_RES_TYPE_MASK, chip->wave_shape); + if (rc < 0) + return rc; + + play_rate = chip->wave_play_rate_us / HAP_RATE_CFG_STEP_US; + + /* + * The frequency of 19.2 MHz RC clock is subject to variation. Currently + * some PMI chips have MISC_TRIM_ERROR_RC19P2_CLK register present in + * MISC peripheral. This register holds the trim error of RC clock. + */ + if (chip->act_type == HAP_LRA && chip->misc_clk_trim_error_reg) { + /* + * Error is available in bits[3:0] and each LSB is 0.7%. + * Bit 7 is the sign bit for error code. If it is set, then a + * negative error correction needs to be made. Otherwise, a + * positive error correction needs to be made. + */ + rc_clk_err_deci_pct = (chip->clk_trim_error_code & 0x0F) * 7; + if (chip->clk_trim_error_code & BIT(7)) + play_rate = (play_rate * + (1000 - rc_clk_err_deci_pct)) / 1000; + else + play_rate = (play_rate * + (1000 + rc_clk_err_deci_pct)) / 1000; + + pr_debug("TRIM register = 0x%x, play_rate=%d\n", + chip->clk_trim_error_code, play_rate); + } + + /* + * Configure RATE_CFG1 and RATE_CFG2 registers. + * Note: For ERM these registers act as play rate and + * for LRA these represent resonance period + */ + rc = qpnp_haptics_update_rate_cfg(chip, play_rate); + if (chip->act_type == HAP_LRA) { + chip->drive_period_code_max_limit = (play_rate * + (100 + chip->drive_period_code_max_var_pct)) / 100; + chip->drive_period_code_min_limit = (play_rate * + (100 - chip->drive_period_code_min_var_pct)) / 100; + pr_debug("Drive period code max limit %x min limit %x\n", + chip->drive_period_code_max_limit, + chip->drive_period_code_min_limit); + } + + rc = qpnp_haptics_brake_config(chip, NULL); + if (rc < 0) + return rc; + + if (chip->play_mode == HAP_BUFFER) { + rc = qpnp_haptics_wave_rep_config(chip, + HAP_WAVE_REPEAT | HAP_WAVE_SAMP_REPEAT); + if (rc < 0) + return rc; + + rc = qpnp_haptics_buffer_config(chip, NULL, false); + } else if (chip->play_mode == HAP_PWM) { + rc = qpnp_haptics_pwm_config(chip); + } else if (chip->play_mode == HAP_AUDIO) { + rc = qpnp_haptics_mod_enable(chip, true); + } + + if (rc < 0) + return rc; + + /* setup play irq */ + if (chip->play_irq >= 0) { + rc = devm_request_threaded_irq(&chip->pdev->dev, chip->play_irq, + NULL, qpnp_haptics_play_irq_handler, IRQF_ONESHOT, + "haptics_play_irq", chip); + if (rc < 0) { + pr_err("Unable to request play(%d) IRQ(err:%d)\n", + chip->play_irq, rc); + return rc; + } + + /* use play_irq only for buffer mode */ + if (chip->play_mode != HAP_BUFFER) { + disable_irq(chip->play_irq); + chip->play_irq_en = false; + } + } + + /* setup short circuit irq */ + if (chip->sc_irq >= 0) { + rc = devm_request_threaded_irq(&chip->pdev->dev, chip->sc_irq, + NULL, qpnp_haptics_sc_irq_handler, IRQF_ONESHOT, + "haptics_sc_irq", chip); + if (rc < 0) { + pr_err("Unable to request sc(%d) IRQ(err:%d)\n", + chip->sc_irq, rc); + return rc; + } + } + + return rc; +} + +static int qpnp_haptics_parse_buffer_dt(struct hap_chip *chip) +{ + struct device_node *node = chip->pdev->dev.of_node; + u32 temp; + int rc, i, wf_samp_len; + + if (chip->wave_rep_cnt > 0 || chip->wave_s_rep_cnt > 0) + return 0; + + chip->wave_rep_cnt = WF_REPEAT_MIN; + rc = of_property_read_u32(node, "qcom,wave-rep-cnt", &temp); + if (!rc) { + chip->wave_rep_cnt = temp; + } else if (rc != -EINVAL) { + pr_err("Unable to read rep cnt rc=%d\n", rc); + return rc; + } + + chip->wave_s_rep_cnt = WF_S_REPEAT_MIN; + rc = of_property_read_u32(node, + "qcom,wave-samp-rep-cnt", &temp); + if (!rc) { + chip->wave_s_rep_cnt = temp; + } else if (rc != -EINVAL) { + pr_err("Unable to read samp rep cnt rc=%d\n", rc); + return rc; + } + + wf_samp_len = of_property_count_elems_of_size(node, + "qcom,wave-samples", sizeof(u32)); + if (wf_samp_len > 0) { + if (wf_samp_len > HAP_WAVE_SAMP_SET_LEN) { + pr_err("Invalid length for wave samples\n"); + return -EINVAL; + } + + rc = of_property_read_u32_array(node, "qcom,wave-samples", + chip->wave_samp, wf_samp_len); + if (rc < 0) { + pr_err("Error in reading qcom,wave-samples, rc=%d\n", + rc); + return rc; + } + } else { + /* Use default values */ + for (i = 0; i < HAP_WAVE_SAMP_LEN; i++) + chip->wave_samp[i] = HAP_WF_SAMP_MAX; + + wf_samp_len = HAP_WAVE_SAMP_LEN; + } + chip->wf_samp_len = wf_samp_len; + + return 0; +} + +static int qpnp_haptics_parse_pwm_dt(struct hap_chip *chip) +{ + struct device_node *node = chip->pdev->dev.of_node; + u32 temp; + int rc; + + if (chip->pwm_data.period_us > 0 && chip->pwm_data.duty_us > 0) + return 0; + + chip->pwm_data.pwm_dev = of_pwm_get(node, NULL); + if (IS_ERR(chip->pwm_data.pwm_dev)) { + rc = PTR_ERR(chip->pwm_data.pwm_dev); + pr_err("Cannot get PWM device rc=%d\n", rc); + chip->pwm_data.pwm_dev = NULL; + return rc; + } + + rc = of_property_read_u32(node, "qcom,period-us", &temp); + if (!rc) { + chip->pwm_data.period_us = temp; + } else { + pr_err("Cannot read PWM period rc=%d\n", rc); + return rc; + } + + rc = of_property_read_u32(node, "qcom,duty-us", &temp); + if (!rc) { + chip->pwm_data.duty_us = temp; + } else { + pr_err("Cannot read PWM duty rc=%d\n", rc); + return rc; + } + + rc = of_property_read_u32(node, "qcom,ext-pwm-dtest-line", &temp); + if (!rc) + chip->ext_pwm_dtest_line = temp; + + rc = of_property_read_u32(node, "qcom,ext-pwm-freq-khz", &temp); + if (!rc) { + chip->ext_pwm_freq_khz = temp; + } else if (rc != -EINVAL) { + pr_err("Unable to read ext pwm freq rc=%d\n", rc); + return rc; + } + + return 0; +} + +static int qpnp_haptics_parse_dt(struct hap_chip *chip) +{ + struct device_node *node = chip->pdev->dev.of_node; + struct device_node *revid_node, *misc_node; + const char *temp_str; + int rc, temp; + + rc = of_property_read_u32(node, "reg", &temp); + if (rc < 0) { + pr_err("Couldn't find reg in node = %s rc = %d\n", + node->full_name, rc); + return rc; + } + + if (temp <= 0) { + pr_err("Invalid base address %x\n", temp); + return -EINVAL; + } + chip->base = (u16)temp; + + revid_node = of_parse_phandle(node, "qcom,pmic-revid", 0); + if (!revid_node) { + pr_err("Missing qcom,pmic-revid property\n"); + return -EINVAL; + } + + chip->revid = get_revid_data(revid_node); + of_node_put(revid_node); + if (IS_ERR_OR_NULL(chip->revid)) { + pr_err("Unable to get pmic_revid rc=%ld\n", + PTR_ERR(chip->revid)); + /* + * the revid peripheral must be registered, any failure + * here only indicates that the rev-id module has not + * probed yet. + */ + return -EPROBE_DEFER; + } + + if (of_find_property(node, "qcom,pmic-misc", NULL)) { + misc_node = of_parse_phandle(node, "qcom,pmic-misc", 0); + if (!misc_node) + return -EINVAL; + + rc = of_property_read_u32(node, "qcom,misc-clk-trim-error-reg", + &chip->misc_clk_trim_error_reg); + if (rc < 0 || !chip->misc_clk_trim_error_reg) { + pr_err("Invalid or missing misc-clk-trim-error-reg\n"); + of_node_put(misc_node); + return rc; + } + + rc = qpnp_misc_read_reg(misc_node, + chip->misc_clk_trim_error_reg, + &chip->clk_trim_error_code); + if (rc < 0) { + pr_err("Couldn't get clk_trim_error_code, rc=%d\n", rc); + of_node_put(misc_node); + return -EPROBE_DEFER; + } + of_node_put(misc_node); + } + + chip->play_irq = platform_get_irq_byname(chip->pdev, "hap-play-irq"); + if (chip->play_irq < 0) { + pr_err("Unable to get play irq\n"); + return chip->play_irq; + } + + chip->sc_irq = platform_get_irq_byname(chip->pdev, "hap-sc-irq"); + if (chip->sc_irq < 0) { + pr_err("Unable to get sc irq\n"); + return chip->sc_irq; + } + + chip->act_type = HAP_LRA; + rc = of_property_read_u32(node, "qcom,actuator-type", &temp); + if (!rc) { + if (temp != HAP_LRA && temp != HAP_ERM) { + pr_err("Incorrect actuator type\n"); + return -EINVAL; + } + chip->act_type = temp; + } + + chip->lra_auto_mode = of_property_read_bool(node, "qcom,lra-auto-mode"); + + rc = of_property_read_string(node, "qcom,play-mode", &temp_str); + if (!rc) { + if (strcmp(temp_str, "direct") == 0) + chip->play_mode = HAP_DIRECT; + else if (strcmp(temp_str, "buffer") == 0) + chip->play_mode = HAP_BUFFER; + else if (strcmp(temp_str, "pwm") == 0) + chip->play_mode = HAP_PWM; + else if (strcmp(temp_str, "audio") == 0) + chip->play_mode = HAP_AUDIO; + else { + pr_err("Invalid play mode\n"); + return -EINVAL; + } + } else { + if (rc == -EINVAL && chip->act_type == HAP_LRA) { + pr_info("Play mode not specified, using auto mode\n"); + chip->lra_auto_mode = true; + } else { + pr_err("Unable to read play mode\n"); + return rc; + } + } + + chip->max_play_time_ms = HAP_MAX_PLAY_TIME_MS; + rc = of_property_read_u32(node, "qcom,max-play-time-ms", &temp); + if (!rc) { + chip->max_play_time_ms = temp; + } else if (rc != -EINVAL) { + pr_err("Unable to read max-play-time rc=%d\n", rc); + return rc; + } + + chip->vmax_mv = HAP_VMAX_MAX_MV; + rc = of_property_read_u32(node, "qcom,vmax-mv", &temp); + if (!rc) { + chip->vmax_mv = temp; + } else if (rc != -EINVAL) { + pr_err("Unable to read Vmax rc=%d\n", rc); + return rc; + } + + chip->ilim_ma = HAP_ILIM_400_MA; + rc = of_property_read_u32(node, "qcom,ilim-ma", &temp); + if (!rc) { + chip->ilim_ma = (u8)temp; + } else if (rc != -EINVAL) { + pr_err("Unable to read ILIM rc=%d\n", rc); + return rc; + } + + chip->sc_deb_cycles = HAP_DEF_SC_DEB_CYCLES; + rc = of_property_read_u32(node, "qcom,sc-dbc-cycles", &temp); + if (!rc) { + chip->sc_deb_cycles = temp; + } else if (rc != -EINVAL) { + pr_err("Unable to read sc debounce rc=%d\n", rc); + return rc; + } + + chip->wave_shape = HAP_WAVE_SQUARE; + rc = of_property_read_string(node, "qcom,wave-shape", &temp_str); + if (!rc) { + if (strcmp(temp_str, "sine") == 0) + chip->wave_shape = HAP_WAVE_SINE; + else if (strcmp(temp_str, "square") == 0) + chip->wave_shape = HAP_WAVE_SQUARE; + else { + pr_err("Unsupported wave shape\n"); + return -EINVAL; + } + } else if (rc != -EINVAL) { + pr_err("Unable to read wave shape rc=%d\n", rc); + return rc; + } + + chip->wave_play_rate_us = HAP_DEF_WAVE_PLAY_RATE_US; + rc = of_property_read_u32(node, + "qcom,wave-play-rate-us", &temp); + if (!rc) { + chip->wave_play_rate_us = temp; + } else if (rc != -EINVAL) { + pr_err("Unable to read play rate rc=%d\n", rc); + return rc; + } + + if (chip->wave_play_rate_us < HAP_WAVE_PLAY_RATE_US_MIN) + chip->wave_play_rate_us = HAP_WAVE_PLAY_RATE_US_MIN; + else if (chip->wave_play_rate_us > HAP_WAVE_PLAY_RATE_US_MAX) + chip->wave_play_rate_us = HAP_WAVE_PLAY_RATE_US_MAX; + + chip->en_brake = of_property_read_bool(node, "qcom,en-brake"); + + rc = of_property_count_elems_of_size(node, + "qcom,brake-pattern", sizeof(u32)); + if (rc > 0) { + if (rc != HAP_BRAKE_PAT_LEN) { + pr_err("Invalid length for brake pattern\n"); + return -EINVAL; + } + + rc = of_property_read_u32_array(node, "qcom,brake-pattern", + chip->brake_pat, HAP_BRAKE_PAT_LEN); + if (rc < 0) { + pr_err("Error in reading qcom,brake-pattern, rc=%d\n", + rc); + return rc; + } + } + + /* Read the following properties only for LRA */ + if (chip->act_type == HAP_LRA) { + rc = of_property_read_string(node, "qcom,lra-auto-res-mode", + &temp_str); + if (!rc) { + if (chip->revid->pmic_subtype == PM660_SUBTYPE) { + chip->ares_cfg.auto_res_mode = + HAP_PM660_AUTO_RES_QWD; + if (strcmp(temp_str, "zxd") == 0) + chip->ares_cfg.auto_res_mode = + HAP_PM660_AUTO_RES_ZXD; + else if (strcmp(temp_str, "qwd") == 0) + chip->ares_cfg.auto_res_mode = + HAP_PM660_AUTO_RES_QWD; + } else { + chip->ares_cfg.auto_res_mode = + HAP_AUTO_RES_ZXD_EOP; + if (strcmp(temp_str, "none") == 0) + chip->ares_cfg.auto_res_mode = + HAP_AUTO_RES_NONE; + else if (strcmp(temp_str, "zxd") == 0) + chip->ares_cfg.auto_res_mode = + HAP_AUTO_RES_ZXD; + else if (strcmp(temp_str, "qwd") == 0) + chip->ares_cfg.auto_res_mode = + HAP_AUTO_RES_QWD; + else if (strcmp(temp_str, "max-qwd") == 0) + chip->ares_cfg.auto_res_mode = + HAP_AUTO_RES_MAX_QWD; + else + chip->ares_cfg.auto_res_mode = + HAP_AUTO_RES_ZXD_EOP; + } + } else if (rc != -EINVAL) { + pr_err("Unable to read auto res mode rc=%d\n", rc); + return rc; + } + + chip->ares_cfg.lra_high_z = HAP_LRA_HIGH_Z_OPT3; + rc = of_property_read_string(node, "qcom,lra-high-z", + &temp_str); + if (!rc) { + if (strcmp(temp_str, "none") == 0) + chip->ares_cfg.lra_high_z = + HAP_LRA_HIGH_Z_NONE; + else if (strcmp(temp_str, "opt1") == 0) + chip->ares_cfg.lra_high_z = + HAP_LRA_HIGH_Z_OPT1; + else if (strcmp(temp_str, "opt2") == 0) + chip->ares_cfg.lra_high_z = + HAP_LRA_HIGH_Z_OPT2; + else + chip->ares_cfg.lra_high_z = + HAP_LRA_HIGH_Z_OPT3; + if (chip->revid->pmic_subtype == PM660_SUBTYPE) { + if (strcmp(temp_str, "opt0") == 0) + chip->ares_cfg.lra_high_z = + HAP_LRA_HIGH_Z_NONE; + } + } else if (rc != -EINVAL) { + pr_err("Unable to read LRA high-z rc=%d\n", rc); + return rc; + } + + chip->ares_cfg.lra_res_cal_period = HAP_RES_CAL_PERIOD_MAX; + rc = of_property_read_u32(node, + "qcom,lra-res-cal-period", &temp); + if (!rc) { + chip->ares_cfg.lra_res_cal_period = temp; + } else if (rc != -EINVAL) { + pr_err("Unable to read cal period rc=%d\n", rc); + return rc; + } + + chip->ares_cfg.lra_qwd_drive_duration = -EINVAL; + chip->ares_cfg.calibrate_at_eop = -EINVAL; + if (chip->revid->pmic_subtype == PM660_SUBTYPE) { + rc = of_property_read_u32(node, + "qcom,lra-qwd-drive-duration", + &chip->ares_cfg.lra_qwd_drive_duration); + if (rc && rc != -EINVAL) { + pr_err("Unable to read LRA QWD drive duration rc=%d\n", + rc); + return rc; + } + + rc = of_property_read_u32(node, + "qcom,lra-calibrate-at-eop", + &chip->ares_cfg.calibrate_at_eop); + if (rc && rc != -EINVAL) { + pr_err("Unable to read Calibrate at EOP rc=%d\n", + rc); + return rc; + } + } + + chip->drive_period_code_max_var_pct = 25; + rc = of_property_read_u32(node, + "qcom,drive-period-code-max-variation-pct", &temp); + if (!rc) { + if (temp > 0 && temp < 100) + chip->drive_period_code_max_var_pct = (u8)temp; + } else if (rc != -EINVAL) { + pr_err("Unable to read drive period code max var pct rc=%d\n", + rc); + return rc; + } + + chip->drive_period_code_min_var_pct = 25; + rc = of_property_read_u32(node, + "qcom,drive-period-code-min-variation-pct", &temp); + if (!rc) { + if (temp > 0 && temp < 100) + chip->drive_period_code_min_var_pct = (u8)temp; + } else if (rc != -EINVAL) { + pr_err("Unable to read drive period code min var pct rc=%d\n", + rc); + return rc; + } + + chip->auto_res_err_recovery_hw = + of_property_read_bool(node, + "qcom,auto-res-err-recovery-hw"); + + if (chip->revid->pmic_subtype != PM660_SUBTYPE) + chip->auto_res_err_recovery_hw = false; + } + + if (rc == -EINVAL) + rc = 0; + + if (chip->play_mode == HAP_BUFFER) + rc = qpnp_haptics_parse_buffer_dt(chip); + else if (chip->play_mode == HAP_PWM) + rc = qpnp_haptics_parse_pwm_dt(chip); + + return rc; +} + +static int qpnp_haptics_probe(struct platform_device *pdev) +{ + struct hap_chip *chip; + int rc, i; + + chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!chip->regmap) { + dev_err(&pdev->dev, "Couldn't get parent's regmap\n"); + return -EINVAL; + } + + chip->pdev = pdev; + rc = qpnp_haptics_parse_dt(chip); + if (rc < 0) { + dev_err(&pdev->dev, "Error in parsing DT parameters, rc=%d\n", + rc); + return rc; + } + + spin_lock_init(&chip->bus_lock); + mutex_init(&chip->play_lock); + mutex_init(&chip->param_lock); + INIT_WORK(&chip->haptics_work, qpnp_haptics_work); + + rc = qpnp_haptics_config(chip); + if (rc < 0) { + dev_err(&pdev->dev, "Error in configuring haptics, rc=%d\n", + rc); + goto fail; + } + + hrtimer_init(&chip->stop_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + chip->stop_timer.function = hap_stop_timer; + hrtimer_init(&chip->auto_res_err_poll_timer, CLOCK_MONOTONIC, + HRTIMER_MODE_REL); + chip->auto_res_err_poll_timer.function = hap_auto_res_err_poll_timer; + dev_set_drvdata(&pdev->dev, chip); + + chip->cdev.name = "vibrator"; + chip->cdev.brightness_get = qpnp_haptics_brightness_get; + chip->cdev.brightness_set = qpnp_haptics_brightness_set; + chip->cdev.max_brightness = 100; + rc = devm_led_classdev_register(&pdev->dev, &chip->cdev); + if (rc < 0) { + dev_err(&pdev->dev, "Error in registering led class device, rc=%d\n", + rc); + goto register_fail; + } + + for (i = 0; i < ARRAY_SIZE(qpnp_haptics_attrs); i++) { + rc = sysfs_create_file(&chip->cdev.dev->kobj, + &qpnp_haptics_attrs[i].attr); + if (rc < 0) { + dev_err(&pdev->dev, "Error in creating sysfs file, rc=%d\n", + rc); + goto sysfs_fail; + } + } + + return 0; + +sysfs_fail: + for (--i; i >= 0; i--) + sysfs_remove_file(&chip->cdev.dev->kobj, + &qpnp_haptics_attrs[i].attr); +register_fail: + cancel_work_sync(&chip->haptics_work); + hrtimer_cancel(&chip->auto_res_err_poll_timer); + hrtimer_cancel(&chip->stop_timer); +fail: + mutex_destroy(&chip->play_lock); + mutex_destroy(&chip->param_lock); + if (chip->pwm_data.pwm_dev) + pwm_put(chip->pwm_data.pwm_dev); + dev_set_drvdata(&pdev->dev, NULL); + return rc; +} + +static int qpnp_haptics_remove(struct platform_device *pdev) +{ + struct hap_chip *chip = dev_get_drvdata(&pdev->dev); + + cancel_work_sync(&chip->haptics_work); + hrtimer_cancel(&chip->auto_res_err_poll_timer); + hrtimer_cancel(&chip->stop_timer); + mutex_destroy(&chip->play_lock); + mutex_destroy(&chip->param_lock); + if (chip->pwm_data.pwm_dev) + pwm_put(chip->pwm_data.pwm_dev); + dev_set_drvdata(&pdev->dev, NULL); + + return 0; +} + +static const struct dev_pm_ops qpnp_haptics_pm_ops = { + .suspend = qpnp_haptics_suspend, +}; + +static const struct of_device_id hap_match_table[] = { + { .compatible = "qcom,qpnp-haptics" }, + { }, +}; + +static struct platform_driver qpnp_haptics_driver = { + .driver = { + .name = "qcom,qpnp-haptics", + .of_match_table = hap_match_table, + .pm = &qpnp_haptics_pm_ops, + }, + .probe = qpnp_haptics_probe, + .remove = qpnp_haptics_remove, +}; +module_platform_driver(qpnp_haptics_driver); + +MODULE_DESCRIPTION("QPNP haptics driver"); +MODULE_LICENSE("GPL v2"); From 7ba1baf98303d46fd2b357f0be23d77604309c9f Mon Sep 17 00:00:00 2001 From: Luca Stefani Date: Sun, 28 Oct 2018 12:22:00 +0100 Subject: [PATCH 327/356] Revert "leds: qpnp-haptics: Allow duration for buffer mode" --- drivers/leds/leds-qpnp-haptics.c | 56 +++++++++++++------------------- 1 file changed, 22 insertions(+), 34 deletions(-) diff --git a/drivers/leds/leds-qpnp-haptics.c b/drivers/leds/leds-qpnp-haptics.c index 764657abeed0..636a02de1d7a 100644 --- a/drivers/leds/leds-qpnp-haptics.c +++ b/drivers/leds/leds-qpnp-haptics.c @@ -1,4 +1,5 @@ -/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2015, 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 @@ -274,7 +275,6 @@ struct hap_lra_ares_param { * @ last_rate_cfg - Last rate config updated * @ wave_rep_cnt - waveform repeat count * @ wave_s_rep_cnt - waveform sample repeat count - * @ wf_samp_len - waveform sample length * @ ext_pwm_freq_khz - external pwm frequency in KHz * @ ext_pwm_dtest_line - DTEST line for external pwm * @ status_flags - status @@ -330,7 +330,6 @@ struct hap_chip { u16 last_rate_cfg; u32 wave_rep_cnt; u32 wave_s_rep_cnt; - u32 wf_samp_len; u32 ext_pwm_freq_khz; u8 ext_pwm_dtest_line; u32 status_flags; @@ -446,19 +445,6 @@ static int qpnp_haptics_masked_write_reg(struct hap_chip *chip, u16 addr, return rc; } -static inline int get_buffer_mode_duration(struct hap_chip *chip) -{ - int sample_count, sample_duration; - - sample_count = chip->wave_rep_cnt * chip->wave_s_rep_cnt * - chip->wf_samp_len; - sample_duration = sample_count * chip->wave_play_rate_us; - pr_debug("sample_count: %d sample_duration: %d\n", sample_count, - sample_duration); - - return (sample_duration / 1000); -} - static bool is_sw_lra_auto_resonance_control(struct hap_chip *chip) { if (chip->act_type != HAP_LRA) @@ -750,12 +736,11 @@ static int qpnp_haptics_play(struct hap_chip *chip, bool enable) goto out; } - if (chip->play_mode == HAP_BUFFER) - time_ms = get_buffer_mode_duration(chip); - hrtimer_start(&chip->stop_timer, - ktime_set(time_ms / MSEC_PER_SEC, - (time_ms % MSEC_PER_SEC) * NSEC_PER_MSEC), - HRTIMER_MODE_REL); + if (chip->play_mode != HAP_BUFFER) + hrtimer_start(&chip->stop_timer, + ktime_set(time_ms / MSEC_PER_SEC, + (time_ms % MSEC_PER_SEC) * NSEC_PER_MSEC), + HRTIMER_MODE_REL); rc = qpnp_haptics_auto_res_enable(chip, true); if (rc < 0) { @@ -782,9 +767,6 @@ static int qpnp_haptics_play(struct hap_chip *chip, bool enable) if (chip->play_mode == HAP_PWM) pwm_disable(chip->pwm_data.pwm_dev); - - if (chip->play_mode == HAP_BUFFER) - chip->wave_samp_idx = 0; } out: @@ -1201,11 +1183,8 @@ static int qpnp_haptics_auto_mode_config(struct hap_chip *chip, int time_ms) if (time_ms <= 20) { wave_samp[0] = HAP_WF_SAMP_MAX; wave_samp[1] = HAP_WF_SAMP_MAX; - chip->wf_samp_len = 2; - if (time_ms > 15) { + if (time_ms > 15) wave_samp[2] = HAP_WF_SAMP_MAX; - chip->wf_samp_len = 3; - } /* short pattern */ rc = qpnp_haptics_parse_buffer_dt(chip); @@ -1320,20 +1299,33 @@ static irqreturn_t qpnp_haptics_play_irq_handler(int irq, void *data) chip->wave_samp_idx += HAP_WAVE_SAMP_LEN; if (chip->wave_samp_idx >= ARRAY_SIZE(chip->wave_samp)) { pr_debug("Samples over\n"); + /* fall through to stop playing */ } else { pr_debug("moving to next sample set %d\n", chip->wave_samp_idx); - /* Moving to next set of wave sample */ rc = qpnp_haptics_buffer_config(chip, NULL, false); if (rc < 0) { pr_err("Error in configuring buffer, rc=%d\n", rc); goto irq_handled; } + + /* + * Moving to next set of wave sample. No need to stop + * or change the play control. Just return. + */ + goto irq_handled; } } + rc = qpnp_haptics_play_control(chip, HAP_STOP); + if (rc < 0) { + pr_err("Error in disabling play, rc=%d\n", rc); + goto irq_handled; + } + chip->wave_samp_idx = 0; + irq_handled: return IRQ_HANDLED; } @@ -1643,7 +1635,6 @@ static ssize_t qpnp_haptics_store_wf_samp(struct device *dev, pos += bytes_read; } - chip->wf_samp_len = i; for (i = 0; i < ARRAY_SIZE(chip->wave_samp); i++) chip->wave_samp[i] = samp[i]; @@ -1992,10 +1983,7 @@ static int qpnp_haptics_parse_buffer_dt(struct hap_chip *chip) /* Use default values */ for (i = 0; i < HAP_WAVE_SAMP_LEN; i++) chip->wave_samp[i] = HAP_WF_SAMP_MAX; - - wf_samp_len = HAP_WAVE_SAMP_LEN; } - chip->wf_samp_len = wf_samp_len; return 0; } From 52db2c3d66da9fabaa6d7daee4a73733a3c117ec Mon Sep 17 00:00:00 2001 From: Luca Stefani Date: Sun, 28 Oct 2018 12:14:40 +0100 Subject: [PATCH 328/356] leds: qpnp-haptics: Import OP changes Change-Id: Iae83768d633f0c2108e142a530715925b79c4172 --- drivers/leds/leds-qpnp-haptics.c | 73 +++++++++++++++++++++++++------- 1 file changed, 58 insertions(+), 15 deletions(-) diff --git a/drivers/leds/leds-qpnp-haptics.c b/drivers/leds/leds-qpnp-haptics.c index 636a02de1d7a..9d60920bebb9 100644 --- a/drivers/leds/leds-qpnp-haptics.c +++ b/drivers/leds/leds-qpnp-haptics.c @@ -1181,10 +1181,14 @@ static int qpnp_haptics_auto_mode_config(struct hap_chip *chip, int time_ms) old_play_mode = chip->play_mode; pr_debug("auto_mode, time_ms: %d\n", time_ms); if (time_ms <= 20) { - wave_samp[0] = HAP_WF_SAMP_MAX; - wave_samp[1] = HAP_WF_SAMP_MAX; - if (time_ms > 15) - wave_samp[2] = HAP_WF_SAMP_MAX; + wave_samp[0] = 0x7e; + wave_samp[1] = 0x7e; + wave_samp[2] = 0x7e; + wave_samp[3] = 0x7e; + wave_samp[4] = 0x7e; + wave_samp[5] = 0x28; + wave_samp[6] = 0x28; + wave_samp[7] = 0x28; /* short pattern */ rc = qpnp_haptics_parse_buffer_dt(chip); @@ -1197,7 +1201,7 @@ static int qpnp_haptics_auto_mode_config(struct hap_chip *chip, int time_ms) return rc; } - rc = qpnp_haptics_buffer_config(chip, wave_samp, true); + rc = qpnp_haptics_buffer_config(chip, wave_samp, false); if (rc < 0) { pr_err("Error in configuring buffer mode %d\n", rc); @@ -1212,26 +1216,61 @@ static int qpnp_haptics_auto_mode_config(struct hap_chip *chip, int time_ms) ares_cfg.lra_qwd_drive_duration = 0; ares_cfg.calibrate_at_eop = 0; } else { - ares_cfg.auto_res_mode = HAP_AUTO_RES_ZXD_EOP; + ares_cfg.auto_res_mode = HAP_AUTO_RES_QWD; ares_cfg.lra_qwd_drive_duration = -EINVAL; ares_cfg.calibrate_at_eop = -EINVAL; } - vmax_mv = HAP_VMAX_MAX_MV; + if (chip->vmax_mv >= 2320) + vmax_mv = HAP_VMAX_MAX_MV; + else + vmax_mv = chip->vmax_mv; rc = qpnp_haptics_vmax_config(chip, vmax_mv, true); if (rc < 0) return rc; + brake_pat[0] = 0x3; + brake_pat[1] = 0x3; + brake_pat[2] = 0x3; + brake_pat[3] = 0x3; + rc = qpnp_haptics_brake_config(chip, brake_pat); + if (rc < 0) + return rc; + /* enable play_irq for buffer mode */ if (chip->play_irq >= 0 && !chip->play_irq_en) { enable_irq(chip->play_irq); chip->play_irq_en = true; } - brake_pat[0] = BRAKE_VMAX; chip->play_mode = HAP_BUFFER; - chip->wave_shape = HAP_WAVE_SQUARE; + chip->wave_shape = HAP_WAVE_SINE; } else { + wave_samp[0] = 0x28; + wave_samp[1] = 0x28; + wave_samp[2] = 0x28; + wave_samp[3] = 0x28; + wave_samp[4] = 0x28; + wave_samp[5] = 0x28; + wave_samp[6] = 0x28; + wave_samp[7] = 0x28; + rc = qpnp_haptics_parse_buffer_dt(chip); + if (!rc) { + rc = qpnp_haptics_wave_rep_config(chip, + HAP_WAVE_REPEAT | HAP_WAVE_SAMP_REPEAT); + if (rc < 0) { + pr_err("Error in configuring wave_rep config %d\n", + rc); + return rc; + } + + rc = qpnp_haptics_buffer_config(chip, wave_samp, false); + if (rc < 0) { + pr_err("Error in configuring buffer mode %d\n", + rc); + return rc; + } + } /* long pattern */ ares_cfg.lra_high_z = HAP_LRA_HIGH_Z_OPT1; if (chip->revid->pmic_subtype == PM660_SUBTYPE) { @@ -1241,7 +1280,7 @@ static int qpnp_haptics_auto_mode_config(struct hap_chip *chip, int time_ms) ares_cfg.lra_qwd_drive_duration = 0; ares_cfg.calibrate_at_eop = 1; } else { - ares_cfg.auto_res_mode = HAP_AUTO_RES_QWD; + ares_cfg.auto_res_mode = HAP_AUTO_RES_ZXD_EOP; ares_cfg.lra_res_cal_period = HAP_RES_CAL_PERIOD_MAX; ares_cfg.lra_qwd_drive_duration = -EINVAL; ares_cfg.calibrate_at_eop = -EINVAL; @@ -1252,13 +1291,21 @@ static int qpnp_haptics_auto_mode_config(struct hap_chip *chip, int time_ms) if (rc < 0) return rc; + brake_pat[0] = 0x3; + brake_pat[1] = 0x3; + brake_pat[2] = 0x3; + brake_pat[3] = 0x3; + rc = qpnp_haptics_brake_config(chip, brake_pat); + if (rc < 0) + return rc; + /* enable play_irq for direct mode */ if (chip->play_irq >= 0 && chip->play_irq_en) { disable_irq(chip->play_irq); chip->play_irq_en = false; } - chip->play_mode = HAP_DIRECT; + chip->play_mode = HAP_BUFFER; chip->wave_shape = HAP_WAVE_SINE; } @@ -1275,10 +1322,6 @@ static int qpnp_haptics_auto_mode_config(struct hap_chip *chip, int time_ms) return rc; } - rc = qpnp_haptics_brake_config(chip, brake_pat); - if (rc < 0) - return rc; - rc = qpnp_haptics_masked_write_reg(chip, HAP_CFG2_REG(chip), HAP_LRA_RES_TYPE_MASK, chip->wave_shape); if (rc < 0) From a8dcf4df4da9de2f77105aaed402e8dbd4dbc5f3 Mon Sep 17 00:00:00 2001 From: LuK1337 Date: Thu, 10 Jan 2019 21:44:07 +0100 Subject: [PATCH 329/356] leds: qpnp-haptics: Don't change irq mode in qpnp_haptics_play_mode_config() * Removing this code and forcing hrtimer_start fixes setting custom vibrate time in Android. Change-Id: I63c83d14c795b7b8c8ca7dd13a3a902e5c19b6c4 --- drivers/leds/leds-qpnp-haptics.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/drivers/leds/leds-qpnp-haptics.c b/drivers/leds/leds-qpnp-haptics.c index 9d60920bebb9..5786b3c04dc0 100644 --- a/drivers/leds/leds-qpnp-haptics.c +++ b/drivers/leds/leds-qpnp-haptics.c @@ -736,11 +736,10 @@ static int qpnp_haptics_play(struct hap_chip *chip, bool enable) goto out; } - if (chip->play_mode != HAP_BUFFER) - hrtimer_start(&chip->stop_timer, - ktime_set(time_ms / MSEC_PER_SEC, - (time_ms % MSEC_PER_SEC) * NSEC_PER_MSEC), - HRTIMER_MODE_REL); + hrtimer_start(&chip->stop_timer, + ktime_set(time_ms / MSEC_PER_SEC, + (time_ms % MSEC_PER_SEC) * NSEC_PER_MSEC), + HRTIMER_MODE_REL); rc = qpnp_haptics_auto_res_enable(chip, true); if (rc < 0) { @@ -1048,15 +1047,6 @@ static int qpnp_haptics_play_mode_config(struct hap_chip *chip) val = chip->play_mode << HAP_WF_SOURCE_SHIFT; rc = qpnp_haptics_masked_write_reg(chip, HAP_SEL_REG(chip), HAP_WF_SOURCE_MASK, val); - if (!rc) { - if (chip->play_mode == HAP_BUFFER && !chip->play_irq_en) { - enable_irq(chip->play_irq); - chip->play_irq_en = true; - } else if (chip->play_mode != HAP_BUFFER && chip->play_irq_en) { - disable_irq(chip->play_irq); - chip->play_irq_en = false; - } - } return rc; } @@ -1957,6 +1947,7 @@ static int qpnp_haptics_config(struct hap_chip *chip) return rc; } + chip->play_irq_en = true; /* use play_irq only for buffer mode */ if (chip->play_mode != HAP_BUFFER) { disable_irq(chip->play_irq); From 72f2b8e58c2f08f443024da928d54640dcdeaa8a Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Sun, 6 Aug 2023 15:07:42 +0000 Subject: [PATCH 330/356] ARM64: enchilada: Switch to LEDS_QPNP_HAPTICS The QTI haptics driver doesn't work very well for us --- arch/arm64/boot/dts/qcom/enchilada.dtsi | 9 +++++++++ arch/arm64/boot/dts/qcom/fajita.dtsi | 9 +++++++++ arch/arm64/boot/dts/qcom/pmi8998.dtsi | 2 +- arch/arm64/configs/vendor/enchilada_defconfig | 2 +- 4 files changed, 20 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/enchilada.dtsi b/arch/arm64/boot/dts/qcom/enchilada.dtsi index 53ce55853b44..53d15cfa88df 100644 --- a/arch/arm64/boot/dts/qcom/enchilada.dtsi +++ b/arch/arm64/boot/dts/qcom/enchilada.dtsi @@ -814,11 +814,20 @@ status = "disabled"; &pmi8998_haptics { status = "okay"; + compatible = "qcom,qpnp-haptics"; + qcom,pmic-misc = <&pmi8998_misc>; + qcom,misc-clk-trim-error-reg = <0xf3>; + qcom,actuator-type = <0>; qcom,wave-shape = "sine"; qcom,play-mode = "buffer"; + qcom,ilim-ma = <800>; qcom,brake-pattern = <0x3 0x3 0x3 0x3>; qcom,drive-period-code-max-variation-pct = <5>; qcom,drive-period-code-min-variation-pct = <5>; + qcom,lra-auto-mode; + qcom,lra-high-z = "opt1"; + qcom,sc-dbc-cycles = <8>; + qcom,en-brake; qcom,wave-rep-cnt = <1>; qcom,wave-samp-rep-cnt = <1>; qcom,vmax-mv = <2088>; diff --git a/arch/arm64/boot/dts/qcom/fajita.dtsi b/arch/arm64/boot/dts/qcom/fajita.dtsi index 6775608478bd..f7962a49978b 100644 --- a/arch/arm64/boot/dts/qcom/fajita.dtsi +++ b/arch/arm64/boot/dts/qcom/fajita.dtsi @@ -1017,11 +1017,20 @@ status = "disabled"; &pmi8998_haptics { status = "okay"; + compatible = "qcom,qpnp-haptics"; + qcom,pmic-misc = <&pmi8998_misc>; + qcom,misc-clk-trim-error-reg = <0xf3>; + qcom,actuator-type = <0>; qcom,wave-shape = "sine"; qcom,play-mode = "buffer"; + qcom,ilim-ma = <800>; qcom,brake-pattern = <0x3 0x3 0x3 0x3>; qcom,drive-period-code-max-variation-pct = <5>; qcom,drive-period-code-min-variation-pct = <5>; + qcom,lra-auto-mode; + qcom,lra-high-z = "opt1"; + qcom,sc-dbc-cycles = <8>; + qcom,en-brake; qcom,wave-rep-cnt = <1>; qcom,wave-samp-rep-cnt = <1>; qcom,vmax-mv = <2088>; diff --git a/arch/arm64/boot/dts/qcom/pmi8998.dtsi b/arch/arm64/boot/dts/qcom/pmi8998.dtsi index a4407664b5f2..fce3e3b06c54 100644 --- a/arch/arm64/boot/dts/qcom/pmi8998.dtsi +++ b/arch/arm64/boot/dts/qcom/pmi8998.dtsi @@ -664,7 +664,7 @@ }; - pmi8998_haptics: qcom,haptic@c000 { + pmi8998_haptics: qcom,haptics@c000 { compatible = "qcom,haptics"; reg = <0xc000 0x100>; interrupts = <0x3 0xc0 0x0 IRQ_TYPE_EDGE_BOTH>, diff --git a/arch/arm64/configs/vendor/enchilada_defconfig b/arch/arm64/configs/vendor/enchilada_defconfig index 8d076a80e2a8..8a17e105a817 100644 --- a/arch/arm64/configs/vendor/enchilada_defconfig +++ b/arch/arm64/configs/vendor/enchilada_defconfig @@ -350,7 +350,6 @@ CONFIG_INPUT_TOUCHSCREEN=y CONFIG_TOUCHSCREEN_SYNAPTICS_S3320_I2C_RMI=y CONFIG_INPUT_MISC=y CONFIG_INPUT_QPNP_POWER_ON=y -CONFIG_INPUT_QTI_HAPTICS=y CONFIG_INPUT_UINPUT=y # CONFIG_SERIO_SERPORT is not set # CONFIG_VT is not set @@ -503,6 +502,7 @@ CONFIG_MMC_CQHCI_CRYPTO=y CONFIG_MMC_CQHCI_CRYPTO_QTI=y CONFIG_LEDS_QTI_TRI_LED=y CONFIG_LEDS_QPNP_FLASH_V2=y +CONFIG_LEDS_QPNP_HAPTICS=y CONFIG_LEDS_TRIGGER_TIMER=y CONFIG_EDAC=y CONFIG_EDAC_KRYO_ARM64=y From bf0723e2ee77ff05254c4d304b175f2624d68a8e Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Sun, 30 Jul 2023 13:07:00 +0000 Subject: [PATCH 331/356] msm: msm_media_info: Import buffer alignment changes from kernel 4.9 Makes venus happy --- include/uapi/media/msm_media_info.h | 175 ++++++++++++++++++---------- 1 file changed, 111 insertions(+), 64 deletions(-) diff --git a/include/uapi/media/msm_media_info.h b/include/uapi/media/msm_media_info.h index 9d0a0a25db43..24e045b5f06b 100644 --- a/include/uapi/media/msm_media_info.h +++ b/include/uapi/media/msm_media_info.h @@ -17,6 +17,10 @@ #define MSM_MEDIA_ROUNDUP(__sz, __r) (((__sz) + ((__r) - 1)) / (__r)) #endif +#ifndef MSM_MEDIA_MAX +#define MSM_MEDIA_MAX(__a, __b) ((__a) > (__b)?(__a):(__b)) +#endif + enum color_fmts { /* Venus NV12: * YUV 4:2:0 image with a plane of 8 bit Y samples followed @@ -49,8 +53,10 @@ enum color_fmts { * UV_Stride : Width aligned to 128 * Y_Scanlines: Height aligned to 32 * UV_Scanlines: Height/2 aligned to 16 - * Total size = align(Y_Stride * Y_Scanlines - * + UV_Stride * UV_Scanlines, 4096) + * Extradata: Arbitrary (software-imposed) padding + * Total size = align((Y_Stride * Y_Scanlines + * + UV_Stride * UV_Scanlines + * + max(Extradata, Y_Stride * 8), 4096) */ COLOR_FMT_NV12, /* Venus NV12: @@ -119,8 +125,11 @@ enum color_fmts { * UV_Stride : Width aligned to 128 * Y_Scanlines: Height aligned to 32 * UV_Scanlines: Height/2 aligned to 16 - * Total size = align(Y_Stride * Y_Scanlines - * + UV_Stride * UV_Scanlines, 4096) + * View_1 begin at: 0 (zero) + * View_2 begin at: Y_Stride * Y_Scanlines + UV_Stride * UV_Scanlines + * Extradata: Arbitrary (software-imposed) padding + * Total size = align((2*(Y_Stride * Y_Scanlines) + * + 2*(UV_Stride * UV_Scanlines) + Extradata), 4096) */ COLOR_FMT_NV21, /* @@ -200,7 +209,7 @@ enum color_fmts { * Y_Stride = align(Width, 128) * UV_Stride = align(Width, 128) * Y_Scanlines = align(Height, 32) - * UV_Scanlines = align(Height/2, 32) + * UV_Scanlines = align(Height/2, 16) * Y_UBWC_Plane_size = align(Y_Stride * Y_Scanlines, 4096) * UV_UBWC_Plane_size = align(UV_Stride * UV_Scanlines, 4096) * Y_Meta_Stride = align(roundup(Width, Y_TileWidth), 64) @@ -209,9 +218,11 @@ enum color_fmts { * UV_Meta_Stride = align(roundup(Width, UV_TileWidth), 64) * UV_Meta_Scanlines = align(roundup(Height, UV_TileHeight), 16) * UV_Meta_Plane_size = align(UV_Meta_Stride * UV_Meta_Scanlines, 4096) + * Extradata = 8k * * Total size = align( Y_UBWC_Plane_size + UV_UBWC_Plane_size + - * Y_Meta_Plane_size + UV_Meta_Plane_size, 4096) + * Y_Meta_Plane_size + UV_Meta_Plane_size + * + max(Extradata, Y_Stride * 48), 4096) * * * (2) Venus NV12 UBWC Interlaced Buffer Format: @@ -385,11 +396,13 @@ enum color_fmts { * UV_BF_Meta_Scanlines = align(roundup(Half_height, UV_TileHeight), 16) * UV_BF_Meta_Plane_size = * align(UV_BF_Meta_Stride * UV_BF_Meta_Scanlines, 4096) + * Extradata = 8k * * Total size = align( Y_UBWC_TF_Plane_size + UV_UBWC_TF_Plane_size + * Y_TF_Meta_Plane_size + UV_TF_Meta_Plane_size + * Y_UBWC_BF_Plane_size + UV_UBWC_BF_Plane_size + - * Y_BF_Meta_Plane_size + UV_BF_Meta_Plane_size +, 4096) + * Y_BF_Meta_Plane_size + UV_BF_Meta_Plane_size + + * + max(Extradata, Y_TF_Stride * 48), 4096) */ COLOR_FMT_NV12_UBWC, /* Venus NV12 10-bit UBWC: @@ -462,8 +475,8 @@ enum color_fmts { * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k * * - * Y_Stride = align(Width * 4/3, 256) - * UV_Stride = align(Width * 4/3, 256) + * Y_Stride = align(Width * 4/3, 128) + * UV_Stride = align(Width * 4/3, 128) * Y_Scanlines = align(Height, 32) * UV_Scanlines = align(Height/2, 16) * Y_UBWC_Plane_Size = align(Y_Stride * Y_Scanlines, 4096) @@ -474,9 +487,11 @@ enum color_fmts { * UV_Meta_Stride = align(roundup(Width, UV_TileWidth), 64) * UV_Meta_Scanlines = align(roundup(Height, UV_TileHeight), 16) * UV_Meta_Plane_size = align(UV_Meta_Stride * UV_Meta_Scanlines, 4096) + * Extradata = 8k * * Total size = align(Y_UBWC_Plane_size + UV_UBWC_Plane_size + - * Y_Meta_Plane_size + UV_Meta_Plane_size, 4096) + * Y_Meta_Plane_size + UV_Meta_Plane_size + * + max(Extradata, Y_Stride * 48), 4096) */ COLOR_FMT_NV12_BPP10_UBWC, /* Venus RGBA8888 format: @@ -501,8 +516,9 @@ enum color_fmts { * RGB_Stride = align(Width * 4, 128) * RGB_Scanlines = align(Height, 32) * RGB_Plane_size = align(RGB_Stride * RGB_Scanlines, 4096) + * Extradata = 8k * - * Total size = align(RGB_Plane_size , 4096) + * Total size = align(RGB_Plane_size + Extradata, 4096) */ COLOR_FMT_RGBA8888, /* Venus RGBA8888 UBWC format: @@ -539,15 +555,17 @@ enum color_fmts { * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k * . . . . . . . . . . . . . . . . V * - * RGB_Stride = align(Width * 4, 256) - * RGB_Scanlines = align(Height, 16) + * RGB_Stride = align(Width * 4, 128) + * RGB_Scanlines = align(Height, 32) * RGB_Plane_size = align(RGB_Stride * RGB_Scanlines, 4096) * RGB_Meta_Stride = align(roundup(Width, RGB_TileWidth), 64) * RGB_Meta_Scanline = align(roundup(Height, RGB_TileHeight), 16) * RGB_Meta_Plane_size = align(RGB_Meta_Stride * * RGB_Meta_Scanlines, 4096) + * Extradata = 8k * - * Total size = align(RGB_Meta_Plane_size + RGB_Plane_size, 4096) + * Total size = align(RGB_Meta_Plane_size + RGB_Plane_size + + * Extradata, 4096) */ COLOR_FMT_RGBA8888_UBWC, /* Venus RGBA1010102 UBWC format: @@ -591,8 +609,10 @@ enum color_fmts { * RGB_Meta_Scanline = align(roundup(Height, RGB_TileHeight), 16) * RGB_Meta_Plane_size = align(RGB_Meta_Stride * * RGB_Meta_Scanlines, 4096) + * Extradata = 8k * - * Total size = align(RGB_Meta_Plane_size + RGB_Plane_size, 4096) + * Total size = align(RGB_Meta_Plane_size + RGB_Plane_size + + * Extradata, 4096) */ COLOR_FMT_RGBA1010102_UBWC, /* Venus RGB565 UBWC format: @@ -629,15 +649,17 @@ enum color_fmts { * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k * . . . . . . . . . . . . . . . . V * - * RGB_Stride = align(Width * 2, 256) + * RGB_Stride = align(Width * 2, 128) * RGB_Scanlines = align(Height, 16) * RGB_Plane_size = align(RGB_Stride * RGB_Scanlines, 4096) * RGB_Meta_Stride = align(roundup(Width, RGB_TileWidth), 64) * RGB_Meta_Scanline = align(roundup(Height, RGB_TileHeight), 16) * RGB_Meta_Plane_size = align(RGB_Meta_Stride * * RGB_Meta_Scanlines, 4096) + * Extradata = 8k * - * Total size = align(RGB_Meta_Plane_size + RGB_Plane_size, 4096) + * Total size = align(RGB_Meta_Plane_size + RGB_Plane_size + + * Extradata, 4096) */ COLOR_FMT_RGB565_UBWC, /* P010 UBWC: @@ -722,9 +744,11 @@ enum color_fmts { * UV_Meta_Stride = align(roundup(Width, UV_TileWidth), 64) * UV_Meta_Scanlines = align(roundup(Height, UV_TileHeight), 16) * UV_Meta_Plane_size = align(UV_Meta_Stride * UV_Meta_Scanlines, 4096) + * Extradata = 8k * * Total size = align(Y_UBWC_Plane_size + UV_UBWC_Plane_size + - * Y_Meta_Plane_size + UV_Meta_Plane_size, 4096) + * Y_Meta_Plane_size + UV_Meta_Plane_size + * + max(Extradata, Y_Stride * 48), 4096) */ COLOR_FMT_P010_UBWC, /* Venus P010: @@ -754,12 +778,14 @@ enum color_fmts { * . . . . . . . . . . . . . . . . V * . . . . . . . . . . . . . . . . --> Buffer size alignment * - * Y_Stride : Width * 2 aligned to 256 - * UV_Stride : Width * 2 aligned to 256 + * Y_Stride : Width * 2 aligned to 128 + * UV_Stride : Width * 2 aligned to 128 * Y_Scanlines: Height aligned to 32 * UV_Scanlines: Height/2 aligned to 16 - * Total size = align(Y_Stride * Y_Scanlines - * + UV_Stride * UV_Scanlines, 4096) + * Extradata: Arbitrary (software-imposed) padding + * Total size = align((Y_Stride * Y_Scanlines + * + UV_Stride * UV_Scanlines + * + max(Extradata, Y_Stride * 8), 4096) */ COLOR_FMT_P010, /* Venus NV12_512: @@ -844,10 +870,13 @@ static inline unsigned int VENUS_Y_STRIDE(unsigned int color_fmt, stride = MSM_MEDIA_ALIGN(stride * 4/3, alignment); break; case COLOR_FMT_P010_UBWC: - case COLOR_FMT_P010: alignment = 256; stride = MSM_MEDIA_ALIGN(width * 2, alignment); break; + case COLOR_FMT_P010: + alignment = 128; + stride = MSM_MEDIA_ALIGN(width*2, alignment); + break; default: break; } @@ -888,10 +917,13 @@ static inline unsigned int VENUS_UV_STRIDE(unsigned int color_fmt, stride = MSM_MEDIA_ALIGN(stride * 4/3, alignment); break; case COLOR_FMT_P010_UBWC: - case COLOR_FMT_P010: alignment = 256; stride = MSM_MEDIA_ALIGN(width * 2, alignment); break; + case COLOR_FMT_P010: + alignment = 128; + stride = MSM_MEDIA_ALIGN(width*2, alignment); + break; default: break; } @@ -1233,7 +1265,9 @@ static inline unsigned int VENUS_RGB_META_SCANLINES(unsigned int color_fmt, static inline unsigned int VENUS_BUFFER_SIZE(unsigned int color_fmt, unsigned int width, unsigned int height) { - unsigned int size = 0; + const unsigned int extra_size = VENUS_EXTRADATA_SIZE(width, height); + unsigned int uv_alignment = 0, size = 0; + unsigned int w_alignment = 512; unsigned int y_plane, uv_plane, y_stride, uv_stride, y_sclines, uv_sclines; unsigned int y_ubwc_plane = 0, uv_ubwc_plane = 0; @@ -1257,54 +1291,62 @@ static inline unsigned int VENUS_BUFFER_SIZE(unsigned int color_fmt, switch (color_fmt) { case COLOR_FMT_NV21: case COLOR_FMT_NV12: + uv_alignment = 4096; + y_plane = y_stride * y_sclines; + uv_plane = uv_stride * uv_sclines + uv_alignment; + size = y_plane + uv_plane + + MSM_MEDIA_MAX(extra_size, 8 * y_stride); + size = MSM_MEDIA_ALIGN(size, 4096); + + /* Additional size to cover last row of non-aligned frame */ + if (width >= 2400 && height >= 2400) { + size += MSM_MEDIA_ALIGN(width, w_alignment) * + w_alignment; + size = MSM_MEDIA_ALIGN(size, 4096); + } + break; case COLOR_FMT_P010: case COLOR_FMT_NV12_512: + uv_alignment = 4096; + y_plane = y_stride * y_sclines; + uv_plane = uv_stride * uv_sclines + uv_alignment; + size = y_plane + uv_plane + + MSM_MEDIA_MAX(extra_size, 8 * y_stride); + size = MSM_MEDIA_ALIGN(size, 4096); + break; case COLOR_FMT_NV12_128: y_plane = y_stride * y_sclines; uv_plane = uv_stride * uv_sclines; size = y_plane + uv_plane; + size = 2 * size + extra_size; + size = MSM_MEDIA_ALIGN(size, 4096); break; case COLOR_FMT_NV12_UBWC: + y_sclines = VENUS_Y_SCANLINES(color_fmt, (height+1)>>1); + y_ubwc_plane = MSM_MEDIA_ALIGN(y_stride * y_sclines, 4096); + uv_sclines = VENUS_UV_SCANLINES(color_fmt, (height+1)>>1); + uv_ubwc_plane = MSM_MEDIA_ALIGN(uv_stride * uv_sclines, 4096); y_meta_stride = VENUS_Y_META_STRIDE(color_fmt, width); - uv_meta_stride = VENUS_UV_META_STRIDE(color_fmt, width); - if (width <= INTERLACE_WIDTH_MAX && - height <= INTERLACE_HEIGHT_MAX && - (height * width) / 256 <= INTERLACE_MB_PER_FRAME_MAX) { - y_sclines = - VENUS_Y_SCANLINES(color_fmt, (height+1)>>1); - y_ubwc_plane = - MSM_MEDIA_ALIGN(y_stride * y_sclines, 4096); - uv_sclines = - VENUS_UV_SCANLINES(color_fmt, (height+1)>>1); - uv_ubwc_plane = - MSM_MEDIA_ALIGN(uv_stride * uv_sclines, 4096); - y_meta_scanlines = + y_meta_scanlines = VENUS_Y_META_SCANLINES(color_fmt, (height+1)>>1); - y_meta_plane = MSM_MEDIA_ALIGN( - y_meta_stride * y_meta_scanlines, 4096); - uv_meta_scanlines = + y_meta_plane = MSM_MEDIA_ALIGN( + y_meta_stride * y_meta_scanlines, 4096); + uv_meta_stride = VENUS_UV_META_STRIDE(color_fmt, width); + uv_meta_scanlines = VENUS_UV_META_SCANLINES(color_fmt, (height+1)>>1); - uv_meta_plane = MSM_MEDIA_ALIGN(uv_meta_stride * - uv_meta_scanlines, 4096); - size = (y_ubwc_plane + uv_ubwc_plane + y_meta_plane + - uv_meta_plane)*2; - } else { - y_sclines = VENUS_Y_SCANLINES(color_fmt, height); - y_ubwc_plane = - MSM_MEDIA_ALIGN(y_stride * y_sclines, 4096); - uv_sclines = VENUS_UV_SCANLINES(color_fmt, height); - uv_ubwc_plane = - MSM_MEDIA_ALIGN(uv_stride * uv_sclines, 4096); - y_meta_scanlines = - VENUS_Y_META_SCANLINES(color_fmt, height); - y_meta_plane = MSM_MEDIA_ALIGN( - y_meta_stride * y_meta_scanlines, 4096); - uv_meta_scanlines = - VENUS_UV_META_SCANLINES(color_fmt, height); - uv_meta_plane = MSM_MEDIA_ALIGN(uv_meta_stride * - uv_meta_scanlines, 4096); - size = (y_ubwc_plane + uv_ubwc_plane + y_meta_plane + - uv_meta_plane); + uv_meta_plane = MSM_MEDIA_ALIGN(uv_meta_stride * + uv_meta_scanlines, 4096); + + size = (y_ubwc_plane + uv_ubwc_plane + y_meta_plane + + uv_meta_plane)*2 + + MSM_MEDIA_MAX(extra_size + 8192, 48 * y_stride); + size = MSM_MEDIA_ALIGN(size, 4096); + + /* Additional size to cover last row of non-aligned frame */ + if (width >= 2400 && height >= 2400) { + size += MSM_MEDIA_ALIGN(width, w_alignment) * + w_alignment; + size = MSM_MEDIA_ALIGN(size, 4096); } break; case COLOR_FMT_NV12_BPP10_UBWC: @@ -1320,7 +1362,9 @@ static inline unsigned int VENUS_BUFFER_SIZE(unsigned int color_fmt, uv_meta_scanlines, 4096); size = y_ubwc_plane + uv_ubwc_plane + y_meta_plane + - uv_meta_plane; + uv_meta_plane + + MSM_MEDIA_MAX(extra_size + 8192, 48 * y_stride); + size = MSM_MEDIA_ALIGN(size, 4096); break; case COLOR_FMT_P010_UBWC: y_ubwc_plane = MSM_MEDIA_ALIGN(y_stride * y_sclines, 4096); @@ -1336,10 +1380,12 @@ static inline unsigned int VENUS_BUFFER_SIZE(unsigned int color_fmt, size = y_ubwc_plane + uv_ubwc_plane + y_meta_plane + uv_meta_plane; + size = MSM_MEDIA_ALIGN(size, 4096); break; case COLOR_FMT_RGBA8888: rgb_plane = MSM_MEDIA_ALIGN(rgb_stride * rgb_scanlines, 4096); size = rgb_plane; + size = MSM_MEDIA_ALIGN(size, 4096); break; case COLOR_FMT_RGBA8888_UBWC: case COLOR_FMT_RGBA1010102_UBWC: @@ -1352,12 +1398,13 @@ static inline unsigned int VENUS_BUFFER_SIZE(unsigned int color_fmt, rgb_meta_plane = MSM_MEDIA_ALIGN(rgb_meta_stride * rgb_meta_scanlines, 4096); size = rgb_ubwc_plane + rgb_meta_plane; + size = MSM_MEDIA_ALIGN(size, 4096); break; default: break; } invalid_input: - return MSM_MEDIA_ALIGN(size, 4096); + return size; } static inline unsigned int VENUS_BUFFER_SIZE_USED(unsigned int color_fmt, From 441b20c89395802c42608de6ad55fd54c92ec3bb Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Sun, 6 Aug 2023 15:50:17 +0000 Subject: [PATCH 332/356] techpack: audio: max98927: Fix build with debugfs disabled --- techpack/audio/asoc/codecs/max98927/max98927.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/techpack/audio/asoc/codecs/max98927/max98927.c b/techpack/audio/asoc/codecs/max98927/max98927.c index 0c5ae34c39fd..f622741eb81c 100644 --- a/techpack/audio/asoc/codecs/max98927/max98927.c +++ b/techpack/audio/asoc/codecs/max98927/max98927.c @@ -336,14 +336,12 @@ struct param_info { char name[80]; int q_val; }; - +#endif //MULTIPLE = 3.33, rdc/(1<<27) * MULTIPLE = [min, max] ohm #define RDC_MIN (241833636) //1.801801 * (1<<27), 1.801801 * MULTIPLE = 6 ohm #define RDC_MAX (403056239) //3.003003 * (1<<27), 3.003003 * MULTIPLE = 10 ohm -#endif - static uint32_t gParam[PKG_HEADER+PAYLOAD_COUNT]; static int maxdsm_open(struct inode *inode, struct file *filep) @@ -420,7 +418,6 @@ static struct miscdevice dsm_ctrl_miscdev = { }; #endif -#ifdef CONFIG_DEBUG_FS /* max. length of a alsa mixer control name */ #define MAX_CONTROL_NAME 48 #define CALIBRATE_FILE "/persist/spkr_calibration.bin" @@ -512,6 +509,7 @@ static bool rdc_check_valid(uint32_t rdc) return false; } +#ifdef CONFIG_DEBUG_FS static ssize_t max989xx_dbgfs_calibrate_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -624,6 +622,7 @@ static ssize_t max989xx_dbgfs_impedance_read(struct file *file, return ret; } +#endif static struct snd_kcontrol_new max98927_at_controls[] = { { @@ -713,7 +712,7 @@ static ssize_t max98927_state_show(struct device *dev, struct device_attribute * static struct device_attribute max98927_state_attr = __ATTR(calibra, 0444, max98927_state_show, max98927_state_store); - +#ifdef CONFIG_DEBUG_FS struct dsm_info_t { int32_t averageTemp[2]; int32_t bits_per_sample; From fb7d8ccc59ece9e9b5d0964da7217d6cf58d3082 Mon Sep 17 00:00:00 2001 From: Sebastiano Barezzi Date: Tue, 28 Jun 2022 23:10:29 +0200 Subject: [PATCH 333/356] init: Add CONFIG_INITRAMFS_IGNORE_SKIP_FLAG * Ignoring an ignore flag, yikes * Also replace skip_initramf with want_initramf (omitting last letter for Magisk since it binary patches that out of kernel, I'm not even sure why we're supporting that mess) Co-authored-by: Erfan Abdi Change-Id: Ifdf726f128bc66bf860bbb71024f94f56879710f --- fs/proc/cmdline.c | 31 +++++++++++++++++++++++++++++++ init/initramfs.c | 2 +- usr/Kconfig | 11 +++++++++++ 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/fs/proc/cmdline.c b/fs/proc/cmdline.c index fa762c5fbcb2..5758cf8a995f 100644 --- a/fs/proc/cmdline.c +++ b/fs/proc/cmdline.c @@ -3,16 +3,47 @@ #include #include #include +#ifdef CONFIG_INITRAMFS_IGNORE_SKIP_FLAG +#include +#endif + +#ifdef CONFIG_INITRAMFS_IGNORE_SKIP_FLAG +#define INITRAMFS_STR_FIND "skip_initramf" +#define INITRAMFS_STR_REPLACE "want_initramf" +#define INITRAMFS_STR_LEN (sizeof(INITRAMFS_STR_FIND) - 1) + +static char proc_command_line[COMMAND_LINE_SIZE]; + +static void proc_command_line_init(void) { + char *offset_addr; + + strcpy(proc_command_line, saved_command_line); + + offset_addr = strstr(proc_command_line, INITRAMFS_STR_FIND); + if (!offset_addr) + return; + + memcpy(offset_addr, INITRAMFS_STR_REPLACE, INITRAMFS_STR_LEN); +} +#endif static int cmdline_proc_show(struct seq_file *m, void *v) { +#ifdef CONFIG_INITRAMFS_IGNORE_SKIP_FLAG + seq_puts(m, proc_command_line); +#else seq_puts(m, saved_command_line); +#endif seq_putc(m, '\n'); return 0; } static int __init proc_cmdline_init(void) { +#ifdef CONFIG_INITRAMFS_IGNORE_SKIP_FLAG + proc_command_line_init(); +#endif + proc_create_single("cmdline", 0, NULL, cmdline_proc_show); return 0; } diff --git a/init/initramfs.c b/init/initramfs.c index e6a800a7c12a..c2ef3486c9b8 100644 --- a/init/initramfs.c +++ b/init/initramfs.c @@ -624,7 +624,7 @@ static int __init skip_initramfs_param(char *str) { if (*str) return 0; - do_skip_initramfs = 1; + do_skip_initramfs = !IS_ENABLED(CONFIG_INITRAMFS_IGNORE_SKIP_FLAG); return 1; } __setup("skip_initramfs", skip_initramfs_param); diff --git a/usr/Kconfig b/usr/Kconfig index 8b4826de1189..de9d04f2c0be 100644 --- a/usr/Kconfig +++ b/usr/Kconfig @@ -32,6 +32,17 @@ config INITRAMFS_FORCE and is useful if you cannot or don't want to change the image your bootloader passes to the kernel. +config INITRAMFS_IGNORE_SKIP_FLAG + bool "Force initramfs even when skip_initramfs is set" + default n + help + Ignore skip_initramfs cmdline flag. + + This should only be used if you have no control over cmdline + passed by your bootloader yet you can't use CMDLINE_FORCE. + + If unsure say N. + config INITRAMFS_ROOT_UID int "User ID to map to 0 (user root)" depends on INITRAMFS_SOURCE!="" From 024c0b766e03ef7a3400594fbe2f0f0b2494a406 Mon Sep 17 00:00:00 2001 From: Yumi Yukimura Date: Sun, 22 Oct 2023 23:06:53 -0700 Subject: [PATCH 334/356] fs: proc: Add PROC_CMDLINE_APPEND_ANDROID_FORCE_NORMAL_BOOT For Android 9 launch A/B devices migrating to Android 10 style system-as-root, `androidboot.force_normal_boot=1` must be passed in cmdline when booting into normal or charger mode. However, it is not always possible for one to modify the bootloader to adhere to these changes. As a workaround, one can use the presence of the `skip_initramfs` flag in cmdline to to decide whether to append the new flag to cmdline on the kernel side. Co-authored-by: jabashque Change-Id: Ia00ea2c54e2a7d2275e552837039033adb98d0ff --- fs/proc/Kconfig | 11 +++++++++++ fs/proc/cmdline.c | 35 +++++++++++++++++++++++------------ 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/fs/proc/Kconfig b/fs/proc/Kconfig index af22f7b261ac..3b78af4c5028 100644 --- a/fs/proc/Kconfig +++ b/fs/proc/Kconfig @@ -103,3 +103,14 @@ config PROC_UID depends on PROC_FS && RT_MUTEXES help Provides aggregated per-uid information under /proc/uid. + +config PROC_CMDLINE_APPEND_ANDROID_FORCE_NORMAL_BOOT + bool "Append androidboot.force_normal_boot=1 to cmdline if skip_initramfs is present" + default n + help + If `skip_initramfs` is present in the kernel cmdline, then append + `androidboot.force_normal_boot=1` to the cmdline string that we present + in /proc/cmdline. + + This is a workaround to allow recovery-as-boot A/B devices that + launched with Android 9 to use two-stage init. diff --git a/fs/proc/cmdline.c b/fs/proc/cmdline.c index 5758cf8a995f..edfd0b97ee12 100644 --- a/fs/proc/cmdline.c +++ b/fs/proc/cmdline.c @@ -3,46 +3,57 @@ #include #include #include -#ifdef CONFIG_INITRAMFS_IGNORE_SKIP_FLAG #include + +#if defined(CONFIG_INITRAMFS_IGNORE_SKIP_FLAG) || \ + defined(CONFIG_PROC_CMDLINE_APPEND_ANDROID_FORCE_NORMAL_BOOT) +#define INITRAMFS_STR_FIND "skip_initramf" #endif #ifdef CONFIG_INITRAMFS_IGNORE_SKIP_FLAG -#define INITRAMFS_STR_FIND "skip_initramf" #define INITRAMFS_STR_REPLACE "want_initramf" #define INITRAMFS_STR_LEN (sizeof(INITRAMFS_STR_FIND) - 1) +#endif + +#ifdef CONFIG_PROC_CMDLINE_APPEND_ANDROID_FORCE_NORMAL_BOOT +#define ANDROID_FORCE_NORMAL_BOOT_STR "androidboot.force_normal_boot=1" +#endif static char proc_command_line[COMMAND_LINE_SIZE]; static void proc_command_line_init(void) { char *offset_addr; + char *proc_command_line_tail; strcpy(proc_command_line, saved_command_line); +#ifdef CONFIG_INITRAMFS_IGNORE_SKIP_FLAG offset_addr = strstr(proc_command_line, INITRAMFS_STR_FIND); - if (!offset_addr) - return; + if (offset_addr) + memcpy(offset_addr, INITRAMFS_STR_REPLACE, INITRAMFS_STR_LEN); +#endif - memcpy(offset_addr, INITRAMFS_STR_REPLACE, INITRAMFS_STR_LEN); -} +#ifdef CONFIG_PROC_CMDLINE_APPEND_ANDROID_FORCE_NORMAL_BOOT + if (strstr(saved_command_line, INITRAMFS_STR_FIND)) { + // point proc_command_line_tail to the null terminator of the cmdline + proc_command_line_tail = proc_command_line + strlen(proc_command_line); + memcpy(proc_command_line_tail, " ", 1); + memcpy(proc_command_line_tail + 1, ANDROID_FORCE_NORMAL_BOOT_STR, + sizeof(ANDROID_FORCE_NORMAL_BOOT_STR)); + } #endif +} static int cmdline_proc_show(struct seq_file *m, void *v) { -#ifdef CONFIG_INITRAMFS_IGNORE_SKIP_FLAG seq_puts(m, proc_command_line); -#else - seq_puts(m, saved_command_line); -#endif seq_putc(m, '\n'); return 0; } static int __init proc_cmdline_init(void) { -#ifdef CONFIG_INITRAMFS_IGNORE_SKIP_FLAG proc_command_line_init(); -#endif proc_create_single("cmdline", 0, NULL, cmdline_proc_show); return 0; From 5a90237869eb2861190d3132294d3201a887bb82 Mon Sep 17 00:00:00 2001 From: Sebastiano Barezzi Date: Sun, 22 Oct 2023 14:05:43 -0700 Subject: [PATCH 335/356] ARM64: configs: Enable CONFIG_INITRAMFS_IGNORE_SKIP_FLAG Change-Id: I22b5eb981c886d9280957f6bd1047fc76ac9916b --- arch/arm64/configs/vendor/enchilada_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/vendor/enchilada_defconfig b/arch/arm64/configs/vendor/enchilada_defconfig index 8a17e105a817..24a0ae4b8cf3 100644 --- a/arch/arm64/configs/vendor/enchilada_defconfig +++ b/arch/arm64/configs/vendor/enchilada_defconfig @@ -30,6 +30,7 @@ CONFIG_NAMESPACES=y # CONFIG_PID_NS is not set CONFIG_SCHED_TUNE=y CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_IGNORE_SKIP_FLAG=y # CONFIG_RD_XZ is not set # CONFIG_RD_LZO is not set # CONFIG_RD_LZ4 is not set From ddab2e9315430c8b5e7dfd4151c04ce0019e536b Mon Sep 17 00:00:00 2001 From: jabashque Date: Sun, 22 Oct 2023 23:21:09 -0700 Subject: [PATCH 336/356] ARM64: configs: Enable CONFIG_PROC_CMDLINE_APPEND_ANDROID_FORCE_NORMAL_BOOT Change-Id: I89f115c5757cdb7edb74bd45f881c5b8a7acd644 --- arch/arm64/configs/vendor/enchilada_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/vendor/enchilada_defconfig b/arch/arm64/configs/vendor/enchilada_defconfig index 24a0ae4b8cf3..826de151b189 100644 --- a/arch/arm64/configs/vendor/enchilada_defconfig +++ b/arch/arm64/configs/vendor/enchilada_defconfig @@ -660,6 +660,7 @@ CONFIG_FUSE_FS=y CONFIG_OVERLAY_FS=y CONFIG_INCREMENTAL_FS=y CONFIG_VFAT_FS=y +CONFIG_PROC_CMDLINE_APPEND_ANDROID_FORCE_NORMAL_BOOT=y CONFIG_TMPFS=y CONFIG_TMPFS_POSIX_ACL=y CONFIG_SDCARD_FS=y From 20fc387b25db34cff0f770045024051d20fc150d Mon Sep 17 00:00:00 2001 From: Sebastiano Barezzi Date: Thu, 18 Aug 2022 15:01:45 +0200 Subject: [PATCH 337/356] ARM: dts: msm: Move to second stage init Change-Id: Ia7642d730b0a68e045f19c6a3fd00ce3c8844379 --- arch/arm64/boot/dts/qcom/sdm845.dtsi | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index 00f3c38311f6..91e6eb4fec3c 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -370,6 +370,7 @@ firmware: firmware { android { compatible = "android,firmware"; + boot_devices = "soc/1d84000.ufshc"; vbmeta { compatible = "android,vbmeta"; parts = "vbmeta,boot,system,vendor,dtbo"; @@ -383,7 +384,7 @@ type = "ext4"; mnt_flags = "ro,barrier=1,discard"; fsmgr_flags = "wait,slotselect,avb"; - status = "ok"; + status = "disabled"; }; }; }; From 50104cb464d5e06a60c5dbeb613560a33914f0f5 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Sun, 28 Jan 2024 16:11:21 +0000 Subject: [PATCH 338/356] power: smb-lib: Remove FB/DRM ifdefs For some reason those break the DRM notifier --- drivers/power/supply/qcom/smb-lib.c | 47 +---------------------------- drivers/power/supply/qcom/smb-lib.h | 4 --- 2 files changed, 1 insertion(+), 50 deletions(-) diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c index 266f73d5e819..200f4a83c045 100644 --- a/drivers/power/supply/qcom/smb-lib.c +++ b/drivers/power/supply/qcom/smb-lib.c @@ -5,8 +5,6 @@ /* david.liu@bsp, 20171023 Battery & Charging porting */ #define pr_fmt(fmt) "SMBLIB: %s: " fmt, __func__ -#define CONFIG_MSM_RDM_NOTIFY -#undef CONFIG_FB #include #include #include @@ -28,13 +26,8 @@ #include #include #include -#if defined(CONFIG_FB) -#include -#include -#elif defined(CONFIG_MSM_RDM_NOTIFY) #include #include -#endif /*CONFIG_FB*/ #include #include #include @@ -7055,36 +7048,6 @@ static void op_check_charger_uovp(struct smb_charger *chg, int vchg_mv) pre_uovp_satus = uovp_satus; } -#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) { @@ -7118,7 +7081,6 @@ static int msm_drm_notifier_callback(struct notifier_block *self, return 0; } -#endif static void ffc_exit(struct smb_charger *chg) { int icharging, batt_volt, temp; @@ -8752,20 +8714,13 @@ int smblib_init(struct smb_charger *chg) g_chg = chg; regsister_notify_usb_enumeration_status(&usb_enumeration); -#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; rc = msm_drm_register_client(&chg->msm_drm_notifier); if (rc) pr_err("Smb unable to register notifier: %d\n", rc); -#endif /*CONFIG_FB*/ + INIT_DELAYED_WORK(&chg->clear_hdc_work, clear_hdc_work); INIT_WORK(&chg->otg_oc_work, smblib_otg_oc_work); INIT_WORK(&chg->vconn_oc_work, smblib_vconn_oc_work); diff --git a/drivers/power/supply/qcom/smb-lib.h b/drivers/power/supply/qcom/smb-lib.h index bc37763aa8ee..4b1a4f28f268 100644 --- a/drivers/power/supply/qcom/smb-lib.h +++ b/drivers/power/supply/qcom/smb-lib.h @@ -293,11 +293,7 @@ struct smb_charger { /* notifiers */ struct notifier_block nb; /* david.liu@bsp, 20171023 Battery & Charging porting */ -#if defined(CONFIG_FB) - struct notifier_block fb_notif; -#elif defined(CONFIG_MSM_RDM_NOTIFY) struct notifier_block msm_drm_notifier; -#endif /* parallel charging */ struct parallel_params pl; From 919ec14ce2c73638c4f739d634d296f9f599ecbd Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Fri, 9 Feb 2024 17:59:30 +0000 Subject: [PATCH 339/356] power: oneplus_fastchg: Update battery status unconditionally Taken from SM8250_R_11.0 --- drivers/power/supply/qcom/oneplus_fastchg.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/drivers/power/supply/qcom/oneplus_fastchg.c b/drivers/power/supply/qcom/oneplus_fastchg.c index 8d2d5beafd7b..1e4e1aeb2d52 100755 --- a/drivers/power/supply/qcom/oneplus_fastchg.c +++ b/drivers/power/supply/qcom/oneplus_fastchg.c @@ -197,7 +197,7 @@ static int is_usb_pluged(void) return -EINVAL; } - pr_info("%s usb_present [%d]\n", __func__, usb_present); + pr_debug("%s usb_present [%d]\n", __func__, usb_present); usb_present = ret.intval; return usb_present; } @@ -1164,16 +1164,13 @@ static long dash_dev_ioctl(struct file *filp, unsigned int cmd, dash_write(di, ALLOW_DATA); break; case DASH_NOTIFY_UPDATE_ADAPTER_INFO: - if (is_usb_pluged() > 0) { + 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); - } else { - pr_err("usb is not online."); - } + 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: From 4d92b9c0a171faa22f2bd2f0bb3dbf39e23f94d4 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Sat, 10 Feb 2024 01:06:31 +0000 Subject: [PATCH 340/356] power: smb-lib: Set DASH charger type when present Taken from SM8250_R_11.0 --- drivers/power/supply/qcom/smb-lib.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/power/supply/qcom/smb-lib.c b/drivers/power/supply/qcom/smb-lib.c index 200f4a83c045..d14f37d249d0 100644 --- a/drivers/power/supply/qcom/smb-lib.c +++ b/drivers/power/supply/qcom/smb-lib.c @@ -6275,6 +6275,10 @@ static int set_dash_charger_present(int status) schedule_delayed_work(&g_chg->dash_check_work, msecs_to_jiffies(2000)); } + 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); From edf25199c032efb0fdee288cb677c876f9fbf048 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Sat, 10 Feb 2024 01:10:05 +0000 Subject: [PATCH 341/356] power: supply: Add WiPower type text For some reason the Dash type doesn't work without this --- drivers/power/supply/power_supply_sysfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c index 02c2877c3acd..0ecf00468df8 100644 --- a/drivers/power/supply/power_supply_sysfs.c +++ b/drivers/power/supply/power_supply_sysfs.c @@ -47,7 +47,7 @@ static const char * const power_supply_type_text[] = { "USB_HVDCP", "USB_HVDCP_3", "USB_HVDCP_3P5", "Wireless", "USB_FLOAT", "BMS", "Parallel", "Main", "USB_C_UFP", "USB_C_DFP", /* david.liu@bsp, 20171023 Battery & Charging porting */ - "Charge_Pump", "DASH" + "Charge_Pump", "Wipower", "DASH" }; /* david.liu@bsp, 20171023 Battery & Charging porting */ From 88b7729c9035b8f18cf3dea2f8e72235e9e9b9b2 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Sun, 20 Jul 2025 16:09:31 +0000 Subject: [PATCH 342/356] touchscreen: synaptics: Fix misleading indentation warnings --- drivers/input/touchscreen/synaptics_driver_s3320.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/input/touchscreen/synaptics_driver_s3320.c b/drivers/input/touchscreen/synaptics_driver_s3320.c index 4477945ba1e2..eba8ff2ceb11 100644 --- a/drivers/input/touchscreen/synaptics_driver_s3320.c +++ b/drivers/input/touchscreen/synaptics_driver_s3320.c @@ -1296,7 +1296,7 @@ static void fp_detect(struct synaptics_ts_data *ts) gf_opticalfp_irq_handler(0); if (ts->fp_aod_cnt > 0) need_reset = 1; - not_getbase = 0; + not_getbase = 0; ts->fp_aod_cnt = 0; break; } @@ -2229,8 +2229,10 @@ static ssize_t synap_write_address(struct file *file, const char __user *buffer, TPD_DEBUG("reg=0x%x\n",reg[i]); } } - else + else { block = temp_block; + } + return count; } From 13de1ed2c5ce2209239ed962fb23f409f6f2a4c0 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Sun, 20 Jul 2025 16:09:51 +0000 Subject: [PATCH 343/356] power: oneplus_fastchg: Fix misleading indentation warning --- drivers/power/supply/qcom/op_dash_adapter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/supply/qcom/op_dash_adapter.c b/drivers/power/supply/qcom/op_dash_adapter.c index 0e5826bfca57..deecd3b91d77 100644 --- a/drivers/power/supply/qcom/op_dash_adapter.c +++ b/drivers/power/supply/qcom/op_dash_adapter.c @@ -91,7 +91,7 @@ static void dash_uart_tx_bit( else dash_uart_gpio_set_value( chip, chip->uart_tx_gpio, 0); - tx_bit++; + tx_bit++; break; case BIT_STOP: case BIT_IDLE: From ebafef4c11535780ec3d49584ddeb9000ac25792 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Sun, 20 Jul 2025 16:10:56 +0000 Subject: [PATCH 344/356] msm: camera_oneplus: Fix misleading indentation warnings --- .../cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 0004d28fd4d8..9dc68e5ee7d3 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -1110,15 +1110,15 @@ static int cam_ife_hw_mgr_acquire_res_ife_csid_rdi( if (!cam_ife_hw_mgr_is_rdi_res(out_port->res_type)) continue; - /* get cid resource */ - rc = cam_ife_mgr_acquire_cid_res(ife_ctx, - in_port, &cid_res_id, - cam_ife_hw_mgr_get_ife_csid_rdi_res_type( - out_port->res_type)); - if (rc) { - CAM_ERR(CAM_ISP, - "Acquire IFE CID resource Failed"); - goto err; + /* get cid resource */ + rc = cam_ife_mgr_acquire_cid_res(ife_ctx, + in_port, &cid_res_id, + cam_ife_hw_mgr_get_ife_csid_rdi_res_type( + out_port->res_type)); + if (rc) { + CAM_ERR(CAM_ISP, + "Acquire IFE CID resource Failed"); + goto err; } rc = cam_ife_hw_mgr_get_res(&ife_ctx->free_res_list, From 94b430717ac69f982f9c7f7100f5ffea2ed8f0d4 Mon Sep 17 00:00:00 2001 From: Trishansh Bhardwaj Date: Mon, 4 Nov 2019 12:13:04 +0530 Subject: [PATCH 345/356] msm: camera_oneplus: core: Prevent crash on kref_put kref_put causes crash if refcount is zero. This change prevents crash by checking if refcount value. CRs-Fixed: 2553290 Change-Id: Ie9a950b289cdb2b8fca8c5d025be540d926eadbd Signed-off-by: Trishansh Bhardwaj --- .../platform/msm/camera_oneplus/cam_core/cam_context.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/msm/camera_oneplus/cam_core/cam_context.c b/drivers/media/platform/msm/camera_oneplus/cam_core/cam_context.c index cedf9417b8a4..78971a932a78 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_core/cam_context.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_core/cam_context.c @@ -504,7 +504,12 @@ int cam_context_deinit(struct cam_context *ctx) void cam_context_putref(struct cam_context *ctx) { - kref_put(&ctx->refcount, cam_node_put_ctxt_to_free_list); + if (kref_read(&ctx->refcount)) + kref_put(&ctx->refcount, cam_node_put_ctxt_to_free_list); + else + WARN(1, "ctx %s %d state %d devhdl %X\n", ctx->dev_name, + ctx->ctx_id, ctx->state, ctx->dev_hdl); + CAM_DBG(CAM_CORE, "ctx device hdl %ld, ref count %d, dev_name %s", ctx->dev_hdl, refcount_read(&(ctx->refcount.refcount)), From 636b34cb98ace4515f9771efa264b2889d236576 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Sat, 11 Oct 2025 20:41:33 +0000 Subject: [PATCH 346/356] oneplus: param_read_write: Switch to vfs_write --- drivers/oneplus/drivers/param_read_write/param_read_write.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/oneplus/drivers/param_read_write/param_read_write.c b/drivers/oneplus/drivers/param_read_write/param_read_write.c index 0e49c40af2d9..a61faadcb6da 100644 --- a/drivers/oneplus/drivers/param_read_write/param_read_write.c +++ b/drivers/oneplus/drivers/param_read_write/param_read_write.c @@ -73,7 +73,7 @@ static int write_param_partition(const char *buf, unsigned long count, goto out; } //ret = filp->f_op->write(filp,(char __user *)buf,count,&filp->f_pos); - ret = __kernel_write(filp, (char __user *)buf, count, &filp->f_pos); + ret = vfs_write(filp, (char __user *)buf, count, &filp->f_pos); out: set_fs(fs); From 5cd59c35397f7c0336101216be86952d33576704 Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Sat, 11 Oct 2025 20:49:40 +0000 Subject: [PATCH 347/356] of: fdt: Initialize param memory region --- drivers/of/fdt.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 9d0090df5eac..1fce390718c0 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -32,6 +32,10 @@ #include "of_private.h" +#ifdef CONFIG_PARAM_READ_WRITE +void init_param_mem_base_size(phys_addr_t base, unsigned long size); +#endif + /* * of_fdt_limit_memory - limit the number of regions in the /memory node * @limit: maximum entries @@ -675,6 +679,11 @@ static int __init __reserved_mem_reserve_reg(unsigned long node, pr_info("Reserved memory: failed to reserve memory for node '%s': base %pa, size %lu MiB\n", uname, &base, (unsigned long)(size / SZ_1M)); + #ifdef CONFIG_PARAM_READ_WRITE + if (!strncmp(uname, "param_mem", 9)) + init_param_mem_base_size(base, size); + #endif + len -= t_len; if (first) { fdt_reserved_mem_save_node(node, uname, base, size); From e7882a2e21716987f224bd68fc16f9bb95a72b0c Mon Sep 17 00:00:00 2001 From: Swami Reddy Reddy Date: Tue, 14 Oct 2025 08:08:19 +0500 Subject: [PATCH 348/356] msm: camera: sensor: TOCTOU error handling - Change to dereference s_ctrl only after proper NULL Dereference Check. CRs-Fixed: 3875406 Change-Id: I8e2c717b22efff2a7d6503d38c048e30eff230da Signed-off-by: Swami Reddy Reddy --- .../cam_sensor_module/cam_sensor/cam_sensor_core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/cam_sensor_core.c index e7747d873c76..a153f2fa7df8 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/cam_sensor_core.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor/cam_sensor_core.c @@ -1,4 +1,5 @@ /* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2024, Qualcomm Innovation Center, Inc. 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 @@ -779,8 +780,7 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, struct cam_control *cmd = (struct cam_control *)arg; struct cam_sensor_power_setting *pu = NULL; struct cam_sensor_power_setting *pd = NULL; - struct cam_sensor_power_ctrl_t *power_info = - &s_ctrl->sensordata->power_info; + struct cam_sensor_power_ctrl_t *power_info = NULL; #ifdef CONFIG_PROJECT_INFO uint32_t count = 0, i; enum COMPONENT_TYPE CameraID; @@ -791,6 +791,8 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, return -EINVAL; } + power_info = &s_ctrl->sensordata->power_info; + if (cmd->op_code != CAM_SENSOR_PROBE_CMD) { if (cmd->handle_type != CAM_HANDLE_USER_POINTER) { CAM_ERR(CAM_SENSOR, "Invalid handle type: %d", From 93abf9ffde92489f754f1950e8cb2879206a2939 Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Wed, 15 Oct 2025 10:17:20 +0500 Subject: [PATCH 349/356] msm: camera: icp: Increase timeout for abort & destroy Due to scheduling delays there is a possibility that the abort/destroy ACK from FW cannot be processed within the current timeout. Hence increasing the timeout to account for these delays. Change-Id: Ia8f670e67dfb3db47e71b1d1e9eeba79bde7f277 Signed-off-by: Karthik Anantha Ram --- .../camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c index 4e84f1330d24..bff06a66a95c 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c @@ -2285,7 +2285,7 @@ static int cam_icp_mgr_abort_handle( int rc = 0; unsigned long rem_jiffies; size_t packet_size; - int timeout = 100; + int timeout = 1000; struct hfi_cmd_work_data *task_data; struct hfi_cmd_ipebps_async *abort_cmd; struct crm_workq_task *task; @@ -2349,7 +2349,7 @@ static int cam_icp_mgr_destroy_handle( struct cam_icp_hw_ctx_data *ctx_data) { int rc = 0; - int timeout = 100; + int timeout = 1000; unsigned long rem_jiffies; size_t packet_size; struct hfi_cmd_work_data *task_data; From 971e44ef19f1e54ddb321fafceebdb432bc5fdaa Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Wed, 15 Oct 2025 10:17:59 +0500 Subject: [PATCH 350/356] msm: camera: icp: Increase number of supported contexts Bumping up the maximum number of ICP contexts from 36 to 54. Change-Id: I8da5a2fadae8a9a0a0814c73b82450f884217d1e Signed-off-by: Karthik Anantha Ram --- .../cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h index 7bb9b9ed18a2..2ebe41417d1d 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h +++ b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-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 @@ -23,7 +23,7 @@ #define CAM_ICP_A5_BW_BYTES_VOTE 40000000 -#define CAM_ICP_CTX_MAX 36 +#define CAM_ICP_CTX_MAX 54 #define CPAS_IPE1_BIT 0x2000 From 2e78f763ba95059a89a8bd473c7a568c92753fab Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Thu, 16 Oct 2025 20:17:53 +0500 Subject: [PATCH 351/356] msm: camera: icp: Use src clk index to populate clk rates Using last clk index doesn't gaurantee the src clock rates are populated properly, instead use src clock index which is already saved pointing to the correct src clock array. Change-Id: I90369bd2d0aefed74ba738a0deb5768d43e6e576 Signed-off-by: Jigarkumar Zala --- .../cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c index bff06a66a95c..63cc0bbecfef 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c @@ -211,9 +211,9 @@ static int cam_icp_supported_clk_rates(struct cam_icp_hw_mgr *hw_mgr, for (i = 0; i < CAM_MAX_VOTE; i++) { ctx_data->clk_info.clk_rate[i] = - soc_info->clk_rate[i][soc_info->num_clk - 1]; - CAM_DBG(CAM_ICP, "clk_info = %d", - ctx_data->clk_info.clk_rate[i]); + soc_info->clk_rate[i][soc_info->src_clk_idx]; + CAM_DBG(CAM_ICP, "clk_info[%d] = %d", + i, ctx_data->clk_info.clk_rate[i]); } return 0; From bbd94132fda46223cde9debc908c780a44b25d5e Mon Sep 17 00:00:00 2001 From: Edwin Moquete Date: Thu, 23 Oct 2025 19:21:43 +0000 Subject: [PATCH 352/356] msm: camera_oneplus: Fix vla-extension warning drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c:23:20: error: variable length arrays are a C99 feature [-Werror,-Wvla-extension] --- .../cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c index 2c1f5204f4cc..4e5956f1875d 100644 --- a/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c +++ b/drivers/media/platform/msm/camera_oneplus/cam_sensor_module/cam_sensor_io/cam_sensor_cci_i2c.c @@ -20,7 +20,7 @@ int32_t cam_cci_i2c_read(struct cam_sensor_cci_client *cci_client, enum camera_sensor_i2c_type data_type) { int32_t rc = -EINVAL; - unsigned char buf[data_type]; + unsigned char buf[CAMERA_SENSOR_I2C_TYPE_DWORD]; struct cam_cci_ctrl cci_ctrl; if (addr_type <= CAMERA_SENSOR_I2C_TYPE_INVALID From 0b20a983d79c92d51a9108c6e842d1a023b19020 Mon Sep 17 00:00:00 2001 From: LuK1337 Date: Fri, 10 May 2024 13:00:58 +0200 Subject: [PATCH 353/356] bq27541: Add support for reading design capacity Change-Id: I2c199704cef3e32d0c103876b3681d30ea22f316 --- .../power/supply/qcom/bq27541_fuelgauger.c | 24 +++++++++++++++++++ drivers/power/supply/qcom/qpnp-fg-gen3.c | 7 +++++- include/linux/power/oem_external_fg.h | 1 + 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/drivers/power/supply/qcom/bq27541_fuelgauger.c b/drivers/power/supply/qcom/bq27541_fuelgauger.c index d0643315388d..f403c1eef75f 100755 --- a/drivers/power/supply/qcom/bq27541_fuelgauger.c +++ b/drivers/power/supply/qcom/bq27541_fuelgauger.c @@ -77,6 +77,7 @@ #define BQ27541_REG_ICR 0x30 #define BQ27541_REG_LOGIDX 0x32 #define BQ27541_REG_LOGBUF 0x34 +#define BQ27541_REG_DCAP 0x3c #define BQ27541_FLAG_DSC BIT(0) #define BQ27541_FLAG_FC BIT(9) @@ -891,6 +892,22 @@ static int bq27541_average_current(struct bq27541_device_info *di) return -curr * 1000; } +static int bq27541_design_capacity(struct bq27541_device_info *di) +{ + int ret; + int cap = 0; + + if (di->allow_reading) { + ret = bq27541_read(BQ27541_REG_DCAP, &cap, 0, di); + if (ret) { + pr_err("error reading design capacity.\n"); + return ret; + } + } + + return cap; +} + static int bq27541_remaining_capacity(struct bq27541_device_info *di) { int ret; @@ -961,6 +978,11 @@ static int bq27541_get_battery_mvolts(void) return bq27541_battery_voltage(bq27541_di); } +static int bq27541_get_batt_design_capacity(void) +{ + return bq27541_design_capacity(bq27541_di); +} + static int bq27541_get_batt_remaining_capacity(void) { return bq27541_remaining_capacity(bq27541_di); @@ -1133,6 +1155,8 @@ static struct external_battery_gauge bq27541_batt_gauge = { .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_design_capacity + = bq27541_get_batt_design_capacity, .get_batt_remaining_capacity = bq27541_get_batt_remaining_capacity, .get_batt_full_chg_capacity diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c index 5deafc16a090..71196f86f8d4 100644 --- a/drivers/power/supply/qcom/qpnp-fg-gen3.c +++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c @@ -3767,7 +3767,12 @@ static int fg_psy_get_property(struct power_supply *psy, rc = fg_get_sram_prop(fg, FG_SRAM_OCV, &pval->intval); break; case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: - pval->intval = chip->cl.nom_cap_uah; + 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_design_capacity) + pval->intval = external_fg->get_batt_design_capacity(); + else + pval->intval = chip->cl.nom_cap_uah; break; case POWER_SUPPLY_PROP_RESISTANCE_ID: pval->intval = fg->batt_id_ohms; diff --git a/include/linux/power/oem_external_fg.h b/include/linux/power/oem_external_fg.h index 7c7b2e6d4ca4..284d134aa15e 100644 --- a/include/linux/power/oem_external_fg.h +++ b/include/linux/power/oem_external_fg.h @@ -36,6 +36,7 @@ struct external_battery_gauge { bool (*is_battery_id_valid)(void); bool (*is_usb_switch_on)(void); int (*get_battery_status)(void); + int (*get_batt_design_capacity)(void); int (*get_batt_remaining_capacity)(void); int (*get_batt_full_chg_capacity)(void); int (*get_batt_health)(void); From b8d59bcd024ab14815ed55c4d63d3e15d2ff6669 Mon Sep 17 00:00:00 2001 From: LuK1337 Date: Fri, 10 May 2024 13:03:46 +0200 Subject: [PATCH 354/356] bq27541: Convert DCAP/FCC to uAh Test: Open Settings -> Battery -> Battery information Change-Id: I755c1baf2045ecd14ca3f82544fe61a9a63f0b41 --- drivers/power/supply/qcom/bq27541_fuelgauger.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/power/supply/qcom/bq27541_fuelgauger.c b/drivers/power/supply/qcom/bq27541_fuelgauger.c index f403c1eef75f..41967476cc8d 100755 --- a/drivers/power/supply/qcom/bq27541_fuelgauger.c +++ b/drivers/power/supply/qcom/bq27541_fuelgauger.c @@ -903,6 +903,7 @@ static int bq27541_design_capacity(struct bq27541_device_info *di) pr_err("error reading design capacity.\n"); return ret; } + cap *= 1000; } return cap; @@ -947,6 +948,7 @@ static int bq27541_full_chg_capacity(struct bq27541_device_info *di) pr_err("error reading full chg capacity.\n"); return ret; } + cap *= 1000; } return cap; From 7e8cb3eed60116ec7be4b12ee1f4874a444bdff5 Mon Sep 17 00:00:00 2001 From: LuK1337 Date: Sat, 18 May 2024 22:37:16 +0200 Subject: [PATCH 355/356] bq27541: Add cache for DCAP/FCC Test: Open Settings -> Battery -> Battery information after idling for longer period of time. Change-Id: I6326ea9589734aca370df1118492266c4e14e4bd --- drivers/power/supply/qcom/bq27541_fuelgauger.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/power/supply/qcom/bq27541_fuelgauger.c b/drivers/power/supply/qcom/bq27541_fuelgauger.c index 41967476cc8d..22e665578e71 100755 --- a/drivers/power/supply/qcom/bq27541_fuelgauger.c +++ b/drivers/power/supply/qcom/bq27541_fuelgauger.c @@ -234,6 +234,8 @@ struct bq27541_device_info { int soc_pre; int batt_vol_pre; int current_pre; + int dcap_pre; + int fcc_pre; int health_pre; int get_over_temp; unsigned long rtc_resume_time; @@ -897,16 +899,20 @@ static int bq27541_design_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->dcap_pre; + if (di->allow_reading) { ret = bq27541_read(BQ27541_REG_DCAP, &cap, 0, di); if (ret) { pr_err("error reading design capacity.\n"); return ret; } - cap *= 1000; + di->dcap_pre = cap * 1000; } - return cap; + return di->dcap_pre; } static int bq27541_remaining_capacity(struct bq27541_device_info *di) @@ -936,6 +942,10 @@ 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->fcc_pre; + if (di->allow_reading) { #ifdef CONFIG_GAUGE_BQ27411 /* david.liu@bsp, 20161004 Add BQ27411 support */ @@ -948,10 +958,10 @@ static int bq27541_full_chg_capacity(struct bq27541_device_info *di) pr_err("error reading full chg capacity.\n"); return ret; } - cap *= 1000; + di->fcc_pre = cap * 1000; } - return cap; + return di->fcc_pre; } static int bq27541_batt_health(struct bq27541_device_info *di) From dc75fe7fba5cef77ca90513381b3344d1d7635f5 Mon Sep 17 00:00:00 2001 From: Peron Date: Mon, 6 Apr 2026 19:21:51 +0800 Subject: [PATCH 356/356] fix(dts): remove duplicate label on qnovo_fet_ctrl_default The node name was repeated as a label, causing a build error with strict DT compilers. --- arch/arm64/boot/dts/qcom/fajita.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/fajita.dtsi b/arch/arm64/boot/dts/qcom/fajita.dtsi index f7962a49978b..b40661d54299 100644 --- a/arch/arm64/boot/dts/qcom/fajita.dtsi +++ b/arch/arm64/boot/dts/qcom/fajita.dtsi @@ -303,7 +303,7 @@ reserved-memory { &pmi8998_gpios { qnovo_fet_ctrl { - qnovo_fet_ctrl_default: qnovo_fet_ctrl_default { + qnovo_fet_ctrl_default { pins = "gpio6"; function = "normal"; output-low;